工具调用
Agent 如何报告工具调用执行
工具调用代表语言模型请求 Agent 在会话期间执行的操作。当 LLM 确定需要与外部系统交互(如读取文件、运行代码或获取数据)时,它会生成由 Agent 代为执行的工具调用。
Agent 通过 session/update 通知报告工具调用,允许客户端向用户显示实时进度和结果。
工具调用更新可能在 Agent 报告 idle 时到达。它们不会改变状态。
虽然 Agent 处理实际执行,但它们可以使用客户端中介的交互(如权限请求)来提供更丰富、更集成的体验。
报告
当语言模型请求工具调用时,Agent 应该 通过 tool_call_update 向客户端报告:
{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"sessionId": "sess_abc123def456",
"update": {
"sessionUpdate": "tool_call_update",
"toolCallId": "call_001",
"title": "Reading configuration file",
"kind": "read",
"status": "pending"
}
}
}
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
toolCallId | ToolCallId | 是 | 此工具调用在会话内的唯一标识符 |
title | string | - | 描述工具正在做什么的人类可读标题。Agent 应该 在首次报告 toolCallId 时包含标题。 |
kind | ToolKind | - | 被调用工具的类别。可选值:read、edit、delete、move、search、execute、think、fetch、other。工具类别帮助客户端选择适当的图标并优化工具执行进度的显示方式。当客户端可以回退到通用工具显示行为时,可以使用自定义或未来的工具类别。自定义工具类别 必须 以 _ 开头。未知的非下划线工具类别保留给未来的 ACP 变体。 |
status | ToolCallStatus | - | 当前执行状态(默认为 pending) |
content | ToolCallContent[] | - | 工具调用产生的内容 |
locations | ToolCallLocation[] | - | 此工具调用影响的文件位置 |
rawInput | object | - | 发送给工具的原始输入参数 |
rawOutput | object | - | 工具返回的原始输出 |
tool_call_update 通知是以 toolCallId 为键的 upsert。对于已有的工具调用,除 _meta 外的字段在省略时保留先前值不变,为 null 时显式清除或取消设置值,发送具体值时替换先前值。对于新的 toolCallId,省略的字段使用客户端默认值。content 和 locations 作为整个数组替换;发送 [] 或 null 清除它们。对于 _meta,省略字段保持不变,设置为 null 清除。当工具增量产生内容且客户端应追加每个项目而非替换整个 content 集合时,使用 tool_call_content_chunk。仅显示的终端字节使用 terminal_output_chunk。
更新
工具执行时,Agent 发送更新以报告进度和结果。
{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"sessionId": "sess_abc123def456",
"update": {
"sessionUpdate": "tool_call_update",
"toolCallId": "call_001",
"status": "in_progress",
"content": [
{
"type": "content",
"content": {
"type": "text",
"text": "Found 3 configuration files..."
}
}
]
}
}
}
更新中除 toolCallId 外的所有字段都是可选的。只需包含正在更改的字段。
流式内容
工具执行时,Agent 可以 使用 tool_call_content_chunk 流式传输单个内容项目:
{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"sessionId": "sess_abc123def456",
"update": {
"sessionUpdate": "tool_call_content_chunk",
"toolCallId": "call_001",
"content": {
"type": "content",
"content": {
"type": "text",
"text": "Found 3 configuration files..."
}
}
}
}
}
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
toolCallId | ToolCallId | 是 | 此内容所属工具调用的 ID |
content | ToolCallContent | 是 | 工具调用产生的单个内容项目 |
客户端按每个 toolCallId 的接收顺序应用 tool_call_update 和 tool_call_content_chunk 通知。tool_call_content_chunk 将其 content 项目追加到当前工具调用内容中。后续带 content 的 tool_call_update 替换该工具调用当前存储的所有内容,包括从先前分块累积的内容。后续分块追加到该替换内容。带 content: [] 或 content: null 的 tool_call_update 清除工具调用内容。tool_call_content_chunk 的 _meta(存在时)是分块作用域的。
请求权限
Agent 可以 在继续操作(如执行工具调用)之前,通过调用 session/request_permission 方法向用户请求权限:
{
"jsonrpc": "2.0",
"id": 5,
"method": "session/request_permission",
"params": {
"sessionId": "sess_abc123def456",
"title": "Approve file edit?",
"description": "Allow the agent to edit src/main.rs?",
"subject": {
"type": "tool_call",
"toolCall": {
"toolCallId": "call_001"
}
},
"options": [
{
"optionId": "allow-once",
"name": "Allow once",
"kind": "allow_once"
},
{
"optionId": "reject-once",
"name": "Reject",
"kind": "reject_once"
}
]
}
}
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
sessionId | SessionId | 是 | 此请求的会话 ID |
title | string | 是 | 权限提示中显示的标题。此文本独立于任何 toolCall 更新,不替换工具调用标题。 |
description | string | - | 权限提示中显示的可选说明。此文本独立于任何 toolCall 更新,不替换工具调用内容。省略或 null 表示未提供单独的权限描述。 |
subject | RequestPermissionSubject | - | 关于需要权限的操作的可选结构化上下文。对于工具调用,使用 type: "tool_call" 和包含操作详情的 toolCall 更新。省略或 null 表示未提供结构化主题。可能出现自定义或未来的主题类型。不理解主题的客户端在代理时应保留它,并使用通用提示字段或根据策略拒绝。 |
options | PermissionOption[] | 是 | 供用户选择的可用权限选项。必须包含至少一个选项。 |
对于提议的命令,主题可以直接描述命令:
{
"title": "Run the test suite?",
"subject": {
"type": "command",
"command": "cargo test",
"cwd": "/home/user/project",
"toolCallId": "call_001",
"terminalId": "term_001"
},
"options": [
{
"optionId": "allow-once",
"name": "Allow once",
"kind": "allow_once"
}
]
}
对于 type: "command",command 和 cwd 是必需的,cwd 必须 为绝对路径。toolCallId、terminalId 和 _meta 是可选且可为 null 的;省略和 null 是等效的,表示未提供该值。这些 ID 仅将权限与显示状态关联,在执行开始前可能不可用。选择允许选项授权 Agent 执行命令;它不要求客户端执行任何操作。
客户端以用户的决定响应:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"outcome": {
"outcome": "selected",
"optionId": "allow-once"
}
}
}
客户端 可以 根据用户设置自动允许或拒绝权限请求。
如果当前活动工作被取消,客户端 必须 以 "cancelled" 结果响应:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"outcome": {
"outcome": "cancelled"
}
}
}
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
outcome | RequestPermissionOutcome | 是 | 用户的决定。已知结果有活动工作被取消时的 cancelled,以及带有所选权限选项 optionId 的 selected。可能出现自定义或未来的结果;不理解结果的 Agent 不得 将其视为批准。 |
权限选项
提供给客户端的每个权限选项包含:
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
optionId | string | 是 | 此选项的唯一标识符 |
name | string | 是 | 要向用户显示的人类可读标签 |
kind | PermissionOptionKind | 是 | 帮助客户端为每个选项选择适当图标和 UI 处理的提示。可选值:allow_once、allow_always、reject_once、reject_always。自定义或未来的权限选项类别可用作 UI 提示。自定义类别 必须 以 _ 开头。未知的非下划线类别保留给未来的 ACP 变体。不理解类别的客户端应保留该值并使用通用的权限选项处理。 |
状态
工具调用在其生命周期中经历不同的状态:
pending- 工具调用尚未开始运行,因为输入正在流式传输或等待批准in_progress- 工具调用当前正在运行completed- 工具调用成功完成failed- 工具调用失败并出错cancelled- 工具调用在完成前被取消
当客户端可以显示通用进度状态时,可以使用自定义或未来的状态值。自定义状态值 必须 以 _ 开头;未知的非下划线状态保留给未来的 ACP 变体。
内容
工具调用可以产生不同类型的内容:工具调用内容 type 值也可以是自定义或未来变体。实现应在存储、重放、代理或转发工具调用时保留未知内容负载,否则渲染通用内容项目或在无安全显示可用时忽略该项目。
常规内容
标准内容块,如文本、图像或资源:
{
"type": "content",
"content": {
"type": "text",
"text": "Analysis complete. Found 3 issues."
}
}
仅显示终端
终端内容项目通过 ID 引用 Agent 拥有的终端:
{
"type": "terminal",
"terminalId": "term_001"
}
该项目仅为显示锚点。terminalId 是必需的。可选可为 null 的 _meta 作用域限定于此内容项目;省略和 null 都表示未提供项目元数据。terminalId 在会话内唯一,在终端生命周期内保持稳定,且 不得 重用于不同的终端。它独立于 toolCallId,即使 Agent 对两者使用相同的字符串。引用和终端的会话更新可能以任意顺序到达,因此客户端为首次出现的 terminalId 保留状态。
Agent 使用 terminal_update 创建和更新已存储的终端状态:
{
"sessionUpdate": "terminal_update",
"terminalId": "term_001",
"command": "cargo test",
"cwd": "/home/user/project",
"output": {
"data": "cnVubmluZyB0ZXN0cw0K"
},
"exitStatus": {
"exitCode": 0,
"signal": null
}
}
terminal_update 是以必需 terminalId 为键的 upsert。其他字段是补丁:省略保留先前值不变,null 清除它,具体值替换它。首次出现的 ID 上,省略的字段以未知或空开始。
-
command描述正在运行的命令。Agent 应该 在首次更新时提供它(如适用)。 -
cwd是命令的工作目录,提供时 必须 为绝对路径。 -
output是权威的替换快照。其必需的data是 RFC 4648 base64 编码字节,JSON Schema 为contentEncoding: "base64"。具体快照是 Agent 希望客户端在该时间点为终端保留的完整字节序列。它替换所有先前存储的字节;客户端 不得 将先前快照中的字节合并或拼接进去。可选可为 null 的output._meta作用域限定于该快照;省略和null都表示未提供快照元数据。 -
具体的
exitStatus将终端标记为已退出。其可选可为 null 的exitCode和signal报告已知的退出信息。其可选可为 null 的_meta作用域限定于该退出信息。对于所有三个字段,省略和null都表示未提供该值。常规 POSIX 信号名称包括SIGTERM、SIGKILL和SIGINT;其他平台可能使用平台特定的名称。终端退出和工具调用状态是独立的。 -
顶层
_meta是终端作用域的,遵循相同的补丁语义。
例如,被 POSIX 终止信号终止的进程可以报告 "exitStatus": { "signal": "SIGTERM" }。
对于实时输出,Agent 发送 terminal_output_chunk:
{
"sessionUpdate": "terminal_output_chunk",
"terminalId": "term_001",
"data": "cGFzc2VkDQo="
}
terminalId 和 data 是必需的。每个 data 值是独立的 RFC 4648 base64 编码字节块,JSON Schema 为 contentEncoding: "base64"。客户端分别解码每个块并按该 terminalId 的接收顺序追加解码后的字节;它们 不得 在解码前拼接编码字符串。块边界可能分割 UTF-8 代码点或终端转义序列,因此解码器跨块保留解析器状态。可选可为 null 的 _meta 是分块作用域的;省略和 null 都表示未提供分块元数据。
差异
以差异形式显示的文件修改。差异始终包含结构化文件更改,可选包含可渲染的补丁文本。
changes 对受影响的绝对路径和操作具有权威性。patch(存在时)为部分或全部更改提供可渲染文本,且 必须 与 changes 一致。Agent 应该 在可行时提供 patch。客户端 必须 处理 patch 被省略或为 null 的差异。
{
"type": "diff",
"changes": [
{
"operation": "modify",
"path": "/home/user/project/src/config.json",
"fileType": "text",
"mimeType": "application/json"
}
],
"patch": {
"format": "git_patch",
"text": "diff --git /home/user/project/src/config.json /home/user/project/src/config.json\n--- /home/user/project/src/config.json\n+++ /home/user/project/src/config.json\n@@ -1,3 +1,3 @@\n {\n- \"debug\": false\n+ \"debug\": true\n }\n"
}
}
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
changes | DiffChange[] | 是 | 此差异描述的结构化文件更改。 |
patch | DiffPatch | - | 可选的可渲染补丁文本。Agent 应该 在可行时提供。省略或 null 表示未提供补丁文本。 |
patch.format / patch.text
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
patch.format | string | 是 | 补丁格式。git_patch 是唯一定义的 ACP 值,是 Git 的 --patch (-p) 文本格式中的一个或多个 diff --git 段。路径 必须 为绝对路径。不得 包含周围的提交元数据和邮件信封。 |
patch.text | string | 是 | 以 patch.format 命名的格式的可渲染补丁文本。 |
changes[]
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
changes[].operation | string | 是 | 文件操作:add、delete、modify、move 或 copy。 |
changes[].path | string | 是 | 操作后的绝对路径。对于删除,这是被删除的路径。 |
changes[].oldPath | string | - | 操作前的绝对路径。move 和 copy 必需。 |
changes[].fileType | string | - | 可选文件类型:text、binary、directory 或 symlink。 |
changes[].mimeType | string | - | 可选的文件内容 MIME 类型。 |
当没有有用的文本补丁时省略 patch,例如同路径的二进制更新或符号链接目标更改:
{
"type": "diff",
"changes": [
{
"operation": "modify",
"path": "/home/user/project/assets/logo.png",
"fileType": "binary",
"mimeType": "image/png"
}
]
}
跟随 Agent
工具调用可以报告它们正在处理的文件位置,允许客户端跟随 Agent 的活动并在编辑器中突出显示相关区域。每个位置指定一个文件路径和可选的行范围。