> ## Documentation Index
> Fetch the complete documentation index at: https://www.truefoundry.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Turn events reference

> All SSE event types emitted during an agent turn: model output, tool calls, thread lifecycle, MCP auth, and terminal states.

For a guided walkthrough, see [Use an agent — Subscribe to events](/docs/agent-platform/agent-harness/sdk/use-agent#subscribe-to-events).

## Turn Events

`turn.execute({ stream: true })` (or `turn.stream()` when reconnecting) streams [Server-Sent Events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). Each event is a JSON object with a `type` field.

* The stream always opens with [`turn.created`](#turncreatedevent) and closes with [`turn.done`](#turndoneevent).
* 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 `execute({ stream: true })` and `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 but are not returned by [`listEvents()` / `list_events()`](/docs/agent-platform/agent-harness/sdk/use-agent#listing-events).

<Tabs>
  <Tab title="turn.*">
    | `type`                              | Description                                            |
    | ----------------------------------- | ------------------------------------------------------ |
    | [`turn.created`](#turncreatedevent) | First event on the stream. Carries `turn_id`.          |
    | [`turn.done`](#turndoneevent)       | Last event on every stream. Carries the final `state`. |
  </Tab>

  <Tab title="model.*">
    Model output.

    | `type`                                           | Description                                                                                                                                |
    | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
    | [`model.message.delta`](#modelmessagedeltaevent) | LLM output - assistant text and/or tool call chunks. Streamed as [`ModelMessageDeltaEvent`](#modelmessagedeltaevent). Most frequent event. |
    | [`model.message`](#modelmessageevent)            | Assembled model message. Returned by `listEvents()` / `list_events()` as [`ModelMessageEvent`](#modelmessageevent).                        |
  </Tab>

  <Tab title="tool.*">
    Tool calls and results.

    | `type`                                                 | Description                                                                      |
    | ------------------------------------------------------ | -------------------------------------------------------------------------------- |
    | [`tool.response`](#toolresponseevent)                  | Complete server-side tool result.                                                |
    | [`tool.approval_required`](#toolapprovalrequiredevent) | A tool call is awaiting human approval. Resume with an approval.                 |
    | [`tool.response_required`](#toolresponserequiredevent) | A client-side tool was called and needs a result. Resume with the tool response. |
  </Tab>

  <Tab title="thread.*">
    Sub-agent thread lifecycle.

    | `type`                                  | Description                                                                                                            |
    | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
    | [`thread.created`](#threadcreatedevent) | A sub-agent thread started. Not emitted for the main thread.                                                           |
    | [`thread.done`](#threaddoneevent)       | A sub-agent thread completed (`done`) or failed (`error`). Not emitted for the main thread; does not close the stream. |
  </Tab>

  <Tab title="mcp.*">
    MCP server lifecycle.

    | `type`                                       | Description                                                                   |
    | -------------------------------------------- | ----------------------------------------------------------------------------- |
    | [`mcp.initialize`](#mcpinitializeevent)      | One or more MCP server sessions were initialized.                             |
    | [`mcp.auth_required`](#mcpauthrequiredevent) | MCP server(s) need OAuth before proceeding. Resume after the user authorizes. |
  </Tab>

  <Tab title="sandbox.*">
    Sandbox lifecycle.

    | `type`                                    | Description                             |
    | ----------------------------------------- | --------------------------------------- |
    | [`sandbox.created`](#sandboxcreatedevent) | A sandbox was provisioned for the Turn. |
  </Tab>
</Tabs>

***

### TurnCreatedEvent

First event on every Turn stream, carrying the Turn's `turn_id` and metadata. Stream-only.

| Field              | Type               | Required | Description                                                               |
| ------------------ | ------------------ | -------- | ------------------------------------------------------------------------- |
| `type`             | `"turn.created"`   | Yes      |                                                                           |
| `id`               | string             | Yes      | Unique event identifier.                                                  |
| `thread_id`        | `null`             | Yes      | Always `null` — turn-level event, not tied to a thread.                   |
| `turn_id`          | string             | Yes      | Unique ID for this Turn.                                                  |
| `previous_turn_id` | string \| None     | No       | Turn ID this Turn chains from, or `None` for the first Turn in a session. |
| `state`            | `TurnStateRunning` | Yes      | Always `{ "status": "running" }` on this event.                           |
| `created_by`       | `Subject`          | Yes      | Subject (user / service account) that created this turn.                  |
| `created_at`       | string             | Yes      | ISO-8601 timestamp when the Turn was created.                             |

***

### ModelMessageDeltaEvent

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`](#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 the [merge pattern](/docs/agent-platform/agent-harness/sdk/use-agent#handling-event-delta-while-streaming) to fold a delta into its base event in place. Import `is_event_delta` and `merge_event_delta` from `truefoundry_gateway_sdk.agents` (Python) or `truefoundry-gateway-sdk/agents` (TypeScript).

| Field               | Type                    | Required | Description                                                                                                                                                         |
| ------------------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`              | `"model.message.delta"` | Yes      |                                                                                                                                                                     |
| `id`                | string                  | Yes      | Shared by all deltas of one message; equal to the assembled [`ModelMessageEvent`](#modelmessageevent) `id`. Use `sequence_number` to distinguish individual deltas. |
| `thread_id`         | string                  | Yes      | Thread this message belongs to. `"main"` for the root agent; a unique ID for sub-agents.                                                                            |
| `content`           | string                  | No       | Incremental text content for this delta.                                                                                                                            |
| `reasoning_content` | string                  | No       | Incremental reasoning/thinking text for this delta; concatenate across deltas.                                                                                      |
| `tool_calls`        | `ToolCallDelta[]`       | No       | Tool call chunks to accumulate by `index`; fully assembled when `finish_reason` is set.                                                                             |
| `finish_reason`     | string                  | No       | Set 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.

| Field       | Type                    | Required | Description                                               |
| ----------- | ----------------------- | -------- | --------------------------------------------------------- |
| `index`     | int                     | Yes      | Position in the `tool_calls` array; used to merge chunks. |
| `id`        | string                  | No       | Tool call ID. First chunk only.                           |
| `type`      | `"function"`            | No       | First chunk only.                                         |
| `function`  | `ToolCallFunctionDelta` | Yes      | The function name and partial arguments for this chunk.   |
| `tool_info` | `ToolCallInfo`          | No       | Tool metadata. First chunk only.                          |

`ToolCallFunctionDelta`:

| Field       | Type   | Required | Description                                                  |
| ----------- | ------ | -------- | ------------------------------------------------------------ |
| `name`      | string | No       | Tool name. Present only in the first chunk for this `index`. |
| `arguments` | string | No       | Partial 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"`):

| Field         | Type    | Required | Description                                 |
| ------------- | ------- | -------- | ------------------------------------------- |
| `type`        | `"mcp"` | Yes      |                                             |
| `server_id`   | string  | Yes      | ID of the MCP server backing this tool.     |
| `server_name` | string  | Yes      | Name of the MCP server backing this tool.   |
| `name`        | string  | Yes      | The tool's original name on the MCP server. |

For built-in TrueFoundry system tools (`type: "truefoundry-system"`), for example `ask_user_question`:

| Field  | Type                   | Required | Description             |
| ------ | ---------------------- | -------- | ----------------------- |
| `type` | `"truefoundry-system"` | Yes      |                         |
| `name` | string                 | Yes      | The system tool's name. |

***

### ModelMessageEvent

The complete, assembled form of a model message: fully concatenated `content` and fully reconstructed `tool_calls`, with `finish_reason` set. Returned by `listEvents()` / `list_events()`; on the stream, the assistant output arrives as [`ModelMessageDeltaEvent`](#modelmessagedeltaevent) deltas that merge into a base event with the same `id`.

| Field               | Type              | Required | Description                                                                                                                                   |
| ------------------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`              | `"model.message"` | Yes      |                                                                                                                                               |
| `id`                | string            | Yes      | Shared across all deltas of one message. Equal to the `id` carried by this message's [`model.message.delta`](#modelmessagedeltaevent) events. |
| `thread_id`         | string            | Yes      | Thread this message belongs to. `"main"` for the root agent; a unique ID for sub-agents.                                                      |
| `content`           | string            | No       | The complete assistant text.                                                                                                                  |
| `reasoning_content` | string            | No       | The complete reasoning/thinking text.                                                                                                         |
| `tool_calls`        | `ToolCall[]`      | No       | Fully assembled tool calls.                                                                                                                   |
| `finish_reason`     | string            | Yes      | Why 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`.

| Field       | Type               | Required | Description                           |
| ----------- | ------------------ | -------- | ------------------------------------- |
| `id`        | string             | Yes      | Tool call ID.                         |
| `type`      | `"function"`       | Yes      | Always `"function"`.                  |
| `function`  | `ToolCallFunction` | Yes      | The tool name and complete arguments. |
| `tool_info` | `ToolCallInfo`     | No       | Tool metadata (same shape as above).  |

`ToolCallFunction`:

| Field       | Type   | Required | Description                                         |
| ----------- | ------ | -------- | --------------------------------------------------- |
| `name`      | string | Yes      | Tool name.                                          |
| `arguments` | string | Yes      | Complete 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.

| Field          | Type              | Required | Description                                          |
| -------------- | ----------------- | -------- | ---------------------------------------------------- |
| `type`         | `"tool.response"` | Yes      |                                                      |
| `thread_id`    | string            | Yes      | Thread this result belongs to.                       |
| `tool_call_id` | string            | Yes      | Links this result back to the originating tool call. |
| `content`      | string            | Yes      | The tool result.                                     |

***

### ThreadCreatedEvent

Emitted when a sub-agent thread starts.

<Note>
  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.
</Note>

| Field        | Type               | Required | Description                                              |
| ------------ | ------------------ | -------- | -------------------------------------------------------- |
| `type`       | `"thread.created"` | Yes      |                                                          |
| `thread_id`  | string             | Yes      | Unique ID for the sub-agent thread.                      |
| `title`      | string             | No       | Human-readable label for the sub-agent thread.           |
| `parent`     | `AgentParent`      | Yes      | Parent thread and tool call that spawned this sub-agent. |
| `agent_info` | `AgentInfo`        | Yes      | Type, name, and input of the thread's agent.             |

`AgentInfo`:

| Field   | Type        | Required | Description                                          |
| ------- | ----------- | -------- | ---------------------------------------------------- |
| `type`  | `"dynamic"` | Yes      | How the sub-agent was defined.                       |
| `name`  | string      | Yes      | The sub-agent's name.                                |
| `input` | string      | No       | The 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. Inspect `state.status` (`"done"` or `"error"`) on the nested [`ThreadState`](#threadstate) object.

<Note>
  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`](#turndoneevent), and the session ends only when it is cancelled.
</Note>

| Field        | Type                          | Required | Description                                                              |
| ------------ | ----------------------------- | -------- | ------------------------------------------------------------------------ |
| `type`       | `"thread.done"`               | Yes      |                                                                          |
| `id`         | string                        | Yes      | Unique event identifier.                                                 |
| `thread_id`  | string                        | Yes      | Unique ID for the sub-agent thread.                                      |
| `title`      | string                        | Yes      | Human-readable label for the sub-agent thread.                           |
| `parent`     | `AgentParent`                 | No       | Parent thread and tool call that spawned this sub-agent.                 |
| `state`      | [`ThreadState`](#threadstate) | Yes      | Terminal thread state: `done` (with `output`) or `error` (with `error`). |
| `created_at` | string                        | Yes      | ISO-8601 timestamp when the event was emitted.                           |

***

### McpInitializeEvent

Emitted when one or more MCP server sessions are initialized for a thread.

| Field         | Type                  | Required | Description                                                         |
| ------------- | --------------------- | -------- | ------------------------------------------------------------------- |
| `type`        | `"mcp.initialize"`    | Yes      |                                                                     |
| `thread_id`   | string                | Yes      |                                                                     |
| `mcp_servers` | `McpServerInitInfo[]` | Yes      | List of initialized MCP servers, each with `name` and `session_id`. |

***

### SandboxCreatedEvent

Emitted once when a sandbox is provisioned for the Turn. The sandbox is reused across Turns within the session.

| Field        | Type                | Required | Description                                             |
| ------------ | ------------------- | -------- | ------------------------------------------------------- |
| `type`       | `"sandbox.created"` | Yes      |                                                         |
| `thread_id`  | `null`              | Yes      | Always `null` — turn-level event, not tied to a thread. |
| `sandbox_id` | string              | Yes      | Unique 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 with [`prepareTurn()` / `prepare_turn()`](/docs/agent-platform/agent-harness/sdk/runtime-api-reference#prepareturn) after the user completes the OAuth flow — no input is required (omit `input` or pass `[]`).

| Field         | Type                  | Required | Description                                                                                            |
| ------------- | --------------------- | -------- | ------------------------------------------------------------------------------------------------------ |
| `type`        | `"mcp.auth_required"` | Yes      |                                                                                                        |
| `thread_id`   | `null`                | Yes      | Always `null` — turn-level event. Blocked threads are listed per server in `mcp_servers[].thread_ids`. |
| `mcp_servers` | `McpServerAuthInfo[]` | Yes      | List of servers needing authorization, each with `id`, `name`, and `auth_url`.                         |

***

### 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 [`UserToolApprovalEvent`](/docs/agent-platform/agent-harness/sdk/runtime-api-reference#usertoolapprovalevent) items — one per pending `tool_call_id` — via [`prepareTurn()` / `prepare_turn()`](/docs/agent-platform/agent-harness/sdk/runtime-api-reference#prepareturn).

| Field        | Type                       | Required | Description                                                                                                                                                                                                                  |
| ------------ | -------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`       | `"tool.approval_required"` | Yes      |                                                                                                                                                                                                                              |
| `thread_id`  | string                     | Yes      |                                                                                                                                                                                                                              |
| `tool_calls` | `ToolCallRef[]`            | Yes      | The tool calls awaiting approval, each with a `tool_call_id` (`id`) and the `source_event_id` of the [`model.message`](#modelmessageevent) 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 [`UserToolResponseEvent`](/docs/agent-platform/agent-harness/sdk/runtime-api-reference#usertoolresponseevent) items — one per pending `tool_call_id` — via [`prepareTurn()` / `prepare_turn()`](/docs/agent-platform/agent-harness/sdk/runtime-api-reference#prepareturn).

| Field        | Type                       | Required | Description                                                                                                                                                                                                                                  |
| ------------ | -------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`       | `"tool.response_required"` | Yes      |                                                                                                                                                                                                                                              |
| `thread_id`  | string                     | Yes      |                                                                                                                                                                                                                                              |
| `tool_calls` | `ToolCallRef[]`            | Yes      | The tool calls awaiting a client-supplied result, each with a `tool_call_id` (`id`) and the `source_event_id` of the [`model.message`](#modelmessageevent) 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 in [`turn.state`](/docs/agent-platform/agent-harness/sdk/runtime-api-reference#typescript-reference) once the turn completes — so callers don't need a separate turn fetch to know what happened.

| Field       | Type                                      | Required | Description                                                                              |
| ----------- | ----------------------------------------- | -------- | ---------------------------------------------------------------------------------------- |
| `type`      | `"turn.done"`                             | Yes      |                                                                                          |
| `thread_id` | `null`                                    | Yes      | Always `null` — turn-level event, not tied to a thread.                                  |
| `state`     | [`TurnTerminalState`](#turnterminalstate) | Yes      | The Turn's terminal state; never running. See [`TurnTerminalState`](#turnterminalstate). |

***

### TurnTerminalState

The terminal lifecycle state of a turn, available on [`turn.state`](/docs/agent-platform/agent-harness/sdk/runtime-api-reference#typescript-reference) and carried by [`TurnDoneEvent`](#turndoneevent)'s `state`. It is one of three objects, discriminated on `status`: [`TurnStateDone`](#turnstatedone), [`TurnStateCancelled`](#turnstatecancelled), or [`TurnStateError`](#turnstateerror). (The non-terminal `TurnStateRunning`, on `turn.state` while a turn is still running, has only `status: "running"`.)

#### TurnStateDone

The turn completed normally.

| Field              | Type                                                                                                                                                                           | Required | Description                                                                                       |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------- |
| `status`           | `"done"`                                                                                                                                                                       | Yes      |                                                                                                   |
| `output`           | [`TurnStateDoneOutput`](#turnstatedoneoutput) \| `null`                                                                                                                        | No       | The final assistant message, or `null` if the turn paused (then `required_actions` is populated). |
| `required_actions` | ([`ToolApprovalRequiredEvent`](#toolapprovalrequiredevent) \| [`ToolResponseRequiredEvent`](#toolresponserequiredevent) \| [`McpAuthRequiredEvent`](#mcpauthrequiredevent))\[] | Yes      | Pause events to act on. Empty when the turn finished without pausing.                             |
| `completed_at`     | string                                                                                                                                                                         | Yes      | ISO-8601 timestamp when the turn completed.                                                       |

#### TurnStateCancelled

The turn was cancelled.

| Field          | Type          | Required | Description                                     |
| -------------- | ------------- | -------- | ----------------------------------------------- |
| `status`       | `"cancelled"` | Yes      |                                                 |
| `reason`       | string        | No       | Why the turn was cancelled.                     |
| `completed_at` | string        | Yes      | ISO-8601 timestamp when the turn was cancelled. |

#### TurnStateError

The turn failed.

| Field          | Type      | Required | Description                              |
| -------------- | --------- | -------- | ---------------------------------------- |
| `status`       | `"error"` | Yes      |                                          |
| `message`      | string    | Yes      | Human-readable error description.        |
| `completed_at` | string    | Yes      | ISO-8601 timestamp when the turn failed. |

***
