What are Agent Gates?
An agent gate is the identity of one agent in Verlon, the way a standard gate is the identity of one LLM call. It answers two questions:- What did my agent do? Every run of your agent becomes a trace: a grouped timeline of its LLM calls, tool executions, and sub-agents, with cost, latency, and coverage accounting.
- What should each call site run on? Your agent’s LLM call sites become tasks you can control from the dashboard: pin a model per call site or delegate a call site to an existing gate — without redeploying code.
When to use an agent gate
| Scenario | Gate type |
|---|---|
| Single LLM call (summarization endpoint, one-shot API) | Standard gate |
| A chatbot — one call per turn, grouped into conversations | Agent gate |
| A loop or workflow that makes several LLM calls per run | Agent gate |
| Agents that call tools you want on the timeline | Agent gate |
| Different models for different call sites, managed remotely | Agent gate |
Vocabulary
Agent gates use standard observability terms with their standard meanings:| Term | Meaning |
|---|---|
| Agent gate | The registered identity of one agent — home of its tasks, traces, and sessions. |
| Task | A named LLM call site inside the agent (classify, respond, …). The unit of remote control. |
| Trace | One bounded run of the agent, end to end — including sub-agents, which appear as nested spans in the same trace. W3C trace ids. |
| Span | One step inside a trace: an agent span, a generation (LLM call), or a tool execution. |
| Session | A conversation label on traces — your id (chat id, ticket number). Sessions never start, end, or expire; they’re a grouping key, not a state. |
Observed (captured at the gateway — ground truth), Reported (measured by the SDK), or OTel (ingested from your own OpenTelemetry instrumentation). Tool calls that only appear in proxied traffic show as Evidenced — facts without fabricated measurements.
Quickstart
Create an agent gate
Dashboard → Agent Gates → Create Agent Gate. Only a name is required —
no model configuration. Calls run on whatever model your code requests
until you pin models per task.
Wrap your agent's entry point
One trace per run. Everything inside the scope lands on the same timeline.
Using native provider SDKs
If your agent is written with the OpenAI or Anthropic SDK, keep it. Spreadtask.clientOptions() into the client constructor — it carries the Verlon base URL, a trace-aware fetch, and the call site’s identity headers:
Tools on the timeline
Two capture modes, and you usually get the first one for free: Evidenced (zero setup). When the model requests a tool and your loop feeds the result back, both directions pass through Verlon. The timeline reconstructs the execution — name, arguments, result — markedEvidenced because the execution itself wasn’t observed (so no made-up durations).
Reported (one line per tool). Wrap a function and every execution becomes a measured tool span — exact duration, error capture, visibility for tools the model never sees:
redact option for sensitive arguments.
Sessions: multi-turn conversations
conversationId is exactly what the name says — the id of the conversation, not the message. Each user message becomes one trace; the shared conversation id is what groups those traces into a session:
In the trace, or beside it?
A trace is the work that produced one run’s output. When a run triggers side work that doesn’t shape its output — generating a chat title, indexing the exchange, firing a notification — give that work its own trace in the same conversation, linked to the run that caused it:traceparent). Links to runs that were never observed are kept and shown as “triggered by an unobserved run” — same honesty rule as coverage. If your own OpenTelemetry instrumentation emits span links, they’re ingested as the same edges automatically.
Tasks: remote control per call site
Tasks are how the dashboard controls your agent’s models. Three states:- Unconfigured (default). A task with no config is pass-through: the call runs whatever model your code requested. Control is never required.
- Pinned. Set a model on the task and every call through it runs that model — changed from the dashboard, live, no redeploy.
- Delegated. Bind the task to an existing standard gate and calls inherit that gate’s model, parameters, and managed instructions. Tune “how to summarize” once on a
summarizegate; every agent that delegates to it follows.
A model must resolve from somewhere on every call. The chain, in
order: task pin or delegation → the model your code requested → the
gate’s own model. An agent gate has no model of its own, so omit
model in task.chat() calls when the dashboard should decide, and
pass one when the code should own the choice (native provider SDKs
always pass one — that’s the pass-through value a pin overrides). If
nothing in the chain resolves, the call fails with a clear 400 —
hardcoding a model into the gate to avoid that error defeats the
point of per-task control.The SDK validates your declared task names against the gate when the first
trace starts and warns on mismatches (set
strictTasks: true in the client
config to throw instead). A typo’d task name is never an error at request
time — the call passes through and the name shows up as unclaimed traffic.Sub-agents
An agent calling another agent nests naturally — open the sub-agent’s trace scope inside the parent’s and it becomes an agent span in the same trace:Crossing process boundaries
Trace context propagates automatically within a process. Across processes or services, pass the standard W3Ctraceparent and resume:
traceparent (most tracing middleware does), Verlon rides it as-is.
OpenTelemetry ingestion
Already instrumented? Point any OTLP exporter at Verlon and your spans land in the same traces:gen_ai conventions, OpenInference, and OpenLLMetry — so framework instrumentation (Vercel AI SDK telemetry, LangChain instrumentors, the OpenAI Agents SDK via an OTel processor) works without changes. Attributes we don’t recognize are preserved verbatim on the span.
Cost alerts
Per-gate thresholds under Settings → Cost alerts, both alert-only — a fired alert notifies you and never interrupts a run:- Per-trace cost — one run exceeded the threshold (fires once per trace).
- Per-session cumulative cost — one conversation’s traces add up past the threshold (fires at most once per day per session).
Coverage: what the timeline doesn’t know
Agent gates never present a partial picture as a complete one. Each trace shows a coverage strip: the share of wall-clock covered by observed work (computed correctly under parallelism), unobserved gaps labeled inline, evidenced-only executions counted, and verified span loss — the SDK counts anything it had to drop, and sequence gaps are detected server-side, so “0 lost” is a checked claim. Two boundary rules make the math predictable:- The trace’s wall-clock is the
trace()scope’s lifetime — scope entry to scope exit, not first span to last span. Work you do inside the scope that isn’t instrumented (a database write before the first model call, post-processing after the last) shows up as an unobserved gap. That’s deliberate: the gap is the honest record that something happened the timeline can’t account for. Wrap it inverlon.tool()if you want it measured, or move it outside the scope if it isn’t part of the run. - The scope itself doesn’t count as observation. Coverage measures generations and tools, so a trace whose LLM calls bypassed Verlon reads as 0% covered — not 100% because the run boundary technically spans everything.
Migrating from v1 agent gates
The v1 session system (SDK 1.x) was replaced end to end. If you integrated against it:| v1 | v2 |
|---|---|
verlon.generateSessionId() + sessionId per call | agent.trace({ conversationId }, fn) — ambient within the scope |
x-verlon-session-id as the run identifier | traceparent (automatic via instrumentFetch / clientOptions) |
verlon.endSession(id) | Not needed — a trace ends when its scope exits |
| Sub-gates attached to an agent gate | Tasks with a gate binding (dashboard → Tasks → Delegate to a gate) |
Modes (observability / orchestrated), model pools | Removed — everything observes; per-task control replaces orchestration |
x-verlon-session-id still works as a legacy alias for x-verlon-conversation-id — both carry the session label (your conversation id) rather than identifying a run.
