mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-08-17 19:47:10 +08:00
141 lines
7.0 KiB
Markdown
141 lines
7.0 KiB
Markdown
以下只基于当前代码。
|
||
|
||
**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 秒直接发送 heartbeat;heartbeat 不进入 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 和正在等待的桥接请求。**
|