Expand description
Subagent lifecycle: SUBAGENT_STARTED, SUBAGENT_FINISHED,
SUBAGENT_ERROR.
Many frameworks let an agent delegate to child agents — a supervisor dispatching research tasks, an agents-as-tools pattern where a tool call is a nested agent, a planner farming out subtasks in parallel. To a frontend all of that arrives as one event stream, and without extra information three concurrent researchers render as one undifferentiated wall of text.
The protocol’s subagent support solves exactly that and nothing more: it attributes each event to the subagent that produced it, and reports when subagents start and stop. It does not orchestrate, schedule or define subagents — that stays with the framework.
§Attribution
Most events carry an optional subagentRunId naming who produced them —
the text, tool-call, activity, reasoning, step and state families, plus
RAW and CUSTOM. An event without one belongs to the parent agent, so a
stream that never sets the field behaves exactly as it did before subagents
existed. The events that describe the run as a whole — RUN_STARTED,
RUN_FINISHED, RUN_ERROR — cannot carry it, and neither can
MESSAGES_SNAPSHOT, whose messages carry their own. See
Event::subagent_run_id and
EventType::is_attributable.
Attribution stands on its own: a producer may tag events without ever
emitting the three lifecycle events, and a consumer must accept an
identifier it never saw announced. Attribution on STATE_* is provenance,
not ownership — the state stays run-scoped, and an attributed snapshot
replaces the run’s state like any other. There is no per-subagent state.
§subagentRunId names an invocation, not a definition
The easiest thing to get wrong. A SubagentRunId is an opaque handle for
one invocation: run the same subagent twice and you get two values. It
is not a name and not a stable id for a reusable definition — that is
SubagentStartedEvent::name. The symmetry with the top-level run is the
way to remember it: agentId is to runId as name is to subagentRunId.
The one exception is suspension. A subagent that finished with
SubagentOutcome::Suspended may reuse its id on the run that resumes
it; a consumer treats that later SUBAGENT_STARTED as a continuation,
never a duplicate.
§Compatibility
Attribution is additive and safe — an unknown field is tolerated — but
the three lifecycle events are unknown event types to a client older than
subagent support, and such a client fails while decoding, before any
application code runs. A producer with older consumers must not emit them;
the server runtime’s SubagentVisibility transformer exists for that.
The model here follows upstream’s docs/concepts/subagents.mdx.
Structs§
- Subagent
Error Event - Marks a subagent invocation as failed.
- Subagent
Finished Event - Closes a subagent invocation’s stream segment for this run.
- Subagent
Started Event - Announces a subagent invocation and gives it a name a UI can display.
Enums§
- Subagent
Outcome - How a subagent invocation’s stream segment closed for this run.