# Agent Bidi / RunSSE 协议消息参考

本文描述 Agent Bidi / RunSSE 链路中的消息功能、字段语义和消息之间的关联关系。

本文是协议参考，不描述服务端或客户端的内部实现。字段定义以当前 `internal/backend/cursor/proto/agent_v1.proto` 和 `internal/backend/cursor/proto/aiserver_v1.proto` 为准。

范围包括 BidiAppend / RunSSE 传输封装、`AgentClientMessage` 的全部顶层分支、`AgentServerMessage` 的全部顶层分支，以及这些分支直接关联的主要请求、响应和控制消息。工具专属的 Args / Result 类型按功能归类，不展开为具体执行流程。

## 1. 协议概览

该协议将一次 Agent 通信拆成两条方向相反的通道：

- `BidiAppend`：客户端向服务端追加消息。
- `RunSSE`：服务端持续向客户端返回消息。

两条通道通过同一个 `request_id` 关联。

```text
客户端                                      服务端
  |                                           |
  | BidiAppend(request_id, append_seqno, data)|
  |------------------------------------------>|
  |                                           |
  | RunSSE(request_id)                        |
  |------------------------------------------>|
  |                                           |
  |       stream AgentServerMessage           |
  |<------------------------------------------|
```

### 1.1 主要关联标识

| 标识 | 范围 | 功能 |
| --- | --- | --- |
| `conversation_id` | 会话 | 标识一个可持续多轮的 Agent 会话。 |
| `request_id` | 请求流 | 关联 BidiAppend、RunSSE 和一次活跃请求。 |
| `run_id` | 运行 | 独立标识一次 Agent Run；不得假定它与 `request_id` 等值。 |
| `message_id` | 用户消息 | 标识一条用户输入。 |
| `model_call_id` | 模型调用 | 标识一次具体的模型调用或 provider pass。 |
| `call_id` / `tool_call_id` | 工具调用 | 标识模型发起的一次工具调用。 |
| `id` | 桥接消息 | 关联 Exec、Interaction 或 KV 的请求和响应。 |
| `exec_id` | 客户端执行 | 标识一次客户端执行任务，可跨多个流式消息。 |
| `append_seqno` | Bidi 请求流 | 表示同一 `request_id` 下客户端上行消息的顺序。 |

### 1.2 Connect 流式帧封装

RunSSE 中的每条消息都位于 Connect 流式帧中。帧由固定 5 字节帧头和消息载荷组成：

| 部分 | 长度 | 功能 |
| --- | --- | --- |
| `flags` | 1 字节 | 描述压缩和流结束状态。 |
| `length` | 4 字节 | 使用大端序表示后续载荷的字节数，不包含 5 字节帧头。 |
| `payload` | `length` 字节 | 普通帧中是 protobuf 消息；流结束帧中是结束状态。 |

`flags` 属于 Connect 传输层，不是 `AgentServerMessage` 或其他 protobuf 消息的字段。当前使用的标志位为：

| 标志 | 含义 |
| --- | --- |
| `0x00` | 普通、未压缩的数据帧。 |
| `0x01` | 压缩的数据帧，载荷需要按照流声明的压缩算法解压后再解析。 |
| `0x02` | 流结束帧，载荷表示 EndStream 状态，不应按业务 protobuf 消息解析。 |

这些值按 bit 表达：最低位 `0x01` 表示压缩，次低位 `0x02` 表示流结束，其余 bit 为保留位。因此，判断帧类型时应读取标志位，而不是把 `flags` 当作 protobuf 枚举。

例如下面的 RunSSE 帧：

```json
{
  "kind": "interaction_update",
  "messageType": "agent.v1.AgentServerMessage",
  "flags": "0x00",
  "length": 4,
  "compressed": false,
  "endStream": false,
  "message": {
    "interaction_update": {
      "heartbeat": {}
    }
  }
}
```

它表示载荷是一个长度为 4 字节、未压缩且尚未结束流的 `AgentServerMessage`。`heartbeat` 消息很小，使用 `0x00` 是正常情况；较大的业务消息可能使用 `0x01`。

## 2. BidiAppend 传输消息

### 2.1 `BidiAppendRequest`

