Skip to main content
Agent SDK is experimental and will have breaking changes!
For a guided walkthrough, see Use an agent — Subscribe to events.

Turn Events

create_turn() streams Server-Sent Events (SSE). Each event is a JSON object with a type field.
  • The stream always opens with turn.created and closes with turn.done.
  • All events carry a thread_id. Thread-scoped events use "main" (root agent) or a unique sub-agent ID; turn-level events use None.
  • thread.created and thread.done track sub-agent threads only - they are not emitted for the main thread, which is created automatically on the first Turn and lives for the session’s lifetime.
  • All events carry an id. It identifies the logical event and is present in both stream() and list_events().
  • Events delivered via stream() also carry a sequence_number, monotonically increasing within a Turn.
  • All events carry a created_at ISO-8601 timestamp marking when the event was emitted.
  • turn.created and turn.done are stream-only; they appear on the stream (stream()) but are not returned by list_events().
typeDescription
turn.createdFirst event on the stream. Carries turn_id.
turn.doneLast event on every stream. Carries the final state.

TurnCreatedEvent

First event on every Turn stream, carrying the Turn’s turn_id and metadata. Stream-only.
FieldTypeRequiredDescription
type"turn.created"Yes
idstringYesUnique event identifier.
thread_idnullYesAlways null — turn-level event, not tied to a thread.
turn_idstringYesUnique ID for this Turn.
previous_turn_idstring | NoneNoTurn ID this Turn chains from, or None for the first Turn in a session.
created_bystringYesSubject (user / service account) that created this Turn.
created_atstringYesISO-8601 timestamp when the Turn was created.

ModelMessageEventDelta

The most frequent SSE event. Carries an incremental LLM delta for one message - assistant text and/or tool call chunks. Every delta shares the id of the base ModelMessageEvent it belongs to; merge each delta into that base event in your id-keyed event index. A delta with a non-null finish_reason signals the message is complete. Use merge_event_delta from truefoundry_gateway_sdk to fold a delta into its base event in place. Alternatively, ModelMessageBuilder accumulates deltas on their own (without a base event) into a complete ModelMessage: add() returns the accumulated message so far, and build_and_reset() returns the complete message once finish_reason is set.
FieldTypeRequiredDescription
type"model.message.delta"Yes
idstringYesShared by all deltas of one message; equal to the assembled ModelMessageEvent id. Use sequence_number to distinguish individual deltas.
thread_idstringYesThread this message belongs to. "main" for the root agent; a unique ID for sub-agents.
contentstringNoIncremental text content for this delta.
reasoning_contentstringNoIncremental reasoning/thinking text for this delta; concatenate across deltas.
tool_callsToolCallDelta[]NoTool call chunks to accumulate by index; fully assembled when finish_reason is set.
finish_reasonstringNoSet on the final delta. Signals the accumulated message is complete.
Each ToolCallDelta is shaped like an OpenAI streaming tool-call chunk. id, type, and tool_info appear only on the first chunk for a given index; function.arguments is a partial JSON string concatenated across chunks.
FieldTypeRequiredDescription
indexintYesPosition in the tool_calls array; used to merge chunks.
idstringNoTool call ID. First chunk only.
type"function"NoFirst chunk only.
functionToolCallFunctionDeltaYesThe function name and partial arguments for this chunk.
tool_infoToolCallInfoNoTool metadata. First chunk only.
ToolCallFunctionDelta:
FieldTypeRequiredDescription
namestringNoTool name. Present only in the first chunk for this index.
argumentsstringNoPartial JSON string; concatenate across chunks.
ToolCallInfo carries metadata about the tool, discriminated on type. Read the tool name from name. For MCP-backed tools (type: "mcp"):
FieldTypeRequiredDescription
type"mcp"Yes
mcp_server_idstringYesID of the MCP server backing this tool.
mcp_server_namestringYesName of the MCP server backing this tool.
namestringYesThe tool’s original name on the MCP server.
is_deferredboolNoWhether the tool call is deferred.
For built-in TrueFoundry system tools (type: "truefoundry-system"), for example ask_user_question:
FieldTypeRequiredDescription
type"truefoundry-system"Yes
namestringYesThe system tool’s name.

