support-bot example so you can see how the pieces connect. When you’re ready to write code, follow one of the two paths in Getting started.
Core concepts
Interaction with an agent follows a strict hierarchy: one Agent → many Sessions → many Turns → many Events → some Deltas. The sections below walk through each layer using a single running example, a customer support agent namedsupport-bot.

Agent
An agent is a saved definition in the Agent Registry — not a running process. You define it once (model, instructions, tools, config) and any number of customers can invoke it by name. Imaginesupport-bot: a customer support assistant that looks up orders and processes refunds via an MCP server. Its spec might look like this:
support-bot — AgentManifest
Session
A session is one issue worked through with the agent. It is the conversation context: all turns on that issue chain together, and the agent remembers what happened earlier in the same session. Each new issue — whether from the same customer or a different one — gets its own session. Example — two independent sessions:| Session | Issue | How it starts |
|---|---|---|
sess-7f2a9c1b | Jane — refund for order ORD-2031 | ”What’s the status of order ORD-2031?” |
sess-9d4e2a88 | Bob — shipping question | A different customer starts their own chat |
sess-7f2a9c1b. Bob’s question runs in a separate session, so the two conversations never share context.
Session for Jane's refund issue
session.id so Jane can return tomorrow and pick up where she left off. Only one turn runs inside a session at a time.
Turn
A turn is one request in the conversation — a single back-and-forth boundary between your app and the agent. Each time Jane sends a message (or your app sends an approval), you create a new turn. Turns inside a session chain automatically: the agent sees every earlier turn in that session. Example — three turns in Jane’s refund session:| Turn | Who sends it | Input | What happens |
|---|---|---|---|
| Turn 1 | Jane (via your app) | "What's the status of order ORD-2031?" | Agent looks up the order and replies with shipping status. |
| Turn 2 | Jane | "Please issue a full refund for that order." | Agent prepares a refund, hits an approval gate, and pauses. |
| Turn 3 | Jane (or support rep) | Approval: allow process_refund | Agent runs the refund and sends a confirmation. |
session.prepare_turn(input=...) and turn.execute(stream=True) once per row and consumes the returned event stream. Turn 2 knows Jane asked about ORD-2031 in Turn 1 without you resending that history — the harness chains turns for you.
A turn can also end paused when the agent asks a clarifying question (
tool.response_required) or needs MCP OAuth (mcp.auth_required). You resume with a new turn, just like Turn 3 above.Event
While a turn runs, the agent emits events over Server-Sent Events (SSE) — one JSON object at a time. Events tell your app what the agent is doing: calling a tool, getting a result, writing a reply, or finishing. Example — events during Turn 1 (Jane asks for order status):| Order | Event type | What your app learns |
|---|---|---|
| 1 | turn.created | Turn started — turn_id: turn-001 |
| 2 | mcp.initialize | Agent connected to orders-api |
| 3 | model.message | Agent decided to call get_order |
| 4 | tool.response | Order data: shipped, $1,240.00 |
| 5 | model.message | Agent starts composing the reply |
| 6–8 | model.message.delta | Reply text arriving in chunks — see Delta below |
| 9 | turn.done | Turn finished — final reply in state.output |
turn.created
tool.response
turn.done
id, a thread_id ("main" for the root agent, or null for turn-level events like turn.created), and a sequence_number. The stream always opens with turn.created and closes with turn.done.
All event types:
| Event type | Meaning |
|---|---|
turn.created | First event on every turn stream. Carries the turn_id and previous_turn_id. |
turn.done | Last event on every turn stream. Carries the terminal state (done, cancelled, or error) and the final output or required_actions. |
model.message | The base assistant message — assembled model output, including any tool calls. On a live stream it arrives empty and fills in via deltas. |
model.message.delta | An incremental fragment of a model.message (text and/or tool-call chunks). Merge into the base by shared id. The most frequent event. |
tool.response | The result of a server-side tool the harness executed, linked to its call by tool_call_id. |
tool.approval_required | A tool call needs human approval before it can run. The turn pauses; resume with a UserToolApprovalEvent. |
tool.response_required | A client-side tool (e.g. ask_user_question) needs a result from you. The turn pauses; resume with a UserToolResponseEvent. |
thread.created | A sub-agent thread started. Carries its thread_id and title. Not emitted for the main thread. |
thread.done | A sub-agent thread finished (done) or failed (error). Not emitted for the main thread; does not close the turn stream. |
mcp.initialize | One or more MCP server sessions were initialized for a thread. Lists each server in mcp_servers. |
mcp.auth_required | One or more MCP servers need OAuth before the agent can proceed. The turn pauses; resume after the user authorizes via the provided auth_url. |
sandbox.created | A sandbox was provisioned for the turn. Reused across turns in the session. |
Delta
Most events arrive as a complete payload. Model output is different — the LLM streams token by token, so the harness sends a basemodel.message event first, then a series of model.message.delta fragments that you merge into it. All deltas share the base event’s id.
Example — streaming Jane’s reply in Turn 1:
The agent’s full reply is: “Your order ORD-2031 shipped on June 12. Total: $1,240.00.”
Your client receives this sequence:
Base event (empty shell)
Deltas (merge into msg-a1 as they arrive)
events["msg-a1"].content on every chunk:
is_event_delta and merge_event_delta from truefoundry_gateway_sdk.agents (Python) or truefoundry-gateway-sdk/agents (TypeScript) — see Handling Event Delta. When the turn completes, turn.list_events() returns one pre-merged model.message — no deltas to handle on replay.
Thread is a related concept: an execution context inside a session. The root agent runs on
thread_id: "main"; sub-agents get their own thread IDs. Events carry thread_id so you can partition a single turn stream when sub-agents run in parallel.End-to-end walkthrough
The three turns from Turn above, shown together with the actual SDK calls and event payloads for Jane’s refund session (sess-7f2a9c1b) against support-bot. Solid arrows are SDK calls you make; dashed arrows are SSE events streamed back from turn.execute(stream=True).