功能：向指定请求流追加一条客户端消息。

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `data` | `string` | 十六进制编码的 `AgentClientMessage` protobuf 数据。 |
| `request_id` | `BidiRequestId` | 指定消息所属的请求流。 |
| `append_seqno` | `int64` | 指定消息在当前请求流中的追加顺序。 |
| `data_binary` | `bytes` | 二进制形式的消息载荷。 |

约束：

- `data` 与 `data_binary` 表达的是消息载荷，不应同时承载语义不同的消息。
- `append_seqno` 只在同一个 `request_id` 内比较。
- 解码后的根消息必须是 `AgentClientMessage`。

### 2.2 `BidiAppendResponse`

功能：确认本次 append 请求已经被接收。

该消息没有业务字段。它只确认 unary 请求本身，不代表 Agent Run 已经完成。

### 2.3 `BidiRequestId`

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `request_id` | `string` | 标识 BidiAppend 与 RunSSE 共享的请求流。 |

## 3. 客户端上行根消息

### 3.1 `AgentClientMessage`

功能：封装一条客户端到服务端的 Agent 消息。

`message` 是 `oneof`，一条消息只能选择以下一个分支：

| 分支 | 消息类型 | 功能 |
| --- | --- | --- |
| `run_request` | `AgentRunRequest` | 启动或恢复一次 Agent Run。 |
| `exec_client_message` | `ExecClientMessage` | 返回客户端工具执行的数据或结果。 |
| `kv_client_message` | `KvClientMessage` | 返回 blob 读取或写入结果。 |
| `conversation_action` | `ConversationAction` | 追加会话动作，例如继续、取消或执行计划。 |
| `exec_client_control_message` | `ExecClientControlMessage` | 返回客户端执行通道的控制事件。 |
| `interaction_response` | `InteractionResponse` | 回答服务端发起的用户交互请求。 |
| `client_heartbeat` | `ClientHeartbeat` | 表示客户端连接仍然活跃。 |
| `prewarm_request` | `PrewarmRequest` | 提前准备会话、模型和上下文。 |

## 4. `AgentRunRequest`

功能：携带启动或恢复 Agent Run 所需的会话状态、动作、模型与能力信息。

### 4.1 核心字段

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `conversation_state` | `ConversationStateStructure` | 客户端掌握的会话 checkpoint。 |
| `action` | `ConversationAction` | 本次 Run 要执行的会话动作。 |
| `model_details` | `ModelDetails` | 旧式或展示用途的模型信息。 |
| `requested_model` | `RequestedModel` | 本次实际请求的模型、参数和凭据。 |
| `conversation_id` | `string?` | 本次 Run 所属会话。 |
| `run_id` | `string?` | 客户端分配的 Run 标识。 |

### 4.2 工具和上下文字段

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `mcp_tools` | `McpTools` | 本次 Run 可用的 MCP 工具定义。 |
| `mcp_file_system_options` | `McpFileSystemOptions?` | MCP 文件系统能力和描述符。 |
| `skill_options` | `SkillOptions?` | 可用技能及技能加载选项。 |
| `custom_system_prompt` | `string?` | 调用方提供的自定义系统提示。 |
| `exclude_workspace_context` | `bool?` | 是否排除工作区上下文。 |
| `pre_fetched_blobs` | `PreFetchedBlob[]` | 调用前已经取得的 blob 内容。 |

### 4.3 模式和子 Agent 字段

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `subagent_type_name` | `string?` | 当前 Run 使用的子 Agent 类型。 |
| `selected_subagent_models` | `RequestedModel[]` | 为子 Agent 选择的模型。 |
| `selected_subagent_model_details` | `ModelDetails[]` | 子 Agent 模型的展示信息。 |
| `subagent_model_overrides` | `SubagentModelOverride[]` | 按子 Agent 类型覆盖模型选择。 |
| `can_create_cloud_subagents` | `bool?` | 客户端是否允许创建云端子 Agent。 |
| `suppress_subagent_progress_update_tool` | `bool?` | 是否隐藏子 Agent 进度更新工具。 |
| `conversation_group_id` | `string?` | 将多个相关会话归入同一组。 |

