.NET API
RunEventType
Tracon.Abstractions.dllEvent types produced during a run. The user interface maps these directly onto visual elements, so the values must stay stable.
[JsonConverter(typeof(JsonStringEnumConverter<RunEventType>))]public enum RunEventTypeFields
Section titled “Fields”ChildRunCompleted = 9
A child agent run finished. Text carries the child agent’s name and
Payload the child run id.
ChildRunStarted = 8
This run started a child agent run. Text carries the child agent’s
name and Payload the child run id.
The child run’s own events are not mirrored into the root stream; only its start and end are reported. Full mirroring would multiply the event volume along the tree and send the same text to the client twice.
ChildRunTimedOut = 30
A sub-agent run passed its wait limit. Text carries the child
agent’s name; Payload is a JSON object with the child run id
(childRunId) and whether the cutoff was a hard one
(hardCutoff). When hardCutoff is false,
the sub-agent’s own cancellation was honored and its resources were
released. When true, the sub-agent ignored
cancellation and keeps running in the background; its eventual
result is discarded without producing a further event, a metric, or
an unobserved exception.
30, not inserted earlier in the list: RunEventType.Custom is 29 and
run_events.type is a smallint column — the enum’s numeric
value is what is stored. Shifting an existing member’s value would
silently reinterpret every already-persisted event of that type.
ContentBlocked = 21
An IContentGuard blocked content. Text carries the guard
name, the rule name and the direction; Payload carries the same four
facts as JSON (guard, rule, direction, action) —
the same shape RunEventType.ContentMasked writes.
The payload does not carry the blocked content. After the
event the run becomes Failed and runs.error_type is written as
content_blocked.
ContentMasked = 20
An IContentGuard masked content. Text carries the guard
name, the rule name and the direction; Payload carries the same four
facts as JSON (guard, rule, direction, action).
Neither Text nor Payload carries the masked
content — they only report THAT masking happened. When the text the
model sees differs from what the user wrote, that is an event and it cannot
stay silent (that rule: a decision that cannot be recorded is a decision
that was not taken).
Custom = 29
A consumer-defined event, written directly with
AgentRunScope.Writer.AppendAsync. CustomType (a
namespaced string, see RunEventCustomTypes) names it;
Payload carries whatever the consumer put there. Tracon
makes no claim about the payload’s shape — it is the consumer’s own
and out of scope for this contract. A consumer’s own Custom event
follows the general rule in the type’s remarks: with
TraconRunRecordingOptions.RecordToolPayloads off it still
appears in the stream but Payload is null. Only
a type under RunEventCustomTypes.ReservedPrefix is exempt.
The escape hatch for the otherwise closed set of event types above. When a built-in event type already fits, use that instead — RunEventType.Custom is for events Tracon has no name for. A type under the RunEventCustomTypes.ReservedPrefix namespace is rejected at write time, so a future built-in custom type can never collide with a consumer’s own.
DocumentAttached = 24
A document was attached to the run through the document channel.
Text carries the document’s name; Payload carries its
size in bytes and a content hash as JSON - never the document’s
content itself.
ExecutorCompleted = 15
An executor completed. Text carries the executor id.
ExecutorFailed = 16
An executor failed. Text carries the executor id and Payload
the error message.
ExecutorInvoked = 14
An executor was invoked. Text carries the executor id.
HistoryCompacted = 10
The chat history was compacted. Text carries a short summary sentence
and Payload the before/after message and token counts.
LoopIterationCompleted = 31
One harness loop iteration was evaluated (see LoopSettings).
Text carries a one-line summary; Payload is a JSON object
with the 1-based iteration number (iteration), whether a criterion
asked for another iteration (continued), the kind of that
criterion (continuedBy, null when every criterion
was satisfied), whether it handed the agent feedback (hasFeedback),
the kind of a criterion that failed to evaluate
(failedCriterion, null otherwise), and whether
the iteration ceiling is what ends the loop (ceilingReached).
The event marks an evaluated iteration, not a model
turn. The turn that reaches LoopSettings.MaxIterations is
not evaluated — there is nothing left to decide — so a loop that ends at
its ceiling writes one event fewer than it takes turns, and its last
event carries ceilingReached.
The criterion’s feedback text is deliberately absent: it is free-form text written for the model, and the run event stream is readable by the client. Its presence is reported, its content is not.
31, not 30: RunEventType.ChildRunTimedOut already holds 30 and
run_events.type is a smallint column, so an existing
member’s numeric value can never be shifted.
MessageCompleted = 2
A message completed.
MessageDelta = 1
A text fragment arrived from the model. Produced only for streaming runs.
ModelFallbackUsed = 22
The primary model provider was unavailable and a
ModelBinding.Fallbacks link answered instead. Text
carries the fallback provider and model ("{provider}/{model}");
Payload carries the primary and fallback bindings and the reason
the primary was skipped.
A model switch is never silent. This event is written in addition to a span tag, not instead of it — an operator reading only the run record must still see which model actually answered.
ReasoningDelta = 23
A reasoning (thinking) delta arrived from the model. Off by default
(TraconRunRecordingOptions.RecordReasoningDeltas).
RunAwaitingInput = 19
The run stopped because it waits for a human answer. It is the last event of the stream.
Separate from RunEventType.RunCompleted and RunEventType.RunFailed: the work neither finished nor failed. On this event the user interface shows the pending request card.
Produced for two different terminal statuses, and Payload differs between
them. For a workflow closing with RunStatus.AwaitingInput, the
details already arrived on the preceding RunEventType.WorkflowRequest event and
this one carries no payload of its own. For a root run closing with
RunStatus.AwaitingApproval, Payload is a JSON array, one
entry per pending tool call: requestId, toolName, and — when a
consumer registered an IToolApprovalPresenter and it resolved
something — entityType, entityId, entityName, and
message from ToolApprovalPresentation. It never carries the
call’s raw arguments; those are read from PendingApproval.Arguments
or from the ToolApprovalRequestContent already present in the response.
RunCompleted = 6
The run finished successfully.
RunContinuationBlocked = 25
Automatic continuation of this interrupted run was refused. Text
carries the reason (a tool whose effect cannot be safely repeated).
Written on a run already closed RunStatus.Failed by
orphaned-run reconciliation; the row itself does not change again.
RunFailed = 7
The run ended with an error.
RunStarted = 0
The run started.
StructuredResponseRejected = 27
The response failed structured output validation and the run is
ending as RunStatus.Failed. Text carries the
safe rejection reason; Payload carries the same reason plus
kind, schemaName, provider and model as JSON.
Neither field carries the model’s raw response text — see IStructuredResponseValidator.
StructuredResponseRepairAttempted = 28
A bounded repair turn is about to run after a rejected structured
response. Text carries the attempt count as "{attempt}/{max}";
Payload carries the same two numbers plus kind and
schemaName as JSON.
Written once per repair round, immediately before the extra model call
it describes, and only when TraconStructuredResponseOptions.MaxRepairAttempts
is greater than zero. See RunEventType.StructuredResponseRejected, which
always precedes it: a repair round only starts after a rejection, never
on its own.
SuperStepCompleted = 13
A super-step completed. Text carries the step number and
Payload the activated executor names plus the checkpoint id, if any.
SuperStepStarted = 12
A super-step started. Text carries the step number and Payload
the names of the executors that sent messages.
ToolFailed = 5
A tool failed.
ToolInvoked = 4
A tool completed successfully. The result is in the event payload.
ToolInvoking = 3
A tool is about to be called. The arguments are in the event payload.
ToolOutputTruncated = 26
A tool result was trimmed to its byte limit. ToolName carries
the tool’s name; Text a short summary of how many bytes were
dropped and the limit. Payload carries the same information as JSON.
Neither field carries the dropped content itself — the point of
trimming is to reduce volume, and writing the discarded part back
into run_events would undo that.
WorkflowOutput = 17
The workflow produced an output. Text carries a text summary of it.
WorkflowRequest = 18
The workflow waits for an external answer (human in the loop). Text
carries the request id and Payload a JSON summary of the request.
The payload carries enough to rebuild the pending request: port id,
request id, request and response type names, and the data to display.
Pending requests are read from these events; no separate table was added.
That is why this event is one of the two exempt from
TraconRunRecordingOptions.RecordToolPayloads (see the type’s
remarks): suppressing this payload would leave the user unable to see
the question they have to answer.
WorkflowStarted = 11
A workflow execution started. Text carries the workflow name.
This is separate from RunEventType.RunStarted: that one reports that the
runs row was opened, this one reports that the Microsoft Agent
Framework execution engine actually took over the graph. Compilation and
validation happen in between, and an error there ends the run before the
graph ever starts.
Remarks
Section titled “Remarks”Written to JSON by name ("Code"), not by number. The
wire contract explains itself that way and survives a change in value order.
The converter sits on the type, so the format is the same everywhere without
touching the consumer’s application-wide JSON options. No enum is PERSISTED as
JSON (RunStatus and RunEventType are smallint in the database,
AgentDefinitionOrigin is rebuilt on read), so a format change does not affect
stored data.
Every member’s Payload is written only when
TraconRunRecordingOptions.RecordToolPayloads is on.
With it off the event still appears in the stream and Text still
carries its summary, but Payload is null — so a
payload described below is what the field holds when it is written, not a
promise that it is always there. Two exceptions always carry theirs,
because there the payload is the function rather than an observability
detail: RunEventType.WorkflowRequest, which is the only place a pending
human request can be read from, and RunEventType.Custom under
RunEventCustomTypes.ReservedPrefix, whose payload carries the
dedup key a client needs to act on the frame. A consumer’s own
RunEventType.Custom event is not exempt.