ModelMessage

The complete, assembled form of a model message: fully concatenated content and fully reconstructed tool_calls, with finish_reason set. This is the shape you get after merging all of a message’s deltas into its base event, or from ModelMessageBuilder.build_and_reset().
FieldTypeRequiredDescription
idstringYesShared across all deltas of one message; equal to the assembled ModelMessageEvent id.
thread_idstringYesThread this message belongs to. "main" for the root agent; a unique ID for sub-agents.
contentstringNoThe complete assistant text.
reasoning_contentstringNoThe complete reasoning/thinking text.
tool_callsToolCall[]NoFully assembled tool calls.
finish_reasonstringYesWhy the message ended (for example, "stop" or "tool_calls").

ModelMessageEvent

The event form of ModelMessage (adds type and id). Returned by list_events(); on the stream, the assistant output arrives as ModelMessageEventDelta deltas instead.
FieldTypeRequiredDescription
type"model.message"Yes
idstringYesUnique event identifier. Equal to the id carried by this message’s model.message.delta events.
thread_idstringYesThread this message belongs to. "main" for the root agent; a unique ID for sub-agents.
contentstringNoThe complete assistant text.
reasoning_contentstringNoThe complete reasoning/thinking text.
tool_callsToolCall[]NoFully assembled tool calls.
finish_reasonstringYesWhy the message ended (for example, "stop" or "tool_calls").
Each ToolCall is shaped like OpenAI’s ChatCompletionMessageToolCall. Read the tool name from tool_info.name.
FieldTypeRequiredDescription
idstringYesTool call ID.
type"function"YesAlways "function".
functionToolCallFunctionYesThe tool name and complete arguments.
tool_infoToolCallInfoNoTool metadata (same shape as above).
ToolCallFunction:
FieldTypeRequiredDescription
namestringYesTool name.
argumentsstringYesComplete JSON string of the tool’s input arguments.

ToolResponseEvent

A complete server-side tool result returned to the LLM. Not a streaming delta - one event carries the full result.
FieldTypeRequiredDescription
type"tool.response"Yes
thread_idstringYesThread this result belongs to.
tool_call_idstringYesLinks this result back to the originating tool call.
contentstringYesThe tool result.

ThreadCreatedEvent

Emitted when a sub-agent thread starts.
Not emitted for the main thread. The main thread (thread_id: "main") is the root agent; it is created automatically on the session’s first Turn and is never the subject of a thread.created or thread.done event. thread.created/thread.done track only sub-agent threads.
FieldTypeRequiredDescription
type"thread.created"Yes
thread_idstringYesUnique ID for the sub-agent thread.
titlestringNoHuman-readable label for the sub-agent thread.
parentAgentParentYesParent thread and tool call that spawned this sub-agent.
agent_infoAgentInfoYesType, name, and input of the thread’s agent.
AgentInfo:
FieldTypeRequiredDescription
type"dynamic"YesHow the sub-agent was defined.
namestringYesThe sub-agent’s name.
inputstringNoThe input the parent thread handed to the sub-agent.

ThreadDoneEvent

Emitted when a sub-agent thread reaches a terminal state. Does not terminate the overall Turn stream.
Not emitted for the main thread. The main thread is never “done” - it lives across Turns for the lifetime of the session. The overall Turn’s completion is signalled by turn.done, and the session ends only when it is cancelled.
FieldTypeRequiredDescription
type"thread.done"Yes
thread_idstringYesUnique ID for the sub-agent thread.
titlestringNoHuman-readable label for the sub-agent thread.
status"done" | "error"Yesdone - completed normally, output is present. error - failed, message is present.
outputModelMessageNoFinal accumulated message. Present when status is "done".
parentAgentParentYesParent thread and tool call that spawned this sub-agent.
messagestringNoPresent when status is "error".