### 4.4 客户端能力字段

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `suggest_next_prompt` | `bool?` | 是否请求生成下一条提示建议。 |
| `harness` | `string?` | 标识调用方所使用的 Agent harness。 |
| `dev_raw_model_slug` | `string?` | 开发模式下使用的原始模型标识。 |
| `client_supports_inline_images` | `bool?` | 客户端是否支持内联图片。 |
| `client_supports_send_to_user` | `bool?` | 客户端是否支持 send-to-user 能力。 |
| `computer_use_coordinate_mode` | `string?` | Computer Use 坐标系模式。 |

## 5. `PrewarmRequest`

功能：提前提供模型、会话状态和能力声明，使后续正式 Run 可以复用已经准备好的上下文。

其主要字段与 `AgentRunRequest` 相同，但没有直接携带 `ConversationAction`：

| 字段组 | 字段 |
| --- | --- |
| 模型 | `model_details`、`requested_model` |
| 会话 | `conversation_id`、`conversation_state`、`conversation_group_id` |
| 工具 | `mcp_tools`、`mcp_file_system_options` |
| Prompt | `custom_system_prompt`、`exclude_workspace_context` |
| 子 Agent | `subagent_type_name`、`selected_subagent_models`、`selected_subagent_model_details`、`subagent_model_overrides` |
| 客户端能力 | `suggest_next_prompt`、`client_supports_inline_images`、`client_supports_send_to_user`、`computer_use_coordinate_mode` |
| 预取 | `pre_fetched_blobs` |
| 候选选择 | `best_of_n_group_id`、`try_use_best_of_n_promotion` |

## 6. 模型选择消息

### 6.1 `RequestedModel`

功能：描述调用方实际希望使用的模型和运行参数。

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `model_id` | `string` | Provider 模型标识。 |
| `max_mode` | `bool` | 是否启用该模型的 max 模式。 |
| `parameters` | `ModelParameterValue[]` | 额外模型参数，每项包含字符串 `id` 和 `value`。 |
| `built_in_model` | `bool` | 是否为内建模型。 |
| `is_variant_string_representation` | `bool` | `model_id` 是否表示模型变体字符串。 |
| `credentials` | `oneof` | `api_key_credentials`、`azure_credentials` 或 `bedrock_credentials`。 |

### 6.2 `ModelDetails`

功能：提供模型展示信息、别名、思考能力和凭据。

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `model_id` | `string` | 模型标识。 |
| `display_model_id` | `string` | 面向 UI 的模型标识。 |
| `display_name` | `string` | 完整展示名称。 |
| `display_name_short` | `string` | 短展示名称。 |
| `aliases` | `string[]` | 可识别的模型别名。 |
| `thinking_details` | `ThinkingDetails?` | 模型思考能力声明。 |
| `max_mode` | `bool?` | 是否启用 max 模式。 |
| `credentials` | `oneof` | API Key、Azure 或 Bedrock 凭据。 |

凭据字段属于敏感信息，不应写入普通日志、错误消息或会话记录。

## 7. `ConversationAction`

功能：描述一次会话级动作。`action` 是 `oneof`。

### 7.1 公共字段

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `triggering_auth_id` | `string?` | 触发动作的认证主体。 |
| `triggering_user_info` | `TriggeringUserInfo?` | 触发用户的信息。 |
| `request_context_parts` | `RequestContextPartReferences?` | 通过 blob 引用传递的大型上下文部分。 |

### 7.2 动作分支

| 分支 | 主要参数 | 功能 |
| --- | --- | --- |
| `user_message_action` | `user_message`、`request_context`、`prepend_user_messages`、`conversation_history` | 提交新用户消息并开始或继续会话。 |
| `resume_action` | `request_context` | 从已有 checkpoint 或等待点继续会话。 |
| `cancel_action` | `reason`、`interrupted_pending_tool_call_resolutions` | 取消当前 Run，并可携带未完成工具的解决结果。 |
| `summarize_action` | 无字段 | 请求生成或刷新会话摘要。 |
| `shell_command_action` | `shell_command`、`exec_id` | 将一次显式 Shell 命令写入会话。 |
| `start_plan_action` | `user_message`、`request_context`、`is_spec` | 进入计划编制流程。 |
| `execute_plan_action` | `request_context`、`plan`、计划文件字段、`execution_mode`、`plan_id` | 执行已有计划。 |
| `async_ask_question_completion_action` | `original_tool_call_id`、`original_args`、`result` | 回填异步 AskQuestion 的结果。 |
| `cancel_subagent_action` | `subagent_id` | 取消指定子 Agent。 |
| `background_task_completion_action` | `completions[]` | 上报后台 Shell 或子 Agent 的进度和终态。 |
| `background_shell_action` | `tool_call_id` | 将指定 Shell 工具调用切换到后台语义。 |
| `background_subagent_action` | `tool_call_id` | 将指定子 Agent 工具调用切换到后台语义。 |
| `subscription_notification_action` | `notifications[]`、`request_context` | 将订阅系统产生的消息注入会话。 |
| `goal_continuation_action` | 无字段 | 继续当前长期目标。 |
| `inject_context_action` | `injection_id`、`expected_run_id`、`user_context/system_context` | 向仍在运行的 Run 注入上下文。 |

