mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-08-17 19:47:10 +08:00
all tools
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
# Cursor Rust 服务端实施与验收计划
|
||||
|
||||
## 项目说明
|
||||
|
||||
`cursor-byok` 是一个兼容 Cursor Agent 客户端协议的自托管服务端项目,用于把 Cursor 客户端接入用户指定的 LLM Provider。项目根据真实客户端流量和提取出的 protobuf 协议实现,不依赖 Cursor 原服务保存对话状态。
|
||||
|
||||
当前 Rust 服务 `cursor-server` 实现以下完整链路:
|
||||
|
||||
- 通过 `RunSSE + BidiAppend` 组成的双向协议与 Cursor 客户端通信。
|
||||
- 将 OpenAI Chat、OpenAI Responses 和 Anthropic 的流式响应统一为内部 `ResponseEvent`。
|
||||
- 运行无状态 LLM Loop:`LLM → 客户端工具执行 → 结果追加 → 下一轮 LLM`,直到 Turn 完成或被新 Run 打断。
|
||||
- 以 append-only messages 作为上下文唯一事实源,保证相邻 LLM 请求的稳定前缀和可重复投射。
|
||||
- 支持文本、thinking、tool start、参数增量、tool result、usage、model、rules、commands、skills、MCP 和 subagent 上下文。
|
||||
- 使用 SQLite 持久化 messages、Run 状态、Blob CAS、引用边和 outbox。
|
||||
- 使用不可变 Blob 对象图表达 Conversation、Turn、UserMessage 和 Steps;BlobID 为原始内容的 `SHA-256`。
|
||||
- 在客户端确认 Blob 已存储后发布 checkpoint,并提供单工具粒度的历史回滚和未确认操作恢复。
|
||||
|
||||
运行时职责划分如下:Cursor 客户端负责真正执行本地工具并保存服务端同步的 Blob;`cursor-server` 负责 Loop 决策、上下文投射、Provider 调用、状态持久化和 checkpoint 构造。Todo/Plan 等业务状态不单独维护,而是从 messages 确定性推导。
|
||||
|
||||
协议与状态模型的抓包结论见 [Cursor上下文与状态同步抓包分析.md](./Cursor上下文与状态同步抓包分析.md)。Rust 服务的启动方式和运行配置见 [cursor-server/README.md](./cursor-server/README.md)。
|
||||
|
||||
## 目录硬约束
|
||||
|
||||
下列目录、文件名和职责是实现验收条件,不是建议。首版只允许一个 `cursor-server` crate;代码必须落在对应文件,不得用 `core.rs`、`service.rs` 等总入口替代,也不得提前创建 MCP/subagent 空模块。新增文件必须说明为何现有职责无法容纳;删除、改名或移动下列文件必须先同步修改本计划。
|
||||
|
||||
```text
|
||||
cursor-byok/
|
||||
├── cursor-server/ # 新 Rust 服务
|
||||
│ ├── Cargo.toml
|
||||
│ ├── build.rs # 从 cursor-proto/proto 生成 prost 类型
|
||||
│ ├── README.md # 启动方式、架构和核心不变量
|
||||
│ │
|
||||
│ ├── migrations/
|
||||
│ │ └── 0001_initial.sql # Blob、messages、runs、outbox
|
||||
│ │
|
||||
│ ├── src/
|
||||
│ │ ├── main.rs # 进程入口
|
||||
│ │ ├── lib.rs # 模块出口
|
||||
│ │ ├── app.rs # 依赖组装、启动和关闭
|
||||
│ │ ├── config.rs # 地址、数据库、provider 配置
|
||||
│ │ ├── error.rs # 服务统一错误
|
||||
│ │ │
|
||||
│ │ ├── model/ # 纯领域类型,不依赖 Cursor/provider
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── message.rs # CanonicalMessage、Role、Origin
|
||||
│ │ │ ├── runtime_tag.rs # RuntimeEvent、exactly-once 约束
|
||||
│ │ │ ├── conversation.rs # Conversation、Turn、revision
|
||||
│ │ │ ├── tool.rs # ToolCall、ToolResult
|
||||
│ │ │ └── usage.rs # provider usage 与 Turn usage
|
||||
│ │ │
|
||||
│ │ ├── run/ # Loop 引擎和一次 request 的状态机
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── registry.rs # request_id → RunHandle
|
||||
│ │ │ ├── actor.rs # 每个 Run 一个 actor
|
||||
│ │ │ ├── command.rs # run_request、exec/KV result、abort
|
||||
│ │ │ ├── inbox.rs # append_seqno 排序、去重
|
||||
│ │ │ ├── loop_engine.rs # LLM → Tool → LLM 主循环
|
||||
│ │ │ └── lifecycle.rs # turn_ended/checkpoint/EndStream
|
||||
│ │ │
|
||||
│ │ ├── cursor/ # Cursor 协议适配器
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── proto.rs # include prost 生成代码
|
||||
│ │ │ ├── connect.rs # 5-byte Connect envelope
|
||||
│ │ │ ├── handlers.rs # Axum 路由入口
|
||||
│ │ │ ├── bidi_append.rs # 上行 AgentClientMessage
|
||||
│ │ │ ├── run_sse.rs # 下行 AgentServerMessage
|
||||
│ │ │ ├── interaction.rs # 交互事件、Tool args 和 usage 投射
|
||||
│ │ │ ├── exec.rs # Exec 上行/下行解析
|
||||
│ │ │ ├── pending.rs # Exec/Interaction 的运行期 ID 关联
|
||||
│ │ │ ├── tools.rs # 唯一工具路由、本地工具和 Cursor step index
|
||||
│ │ │ ├── tool_result.rs # typed result、UI completion 和结果通道
|
||||
│ │ │ ├── blob_sync.rs # KV GET/SET、ACK、重试
|
||||
│ │ │ └── checkpoint.rs # Blob 图和 checkpoint 构造
|
||||
│ │ │
|
||||
│ │ ├── provider/ # LLM 端点适配器
|
||||
│ │ │ ├── mod.rs # Provider trait
|
||||
│ │ │ ├── event.rs # Canonical ResponseEvent
|
||||
│ │ │ ├── openai_chat.rs # 第一条可运行链路
|
||||
│ │ │ ├── openai_responses.rs
|
||||
│ │ │ └── anthropic.rs
|
||||
│ │ │
|
||||
│ │ ├── prompting/ # 模型请求编译
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── assets.rs # 校验并嵌入根目录 prompt/
|
||||
│ │ │ ├── compiler.rs # messages + mode + tools
|
||||
│ │ │ ├── projector.rs # CanonicalMessage → provider 格式
|
||||
│ │ │ └── derived_state.rs # 从 messages fold Todo/Plan
|
||||
│ │ │
|
||||
│ │ └── store/ # SQLite 持久化
|
||||
│ │ ├── mod.rs
|
||||
│ │ ├── sqlite.rs # pool、事务、PRAGMA
|
||||
│ │ ├── messages.rs # append-only messages
|
||||
│ │ ├── blobs.rs # CAS 与引用边
|
||||
│ │ ├── conversations.rs # conversation head/revision
|
||||
│ │ ├── runs.rs # 活动 Run 和恢复信息
|
||||
│ │ └── outbox.rs # KV/checkpoint 待确认操作
|
||||
│ │
|
||||
│ └── tests/
|
||||
│ ├── support/
|
||||
│ │ ├── fake_provider.rs
|
||||
│ │ ├── fake_cursor.rs
|
||||
│ │ └── fixtures.rs
|
||||
│ ├── text_turn.rs # 纯文本完整 Turn
|
||||
│ ├── tool_loop.rs # LLM → Tool → LLM
|
||||
│ ├── runtime_tag_once.rs # Runtime tag 不重复追加
|
||||
│ ├── prefix_stability.rs # M(n) 是 M(n+1) 前缀
|
||||
│ ├── checkpoint_recovery.rs # 单 Tool 回滚
|
||||
│ ├── interrupt.rs # 新 Run 打断旧 Run
|
||||
│ └── connect_wire.rs # Connect 二进制兼容性
|
||||
│
|
||||
├── cursor-proto/ # 现有 protobuf 提取和源文件
|
||||
├── cursor-backend/ # 现有 Go 抓包调试器
|
||||
├── prompt/ # 已复制的完整模式资产
|
||||
└── docs/
|
||||
```
|
||||
|
||||
## 按文件实施顺序与通过条件
|
||||
|
||||
1. `Cargo.toml`、`build.rs`、`src/{main,lib,app,config,error}.rs`:服务能加载配置、迁移数据库、生成 Cursor protobuf 并启动/优雅关闭。
|
||||
2. `src/model/*.rs`、`src/store/*.rs`、`migrations/0001_initial.sql`:实现纯领域消息、runtime tag、tool/usage,以及 append-only messages、Blob CAS/引用边、revision、run 恢复与 outbox;`tests/runtime_tag_once.rs` 和 `tests/prefix_stability.rs` 必须通过。
|
||||
3. `src/cursor/{proto,connect,handlers,bidi_append,run_sse}.rs`:实现抓包一致的 5-byte Connect envelope、二进制 RunSSE、BidiAppend 解码和 `append_seqno` 排序去重;`tests/connect_wire.rs` 必须通过。
|
||||
4. `src/provider/{event,openai_chat,openai_responses,anthropic}.rs`、`src/prompting/*.rs`:三个端点统一为 canonical `ResponseEvent`;所有 mode 的 prompt/tool 资产可加载;messages 投射幂等且保持严格前缀。
|
||||
5. `src/run/*.rs`、`src/cursor/{tools,interaction,exec,pending,tool_result}.rs`:一个 request 一个 RunActor;Loop 只处理统一 `ToolCompletion`,工具名称到 Exec/Interaction/Local 的唯一映射只存在于 `cursor/tools.rs`;完成 toolstart 占位、参数增量、客户端执行、打断与 usage。每个完成的工具必须原子追加 `assistant(tool_call) → tool(result)`,整批完成前不得进入下一次 LLM。
|
||||
6. `src/cursor/{blob_sync,checkpoint}.rs`、`src/store/{blobs,outbox}.rs`:构造不可变 Blob 对象图,KV SET 未 ACK 前不得发布引用它的 checkpoint;checkpoint 达到单工具粒度,最终状态重复发布后再 EndStream;`tests/checkpoint_recovery.rs` 必须通过。
|
||||
7. `tests/{text_turn,tool_loop,interrupt}.rs` 与 `tests/support/*.rs`:覆盖纯文本 Turn、完整工具循环、新 Run 打断旧 Run和恢复路径。最终验收命令固定为 `cargo fmt --check`、`cargo clippy --all-targets -- -D warnings`、`cargo test --all-targets`。
|
||||
|
||||
|
||||
模块依赖方向固定为:
|
||||
|
||||
HTTP/Connect
|
||||
↓
|
||||
cursor adapter
|
||||
↓
|
||||
run actor
|
||||
↓
|
||||
model + prompting
|
||||
↓
|
||||
provider / client tools
|
||||
↓
|
||||
store + checkpoint
|
||||
|
||||
几个关键决定:
|
||||
model/ 不引用 Cursor protobuf,也不引用具体 provider。
|
||||
cursor/ 只负责协议转换,不能包含 Loop 业务决策。
|
||||
provider/ 只把不同端点转换为统一 ResponseEvent。
|
||||
prompting/derived_state.rs 只 fold messages,不持久化 Todo/Plan。
|
||||
store/messages.rs 是上下文唯一事实源。
|
||||
store/outbox.rs 保存尚未确认的 Blob/checkpoint 操作。
|
||||
MCP 和 subagent 暂时不建空目录:MCP 先作为动态 Tool 接入;subagent 复用 RunActor,需求落地时再加入 run/subagent.rs。
|
||||
|
||||
依赖建议:
|
||||
```
|
||||
tokio 异步运行时
|
||||
axum + hyper Connect HTTP 服务
|
||||
prost + prost-build protobuf
|
||||
protoc-bin-vendored 避免系统 protoc 依赖
|
||||
sqlx/sqlite 持久化和事务
|
||||
reqwest provider HTTP
|
||||
eventsource-stream provider SSE
|
||||
serde/serde_json 模型和工具 JSON
|
||||
sha2 + base64 BlobID
|
||||
bytes 二进制载荷
|
||||
tokio-util CancellationToken
|
||||
thiserror + tracing 错误和日志
|
||||
include_dir 编译期嵌入 prompt/ 资产
|
||||
```
|
||||
|
||||
Cursor上下文与状态同步抓包分析.md 来告诉你很多信息,你需要一次性读他
|
||||
|
||||
Users/leokun/Library/Application Support/cursor-byok/cursor-proxy-debugger.db 是cursor的原服务抓包信息,内容由/Users/leokun/Documents/cursor-byok/cursor-backend产生
|
||||
Reference in New Issue
Block a user