Files
cursor-byok/docs/协议分析.md
T
2026-08-13 22:01:11 +08:00

141 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
以下只基于当前代码。
**1. 当前请求 `AgentClientMessage.oneof message` 类型**
协议定义了 8 类上行消息,[agent_v1.proto](/Users/leokun/Documents/cursor-byok/internal/backend/cursor/proto/agent_v1.proto:57)
1. `run_request`
- 新建/恢复一次 Agent 执行。
- 当前提取 `conversation_id`、conversation state、action、用户消息、request context、模型、thinking effort、mode、subagent 信息。
2. `prewarm_request`
- 建立运行态和 checkpoint,但不启动 provider。
3. `conversation_action`
- 会启动 Run`user_message``resume``summarize``start_plan``execute_plan`
- 会取消:`cancel`
- 其他 action 当前基本按 metadata 处理。
4. `exec_client_message`
- 客户端工具执行数据或结果。
- 当前主要处理 Read、Write、Delete、Glob/Grep、Diagnostics、Ls、ShellStream、MCP、Subagent、WriteShellStdin、ForceBackgroundShell、ExecuteHook。
5. `exec_client_control_message`
- `stream_close``throw``heartbeat`
6. `interaction_response`
- 当前处理 AskQuestion、CreatePlan、WebSearch、WebFetch、SwitchMode 的客户端响应。
7. `kv_client_message`
- proto 支持 `get_blob_result``set_blob_result`;当前业务主要消费 `set_blob_result`,用于 checkpoint blob 确认。
8. `client_heartbeat`
- 当前归为 metadata,不推进执行状态。
识别和内部 intent 映射集中在 [inbound.go](/Users/leokun/Documents/cursor-byok/internal/backend/agent/protocol/inbound.go:60) 与 [service.go](/Users/leokun/Documents/cursor-byok/internal/backend/forwarder/service.go:543)。
---
**2. 当前返回 `AgentServerMessage.oneof message` 类型**
外层 6 类全部有实际使用,[agent_v1.proto](/Users/leokun/Documents/cursor-byok/internal/backend/cursor/proto/agent_v1.proto:129)
1. `interaction_update`
- `text_delta`
- `thinking_delta`
- `thinking_completed`
- `summary_started`
- `summary`
- `summary_completed`
- `tool_call_started`
- `partial_tool_call`
- `tool_call_delta`
- `tool_call_completed`
- `shell_output_delta`
- `heartbeat`
- `turn_ended`
2. `exec_server_message`
- 服务端要求客户端执行工具。
- 当前包括 Read、Write、Delete、Grep、Ls、Diagnostics、ShellStream、WriteShellStdin、ForceBackgroundShell、MCP、MCP resource、Subagent、ExecuteHook。
3. `exec_server_control_message`
- 当前只有 `abort`,取消尚未完成的客户端执行。
4. `conversation_checkpoint_update`
- 返回完整的 `ConversationStateStructure` 投影。
5. `kv_server_message`
- 当前主要发送 `set_blob_args`,要求客户端保存 checkpoint blob。
6. `interaction_query`
- 当前包括 AskQuestion、CreatePlan、WebSearch、WebFetch、SwitchMode。
构造入口分别在 [events.go](/Users/leokun/Documents/cursor-byok/internal/backend/forwarder/events.go:17)、[exec bridge](/Users/leokun/Documents/cursor-byok/internal/backend/agent/bridge/exec/bridge.go:66) 和 [interaction bridge](/Users/leokun/Documents/cursor-byok/internal/backend/agent/bridge/interaction/bridge.go:66)。
另外,成功、取消、provider 错误不一定表现为 `oneMessage`:最终通过 `StreamEvent.End` 转换成 Connect end-stream 或结构化错误。
---
**3. 当前需要处理的协议信息**
传输层:
- `POST /aiserver.v1.BidiService/BidiAppend`Connect unary。
- `POST /agent.v1.AgentService/RunSSE`Connect server stream。
- RunSSE 响应头被强制兼容成 `text/event-stream`
- 实际消息仍由 Connect handler 负责 framing。
Bidi 外层:
- `request_id`:整条活动流的主键。
- `append_seqno`:同一 request 上行消息排序和去重。
- `data`:十六进制字符串,解码后才是 `AgentClientMessage protobuf`
- `data_binary`:proto 中存在,但当前实现没有使用。
- `BidiAppendResponse`:始终是空 ACK。
业务关联标识:
- `conversation_id`:持久化会话与历史。
- `request_id`:一次活跃请求以及 Bidi/RunSSE 配对。
- `turn_seq`:会话中的轮次。
- `model_call_id`:一次 provider pass。
- `tool_call_id`:模型工具调用。
- `ExecServerMessage.id + exec_id`:客户端执行请求和回包关联。
- `InteractionQuery.id`:交互查询和响应关联。
- `KvServerMessage.id`checkpoint blob 请求与确认关联。
还需要解析 conversation state、action、mode、requested model、thinking effort、request context、workspace/MCP/skill 信息。当前归一化后的协议载体是 [InboundIntent](/Users/leokun/Documents/cursor-byok/internal/backend/forwarder/types.go:418)。
---
**4. 当前怎样维护 Bidi 和 RunSSE 状态**
Bidi 顺序状态:
- `appendSequenceTracker``request_id` 建立状态。
- 维护 `next``processing``ready`
- 小于 `next` 的消息视为重复并忽略。
- 大于 `next` 的消息等待前序完成。
- Cursor 复用 `request_id` 且重新从 `append_seqno=1` 开始时,会在空闲状态重置序列。
- 状态空闲十分钟后清理。
- `append_seqno <= 0` 会绕过这个顺序机制。
见 [append_seq.go](/Users/leokun/Documents/cursor-byok/internal/backend/forwarder/append_seq.go:11)。
运行状态:
- `StreamBroker` 使用 `map[requestID]*ActiveStream`
- 每个 `ActiveStream` 保存 provider、phase、backlog、subscriber、pending exec、pending interaction、checkpoint 和工具运行状态。
- Bidi、provider event、timer 和 compaction event 都投递到该 stream 的单一 actor mailbox 串行处理。
- Phase 包括 `idle``provider_running``waiting_external``awaiting_user``compacting``checkpointing``completed/failed/canceled`
见 [types.go](/Users/leokun/Documents/cursor-byok/internal/backend/forwarder/types.go:126) 和 [actor.go](/Users/leokun/Documents/cursor-byok/internal/backend/forwarder/actor.go:18)。
RunSSE 状态:
- RunSSE 可以先于 Bidi 到达,此时 Broker 创建只有 `request_id` 的占位 stream。
- 每个 RunSSE 连接注册独立 subscriber,但数据事实源是共享 `Backlog []StreamEvent`
- `Publish` 先追加 backlog,再用容量为 1 的 signal 唤醒订阅者;signal 可以合并,但事件不会丢,因为客户端重新读取 backlog。
- 每个连接从本地 `cursor=0` 开始,所以重新连接会从头回放当前内存 backlog。
- backlog 暂时为空时,每 5 秒直接发送 heartbeatheartbeat 不进入 backlog。
- 最后一个订阅者断开后,给活跃请求 30 秒重连宽限期,之后 actor 执行取消。
- 终态 stream 在无订阅者时保留 30 秒,然后从 Broker 删除。
见 [broker.go](/Users/leokun/Documents/cursor-byok/internal/backend/forwarder/broker.go:131) 和 [service.go](/Users/leokun/Documents/cursor-byok/internal/backend/forwarder/service.go:419)。
关键结论:**Bidi/RunSSE 的活动状态、backlog、cursor、pending exec/interaction 都是内存态;持久化的是 conversation history/checkpoint,不是活动流本身。进程重启后无法恢复原 RunSSE backlog 和正在等待的桥接请求。**