## 8. `UserMessage`

功能：描述用户输入及其选择的上下文和运行模式。

| 字段组 | 字段 | 功能 |
| --- | --- | --- |
| 内容 | `text`、`rich_text`、`text_blob_id`、`rich_text_blob_id` | 用户输入的纯文本、富文本或 blob 引用。 |
| 身份 | `message_id`、`thread_id`、`prompt_reference_id` | 消息、线程和提示引用标识。 |
| 上下文 | `selected_context`、`conversation_state_blob_id` | 用户选择的文件、代码或会话状态。 |
| 模式 | `mode`、`custom_mode_intent` | Agent、Ask、Plan、Debug、Multitask 或自定义模式。 |
| 计划 | `execute_plan_info` | 当前消息关联的计划。 |
| 子 Agent | `subagent_system_reminder`、`project_details` | 子 Agent 或项目相关信息。 |
| 模拟消息 | `is_simulated_msg`、`simulated_msg_reason`、`simulated_message_metadata` | 标记系统代用户生成的输入。 |
| Hook | `hook_additional_contexts` | Hook 产生的附加上下文。 |

## 9. `RequestContext`

功能：描述本次请求可见的工作区、规则、工具和运行环境。

字段较多，按语义分组如下：

| 字段组 | 代表字段 | 功能 |
| --- | --- | --- |
| 环境 | `env` | OS、Shell、工作区路径、时区、终端目录、sandbox 与 Computer Use 能力。 |
| 规则 | `rules`、`non_file_rules`、`cloud_rule`、`disabled_team_rules` | 本次请求适用的规则集合。 |
| 仓库 | `repository_info`、`git_repos`、`project_layouts`、完整性标记 | 仓库索引、Git 和项目布局。 |
| MCP | `tools`、`mcp_instructions`、`mcp_file_system_options`、`mcp_meta_tool_options` | MCP 工具与文件系统能力。 |
| 技能 | `skill_options`、`agent_skills` | 可用技能和技能内容。 |
| 子 Agent | `custom_subagents` | 自定义子 Agent 声明。 |
| 文件 | `file_contents` | 已预取的路径到文件内容映射。 |
| Web | `web_search_enabled`、`web_fetch_enabled` | Web Search 和 Web Fetch 能力开关。 |
| Hook | `hooks_additional_context`、`hooks_config` | Hook 配置和附加上下文。 |
| 权限 | `user_permissions_auto_run`、`project_permissions_auto_run`、`admin_permissions_auto_run`、`admin_command_denylist` | 自动执行许可和禁止命令。 |
| 功能能力 | `supports_mcp_auth`、`read_lints_enabled`、`search_conversations_enabled`、`send_message_enabled` | 客户端可提供的附加能力。 |

大型上下文也可以通过 `RequestContextPartReferences` 传递。该结构为 rules、skills、subagents 和 MCP 分别携带 `blob_id` 与字节长度，并用 `dynamic_context` 继续携带小型动态字段。

## 10. `ExecClientMessage`

功能：返回 `ExecServerMessage` 所请求的客户端执行数据或结果。

### 10.1 公共字段

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `id` | `uint32` | 与对应 `ExecServerMessage.id` 相同。 |
| `exec_id` | `string` | 与对应 `ExecServerMessage.exec_id` 相同。 |
| `local_execution_time_ms` | `int32?` | 客户端本地执行耗时。 |
| `hook_additional_contexts` | `HookAdditionalContext[]` | 执行 Hook 返回的附加上下文。 |
| `message` | `oneof` | 工具特定的结果或流式事件。 |

