391 lines
8.8 KiB
Markdown
391 lines
8.8 KiB
Markdown
# sgClaw 本项目团队开发启动文档
|
||
|
||
**适用对象**:sgClaw Rust / Agent 项目开发团队(P1a、P1b)
|
||
**目标**:项目团队拿到本文档后即可独立启动 Rust 侧开发,并在一个周期后与浏览器团队完成 Pipe 联调。
|
||
**协议版本**:`1.0`
|
||
**冻结日期**:`2026-03-24`
|
||
|
||
---
|
||
|
||
## 1. 开发目标
|
||
|
||
本项目团队本周期只负责 sgClaw Rust 侧能力,不负责 Chromium 内部实现。
|
||
|
||
本周期结束时,Rust 侧必须具备以下能力:
|
||
|
||
1. 可作为浏览器子进程启动。
|
||
2. 通过 `stdin/stdout` 执行双向 `JSON Line` 通信。
|
||
3. 完成 `init -> init_ack` 握手。
|
||
4. 提供 `BrowserPipeTool`,可发送 `click/type/navigate/getText`。
|
||
5. 能等待并解析浏览器侧 `response`。
|
||
6. 能执行本地 `MAC Policy` 初步校验。
|
||
|
||
本周期不做:
|
||
|
||
1. 不切回 HTTP/TCP 演示通道。
|
||
2. 不依赖浏览器团队未完成的 UI。
|
||
3. 不把 pipe 协议和业务 skill 混在一起推进。
|
||
4. 不要求本周期完成完整 15 action。
|
||
|
||
---
|
||
|
||
## 2. Rust 团队负责的交付物
|
||
|
||
本周期交付以下文件或等价模块:
|
||
|
||
1. `src/main.rs`
|
||
2. `src/pipe/protocol.rs`
|
||
3. `src/pipe/handshake.rs`
|
||
4. `src/pipe/browser_tool.rs`
|
||
5. `src/pipe/mod.rs`
|
||
6. `src/security/mac_policy.rs`
|
||
7. `src/security/hmac.rs`
|
||
8. `tests/pipe_protocol_test.rs`
|
||
9. `tests/pipe_handshake_test.rs`
|
||
10. `tests/browser_tool_test.rs`
|
||
11. `tests/integration/handshake_flow_test.rs`
|
||
|
||
建议本周期目录保持如下:
|
||
|
||
```text
|
||
src/
|
||
main.rs
|
||
lib.rs
|
||
pipe/
|
||
mod.rs
|
||
protocol.rs
|
||
handshake.rs
|
||
browser_tool.rs
|
||
security/
|
||
mod.rs
|
||
hmac.rs
|
||
mac_policy.rs
|
||
tests/
|
||
pipe_protocol_test.rs
|
||
pipe_handshake_test.rs
|
||
browser_tool_test.rs
|
||
integration/
|
||
handshake_flow_test.rs
|
||
resources/
|
||
rules.json
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 冻结边界
|
||
|
||
### 3.1 本周期团队边界
|
||
|
||
P1a 负责:
|
||
|
||
1. Pipe 协议结构体。
|
||
2. 握手。
|
||
3. `BrowserPipeTool`。
|
||
4. HMAC 计算。
|
||
5. response 关联和超时处理。
|
||
|
||
P1b 负责:
|
||
|
||
1. 将 `BrowserPipeTool` 作为工具注册到后续 `AgentRuntime`。
|
||
2. 但本周期联调不阻塞于完整 ReAct Loop。
|
||
|
||
本周期联调最小成功标准是:
|
||
|
||
1. Rust 能发命令。
|
||
2. 浏览器能执行并返回。
|
||
3. Rust 能按 `seq` 收到正确 response。
|
||
|
||
### 3.2 进程与日志约束
|
||
|
||
1. `stdin` 只读协议消息。
|
||
2. `stdout` 只写协议消息。
|
||
3. 所有日志必须写到 `stderr`。
|
||
4. 遇到协议错误时返回结构化错误或退出,不允许把调试日志写进 `stdout`。
|
||
|
||
---
|
||
|
||
## 4. 冻结协议
|
||
|
||
### 4.1 Browser -> sgClaw
|
||
|
||
`init`
|
||
|
||
```json
|
||
{"type":"init","version":"1.0","hmac_seed":"0123456789abcdef","capabilities":["browser_action"]}
|
||
```
|
||
|
||
`response`
|
||
|
||
```json
|
||
{"type":"response","seq":1,"success":true,"data":{},"aom_snapshot":[],"timing":{"queue_ms":1,"exec_ms":20}}
|
||
```
|
||
|
||
### 4.2 sgClaw -> Browser
|
||
|
||
`init_ack`
|
||
|
||
```json
|
||
{"type":"init_ack","version":"1.0","agent_id":"uuid-v4","supported_actions":["click","type","navigate","getText","getHtml","waitForSelector","pageScreenshot","select","scrollTo","getAomSnapshot","storageSet","storageGet","zombieSpawn","zombieKill"]}
|
||
```
|
||
|
||
`command`
|
||
|
||
```json
|
||
{
|
||
"type":"command",
|
||
"seq":1,
|
||
"action":"click",
|
||
"params":{"selector":"#submit"},
|
||
"security":{
|
||
"expected_domain":"oa.example.com",
|
||
"hmac":"<hex>"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.3 必须满足的协议规则
|
||
|
||
1. 编码为 UTF-8。
|
||
2. 每行一个完整 JSON。
|
||
3. 单消息最大 `1 MB`。
|
||
4. `seq` 从 `1` 开始递增。
|
||
5. 每个 `command.seq` 对应唯一 `response.seq`。
|
||
6. `version` 固定为 `1.0`。
|
||
|
||
---
|
||
|
||
## 5. Rust 侧实现要求
|
||
|
||
### 5.1 main.rs
|
||
|
||
本周期 `main` 的目标很简单:
|
||
|
||
1. 初始化日志到 `stderr`。
|
||
2. 用 `stdin/stdout` 执行握手。
|
||
3. 初始化 `BrowserPipeTool` 所需对象。
|
||
4. 保持进程存活,等待命令结果和后续任务。
|
||
|
||
如果当前代码还保留演示版 HTTP 入口,本周期必须恢复到 pipe 入口优先。
|
||
|
||
### 5.2 handshake.rs
|
||
|
||
必须实现:
|
||
|
||
1. 从 `stdin` 读取第一条 `init`。
|
||
2. 校验 `version`。
|
||
3. 从 `hmac_seed` 派生会话级 HMAC key。
|
||
4. 生成 `agent_id`。
|
||
5. 向 `stdout` 回写 `init_ack`。
|
||
|
||
失败条件:
|
||
|
||
1. 第一条消息不是 `init`。
|
||
2. `version` 不匹配。
|
||
3. `hmac_seed` 非法。
|
||
|
||
### 5.3 protocol.rs
|
||
|
||
必须定义:
|
||
|
||
1. `BrowserMessage`
|
||
2. `AgentMessage`
|
||
3. `SecurityFields`
|
||
4. `Timing`
|
||
5. `Action`
|
||
|
||
本周期最小 `Action` 必须覆盖:
|
||
|
||
1. `click`
|
||
2. `type`
|
||
3. `navigate`
|
||
4. `getText`
|
||
|
||
建议保留剩余 action 枚举,为后续扩展留口。
|
||
|
||
### 5.4 browser_tool.rs
|
||
|
||
必须实现:
|
||
|
||
1. 输入参数反序列化为 `Action`。
|
||
2. 调用本地 `MAC Policy` 做前置校验。
|
||
3. 分配递增 `seq`。
|
||
4. 计算 `security.hmac`。
|
||
5. 向 `stdout` 写出 `command`。
|
||
6. 等待同 `seq` 的 `response`。
|
||
7. 超时返回错误。
|
||
|
||
建议超时:
|
||
|
||
1. 握手超时:`5s`
|
||
2. 单 action 响应超时:`30s`
|
||
|
||
### 5.5 mac_policy.rs
|
||
|
||
本周期最小校验:
|
||
|
||
1. action 白名单。
|
||
2. 域名白名单。
|
||
3. storage key 前缀约束可后置。
|
||
4. 熔断器可后置,但接口要预留。
|
||
|
||
`rules.json` 建议格式:
|
||
|
||
```json
|
||
{
|
||
"version": "1.0",
|
||
"domains": {
|
||
"allowed": ["oa.example.com", "erp.example.com", "hr.example.com"]
|
||
},
|
||
"pipe_actions": {
|
||
"allowed": ["click", "type", "navigate", "getText"],
|
||
"blocked": ["eval", "executeJsInPage"]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 本周期开发顺序
|
||
|
||
### Day 1-2
|
||
|
||
1. 固定协议结构体。
|
||
2. 写 `pipe_protocol_test`。
|
||
3. 写 `pipe_handshake_test`。
|
||
4. 恢复 `stdin/stdout` 入口。
|
||
|
||
验收:
|
||
|
||
1. 能独立运行进程并手动喂一条 `init`。
|
||
2. 能正确输出 `init_ack`。
|
||
|
||
### Day 3-4
|
||
|
||
1. 完成 `BrowserPipeTool`。
|
||
2. 完成 HMAC 计算。
|
||
3. 完成基于 `seq` 的 response 匹配。
|
||
4. 与本地 mock 浏览器进程联通。
|
||
|
||
验收:
|
||
|
||
1. Rust 能发出 `click/type/navigate/getText` 四类命令。
|
||
2. mock response 能被正确接收。
|
||
|
||
### Day 5-6
|
||
|
||
1. 接入最小 `MAC Policy`。
|
||
2. 完成 integration test。
|
||
3. 准备联调脚本和示例 JSON。
|
||
|
||
验收:
|
||
|
||
1. 非白名单 action 在 Rust 侧被前置拒绝。
|
||
2. 域名不合法时直接失败。
|
||
|
||
### Day 7
|
||
|
||
1. 收口测试。
|
||
2. 输出联调说明。
|
||
3. 与浏览器团队联调。
|
||
|
||
---
|
||
|
||
## 7. Rust 团队自测清单
|
||
|
||
- [ ] `protocol.rs` 序列化/反序列化测试通过。
|
||
- [ ] `init -> init_ack` 测试通过。
|
||
- [ ] `version` 不匹配时握手失败。
|
||
- [ ] `hmac_seed` 非法时握手失败。
|
||
- [ ] `click/type/navigate/getText` 命令都能正确编码。
|
||
- [ ] `response.seq` 不匹配时不会误关联。
|
||
- [ ] 单 action 超时能返回错误。
|
||
- [ ] 非白名单 action 被 `MAC Policy` 拒绝。
|
||
- [ ] 日志只出现在 `stderr`。
|
||
|
||
---
|
||
|
||
## 8. 联调输入输出样例
|
||
|
||
### 8.1 手动运行握手
|
||
|
||
输入:
|
||
|
||
```json
|
||
{"type":"init","version":"1.0","hmac_seed":"00112233445566778899aabbccddeeff","capabilities":["browser_action"]}
|
||
```
|
||
|
||
期望输出:
|
||
|
||
```json
|
||
{"type":"init_ack","version":"1.0","agent_id":"00000000-0000-0000-0000-000000000000","supported_actions":["click","type","navigate","getText","getHtml","waitForSelector","pageScreenshot","select","scrollTo","getAomSnapshot","storageSet","storageGet","zombieSpawn","zombieKill"]}
|
||
```
|
||
|
||
### 8.2 最小命令样例
|
||
|
||
输出给浏览器:
|
||
|
||
```json
|
||
{"type":"command","seq":1,"action":"navigate","params":{"url":"https://oa.example.com/login"},"security":{"expected_domain":"oa.example.com","hmac":"<hex>"}}
|
||
```
|
||
|
||
浏览器回:
|
||
|
||
```json
|
||
{"type":"response","seq":1,"success":true,"data":{},"aom_snapshot":[],"timing":{"queue_ms":1,"exec_ms":50}}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 联调前必须提供的东西
|
||
|
||
本项目团队在联调前必须准备:
|
||
|
||
1. 可运行的 `sgclaw` 可执行文件或 debug 启动方式。
|
||
2. 协议样例文件。
|
||
3. `rules.json` 默认测试配置。
|
||
4. 四个最小 action 的参数样例。
|
||
5. 一份错误码表。
|
||
6. 一份 `stderr` 日志关键字段说明。
|
||
|
||
---
|
||
|
||
## 10. 周期结束验收标准
|
||
|
||
以下全部满足,Rust 团队本周期完成:
|
||
|
||
1. `sgclaw` 可以被浏览器作为子进程启动。
|
||
2. `init -> init_ack` 成功率 100%。
|
||
3. 能稳定发送 `click/type/navigate/getText` 四类命令。
|
||
4. 能稳定按 `seq` 收到并解析 response。
|
||
5. Rust 侧前置 `MAC Policy` 生效。
|
||
6. 与浏览器团队在同一测试页面上联调成功。
|
||
|
||
---
|
||
|
||
## 11. 联调日执行顺序
|
||
|
||
联调当天只按下面顺序走,避免双方并发改协议:
|
||
|
||
1. 先验证 `init -> init_ack`。
|
||
2. 再验证 `navigate`。
|
||
3. 再验证 `type`。
|
||
4. 再验证 `click`。
|
||
5. 最后验证 `getText`。
|
||
6. 再补失败场景:域名拒绝、非法 action、超时。
|
||
|
||
任何协议字段问题,一律以 `protocol.rs` 和本文件为准,不在联调现场临时改口。
|
||
|
||
---
|
||
|
||
## 12. 对浏览器团队的依赖
|
||
|
||
Rust 团队本周期只依赖浏览器团队提供以下冻结输入:
|
||
|
||
1. 浏览器能启动子进程。
|
||
2. 浏览器能收发 JSON Line。
|
||
3. 浏览器支持 4 个最小 action。
|
||
4. 浏览器返回结构化 `response`。
|
||
|
||
浏览器内部如何落到 `CommandRouter`,不属于 Rust 团队阻塞项。
|
||
|