Skip to main content
Version: 0.18.0

Type Alias: AgentEvent

type AgentEvent =
| {
text: string;
type: "text";
}
| {
input: unknown;
toolName: string;
toolUseId?: string;
type: "action";
}
| {
input: unknown;
parentToolUseId?: string;
toolName: string;
toolUseId?: string;
type: "subagent-action";
}
| {
isError: boolean;
text: string;
toolName: string;
toolUseId: string;
type: "tool-result";
}
| {
failedServers: string[];
type: "mcp-error";
}
| {
errorText: string;
failed: boolean;
resultText: string | null;
status: string;
type: "turn-end";
usage?: SessionUsage;
}
| {
level: "info" | "notice" | "suggestion" | "warning" | "local-command";
text: string;
type: "info";
}
| {
suggestion: string;
type: "prompt-suggestion";
};

Defined in: core/runner.ts:14

A transport-agnostic view of one turn's worth of output from query() — the same normalized shape whether the caller is going to print it to a console, forward it to a chat REPL, or serialize it over Electron IPC (a real consuming agent had four separate entry points — CLI run, CLI chat, an exploration mode and a desktop chat — that all parsed the SDK's raw message stream themselves, nearly identically).

Deliberately thin: no formatting (no "[agent]"/"[action]" prefixes, no friendly tool labels — those are domain/presentation concerns the caller owns), and no filtering beyond what's always correct regardless of caller (see action below).

Union Members​

Type Literal​

{
text: string;
type: "text";
}

One streamed text token from the agent's own reply. No separate "block started" event: a caller that wants a prefix before a new run of text (e.g. "\n[agent] ") can track "was the previous event also text?" itself — simpler than mirroring the SDK's own content-block boundaries, and equivalent in practice.


Type Literal​

{
input: unknown;
toolName: string;
toolUseId?: string;
type: "action";
}

A tool call the main agent itself made — never from inside a subagent's own private turn (an assistant message with a non-null parent_tool_use_id, e.g. a subagent spawned via the Agent tool): those are already reported back to the Agent tool call that started them, so surfacing their internal tool use here would make it look like a subagent had taken over the session, not just handed a result back to the main agent. This filtering is the one piece of interpretation this module always applies, since it's correct for every caller, not a presentation choice.


Type Literal​

{
input: unknown;
parentToolUseId?: string;
toolName: string;
toolUseId?: string;
type: "subagent-action";
}

A tool call made inside a subagent's own turn (see action above for why those are kept apart). Only for showing that a subagent is busy: a console log ignores it.


Type Literal​

{
isError: boolean;
text: string;
toolName: string;
toolUseId: string;
type: "tool-result";
}

What one of the main agent's tool calls returned, paired with its action by toolUseId, as plain text (images and other non-text parts left out). Subagents' results stay out, as their actions do. A console log ignores it.


Type Literal​

{
failedServers: string[];
type: "mcp-error";
}

One or more MCP servers failed to connect at session startup.


Type Literal​

{
errorText: string;
failed: boolean;
resultText: string | null;
status: string;
type: "turn-end";
usage?: SessionUsage;
}

A turn (one full query() response cycle) has finished. failed is the real failure signal — the SDK can report status: "success" even when the turn actually failed on an API error (billing/access denied, etc.), with the real message landing in resultText instead of errorText in that specific case (confirmed empirically: an org-level access error came back as subtype "success", is_error: true, with the real message in result) — check failed, not status === "success".


Type Literal​

{
level: "info" | "notice" | "suggestion" | "warning" | "local-command";
text: string;
type: "info";
}

Out-of-band text from the CLI loop itself, not from the model: local-command output (e.g. built-in /usage) or an informational banner (hook feedback, an unrecognized /slash-command notice, ...). Without this, those system messages fell through generateEvents() unhandled — confirmed empirically: typing an unrecognized/ unnamespaced plugin slash command produced total silence (no text, no error, nothing), because the SDK's own response to it arrives as exactly this message shape and this module simply dropped it.


Type Literal​

{
suggestion: string;
type: "prompt-suggestion";
}

The predicted next prompt, when Options.promptSuggestions is on. It arrives after that turn's turn-end, so a reader that stops at turn-end sees it first thing in the next turn; a console log ignores it.