### 10.2 主要结果分支

| 分类 | 分支 | 功能 |
| --- | --- | --- |
| 文件 | `read_result`、`redacted_read_result` | 返回文件读取结果。 |
| 文件 | `write_result`、`delete_result` | 返回文件写入或删除结果。 |
| 搜索 | `grep_result`、`ls_result` | 返回文本搜索、Glob 或目录列表结果。 |
| 诊断 | `diagnostics_result`、`canvas_diagnostics_result` | 返回代码或 Canvas 诊断结果。 |
| Shell | `shell_result`、`shell_stream` | 返回一次性 Shell 结果或流式 Shell 事件。 |
| Shell | `background_shell_spawn_result`、`write_shell_stdin_result`、`force_background_shell_result` | 返回后台 Shell 创建、输入和后台切换结果。 |
| 上下文 | `request_context_result` | 返回动态构建的 RequestContext。 |
| MCP | `mcp_result`、`list_mcp_resources_exec_result`、`read_mcp_resource_exec_result`、`mcp_state_exec_result` | 返回 MCP 调用和资源操作结果。 |
| Hook | `execute_hook_result` | 返回 Hook 执行结果。 |
| 子 Agent | `subagent_result`、`force_background_subagent_result`、`subagent_await_result` | 返回子 Agent 运行、后台切换和等待结果。 |
| Web/Computer | `fetch_result`、`record_screen_result`、`computer_use_result` | 返回网页、录屏或 Computer Use 结果。 |
| 权限预检 | `shell_allowlist_precheck_result`、`mcp_allowlist_precheck_result`、`web_fetch_allowlist_precheck_result` | 返回 allowlist 检查结果。 |
| Git | `git_diff_response` | 返回 Git diff。 |
| Pi 工具 | `pi_read_result`、`pi_bash_result`、`pi_edit_result`、`pi_write_result`、`pi_grep_result`、`pi_find_result`、`pi_ls_result` | 返回 Pi 工具族的执行结果。 |
| 其他 | `smart_mode_classifier_result`、`conversation_search_result`、`agent_store_conflict_result` | 返回模式分类、会话搜索或 Agent Store 冲突处理结果。 |

对于 `shell_stream`，其内部 `event` 也是 `oneof`，常见事件包括：

- `start`：进程已经启动。
- `stdout`：标准输出增量。
- `stderr`：标准错误增量。
- `exit`：进程已经退出。
- `rejected`：执行请求被拒绝。
- `permission_denied`：缺少执行权限。
- `backgrounded`：进程已经转入后台。

## 11. `ExecClientControlMessage`

功能：描述客户端执行通道本身的状态，不承载正常工具结果。

`message` 是 `oneof`：

| 分支 | 参数 | 功能 |
| --- | --- | --- |
| `stream_close` | `id` | 表示指定 Exec 数据流已经关闭。 |
| `throw` | `id`、`error`、`stack_trace?`、`error_code?` | 表示客户端执行通道异常终止。 |
| `heartbeat` | `id` | 表示指定 Exec 仍然存活。 |

## 12. `InteractionResponse`

功能：返回客户端或用户对 `InteractionQuery` 的响应。

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `id` | `uint32` | 与对应 `InteractionQuery.id` 相同。 |
| `result` | `oneof` | 交互类型对应的响应。 |

当前主要响应分支：

| 分支 | 主要内容 | 功能 |
| --- | --- | --- |
| `ask_question_interaction_response` | `AskQuestionResult` | 返回问题答案、拒绝、错误或异步状态。 |
| `create_plan_request_response` | `CreatePlanResult` | 返回计划 URI以及成功或错误。 |
| `web_search_request_response` | `approved/rejected` | 批准或拒绝 Web Search。 |
| `web_fetch_request_response` | `approved/rejected` | 批准或拒绝 Web Fetch。 |
| `switch_mode_request_response` | `approved/rejected` | 批准或拒绝模式切换。 |

协议还定义 VM 环境、PR 管理、MCP Auth、图片生成、环境替换和 SCM 连接等响应分支。

## 13. `KvClientMessage`