- Turn 1 — Order status
- Turn 2 — Refund (pauses)
- Turn 3 — Approve (resume)
Input:
"What's the status of order ORD-2031?"| seq | type | summary |
|---|---|---|
| 1 | turn.created | Turn starts |
| 2 | mcp.initialize | Connected to orders-api |
| 3–4 | model.message + deltas | Agent calls get_order |
| 5 | tool.response | { status: shipped, total: 1240.00 } |
| 6–8 | model.message + deltas | Streams reply to Jane’s UI |
| 9 | turn.done | Done — output has full reply |
| Turn | Jane’s action | Ends with | What your app does next |
|---|---|---|---|
| 1 | Asks for order status | Reply in output | Show reply, wait for next message |
| 2 | Requests refund | tool.approval_required | Show approval UI → Turn 3 |
| 3 | Approves refund | Confirmation in output | Show confirmation, issue closed |
Getting started
Two SDK packages, two paths. You can create agents in the Playground and skip the create path entirely.| Task | Package | Client |
|---|---|---|
| Define and save an agent | truefoundry | from truefoundry import client |
| Run a saved agent (Python) | truefoundry-gateway-sdk | AgentSessionClient from truefoundry_gateway_sdk.agents |
| Run a saved agent (TypeScript) | truefoundry-gateway-sdk | AgentSessionClient from truefoundry-gateway-sdk/agents |
Create an agent
Define an
AgentManifest and save it to the Registry with the truefoundry client — model, MCP tools, skills, and runtime config.Use an agent
Invoke a saved agent with the gateway SDK —
AgentSessionClient in Python and TypeScript — sessions, turns, event streaming, delta merging, approvals, threads, and reconnects.Complete example
Runnable terminal chat client handling every event type.
Agent Playground
Build and test agents in the UI, then invoke them from code.
Reference
Agent manifest
Every field on
AgentManifest.Turn events
All event types with field schemas.
Runtime API
SDK methods and turn input types.