McpInitializedEvent

Emitted when one or more MCP server sessions are initialized for a thread.
FieldTypeRequiredDescription
type"mcp.initialize"Yes
thread_idstringYes
contentMcpInitializationInfo[]YesList of initialized MCP servers, each with mcp_server_name and session_id.

SandboxCreatedEvent

Emitted once when a sandbox is provisioned for the Turn. The sandbox is reused across Turns within the session.
FieldTypeRequiredDescription
type"sandbox.created"Yes
thread_idnullYesAlways null — turn-level event, not tied to a thread.
sandbox_idstringYesUnique identifier for the provisioned sandbox.

McpAuthRequiredEvent

Emitted when one or more MCP servers require OAuth authorization before the agent can proceed. The stream ends after this event. Resume by creating a new Turn on the same session and starting it (for example with stream()) after the user completes the OAuth flow - no input is required (omit input or pass []).
FieldTypeRequiredDescription
type"mcp.auth_required"Yes
thread_idnullYesAlways null — turn-level event. Blocked threads are listed per server in servers[].thread_ids.
serversMcpServerAuthInfo[]YesList of servers needing authorization, each with mcp_server_name, auth_url, and thread_ids.

ToolApprovalRequiredEvent

Emitted when one or more tool calls require explicit human approval before they can run. The stream ends after this event. Resume by creating a new Turn with UserToolApproval items - one per pending tool_call_id - and starting it (for example with stream()).
FieldTypeRequiredDescription
type"tool.approval_required"Yes
thread_idstringYes
tool_callsToolCallRef[]YesThe tool calls awaiting approval, each with a tool_call_id (id) and the event_id of the model.message that emitted it - look it up in your event index for the tool name and arguments.

ToolResponseRequiredEvent

Emitted when the agent has called a client-side tool and is waiting for the result. The stream ends after this event. Resume by creating a new Turn with UserToolResponse items - one per pending tool_call_id - and starting it (for example with stream()).
FieldTypeRequiredDescription
type"tool.response_required"Yes
thread_idstringYes
tool_callsToolCallRef[]YesThe tool calls awaiting a client-supplied result, each with a tool_call_id (id) and the event_id of the model.message that emitted it - look it up in your event index for the tool name and arguments.

TurnDoneEvent

Final event on every Turn stream. Stream-only. Its state is the terminal state object - the same value returned by wait_for_completion() - so callers don’t need a separate Turn fetch to know what happened.
FieldTypeRequiredDescription
type"turn.done"Yes
thread_idnullYesAlways null — turn-level event, not tied to a thread.
stateTurnTerminalStateYesThe Turn’s terminal state; never running. See TurnTerminalState.

TurnTerminalState

The terminal lifecycle state of a Turn, returned by wait_for_completion() and carried by TurnDoneEvent’s state. It is one of three objects, discriminated on status: TurnDoneState, TurnCancelledState, or TurnErrorState. (The non-terminal TurnRunningState, returned by state() while a Turn is still running, has only status: "running".)

TurnDoneState

The Turn completed normally.
FieldTypeRequiredDescription
status"done"Yes
outputModelMessageEvent | nullNoThe final assistant message, or null if the Turn paused (then required_actions is populated).
required_actions(ToolApprovalRequiredEvent | ToolResponseRequiredEvent | McpAuthRequiredEvent)[]NoPause events to act on. Empty if none.
completed_atstringYesISO-8601 timestamp when the Turn completed.

TurnCancelledState

The Turn was cancelled.
FieldTypeRequiredDescription
status"cancelled"Yes
reasonstring | nullNoWhy the Turn was cancelled.
completed_atstringYesISO-8601 timestamp when the Turn was cancelled.

TurnErrorState

The Turn failed.
FieldTypeRequiredDescription
status"error"Yes
messagestringYesHuman-readable error description.
completed_atstringYesISO-8601 timestamp when the Turn failed.