功能：返回 `KvServerMessage` 发起的 blob 操作结果。

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `id` | `uint32` | 与对应 `KvServerMessage.id` 相同。 |
| `get_blob_result` | `GetBlobResult` | 返回 `blob_data` 或 `error`。 |
| `set_blob_result` | `SetBlobResult` | 返回可选的写入错误；无错误表示写入成功。 |

## 14. `ClientHeartbeat`

功能：表示客户端 Agent 通道仍然存活。

该消息没有业务字段，也不与 `ExecClientHeartbeat` 混用：

- `ClientHeartbeat` 面向整个 Agent 请求通道。
- `ExecClientHeartbeat` 面向某个具体 `ExecServerMessage.id`。

## 15. RunSSE 请求与服务端根消息

### 15.1 RunSSE 请求

RunSSE 请求体是 `BidiRequestId`，只包含：

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `request_id` | `string` | 订阅指定请求流的服务端消息。 |

### 15.2 `AgentServerMessage`

功能：封装一条服务端到客户端的 Agent 消息。

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `ttft_breakdown` | `TtftBreakdown` | 可选的首 token 延迟分解。 |
| `message` | `oneof` | 本条消息的业务载荷。 |

`message` 可以选择以下一个分支：

| 分支 | 消息类型 | 功能 |
| --- | --- | --- |
| `interaction_update` | `InteractionUpdate` | 返回文本、思考、工具和 turn 生命周期更新。 |
| `exec_server_message` | `ExecServerMessage` | 请求客户端执行本地工具。 |
| `exec_server_control_message` | `ExecServerControlMessage` | 控制已经发出的客户端执行。 |
| `conversation_checkpoint_update` | `ConversationStateStructure` | 更新客户端持有的会话 checkpoint。 |
| `kv_server_message` | `KvServerMessage` | 请求客户端读取或写入 blob。 |
| `interaction_query` | `InteractionQuery` | 请求用户或客户端作出交互决策。 |

## 16. `InteractionUpdate`

功能：承载模型输出和一次 turn 中的增量状态。

`message` 是 `oneof`。当前主要消息如下。

### 16.1 文本和思考

| 分支 | 参数 | 功能 |
| --- | --- | --- |
| `text_delta` | `text`、`is_server_notice` | 返回可展示文本增量。 |
| `thinking_delta` | `text`、`thinking_style?` | 返回思考文本增量及展示样式。 |
| `thinking_completed` | `thinking_duration_ms` | 表示思考阶段结束。 |

### 16.2 工具调用

| 分支 | 参数 | 功能 |
| --- | --- | --- |
| `tool_call_started` | `call_id`、`tool_call`、`model_call_id` | 宣布工具调用已经建立。 |
| `partial_tool_call` | `call_id`、`tool_call`、`args_text_delta`、`model_call_id` | 在参数尚未完整时返回部分 ToolCall。 |
| `tool_call_delta` | `call_id`、`tool_call_delta`、`model_call_id` | 返回 Shell、Task、Edit 或环境替换的增量。 |
| `tool_call_completed` | `call_id`、`tool_call`、`model_call_id` | 表示工具调用已经得到终态结果。 |
| `shell_output_delta` | `stdout/stderr/start/exit` | 返回 Shell 进程输出和生命周期增量。 |

同一次工具调用的这些消息必须使用相同的 `call_id`；同一次模型调用产生的工具事件应使用相同的 `model_call_id`。

### 16.3 摘要和结束

| 分支 | 参数 | 功能 |
| --- | --- | --- |
| `summary_started` | 无字段 | 表示摘要阶段开始。 |
| `summary` | `summary` | 返回摘要文本。 |
| `summary_completed` | `hook_message?` | 表示摘要阶段完成，并可携带后续 Hook 信息。 |
| `turn_ended` | token 统计字段 | 表示当前 turn 正常结束。 |

`turn_ended` 的 token 字段包括：

- `input_tokens`
- `output_tokens`
- `cache_read_tokens`
- `cache_write_tokens`
- `reasoning_tokens`

### 16.4 保活

| 分支 | 参数 | 功能 |
| --- | --- | --- |
| `heartbeat` | 无字段 | 保持 RunSSE 活跃，不表示业务状态变化。 |

协议还定义 `user_message_appended`、`token_delta`、step 生命周期、prompt suggestion、branch change、feedback、response comparison 和 context injection state 等更新。

## 17. `ExecServerMessage`

