Event Schema Reference

June 29, 2026 · View on GitHub

This document mirrors tests/instrument/_event_schema.py, which is the enforced source of truth. That module is validated in CI: the capture_trace / capture_framework_trace fixtures validate every uploaded event, so every adapter unit suite participates in the lock without per-test wiring. If you change the schema, change it there first — the two must stay in sync, and adding a new event type is a deliberate act (add it in the same PR that introduces it).

This is the canonical payload vocabulary the adapters must emit. Any new drift fails loudly; ratcheting the documented exceptions down is the future §3.6 convergence work (the module is that worklist), not a renaming pass.


Known event types (KNOWN_EVENT_TYPES)

Every payload uploaded by a unit suite must use an event type registered in KNOWN_EVENT_TYPES. An unregistered type is a hard failure.

Agent family

Event typeDescription
agent.inputInput handed to an agent.
agent.outputOutput produced by an agent.
agent.errorError raised during an agent run.
agent.stepA single step in an agent's execution.
agent.codeCode emitted/executed by a code-acting agent.
agent.handoffHandoff/delegation between agents (e.g. collaborator handoff).
agent.identityAgent identity metadata.
agent.interactionAn interaction involving the agent.
agent.lifecycleAgent lifecycle event.
agent.state.changeA change in agent state.
agent.node.enterEntry into a graph node.
agent.node.exitExit from a graph node.

Model / cost / environment

Event typeDescription
model.invokeA model invocation (carries a usage token dict).
cost.recordA cost record (must carry token counts; cost_usd optional — see below).
embedding.createAn embedding creation call (carries a usage token dict).
environment.configEnvironment configuration captured at call time.
environment.metricsEnvironment/runtime metrics.

Tools / retrieval

Event typeDescription
tool.callA tool invocation.
tool.resultA tool result.
tool.logicTool logic/decision event.
tool.environmentTool environment event.
retrieval.queryA retrieval/RAG query.

Conversation (autogen group chat)

Event typeDescription
conversation.startedA group-chat conversation started.
conversation.endedA group-chat conversation ended.
conversation.messageA message within a group-chat conversation.

Policy / evaluation

Event typeDescription
policy.violationA policy violation was detected.
evaluation.resultAn evaluation result.

Protocol family

Event typeDescription
protocol.agent_cardA protocol agent card.
protocol.stream.eventA streamed protocol event.
protocol.lifecycleA protocol lifecycle event.
protocol.task.submittedA protocol task was submitted.
protocol.task.completedA protocol task completed.
protocol.async_taskAn asynchronous protocol task.
protocol.elicitation.requestA protocol elicitation request.
protocol.elicitation.responseA protocol elicitation response.
protocol.tool.structured_outputStructured tool output over a protocol.
protocol.mcp_app.invocationAn MCP-app invocation over a protocol.

MCP

Event typeDescription
mcp.tool.callAn MCP tool call.
mcp.tools.listedMCP tools were listed.
mcp.async_taskAn asynchronous MCP task.
mcp.elicitationAn MCP elicitation.
mcp.structured_outputMCP structured output.

A2A (agent-to-agent)

Event typeDescription
a2a.task.createdAn A2A task was created.
a2a.task.updatedAn A2A task was updated.
a2a.task.completedAn A2A task completed.
a2a.agent.cardAn A2A agent card.
a2a.agent.card.servedAn A2A agent card was served.
a2a.agent.discoveredAn A2A agent was discovered.
a2a.delegationAn A2A delegation.

AG-UI

Event typeDescription
agui.messageAn AG-UI message.
agui.tool_callAn AG-UI tool call.
agui.stateAn AG-UI state event.

Commerce

Event typeDescription
commerce.supplier_discoveredA supplier was discovered.
commerce.catalog.browsedA catalog was browsed.
commerce.checkout.startedA checkout was started.
commerce.checkout_completedA checkout completed.
commerce.refund_issuedA refund was issued.
commerce.ui.surface_createdA commerce UI surface was created.
commerce.ui.user_actionA user action on a commerce UI surface.

Payment

Event typeDescription
payment.intent_mandateA payment intent mandate.
payment.mandate_signedA payment mandate was signed.
payment.receipt_issuedA payment receipt was issued.

Token / usage vocabulary

There are two token vocabularies. Mixing them in a single payload is drift and fails the lock.

Provider-family events: the usage dict (USAGE_KEYS)

Provider-family events (model.invoke / embedding.create) carry a usage dict. Its keys must come from USAGE_KEYS:

  • prompt_tokens
  • completion_tokens
  • total_tokens
  • input_tokens
  • output_tokens
  • cached_tokens
  • reasoning_tokens
  • thinking_tokens
  • cache_read_input_tokens
  • cache_creation_input_tokens

usage must be a dict, and every value must be int or None. Unknown keys fail (extend USAGE_KEYS deliberately).

Framework-family events: flat token fields (FRAMEWORK_TOKEN_KEYS)

Framework-family emitters use flat fields rather than a nested usage dict:

  • tokens_prompt
  • tokens_completion
  • tokens_total

Each flat token value must be int or None. A payload may not mix the framework flat vocabulary (tokens_prompt/tokens_completion) with the provider vocabulary (prompt_tokens/completion_tokens/total_tokens).


Canonical timing field

latency_ms (a number) is the canonical duration field. When present it must be numeric.

Drift exception: duration_ns (DURATION_NS_EXCEPTIONS)

duration_ns is non-canonical — new adapters must use latency_ms. It survives only where the drift table records today's drift. The table is a set of (framework marker, event_type) pairs, where "*" matches any event type from that adapter:

Adapter (marker)Event typeWhy it's grandfathered
smolagents* (all events)Pre-existing drift — smolagents emits duration_ns everywhere.
crewai* (all events)Pre-existing drift — crewai root events emit duration_ns.
strands* (all events)Pre-existing drift — strands root events emit duration_ns.
google_adk* (all events)Pre-existing drift — google_adk root events emit duration_ns.

This is the §3.6 drift table from the stability report. The rule is shrink it, never grow it — any other adapter emitting duration_ns fails the lock.


cost.record requirement

A cost.record event must carry token counts (either the framework flat fields or the provider-style fields); a cost.record with no token counts fails.

cost_usd is optional: when present it must be a number, but it is not required. This is because 15 of 18 framework emitters don't compute it — a documented §3.6 gap and convergence-work item. Locking cost_usd as required would be a rename-scale change, so for a priced model the expectation is that cost.record carries cost_usd, but the lock does not yet enforce its presence.