Agent SDK is experimental and will have breaking changes!
For a guided walkthrough, see SDK overview.
Each Turn’s input is a list of one of these types. Resuming a Turn paused by mcp.auth_required needs no input - omit input or pass [].
User messages (UserMessage) cannot be mixed with tool approvals or client-side tool responses in the same input list. UserToolApproval and UserToolResponse may be mixed together.
UserMessage
Start a new conversation or send the next user message. content is either a plain string or a list of content parts, letting you attach files alongside text.
{ "type": "user.message", "content": "I would like to file a support ticket." }
{
"type": "user.message",
"content": [
{ "type": "text", "text": "Please review this document." },
{
"type": "file_upload",
"file": {
"filename": "report.pdf",
"file_data": "data:application/pdf;base64,JVBERi0xLjQK..."
}
}
]
}
| Field | Type | Required | Description |
|---|
type | "user.message" | Yes | |
content | string | UserContent[] | Yes | The message text, or a list of content parts (text and file uploads). |
UserContent
A content part is one of:
Text
| Field | Type | Required | Description |
|---|
type | "text" | Yes | |
text | string | Yes | The message text. |
File upload
| Field | Type | Required | Description |
|---|
type | "file_upload" | Yes | |
file.filename | string | Yes | Name of the uploaded file. |
file.file_data | string | Yes | Data URI: data:<mime>;base64,<payload>. |
Sent to resume a Turn paused by tool.approval_required. One item per pending tool call.
{
"type": "user.tool_approval",
"thread_id": "main",
"tool_call_id": "call_restart_billing",
"approval": { "status": "allow" }
}
| Field | Type | Required | Description |
|---|
type | "user.tool_approval" | Yes | |
thread_id | string | Yes | thread_id from the tool.approval_required event. |
tool_call_id | string | Yes | ID of the tool call being approved or denied. |
approval | ApprovalAllow | ApprovalDeny | Yes | Use {"status": "allow"} to permit the call, or {"status": "deny", "reason": "..."} to block it. reason is optional. |
Sent to resume a Turn paused by tool.response_required. One item per pending tool call.
{
"type": "user.tool_response",
"thread_id": "main",
"tool_call_id": "call_a1b2",
"content": "tfy-prod-us (production)"
}
| Field | Type | Required | Description |
|---|
type | "user.tool_response" | Yes | |
thread_id | string | Yes | thread_id from the tool.response_required event. |
tool_call_id | string | Yes | ID of the tool call whose result is being supplied. |
content | string | Yes | The result to return to the agent. |
Reference
create_session
client.agents.create_session(agent_name, title=None) -> Session
Create a conversation Session for a saved agent.
| Param | Type | Required | Description |
|---|
agent_name | string | Yes | Name of the saved agent to invoke. |
title | string | No | Optional human-readable title for the session. |
list_sessions
client.agents.list_sessions(agent_name, created_by_subject_slug=None, start_timestamp=None, end_timestamp=None, limit=100) -> Iterator[Session]
Iterate over the Sessions for a saved agent, newest-first, transparently paginating through all pages.
| Param | Type | Required | Description |
|---|
agent_name | string | Yes | Filter to sessions for a specific named agent. |
created_by_subject_slug | string | No | Filter to sessions created by a specific user / service account. |
start_timestamp | string | No | ISO-8601 lower bound on session creation time. |
end_timestamp | string | No | ISO-8601 upper bound on session creation time. |
limit | int | No | Number of sessions fetched per page (not a total cap). Defaults to 100. |
Session
The conversation context for a saved agent. Turns created within a Session are chained automatically, so each Turn sees the history of earlier ones. Key members:
| Member | Type | Description |
|---|
id | string | Unique session identifier. Persist it to resume the conversation later via client.agents.get_session(session_id). |
create_turn(...) | method | Prepare a Turn and return a LazyTurn without any network call. Start it with stream() (to stream events) or wait_for_completion() / state() (without streaming). See create_turn. |
list_turns() | method | Iterate over the Turns in this session, always in descending order (newest-first). |
get_turn(turn_id) | method | Fetch a single Turn by ID. |
cancel() | method | Cancel the session and any currently running Turn. Idempotent; after this, create_turn() raises. |
create_turn
session.create_turn(input=None, previous_turn_id="auto")
-> LazyTurn
Prepare a Turn in the session. This makes no network call and returns a LazyTurn with no id yet. The Turn is created server-side on the first method call, and the SDK branches on which one you call first: stream() opens an SSE stream, while wait_for_completion() and state() create the Turn without streaming. Calling cancel() or list_events() before the Turn is started raises.
| Param | Type | Required | Description |
|---|
input | TurnInput | No | Input items for this Turn. See Turn input. Omit or pass [] to resume after mcp.auth_required. |
previous_turn_id | string | "auto" | No | Turn chaining point. Defaults to "auto", letting the server chain to the latest Turn. |
Turn
A single request/response cycle within a Session. Transitions: running → done | cancelled | error.
list_turns() and get_turn() return a fully-qualified Turn whose id and metadata are always populated. create_turn() instead returns a LazyTurn - the same type with the same methods, but its id, previous_turn_id, created_by, and created_at are None until the Turn is started. Starting it via stream(), wait_for_completion(), or state() creates the Turn server-side and populates these (for stream(), from the first turn.created event). Calling list_events() or cancel() on a LazyTurn before it is started raises.
| Member | Type | Description |
|---|
id | string | None | Unique turn identifier (UUIDv7). None on a LazyTurn until it is started. |
session | Session | The Session this Turn belongs to. |
previous_turn_id | string | None | Turn ID this Turn chains from, or None for the first Turn (also None on a LazyTurn until started). |
created_by | string | None | Subject (user / service account) that created this Turn. None on a LazyTurn until started. |
created_at | string | None | ISO-8601 timestamp of Turn creation. None on a LazyTurn until started. |
input | TurnInput | None | The Turn input that triggered this Turn, if any. |
state() | method | Fetch the current lifecycle state from the server. Returns one of TurnRunningState, TurnDoneState, TurnCancelledState, or TurnErrorState. On an unstarted LazyTurn, creates the Turn first. |
stream(after_sequence_number=0) | method | Start an unstarted LazyTurn and stream its events, or reconnect to a running Turn’s live SSE stream. On reconnect, resumes after after_sequence_number (default 0, from the first event); also auto-resumes on any mid-stream drop. Closes when the Turn reaches a terminal state. On a started Turn, raises if it is not running — use list_events() for completed Turns. |
list_events(...) | method | Return a point-in-time snapshot of events accumulated so far, paginating automatically. Only available for completed Turns. order="asc" is natural for replaying history forward. Raises on an unstarted LazyTurn. |
wait_for_completion() | method | Block until the Turn reaches a terminal state and return it. Returns immediately if already terminal. On an unstarted LazyTurn, creates the Turn first. |
cancel() | method | Request cancellation. Idempotent; safe to call on already-terminal Turns. Cancellation is asynchronous — a few more events may arrive before the stream closes. Raises on an unstarted LazyTurn. |
To define or configure the agent itself, see Create an agent.