功能：要求客户端执行一项本地能力。

### 17.1 公共字段

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `id` | `uint32` | 执行桥消息编号，客户端回包必须原样携带。 |
| `exec_id` | `string` | 执行任务标识，流式消息应保持一致。 |
| `span_context` | `SpanContext?` | 可选的分布式追踪上下文。 |
| `accept_hook_additional_contexts` | `bool?` | 是否接受客户端在结果中返回 Hook 附加上下文。 |
| `message` | `oneof` | 工具特定的执行参数。 |

### 17.2 主要执行分支

| 分类 | 分支 | 功能 |
| --- | --- | --- |
| 文件 | `read_args`、`write_args`、`delete_args` | 读取、写入或删除文件。 |
| 搜索 | `grep_args`、`ls_args` | 搜索文本、匹配路径或列出目录。 |
| 诊断 | `diagnostics_args` | 获取编辑器或项目诊断。 |
| Shell | `shell_stream_args` | 启动流式 Shell 命令。 |
| Shell | `write_shell_stdin_args`、`force_background_shell_args` | 向 Shell 写入输入或切换后台执行。 |
| MCP | `mcp_args`、`list_mcp_resources_exec_args`、`read_mcp_resource_exec_args` | 调用 MCP 工具或读取 MCP 资源。 |
| Hook | `execute_hook_args` | 请求客户端执行 Agent Hook。 |
| 子 Agent | `subagent_args` | 请求客户端启动子 Agent。 |

协议还定义普通 Shell、后台 Shell 创建、RequestContext、Fetch、Computer Use、allowlist 预检、Git diff、Pi 工具、会话搜索和 Agent Store 冲突等执行分支。

### 17.3 回包规则

客户端返回 `ExecClientMessage` 或 `ExecClientControlMessage` 时：

- `id` 必须与请求一致。
- 如果存在 `exec_id`，应与请求一致。
- 流式执行可以返回多条数据消息。
- 最终结果、`throw` 或明确终态用于结束本次执行关联。

## 18. `ExecServerControlMessage`

功能：控制此前已经发出的 Exec 请求。

当前协议分支：

| 分支 | 参数 | 功能 |
| --- | --- | --- |
| `abort` | `id` | 请求客户端终止对应的 Exec。 |

`abort.id` 对应 `ExecServerMessage.id`，不是 `tool_call_id`。

## 19. `InteractionQuery`

功能：请求用户或客户端完成不能由模型单独决定的交互。

### 19.1 公共字段

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `id` | `uint32` | 交互编号，响应必须原样携带。 |
| `query` | `oneof` | 具体交互内容。 |

### 19.2 主要查询分支

| 分支 | 主要参数 | 功能 |
| --- | --- | --- |
| `ask_question_interaction_query` | `args`、`tool_call_id` | 向用户展示一个或多个问题。 |
| `create_plan_request_query` | `args`、`tool_call_id` | 请求客户端创建或保存计划。 |
| `web_search_request_query` | `args` | 请求批准 Web Search。 |
| `web_fetch_request_query` | `args`、`skip_approval`、`smart_mode_approval` | 请求批准或执行 Web Fetch。 |
| `switch_mode_request_query` | `args.target_mode_id`、`explanation?`、`tool_call_id` | 请求切换 Agent 模式。 |

协议还定义 VM 环境、PR 管理、MCP Auth、图片生成、环境替换和 SCM 连接查询。

### 19.3 响应规则

客户端必须用 `InteractionResponse` 返回结果：

- `InteractionResponse.id` 与查询 `id` 相同。
- `result` 分支必须与原查询类型匹配。
- 批准/拒绝型响应应明确选择对应的 `oneof` 分支，不能用空消息代替拒绝。

## 20. `KvServerMessage`

功能：请求客户端提供或保存较大的二进制数据。

| 字段 | 类型 | 功能 |
| --- | --- | --- |
| `id` | `uint32` | KV 操作编号。 |
| `span_context` | `SpanContext?` | 可选追踪上下文。 |
| `get_blob_args` | `GetBlobArgs` | 按 `blob_id` 读取数据。 |
| `set_blob_args` | `SetBlobArgs` | 按 `blob_id` 保存 `blob_data`。 |

客户端使用相同 `id` 返回 `KvClientMessage`。

