多代理会话
在单个会话中协调多个代理。
多代理编排让一个代理与其他代理协调以完成复杂的工作。代理可以并行运行,拥有自己的隔离上下文,这有助于提高输出质量,也可以改善完成时间。
所有托管代理 API 请求都需要 managed-agents-2026-04-01 beta 头。SDK 会自动设置该 beta 头。
工作原理
所有代理共享相同的容器、文件系统和保险库凭据,但每个代理在自己的会话线程中运行,这是一个具有自己对话历史的上下文隔离的事件流。协调器在主线程中报告活动(这与会话级别的事件流相同);附加线程在协调器委派工作时在运行时生成。
线程是持久的:协调器可以向之前调用的代理发送后续消息,该代理保留之前所有轮次的内容。
每个代理使用其创建时定义的配置(模型、系统提示、工具、MCP 服务器和技能)。工具、MCP 服务器和上下文不共享。
委派什么
多代理协调最适合复杂任务,这些任务要么需要跨多个方面的工作,要么多个范围明确的任务共同贡献于一个整体目标。
适合的模式:
- **并行化:**同时分散独立的子任务(搜索多个来源、分析单独的文件),让协调器综合结果。
- **专业化:**路由到具有领域特定系统提示和工具的代理,例如安全代理或文档代理,而不是将所有功能加载到单个代理中。
- **升级:**为一部分复杂子任务咨询更强大的代理或模型。
配置协调器
在定义代理时,设置 multiagent 以声明协调器可以委派的代理名单:
coordinator=$(curl -fsS https://api.anthropic.com/v1/agents \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-d @- <<EOF
{
"name": "Engineering Lead",
"model": "claude-opus-4-7",
"system": "You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.",
"tools": [
{
"type": "agent_toolset_20260401"
}
],
"multiagent": {
"type": "coordinator",
"agents": [
{"type": "agent", "id": "$REVIEWER_AGENT_ID"},
{"type": "agent", "id": "$TEST_WRITER_AGENT_ID"}
]
}
}
EOF
)
ant beta:agents create <<YAML
name: Engineering Lead
model: claude-opus-4-7
system: You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.
tools:
- type: agent_toolset_20260401
multiagent:
type: coordinator
agents:
- type: agent
id: $REVIEWER_AGENT_ID
- type: agent
id: $TEST_WRITER_AGENT_ID
YAML
coordinator = client.beta.agents.create(
name="Engineering Lead",
model="claude-opus-4-7",
system="You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.",
tools=[
{"type": "agent_toolset_20260401"},
],
multiagent={
"type": "coordinator",
"agents": [
{"type": "agent", "id": reviewer_agent.id},
{"type": "agent", "id": test_writer_agent.id},
],
},
)
const coordinator = await client.beta.agents.create({
name: "Engineering Lead",
model: "claude-opus-4-7",
system:
"You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.",
tools: [{ type: "agent_toolset_20260401" }],
multiagent: {
type: "coordinator",
agents: [
{ type: "agent", id: reviewerAgent.id },
{ type: "agent", id: testWriterAgent.id },
],
},
});
var coordinator = await client.Beta.Agents.Create(new()
{
Name = "Engineering Lead",
Model = BetaManagedAgentsModel.ClaudeOpus4_7,
System = "You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.",
Tools =
[
new BetaManagedAgentsAgentToolset20260401Params
{
Type = BetaManagedAgentsAgentToolset20260401ParamsType.AgentToolset20260401,
},
],
Multiagent = new BetaManagedAgentsMultiagentParams
{
Type = BetaManagedAgentsMultiagentParamsType.Coordinator,
Agents = [reviewerAgent.ID, testWriterAgent.ID],
},
});
coordinator, err := client.Beta.Agents.New(ctx, anthropic.BetaAgentNewParams{
Name: "Engineering Lead",
Model: anthropic.BetaManagedAgentsModelConfigParams{ID: anthropic.BetaManagedAgentsModelClaudeOpus4_7},
System: anthropic.String("You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent."),
Tools: []anthropic.BetaAgentNewParamsToolUnion{{
OfAgentToolset20260401: &anthropic.BetaManagedAgentsAgentToolset20260401Params{
Type: anthropic.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
},
}},
Multiagent: anthropic.BetaManagedAgentsMultiagentParams{
Type: anthropic.BetaManagedAgentsMultiagentParamsTypeCoordinator,
Agents: []anthropic.BetaManagedAgentsMultiagentRosterEntryParamsUnion{
{OfString: anthropic.String(reviewerAgent.ID)},
{OfString: anthropic.String(testWriterAgent.ID)},
},
},
})
if err != nil {
panic(err)
}
var coordinator = client.beta().agents().create(
AgentCreateParams.builder()
.name("Engineering Lead")
.model(BetaManagedAgentsModel.CLAUDE_OPUS_4_7)
.system("You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.")
.addTool(
BetaManagedAgentsAgentToolset20260401Params.builder()
.type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
.build()
)
.multiagent(BetaManagedAgentsMultiagentParams.builder()
.type(BetaManagedAgentsMultiagentParams.Type.COORDINATOR)
.addAgent(BetaManagedAgentsAgentParams.builder()
.type(BetaManagedAgentsAgentParams.Type.AGENT)
.id(reviewerAgent.id())
.build())
.addAgent(BetaManagedAgentsAgentParams.builder()
.type(BetaManagedAgentsAgentParams.Type.AGENT)
.id(testWriterAgent.id())
.build())
.build())
.build()
);
$coordinator = $client->beta->agents->create(
name: 'Engineering Lead',
model: 'claude-opus-4-7',
system: 'You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.',
tools: [
['type' => 'agent_toolset_20260401'],
],
multiagent: [
'type' => 'coordinator',
'agents' => [
['type' => 'agent', 'id' => $reviewerAgent->id],
['type' => 'agent', 'id' => $testWriterAgent->id],
],
],
);
coordinator = client.beta.agents.create(
name: "Engineering Lead",
model: "claude-opus-4-7",
system: "You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.",
tools: [
{type: "agent_toolset_20260401"}
],
multiagent: {
type: "coordinator",
agents: [
{type: "agent", id: reviewer_agent.id},
{type: "agent", id: test_writer_agent.id}
]
}
)
multiagent.agents 可以接受以下任一形式:
{"type": "agent", "id": agent.id}通过 ID 引用先前创建的agent。如果未指定version,则默认固定到最新的代理版本。{"type": "agent", "id": agent.id, "version": agent.version}固定到特定代理版本。{"type": "self"}允许协调器生成自身的副本。
协调器只能委派到一层代理;深度 > 1 将被忽略。multiagent.agents 中最多可列出 20 个唯一代理,但协调器可以调用每个代理的多个副本。
创建会话
创建引用协调器的会话。协调器根据需要委派给其名单中的代理。
session=$(curl -fsSL https://api.anthropic.com/v1/sessions \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-d @- <<EOF
{
"agent": "$COORDINATOR_ID",
"environment_id": "$ENVIRONMENT_ID"
}
EOF
)
SESSION_ID=$(jq -r '.id' <<< "$session")
ant beta:sessions create \
--agent "$COORDINATOR_ID" \
--environment-id "$ENVIRONMENT_ID"
session = client.beta.sessions.create(
agent=coordinator.id,
environment_id=environment.id,
)
const session = await client.beta.sessions.create({
agent: coordinator.id,
environment_id: environment.id,
});
var session = await client.Beta.Sessions.Create(new()
{
Agent = coordinator.ID,
EnvironmentID = environment.ID,
});
session, err := client.Beta.Sessions.New(ctx, anthropic.BetaSessionNewParams{
Agent: anthropic.BetaSessionNewParamsAgentUnion{
OfString: anthropic.String(coordinator.ID),
},
EnvironmentID: environment.ID,
})
if err != nil {
panic(err)
}
var session = client.beta().sessions().create(SessionCreateParams.builder()
.agent(coordinator.id())
.environmentId(environment.id())
.build());
$session = $client->beta->sessions->create(
agent: $coordinator->id,
environmentID: $environment->id,
);
session = client.beta.sessions.create(
agent: coordinator.id,
environment_id: environment.id
)
将代理连接到 MCP 服务器
MCP 服务器是代理范围的(每个代理定义声明自己的服务器和工具),而保险库凭据是会话范围的(会话创建时传递的 vault_ids 适用于每个线程)。对您的集成有两个影响:
- 要认证 MCP 服务器,请为所有代理使用的所有 MCP 服务器包含保险库凭据。
- 要限制代理的访问,请在其代理定义中仅声明其需要的服务器。
research_agent_id=$(curl --fail-with-body -sS "$BASE/v1/agents" "${H[@]}" --data @- <<'EOF' | jq -er '.id'
{
"name": "researcher",
"model": "claude-haiku-4-5",
"mcp_servers": [{"type": "url", "name": "github", "url": "https://api.githubcopilot.com/mcp/"}],
"tools": [{"type": "mcp_toolset", "mcp_server_name": "github"}]
}
EOF
)
coordinator_id=$(curl --fail-with-body -sS "$BASE/v1/agents" "${H[@]}" --data @- <<EOF | jq -er '.id'
{
"name": "coordinator",
"model": "claude-opus-4-7",
"tools": [{"type": "agent_toolset_20260401"}],
"multiagent": {
"type": "coordinator",
"agents": [{"type": "agent", "id": "$research_agent_id"}]
}
}
EOF
)
session_id=$(curl --fail-with-body -sS "$BASE/v1/sessions" "${H[@]}" --data @- <<EOF | jq -er '.id'
{
"agent": "$coordinator_id",
"environment_id": "$environment_id",
"vault_ids": ["$vault_id"]
}
EOF
)
echo "$session_id"
research_agent_id=$(ant beta:agents create --transform id --raw-output <<YAML
name: researcher
model: claude-haiku-4-5
mcp_servers:
- type: url
name: github
url: https://api.githubcopilot.com/mcp/
tools:
- type: mcp_toolset
mcp_server_name: github
YAML
)
coordinator_id=$(ant beta:agents create --transform id --raw-output <<YAML
name: coordinator
model: claude-opus-4-7
tools:
- type: agent_toolset_20260401
multiagent:
type: coordinator
agents:
- type: agent
id: $research_agent_id
YAML
)
session_id=$(ant beta:sessions create \
--agent "$coordinator_id" \
--environment-id "$environment_id" \
--vault-id "$vault_id" \
--transform id --raw-output)
echo "$session_id"
research_agent = client.beta.agents.create(
name="researcher",
model="claude-haiku-4-5",
mcp_servers=[
{"type": "url", "name": "github", "url": "https://api.githubcopilot.com/mcp/"},
],
tools=[{"type": "mcp_toolset", "mcp_server_name": "github"}],
)
coordinator = client.beta.agents.create(
name="coordinator",
model="claude-opus-4-7",
tools=[{"type": "agent_toolset_20260401"}],
multiagent={
"type": "coordinator",
"agents": [{"type": "agent", "id": research_agent.id}],
},
)
session = client.beta.sessions.create(
agent=coordinator.id,
environment_id=environment.id,
vault_ids=[vault.id],
)
print(session.id)
const researchAgent = await client.beta.agents.create({
name: "researcher",
model: "claude-haiku-4-5",
mcp_servers: [
{ type: "url", name: "github", url: "https://api.githubcopilot.com/mcp/" },
],
tools: [{ type: "mcp_toolset", mcp_server_name: "github" }],
});
const coordinator = await client.beta.agents.create({
name: "coordinator",
model: "claude-opus-4-7",
tools: [{ type: "agent_toolset_20260401" }],
multiagent: {
type: "coordinator",
agents: [{ type: "agent", id: researchAgent.id }],
},
});
const session = await client.beta.sessions.create({
agent: coordinator.id,
environment_id: environment.id,
vault_ids: [vault.id],
});
console.log(session.id);
var researchAgent = await client.Beta.Agents.Create(new()
{
Name = "researcher",
Model = BetaManagedAgentsModel.ClaudeHaiku4_5,
McpServers =
[
new()
{
Type = BetaManagedAgentsUrlMcpServerParamsType.Url,
Name = "github",
Url = "https://api.githubcopilot.com/mcp/",
},
],
Tools =
[
new BetaManagedAgentsMcpToolsetParams
{
Type = BetaManagedAgentsMcpToolsetParamsType.McpToolset,
McpServerName = "github",
},
],
});
var coordinator = await client.Beta.Agents.Create(new()
{
Name = "coordinator",
Model = BetaManagedAgentsModel.ClaudeOpus4_7,
Tools =
[
new BetaManagedAgentsAgentToolset20260401Params
{
Type = BetaManagedAgentsAgentToolset20260401ParamsType.AgentToolset20260401,
},
],
Multiagent = new()
{
Type = BetaManagedAgentsMultiagentParamsType.Coordinator,
Agents =
[
new BetaManagedAgentsAgentParams
{
Type = Anthropic.Models.Beta.Sessions.Type.Agent,
ID = researchAgent.ID,
},
],
},
});
var session = await client.Beta.Sessions.Create(new()
{
Agent = coordinator.ID,
EnvironmentID = environment.ID,
VaultIds = [vault.ID],
});
Console.WriteLine(session.ID);
researcher, err := client.Beta.Agents.New(ctx, anthropic.BetaAgentNewParams{
Name: "researcher",
Model: anthropic.BetaManagedAgentsModelConfigParams{ID: anthropic.BetaManagedAgentsModelClaudeHaiku4_5},
MCPServers: []anthropic.BetaManagedAgentsURLMCPServerParams{{
Type: anthropic.BetaManagedAgentsURLMCPServerParamsTypeURL,
Name: "github",
URL: "https://api.githubcopilot.com/mcp/",
}},
Tools: []anthropic.BetaAgentNewParamsToolUnion{{
OfMCPToolset: &anthropic.BetaManagedAgentsMCPToolsetParams{
Type: anthropic.BetaManagedAgentsMCPToolsetParamsTypeMCPToolset,
MCPServerName: "github",
},
}},
})
if err != nil {
panic(err)
}
coordinator, err := client.Beta.Agents.New(ctx, anthropic.BetaAgentNewParams{
Name: "coordinator",
Model: anthropic.BetaManagedAgentsModelConfigParams{ID: anthropic.BetaManagedAgentsModelClaudeOpus4_7},
Tools: []anthropic.BetaAgentNewParamsToolUnion{{
OfAgentToolset20260401: &anthropic.BetaManagedAgentsAgentToolset20260401Params{
Type: anthropic.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
},
}},
Multiagent: anthropic.BetaManagedAgentsMultiagentParams{
Type: anthropic.BetaManagedAgentsMultiagentParamsTypeCoordinator,
Agents: []anthropic.BetaManagedAgentsMultiagentRosterEntryParamsUnion{{
OfBetaManagedAgentsAgents: &anthropic.BetaManagedAgentsAgentParams{
Type: anthropic.BetaManagedAgentsAgentParamsTypeAgent,
ID: researcher.ID,
},
}},
},
})
if err != nil {
panic(err)
}
session, err := client.Beta.Sessions.New(ctx, anthropic.BetaSessionNewParams{
Agent: anthropic.BetaSessionNewParamsAgentUnion{
OfString: anthropic.String(coordinator.ID),
},
EnvironmentID: environment.ID,
VaultIDs: []string{vault.ID},
})
if err != nil {
panic(err)
}
fmt.Println(session.ID)
var researcher = client.beta().agents().create(
AgentCreateParams.builder()
.name("researcher")
.model(BetaManagedAgentsModel.CLAUDE_HAIKU_4_5)
.addMcpServer(BetaManagedAgentsUrlMcpServerParams.builder()
.name("github")
.type(BetaManagedAgentsUrlMcpServerParams.Type.URL)
.url("https://api.githubcopilot.com/mcp/")
.build())
.addTool(BetaManagedAgentsMcpToolsetParams.builder()
.type(BetaManagedAgentsMcpToolsetParams.Type.MCP_TOOLSET)
.mcpServerName("github")
.build())
.build()
);
var coordinator = client.beta().agents().create(
AgentCreateParams.builder()
.name("coordinator")
.model(BetaManagedAgentsModel.CLAUDE_OPUS_4_7)
.addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
.type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
.build())
.multiagent(BetaManagedAgentsMultiagentParams.builder()
.type(BetaManagedAgentsMultiagentParams.Type.COORDINATOR)
.addAgent(BetaManagedAgentsAgentParams.builder()
.type(BetaManagedAgentsAgentParams.Type.AGENT)
.id(researcher.id())
.build())
.build())
.build()
);
var session = client.beta().sessions().create(SessionCreateParams.builder()
.agent(coordinator.id())
.environmentId(environment.id())
.vaultIds(List.of(vault.id()))
.build());
IO.println(session.id());
$researchAgent = $client->beta->agents->create(
name: 'researcher',
model: 'claude-haiku-4-5',
mcpServers: [
['type' => 'url', 'name' => 'github', 'url' => 'https://api.githubcopilot.com/mcp/'],
],
tools: [
['type' => 'mcp_toolset', 'mcp_server_name' => 'github'],
],
);
$coordinator = $client->beta->agents->create(
name: 'coordinator',
model: 'claude-opus-4-7',
tools: [
['type' => 'agent_toolset_20260401'],
],
multiagent: [
'type' => 'coordinator',
'agents' => [
['type' => 'agent', 'id' => $researchAgent->id],
],
],
);
$session = $client->beta->sessions->create(
agent: $coordinator->id,
environmentID: $environment->id,
vaultIDs: [$vault->id],
);
echo "{$session->id}\n";
research_agent = client.beta.agents.create(
name: "researcher",
model: "claude-haiku-4-5",
mcp_servers: [
{type: "url", name: "github", url: "https://api.githubcopilot.com/mcp/"}
],
tools: [
{type: "mcp_toolset", mcp_server_name: "github"}
]
)
coordinator = client.beta.agents.create(
name: "coordinator",
model: "claude-opus-4-7",
tools: [
{type: "agent_toolset_20260401"}
],
multiagent: {
type: "coordinator",
agents: [
{type: "agent", id: research_agent.id}
]
}
)
session = client.beta.sessions.create(
agent: coordinator.id,
environment_id: environment.id,
vault_ids: [vault.id]
)
puts session.id
在此示例中,只有 researcher 声明了 GitHub MCP 服务器,因此协调器没有访问权限。会话的 vault_ids 为 researcher 的线程提供 GitHub 凭据。
如果代理的 MCP 调用在您声明服务器后认证失败,请确认凭据的 mcp_server_url 与代理的 mcp_servers[].url 完全匹配,包括协议和尾部斜杠。
线程
会话级事件流(/v1/sessions/:id/events/stream)被视为主线程,包含所有线程活动的浓缩视图。您不会看到子代理的完整活动,但会看到其工作的开始和结束,以及阻止事件(如工具权限请求)。
会话线程是您深入了解特定代理活动的地方。
会话 status 是所有代理活动的聚合;如果至少有一个线程是 running,那么整体会话状态也是 running。
最多支持 25 个并发线程。协调器可以调用名单中单个代理的多个副本,创建与一个 agent 关联的多个线程。
列出与会话关联的所有线程:
curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
| jq -r '.data[] | "[\(.agent.name)] \(.status)"'
ant beta:sessions:threads list --session-id "$SESSION_ID"
for thread in client.beta.sessions.threads.list(session.id):
print(f"[{thread.agent.name}] {thread.status}")
for await (const thread of client.beta.sessions.threads.list(session.id)) {
console.log(`[${thread.agent.name}] ${thread.status}`);
}
await foreach (var thread in (await client.Beta.Sessions.Threads.List(session.ID)).Paginate())
{
Console.WriteLine({{CONTENT}}quot;[{thread.Agent.Name}] {thread.Status}");
}
threads := client.Beta.Sessions.Threads.ListAutoPaging(ctx, session.ID, anthropic.BetaSessionThreadListParams{})
for threads.Next() {
thread := threads.Current()
fmt.Printf("[%s] %s\n", thread.Agent.Name, thread.Status)
}
if err := threads.Err(); err != nil {
panic(err)
}
for (var thread : client.beta().sessions().threads().list(session.id()).autoPager()) {
IO.println("[" + thread.agent().name() + "] " + thread.status());
}
foreach ($client->beta->sessions->threads->list($session->id)->pagingEachItem() as $thread) {
echo "[{$thread->agent->name}] {$thread->status}\n";
}
client.beta.sessions.threads.list(session.id).auto_paging_each do |thread|
puts "[#{thread.agent.name}] #{thread.status}"
end
完整列表包括主线程。主线程的 parent_thread_id 为 null。
发送带有 session_thread_id 的 user.interrupt 以停止特定线程。省略 session_thread_id 将针对主线程。
curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/events?beta=true" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-d "{\"events\": [{\"type\": \"user.interrupt\", \"session_thread_id\": \"$THREAD_ID\"}]}"
ant beta:sessions:events send \
--session-id "$SESSION_ID" \
--event "{type: user.interrupt, session_thread_id: $THREAD_ID}"
client.beta.sessions.events.send(
session.id,
events=[{"type": "user.interrupt", "session_thread_id": thread.id}],
)
await client.beta.sessions.events.send(session.id, {
events: [{ type: "user.interrupt", session_thread_id: thread.id }],
});
await client.Beta.Sessions.Events.Send(session.ID, new()
{
Events =
[
new BetaManagedAgentsUserInterruptEventParams
{
Type = BetaManagedAgentsUserInterruptEventParamsType.UserInterrupt,
SessionThreadID = thread.ID,
},
],
});
if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
OfUserInterrupt: &anthropic.BetaManagedAgentsUserInterruptEventParams{
Type: anthropic.BetaManagedAgentsUserInterruptEventParamsTypeUserInterrupt,
SessionThreadID: anthropic.String(thread.ID),
},
}},
}); err != nil {
panic(err)
}
client.beta().sessions().events().send(
session.id(),
EventSendParams.builder()
.addEvent(BetaManagedAgentsUserInterruptEventParams.builder()
.type(BetaManagedAgentsUserInterruptEventParams.Type.USER_INTERRUPT)
.sessionThreadId(thread.id())
.build())
.build());
$client->beta->sessions->events->send(
$session->id,
events: [
['type' => 'user.interrupt', 'session_thread_id' => $thread->id],
],
);
client.beta.sessions.events.send_(
session.id,
events: [{type: "user.interrupt", session_thread_id: thread.id}]
)
对于在 requires_action 上阻塞的子线程,中断会将每个待处理的工具调用标记为已拒绝,并直接重新发出 session.thread_status_idle(包含 stop_reason: end_turn);模型不会被采样。对于已经处于 idle 的线程,中断是无操作。
可选地在会话线程完成工作后归档它。这会释放一个线程以应对 25 线程限制。
curl -fsS -X POST "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/archive" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01"
ant beta:sessions:threads archive \
--session-id "$SESSION_ID" \
--thread-id "$THREAD_ID"
archived = client.beta.sessions.threads.archive(thread.id, session_id=session.id)
print(archived.status, archived.archived_at)
const archived = await client.beta.sessions.threads.archive(thread.id, {
session_id: session.id,
});
console.log(archived.status, archived.archived_at);
var archived = await client.Beta.Sessions.Threads.Archive(thread.ID, new() { SessionID = session.ID });
Console.WriteLine({{CONTENT}}quot;{archived.Status} {archived.ArchivedAt}");
archived, err := client.Beta.Sessions.Threads.Archive(ctx, thread.ID, anthropic.BetaSessionThreadArchiveParams{
SessionID: session.ID,
})
if err != nil {
panic(err)
}
fmt.Println(archived.Status, archived.ArchivedAt)
var archived = client.beta().sessions().threads().archive(
thread.id(),
ThreadArchiveParams.builder()
.sessionId(session.id())
.build());
IO.println(archived.status() + " " + archived.archivedAt());
$archived = $client->beta->sessions->threads->archive($thread->id, sessionID: $session->id);
echo "{$archived->status} {$archived->archivedAt->format(DATE_ATOM)}\n";
archived = client.beta.sessions.threads.archive(thread.id, session_id: session.id)
puts "#{archived.status} #{archived.archived_at}"
归档只有在线程处于 idle 状态时才能成功。如果线程正在运行或在 requires_action 上阻塞,请先中断它:
# Interrupt the thread, then archive it
curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/events?beta=true" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-d "{\"events\": [{\"type\": \"user.interrupt\", \"session_thread_id\": \"$THREAD_ID\"}]}"
curl -fsS -X POST "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/archive" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01"
ant beta:sessions:events send \
--session-id "$SESSION_ID" \
--event "{type: user.interrupt, session_thread_id: $THREAD_ID}"
ant beta:sessions:threads archive \
--session-id "$SESSION_ID" \
--thread-id "$THREAD_ID"
client.beta.sessions.events.send(
session.id,
events=[{"type": "user.interrupt", "session_thread_id": thread.id}],
)
archived = client.beta.sessions.threads.archive(thread.id, session_id=session.id)
print(archived.status, archived.archived_at)
await client.beta.sessions.events.send(session.id, {
events: [{ type: "user.interrupt", session_thread_id: thread.id }],
});
const archived = await client.beta.sessions.threads.archive(thread.id, {
session_id: session.id,
});
console.log(archived.status, archived.archived_at);
await client.Beta.Sessions.Events.Send(session.ID, new()
{
Events =
[
new BetaManagedAgentsUserInterruptEventParams
{
Type = BetaManagedAgentsUserInterruptEventParamsType.UserInterrupt,
SessionThreadID = thread.ID,
},
],
});
archived = await client.Beta.Sessions.Threads.Archive(thread.ID, new() { SessionID = session.ID });
Console.WriteLine({{CONTENT}}quot;{archived.Status} {archived.ArchivedAt}");
if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
OfUserInterrupt: &anthropic.BetaManagedAgentsUserInterruptEventParams{
Type: anthropic.BetaManagedAgentsUserInterruptEventParamsTypeUserInterrupt,
SessionThreadID: anthropic.String(thread.ID),
},
}},
}); err != nil {
panic(err)
}
archived, err := client.Beta.Sessions.Threads.Archive(ctx, thread.ID, anthropic.BetaSessionThreadArchiveParams{
SessionID: session.ID,
})
if err != nil {
panic(err)
}
fmt.Println(archived.Status, archived.ArchivedAt)
client.beta().sessions().events().send(
session.id(),
EventSendParams.builder()
.addEvent(BetaManagedAgentsUserInterruptEventParams.builder()
.type(BetaManagedAgentsUserInterruptEventParams.Type.USER_INTERRUPT)
.sessionThreadId(thread.id())
.build())
.build());
archived = client.beta().sessions().threads().archive(
thread.id(),
ThreadArchiveParams.builder()
.sessionId(session.id())
.build());
IO.println(archived.status() + " " + archived.archivedAt());
$client->beta->sessions->events->send(
$session->id,
events: [['type' => 'user.interrupt', 'session_thread_id' => $thread->id]],
);
$archived = $client->beta->sessions->threads->archive($thread->id, sessionID: $session->id);
echo "{$archived->status} {$archived->archivedAt->format(DATE_ATOM)}\n";
client.beta.sessions.events.send_(
session.id,
events: [{type: "user.interrupt", session_thread_id: thread.id}]
)
archived = client.beta.sessions.threads.archive(thread.id, session_id: session.id)
puts "#{archived.status} #{archived.archived_at}"
主线程事件
这些事件在 /v1/sessions/:id/events/stream 的主线上显示多代理活动。
| 类型 | 描述 |
|---|---|
session.thread_created | 线程已创建。包含 session_thread_id 和 agent_name。 |
session.thread_status_running | 线程开始了活动。 |
session.thread_status_idle | 与线程关联的代理正在等待输入。包含一个 stop_reason,指示代理停止的原因。 |
session.thread_status_terminated | 线程已归档或遇到终端错误。 |
agent.thread_message_received | 代理将其结果传递给协调器。包含 from_session_thread_id、from_agent_name 和 content。 |
agent.thread_message_sent | 协调器向另一个代理发送后续消息。包含 to_session_thread_id、to_agent_name 和 content。 |
会话线程事件
关键事件会被代理到主线程。但是,您可能仍然想调查特定代理的推理和工具调用。为此,请从关联的会话线程流式传输或列出事件。
curl -fsSN "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/stream?beta=true" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" |
while IFS= read -r line; do
[[ $line == data:* ]] || continue
json=${line#data: }
case $(jq -r '.type' <<<"$json") in
agent.message)
printf '%s' "$(jq -j '.content[] | select(.type == "text") | .text' <<<"$json")"
;;
session.thread_status_idle)
break
;;
esac
done
ant beta:sessions:threads:events stream \
--session-id "$SESSION_ID" \
--thread-id "$THREAD_ID"
with client.beta.sessions.threads.events.stream(
thread.id,
session_id=session.id,
) as stream:
for event in stream:
match event.type:
case "agent.message":
for block in event.content:
if block.type == "text":
print(block.text, end="")
case "session.thread_status_idle":
break
const stream = await client.beta.sessions.threads.events.stream(thread.id, {
session_id: session.id,
});
for await (const event of stream) {
if (event.type === "agent.message") {
for (const block of event.content) {
if (block.type === "text") {
process.stdout.write(block.text);
}
}
} else if (event.type === "session.thread_status_idle") {
break;
}
}
await foreach (var evt in client.Beta.Sessions.Threads.Events.StreamStreaming(thread.ID, new() { SessionID = session.ID }))
{
if (evt.Value is BetaManagedAgentsAgentMessageEvent message)
{
foreach (var block in message.Content)
{
if (block.Type == "text")
{
Console.Write(block.Text);
}
}
}
else if (evt.Value is BetaManagedAgentsSessionThreadStatusIdleEvent)
{
break;
}
}
stream := client.Beta.Sessions.Threads.Events.StreamEvents(ctx, thread.ID, anthropic.BetaSessionThreadEventStreamParams{
SessionID: session.ID,
})
defer stream.Close()
loop:
for stream.Next() {
event := stream.Current()
switch event.Type {
case "agent.message":
for _, block := range event.AsAgentMessage().Content {
if block.Type == "text" {
fmt.Print(block.Text)
}
}
case "session.thread_status_idle":
break loop
}
}
if err := stream.Err(); err != nil {
panic(err)
}
try (var streamResponse = client.beta().sessions().threads().events().streamStreaming(
thread.id(),
EventStreamParams.builder().sessionId(session.id()).build()
)) {
for (var event : (Iterable<BetaManagedAgentsStreamSessionThreadEvents>) streamResponse.stream()::iterator) {
if (event.isAgentMessage()) {
for (var block : event.asAgentMessage().content()) {
IO.print(block.text());
}
} else if (event.isSessionThreadStatusIdle()) {
break;
}
}
}
$stream = $client->beta->sessions->threads->events->streamStream(
$thread->id,
sessionID: $session->id,
);
foreach ($stream as $event) {
if ($event->type === 'agent.message') {
foreach ($event->content as $block) {
if ($block->type === 'text') {
echo $block->text;
}
}
} elseif ($event->type === 'session.thread_status_idle') {
break;
}
}
client.beta.sessions.threads.events.stream_events(thread.id, session_id: session.id).each do |event|
case event.type
when :"agent.message"
event.content.each do |block|
print block.text if block.type == :text
end
when :"session.thread_status_idle"
break
end
end
列出所有过去的会话线程事件以获取完整历史。
curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/events" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
| jq -r '.data[] | "[\(.type)] \(.processed_at)"'
ant beta:sessions:threads:events list \
--session-id "$SESSION_ID" \
--thread-id "$THREAD_ID"
for event in client.beta.sessions.threads.events.list(
thread.id,
session_id=session.id,
):
print(f"[{event.type}] {event.processed_at}")
for await (const event of client.beta.sessions.threads.events.list(thread.id, {
session_id: session.id,
})) {
console.log(`[${event.type}] ${event.processed_at}`);
}
var page = await client.Beta.Sessions.Threads.Events.List(thread.ID, new() { SessionID = session.ID });
await foreach (var evt in page.Paginate())
{
Console.WriteLine({{CONTENT}}quot;[{evt.Type}] {evt.ProcessedAt}");
}
pager := client.Beta.Sessions.Threads.Events.ListAutoPaging(ctx, thread.ID, anthropic.BetaSessionThreadEventListParams{
SessionID: session.ID,
})
for pager.Next() {
event := pager.Current()
fmt.Printf("[%s] %s\n", event.Type, event.ProcessedAt)
}
if err := pager.Err(); err != nil {
panic(err)
}
for (var event : client.beta().sessions().threads().events().list(
thread.id(),
EventListParams.builder().sessionId(session.id()).build()
).autoPager()) {
var json = (Map<String, JsonValue>) event._json().orElseThrow().asObject().orElseThrow();
var type = json.get("type").asStringOrThrow();
var processedAt = json.containsKey("processed_at")
? json.get("processed_at").asStringOrThrow()
: "pending";
IO.println("[" + type + "] " + processedAt);
}
foreach (
$client->beta->sessions->threads->events->list(
$thread->id,
sessionID: $session->id,
)->pagingEachItem() as $event
) {
echo "[{$event->type}] {$event->processedAt->format(DATE_RFC3339)}\n";
}
client.beta.sessions.threads.events.list(
thread.id,
session_id: session.id
).auto_paging_each do |event|
puts "[#{event.type}] #{event.processed_at}"
end
工具权限和自定义工具
如果子代理需要您的客户端提供某些内容,例如运行 always_ask 工具的权限,或自定义工具的结果,该事件会交叉发布到主线程,其中 session_thread_id 标识原始会话线程。
{
"type": "session.thread_status_idle",
"id": "sevt_01ABC...",
"session_thread_id": "sth_01DEF...",
"agent_name": "code-reviewer",
"stop_reason": {
"type": "requires_action",
"event_ids": ["toolu_01XYZ..."]
}
}
发布 user.tool_confirmation(带 tool_use_id)或 user.custom_tool_result(带 custom_tool_use_id);服务器会自动将响应路由到正确的线程。
以下示例扩展了工具确认处理器以路由回复。同样的模式适用于 user.custom_tool_result。
while IFS= read -r event_id; do
jq -n --arg id "$event_id" \
'{events: [{type: "user.tool_confirmation", tool_use_id: $id, result: "allow"}]}' |
curl -fsS "https://api.anthropic.com/v1/sessions/$SESSION_ID/events?beta=true" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-d @-
done < <(jq -r '.stop_reason.event_ids[]' <<<"$data")
# This workflow does not translate well to a one-off shell command.
# Use one of the SDK examples in this code group instead.
for event_id in stop.event_ids:
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.tool_confirmation",
"tool_use_id": event_id,
"result": "allow",
}
],
)
for (const eventId of stop.event_ids) {
await client.beta.sessions.events.send(session.id, {
events: [
{
type: "user.tool_confirmation",
tool_use_id: eventId,
result: "allow",
},
],
});
}
foreach (var eventId in requiresAction.EventIds)
{
await client.Beta.Sessions.Events.Send(session.ID, new()
{
Events =
[
new BetaManagedAgentsUserToolConfirmationEventParams
{
Type = BetaManagedAgentsUserToolConfirmationEventParamsType.UserToolConfirmation,
ToolUseID = eventId,
Result = BetaManagedAgentsUserToolConfirmationEventParamsResult.Allow,
},
],
});
}
for _, eventID := range stopReason.EventIDs {
params := anthropic.BetaManagedAgentsUserToolConfirmationEventParams{
Type: anthropic.BetaManagedAgentsUserToolConfirmationEventParamsTypeUserToolConfirmation,
ToolUseID: eventID,
Result: anthropic.BetaManagedAgentsUserToolConfirmationEventParamsResultAllow,
}
if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
Events: []anthropic.BetaManagedAgentsEventParamsUnion{{OfUserToolConfirmation: ¶ms}},
}); err != nil {
panic(err)
}
}
for (var eventId : pendingToolUseIds) {
client.beta().sessions().events().send(
session.id(),
EventSendParams.builder()
.addEvent(BetaManagedAgentsUserToolConfirmationEventParams.builder()
.toolUseId(eventId)
.result(BetaManagedAgentsUserToolConfirmationEventParams.Result.ALLOW)
.build())
.build()
);
}
foreach ($event->stopReason->eventIDs as $eventId) {
$client->beta->sessions->events->send($session->id, events: [[
'type' => 'user.tool_confirmation',
'tool_use_id' => $eventId,
'result' => 'allow',
]]);
}
event_ids.each do |event_id|
client.beta.sessions.events.send_(session.id, events: [{
type: "user.tool_confirmation",
tool_use_id: event_id,
result: "allow"
}])
end