session-threads changedmanaged-agents/session-threads
Nearest release: v2.1.300, published 2 hours after this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Recorded here
Lines+16added
Lines−15removed
From line
18
where the diff opens
First seen
9 Oct 2026
this site's first read of the page
Recorded edits11to this page, all time
The whole hunk
from line 18, old and new numbered
/
from line 18
1818
1919**Session threads** are where you drill into a specific agent's activity.
2020
21The session `status` (java, php; csharp, go: `Status`) is an aggregation of all agent activity; if at least one thread is `running`, then the overall session status is `running` as well. A [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs) that's running can keep the session `running` too, even while none of its threads is working. When no thread is working and a thread waits on your client, the session is `idle`; see [Know when the work is done](https://platform.claude.com/docs/en/managed-agents/workflow-runs#know-when-the-work-is-done).
21The session `status` (csharp, go: `Status`) is an aggregation of all agent activity; if at least one thread is `running`, then the overall session status is `running` as well. A [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs) that's running can keep the session `running` too, even while none of its threads is working. When no thread is working and a thread waits on your client, the session is `idle`; see [Know when the work is done](https://platform.claude.com/docs/en/managed-agents/workflow-runs#know-when-the-work-is-done).
2222
2323A [session budget](https://platform.claude.com/docs/en/managed-agents/budgets) is a single shared cap across all of a session's threads. As the cap is reached, threads pause independently, and each thread's cost is priced at the thread's own served model.
2424
from line 102
102102 ```
103103</CodeGroup>
104104
105The full list includes the primary thread. `parent_thread_id` (java: `parentThreadId`; php: `parentThreadID`; csharp, go: `ParentThreadID`) is `null` for the primary thread. Every other thread is a child thread. `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) is `null` except on [a run's threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads).
105The full list includes the primary thread. `parent_thread_id` (java: `parentThreadId`; php: `parentThreadID`; csharp, go: `ParentThreadID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) for the primary thread. Every other thread is a child thread. `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) except on [a run's threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads).
106106
107107To list only threads that have certain statuses, add `statuses[]` to the request, and repeat it to give more than one status, as in `?statuses[]=running&statuses[]=idle`. Leave it out to return threads of every status.
108108
from line 386
386386
387387These events surface multiagent activity on the primary thread at `/v1/sessions/{session_id}/events/stream`. Message-direction events are named relative to the thread whose stream they appear on: `agent.thread_message_received` means a message arrived on this thread from another thread, and `agent.thread_message_sent` means this thread sent one. The task that the primary thread's agent delegates, for example, arrives on the child's own stream as an `agent.thread_message_received` event.
388388
389| Type | Description |
390| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
391| `session.thread_created` | A thread was created. Includes `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) and `agent_name` (java, php: `agentName`; csharp, go: `AgentName`). |
392| `session.thread_status_running` | A thread started activity. |
393| `session.thread_status_idle` | The agent associated with the thread is awaiting input. Includes a `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`) indicating why the agent stopped. |
394| `session.thread_status_terminated` | A thread terminated and accepts no further input, for example because it was archived or encountered an unrecoverable error. An advisor thread also terminates when its consultation ends. |
395| `agent.thread_message_received` | On the primary thread, a subagent sent the primary thread's agent a report or question. Includes `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`), `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`), and `content` (java, php; csharp, go: `Content`). |
396| `agent.thread_message_sent` | On the primary thread, the primary thread's agent sent a subagent a task or follow-up message. Includes `to_session_thread_id` (java: `toSessionThreadId`; php: `toSessionThreadID`; csharp, go: `ToSessionThreadID`), `to_agent_name` (java, php: `toAgentName`; csharp, go: `ToAgentName`), and `content` (java, php; csharp, go: `Content`). |
389| Type | Description |
390| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
391| `session.thread_created` | A thread was created. Includes `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) and `agent_name` (java, php: `agentName`; csharp, go: `AgentName`). |
392| `session.thread_status_running` | A thread started activity. |
393| `session.thread_status_idle` | The agent associated with the thread is awaiting input. Includes a `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`) indicating why the agent stopped. |
394| `session.thread_status_terminated` | A thread terminated and accepts no further input, for example because it was archived or encountered an unrecoverable error. An advisor thread also terminates when its consultation ends. |
395| `agent.thread_message_received` | On the primary thread, a subagent sent the primary thread's agent a report or question. Includes `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`), `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`), and `content` (csharp, go: `Content`). |
396| `agent.thread_message_sent` | On the primary thread, the primary thread's agent sent a subagent a task or follow-up message. Includes `to_session_thread_id` (java: `toSessionThreadId`; php: `toSessionThreadID`; csharp, go: `ToSessionThreadID`), `to_agent_name` (java, php: `toAgentName`; csharp, go: `ToAgentName`), and `content` (csharp, go: `Content`). |
397397
398398Advisor consultations emit these same thread events under the reserved name `anthropic.advisor` (as `agent_name` (java, php: `agentName`; csharp, go: `AgentName`) on the thread lifecycle events and `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`) on the advice delivery); see [Give the session an advisor](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#give-the-session-an-advisor) for the sequence.
399399
from line 410
410410
411411Each session thread has its own event stream at `/v1/sessions/{session_id}/threads/{thread_id}/stream`, and it accepts the same `event_deltas[]` parameter as the session-level stream, so you can preview a subagent's text as the model generates it. A connection previews only the thread it's reading: a child thread's previews never appear on the session-level stream, so to watch a subagent live, open its own thread stream. See [Preview session thread events](https://platform.claude.com/docs/en/managed-agents/event-deltas#preview-session-thread-events) for opting in, accumulating, and reconciling previews.
412412
413In a workflow run, the server runs a workflow: a program that the primary thread's agent writes. On each of the run's threads, the first `agent.thread_message_received` is the prompt that the workflow wrote. Its `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`) is the primary thread's ID, and it has no `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`). The API doesn't guarantee the prompt's text, so don't parse it. The thread's `session.thread_status_terminated` event, on the primary thread's stream, tells you the thread is done. No event records the result it returned to the workflow.
413In a workflow run, the server runs a workflow: a program that the primary thread's agent writes. On each of the run's threads, the first `agent.thread_message_received` is the prompt that the workflow wrote. Its `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`) is the primary thread's ID, and the API doesn't set its `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`). The API doesn't guarantee the prompt's text, so don't parse it. The thread's `session.thread_status_terminated` event, on the primary thread's stream, tells you the thread is done. No event records the result it returned to the workflow.
414414
415A thread's stream doesn't replay earlier events. Right after `session.thread_created`, the event list of a run's thread can be empty, because the server writes the thread's first event after it. So open the thread's stream first, then list the thread's events, and skip each streamed event whose `id` (java, php; csharp, go: `ID`) the list returned.
415A thread's stream doesn't replay earlier events. Right after `session.thread_created`, the event list of a run's thread can be empty, because the server writes the thread's first event after it. So open the thread's stream first, then list the thread's events, and skip each streamed event whose `id` (csharp, go: `ID`) the list returned.
416416
417417<Tabs>
418418 <Tab title="Stream session thread events">
from line 687
687687}
688688```
689689
690Post `user.tool_confirmation` (with `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`)) or `user.custom_tool_result` (with `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)); the server routes the response to the correct thread automatically. The response can appear on the primary thread and on the subagent's thread with different `id` (java, php; csharp, go: `ID`) values. To match the two copies, compare `type` (java, php; csharp, go: `Type`) and `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) (or `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)), not `id` (java, php; csharp, go: `ID`).
690Post `user.tool_confirmation` (with `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`)) or `user.custom_tool_result` (with `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)); the server routes the response to the correct thread automatically. The response can appear on the primary thread and on the subagent's thread with different `id` (csharp, go: `ID`) values. To match the two copies, compare `type` (csharp, go: `Type`) and `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) (or `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)), not `id` (csharp, go: `ID`).
691691
692692The session goes `idle` only when no thread is `running`, so `session.status_idle` can arrive long after a subagent's call. You don't have to wait for it: send the `user.custom_tool_result` as soon as the cross-posted `agent.custom_tool_use` event arrives.
693693
694694Under `auto`, your `user.message` events can lead the server to allow a call it would otherwise deny. Nothing in a subagent's thread counts as your intent. Your client posts no messages there, and the messages that the primary thread's agent sends the subagent don't count. When the server denies a call under `auto`, nothing is cross-posted: the event and the error tool result appear only on the subagent's own [thread stream](https://platform.claude.com/docs/en/managed-agents/session-threads#session-thread-events), and the subagent keeps running.
695695
696The following example goes inside the event loop of the [tool confirmation handler](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#tool-confirmation). For each ID in `stop_reason.event_ids`, it sends a `user.tool_confirmation` that allows the call. The same pattern applies to `user.custom_tool_result`.
696The following example goes inside the event loop of the [tool confirmation handler](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#tool-confirmation). For each ID in `stop_reason.event_ids`, it sends a `user.tool_confirmation` that allows the call. The same pattern applies to `user.custom_tool_result`, which you can also send as soon as its `agent.custom_tool_use` event arrives.
697697
698698<CodeGroup>
699699 ```bash cURL
from line 781
781781 session.id(),
782782 EventSendParams.builder()
783783 .addEvent(BetaManagedAgentsUserToolConfirmationEventParams.builder()
784 .type(BetaManagedAgentsUserToolConfirmationEventParams.Type.USER_TOOL_CONFIRMATION)
784785 .toolUseId(eventId)
785786 .result(BetaManagedAgentsUserToolConfirmationEventParams.Result.ALLOW)
786787 .build())
No line in this hunk matches that.