Blob 字段是原始 bytes。协议使用 `blob_id` 引用它们，以避免在主要会话消息中重复传输大型上下文。

## 21. `ConversationStateStructure`

功能：表示可跨请求传递的会话 checkpoint。

该结构既可以由客户端随 `AgentRunRequest` 上传，也可以由服务端通过 `conversation_checkpoint_update` 返回。

| 字段组 | 代表字段 | 功能 |
| --- | --- | --- |
| Prompt | `root_prompt_messages_json` | 根 Prompt 消息，元素以 bytes 保存。 |
| Turn | `turns`、`turn_timings` | 历史 turn 和耗时。 |
| 工具 | `pending_tool_calls` | 尚未解决的工具调用。 |
| 状态 | `todos`、`plan`、`plans` | Todo 和计划状态。 |
| Token | `token_details` | 已用 token、最大 token 和上下文分解。 |
| 摘要 | `summary`、`summary_archive`、`summary_archives`、`self_summary_count` | 当前摘要和历史摘要。 |
| 文件 | `file_states`、`file_states_v2`、`read_paths` | 会话涉及的文件状态。 |
| 工作区 | `previous_workspace_uris`、`tracked_git_repo_branches`、`active_branch_name` | 工作区和 Git 状态。 |
| 模式 | `mode`、`agent_type` | 当前 Agent 模式和类型。 |
| 子 Agent | `subagent_states`、`subagent_threads`、`subagent_runs_by_parent_tool_call_id`、`subagent_state_refs` | 子 Agent checkpoint。 |
| 通信进度 | `communicate_update_*` | 长任务进度和最终摘要。 |
| 会话时间 | `conversation_started_timestamp_ms`、`conversation_started_time_zone` | 会话开始时间。 |
| Goal | `goal_state` | 长期目标状态。 |

注意：多个字段使用 `bytes`，其内部内容通常仍是另一种 protobuf 或 JSON 编码。消费者必须依据字段定义解码，不能把所有 bytes 都当作 UTF-8 文本。

## 22. 消息配对关系

### 22.1 Run

```text
AgentClientMessage.run_request
  -> AgentServerMessage.interaction_update (...多条)
  -> AgentServerMessage.conversation_checkpoint_update
  -> AgentServerMessage.interaction_update.turn_ended
  -> stream end
```

### 22.2 Exec

```text
AgentServerMessage.exec_server_message(id, exec_id)
  -> AgentClientMessage.exec_client_message(id, exec_id) (...可多条)
  -> AgentClientMessage.exec_client_control_message(id)   (...可选)
```

### 22.3 Interaction

```text
AgentServerMessage.interaction_query(id, query)
  -> AgentClientMessage.interaction_response(id, matching_result)
```

### 22.4 KV

```text
AgentServerMessage.kv_server_message(id, get/set)
  -> AgentClientMessage.kv_client_message(id, matching_result)
```

## 23. `oneof` 与可选字段规则

- 同一个 `oneof` 在一条 protobuf 消息中只能设置一个分支。
- 未设置 `optional` 字段和设置为默认值在业务语义上可能不同，消费者需要保留 presence 信息。
- 未识别的 protobuf 字段应按 protobuf 兼容规则保留或忽略，不应导致整条消息无法解析。
- 请求与响应的类型必须匹配，不能只依赖相同的 `id`。
- `request_id`、`conversation_id`、`model_call_id`、`tool_call_id`、`exec_id` 和桥接 `id` 属于不同命名空间，不应互相替代。
- 增量消息只表达追加内容；接收方不应把 delta 当作完整快照覆盖已有内容。
- checkpoint 表达完整状态视图；同类的新 checkpoint 可以替代旧 checkpoint。

## 24. 错误与终止语义

协议需要区分三类结束：

1. 正常业务结束
   - 典型信号是 `InteractionUpdate.turn_ended`，随后流结束。
2. 用户或系统取消
   - 可能先出现 Exec `abort`，随后 RunSSE 以 canceled 状态结束。
3. 协议、provider 或服务错误
   - 可以通过 Connect end-stream error 返回，不一定存在对应的 `AgentServerMessage.oneof` 分支。

因此，客户端不能仅凭“流关闭”判断正常完成；还需要结合最后一条业务消息和流终止状态。
