Skip to content
Tracon

RunEventType

Namespace Tracon · Assembly Tracon.Abstractions.dll

Event 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 RunEventType

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.

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.