diff --git a/docs/L0-产品白皮书与能力全景层.md b/docs/L0-产品白皮书与能力全景层.md index 1c3cafd..ce9bd9c 100644 --- a/docs/L0-产品白皮书与能力全景层.md +++ b/docs/L0-产品白皮书与能力全景层.md @@ -1,474 +1,129 @@ # L0 — 产品白皮书与能力全景层 -**文档版本**: 1.0 -**适用项目**: sgClaw (业数融合一平台 AI Agent 底座) -**编制日期**: 2026-03-03 +**文档版本**: 2.0 +**适用项目**: sgClaw(ZeroClaw 重构版) +**编制日期**: 2026-03-26 --- -## 1. 产品定位 +## 1. 产品定义 -sgClaw 是面向国家电网"业数融合一平台"的 **AI 驱动智能代理平台**。它并非一个独立应用程序,而是作为核心能力嵌入 SuperRPA 定制 Chromium 浏览器内核之中,通过浏览器 Side Panel 中的控制按钮一键激活。 +sgClaw 是一个嵌入企业浏览器运行环境中的浏览器智能体执行内核。它的职责不是替代整个平台,也不是承诺“全自动数字员工”,而是把自然语言任务转换成受控的浏览器操作,并通过既有浏览器宿主完成页面执行。 -用户只需用自然语言描述业务意图,sgClaw 即可自主理解指令语义,规划执行步骤,在 ERP、OA、财务、人力资源、经济法务等复杂业务系统中完成跨系统操作——**无需编写任何代码**。 +ZeroClaw 重构之后,sgClaw 的产品形态可以概括为三件事: -> **核心比喻:一位会思考、能学习、永不犯错的数字员工。** +1. 把用户任务接入统一的 Agent 执行入口。 +2. 通过固定的 `browser_action` 工具把意图翻译为浏览器命令。 +3. 在协议、域名和动作白名单的约束下完成可审计的页面操作。 -sgClaw 从浏览器内核层面发起操作,与真实用户行为完全一致,不可被反自动化机制识别,从根本上解决了传统外部 RPA 工具被检测、被拦截的行业痛点。 - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ SuperRPA 定制 Chromium 浏览器 │ -│ │ -│ ┌──────────────────────┐ ┌────────────────────────────────┐ │ -│ │ 浏览器主窗口 │ │ Side Panel 控制区 │ │ -│ │ │ │ │ │ -│ │ ┌────────────────┐ │ │ ┌──────────────────────────┐ │ │ -│ │ │ ERP / OA / │ │ │ │ [启动 Agent] [停止] │ │ │ -│ │ │ 财务 / HR 等 │ │ │ │ │ │ │ -│ │ │ 业务系统页面 │ │ │ │ 指令输入: │ │ │ -│ │ │ │ │ │ │ "导出本月合规报表" │ │ │ -│ │ │ │ │ │ │ │ │ │ -│ │ └────────────────┘ │ │ │ ▼ 任务进度 │ │ │ -│ │ ▲ │ │ │ ████████░░ 80% │ │ │ -│ │ │ 内核级操作 │ │ │ │ │ │ -│ │ │ │ │ │ ✓ 已登录 ERP │ │ │ -│ │ ┌──────┴─────────┐ │ │ │ ✓ 已导出财务报表 │ │ │ -│ │ │ sgClaw 引擎 │◄─┼────┼──│ ► 正在导出合规报表... │ │ │ -│ │ │ (Rust Binary) │ │ │ │ │ │ │ -│ │ └────────────────┘ │ │ └──────────────────────────┘ │ │ -│ └──────────────────────┘ └────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────┘ -``` +当前仓库中的 sgClaw 不是一个完整前端产品,也不是浏览器发行版本身,而是“浏览器 Agent Runtime + Pipe 协议 + ZeroClaw 兼容层”的产品核心。 --- -## 2. 行业痛点 +## 2. 重构后的产品边界 -国家电网及大型央企的业务运营高度依赖多套信息系统协同。一线业务人员每天需要在 5 至 10 余套系统之间反复切换,手工搬运数据,面临以下核心痛点: +### 2.1 当前已经落地的能力 -### 2.1 效率低下 +- 浏览器侧通过 STDIO JSON Line 协议与 Rust 进程通信。 +- 启动时执行 `init -> init_ack` 握手,并建立会话级 HMAC 密钥。 +- 任务输入统一走 `submit_task` 消息。 +- Rust 侧支持两条执行路径: + - 未配置大模型时,使用仓库内置 planner/fallback 逻辑。 + - 配置 `DEEPSEEK_*` 环境变量时,切换到 ZeroClaw compatibility runtime。 +- 当前有效工具面收敛为一个工具:`browser_action`。 +- 当前真正开放给模型的动作仅 4 个:`click`、`type`、`navigate`、`getText`。 +- 所有浏览器动作都受 `resources/rules.json` 中的域名和动作白名单约束。 +- 执行过程中会向宿主发送结构化日志和最终任务结果。 -一线员工日常需在 ERP、OA、财务管控、人力资源、经济法务、营销等多套系统间反复登录、切换、手工录入。一项跨系统操作(如合规线索提报)平均需要 **15-30 分钟**,涉及 **3-5 个系统** 的数据交叉核对。全年此类重复操作累计耗费数万人时。 +### 2.2 当前明确不宣称的能力 -### 2.2 人工差错 +以下内容在旧文档中存在较多规划性描述,但并非当前仓库中的已实现事实: -手工跨系统数据搬运极易出错。财务合规场景下,一个数字的录入错误可能导致审计异常,引发合规风险。据行业统计,人工跨系统操作的 **错误率约为 2%-5%**,在高强度、高压力的月末结算期间错误率更高。 +- 独立的 Skill 仓库与 Skill 脚本执行引擎。 +- 完整 MCP 工具接入和多工具编排。 +- 独立 Critic/Circuit Breaker 子系统。 +- 完整的浏览器 Side Panel 产品界面。 +- 40+ 页面动作在 Agent 侧全部开放。 +- 真实生产级多租户、审计后台、任务编排中心。 -### 2.3 培训成本高 - -新员工需要 **3-6 个月** 才能熟练掌握多套业务系统的操作流程和业务规则。人员调动频繁时,培训成本成倍增长,且经验难以沉淀、传承。 - -### 2.4 合规风险 - -手工操作缺乏完整的审计轨迹,难以事后追溯"谁在什么时间对哪个系统做了什么操作"。在日趋严格的内控与合规要求下,这构成了显著的制度性风险。 - -### 2.5 重复劳动 - -经调研分析,一线业务人员 **约 80%** 的跨系统操作属于规则明确、流程固定的重复性工作。这些工作本应由自动化工具承担,但因系统间壁垒和技术限制,长期依赖人力完成。 - -### 2.6 传统 RPA 局限 - -外部 RPA 工具(UiPath、BluePrism 等)通过屏幕抓取、模拟点击等方式操控浏览器,存在根本性缺陷: - -- **易被检测**:反自动化机制可识别 WebDriver、Selenium 等注入痕迹 -- **被系统拦截**:越来越多的业务系统部署了 Bot Detection,直接阻断 RPA 操作 -- **需专业脚本**:每个流程需要专门开发自动化脚本,维护成本高 -- **环境依赖**:对操作系统版本、屏幕分辨率、系统界面变更高度敏感 +这些能力可以保留为后续扩展方向,但不应继续写入 L0-L4 作为现状描述。 --- -## 3. 核心能力矩阵 +## 3. 产品价值主张 -| 能力维度 | 能力描述 | 关键指标 | -|---------|---------|---------| -| **自然语言驱动** | 用户以自然语言(中文)描述业务意图,Agent 自主理解语义、分解任务、规划步骤并执行 | 支持复杂多步指令,意图识别准确率 > 95% | -| **内核级隐蔽操作** | 从浏览器内核层面发起 DOM 操作与事件派发,与真实用户行为在技术栈上完全一致 | 反自动化检测通过率 100%,零注入痕迹 | -| **自进化学习** | 每次成功执行的操作序列自动沉淀为 Skill,后续同类任务直接复用,无需重复推理 | Skill 复用率随使用时长持续提升 | -| **三层安全防御** | Pipeline 协议层安全 + Rust 命令验证层 + C++ 内核 MAC 强制访问控制 | 纵深防御,任一层均可独立拦截非法操作 | -| **Skill 技能仓库** | 预置覆盖财务合规、风险管控、营销、人力资源、经济法务等业务领域的操作技能包 | 开箱即用,支持自定义扩展 | -| **多模型适配** | 支持 Claude、GPT 系列、本地化模型(Qwen、ChatGLM 等),可按安全等级灵活切换 | 模型切换零代码,响应延迟 < 2s | -| **跨平台支持** | 原生支持 Linux(银河麒麟 V10)与 Windows,满足国产化适配要求 | 信创环境全面兼容 | -| **极致轻量** | Rust 编写的 Agent 引擎,资源占用极低 | 内存 ~5MB,冷启动 < 10ms | +ZeroClaw 重构后的 sgClaw,核心价值不在“功能堆叠”,而在于把原本分散的浏览器自动化能力收敛成一个可控、可替换、可验证的智能体执行底座。 -``` -┌─────────────────────────────────────────────────────────────┐ -│ sgClaw 核心能力全景图 │ -├─────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ -│ │ 自然语言 │ │ 自进化学习 │ │ 多模型适配 │ │ -│ │ 理解与规划 │ │ Skill 沉淀 │ │ Claude/GPT/Qwen │ │ -│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │ -│ │ │ │ │ -│ ▼ ▼ ▼ │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ sgClaw Agent 引擎 (Rust) │ │ -│ │ 内存 ~5MB | 冷启动 < 10ms │ │ -│ └───────────────────────┬──────────────────────────────┘ │ -│ │ │ -│ ┌────────────────┼────────────────┐ │ -│ ▼ ▼ ▼ │ -│ ┌────────────┐ ┌─────────────┐ ┌────────────────┐ │ -│ │ Pipeline │ │ Rust 命令 │ │ C++ 内核 MAC │ │ -│ │ 协议层安全 │ │ 验证层 │ │ 强制访问控制 │ │ -│ └────────────┘ └─────────────┘ └────────────────┘ │ -│ │ │ │ │ -│ └────────────────┼────────────────┘ │ -│ ▼ │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ 内核级隐蔽操作 (Chromium C++ 层) │ │ -│ │ DOM 操作 · 事件派发 · 与真实用户行为完全一致 │ │ -│ └──────────────────────────────────────────────────────┘ │ -│ │ │ -│ ┌────────────────┼────────────────┐ │ -│ ▼ ▼ ▼ │ -│ ┌────────────┐ ┌─────────────┐ ┌────────────────┐ │ -│ │ Skill 仓库 │ │ 跨平台支持 │ │ 全链路审计 │ │ -│ │ 业务技能包 │ │ 麒麟/Windows │ │ trace_id 追溯 │ │ -│ └────────────┘ └─────────────┘ └────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────┘ -``` +### 3.1 对业务侧 + +- 用自然语言触发浏览器任务,不再直接暴露底层页面命令。 +- 统一任务入口,降低页面自动化能力的使用门槛。 +- 执行链路具备日志、结果回传和协议约束,便于纳入业务流程。 + +### 3.2 对集成侧 + +- 浏览器宿主只需实现固定协议,不必理解模型内部细节。 +- Agent Runtime 可以在保留宿主协议的前提下切换实现策略。 +- ZeroClaw 兼容层把未来模型、记忆、工具调度的升级入口预留在 Rust 侧。 + +### 3.3 对安全侧 + +- 不是“模型可任意操作浏览器”,而是“模型只能调用被允许的动作”。 +- 安全边界前置到协议和 MAC Policy,而不是把约束留给提示词。 +- 域名、动作、HMAC 三类控制共同组成最小可信执行面。 --- -## 4. 典型业务场景 +## 4. 能力全景 -### 4.1 财务合规 - -**场景示例**:合规线索提报与交叉核查 - -用户指令:*"将本月 ERP 中的异常交易记录与财务管控系统的合规规则交叉比对,生成合规线索提报清单。"* - -sgClaw 执行流程: -1. 自动登录 ERP 系统,导航至异常交易模块 -2. 按时间范围筛选并导出本月异常交易数据 -3. 切换至财务管控系统,调取对应合规规则库 -4. 逐条交叉比对,标记命中合规规则的记录 -5. 自动生成合规线索提报清单,填入指定模板 -6. 提交至审批流程,附加完整操作审计记录 - -**业务价值**:原需 2-3 小时的人工操作压缩至 **5-8 分钟**,错误率从 3% 降至 **0%**。 - -### 4.2 风险管控 - -**场景示例**:跨系统风险指标监测与异常预警 - -用户指令:*"每日自动检查 ERP 和风控系统中的关键风险指标,发现异常立即生成预警报告。"* - -sgClaw 执行流程: -1. 定时自动巡检 ERP 系统中的关键财务指标 -2. 同步核查风控系统中的风险阈值配置 -3. 对比分析指标偏离情况,识别异常模式 -4. 异常触发时自动截屏取证、生成预警报告 -5. 推送至相关负责人,并在 OA 系统创建跟踪工单 - -**业务价值**:实现 **7x24 小时** 不间断风险监控,预警响应时间从 "次日发现" 缩短至 **实时告警**。 - -### 4.3 营销 - -**场景示例**:电费异常批量处理与账单核对 - -用户指令:*"批量处理本月电费账单异常记录,对比营销系统与财务系统的数据差异。"* - -sgClaw 执行流程: -1. 进入营销系统,筛选本月标记为异常的电费账单 -2. 逐条提取异常记录的用户编号、金额、异常类型 -3. 在财务系统中查询对应的收费记录 -4. 自动比对金额差异,生成差异明细报表 -5. 对可自动修正的记录执行批量修正操作 -6. 对需人工确认的记录生成待办清单 - -**业务价值**:月均处理量从 **200 条/人日** 提升至 **5000+ 条/小时**,释放大量人力投入高价值工作。 - -### 4.4 人力资源 - -**场景示例**:社保表单自动填报与薪酬数据核验 - -用户指令:*"从 HR 系统导出本月社保基数变更人员名单,自动填入社保申报表并交叉验证薪酬数据。"* - -sgClaw 执行流程: -1. 登录 HR 系统,导出社保基数变更人员明细 -2. 自动填入社保局在线申报表单的对应字段 -3. 同步查询薪酬系统中的工资明细数据 -4. 交叉验证社保基数与实际薪酬的一致性 -5. 标记不一致记录,生成差异报告 -6. 合规记录自动提交,异常记录流转至人工复核 - -**业务价值**:每月社保申报工作从 **3-5 个工作日** 压缩至 **2-4 小时**。 - -### 4.5 经济法务 - -**场景示例**:合同履约监测与法律风险预警 - -用户指令:*"监控即将到期的合同,检查履约状态,对存在违约风险的合同生成法律风险预警。"* - -sgClaw 执行流程: -1. 在合同管理系统中筛选 30 天内到期的合同 -2. 逐一核查合同关键条款的履约状态 -3. 交叉查询 ERP 系统中的付款/交货记录 -4. 识别履约偏差,评估违约风险等级 -5. 生成法律风险预警报告,按风险等级排序 -6. 自动推送至法务部门,创建跟踪任务 - -**业务价值**:合同风险识别从 "事后补救" 转变为 **"事前预警"**,法律纠纷发生率显著降低。 - -### 4.6 协同办公 - -**场景示例**:跨系统数据同步与报表整合 - -用户指令:*"从 ERP、财务、HR 三个系统导出本月关键运营数据,汇总生成月度经营分析报表。"* - -sgClaw 执行流程: -1. 依次登录 ERP、财务、HR 系统 -2. 按预设模板提取各系统的关键运营数据 -3. 自动对齐数据口径,统一格式 -4. 汇总计算关键指标,生成月度经营分析报表 -5. 导出为标准格式,上传至 OA 系统 - -**业务价值**:月度报表整合从 **2-3 天人工汇总** 缩短至 **30 分钟自动生成**。 - -### 4.7 通用场景 - -用户只需一句自然语言指令,sgClaw 即可自主完成端到端的跨系统操作: - -| 自然语言指令 | Agent 自主完成的操作 | -|------------|-------------------| -| "导出本月所有合规报表" | 依次登录各业务系统 → 定位报表模块 → 设定时间范围 → 导出 → 汇总 | -| "检查上周新入职员工的系统权限配置" | HR 系统查询入职名单 → 各业务系统逐一核查权限 → 生成核查报告 | -| "把 ERP 里的采购订单数据同步到财务系统" | ERP 导出订单 → 格式转换 → 财务系统录入 → 数据校验 | -| "统计各部门本季度差旅报销总额" | OA 系统提取差旅审批 → 财务系统核查报销 → 按部门汇总 → 生成报表 | +| 能力域 | 当前状态 | 产品含义 | +|---|---|---| +| 任务接入 | 已实现 | 接收浏览器宿主发来的 `submit_task` 指令 | +| 协议握手 | 已实现 | 统一版本、会话标识、HMAC 种子交换 | +| Agent 执行 | 已实现 | planner fallback 与 ZeroClaw compat 共存 | +| 浏览器工具 | 已实现 | 单一 `browser_action` 工具 | +| 核心动作 | 已实现 | `click/type/navigate/getText` | +| 域名白名单 | 已实现 | 仅允许规则文件中的域名 | +| 动作白名单 | 已实现 | 仅允许规则文件中的动作 | +| 结构化日志 | 已实现 | `log_entry` 与 `task_complete` 回传 | +| 扩展动作枚举 | 已预留 | 协议枚举已定义,但默认未开放 | +| Skill 引擎 | 未独立实现 | 当前仅保留“可被工具和提示词扩展”的语义入口 | +| MCP 生态 | 未在主链路启用 | ZeroClaw 兼容层为后续保留位置 | --- -## 5. 技术优势对比 +## 5. 典型产品场景 -### 5.1 综合对比矩阵 +### 5.1 页面导航与信息读取 -| 对比维度 | 人工操作 | 传统 RPA (UiPath/BluePrism) | 外部 Agent (OpenClaw) | **sgClaw** | -|---------|---------|---------------------------|---------------------|-----------| -| **架构方式** | N/A | 外部进程控制浏览器 | 外部进程 + WebSocket | **嵌入浏览器内核** | -| **反检测能力** | 天然通过 | 易被检测拦截 | 可被端口扫描发现 | **原生行为,不可检测** | -| **安全层级** | 依赖人员素质 | 应用层安全 | 应用层安全 | **三层纵深防御** | -| **通信方式** | N/A | HTTP / COM | HTTP / WebSocket (端口暴露) | **STDIO Pipe (进程私有)** | -| **内存占用** | N/A | 200-500MB | 394MB+ | **~5MB** | -| **冷启动时间** | N/A | 10-30s | 5-15s | **< 10ms** | -| **技能复用** | 经验口传 | 需重新开发脚本 | 需重新训练 | **复用已有 JS 业务代码** | -| **部署方式** | N/A | 独立安装 + 配置 | 独立安装 + 配置 | **内嵌浏览器,零独立安装** | -| **自然语言** | N/A | 不支持 | 部分支持 | **完整支持中文自然语言** | -| **国产化适配** | N/A | 有限支持 | 不支持 | **银河麒麟 V10 原生支持** | -| **学习门槛** | 3-6 个月 | 需专业 RPA 开发 | 需技术配置 | **自然语言,零学习成本** | +用户输入“进入 ERP 首页并读取当前待办数量”,系统可以拆解为: -### 5.2 关键差异化优势 +1. `navigate` 到目标地址。 +2. `getText` 读取页面目标区域。 +3. 返回结构化结果摘要。 -``` -┌──────────────────────────────────────────────────────────────────┐ -│ 架构差异:外部控制 vs 内核嵌入 │ -├──────────────────────────────────────────────────────────────────┤ -│ │ -│ 传统 RPA / 外部 Agent 方案: │ -│ │ -│ ┌────────────┐ HTTP/WS ┌──────────────┐ │ -│ │ RPA Engine │ ──────────────→│ 浏览器 │ │ -│ │ (外部进程) │ 端口暴露 │ (被外部控制) │ │ -│ └────────────┘ 可被检测 └──────────────┘ │ -│ 394MB+ 反自动化机制 │ -│ 可识别拦截 │ -│ │ -│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ -│ │ -│ sgClaw 方案: │ -│ │ -│ ┌──────────────────────────────────────────────┐ │ -│ │ SuperRPA Chromium 浏览器 │ │ -│ │ │ │ -│ │ ┌──────────┐ STDIO Pipe ┌──────────────┐ │ │ -│ │ │ sgClaw │ ◄──────────► │ Chromium C++ │ │ │ -│ │ │ (Rust) │ 进程私有 │ 内核层 │ │ │ -│ │ │ ~5MB │ 零端口暴露 │ │ │ │ -│ │ └──────────┘ └──────────────┘ │ │ -│ │ │ │ -│ │ 操作 = 原生用户行为,不可被检测 │ │ -│ └──────────────────────────────────────────────┘ │ -│ │ -└──────────────────────────────────────────────────────────────────┘ -``` +这是当前仓库最稳定、最符合实现面的任务类型。 + +### 5.2 表单录入与提交流程中的局部自动化 + +当页面元素定位规则明确时,系统可用 `click` 和 `type` 组合完成表单录入、按钮点击、简单提交等动作。 +是否能覆盖完整业务流程,取决于浏览器宿主是否提供对应页面、选择器和回包信息,而不是文档层面预设“所有流程都能端到端执行”。 + +### 5.3 作为更大产品中的 Agent 执行核 + +sgClaw 更适合被理解为产品底座中的一个执行核: + +- 上层可以接入任务输入框、审批入口或业务编排器。 +- 下层通过既有浏览器控制面执行。 +- 中间由 sgClaw 把自然语言与浏览器动作连接起来。 --- -## 6. 安全与合规保障 +## 6. 成功标准 -sgClaw 将安全视为产品基因而非附加功能,构建了从通信层到内核层的 **三层纵深防御体系**。 +重构后的产品文档,以“真实能力清晰可交付”为标准,而不是以“愿景尽可能大”为标准。当前版本应满足: -### 6.1 进程隔离通信 - -- 采用 **STDIO Pipe** 作为 Agent 与浏览器内核的唯一通信通道 -- 不开放任何网络端口,外部进程无法探测或连接 -- 通信数据仅存在于父子进程的文件描述符中,操作系统级别的隐私保护 - -### 6.2 MAC 强制访问控制 - -- 浏览器 C++ 内核层实施 **Mandatory Access Control** -- 严格的域名白名单机制:Agent 仅可操作授权的业务系统域名 -- 敏感操作(如支付、审批)需额外的内核级权限校验 -- 白名单策略由管理员统一配置,Agent 无法自行绕过 - -### 6.3 凭证安全保护 - -- 用户凭证由浏览器 Zombie Session Pool 统一管理 -- 凭证信息 **永远不会通过 Pipe 协议传输** 至 Agent 进程 -- Agent 通过 BrowserAction API 间接使用已建立的会话,无需接触明文密码 - -### 6.4 人工激活机制 - -- Agent 功能 **默认关闭**,需用户在 Side Panel 中显式点击启动按钮 -- 每次启动均需用户确认,杜绝后台无感自动运行 -- 用户可随时一键停止 Agent 的所有操作 - -### 6.5 全链路审计追溯 - -- 每次 Agent 会话分配唯一 **trace_id** -- 所有操作步骤(页面导航、元素点击、数据读取、表单提交)均有完整日志记录 -- 日志包含操作时间戳、目标系统、操作类型、执行结果 -- 支持事后审计回溯与合规举证 - -### 6.6 防失控熔断机制 - -- 内置 **Circuit Breaker** 机制,防止 Agent 进入死循环或失控状态 -- 单次任务设置最大步骤数上限 -- 连续失败自动熔断,暂停执行并通知用户 -- 关键操作设置人工确认断点(human-in-the-loop) - ---- - -## 7. 产品形态与交付方式 - -### 7.1 产品形态 - -| 组件 | 形态 | 规格 | -|------|------|------| -| Agent 引擎 | Rust 编译二进制 | 约 8.8MB | -| 宿主环境 | SuperRPA 定制 Chromium 浏览器 | 集成交付 | -| 用户界面 | 浏览器 Side Panel 控制区 | 启停按钮 + 指令输入 + 任务进度 | -| Skill 仓库 | JSON 格式技能定义文件 | 随浏览器内置,支持在线更新 | -| 运行时依赖 | 无 | Rust 静态编译,零外部依赖 | - -### 7.2 交付方式 - -- **Linux (银河麒麟 V10)**:集成于 `superrpa-chromium` .deb 安装包 -- **Windows**:集成于 `superrpa-chromium` .exe 安装包 -- **无需独立安装**:随浏览器一并部署,无额外配置步骤 -- **无需独立升级**:随浏览器版本统一升级管理 - -### 7.3 用户交互流程 - -``` -用户操作流程: - - 打开 SuperRPA 浏览器 - │ - ▼ - 访问业务系统(自动登录) - │ - ▼ - 打开 Side Panel ──→ 看到 sgClaw 控制区 - │ - ▼ - 点击 [启动 Agent] 按钮 - │ - ▼ - 输入自然语言指令 ──→ "导出本月所有合规报表" - │ - ▼ - Agent 自主执行 ──→ Side Panel 实时显示进度 - │ - ▼ - 执行完成 ──→ 结果展示 / 文件下载 - │ - ▼ - (可选)点击 [停止] 终止任务 -``` - ---- - -## 8. 与 SuperRPA 浏览器的协同关系 - -sgClaw 并非独立产品,而是与 SuperRPA 浏览器深度耦合的 **智能增强层**。两者各司其职,协同构成完整的"智能数字员工"平台。 - -### 8.1 能力分工 - -``` -┌────────────────────────────────────────────────────────────────────┐ -│ "智能数字员工" 完整能力栈 │ -├────────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌──────────────────────────────────────────────────────────────┐ │ -│ │ sgClaw 智能增强层 │ │ -│ │ │ │ -│ │ ┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ -│ │ │ LLM 智能 │ │ 自然语言 │ │ 多步自主 │ │ 自进化学习 │ │ │ -│ │ │ 推理引擎 │ │ 理解 │ │ 任务执行 │ │ Skill 沉淀 │ │ │ -│ │ └────────────┘ └──────────┘ └──────────┘ └──────────────┘ │ │ -│ │ │ │ -│ └──────────────────────────┬───────────────────────────────────┘ │ -│ │ STDIO Pipe │ -│ ┌──────────────────────────┴───────────────────────────────────┐ │ -│ │ SuperRPA 浏览器基础设施层 │ │ -│ │ │ │ -│ │ ┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ -│ │ │ Zombie │ │ SDK │ │ Browser │ │ 凭证与会话 │ │ │ -│ │ │ Session │ │ 注入引擎 │ │ Action │ │ 安全管理 │ │ │ -│ │ │ Pool │ │ │ │ API │ │ │ │ │ -│ │ └────────────┘ └──────────┘ └──────────┘ └──────────────┘ │ │ -│ │ │ │ -│ │ ┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ -│ │ │ 反检测 │ │ 多标签页 │ │ 域名 │ │ C++ 内核 │ │ │ -│ │ │ 指纹伪装 │ │ 并发管理 │ │ 白名单 │ │ MAC 控制 │ │ │ -│ │ └────────────┘ └──────────┘ └──────────┘ └──────────────┘ │ │ -│ │ │ │ -│ └──────────────────────────────────────────────────────────────┘ │ -│ │ -├────────────────────────────────────────────────────────────────────┤ -│ 协同价值 │ -│ │ -│ SuperRPA 提供: sgClaw 增加: │ -│ ├─ Zombie Session Pool 会话池 ├─ LLM 智能推理能力 │ -│ ├─ SDK 注入与 JS 执行环境 ├─ 自然语言理解与意图解析 │ -│ ├─ BrowserAction API 操作接口 ├─ 自主多步任务规划与执行 │ -│ ├─ 凭证管理与自动登录 ├─ 自进化学习与 Skill 积累 │ -│ ├─ 反自动化检测基础设施 ├─ 跨系统业务流程编排 │ -│ └─ 内核级安全强制控制 └─ 业务语义理解与异常处理 │ -│ │ -│ 单独的 SuperRPA = 强大的自动化浏览器 │ -│ SuperRPA + sgClaw = 会思考的智能数字员工 │ -│ │ -└────────────────────────────────────────────────────────────────────┘ -``` - -### 8.2 典型协同流程 - -以"自动完成月度合规报表导出"为例: - -| 步骤 | 执行者 | 操作 | -|------|-------|------| -| 1 | SuperRPA | Zombie Session Pool 提供已登录的各系统会话 | -| 2 | sgClaw | LLM 理解用户指令,规划任务步骤 | -| 3 | sgClaw | 通过 BrowserAction API 向浏览器发送操作指令 | -| 4 | SuperRPA | SDK 注入层执行 DOM 操作(内核级,不可检测) | -| 5 | SuperRPA | C++ 内核 MAC 校验操作合法性(域名白名单) | -| 6 | sgClaw | 解析操作结果,决定下一步行动 | -| 7 | sgClaw | 任务完成后将操作序列沉淀为 Skill | -| 8 | SuperRPA | 记录完整操作审计日志(含 trace_id) | - -### 8.3 价值总结 - -sgClaw 与 SuperRPA 浏览器的结合,实现了 **"能力 + 智能"** 的完整闭环: - -- **SuperRPA 浏览器** 解决了 "如何安全、隐蔽地操作业务系统" 的基础设施问题 -- **sgClaw** 解决了 "如何智能地理解业务意图并自主执行" 的上层智能问题 -- 两者结合,使"业数融合一平台"真正具备 **"理解自然语言 → 自主规划 → 安全执行 → 持续进化"** 的完整智能数字员工能力 - ---- - -> **sgClaw — 让每一位员工都拥有一位永不疲倦、永不犯错的智能数字助手。** +- 任何架构描述都能在 `src/`、`resources/`、`tests/` 中找到对应实现。 +- 任何对外宣称的动作能力都与 `rules.json` 和工具 schema 一致。 +- 任何“未来可扩展”内容都与“当前已实现”明确区分。 +- L0 到 L4 能从产品、架构、接口、数据流、工程五层连续闭环。 diff --git a/docs/L1-系统架构与安全模型层.md b/docs/L1-系统架构与安全模型层.md index 69102bd..df94d5d 100644 --- a/docs/L1-系统架构与安全模型层.md +++ b/docs/L1-系统架构与安全模型层.md @@ -1,996 +1,162 @@ # L1 — 系统架构与安全模型层 -**文档版本**: 1.0 -**适用项目**: sgClaw (业数融合一平台 AI Agent 底座) -**编制日期**: 2026-03-03 +**文档版本**: 2.0 +**适用项目**: sgClaw(ZeroClaw 重构版) +**编制日期**: 2026-03-26 --- -## 1. 全局架构拓扑 +## 1. 架构总览 -### 1.1 完整架构图 - -以下是 sgClaw 系统的完整进程与组件拓扑。图中标注了新增组件(New)与已有组件(Existing), -以便评估改造范围。 +重构后的 sgClaw 架构要点很简单:浏览器宿主负责页面执行,Rust 进程负责任务解释与协议编排,ZeroClaw 作为兼容运行时被接入到 Rust 侧,而不是直接替代整个系统。 ``` -superrpa-chromium.sh (wrapper, 启动入口) - │ - ├─ watchdog (background) ─────────────────────────── [Existing, 不变] - │ └─ node local_service [Existing, 不变] - │ ├─ 本地 HTTP API (端口 9527) - │ └─ 文件上传 / 下载辅助 - │ - └─ chrome (main process, foreground) ─────────────── [Existing, 不变] - │ - ├─ SgClawProcessHost ────────────────────────── [New, Singleton in Browser Process] - │ │ - │ ├── STDIO Pipe (stdin/stdout) ──────────→ sgclaw (Rust child process) - │ │ │ - │ │ ├─ Agent Runtime ──────── ZeroClaw ReAct Loop - │ │ │ └─ think → act → observe → repeat - │ │ │ - │ │ ├─ LLM Provider ──────── Claude / GPT / 本地模型 - │ │ │ ├─ streaming 支持 - │ │ │ └─ token 用量统计 - │ │ │ - │ │ ├─ BrowserPipeTool ──── 自定义 Tool trait 实现 - │ │ │ └─ 将 Agent action 序列化为 pipe command - │ │ │ - │ │ ├─ SkillLoader ──────── 加载 JS 业务技能脚本 - │ │ │ ├─ 技能签名校验 - │ │ │ └─ 沙箱执行环境 - │ │ │ - │ │ ├─ MAC Policy ──────── 域 / Action 白名单 - │ │ │ └─ rules.json 配合浏览器侧双重校验 - │ │ │ - │ │ ├─ Critic ─────────── 输出质量评估 - │ │ │ └─ Circuit Breaker (熔断器) - │ │ │ - │ │ ├─ Memory ─────────── SQLite + Vector 向量存储 - │ │ │ ├─ 短期对话记忆 - │ │ │ └─ 长期任务知识库 - │ │ │ - │ │ └─ MCP Client ─────── rmcp (Rust MCP SDK) - │ │ └─ 连接外部 MCP Server 获取工具 - │ │ - │ ├─ PipeListener (async read loop) - │ │ └─ 解析 JSON Line,分发到 MAC 校验 - │ │ - │ ├─ MAC Whitelist Check ──────────────────── [New, ~100 lines C++] - │ │ ├─ 校验 action 是否在 pipe 允许列表 - │ │ └─ 校验 expected_domain 是否匹配当前页 - │ │ - │ └─→ CommandRouter ──────────────────────── [Existing, 40+ actions, 不变] - │ ├─ CdpCommandExecutor → 页面操作 - │ ├─ ZombiePageManager → 后台会话池 - │ └─ SessionManager → 会话状态机 - │ - ├─ CdpBridgeManager ────────────────────────── [Existing, 页内 JS SDK, 不变] - │ └─ 页面 JS → CDP binding → CommandRouter - │ - ├─ ZombiePageManager ───────────────────────── [Existing, 后台会话池, 不变] - │ └─ 最多 5 个 zombie page,自动回收 - │ - ├─ SessionManager ──────────────────────────── [Existing, 会话状态机, 不变] - │ └─ login → active → expired → re-login - │ - └─ RpaGlobalStorage ────────────────────────── [Existing, 跨页存储, 不变] - └─ key-value 存储,持久化到磁盘 +┌──────────────────────────────┐ +│ Browser Host / Chromium Side │ +│ - 启动 sgClaw 子进程 │ +│ - 发送 init / submit_task │ +│ - 执行 command 并回 response │ +└──────────────┬───────────────┘ + │ STDIO + JSON Line +┌──────────────▼───────────────┐ +│ sgClaw Rust Runtime │ +│ - 握手与消息循环 │ +│ - MAC Policy │ +│ - BrowserPipeTool │ +│ - Planner fallback │ +│ - ZeroClaw compat runtime │ +└──────────────┬───────────────┘ + │ Provider API / Local Config +┌──────────────▼───────────────┐ +│ Model Provider │ +│ - DeepSeek/OpenAI-compatible │ +│ - 仅在配置存在时启用 │ +└──────────────────────────────┘ ``` -### 1.2 简化四组件视图 - -从系统集成的角度,sgClaw 的架构可简化为四个核心组件的交互: - -``` -┌─────────────────────┐ STDIO Pipe ┌─────────────────────┐ -│ │ ◄──────────────────────────► │ │ -│ SuperRPA Browser │ JSON Line Protocol │ sgClaw (Rust) │ -│ (C++ Chromium) │ 单连接、进程私有 │ 基于 ZeroClaw │ -│ │ │ │ -│ • CommandRouter │ │ • Agent Runtime │ -│ • CdpBridgeManager│ │ • BrowserPipeTool │ -│ • ZombiePageMgr │ │ • SkillLoader │ -│ • SessionManager │ │ • Memory │ -│ • SgClawProcessHost│ │ • MAC Policy │ -│ (New) │ │ • Critic │ -└─────────┬───────────┘ └──────┬──┬──────────┘ - │ │ │ - │ 页面渲染 API 调用 │ │ 加载技能 - │ 用户交互 │ │ - ▼ ▼ ▼ -┌─────────────────────┐ ┌────────────────────────────┐ -│ │ │ │ -│ 用户 (前台浏览器) │ │ LLM Cloud / Local │ -│ │ │ ├─ Claude API │ -│ • Side Panel UI │ │ ├─ GPT API │ -│ • 启动/停止按钮 │ │ └─ 本地模型 (Ollama 等) │ -│ • 任务输入框 │ │ │ -│ • 执行日志 │ ├────────────────────────────┤ -│ │ │ │ -└─────────────────────┘ │ Skill Repository │ - │ ├─ 内置技能 (OA 审批等) │ - │ ├─ 用户自定义技能 │ - │ └─ 签名校验 + 版本管理 │ - │ │ - └────────────────────────────┘ -``` +架构上最重要的变化是:当前系统不是“完整 ZeroClaw 产品”,而是“保留现有浏览器协议的前提下,把 ZeroClaw 作为兼容执行内核引入”。 --- -## 2. 技术选型决策记录 +## 2. 运行时分层 -### 2.1 基底框架选型: ZeroClaw +### 2.1 浏览器宿主层 -在确定 sgClaw 的 Agent Runtime 底座时,团队对 Rust 生态中主流 Agent 框架进行了系统评估。 -评估维度包括:社区活跃度、内存占用、可嵌入性(是否支持替换浏览器控制层)、以及与我们 -STDIO Pipe 架构的兼容性。 +宿主负责三类职责: -| Framework | Language | Stars | Runtime Memory | Embeddability | Browser Layer Replaceable | 备注 | -|------------|----------|-------|----------------|----------------------|---------------------------|---------------------------| -| **ZeroClaw** | Rust | 17K | ~5 MB | High (trait-driven) | **Best** | 活跃社区,trait 抽象完善 | -| Rig | Rust | 6.2K | Minimal | Best (cargo add) | Full custom | 轻量但 Agent loop 需自建 | -| Moltis | Rust | - | ~40 MB | Medium | Via MCP only | 内存偏高,嵌入需改造 | -| OpenFang | Rust | New | ~40 MB | Low (API only) | Difficult | API Server 架构,不适合嵌入 | -| MicroClaw | Rust | 152 | - | Low (fork needed) | Via MCP only | 社区不活跃,需 fork 维护 | +- 启动和托管 sgClaw Rust 子进程。 +- 按协议发送 `init`、`submit_task`、`response`。 +- 执行 Rust 发来的浏览器命令并回包。 -**决策:ZeroClaw** +sgClaw 仓库本身不包含 Chromium/C++ 实现代码,因此 L1 只定义宿主责任边界,不再把外部仓库中的假定文件结构写成“当前仓库现状”。 -核心理由: +### 2.2 Rust 控制层 -1. **trait-driven 架构**:ZeroClaw 将 Tool、Provider、Memory、Security 全部定义为 trait, - 允许我们用自定义的 `BrowserPipeTool` 替换默认的浏览器控制层(如 Playwright/Puppeteer), - 同时复用其 Agent Runtime、Provider 抽象、Memory 系统和安全模块。 +Rust 侧是当前仓库的事实主体,职责包括: -2. **内存优势**:~5 MB 的运行时内存占用,在 8 GB 总内存预算内几乎可以忽略不计。 - 相比 Moltis/OpenFang 的 ~40 MB,差异显著。 +- 在 [`src/lib.rs`](/home/zyl/projects/sgClaw/claw/src/lib.rs) 中建立 `StdioTransport`。 +- 完成握手、加载 `rules.json`、创建 `BrowserPipeTool`。 +- 在消息循环中接收浏览器消息并分发到执行层。 +- 把执行日志和任务结果回传给宿主。 -3. **ReAct Loop 成熟**:ZeroClaw 内置 think → act → observe 循环,支持 streaming、 - multi-turn、tool-use,无需从零构建。 +### 2.3 执行层 -4. **MCP 生态兼容**:内置 rmcp client,可在需要时连接外部 MCP Server 扩展工具集。 +执行层当前有两条路径: -### 2.2 通信协议选型: STDIO Pipe +1. `planner fallback` +说明:当未配置 `DEEPSEEK_API_KEY` 等环境变量时,使用仓库内置的轻量 planner 执行。 -sgClaw (Rust) 与 SuperRPA Browser (C++) 之间的 IPC 通道是整个架构的关键路径。 -团队评估了四种 IPC 机制: +2. `ZeroClaw compat runtime` +说明:当提供模型配置后,通过 [`src/compat/runtime.rs`](/home/zyl/projects/sgClaw/claw/src/compat/runtime.rs) 构造 provider、memory 和 `browser_action` 工具,把任务交给 vendored ZeroClaw Agent。 -| 方式 | Linux 支持 | Windows 支持 | 安全性 | 多连接支持 | 延迟 | -|------------------|-------------|---------------------|---------------------------------|-----------|----------| -| **STDIO Pipe** | fd inherit | HANDLE inherit | **最高** (进程私有,无法外部连接) | 否 | ~0.1 ms | -| Unix Domain Socket| /tmp/sock | 不支持 | 高 (文件权限控制) | 是 | ~0.2 ms | -| Named Pipe | 不支持 | \\\\.\pipe\ | 高 (DACL) | 是 | ~0.2 ms | -| TCP localhost | 支持 | 支持 | **低** (任意进程可连) | 是 | ~0.5 ms | - -**决策:STDIO Pipe** - -核心理由: - -1. **安全性最高**:STDIO Pipe 是进程私有的文件描述符(Linux)或句柄(Windows), - 只有父子进程间可以访问。本机其他进程无法连接、监听或注入命令。 - 这从物理层面杜绝了 Pipe Hijack 攻击。 - -2. **跨平台统一**:Chromium 的 `base::LaunchProcess` 已经抽象了跨平台的管道创建, - Linux 使用 `pipe()` + `fork()`/`exec()`,Windows 使用 `CreatePipe()` + `CreateProcess()`。 - 我们不需要编写任何平台特定代码。 - -3. **单连接足够**:sgClaw 是 Browser 的唯一 Rust 子进程,一条 STDIO Pipe 即可满足 - 全部双向通信需求。不需要多客户端并发连接的能力。 - -4. **延迟最低**:内核态 pipe buffer(Linux 默认 64 KB)的读写延迟约 0.1 ms, - 远低于 socket 方案。 - -### 2.3 Why Rust - -为什么 sgClaw 选择 Rust 而非 C++/Python/Node.js: - -1. **内存安全无 GC**:在 8 GB 总内存限制下,GC 语言的内存开销和暂停不可接受。 - Rust 的零成本抽象确保 ~5 MB 运行时内存,无 GC 停顿。 - -2. **跨平台编译**:目标平台包括 Linux 银河麒麟 V10 SP1 (x86_64) 和 Windows 10/11。 - Rust 的 cross-compilation 工具链 (`cross`, `cargo-zigbuild`) 可直接生成两个平台的二进制。 - -3. **极小二进制体积**:release 构建约 8.8 MB(含 LLM provider、memory、MCP client 全部功能), - Windows 约 9 MB。无需额外运行时依赖。 - -4. **冷启动极快**:< 10 ms 内完成进程初始化和 pipe handshake,用户点击"启动"后几乎无感。 - -5. **ZeroClaw 生态**:ZeroClaw 本身及其核心依赖(rmcp、tokenizers 等)均为 Rust 实现, - 选择 Rust 可直接复用,无需 FFI 桥接。 +这两条路径共存,是当前重构期的核心现实。文档必须保留这一点,否则会误导实现和联调。 --- -## 3. 进程模型与生命周期 +## 3. ZeroClaw 重构的架构意义 -### 3.1 进程层次结构 +ZeroClaw 在本项目中的角色不是“大而全框架接管一切”,而是解决三个具体问题: -sgClaw 嵌入 SuperRPA 浏览器的既有进程树中,作为 Chrome 主进程的子进程存在。 +- 统一模型 Provider 抽象。 +- 为后续记忆、工具调度、可观测性留出标准扩展位。 +- 在不改浏览器协议的前提下,替换任务执行内核。 -``` -superrpa-chromium.sh (wrapper, PID 1001) - │ - ├─ watchdog (PID 1002, background, 守护进程) - │ └─ node local_service (PID 1003, HTTP API) - │ ├─ 监听 127.0.0.1:9527 - │ ├─ 文件上传/下载 - │ └─ 与浏览器通过 HTTP 通信 - │ - └─ chrome (PID 1004, foreground, 用户交互主进程) - │ - │ 当用户在 Side Panel 点击 [启动] 按钮时: - │ SgClawProcessHost::Start() 被调用 - │ - └─ sgclaw (PID 1005, child of chrome) - │ - ├─ stdin ← chrome stdout (接收命令响应/事件) - ├─ stdout → chrome stdin (发送命令请求) - │ - ├─ Agent Runtime (ReAct loop) - ├─ LLM Provider (网络出口) - └─ Memory (SQLite 文件 I/O) -``` +当前兼容层的限制也必须明确: -关键特征: - -- sgclaw 是 chrome 的**直接子进程**,继承 chrome 的 UID/GID 权限 -- STDIO Pipe 的文件描述符在 `fork()`/`exec()` 时自动继承,无需额外传递 -- 当 chrome 进程退出时,sgclaw 会收到 SIGPIPE/EOF,自行退出 -- watchdog 和 local_service 与 sgclaw **无直接通信**,完全独立 - -### 3.2 生命周期状态机 - -``` - ┌──────────────────────────────────┐ - │ Side Panel UI: [启动] 按钮 │ - └──────────────┬───────────────────┘ - │ 用户点击 - ▼ - ┌──────────────────────────────────┐ - │ SgClawProcessHost::Start() │ - │ │ - │ 1. Check: sgclaw 二进制存在? │ - │ → 不存在: 报错,终止 │ - │ │ - │ 2. Check: 是否已有实例运行? │ - │ → 已运行: 直接返回 │ - │ │ - │ 3. 创建 pipe pair (读端+写端) │ - │ │ - │ 4. base::LaunchProcess( │ - │ "sgclaw", pipe_opts) │ - │ │ - │ 5. 启动 PipeReader async loop │ - │ │ - │ 6. 发送 handshake: │ - │ {"type":"init","version":"1.0"}│ - │ │ - │ 7. 等待 sgClaw ack (超时 5s) │ - │ → 超时: Kill + 报错 │ - │ │ - │ 8. Notify UI: Running │ - └──────────────┬───────────────────┘ - │ - ┌──────────────┴───────────────────┐ - │ Running (正常运行) │ - │ │ - │ • PipeReader 持续监听响应 │ - │ • Agent Runtime 接受用户任务 │ - │ • 命令经 pipe 发往 Browser │ - └──────┬──────────┬──────────┬─────┘ - │ │ │ - 用户点击 浏览器 sgClaw - [停止] 正常退出 异常崩溃 - │ │ │ - ▼ ▼ ▼ - ┌──────────┐ ┌─────────┐ ┌──────────────────┐ - │ Stop() │ │Shutdown()│ │ OnProcessCrash() │ - │ │ │ │ │ │ - │ 发送 │ │ 发送 │ │ 1. 记录崩溃日志 │ - │ shutdown │ │ SIGTERM │ │ 2. 收集 stderr │ - │ 命令 │ │ + 等待 │ │ 3. 通知 UI 异常 │ - │ 等待退出 │ │ 2s 超时 │ │ 4. 关闭 pipe │ - │ Kill │ │ SIGKILL │ │ │ - └────┬─────┘ └────┬────┘ │ *** 不自动重启 ***│ - │ │ └────────┬─────────┘ - ▼ ▼ ▼ - ┌──────────────────────────────────┐ - │ Stopped (已停止) │ - │ │ - │ • Pipe 已关闭 │ - │ • 子进程已退出 │ - │ • UI 显示 [启动] 按钮 │ - │ • 用户可再次点击启动 │ - └──────────────────────────────────┘ -``` - -**关键决策:崩溃不自动重启** - -当 sgclaw 进程崩溃时(如 panic、OOM、非零退出码),系统**不会**自动重启。 -用户必须显式点击 [启动] 按钮才能再次启动。理由: - -- 防止恶意 prompt injection 导致的无限崩溃重启循环 -- 防止异常状态下的资源耗尽(内存泄漏累积、日志磁盘写满) -- 给用户明确的故障感知,而非静默恢复后行为异常 - -### 3.3 内存预算 (8 GB 约束) - -目标部署环境为 8 GB 内存的银河麒麟工作站。以下是各组件的内存分配: - -``` -┌───────────────────────────────────┬────────────┬──────────┐ -│ 组件 │ 内存占用 │ 备注 │ -├───────────────────────────────────┼────────────┼──────────┤ -│ OS + Desktop (银河麒麟 V10) │ ~2.0 GB │ 固定开销 │ -│ Browser Process (主进程) │ ~0.2 GB │ 已有 │ -│ Foreground Tabs (1-3 tabs) │ ~0.3-0.9 GB│ 用户页面 │ -│ Side Panel (Agent UI) │ ~0.05 GB │ Vue SPA │ -│ Zombie Page Pool (max 5) │ ~0.15-0.25 GB│ 后台会话 │ -│ local_service (Node.js) │ ~0.1 GB │ 已有 │ -│ sgClaw (Rust binary) │ ~0.005 GB │ 5 MB │ -│ LLM context cache (对话历史) │ ~0.05 GB │ 内存缓存 │ -│ SQLite + vector memory │ ~0.02 GB │ 磁盘为主 │ -├───────────────────────────────────┼────────────┼──────────┤ -│ **Total** │ **~3.0-3.6 GB** │ │ -│ **Headroom** │ **~4.4-5.0 GB** │ >50% │ -└───────────────────────────────────┴────────────┴──────────┘ -``` - -sgClaw 的 ~5 MB 内存占用仅为总预算的 0.06%,对系统几乎零负担。 -即使在极端场景下(3 个前台标签 + 5 个 zombie page + LLM 长对话), -总内存使用也不超过 4 GB,保留超过 50% 的余量供操作系统和突发需求使用。 +- 只注册一个工具:`browser_action`。 +- 只开放 4 个动作:`click/type/navigate/getText`。 +- 不以 ZeroClaw 的全量工具生态作为对外能力宣称。 --- -## 4. 安全架构 +## 4. 安全模型 -### 4.1 三层纵深防御模型 +### 4.1 安全目标 -sgClaw 的安全架构采用纵深防御(Defense in Depth)策略,从内到外设置三道独立的安全层。 -任何单一层被突破时,上层仍能有效阻止攻击。 +系统安全目标不是“模型永远正确”,而是“即使模型给出错误指令,也只能在受限边界内执行”。 -``` -┌─────────────────────────────────────────────────────────────────────────┐ -│ │ -│ Layer 3: 浏览器内核层 (C++ Browser Process) │ -│ 最后一道防线 —— 不信任外部一切输入 │ -│ │ -│ ┌─ MAC 强制访问控制 ───────────────────────────────────────────┐ │ -│ │ │ │ -│ │ • 域白名单: 仅 rules.json 中配置的域允许特权操作 │ │ -│ │ → 未知域的 click/type 等操作直接拒绝 │ │ -│ │ │ │ -│ │ • Action 白名单: pipe 来源命令受限于安全子集 │ │ -│ │ → eval、executeJsInPage 等危险操作禁止通过 pipe 调用 │ │ -│ │ │ │ -│ │ • 凭证隔离: credential_store 数据永不通过 pipe 暴露 │ │ -│ │ → 登录操作由 SessionManager 内部完成 │ │ -│ │ │ │ -│ │ • 速率限制: 单域每秒最多 N 次特权操作 (可配置,默认 10) │ │ -│ │ → 超限后暂停该域操作 30 秒 │ │ -│ │ │ │ -│ └──────────────────────────────────────────────────────────────┘ │ -│ │ -├─────────────────────────────────────────────────────────────────────────┤ -│ │ -│ Layer 2: Rust 中枢层 (sgClaw Agent) │ -│ 核心原则 —— 不信任 LLM 输出 │ -│ │ -│ ┌─ 命令校验沙箱 ──────────────────────────────────────────────┐ │ -│ │ │ │ -│ │ • JSON Schema 严格校验: LLM 输出必须符合预定义的命令格式 │ │ -│ │ → 非法字段、类型错误、缺失必要参数均被拒绝 │ │ -│ │ │ │ -│ │ • 禁止危险命令: LLM 不可生成 eval / executeJsInPage 类命令 │ │ -│ │ → BrowserPipeTool 的 action 枚举中不包含这些操作 │ │ -│ │ │ │ -│ │ • Human-in-the-loop: 敏感操作弹窗确认 │ │ -│ │ → sessionLogin / sessionLogout / 大批量操作 │ │ -│ │ │ │ -│ │ • 序列号 + HMAC: 每条 pipe 消息携带递增 sequence_id │ │ -│ │ → 防止消息重放和篡改 │ │ -│ │ │ │ -│ │ • 熔断器 (Circuit Breaker): 连续失败 N 次自动停止 Agent │ │ -│ │ → 默认阈值 10 次,指数退避冷却 │ │ -│ │ │ │ -│ └──────────────────────────────────────────────────────────────┘ │ -│ │ -├─────────────────────────────────────────────────────────────────────────┤ -│ │ -│ Layer 1: 管道传输层 (STDIO Pipe) │ -│ 物理隔离 —— 传输通道本身不可被第三方访问 │ -│ │ -│ ┌─ 安全通道 ──────────────────────────────────────────────────┐ │ -│ │ │ │ -│ │ • STDIO Pipe: 进程私有 fd/HANDLE,无法被外部进程连接 │ │ -│ │ → 不经过文件系统、不绑定端口、不暴露地址 │ │ -│ │ │ │ -│ │ • Handshake 校验: 启动时双向版本握手 │ │ -│ │ → 版本不匹配则立即断开 │ │ -│ │ │ │ -│ │ • 递增 sequence_id: 所有消息附带全局递增序列号 │ │ -│ │ → 检测到乱序或重复即报警并断开 │ │ -│ │ │ │ -│ │ • 格式约束: JSON Line 格式,单消息最大 1 MB │ │ -│ │ → 超大消息直接丢弃,防止内存 DoS │ │ -│ │ │ │ -│ └──────────────────────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────────┘ -``` +### 4.2 三层安全约束 -### 4.2 各层防御详解 +#### 第一层:握手与会话完整性 -**Layer 1 — 管道传输层** +- 浏览器必须先发 `init`。 +- sgClaw 必须回 `init_ack`。 +- 会话级 `hmac_seed` 用于后续命令签名。 +- 未完成握手,不进入运行态。 -本层的设计目标是确保 sgClaw 与 Browser 之间的通信通道从物理层面不可被第三方窃听或注入。 +#### 第二层:Rust 侧 MAC Policy -防御对象: -- 本机恶意进程尝试连接或嗅探 IPC 通道 -- 中间人攻击(消息篡改、注入伪造命令) -- 消息重放(录制合法命令序列后重新发送) +[`src/security/mac_policy.rs`](/home/zyl/projects/sgClaw/claw/src/security/mac_policy.rs) 从 [`resources/rules.json`](/home/zyl/projects/sgClaw/claw/resources/rules.json) 加载规则,校验: -实现机制: -- STDIO Pipe 使用操作系统内核的匿名管道,文件描述符仅在父子进程间继承, - `/proc/[pid]/fd/` 对其他用户不可见(取决于 procfs 挂载选项,银河麒麟默认安全) -- 启动时的 handshake 消息包含协议版本号,防止二进制版本不匹配导致的解析错误 -- 每条消息的 `sequence_id` 全局递增,接收方校验连续性,检测到跳号或重复立即断开 pipe +- 目标域名是否在 `domains.allowed` 中。 +- 动作是否在 `pipe_actions.allowed` 中。 +- 被明确封禁的动作是否命中 `pipe_actions.blocked`。 -**Layer 2 — Rust 中枢层** +这意味着即便协议枚举中定义了更多动作,也不代表当前会话可以执行它们。 -本层的核心假设是 **LLM 的输出不可信**。无论是 prompt injection 还是 hallucination, -LLM 可能生成任何格式、任何内容的输出。sgClaw 必须在将命令发往 Browser 之前进行严格校验。 +#### 第三层:宿主侧命令执行约束 -防御对象: -- Prompt injection:恶意网页内容被 LLM 读取后,诱导其生成危险操作 -- Hallucination:LLM 生成不存在的 action 或格式错误的参数 -- 无限循环:LLM 陷入 retry 死循环,持续消耗资源 +浏览器宿主仍应在接收命令后做本地校验,包括: -实现机制: -- `BrowserPipeTool` 定义了一个封闭的 action 枚举(enum),LLM 只能选择预定义的安全操作 -- 每个 action 都有对应的 JSON Schema,参数类型、范围、必填项均有严格约束 -- Critic 模块在 Agent 每步 observe 后评估输出质量,异常时触发终止 -- Circuit Breaker 在连续 10 次操作失败后自动停止 Agent loop,需用户手动恢复 -- 敏感操作(涉及登录、批量删除等)通过 Side Panel UI 弹窗请求用户确认 +- 序列号关联。 +- HMAC 校验。 +- 域名与页面上下文匹配。 +- 非法参数拒绝执行。 -**Layer 3 — 浏览器内核层** - -本层是安全架构的最后防线。即使 sgClaw 的 Rust 层被完全绕过(理论上几乎不可能), -Browser 的 C++ 代码仍会独立执行 MAC 检查。 - -防御对象: -- 已突破 Layer 2 的命令(假设 sgClaw 被完全控制) -- 未授权域上的操作(sgClaw 试图操作不在白名单中的网站) -- 凭证窃取(任何试图通过 pipe 读取存储密码的操作) - -实现机制: -- `rules.json` 白名单由管理员配置,列出允许 Agent 操作的域名(如 `oa.example.com`) -- 每条 pipe 命令到达 Browser 后,先校验 `expected_domain` 是否与当前页面的实际域名一致 -- `credential_store`(Linux Keyring / Windows Credential Manager)的 API 在 pipe handler 中 - 没有任何暴露点——登录凭证只能由 SessionManager 在 Browser 内部使用 -- 速率限制器独立于 sgClaw 的 Circuit Breaker,即使后者被禁用,Browser 侧的限速仍然生效 +[`docs/浏览器对接标准.md`](/home/zyl/projects/sgClaw/claw/docs/浏览器对接标准.md) 是这一层的联调基线。 --- -## 5. 威胁模型与对抗策略 +## 5. 关键架构决策 -### 5.1 威胁分类总表 +### 5.1 使用 STDIO 作为唯一主链路 -| # | 威胁名称 | 描述 | 影响 | 防御层 | 对抗策略 | -|----|------------------------|------------------------------------------------|----------------------------|-----------------|---------------------------------------------------------| -| T1 | Pipe Hijack | 本机攻击者劫持 STDIO Pipe | 完全控制浏览器操作 | Layer 1 | STDIO 进程私有;fd 不经过文件系统;procfs 受限 | -| T2 | LLM Prompt Injection | 恶意页面内容注入 LLM prompt | 执行未授权操作 | Layer 2 | JSON Schema 校验;Action 枚举白名单;禁止 eval | -| T3 | Skill Poisoning | 注入恶意 Skill 脚本 | 持久化后门 | Layer 2 + 3 | Skill 签名校验;沙箱执行;MAC 域名限制 | -| T4 | Credential Leakage | 通过 pipe 读取浏览器存储的密码 | 账户泄露 | Layer 3 | credential_store API 不暴露给 pipe;凭证仅内部使用 | -| T5 | Replay Attack | 录制合法命令后重放 | 重复执行敏感操作 | Layer 2 | sequence_id 递增校验 + HMAC 签名 | -| T6 | Retry Storm | LLM 无限重试导致资源耗尽 | CPU/内存/网络耗尽 | Layer 2 | Circuit Breaker (阈值 10);指数退避;最大重试限制 | +原因: -### 5.2 各威胁详细分析 +- 进程私有,外部进程不能直接接入。 +- 与浏览器子进程托管方式天然匹配。 +- 协议简单,适合 JSON Line 一问一答模型。 -**T1: Pipe Hijack(管道劫持)** +### 5.2 保留协议前提下重构执行核 -攻击路径:同一台机器上的恶意进程尝试读取/写入 sgClaw 与 Browser 之间的 STDIO Pipe。 +原因: -分析:STDIO Pipe 基于操作系统匿名管道实现,没有文件系统路径,没有网络端口。 -攻击者需要获取目标进程的 fd(Linux)或 HANDLE(Windows),这在标准安全配置下 -需要 root 权限或 `ptrace` 能力。银河麒麟 V10 默认启用 `kernel.yama.ptrace_scope=1`, -非父进程无法 ptrace。 +- 浏览器宿主联调成本最低。 +- Rust 侧可以独立迭代 planner 和 ZeroClaw 路径。 +- 产品文档、测试和协议标准可以围绕同一条 contract 收敛。 -残余风险:root 用户可以访问任何进程的 fd。但在本部署场景中,root 被视为可信实体。 +### 5.3 先做最小工具面,再扩动作 -**T2: LLM Prompt Injection(提示注入)** +原因: -攻击路径:用户访问的恶意网页中包含精心构造的文本,当 sgClaw 读取页面内容并发送给 LLM 时, -这些文本被 LLM 误解为指令,导致 Agent 执行非预期操作。 - -分析:这是 AI Agent 面临的最常见威胁。sgClaw 的防御不依赖于 LLM 本身的抗注入能力 -(这是不可靠的),而是在 Rust 层进行硬编码限制: -- LLM 只能输出预定义的 action 枚举值,任何不在枚举中的操作被直接拒绝 -- 最危险的 `eval`、`executeJsInPage` 不在枚举中,从根本上不可能被 LLM 触发 -- `expected_domain` 字段要求 LLM 明确声明目标域名,Browser 侧校验实际域名是否匹配 - -**T3: Skill Poisoning(技能投毒)** - -攻击路径:攻击者将恶意 JavaScript Skill 注入到 Skill Repository 中, -当 sgClaw 加载该 Skill 时执行恶意代码。 - -分析:Skill 文件在加载前经过以下校验链: -1. 签名校验:每个 Skill 文件必须附带由构建系统生成的数字签名 -2. 沙箱执行:Skill 代码在受限的 JavaScript 沙箱中运行,无法访问文件系统或网络 -3. MAC 限制:即使 Skill 生成了恶意命令,Browser 侧的域白名单仍会阻止未授权操作 - -**T4: Credential Leakage(凭证泄漏)** - -攻击路径:通过 pipe 发送特制命令,尝试读取 Browser 中存储的登录密码。 - -分析:`credential_store` 使用 Linux Keyring(银河麒麟)或 Windows Credential Manager -存储加密凭证。其 C++ API 仅在 `SessionManager::DoLogin()` 内部调用, -没有任何 CommandRouter action 会暴露凭证数据。pipe handler 的代码路径中 -完全不存在读取凭证的逻辑。 - -**T5: Replay Attack(重放攻击)** - -攻击路径:攻击者(假设已突破 Layer 1)录制合法的 pipe 命令序列,稍后重放。 - -分析:每条消息携带递增的 `sequence_id` 和基于共享密钥的 HMAC。 -接收方维护已处理的最大 sequence_id,拒绝任何小于或等于该值的消息。 -HMAC 密钥在每次 sgclaw 启动时通过 handshake 动态协商,重启后旧命令的 HMAC 无效。 - -**T6: Retry Storm(重试风暴)** - -攻击路径:LLM 因 hallucination 或 prompt injection 陷入无限循环, -持续生成失败命令并重试。 - -分析:sgClaw 内置两级防护: -1. Agent Runtime 层:单次任务最大步数限制(默认 50 步),超出自动终止 -2. Circuit Breaker:连续 10 次操作失败后,断路器打开,停止所有 pipe 通信, - 需要用户手动恢复。冷却期间采用指数退避(1s → 2s → 4s → ... → 30s max) +- 当前最稳定的是 `click/type/navigate/getText`。 +- 动作越多,宿主和模型之间的契约越难稳定。 +- 在规则文件仍只开放 4 个动作的前提下,文档不应提前放大能力范围。 --- -## 6. 通信架构 +## 6. 架构结论 -### 6.1 Pipe 协议概览 +L1 层面可以把 sgClaw 定义为:一个通过固定浏览器协议接入宿主、以 Rust 为控制层、以 ZeroClaw 为兼容执行核、以 MAC Policy 为最小安全边界的浏览器智能体运行时。 -sgClaw 与 Browser 之间使用 JSON Line 格式通过 STDIO Pipe 通信。 -每条消息占一行(以 `\n` 结尾),单消息最大 1 MB。 - -**消息类型一览:** - -``` -sgClaw → Browser: - ├─ command (请求执行浏览器操作) - └─ ack (确认收到事件) - -Browser → sgClaw: - ├─ response (命令执行结果) - ├─ event (主动推送的页面事件) - └─ init_ack (handshake 响应) -``` - -**Request 格式(sgClaw → Browser):** - -```json -{ - "seq": 1, - "type": "command", - "action": "click", - "params": { - "selector": "#submit-btn", - "wait_after": 1000 - }, - "security": { - "expected_domain": "oa.example.com", - "hmac": "a3f8c2..." - } -} -``` - -字段说明: -- `seq`: 递增序列号,全局唯一,用于匹配 response 和防重放 -- `type`: 消息类型,`command` 表示操作请求 -- `action`: 操作名称,必须在允许列表中 -- `params`: 操作参数,每个 action 有独立的 JSON Schema -- `security.expected_domain`: 期望的目标域名,Browser 侧校验 -- `security.hmac`: 消息完整性签名 - -**Response 格式(Browser → sgClaw):** - -```json -{ - "seq": 1, - "type": "response", - "success": true, - "data": { - "clicked": true, - "element_text": "提交" - }, - "aom_snapshot": [ - {"role": "button", "name": "提交", "bounds": [100, 200, 80, 30]} - ], - "timing": { - "queue_ms": 2, - "exec_ms": 45 - } -} -``` - -字段说明: -- `seq`: 与请求对应的序列号 -- `success`: 操作是否成功 -- `data`: 操作结果数据,格式因 action 而异 -- `aom_snapshot`: 操作后的 AOM(Accessibility Object Model)快照, - 供 Agent 的 observe 阶段使用,理解页面当前状态 -- `timing`: 性能计时信息 - -**Event 格式(Browser → sgClaw,主动推送):** - -```json -{ - "type": "event", - "event": "page_navigated", - "data": { - "url": "https://oa.example.com/approval/list", - "title": "审批列表 - OA系统", - "domain": "oa.example.com" - }, - "timestamp": 1709452800000 -} -``` - -支持的事件类型: -- `page_navigated`: 页面导航完成 -- `page_loaded`: 页面 DOMContentLoaded -- `dialog_appeared`: 浏览器对话框弹出(alert/confirm/prompt) -- `session_expired`: SessionManager 检测到会话过期 -- `zombie_ready`: Zombie page 初始化完成 - -### 6.2 与 CommandRouter 的对接 - -sgClaw 的命令最终汇入 SuperRPA 已有的 CommandRouter,这是一个统一的命令分发器, -支持 40+ 种浏览器操作。sgClaw 作为新增的命令来源,与已有的 JS SDK 并行存在。 - -**sgClaw Pipe 路径(新增):** - -``` -sgClaw (Rust) - │ - │ JSON Line over STDIO Pipe - │ - ▼ -SgClawProcessHost (C++, Browser Process) - │ - ▼ -PipeListener (async read, parse JSON) - │ - ├─── MAC Whitelist Check ─────────────────────────────┐ - │ │ │ - │ ├─ action in allowed_pipe_actions? │ - │ │ → No: reject with error response │ - │ │ │ - │ ├─ expected_domain matches current page? │ - │ │ → No: reject with domain_mismatch error │ - │ │ │ - │ └─ rate limit not exceeded? │ - │ → Exceeded: reject with rate_limit error │ - │ │ - ▼ │ -CommandRouter (Existing, 40+ actions) ◄──────────────────┘ - │ - ├───────────┬──────────────┬──────────────┐ - ▼ ▼ ▼ ▼ -CdpCommand ZombiePage Session RpaGlobal -Executor Manager Manager Storage - │ - ▼ -Page DOM Operations (click, type, getText, etc.) -``` - -**已有 JS SDK 路径(不变):** - -``` -页面内 JavaScript - │ - │ CDP binding (chrome.runtime.sendMessage) - │ - ▼ -CdpBridgeManager (C++, Renderer → Browser IPC) - │ - ▼ -CommandRouter (Same instance!) ◄── 同一个 CommandRouter - │ - ├───────────┬──────────────┬──────────────┐ - ▼ ▼ ▼ ▼ -CdpCommand ZombiePage Session RpaGlobal -Executor Manager Manager Storage -``` - -两条路径汇聚于同一个 CommandRouter 实例。sgClaw 只是新增了一个命令来源, -不改变 CommandRouter 的任何现有逻辑。区别仅在于: - -- JS SDK 路径:无 MAC whitelist check(页面 JS 已通过 CSP 和 rules.json 限制) -- Pipe 路径:增加 MAC whitelist check(因为 sgClaw 被视为外部进程,需额外校验) - -### 6.3 Pipe 允许的 Action 子集 - -并非所有 CommandRouter 支持的 40+ 个 action 都允许通过 pipe 调用。 -出于安全考虑,pipe 来源的命令被限制在以下安全子集中: - -**允许通过 Pipe 调用(无需确认):** - -| Action | 描述 | 备注 | -|------------------|--------------------|---------------------------------| -| click | 点击元素 | 需 expected_domain 匹配 | -| type | 输入文本 | 需 expected_domain 匹配 | -| navigate | 导航到 URL | URL 必须在域白名单内 | -| getText | 获取元素文本 | 只读操作,安全 | -| getHtml | 获取元素 HTML | 只读操作,安全 | -| waitForSelector | 等待元素出现 | 只读操作,安全 | -| pageScreenshot | 页面截图 | 返回 base64,用于 Agent observe | -| storageSet | 写 RpaGlobalStorage | key 前缀限制为 sgclaw.* | -| storageGet | 读 RpaGlobalStorage | key 前缀限制为 sgclaw.* | -| zombieSpawn | 创建 zombie page | 受池大小限制(max 5) | -| zombieKill | 销毁 zombie page | 只能销毁自己创建的 zombie | -| select | 下拉框选择 | 需 expected_domain 匹配 | -| scrollTo | 滚动页面 | 需 expected_domain 匹配 | -| getAomSnapshot | 获取 AOM 快照 | 只读操作,核心 observe 能力 | - -**禁止通过 Pipe 调用(硬编码拒绝):** - -| Action | 描述 | 禁止原因 | -|--------------------|--------------------|--------------------------------------------| -| eval | 执行任意 JS | 最高危操作,可绕过一切安全限制 | -| executeJsInPage | 在页面执行 JS | 等同于 eval,prompt injection 核心攻击面 | -| registerJsFunction | 注册 JS 回调 | 可植入持久化代码 | -| setRequestInterceptor | 拦截网络请求 | 可窃取请求中的 token/cookie | -| exportCookies | 导出所有 cookie | 可窃取会话凭证 | - -**需要用户确认的操作(Human-in-the-loop):** - -| Action | 描述 | 确认原因 | -|------------------|--------------------|---------------------------------| -| sessionLogin | 执行登录流程 | 涉及凭证使用,需用户知情 | -| sessionLogout | 登出会话 | 可能中断用户正在进行的工作 | -| clearStorage | 清空存储 | 不可逆操作 | - ---- - -## 7. 跨平台策略 - -### 7.1 STDIO Pipe 跨平台实现 - -STDIO Pipe 的跨平台实现依赖 Chromium 已有的 `base::LaunchProcess` 抽象层, -sgClaw 团队无需编写平台特定的管道代码。 - -**Linux 实现路径:** - -``` -Browser Process (C++) sgClaw (Rust) -───────────────────── ───────────── -1. pipe(fds) → fds[0](读), fds[1](写) -2. pipe(fds2) → fds2[0](读), fds2[1](写) -3. fork() -4. 子进程: - dup2(fds[0], STDIN_FILENO) - dup2(fds2[1], STDOUT_FILENO) - exec("sgclaw") ──────────────────→ main() -5. 父进程: std::io::stdin() → 读取命令 - write(fds[1], ...) ──────────────→ std::io::stdout() → 写回响应 - read(fds2[0], ...) ◄──────────── BufReader + BufWriter -``` - -Chromium 的 `base::LaunchProcess` 封装了上述 `pipe()` + `fork()` + `exec()` 流程, -通过 `LaunchOptions::fds_to_remap` 配置 fd 映射。 - -**Windows 实现路径:** - -``` -Browser Process (C++) sgClaw (Rust) -───────────────────── ───────────── -1. CreatePipe(&hRead1, &hWrite1, ...) -2. CreatePipe(&hRead2, &hWrite2, ...) -3. SetHandleInformation(hRead1, INHERIT) -4. SetHandleInformation(hWrite2, INHERIT) -5. CreateProcess("sgclaw.exe", - STARTUPINFO { - hStdInput = hRead1, main() - hStdOutput = hWrite2 std::io::stdin() → ReadFile - }) std::io::stdout() → WriteFile -6. WriteFile(hWrite1, ...) ──────────→ - ReadFile(hRead2, ...) ◄──────── -``` - -Chromium 的 `base::LaunchProcess` 在 Windows 下使用 `CreateProcess` + `STARTUPINFO` -实现句柄继承,与 Linux 的 fd 继承语义一致。 - -**Rust 侧统一代码:** - -无论 Linux 还是 Windows,sgclaw 的 Rust 代码完全一致: - -```rust -// sgclaw 端无需区分平台 -let reader = BufReader::new(std::io::stdin()); -let writer = BufWriter::new(std::io::stdout()); - -for line in reader.lines() { - let msg: PipeMessage = serde_json::from_str(&line?)?; - let response = handle_message(msg).await?; - writeln!(writer, "{}", serde_json::to_string(&response)?)?; - writer.flush()?; -} -``` - -### 7.2 目标平台 - -| 平台 | 操作系统 | CPU 架构 | 状态 | 备注 | -|-----------|--------------------------|----------|------------------|-----------------------------| -| Primary | 银河麒麟 V10 SP1 | x86_64 | 目标部署环境 | 政企客户主要使用平台 | -| Secondary | Windows 10 / 11 | x86_64 | 开发 + 部分部署 | 开发团队日常使用 + 部分客户 | -| Future | 银河麒麟 V10 SP1 | aarch64 | 规划中 | 国产 ARM 服务器/终端 | - -**银河麒麟 V10 SP1 特殊注意事项:** - -- 基于 Ubuntu 内核,但定制了安全策略(SELinux/AppArmor 变体) -- `procfs` 默认配置限制跨进程 fd 访问,有利于 Pipe Hijack 防御 -- `kernel.yama.ptrace_scope=1`,非父进程无法 ptrace,增强安全性 -- glibc 版本需确认兼容(通常 >= 2.31),Rust musl 静态链接可规避 - -### 7.3 sgClaw 二进制分发 - -sgClaw 编译为单一静态链接的 Rust 二进制,无外部运行时依赖。 - -``` -sgclaw 二进制产物 -├─ Linux: sgclaw (~8.8 MB, musl 静态链接, strip) -│ target: x86_64-unknown-linux-musl -│ 无 glibc 依赖,银河麒麟直接运行 -│ -└─ Windows: sgclaw.exe (~9.0 MB, MSVC 链接, strip) - target: x86_64-pc-windows-msvc - 无额外 DLL 依赖 -``` - -构建命令: - -```bash -# Linux (musl 静态链接,确保银河麒麟兼容) -cargo build --release --target x86_64-unknown-linux-musl -strip target/x86_64-unknown-linux-musl/release/sgclaw - -# Windows (交叉编译) -cargo build --release --target x86_64-pc-windows-msvc -``` - -部署方式:将 `sgclaw` / `sgclaw.exe` 放置在 SuperRPA 浏览器安装目录下: - -``` -superrpa-browser/ -├─ chrome (浏览器主程序) -├─ superrpa-chromium.sh (启动脚本) -├─ sgclaw (AI Agent, 新增) -├─ sgclaw-skills/ (技能目录, 新增) -│ ├─ oa-approval.js -│ └─ ... -└─ resources/ - └─ rules.json (域白名单, 已有) -``` - ---- - -## 8. 与 SuperRPA 已有子系统的关系 - -### 8.1 复用与新增总览 - -sgClaw 的核心设计原则之一是**最小侵入**——最大限度复用 SuperRPA 浏览器的已有基础设施, -将新增代码量控制在最低水平。 - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ SuperRPA Browser 已有子系统 │ -│ (全部保持不变,零修改) │ -│ │ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ Command │ │ CdpBridge │ │ ZombiePage │ │ -│ │ Router │ │ Manager │ │ Manager │ │ -│ │ (40+ acts) │ │ (JS SDK) │ │ (5 pools) │ │ -│ └──────┬──────┘ └─────────────┘ └─────────────┘ │ -│ │ │ -│ ┌──────┴──────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ CdpCommand │ │ Session │ │ RpaGlobal │ │ -│ │ Executor │ │ Manager │ │ Storage │ │ -│ │ │ │ (状态机) │ │ (KV store) │ │ -│ └─────────────┘ └─────────────┘ └─────────────┘ │ -│ │ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ credential │ │ rules.json │ │ BrowserAction│ │ -│ │ _store │ │ (URL白名单) │ │ API │ │ -│ │ (Keyring) │ │ │ │ (JS 调度) │ │ -│ └─────────────┘ └─────────────┘ └─────────────┘ │ -│ │ -├─────────────────────────────────────────────────────────────────────┤ -│ sgClaw 新增组件 │ -│ (~500 lines C++ in Browser + Rust binary) │ -│ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ SgClawProcessHost (C++, ~200-300 lines) │ │ -│ │ ├─ 进程生命周期管理 (Start / Stop / OnCrash) │ │ -│ │ ├─ PipeListener (~150 lines, async read loop) │ │ -│ │ ├─ MAC Whitelist Check (~100 lines) │ │ -│ │ └─ FunctionsUI handlers for start/stop (~50 lines) │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ Side Panel UI Controls (Vue, ~100 lines) │ │ -│ │ ├─ [启动] / [停止] 按钮 │ │ -│ │ ├─ 状态指示 (Running / Stopped / Error) │ │ -│ │ ├─ 任务输入框 │ │ -│ │ └─ 执行日志 (streaming output) │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ sgclaw Binary (Rust, based on ZeroClaw) │ │ -│ │ ├─ Agent Runtime (ReAct loop) │ │ -│ │ ├─ BrowserPipeTool (custom Tool trait impl) │ │ -│ │ ├─ SkillLoader (JS business skills) │ │ -│ │ ├─ LLM Provider (Claude / GPT / local) │ │ -│ │ ├─ Memory (SQLite + vector) │ │ -│ │ ├─ MAC Policy (domain / action whitelist) │ │ -│ │ ├─ Critic + Circuit Breaker │ │ -│ │ └─ MCP Client (rmcp) │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -### 8.2 复用子系统详细说明 - -| 子系统 | 代码位置 | sgClaw 如何复用 | 是否修改 | -|---------------------|----------------------|---------------------------------------------------|---------| -| CommandRouter | browser/rpa/command/ | sgClaw 通过 pipe → PipeListener → CommandRouter | 不修改 | -| CdpBridgeManager | browser/rpa/cdp/ | 独立运行,JS SDK 路径不受影响 | 不修改 | -| ZombiePageManager | browser/rpa/zombie/ | sgClaw 通过 zombieSpawn/zombieKill action 使用 | 不修改 | -| SessionManager | browser/rpa/session/ | sgClaw 可触发 sessionLogin (需确认) | 不修改 | -| RpaGlobalStorage | browser/rpa/storage/ | sgClaw 通过 storageSet/storageGet 读写 | 不修改 | -| BrowserAction API | browser/rpa/action/ | 已有 JS SDK 继续使用,与 sgClaw 独立 | 不修改 | -| credential_store | browser/rpa/cred/ | 仅 SessionManager 内部使用,sgClaw 无法访问 | 不修改 | -| rules.json | resources/ | sgClaw 的 MAC Policy 也读取此文件进行域校验 | 不修改 | - -### 8.3 新增代码量估算 - -| 组件 | 语言 | 估计行数 | 位置 | -|-----------------------------|--------|-------------|-------------------------------| -| SgClawProcessHost | C++ | ~200-300 | browser/rpa/sgclaw/ | -| PipeListener | C++ | ~150 | browser/rpa/sgclaw/ | -| MAC Whitelist Check (Pipe) | C++ | ~100 | browser/rpa/sgclaw/ | -| FunctionsUI handlers | C++ | ~50 | browser/rpa/functions_ui/ | -| Side Panel UI controls | Vue | ~100 | resources/side_panel/ | -| **Browser 侧合计** | | **~500-600**| | -| sgclaw binary | Rust | ~3000-5000 | 独立仓库 sgclaw/ | - -### 8.4 影响评估 - -**对已有功能的影响:零。** - -具体论证: - -1. **CommandRouter 不变**:sgClaw 只是新增了一个命令来源(pipe),CommandRouter 本身的 - dispatch 逻辑、action 处理函数、错误处理均不修改。 - -2. **JS SDK 不变**:CdpBridgeManager 独立于 SgClawProcessHost,两者通过不同的 IPC 路径 - 到达同一个 CommandRouter。JS SDK 的用户不会感知到 sgClaw 的存在。 - -3. **会话管理不变**:SessionManager 的状态机(login → active → expired → re-login) - 完全不变。sgClaw 只能通过 CommandRouter 触发 sessionLogin action(需用户确认), - 不直接操作 SessionManager 内部状态。 - -4. **存储隔离**:sgClaw 通过 RpaGlobalStorage 的 key 被限制在 `sgclaw.*` 命名空间下, - 不会与已有的 JS SDK 存储的 key 冲突。 - -5. **二进制独立**:sgclaw 是独立二进制,不链接 Chromium 的任何库。 - 即使 sgclaw 构建失败或缺失,浏览器仍然正常工作——只是 Side Panel 的 [启动] 按钮 - 会报错"sgclaw binary not found"。 - ---- - -*文档结束。本文档为 sgClaw L1 层架构设计参考,后续 L2(详细设计)、L3(实现规范) -将在此基础上展开。* +这一定义与当前仓库实现保持一致,也为后续继续扩展动作、工具和记忆系统保留了清晰边界。 diff --git a/docs/L2-核心模块与接口契约层.md b/docs/L2-核心模块与接口契约层.md index 963355d..4d4f3b7 100644 --- a/docs/L2-核心模块与接口契约层.md +++ b/docs/L2-核心模块与接口契约层.md @@ -1,2009 +1,289 @@ # L2 — 核心模块与接口契约层 -**文档版本**: 1.0 -**适用项目**: sgClaw (业数融合一平台 AI Agent 底座) -**编制日期**: 2026-03-03 +**文档版本**: 2.0 +**适用项目**: sgClaw(ZeroClaw 重构版) +**编制日期**: 2026-03-26 -**读者**: 各组组长(Rust 组、浏览器 C++ 组、前端组)—— 需要理解模块边界、接口契约、依赖关系,指导各组并行开发。 +**读者**: 架构工程师、实现工程师、联调工程师 --- -## 1. 模块总览与依赖拓扑 +## 1. 模块地图 -### 1.1 全局模块图 - -sgClaw 系统由三个独立的代码域组成:Rust 端(sgclaw binary)、C++ 端(Browser Process 新增模块)、前端(Side Panel Vue 组件)。以下拓扑展示了所有模块及其依赖关系。 +当前仓库中的有效模块结构如下: ``` -┌──────────────────────────────────────────────────────────────────────────┐ -│ sgClaw Rust Binary │ -│ │ -│ ┌──────────┐ ┌──────────────┐ ┌───────────┐ ┌────────────────┐ │ -│ │ main.rs │──→│ Agent Runtime│──→│ Critic │ │ Config/ │ │ -│ │ (入口) │ │ (ReAct) │ │ (评估器) │ │ Settings │ │ -│ └────┬─────┘ └──────┬───────┘ └─────┬─────┘ └────────────────┘ │ -│ │ │ │ │ -│ │ ┌──────┴───────┐ ┌──────┴──────┐ │ -│ │ │ BrowserPipe │ │ Circuit │ │ -│ │ │ Tool │ │ Breaker │ │ -│ │ │ (Tool trait) │ └─────────────┘ │ -│ │ └──────┬───────┘ │ -│ │ │ │ -│ ┌────┴─────┐ ┌──────┴───────┐ ┌───────────┐ ┌────────────────┐ │ -│ │ Pipe │ │ MAC Policy │ │ Memory │ │ LLM Provider │ │ -│ │ Protocol │ │ (安全策略) │ │ (记忆层) │ │ (模型适配) │ │ -│ └──────────┘ └──────────────┘ └───────────┘ └────────────────┘ │ -│ │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │ SkillLoader │ │ MCP Client │ │ -│ │ (技能加载) │ │ (rmcp) │ │ -│ └──────────────┘ └──────────────┘ │ -│ │ -└───────────────────────────────┬──────────────────────────────────────────┘ - │ STDIO Pipe (JSON Line) - │ -┌───────────────────────────────┴──────────────────────────────────────────┐ -│ SuperRPA Browser Process (C++ 新增) │ -│ │ -│ ┌─────────────────────────┐ │ -│ │ SgClawProcessHost │ Singleton, 进程生命周期管理 │ -│ │ ├─ PipeListener │ 异步读取循环, 解析 JSON Line │ -│ │ ├─ MAC Whitelist Check │ action + domain 白名单校验 │ -│ │ └─→ CommandRouter │ [Existing] 40+ actions, 零修改 │ -│ └─────────────────────────┘ │ -│ │ -└──────────────────────────────────────────────────────────────────────────┘ - │ FunctionsUI IPC - │ -┌───────────────────────────────┴──────────────────────────────────────────┐ -│ Side Panel (Vue 前端) │ -│ │ -│ ┌─────────────────────────┐ │ -│ │ AgentControlPanel.vue │ 启停按钮 + 指令输入 + 状态显示 + 执行日志 │ -│ └─────────────────────────┘ │ -│ │ -└──────────────────────────────────────────────────────────────────────────┘ +src/ +├── main.rs +├── lib.rs +├── agent/ +├── compat/ +├── config/ +├── llm/ +├── pipe/ +└── security/ ``` -### 1.2 模块依赖矩阵 +模块边界按职责划分为四层: -以下矩阵展示 Rust 端各模块之间的依赖关系(行依赖列): - -``` - Runtime BrowserPipe Protocol MAC Memory LLM Skill Critic MCP Config -Runtime - ✓ - - ✓ ✓ ✓ ✓ ✓ ✓ -BrowserPipe - - ✓ ✓ - - - - - - -Protocol - - - - - - - - - ✓ -MAC Policy - - - - - - - - - ✓ -Memory - - - - - - - - - ✓ -LLM Provider - - - - - - - - - ✓ -SkillLoader - - - - - - - - - ✓ -Critic - - - - ✓ - - - - ✓ -MCP Client - - - - - - - - - ✓ -Config - - - - - - - - - - -``` - -设计原则: -- **Config 是叶节点**:所有模块依赖 Config,Config 不依赖任何业务模块 -- **Runtime 是根节点**:Agent Runtime 协调所有模块,是唯一的"上帝模块" -- **BrowserPipeTool 仅依赖 Protocol 和 MAC**:确保 Tool 实现的纯粹性 -- **无循环依赖**:依赖图是 DAG(有向无环图) - -### 1.3 并行开发分工 - -基于模块依赖关系,三个组可以并行开发: - -| 组别 | 负责模块 | 依赖条件 | 可并行阶段 | -|------|---------|---------|-----------| -| **Rust 组** | Agent Runtime, BrowserPipeTool, Protocol, MAC Policy, Memory, LLM Provider, SkillLoader, Critic, MCP Client, Config | 无外部依赖,可先行 | 第一阶段即可开始 | -| **C++ 组** | SgClawProcessHost, PipeListener, MAC Whitelist Check | 需与 Rust 组对齐 Pipe 协议格式 | 协议 JSON Schema 确定后开始 | -| **前端组** | AgentControlPanel.vue | 需 C++ 组提供 FunctionsUI handler | C++ 组 handler 就绪后开始 | +| 层级 | 模块 | 责任 | +|---|---|---| +| 传输层 | `pipe` | 定义消息、握手、序列号、收发与命令等待 | +| 控制层 | `lib.rs`、`agent` | 接收任务、选择执行路径、回传日志与结果 | +| 兼容层 | `compat` | 对接 vendored ZeroClaw,暴露单一 `browser_action` | +| 安全层 | `security`、`resources/rules.json` | 域名与动作白名单控制 | --- -## 2. sgClaw Rust 端模块详细设计 +## 2. 核心模块职责 -### 2.1 main.rs — 进程入口 +### 2.1 `src/lib.rs` -**职责**:初始化 Pipe I/O、配置加载、tokio 异步运行时启动、模块组装、handshake 握手。 +[`src/lib.rs`](/home/zyl/projects/sgClaw/claw/src/lib.rs) 是运行时总装入口,负责: -**启动序列**: +- 创建 `StdioTransport`。 +- 调用 `perform_handshake`。 +- 加载默认规则文件 `resources/rules.json`。 +- 构造 `BrowserPipeTool`。 +- 进入长循环,接收浏览器消息并交给 `agent::handle_browser_message`。 -``` -main() - │ - ├── 1. 初始化 tracing (日志) - │ └── 日志输出到 stderr (stdout 保留给 pipe) - │ - ├── 2. 加载 Config - │ ├── 默认值 (编译时内嵌) - │ ├── 配置文件 (sgclaw.toml, 可选) - │ └── 环境变量覆盖 (SGCLAW_*) - │ - ├── 3. 初始化 tokio runtime - │ └── multi_thread, worker_threads = 2 - │ - ├── 4. 创建 Pipe I/O - │ ├── stdin → BufReader (接收 Browser 消息) - │ └── stdout → BufWriter (发送消息到 Browser) - │ - ├── 5. Handshake - │ ├── 等待 Browser 的 init 消息 (超时 5s) - │ ├── 校验协议版本 - │ ├── 交换 HMAC 密钥种子 - │ └── 发送 init_ack 确认 - │ - ├── 6. 组装模块 - │ ├── MAC Policy ← Config (rules 路径) - │ ├── Protocol ← Config (max_message_size) - │ ├── BrowserPipeTool ← Protocol + MAC - │ ├── LLM Provider ← Config (model, api_key) - │ ├── Memory ← Config (db_path) - │ ├── SkillLoader ← Config (skills_dir) - │ ├── MCP Client ← Config (mcp_servers) - │ ├── Critic ← Config (thresholds) + Memory - │ └── Agent Runtime ← 以上全部 - │ - ├── 7. 启动 Agent 消息循环 - │ └── 监听 pipe 输入,分发到 Runtime - │ - └── 8. 优雅退出 - ├── 收到 shutdown 命令 / EOF / SIGTERM - ├── 停止 Agent loop - ├── flush Memory 到磁盘 - └── 退出进程 (exit code 0) -``` +这里没有业务 UI、任务队列或调度中心逻辑,只有最小可运行闭环。 -**关键设计决策**: +### 2.2 `src/agent/mod.rs` -- **stdout 专用于 pipe**:所有日志、调试信息通过 `tracing` 输出到 stderr。stdout 严格保留给 JSON Line 协议,防止日志混入 pipe 流导致解析失败。 -- **tokio worker_threads = 2**:在 8 GB 内存约束下,2 个 worker 线程足以处理 pipe I/O + LLM HTTP 请求。不需要更多并发。 -- **模块组装使用依赖注入**:所有模块通过构造函数接收依赖,便于测试时替换为 mock 实现。 +[`src/agent/mod.rs`](/home/zyl/projects/sgClaw/claw/src/agent/mod.rs) 决定执行路径: -### 2.2 Agent Runtime — ReAct 循环 +- 收到 `BrowserMessage::SubmitTask` 时优先尝试读取 `DeepSeekSettings`。 +- 环境配置存在,则走 `compat::runtime::execute_task`。 +- 环境配置不存在,则走内置 planner fallback。 -**职责**:实现 think → act → observe 循环,协调 LLM、Tool、Memory、Critic 完成用户任务。 +这就是当前系统的“路由器”。 -**模块接口**: +### 2.3 `src/agent/runtime.rs` -```rust -/// Agent Runtime 核心结构 -pub struct AgentRuntime { - provider: Box, - tools: Vec>, // 包含 BrowserPipeTool + MCP tools - memory: Arc, - critic: Critic, - config: RuntimeConfig, -} +该文件保留了仓库内的轻量 LLM/tool 调用逻辑,核心特点: -/// Runtime 配置 -pub struct RuntimeConfig { - pub max_steps: u32, // 单次任务最大步数 (默认 50) - pub max_thinking_tokens: u32, // 单步 thinking 最大 token (默认 4096) - pub system_prompt_template: String, // 系统提示模板路径 - pub human_confirm_actions: Vec, // 需人工确认的 action 列表 -} +- 工具名固定为 `browser_action`。 +- schema 只允许 `click/type/navigate/getText`。 +- 每次工具调用前后发送 `log_entry`。 +- 结果失败时直接返回 `PipeError::Protocol`。 -impl AgentRuntime { - /// 创建 Runtime 实例 - pub fn new( - provider: Box, - tools: Vec>, - memory: Arc, - critic: Critic, - config: RuntimeConfig, - ) -> Self; +### 2.4 `src/compat/runtime.rs` - /// 执行用户任务 (核心入口) - /// 返回任务执行结果或错误 - pub async fn execute_task(&mut self, task: &str) -> Result; +[`src/compat/runtime.rs`](/home/zyl/projects/sgClaw/claw/src/compat/runtime.rs) 是 ZeroClaw 重构的关键模块: - /// 停止当前任务 (由外部 shutdown 信号触发) - pub fn abort(&self); -} +- 负责构造 ZeroClaw config。 +- 负责创建 provider。 +- 负责把 `BrowserPipeTool` 包装成 ZeroClaw Tool。 +- 负责消费 ZeroClaw `TurnEvent` 并桥接为 `log_entry`。 -/// 任务执行结果 -pub struct TaskResult { - pub success: bool, - pub summary: String, // LLM 生成的任务完成摘要 - pub steps: Vec, // 所有执行步骤记录 - pub token_usage: TokenUsage, // token 消耗统计 -} +重要事实: -/// 单步执行记录 -pub struct StepRecord { - pub step_num: u32, - pub thinking: String, // LLM 的推理内容 - pub action: Option, // 选择的操作 (None = 任务完成) - pub observation: String, // 操作结果观察 - pub duration_ms: u64, -} -``` +- 当前 compat 层只向 ZeroClaw 注册一个工具。 +- `allowed_tools` 被收敛到 `browser_action`。 +- 这意味着 ZeroClaw 在本项目中是“兼容执行器”,不是“多工具平台”。 -**ReAct 循环伪码**: +### 2.5 `src/pipe/browser_tool.rs` -``` -execute_task(user_instruction): - context = memory.load_context(user_instruction) - system_prompt = render_template(config.system_prompt_template, { - available_tools: tools.descriptions(), - skills: skill_loader.list_skills(), - context: context, - }) +该模块承担真实浏览器命令发送职责: - for step in 1..=config.max_steps: - // === THINK === - llm_response = provider.chat(system_prompt, messages, tools) +- 为每个命令分配 `seq`。 +- 计算 HMAC。 +- 发送 `AgentMessage::Command`。 +- 阻塞等待对应 `BrowserMessage::Response`。 +- 在超时、响应错配、校验失败时返回错误。 - if llm_response.is_final_answer(): - return TaskResult { success: true, summary: llm_response.text } +它是 Rust 侧最重要的协议执行点。 - // === ACT === - action = llm_response.tool_call - if action.name in config.human_confirm_actions: - confirmation = request_human_confirm(action) // 通过 pipe 发送确认请求 - if not confirmation: - messages.push(observation: "用户拒绝了此操作") - continue +### 2.6 `src/security/mac_policy.rs` - result = tools.execute(action) +安全策略只认规则文件,不认模型意图。 +规则来源为 [`resources/rules.json`](/home/zyl/projects/sgClaw/claw/resources/rules.json),当前默认约束是: - // === OBSERVE === - observation = format_observation(result) - messages.push(observation) - - // === CRITIC === - critic_verdict = critic.evaluate(step, action, result) - if critic_verdict.should_abort: - return TaskResult { success: false, summary: critic_verdict.reason } - - memory.record_step(step, action, result) - - return TaskResult { success: false, summary: "达到最大步数限制" } -``` - -### 2.3 BrowserPipeTool — 自定义 Tool trait 实现 - -**职责**:将 Agent 的 action 请求序列化为 Pipe JSON 命令,发送到 Browser 并等待响应。这是 sgClaw 与 ZeroClaw 框架的核心对接点。 - -**模块接口**: - -```rust -/// ZeroClaw 的 Tool trait (框架定义) -#[async_trait] -pub trait Tool: Send + Sync { - fn name(&self) -> &str; - fn description(&self) -> &str; - fn parameters_schema(&self) -> serde_json::Value; - async fn execute(&self, params: serde_json::Value) -> Result; -} - -/// sgClaw 的浏览器操作工具实现 -pub struct BrowserPipeTool { - pipe_writer: Arc>, - pipe_reader: Arc, - mac_policy: Arc, - seq_counter: AtomicU64, - hmac_key: [u8; 32], -} - -impl BrowserPipeTool { - pub fn new( - pipe_writer: Arc>, - pipe_reader: Arc, - mac_policy: Arc, - hmac_key: [u8; 32], - ) -> Self; -} - -#[async_trait] -impl Tool for BrowserPipeTool { - fn name(&self) -> &str { "browser_action" } - - fn description(&self) -> &str { - "在浏览器中执行操作。支持的操作包括:click, type, navigate, \ - getText, getHtml, waitForSelector, pageScreenshot, select, \ - scrollTo, getAomSnapshot, storageSet, storageGet, \ - zombieSpawn, zombieKill" - } - - fn parameters_schema(&self) -> serde_json::Value { - // 返回所有 action 的 JSON Schema (oneOf 结构) - // 详见 §5 接口契约 - } - - async fn execute(&self, params: serde_json::Value) -> Result { - // 1. 解析 action + params - let action: Action = serde_json::from_value(params)?; - - // 2. MAC 策略校验 - self.mac_policy.check(&action)?; - - // 3. 构造 pipe message - let seq = self.seq_counter.fetch_add(1, Ordering::SeqCst); - let msg = PipeMessage::command(seq, &action, &self.hmac_key); - - // 4. 发送到 Browser - self.pipe_writer.lock().await.send(&msg)?; - - // 5. 等待对应 seq 的 response (超时 30s) - let response = self.pipe_reader.recv(seq, Duration::from_secs(30)).await?; - - // 6. 转换为 ToolOutput - Ok(ToolOutput::from_pipe_response(response)) - } -} -``` - -**Action 枚举(白名单)**: - -```rust -/// 允许通过 pipe 的操作类型 (封闭枚举) -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "action", content = "params")] -pub enum Action { - #[serde(rename = "click")] - Click { selector: String, wait_after: Option }, - - #[serde(rename = "type")] - Type { selector: String, text: String, clear_first: Option }, - - #[serde(rename = "navigate")] - Navigate { url: String }, - - #[serde(rename = "getText")] - GetText { selector: String }, - - #[serde(rename = "getHtml")] - GetHtml { selector: String, outer: Option }, - - #[serde(rename = "waitForSelector")] - WaitForSelector { selector: String, timeout_ms: Option }, - - #[serde(rename = "pageScreenshot")] - PageScreenshot { full_page: Option }, - - #[serde(rename = "select")] - Select { selector: String, value: String }, - - #[serde(rename = "scrollTo")] - ScrollTo { selector: Option, x: Option, y: Option }, - - #[serde(rename = "getAomSnapshot")] - GetAomSnapshot { root_selector: Option }, - - #[serde(rename = "storageSet")] - StorageSet { key: String, value: String }, - - #[serde(rename = "storageGet")] - StorageGet { key: String }, - - #[serde(rename = "zombieSpawn")] - ZombieSpawn { url: String }, - - #[serde(rename = "zombieKill")] - ZombieKill { page_id: String }, -} -``` - -### 2.4 SkillLoader — 技能加载器 - -**职责**:发现、校验、加载 JavaScript 业务技能脚本,将其注册到 Agent 的工具集中。 - -**模块接口**: - -```rust -/// 技能加载器 -pub struct SkillLoader { - skills_dir: PathBuf, - registry: HashMap, - signature_verifier: SignatureVerifier, -} - -/// 技能定义 -pub struct Skill { - pub name: String, // 技能名称 (如 "oa-approval") - pub version: String, // 语义版本 (如 "1.2.0") - pub description: String, // 自然语言描述 (供 LLM 选择) - pub target_domains: Vec,// 适用域名列表 - pub parameters: JsonSchema, // 输入参数 schema - pub script: String, // JS 脚本内容 - pub signature: String, // 数字签名 (Ed25519) -} - -/// 技能清单文件 (registry.json) -pub struct SkillRegistry { - pub version: String, - pub skills: Vec, -} - -pub struct SkillManifestEntry { - pub name: String, - pub file: String, // 相对路径 (如 "builtin/oa-approval.js") - pub hash: String, // SHA-256 文件哈希 - pub signature: String, // Ed25519 签名 -} - -impl SkillLoader { - /// 创建加载器并扫描技能目录 - pub fn new(skills_dir: PathBuf, public_key: &[u8]) -> Result; - - /// 获取所有已加载技能的描述 (供 LLM system prompt) - pub fn list_skills(&self) -> Vec; - - /// 获取指定技能的 JS 脚本 - pub fn get_script(&self, name: &str) -> Option<&str>; - - /// 运行时重新加载技能 (热更新) - pub fn reload(&mut self) -> Result<(), SkillError>; -} -``` - -**技能加载流程**: - -``` -SkillLoader::new(skills_dir) - │ - ├── 1. 读取 skills/registry.json - │ └── 解析技能清单 - │ - ├── 2. 遍历每个 SkillManifestEntry - │ │ - │ ├── 2a. 读取技能文件 - │ │ - │ ├── 2b. 计算文件 SHA-256 - │ │ └── 与 registry.json 中的 hash 比对 - │ │ └── 不匹配 → 跳过 + 警告日志 - │ │ - │ ├── 2c. 验证 Ed25519 签名 - │ │ └── 使用编译时内嵌的公钥 - │ │ └── 签名无效 → 跳过 + 警告日志 - │ │ - │ └── 2d. 解析技能元数据 (JS 文件头部注释) - │ └── 注册到 registry HashMap - │ - └── 3. 日志: "Loaded N skills, skipped M (signature failed)" -``` - -**技能文件格式** (JS 文件头部): - -```javascript -/** - * @skill oa-approval - * @version 1.2.0 - * @description OA系统审批单自动处理:查询待审批列表、批量审批、添加审批意见 - * @domains oa.example.com, oa-test.example.com - * @params { - * "type": "object", - * "properties": { - * "action": { "enum": ["list", "approve", "reject"] }, - * "opinion": { "type": "string" } - * } - * } - */ -async function execute(params, browserAction) { - // browserAction 是 BrowserAction 函数的引用 - // 技能代码使用 browserAction 调用浏览器操作 - - if (params.action === 'list') { - await browserAction('navigate', 'https://oa.example.com/approval/pending'); - await browserAction('waitForSelector', '.approval-list'); - const items = await browserAction('getText', '.approval-list'); - return { success: true, data: items }; - } - // ... -} -``` - -### 2.5 MAC Policy — 强制访问控制策略 - -**职责**:在 Rust 端实施域名白名单和 Action 白名单校验,作为安全架构 Layer 2 的核心组件。 - -**模块接口**: - -```rust -/// MAC 策略引擎 -pub struct MacPolicy { - allowed_domains: HashSet, // 允许操作的域名集合 - allowed_actions: HashSet, // 允许的 action 名称集合 - blocked_actions: HashSet, // 硬性禁止的 action 集合 - confirm_actions: HashSet, // 需人工确认的 action 集合 - storage_key_prefix: String, // 存储 key 前缀限制 (默认 "sgclaw.") - rate_limits: HashMap, // 每域速率限制 -} - -/// 速率限制配置 -pub struct RateLimit { - pub max_per_second: u32, // 每秒最大操作数 - pub cooldown_seconds: u32, // 超限后冷却时间 -} - -/// MAC 校验结果 -pub enum MacVerdict { - Allow, // 允许执行 - NeedConfirm(String), // 需要用户确认 (附确认提示) - Deny(MacDenyReason), // 拒绝执行 -} - -/// 拒绝原因 -pub enum MacDenyReason { - ActionNotAllowed(String), // action 不在白名单 - ActionBlocked(String), // action 在黑名单 (eval 等) - DomainNotAllowed(String), // 域名不在白名单 - StorageKeyViolation(String), // storage key 前缀不合规 - RateLimitExceeded(String, u32), // 超过速率限制 (域名, 当前速率) -} - -impl MacPolicy { - /// 从 rules.json 加载策略 - pub fn from_rules_file(path: &Path) -> Result; - - /// 校验 action 是否允许 - pub fn check(&self, action: &Action) -> MacVerdict; - - /// 校验域名是否在白名单 - pub fn check_domain(&self, domain: &str) -> bool; - - /// 记录一次操作 (用于速率统计) - pub fn record_access(&self, domain: &str); -} -``` - -**rules.json 策略文件格式**: - -```json -{ - "version": "1.0", - "domains": { - "allowed": [ - "oa.example.com", - "erp.example.com", - "hr.example.com", - "finance.example.com" - ] - }, - "pipe_actions": { - "allowed": [ - "click", "type", "navigate", "getText", "getHtml", - "waitForSelector", "pageScreenshot", "select", "scrollTo", - "getAomSnapshot", "storageSet", "storageGet", - "zombieSpawn", "zombieKill" - ], - "blocked": [ - "eval", "executeJsInPage", "registerJsFunction", - "setRequestInterceptor", "exportCookies" - ], - "need_confirm": [ - "sessionLogin", "sessionLogout", "clearStorage" - ] - }, - "storage": { - "key_prefix": "sgclaw." - }, - "rate_limits": { - "default": { "max_per_second": 10, "cooldown_seconds": 30 }, - "overrides": { - "finance.example.com": { "max_per_second": 5, "cooldown_seconds": 60 } - } - } -} -``` - -### 2.6 Critic — 输出质量评估器 - -**职责**:在 Agent 每步 observe 后评估操作结果质量,检测异常模式,触发熔断保护。 - -**模块接口**: - -```rust -/// 输出质量评估器 -pub struct Critic { - circuit_breaker: CircuitBreaker, - memory: Arc, - config: CriticConfig, -} - -pub struct CriticConfig { - pub consecutive_failure_threshold: u32, // 连续失败熔断阈值 (默认 10) - pub same_action_repeat_limit: u32, // 同一 action 重复上限 (默认 5) - pub max_task_duration_secs: u64, // 单任务最大时长 (默认 600) -} - -/// 评估结果 -pub struct CriticVerdict { - pub should_abort: bool, // 是否应终止任务 - pub reason: Option, // 终止原因 - pub warning: Option, // 警告 (不终止但需记录) -} - -/// 熔断器 -pub struct CircuitBreaker { - state: CircuitState, - consecutive_failures: AtomicU32, - last_failure_time: Mutex>, - config: CircuitBreakerConfig, -} - -pub enum CircuitState { - Closed, // 正常 — 允许操作 - Open, // 断开 — 拒绝所有操作 - HalfOpen, // 半开 — 允许一次试探 -} - -pub struct CircuitBreakerConfig { - pub failure_threshold: u32, // 失败次数阈值 (默认 10) - pub cooldown_base_secs: u64, // 基础冷却时间 (默认 1) - pub cooldown_max_secs: u64, // 最大冷却时间 (默认 30) - pub reset_on_success: bool, // 成功后是否重置计数 (默认 true) -} - -impl Critic { - pub fn new(memory: Arc, config: CriticConfig) -> Self; - - /// 评估单步结果 - pub fn evaluate( - &self, - step: u32, - action: &Action, - result: &ToolOutput, - elapsed: Duration, - ) -> CriticVerdict; - - /// 重置熔断器 (用户手动恢复时调用) - pub fn reset(&self); -} -``` - -**评估逻辑**: - -``` -evaluate(step, action, result, elapsed): - // 1. 检查操作是否失败 - if result.is_error(): - circuit_breaker.record_failure() - if circuit_breaker.state == Open: - return Verdict { should_abort: true, reason: "连续失败次数达到熔断阈值" } - - // 2. 检查是否在重复同一操作 - recent_actions = memory.get_recent_actions(config.same_action_repeat_limit) - if all_same(recent_actions, action): - return Verdict { should_abort: true, reason: "检测到死循环:连续重复相同操作" } - - // 3. 检查任务时长 - if elapsed > config.max_task_duration_secs: - return Verdict { should_abort: true, reason: "任务执行超时" } - - // 4. 成功时重置计数 - if result.is_success() && config.reset_on_success: - circuit_breaker.reset_failures() - - return Verdict { should_abort: false } -``` - -### 2.7 Memory — 记忆系统 - -**职责**:管理 Agent 的短期对话记忆和长期任务知识库,支持上下文检索和经验沉淀。 - -**模块接口**: - -```rust -/// Memory trait (ZeroClaw 框架定义) -#[async_trait] -pub trait Memory: Send + Sync { - /// 存储对话消息 - async fn store_message(&self, msg: &Message) -> Result<(), MemoryError>; - - /// 检索相关上下文 (语义搜索) - async fn retrieve(&self, query: &str, limit: usize) -> Result, MemoryError>; - - /// 清除当前会话记忆 - async fn clear_session(&self) -> Result<(), MemoryError>; -} - -/// sgClaw 的复合记忆实现 -pub struct CompositeMemory { - short_term: ShortTermMemory, // Ring Buffer 短期记忆 - long_term: LongTermMemory, // SQLite 长期记忆 -} - -/// 短期记忆 (Ring Buffer) -pub struct ShortTermMemory { - buffer: VecDeque, - max_size: usize, // 默认 50 条消息 - max_tokens: usize, // 默认 8000 tokens -} - -/// 长期记忆 (SQLite + 简单向量) -pub struct LongTermMemory { - db: SqlitePool, // SQLite 连接池 - embedding_dim: usize, // 向量维度 (默认 384) -} - -/// 记忆条目 -pub struct MemoryEntry { - pub id: String, - pub content: String, - pub entry_type: MemoryType, - pub relevance_score: f32, // 与查询的相关度 (0.0 ~ 1.0) - pub created_at: DateTime, -} - -pub enum MemoryType { - Conversation, // 对话历史 - TaskResult, // 任务执行结果 - SkillExperience, // 技能执行经验 - UserPreference, // 用户偏好 -} - -impl CompositeMemory { - pub fn new(config: MemoryConfig) -> Result; - - /// 获取最近 N 步的 action 记录 (供 Critic 查重) - pub fn get_recent_actions(&self, n: usize) -> Vec; - - /// 保存任务执行经验 (供自进化学习) - pub async fn save_task_experience( - &self, - task: &str, - result: &TaskResult, - ) -> Result<(), MemoryError>; -} -``` - -**存储 Schema** (SQLite): - -```sql --- 长期记忆表 -CREATE TABLE memory_entries ( - id TEXT PRIMARY KEY, - content TEXT NOT NULL, - entry_type TEXT NOT NULL, -- 'conversation' | 'task_result' | 'skill_exp' | 'user_pref' - embedding BLOB, -- f32 向量 (384 维 = 1536 bytes) - metadata TEXT, -- JSON 附加信息 - created_at TEXT NOT NULL, - session_id TEXT -- 关联的 trace_id -); - --- 向量索引 (简单线性扫描,数据量小时足够) -CREATE INDEX idx_memory_type ON memory_entries(entry_type); -CREATE INDEX idx_memory_session ON memory_entries(session_id); - --- 技能执行记录表 -CREATE TABLE skill_executions ( - id TEXT PRIMARY KEY, - skill_name TEXT NOT NULL, - input_hash TEXT NOT NULL, -- 输入参数 hash (用于精确匹配) - success INTEGER NOT NULL, - duration_ms INTEGER, - created_at TEXT NOT NULL -); -``` - -### 2.8 LLM Provider — 模型适配层 - -**职责**:统一封装不同 LLM 服务的调用接口,支持 streaming、tool-use、token 计量。 - -**模块接口**: - -```rust -/// LLM Provider trait (ZeroClaw 框架定义) -#[async_trait] -pub trait LlmProvider: Send + Sync { - /// 发送聊天请求 - async fn chat( - &self, - messages: &[Message], - tools: &[ToolDefinition], - config: &ChatConfig, - ) -> Result; - - /// 发送 streaming 请求 - async fn chat_stream( - &self, - messages: &[Message], - tools: &[ToolDefinition], - config: &ChatConfig, - ) -> Result>>>, LlmError>; - - /// 获取 provider 信息 - fn info(&self) -> ProviderInfo; -} - -/// 聊天配置 -pub struct ChatConfig { - pub max_tokens: u32, // 最大生成 token 数 - pub temperature: f32, // 温度 (默认 0.1, Agent 场景偏低) - pub stop_sequences: Vec, // 停止序列 -} - -/// LLM 响应 -pub struct LlmResponse { - pub content: Option, // 文本回复 - pub tool_calls: Vec, // 工具调用请求 - pub usage: TokenUsage, // token 使用量 - pub finish_reason: FinishReason, -} - -/// Token 使用统计 -pub struct TokenUsage { - pub prompt_tokens: u32, - pub completion_tokens: u32, - pub total_tokens: u32, -} - -/// Provider 信息 -pub struct ProviderInfo { - pub name: String, // "claude" | "openai" | "ollama" - pub model: String, // 如 "claude-sonnet-4-20250514" - pub max_context_tokens: u32, // 最大上下文窗口 - pub supports_tools: bool, - pub supports_streaming: bool, -} -``` - -**已实现的 Provider**: - -| Provider | 模块 | 支持功能 | 适用场景 | -|----------|------|---------|---------| -| **Claude** | `llm/claude.rs` | streaming + tool-use + vision | 默认推荐,综合能力最强 | -| **OpenAI** | `llm/openai.rs` | streaming + tool-use | 兼容 GPT-4 及 API 兼容服务 | -| **Ollama** | `llm/ollama.rs` | streaming + tool-use (部分模型) | 本地部署,离线场景 | - -**Provider 选择逻辑**: - -```rust -/// 根据配置创建 Provider 实例 -pub fn create_provider(config: &LlmConfig) -> Result, LlmError> { - match config.provider.as_str() { - "claude" => Ok(Box::new(ClaudeProvider::new( - &config.api_key, - &config.model, // 如 "claude-sonnet-4-20250514" - config.base_url.as_deref(), - )?)), - "openai" => Ok(Box::new(OpenAiProvider::new( - &config.api_key, - &config.model, // 如 "gpt-4o" - config.base_url.as_deref(), - )?)), - "ollama" => Ok(Box::new(OllamaProvider::new( - &config.model, // 如 "qwen2.5:32b" - config.base_url.as_deref().unwrap_or("http://localhost:11434"), - )?)), - other => Err(LlmError::UnknownProvider(other.to_string())), - } -} -``` - -### 2.9 MCP Client — 外部工具扩展 - -**职责**:通过 rmcp(Rust MCP SDK)连接外部 MCP Server,动态获取额外工具供 Agent 使用。 - -**模块接口**: - -```rust -/// MCP 客户端管理器 -pub struct McpClientManager { - clients: HashMap, // server_name → client - config: McpConfig, -} - -pub struct McpConfig { - pub servers: Vec, -} - -pub struct McpServerConfig { - pub name: String, // 服务器标识名 - pub command: String, // 启动命令 - pub args: Vec, // 命令参数 - pub env: HashMap, // 环境变量 -} - -impl McpClientManager { - /// 创建并连接所有配置的 MCP Server - pub async fn new(config: McpConfig) -> Result; - - /// 获取所有 MCP Server 提供的工具列表 - pub fn list_tools(&self) -> Vec; - - /// 调用 MCP 工具 - pub async fn call_tool( - &self, - server: &str, - tool: &str, - params: serde_json::Value, - ) -> Result; - - /// 关闭所有连接 - pub async fn shutdown(&mut self); -} -``` +- 允许域名:`oa.example.com`、`erp.example.com`、`hr.example.com` 及 demo 域名。 +- 允许动作:`click`、`type`、`navigate`、`getText`。 +- 显式阻断:`eval`、`executeJsInPage`。 --- -## 3. 浏览器 C++ 端模块详细设计 +## 3. 协议契约 -### 3.1 SgClawProcessHost — 进程宿主 +### 3.1 消息类型 -**职责**:Singleton,管理 sgclaw 子进程的完整生命周期(Start / Stop / OnCrash),创建和持有 STDIO Pipe。 +[`src/pipe/protocol.rs`](/home/zyl/projects/sgClaw/claw/src/pipe/protocol.rs) 定义了三类浏览器到 Rust 的消息: -**接口声明**: - -```cpp -// sg_claw_process_host.h - -#ifndef CHROME_BROWSER_SUPERRPA_SGCLAW_SG_CLAW_PROCESS_HOST_H_ -#define CHROME_BROWSER_SUPERRPA_SGCLAW_SG_CLAW_PROCESS_HOST_H_ - -#include -#include -#include "base/process/launch.h" -#include "base/process/process.h" - -namespace superrpa { -namespace sgclaw { - -class PipeListener; - -// sgClaw 进程状态 -enum class ProcessState { - kStopped, // 初始状态 / 已停止 - kStarting, // 正在启动 (等待 handshake) - kRunning, // 正常运行 - kStopping, // 正在停止 - kCrashed, // 异常退出 -}; - -// 进程事件观察者 -class ProcessObserver { - public: - virtual ~ProcessObserver() = default; - virtual void OnStateChanged(ProcessState new_state) = 0; - virtual void OnPipeMessage(const std::string& json_line) = 0; - virtual void OnProcessCrash(int exit_code, const std::string& stderr_output) = 0; -}; - -// sgClaw 进程宿主 (Singleton) -class SgClawProcessHost { - public: - static SgClawProcessHost* GetInstance(); - - // 启动 sgClaw 子进程 - // 成功返回 true,失败返回 false 并通过 observer 通知 - bool Start(); - - // 优雅停止 sgClaw - void Stop(); - - // 发送消息到 sgClaw - bool SendMessage(const std::string& json_line); - - // 获取当前状态 - ProcessState GetState() const; - - // 注册/移除观察者 - void AddObserver(ProcessObserver* observer); - void RemoveObserver(ProcessObserver* observer); - - private: - SgClawProcessHost(); - ~SgClawProcessHost(); - - // 禁止拷贝 - SgClawProcessHost(const SgClawProcessHost&) = delete; - SgClawProcessHost& operator=(const SgClawProcessHost&) = delete; - - // 内部方法 - base::FilePath GetSgClawBinaryPath() const; - void OnChildProcessExited(int exit_code); - void DoHandshake(); - - // 成员 - ProcessState state_ = ProcessState::kStopped; - base::Process child_process_; - std::unique_ptr pipe_listener_; - - // Pipe 文件描述符 (Linux: fd, Windows: HANDLE) - base::ScopedFD pipe_write_fd_; // Browser → sgClaw - base::ScopedFD pipe_read_fd_; // sgClaw → Browser - - std::vector observers_; -}; - -} // namespace sgclaw -} // namespace superrpa - -#endif +```rust +BrowserMessage::Init +BrowserMessage::SubmitTask +BrowserMessage::Response ``` -**关键实现说明**: +以及四类 Rust 到浏览器的消息: -- **Singleton**:使用 `base::NoDestructor` 实现进程全局唯一实例 -- **Start() 流程**:检查二进制存在 → 创建 pipe pair → `base::LaunchProcess` → 启动 PipeListener → 发送 handshake → 等待 ack (5s 超时) → 状态切换到 Running -- **Stop() 流程**:发送 `{"type":"shutdown"}` → 等待进程退出 (2s 超时) → SIGTERM → 再等 2s → SIGKILL -- **OnChildProcessExited()**:检查退出码,非零且非主动 Stop → 视为 Crash → 通知 observers → 不自动重启 -- **线程安全**:所有方法在 Browser UI 线程调用,Pipe 读取在 IO 线程 - -### 3.2 PipeListener — 异步读取循环 - -**职责**:在 IO 线程上异步读取 sgClaw 的 stdout 输出,按行解析 JSON,分发到 MAC 校验和 CommandRouter。 - -**接口声明**: - -```cpp -// pipe_listener.h - -#ifndef CHROME_BROWSER_SUPERRPA_SGCLAW_PIPE_LISTENER_H_ -#define CHROME_BROWSER_SUPERRPA_SGCLAW_PIPE_LISTENER_H_ - -#include -#include -#include "base/files/file_descriptor_watcher_posix.h" // Linux -// Windows: base/win/object_watcher.h - -namespace superrpa { -namespace sgclaw { - -class PipeListener { - public: - using MessageCallback = std::function; - using ErrorCallback = std::function; - - PipeListener(base::ScopedFD read_fd, - MessageCallback on_message, - ErrorCallback on_error); - ~PipeListener(); - - // 开始异步监听 - void StartListening(); - - // 停止监听 - void StopListening(); - - private: - void OnReadable(); // fd 可读回调 - void ProcessBuffer(); // 从 buffer 中提取完整行 - bool ValidateMessageSize(const std::string& line); // 检查消息大小 (<=1MB) - - base::ScopedFD read_fd_; - std::string read_buffer_; // 累积读取缓冲 - MessageCallback on_message_; - ErrorCallback on_error_; - - // Linux: FileDescriptorWatcher - std::unique_ptr fd_watcher_; -}; - -} // namespace sgclaw -} // namespace superrpa - -#endif +```rust +AgentMessage::InitAck +AgentMessage::LogEntry +AgentMessage::TaskComplete +AgentMessage::Command ``` -**读取流程**: +### 3.2 `Init` / `InitAck` -``` -StartListening() - │ - └── 注册 fd_watcher_ 监听 read_fd_ 可读事件 - │ - ▼ -OnReadable() [IO 线程回调] - │ - ├── read(read_fd_, temp_buffer, 4096) - │ → 返回 0: EOF → 通知 process exited - │ → 返回 -1: EAGAIN → 忽略 (非阻塞 I/O) - │ → 返回 N: 追加到 read_buffer_ - │ - └── ProcessBuffer() - │ - ├── 在 read_buffer_ 中查找 '\n' - │ → 找到: 提取该行作为 json_line - │ → 未找到: 等待下次 OnReadable() - │ - ├── ValidateMessageSize(json_line) - │ → > 1MB: 丢弃 + 日志警告 - │ - └── on_message_(json_line) - │ - └── [UI 线程] MAC 校验 → CommandRouter -``` +握手字段: -### 3.3 MAC Whitelist Check — Pipe 来源 MAC 校验 +- `version` +- `hmac_seed` +- `capabilities` -**职责**:对通过 Pipe 收到的命令进行强制访问控制校验,作为安全架构 Layer 3 的实现。 +Rust 返回: -**接口声明**: +- `version` +- `agent_id` +- `supported_actions` -```cpp -// mac_whitelist_check.h +注意:`supported_actions` 是协议枚举能力,不等于当前策略白名单。 -#ifndef CHROME_BROWSER_SUPERRPA_SGCLAW_MAC_WHITELIST_CHECK_H_ -#define CHROME_BROWSER_SUPERRPA_SGCLAW_MAC_WHITELIST_CHECK_H_ +### 3.3 `Command` -#include -#include -#include "base/values.h" - -namespace superrpa { -namespace sgclaw { - -// MAC 校验结果 -enum class MacResult { - kAllow, // 允许 - kDeny, // 拒绝 - kNeedConfirm, // 需用户确认 -}; - -struct MacCheckResult { - MacResult result; - std::string reason; // 拒绝/确认原因 -}; - -class MacWhitelistCheck { - public: - // 从 rules.json 加载策略 - static std::unique_ptr CreateFromRules( - const base::FilePath& rules_path); - - // 校验 pipe 命令 - MacCheckResult Check(const std::string& action, - const std::string& expected_domain, - const std::string& current_page_domain) const; - - private: - MacWhitelistCheck(); - - std::set allowed_actions_; - std::set blocked_actions_; - std::set confirm_actions_; - std::set allowed_domains_; -}; - -} // namespace sgclaw -} // namespace superrpa - -#endif -``` - -**校验流程**: - -``` -Check(action, expected_domain, current_page_domain): - │ - ├── 1. action 在 blocked_actions_ 中? - │ → 是: return Deny("Action is blocked: " + action) - │ - ├── 2. action 不在 allowed_actions_ 中? - │ → 是: return Deny("Action not in pipe whitelist: " + action) - │ - ├── 3. expected_domain 不在 allowed_domains_ 中? - │ → 是: return Deny("Domain not in whitelist: " + expected_domain) - │ - ├── 4. expected_domain != current_page_domain? - │ → 是: return Deny("Domain mismatch: expected " + expected_domain - │ + " but current is " + current_page_domain) - │ - ├── 5. action 在 confirm_actions_ 中? - │ → 是: return NeedConfirm("操作需要用户确认: " + action) - │ - └── 6. return Allow -``` - ---- - -## 4. 前端 Side Panel 新增 UI - -### 4.1 AgentControlPanel.vue - -**职责**:在 Side Panel 中提供 Agent 控制面板,包括启停按钮、指令输入、状态显示、执行日志流。 - -**组件接口**: - -``` -AgentControlPanel.vue -│ -├── Props: 无 (独立组件) -│ -├── State: -│ ├── agentState: 'stopped' | 'starting' | 'running' | 'error' -│ ├── taskInput: string // 用户输入的自然语言指令 -│ ├── logs: LogEntry[] // 执行日志条目 -│ ├── currentTask: string // 当前执行的任务描述 -│ └── errorMessage: string // 错误信息 -│ -├── Methods: -│ ├── startAgent() // 调用 FunctionsUI → SgClawProcessHost::Start() -│ ├── stopAgent() // 调用 FunctionsUI → SgClawProcessHost::Stop() -│ ├── submitTask(instruction) // 发送任务到 Agent -│ ├── confirmAction(actionId) // 用户确认 human-in-the-loop 操作 -│ └── rejectAction(actionId) // 用户拒绝操作 -│ -└── Events (from C++ via FunctionsUI): - ├── onStateChanged(state) // Agent 状态变更 - ├── onLogEntry(entry) // 新日志条目 - ├── onConfirmRequired(action) // 需要用户确认的操作 - └── onTaskCompleted(result) // 任务完成 -``` - -**UI 布局**: - -``` -┌─────────────────────────────────────┐ -│ sgClaw Agent │ -├─────────────────────────────────────┤ -│ │ -│ 状态: ● 运行中 │ -│ │ -│ ┌─────────────────────────────┐ │ -│ │ 请输入业务指令... │ │ -│ │ │ │ -│ └─────────────────────────────┘ │ -│ [ 发送 ] │ -│ │ -│ ─── 执行日志 ─────────────────── │ -│ │ -│ ▸ [10:23:01] 正在分析指令... │ -│ ▸ [10:23:03] 导航至 ERP 系统 │ -│ ▸ [10:23:05] 点击"财务报表"菜单 │ -│ ▸ [10:23:08] 设置时间范围: 本月 │ -│ ▸ [10:23:10] 正在导出数据... │ -│ │ -│ ─── 确认请求 ─────────────────── │ -│ │ -│ ⚠ Agent 请求执行登录操作 │ -│ 目标系统: erp.example.com │ -│ [ 允许 ] [ 拒绝 ] │ -│ │ -├─────────────────────────────────────┤ -│ [ 启动 Agent ] [ 停止 Agent ] │ -└─────────────────────────────────────┘ -``` - -**与 C++ 层的通信**: - -前端通过 FunctionsUI 机制(SuperRPA 已有的 JS → C++ IPC)与 SgClawProcessHost 交互。 - -```javascript -// 启动 Agent -window.sgFunctionsUI('sgclaw_start', {}, (response) => { - // response: { success: true } 或 { success: false, error: "..." } -}); - -// 停止 Agent -window.sgFunctionsUI('sgclaw_stop', {}, (response) => { ... }); - -// 发送任务 -window.sgFunctionsUI('sgclaw_submit_task', { - instruction: "导出本月合规报表" -}, (response) => { ... }); - -// 确认/拒绝操作 -window.sgFunctionsUI('sgclaw_confirm', { - action_id: "abc123", - approved: true -}, (response) => { ... }); -``` - -**事件接收**(C++ → JS 推送): - -```javascript -// C++ 通过 ExecuteJavaScript 推送事件到 Side Panel -// 前端注册全局事件处理器 -window.sgClawEvents = { - onStateChanged: function(state) { - // state: 'stopped' | 'starting' | 'running' | 'error' - vm.agentState = state; - }, - onLogEntry: function(entry) { - // entry: { time: "10:23:01", message: "正在分析指令...", level: "info" } - vm.logs.push(entry); - }, - onConfirmRequired: function(action) { - // action: { id: "abc123", type: "sessionLogin", domain: "erp.example.com" } - vm.pendingConfirm = action; - }, - onTaskCompleted: function(result) { - // result: { success: true, summary: "已成功导出3份报表" } - vm.currentTask = null; - } -}; -``` - ---- - -## 5. 接口契约 - -### 5.1 Pipe JSON 协议完整 Schema - -以下定义了 sgClaw 与 Browser 之间所有 Pipe 消息的完整 JSON Schema。 - -**Handshake — Browser → sgClaw**: +命令消息结构: ```json { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "PipeInitMessage", - "type": "object", - "required": ["type", "version", "hmac_seed"], - "properties": { - "type": { "const": "init" }, - "version": { - "type": "string", - "pattern": "^\\d+\\.\\d+$", - "description": "协议版本号 (如 1.0)" - }, - "hmac_seed": { - "type": "string", - "minLength": 32, - "maxLength": 64, - "description": "HMAC 密钥种子 (hex 编码)" - }, - "capabilities": { - "type": "array", - "items": { "type": "string" }, - "description": "Browser 支持的扩展能力列表" - } + "seq": 1, + "type": "command", + "action": "click", + "params": { "selector": "#submit" }, + "security": { + "expected_domain": "erp.example.com", + "hmac": "" } } ``` -**Handshake — sgClaw → Browser**: +契约重点: + +- `seq` 必须单调递增。 +- `action` 必须是协议枚举之一。 +- `expected_domain` 必须参与安全校验。 +- `hmac` 必须由当前会话密钥计算。 + +### 3.4 `Response` + +浏览器回包结构: ```json { - "title": "PipeInitAckMessage", - "type": "object", - "required": ["type", "version", "agent_id"], - "properties": { - "type": { "const": "init_ack" }, - "version": { - "type": "string", - "description": "sgClaw 协议版本 (必须与 init.version 一致)" - }, - "agent_id": { - "type": "string", - "description": "Agent 实例唯一标识 (UUID v4)" - }, - "supported_actions": { - "type": "array", - "items": { "type": "string" }, - "description": "sgClaw 可使用的 action 列表" - } - } -} -``` - -**Command — sgClaw → Browser**: - -```json -{ - "title": "PipeCommandMessage", - "type": "object", - "required": ["seq", "type", "action", "params", "security"], - "properties": { - "seq": { - "type": "integer", - "minimum": 1, - "description": "全局递增序列号" - }, - "type": { "const": "command" }, - "action": { - "type": "string", - "enum": [ - "click", "type", "navigate", "getText", "getHtml", - "waitForSelector", "pageScreenshot", "select", "scrollTo", - "getAomSnapshot", "storageSet", "storageGet", - "zombieSpawn", "zombieKill" - ] - }, - "params": { - "type": "object", - "description": "操作参数,格式取决于 action (见 §5.2)" - }, - "security": { - "type": "object", - "required": ["expected_domain", "hmac"], - "properties": { - "expected_domain": { - "type": "string", - "description": "期望操作的目标域名" - }, - "hmac": { - "type": "string", - "description": "HMAC-SHA256 签名 (hex)" - } - } - } - } -} -``` - -**Response — Browser → sgClaw**: - -```json -{ - "title": "PipeResponseMessage", - "type": "object", - "required": ["seq", "type", "success"], - "properties": { - "seq": { - "type": "integer", - "description": "对应 command 的序列号" - }, - "type": { "const": "response" }, - "success": { "type": "boolean" }, - "data": { - "type": "object", - "description": "操作结果数据 (成功时)" - }, - "error": { - "type": "object", - "properties": { - "code": { "type": "string" }, - "message": { "type": "string" } - }, - "description": "错误信息 (失败时)" - }, - "aom_snapshot": { - "type": "array", - "items": { - "type": "object", - "properties": { - "role": { "type": "string" }, - "name": { "type": "string" }, - "bounds": { - "type": "array", - "items": { "type": "integer" }, - "minItems": 4, - "maxItems": 4, - "description": "[x, y, width, height]" - }, - "value": { "type": "string" }, - "children": { "type": "array" } - } - }, - "description": "操作后的 AOM 快照" - }, - "timing": { - "type": "object", - "properties": { - "queue_ms": { "type": "integer" }, - "exec_ms": { "type": "integer" } - } - } - } -} -``` - -### 5.2 各 Action 参数 Schema - -**click**: - -```json -{ - "type": "object", - "required": ["selector"], - "properties": { - "selector": { - "type": "string", - "description": "CSS 选择器" - }, - "wait_after": { - "type": "integer", - "minimum": 0, - "maximum": 30000, - "default": 1000, - "description": "点击后等待时间 (ms)" - } - } -} -``` - -**type**: - -```json -{ - "type": "object", - "required": ["selector", "text"], - "properties": { - "selector": { - "type": "string", - "description": "CSS 选择器" - }, - "text": { - "type": "string", - "maxLength": 10000, - "description": "要输入的文本" - }, - "clear_first": { - "type": "boolean", - "default": true, - "description": "输入前是否清空已有内容" - } - } -} -``` - -**navigate**: - -```json -{ - "type": "object", - "required": ["url"], - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "目标 URL (必须在域白名单内)" - } - } -} -``` - -**getText**: - -```json -{ - "type": "object", - "required": ["selector"], - "properties": { - "selector": { - "type": "string", - "description": "CSS 选择器" - } - } -} -``` - -**getHtml**: - -```json -{ - "type": "object", - "required": ["selector"], - "properties": { - "selector": { - "type": "string" - }, - "outer": { - "type": "boolean", - "default": false, - "description": "true 返回 outerHTML, false 返回 innerHTML" - } - } -} -``` - -**waitForSelector**: - -```json -{ - "type": "object", - "required": ["selector"], - "properties": { - "selector": { - "type": "string" - }, - "timeout_ms": { - "type": "integer", - "minimum": 100, - "maximum": 30000, - "default": 5000, - "description": "等待超时 (ms)" - } - } -} -``` - -**pageScreenshot**: - -```json -{ - "type": "object", - "properties": { - "full_page": { - "type": "boolean", - "default": false, - "description": "是否截取整页 (true) 或仅可视区域 (false)" - } - } -} -``` - -**select**: - -```json -{ - "type": "object", - "required": ["selector", "value"], - "properties": { - "selector": { - "type": "string", - "description": "select 元素的 CSS 选择器" - }, - "value": { - "type": "string", - "description": "要选择的 option 的 value 值" - } - } -} -``` - -**scrollTo**: - -```json -{ - "type": "object", - "properties": { - "selector": { - "type": "string", - "description": "滚动到指定元素 (优先于 x/y)" - }, - "x": { - "type": "integer", - "description": "水平滚动位置 (px)" - }, - "y": { - "type": "integer", - "description": "垂直滚动位置 (px)" - } - } -} -``` - -**getAomSnapshot**: - -```json -{ - "type": "object", - "properties": { - "root_selector": { - "type": "string", - "description": "从指定元素开始获取 AOM 子树 (默认整页)" - } - } -} -``` - -**storageSet**: - -```json -{ - "type": "object", - "required": ["key", "value"], - "properties": { - "key": { - "type": "string", - "pattern": "^sgclaw\\.", - "description": "存储键名 (必须以 sgclaw. 开头)" - }, - "value": { - "type": "string", - "maxLength": 65536, - "description": "存储值" - } - } -} -``` - -**storageGet**: - -```json -{ - "type": "object", - "required": ["key"], - "properties": { - "key": { - "type": "string", - "pattern": "^sgclaw\\.", - "description": "存储键名 (必须以 sgclaw. 开头)" - } - } -} -``` - -**zombieSpawn**: - -```json -{ - "type": "object", - "required": ["url"], - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "Zombie page 加载的 URL (必须在域白名单内)" - } - } -} -``` - -**zombieKill**: - -```json -{ - "type": "object", - "required": ["page_id"], - "properties": { - "page_id": { - "type": "string", - "description": "要销毁的 zombie page ID" - } - } -} -``` - -### 5.3 错误码体系 - -所有错误响应使用统一的错误码格式: - -```json -{ - "seq": 5, + "seq": 1, "type": "response", - "success": false, - "error": { - "code": "MAC_DOMAIN_MISMATCH", - "message": "Expected domain erp.example.com but current page is oa.example.com" + "success": true, + "data": {}, + "aom_snapshot": [], + "timing": { + "queue_ms": 0, + "exec_ms": 12 } } ``` -**错误码分类**: +Rust 侧依赖此消息完成工具调用闭环。 +`seq` 不匹配、超时或缺失都应视为协议错误。 -| 错误码前缀 | 来源 | 描述 | -|-----------|------|------| -| `PIPE_*` | PipeListener | Pipe 传输层错误 | -| `MAC_*` | MAC Whitelist Check | 安全策略拒绝 | -| `CMD_*` | CommandRouter | 命令执行错误 | -| `SESSION_*` | SessionManager | 会话相关错误 | -| `INTERNAL_*` | 内部 | 系统内部错误 | +### 3.5 与浏览器对接标准的关系 -**完整错误码列表**: +[`docs/浏览器对接标准.md`](/home/zyl/projects/sgClaw/claw/docs/浏览器对接标准.md) 是联调规范。 +L2 是产品内核视角的契约说明。两者关系如下: -| 错误码 | 描述 | 建议处理 | -|--------|------|---------| -| `PIPE_INVALID_JSON` | JSON 解析失败 | 检查消息格式 | -| `PIPE_MESSAGE_TOO_LARGE` | 消息超过 1MB 限制 | 减小消息体积 | -| `PIPE_SEQ_DUPLICATE` | 序列号重复 | 检查 seq 生成逻辑 | -| `PIPE_SEQ_OUT_OF_ORDER` | 序列号乱序 | 检查消息发送顺序 | -| `PIPE_HMAC_INVALID` | HMAC 签名校验失败 | 检查密钥和签名算法 | -| `MAC_ACTION_BLOCKED` | Action 在黑名单中 | 使用允许的 action | -| `MAC_ACTION_NOT_ALLOWED` | Action 不在白名单中 | 检查 action 名称 | -| `MAC_DOMAIN_NOT_ALLOWED` | 域名不在白名单中 | 联系管理员添加域名 | -| `MAC_DOMAIN_MISMATCH` | 期望域名与实际不匹配 | 确认当前页面域名 | -| `MAC_RATE_LIMIT` | 超过速率限制 | 降低操作频率 | -| `MAC_NEED_CONFIRM` | 操作需要用户确认 | 等待用户确认 | -| `CMD_SELECTOR_NOT_FOUND` | 选择器未匹配到元素 | 检查选择器或等待元素 | -| `CMD_SELECTOR_TIMEOUT` | 等待元素超时 | 增加超时时间 | -| `CMD_NAVIGATION_FAILED` | 页面导航失败 | 检查 URL 可达性 | -| `CMD_ZOMBIE_POOL_FULL` | Zombie 池已满 (max 5) | 先销毁不需要的 zombie | -| `CMD_ZOMBIE_NOT_FOUND` | 指定的 zombie page 不存在 | 检查 page_id | -| `SESSION_EXPIRED` | 会话已过期 | 触发重新登录 | -| `SESSION_LOGIN_FAILED` | 登录失败 | 检查凭证或网络 | -| `INTERNAL_UNKNOWN` | 未知内部错误 | 查看日志 | - -### 5.4 Handshake 协议流程 - -``` -Browser sgClaw - │ │ - │ (1) Start child process │ - │ ──────────────────────────────────→ │ - │ │ - │ (2) init message │ - │ {"type":"init", │ - │ "version":"1.0", │ - │ "hmac_seed":"a1b2c3..."} │ - │ ──────────────────────────────────→ │ - │ │ 校验版本号 - │ │ 派生 HMAC 密钥 - │ (3) init_ack │ - │ {"type":"init_ack", │ - │ "version":"1.0", │ - │ "agent_id":"uuid-v4", │ - │ "supported_actions":[...]} │ - │ ◄────────────────────────────────── │ - │ │ - │ 校验版本号 │ - │ 记录 agent_id (审计) │ - │ 状态 → Running │ - │ │ - │ (4) 正常通信开始 │ - │ ◄═══════════════════════════════════►│ - │ │ -``` - -**超时处理**: -- Browser 发送 init 后等待 5 秒 -- 超时未收到 init_ack → Kill 子进程 → 状态切换到 Crashed → 通知 UI - -**版本不匹配处理**: -- sgClaw 收到的 version 与自身版本不一致 → 发送 error ack → 主动退出 -- Browser 收到的 version 与自身不一致 → Kill 子进程 → 报错 +- L2 负责解释“为什么有这些字段、这些模块如何依赖它们”。 +- 对接标准负责约束“浏览器宿主必须如何实现 wire contract”。 --- -## 6. 跨模块交互时序 +## 4. 动作契约 -### 6.1 用户启动 Agent 完整时序 +### 4.1 协议枚举 -``` -用户 Side Panel C++ (Browser) Rust (sgClaw) - │ │ │ │ - │ 点击 [启动] │ │ │ - │ ──────────────→ │ │ │ - │ │ sgclaw_start │ │ - │ │ ────────────────→ │ │ - │ │ │ Start() │ - │ │ │ ├ 检查二进制 │ - │ │ │ ├ 创建 pipe pair │ - │ │ │ ├ LaunchProcess │ - │ │ │ │ ─────────────────→ │ main() - │ │ │ │ │ ├ 初始化 - │ │ │ │ init message │ ├ 等待 init - │ │ │ │ ─────────────────→ │ - │ │ │ │ │ ├ 校验版本 - │ │ │ │ init_ack │ ├ 派生 HMAC - │ │ │ │ ◄───────────────── │ - │ │ │ ├ 状态 → Running │ - │ │ { success: true } │ │ - │ │ ◄──────────────── │ │ - │ 状态: ● 运行中 │ │ │ - │ ◄────────────── │ │ │ -``` +协议层已经定义了以下动作枚举: -### 6.2 用户提交任务完整时序 +- `click` +- `type` +- `navigate` +- `getText` +- `getHtml` +- `waitForSelector` +- `pageScreenshot` +- `select` +- `scrollTo` +- `getAomSnapshot` +- `storageSet` +- `storageGet` +- `zombieSpawn` +- `zombieKill` -``` -用户 Side Panel C++ (Browser) Rust (sgClaw) LLM - │ │ │ │ │ - │ "导出合规报表" │ │ │ │ - │ ───────────→ │ │ │ │ - │ │ sgclaw_submit_task │ │ │ - │ │ ──────────────────→ │ │ │ - │ │ │ Pipe: submit_task │ │ - │ │ │ ──────────────────→ │ │ - │ │ │ │ execute_task() │ - │ │ │ │ │ - │ │ │ │ ┌─ ReAct Loop ───┤ - │ │ │ │ │ │ - │ │ │ │ │ THINK │ - │ │ │ │ │ ──────────────→│ - │ │ │ │ │ LLM response │ - │ │ │ │ │ ◄──────────────│ - │ │ │ │ │ │ - │ │ │ │ │ ACT │ - │ │ │ Pipe: click │ │ │ - │ │ │ ◄────────────────── │ │ │ - │ │ │ MAC Check → Allow │ │ │ - │ │ │ CommandRouter.exec │ │ │ - │ │ │ Pipe: response │ │ │ - │ │ │ ──────────────────→ │ │ │ - │ │ │ │ │ OBSERVE │ - │ │ │ │ │ CRITIC │ - │ │ │ │ │ │ - │ │ │ │ │ (repeat...) │ - │ │ │ │ └────────────────┤ - │ │ │ │ │ - │ │ │ Pipe: task_complete │ │ - │ │ │ ◄────────────────── │ │ - │ │ onTaskCompleted │ │ │ - │ │ ◄────────────────── │ │ │ - │ "已导出3份报表" │ │ │ │ - │ ◄─────────── │ │ │ │ -``` +### 4.2 当前生效动作 -### 6.3 Human-in-the-loop 确认时序 +当前文档、规则和工具 schema 必须以“生效动作”为准,而不是“预留枚举”为准。 +生效动作只有 4 个: -``` -Rust (sgClaw) C++ (Browser) Side Panel 用户 - │ │ │ │ - │ Pipe: command │ │ │ - │ action=sessionLogin │ │ │ - │ ──────────────────→ │ │ │ - │ │ MAC: NeedConfirm │ │ - │ │ push onConfirmReq │ │ - │ │ ──────────────────→ │ │ - │ │ │ 显示确认对话框 │ - │ │ │ ───────────────→ │ - │ │ │ │ - │ │ │ 用户点击 [允许] │ - │ │ │ ◄─────────────── │ - │ │ sgclaw_confirm │ │ - │ │ ◄────────────────── │ │ - │ │ │ │ - │ │ CommandRouter.exec │ │ - │ │ (sessionLogin) │ │ - │ Pipe: response │ │ │ - │ ◄────────────────── │ │ │ - │ │ │ │ -``` +- `click` +- `type` +- `navigate` +- `getText` + +约束来源有三处,三者必须一致: + +1. `resources/rules.json` +2. `src/agent/runtime.rs` 的 tool definition +3. `src/compat/browser_tool_adapter.rs` 的 `parameters_schema` 与 `parse_action` --- -## 7. 配置体系 +## 5. `browser_action` 工具契约 -### 7.1 sgclaw.toml 配置文件 +### 5.1 工具名 -```toml -# sgClaw 配置文件 -# 路径: 与 sgclaw 二进制同目录, 或 $SGCLAW_CONFIG 指定 +固定为: -[general] -# Agent 日志级别: trace | debug | info | warn | error -log_level = "info" - -[llm] -# LLM Provider: claude | openai | ollama -provider = "claude" -model = "claude-sonnet-4-20250514" -# API Key (建议通过环境变量 SGCLAW_LLM_API_KEY 设置) -# api_key = "sk-..." -# 自定义 API 端点 (可选) -# base_url = "https://api.example.com/v1" - -[llm.config] -max_tokens = 4096 -temperature = 0.1 - -[agent] -# 单次任务最大步数 -max_steps = 50 -# 系统提示模板路径 (相对于 sgclaw 二进制) -system_prompt_template = "prompts/system.txt" - -[memory] -# SQLite 数据库路径 -db_path = "data/memory.db" -# 短期记忆最大条数 -short_term_max_messages = 50 -# 短期记忆最大 token 数 -short_term_max_tokens = 8000 - -[security] -# rules.json 路径 (域白名单 + action 白名单) -rules_path = "rules.json" -# Skill 公钥路径 (Ed25519) -skill_public_key_path = "keys/skill_verify.pub" - -[skills] -# 技能目录路径 -skills_dir = "sgclaw-skills" - -[circuit_breaker] -# 连续失败熔断阈值 -failure_threshold = 10 -# 基础冷却时间 (秒) -cooldown_base_secs = 1 -# 最大冷却时间 (秒) -cooldown_max_secs = 30 - -[mcp] -# MCP Server 配置 (可选) -# [[mcp.servers]] -# name = "filesystem" -# command = "npx" -# args = ["-y", "@anthropic/mcp-server-filesystem", "/tmp"] +```text +browser_action ``` -### 7.2 环境变量覆盖 +### 5.2 参数 schema -所有配置均可通过 `SGCLAW_` 前缀的环境变量覆盖: +当前有效参数: -| 环境变量 | 覆盖配置项 | 示例 | -|---------|-----------|------| -| `SGCLAW_LOG_LEVEL` | `general.log_level` | `debug` | -| `SGCLAW_LLM_PROVIDER` | `llm.provider` | `ollama` | -| `SGCLAW_LLM_MODEL` | `llm.model` | `qwen2.5:32b` | -| `SGCLAW_LLM_API_KEY` | `llm.api_key` | `sk-...` | -| `SGCLAW_LLM_BASE_URL` | `llm.base_url` | `http://localhost:11434` | -| `SGCLAW_MAX_STEPS` | `agent.max_steps` | `100` | -| `SGCLAW_RULES_PATH` | `security.rules_path` | `/etc/sgclaw/rules.json` | +- `action` +- `expected_domain` +- `selector` +- `text` +- `url` +- `clear_first` -优先级:环境变量 > 配置文件 > 编译时默认值。 +其中: + +- `click` 通常需要 `selector` +- `type` 通常需要 `selector` 与 `text` +- `navigate` 通常需要 `url` +- `getText` 通常需要 `selector` + +### 5.3 失败语义 + +工具执行失败分两类: + +1. 参数级失败 +说明:缺少必填字段、动作不支持、参数类型错误。 + +2. 协议级失败 +说明:MAC 不通过、浏览器回包 `success=false`、响应超时、序列号异常。 + +这两类失败最终都会转为任务失败并通过 `task_complete` 回传。 --- -*文档结束。本文档为 sgClaw L2 层模块设计与接口契约参考,各组应基于此文档中的接口定义 -进行并行开发。接口变更需经三方组长会审后更新本文档。* +## 6. 接口演进原则 + +L2 之后的扩展应遵守以下原则: + +- 新增动作先进入协议枚举,再补规则白名单,再开放给 tool schema。 +- 不允许只改文档或只改提示词就宣称动作可用。 +- 兼容层与 fallback 路径必须对外保持同一工具名和同一主契约。 +- 浏览器宿主联调时以 wire contract 为最高优先级,不把模型行为假设写进协议。 diff --git a/docs/L3-数据流与Skill体系层.md b/docs/L3-数据流与Skill体系层.md index f5920ad..fc14f11 100644 --- a/docs/L3-数据流与Skill体系层.md +++ b/docs/L3-数据流与Skill体系层.md @@ -1,1361 +1,208 @@ # L3 — 数据流与 Skill 体系层 -**文档版本**: 1.0 -**适用项目**: sgClaw (业数融合一平台 AI Agent 底座) -**编制日期**: 2026-03-03 +**文档版本**: 2.0 +**适用项目**: sgClaw(ZeroClaw 重构版) +**编制日期**: 2026-03-26 -**读者**: 高级开发者、Skill 开发者 —— 需要理解 Agent 内部数据流转、编写业务 Skill、集成 LLM、 -调优感知层和记忆系统。 +**读者**: 高级开发者、联调工程师、后续扩展设计人员 --- -## 1. 核心数据流时序 +## 1. 端到端数据流 -### 1.1 端到端数据流全景 - -一次完整的用户任务执行涉及以下数据流转路径。从用户在 Side Panel 输入自然语言指令开始, -到最终任务完成结果返回,数据流经前端 → C++ → Pipe → Rust → LLM → Pipe → C++ → DOM。 +当前主链路的数据流如下: ``` -用户输入 结果展示 -"导出本月合规报表" "已导出3份报表" - │ ▲ - ▼ │ -┌─────────────────────────────────────────────────────────────────────────────┐ -│ Side Panel (Vue) │ -│ AgentControlPanel.vue │ -│ ├─ sgFunctionsUI('sgclaw_submit_task', { instruction: "..." }) │ -│ └─ 接收 onLogEntry / onTaskCompleted 事件 │ -└──────────────┬────────────────────────────────────────────────┬────────────┘ - │ FunctionsUI IPC ▲ ExecuteJS push - ▼ │ -┌─────────────────────────────────────────────────────────────────────────────┐ -│ C++ Browser Process │ -│ │ -│ SgClawProcessHost │ -│ ├─ 将 instruction 封装为 pipe submit_task 消息 │ -│ ├─ PipeListener 接收 sgClaw 的 command 消息 │ -│ ├─ MAC Whitelist Check 校验 │ -│ └─→ CommandRouter → CdpCommandExecutor → 页面 DOM 操作 │ -│ │ -│ 响应路径: │ -│ CommandRouter result → PipeWriter → sgClaw │ -│ + AOM Snapshot (操作后的页面状态快照) │ -└──────────────┬────────────────────────────────────────────────┬────────────┘ - │ STDIO Pipe (JSON Line) ▲ - ▼ │ -┌─────────────────────────────────────────────────────────────────────────────┐ -│ sgClaw Rust Process │ -│ │ -│ ┌──────────────────────────────────────────────────────────────┐ │ -│ │ Agent Runtime (ReAct Loop) │ │ -│ │ │ │ -│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ -│ │ │ THINK │───→│ ACT │───→│ OBSERVE │──┐ │ │ -│ │ │ │ │ │ │ │ │ │ │ -│ │ │ LLM 推理 │ │ 执行工具 │ │ 解析结果 │ │ │ │ -│ │ │ 生成计划 │ │ 发送命令 │ │ 更新记忆 │ │ │ │ -│ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ -│ │ ▲ │ │ │ -│ │ └──── Critic 评估 ◄──────────────────────┘ │ │ -│ │ │ OK → 继续循环 │ │ -│ │ │ Abort → 终止任务 │ │ -│ └──────────────────────────────────────────────────────────────┘ │ -│ │ -│ 数据交互: │ -│ ├─ BrowserPipeTool ──→ Pipe ──→ Browser (command) │ -│ ├─ LLM Provider ──→ HTTP(S) ──→ Claude / GPT / Ollama │ -│ ├─ Memory ──→ SQLite (本地文件) │ -│ └─ SkillLoader ──→ 文件系统 (技能脚本) │ -│ │ -└─────────────────────────────────────────────────────────────────────────────┘ +Browser Host + └─ submit_task + ↓ +sgClaw Transport / Handshake + └─ handle_browser_message + ↓ +Execution Path Select + ├─ planner fallback + └─ zeroclaw compat runtime + ↓ +browser_action + ↓ +AgentMessage::Command + ↓ +Browser executes action + ↓ +BrowserMessage::Response + ↓ +log_entry / task_complete ``` -### 1.2 单步数据流详解 - -Agent 每一步(ReAct loop 的一次迭代)的数据流如下: - -``` -Step N 开始 -│ -├── 1. 构造 LLM 输入 -│ ├── system_prompt (模板渲染) -│ │ ├── 可用工具描述 (BrowserPipeTool + MCP tools) -│ │ ├── 可用技能列表 (SkillLoader.list_skills()) -│ │ ├── 安全约束说明 -│ │ └── 当前会话 trace_id -│ │ -│ ├── messages (对话历史) -│ │ ├── 短期记忆 (最近 N 条, token 截断) -│ │ └── 长期记忆检索结果 (语义相关的历史经验) -│ │ -│ └── tools (工具定义) -│ ├── browser_action: { 参数 JSON Schema } -│ └── mcp_tools: [外部工具列表] -│ -├── 2. 调用 LLM (THINK) -│ ├── → HTTP(S) → Claude API / OpenAI API / Ollama -│ ├── ← streaming chunks (thinking + tool_call) -│ └── 解析 LLM 输出: -│ ├── 纯文本 → 最终回答 (任务完成) -│ └── tool_call → 继续执行 -│ -├── 3. 执行工具调用 (ACT) -│ │ -│ ├── [browser_action] BrowserPipeTool.execute() -│ │ ├── MAC Policy 校验 (Rust 层) -│ │ ├── 构造 pipe command JSON -│ │ │ { seq: N, type: "command", action: "click", -│ │ │ params: { selector: "#btn" }, -│ │ │ security: { expected_domain: "erp.example.com", hmac: "..." } } -│ │ ├── 写入 stdout (→ pipe → Browser) -│ │ └── 等待 response (← pipe ← Browser) -│ │ { seq: N, type: "response", success: true, -│ │ data: { clicked: true }, -│ │ aom_snapshot: [...] } -│ │ -│ └── [mcp_tool] McpClientManager.call_tool() -│ ├── STDIO → MCP Server -│ └── ← tool result JSON -│ -├── 4. 处理结果 (OBSERVE) -│ ├── 格式化 observation 文本 -│ │ ├── 操作成功/失败 -│ │ ├── 结果数据摘要 -│ │ └── AOM 快照 (页面状态描述) -│ │ -│ ├── 存入短期记忆 -│ └── 追加到 messages 历史 -│ -├── 5. 质量评估 (CRITIC) -│ ├── 检查操作成功/失败 -│ ├── 检查是否重复操作 (死循环检测) -│ ├── 检查任务时长 -│ └── 更新 Circuit Breaker 状态 -│ -└── Step N 结束 → Step N+1 或 任务完成 -``` - -### 1.3 数据格式在各阶段的变换 - -``` -阶段 数据格式 示例 -──────────── ──────────────────────────── ────────────────────────────── -用户输入 自然语言字符串 "导出本月合规报表" - │ - ▼ -LLM 输入 Message[] + ToolDef[] { role: "user", content: "..." } - │ - ▼ -LLM 输出 ToolCall { name: "browser_action", - │ arguments: { action: "click", ... } } - ▼ -Pipe 命令 JSON Line {"seq":1,"type":"command","action":"click",...} - │ - ▼ -C++ 内部 base::Value (Dict) CommandRouter 参数字典 - │ - ▼ -DOM 操作 CDP / JS 执行 document.querySelector('#btn').click() - │ - ▼ -DOM 结果 CDP 返回值 { "result": { "type": "undefined" } } - │ - ▼ -Pipe 响应 JSON Line {"seq":1,"type":"response","success":true,...} - │ - ▼ -Observation 格式化文本 "操作成功:点击了'提交'按钮。\n当前页面..." - │ - ▼ -LLM 下一轮 Message (role: "tool") { role: "tool", content: "操作成功:..." } -``` +这条链路里没有独立 Skill 执行器,也没有独立任务编排数据库。 +因此 L3 的重点不再是“描述一个理想化智能体平台”,而是说明当前仓库里真实存在的数据流状态机。 --- -## 2. Agent 循环详解 +## 2. 任务生命周期 -### 2.1 ReAct 循环模型 +### 2.1 启动阶段 -sgClaw 采用 ReAct(Reasoning + Acting)循环模型,这是当前 AI Agent 领域最成熟的执行范式。 -核心思想:让 LLM 交替进行推理(Reasoning)和行动(Acting),每次行动后观察结果, -再决定下一步。 +1. 浏览器宿主拉起 sgClaw 进程。 +2. 宿主发送 `init`。 +3. sgClaw 返回 `init_ack`。 +4. `StdioTransport` 进入阻塞接收循环。 -``` -┌─────────────────────────────────────────────────────────┐ -│ ReAct 循环 │ -│ │ -│ ┌──────────┐ │ -│ │ 用户指令 │ │ -│ └─────┬────┘ │ -│ │ │ -│ ▼ │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ -│ │ │ │ │ │ │ │ -│ ┌─→│ THINK │────→│ ACT │────→│ OBSERVE │──┐ │ -│ │ │ │ │ │ │ │ │ │ -│ │ │ 推理下一步│ │ 调用工具 │ │ 读取结果 │ │ │ -│ │ │ 生成计划 │ │ 执行操作 │ │ 理解状态 │ │ │ -│ │ └──────────┘ └──────────┘ └──────────┘ │ │ -│ │ │ │ -│ │ ┌──────────┐ │ │ -│ └─────────│ CRITIC │◄─────────────────────────────┘ │ -│ │ │ │ -│ │ 质量评估 │ │ -│ │ 熔断检查 │ │ -│ └────┬─────┘ │ -│ │ │ -│ OK → 继续 │ -│ Abort → 终止 │ -│ Done → 返回结果 │ -│ │ -└─────────────────────────────────────────────────────────┘ +此阶段的目标是建立会话、版本和 HMAC 基线。 + +### 2.2 任务接收阶段 + +宿主发送: + +```json +{ "type": "submit_task", "instruction": "..." } ``` -### 2.2 System Prompt 模板 +Rust 侧在 [`src/agent/mod.rs`](/home/zyl/projects/sgClaw/claw/src/agent/mod.rs) 中接收后,不直接执行页面命令,而是先决定走哪条执行路径。 -Agent 的行为由 System Prompt 定义。以下是 sgClaw 的 System Prompt 模板结构: +### 2.3 执行路径选择 -``` -你是 sgClaw,一个运行在 SuperRPA 浏览器中的 AI 助手。你的任务是帮助用户在企业业务系统 -中完成自动化操作。 +#### 路径 A:planner fallback -## 身份与角色 -- 你运行在国家电网"业数融合一平台"的 SuperRPA 浏览器中 -- 你可以操控浏览器中打开的业务系统页面(ERP、OA、财务、HR 等) -- 你的每个操作都会被审计记录,trace_id: {{trace_id}} +条件:没有可用的 `DEEPSEEK_*` 环境配置。 +行为:使用仓库内置 planner 直接产生若干步骤,并逐个调用 `BrowserPipeTool`。 -## 可用工具 -你有一个核心工具 `browser_action`,支持以下操作: -{{#each tools}} -### {{this.name}} -{{this.description}} -参数: {{this.parameters}} -{{/each}} +特点: -## 可用技能 -以下是预置的业务技能脚本,当任务匹配时优先使用: -{{#each skills}} -- **{{this.name}}** (v{{this.version}}): {{this.description}} - 适用域名: {{this.domains}} -{{/each}} +- 依赖更少。 +- 逻辑可预测。 +- 适合协议联调和最小功能验证。 -## 安全约束 -1. 只能操作以下域名的页面: {{allowed_domains}} -2. 每个 browser_action 调用必须指定 expected_domain -3. 禁止尝试执行 eval、executeJsInPage 等操作 -4. 涉及登录、登出、清空存储的操作会请求用户确认 -5. 不要尝试读取或猜测用户密码 +#### 路径 B:ZeroClaw compat runtime -## 执行策略 -1. 先观察当前页面状态 (getAomSnapshot) -2. 制定执行计划,分步骤完成 -3. 每步操作后检查结果 -4. 遇到异常时尝试恢复(最多重试 3 次) -5. 任务完成后提供简明的执行摘要 +条件:存在有效模型配置。 +行为:构建 ZeroClaw Agent,注册 `browser_action` 工具,消费 `TurnEvent`,再通过 `BrowserPipeTool` 下发动作。 -## 输出格式 -- 思考过程用自然语言描述 -- 操作通过 tool_call 执行 -- 最终结果用中文文本总结 -``` +特点: -### 2.3 消息历史管理策略 - -Agent 的 LLM 调用需要发送对话历史(messages),但上下文窗口有限。 -sgClaw 采用分层记忆策略管理消息历史: - -``` -┌──────────────────────────────────────────────────────────────┐ -│ LLM 上下文窗口 (如 200K tokens) │ -│ │ -│ ┌─ System Prompt ────────────────────────────────────────┐ │ -│ │ ~2000 tokens (固定) │ │ -│ │ 工具定义 + 技能列表 + 安全约束 + 执行策略 │ │ -│ └────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─ 长期记忆检索 ─────────────────────────────────────────┐ │ -│ │ ~1000 tokens (按相关度检索) │ │ -│ │ 相似任务的历史经验、成功的操作路径 │ │ -│ └────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─ 短期对话记忆 ─────────────────────────────────────────┐ │ -│ │ 动态大小 (剩余 token 预算) │ │ -│ │ │ │ -│ │ ┌─ 最近 N 步完整记录 ──────────────────────────────┐ │ │ -│ │ │ Step K: thinking + action + observation │ │ │ -│ │ │ Step K+1: thinking + action + observation │ │ │ -│ │ │ ... │ │ │ -│ │ │ Step N: thinking + action + observation │ │ │ -│ │ └──────────────────────────────────────────────────┘ │ │ -│ │ │ │ -│ │ ┌─ 更早步骤的压缩摘要 ─────────────────────────────┐ │ │ -│ │ │ "Steps 1-5: 登录 ERP,导航到报表模块, │ │ │ -│ │ │ 设置了时间范围为本月" │ │ │ -│ │ └──────────────────────────────────────────────────┘ │ │ -│ │ │ │ -│ └────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─ 当前用户指令 ─────────────────────────────────────────┐ │ -│ │ ~100 tokens │ │ -│ │ "导出本月合规报表" │ │ -│ └────────────────────────────────────────────────────────┘ │ -│ │ -└──────────────────────────────────────────────────────────────┘ -``` - -**Token 预算分配**: - -| 区域 | Token 预算 | 策略 | -|------|-----------|------| -| System Prompt | ~2000 | 固定,编译时确定 | -| 长期记忆检索 | ~1000 | 按语义相关度排序取 top-3 | -| 短期对话记忆 | 剩余空间 | 最近步骤完整保留,早期步骤压缩 | -| 用户指令 | ~100 | 原文保留 | -| LLM 生成预留 | ~4096 | max_tokens 参数 | - -**短期记忆截断算法**: - -``` -truncate_messages(messages, token_budget): - // 1. 保留最近 5 步完整记录 - recent = messages[-5:] - recent_tokens = count_tokens(recent) - - // 2. 如果最近 5 步已超预算,减少保留数 - while recent_tokens > token_budget * 0.8 and len(recent) > 2: - recent = recent[-len(recent)+1:] - recent_tokens = count_tokens(recent) - - // 3. 对更早的步骤生成压缩摘要 - remaining_budget = token_budget - recent_tokens - older = messages[:-len(recent)] - if older: - summary = compress_steps(older, remaining_budget) - return [summary_message] + recent - else: - return recent -``` - -### 2.4 任务生命周期状态机 - -``` - ┌────────────────────────────┐ - │ TaskState Machine │ - └────────────────────────────┘ - - ┌─────────┐ - │ Idle │ - └────┬────┘ - │ submit_task(instruction) - ▼ - ┌─────────┐ - │Planning │ ← LLM 分析指令,生成初步计划 - └────┬────┘ - │ 计划生成完成 - ▼ - ┌─────────┐ - ┌───→│Executing│◄───┐ - │ └────┬────┘ │ - │ │ │ - │ ┌────┴────┐ │ - │ │Step N │ │ - │ │executing│ │ - │ └────┬────┘ │ - │ │ │ - │ ┌────┴────┐ │ - │ │Waiting │ │ step OK, more to do - │ │for resp │ │ - │ └────┬────┘ │ - │ │ │ - │ ┌────┴────┐ │ - │ │Observing│────┘ - │ └────┬────┘ - │ │ - │ ┌────┴────┐ - │ │Confirm? │ ← human-in-the-loop - │ └──┬───┬──┘ - │ yes │ │ no (auto-proceed) - │ │ │ - │ ┌──┴───┴──┐ - └────│Evaluate │ - └────┬────┘ - │ - ┌─────────┼─────────┐ - │ │ │ - ▼ ▼ ▼ - ┌─────────┐ ┌──────┐ ┌────────┐ - │Completed│ │Failed│ │Aborted │ - │ (成功) │ │(失败) │ │(用户终止)│ - └─────────┘ └──────┘ └────────┘ -``` +- 可以承载更自然的 agent 行为。 +- 为后续记忆、可观测性与 provider 扩展保留接口。 +- 当前仍严格受单工具和四动作约束。 --- -## 3. Skill 体系 +## 3. 单步动作数据流 -### 3.1 Skill 定义格式 +无论走哪条路径,真正触达浏览器时的数据流是一致的: -每个 Skill 是一个 JavaScript 文件,包含元数据头和执行函数。 +1. 生成动作 +说明:动作最终都被规约成 `Action + params + expected_domain`。 -**完整 Skill 文件结构**: +2. 本地策略校验 +说明:`BrowserPipeTool` 在发送前执行 MAC Policy 校验。 -```javascript -/** - * @skill erp-monthly-report - * @version 1.0.0 - * @description 从ERP系统导出月度财务报表。支持按部门、科目筛选, - * 自动处理分页数据,合并导出为完整报表。 - * @domains erp.example.com, erp-test.example.com - * @author sgClaw Team - * @params { - * "type": "object", - * "required": ["month"], - * "properties": { - * "month": { - * "type": "string", - * "pattern": "^\\d{4}-\\d{2}$", - * "description": "报表月份 (如 2026-03)" - * }, - * "department": { - * "type": "string", - * "description": "部门名称 (可选, 不填则导出全部)" - * }, - * "format": { - * "type": "string", - * "enum": ["xlsx", "csv", "pdf"], - * "default": "xlsx", - * "description": "导出格式" - * } - * } - * } - */ +3. 组装命令 +说明:生成 `AgentMessage::Command`,写入 `seq` 与 `security.hmac`。 -/** - * 技能执行入口 - * @param {object} params - 输入参数 (符合上方 @params 定义) - * @param {function} browserAction - BrowserAction 调用函数 - * @returns {object} 执行结果 { success: boolean, data?: any, error?: string } - */ -async function execute(params, browserAction) { - const { month, department, format = 'xlsx' } = params; +4. 浏览器执行 +说明:宿主按其自身执行器把命令转换为页面动作。 - try { - // Step 1: 导航到 ERP 报表页面 - await browserAction('navigate', 'https://erp.example.com/report/finance'); - await browserAction('waitForSelector', '.report-filter', 5000); +5. 接收回包 +说明:Rust 侧等待同 `seq` 的 `BrowserMessage::Response`。 - // Step 2: 设置筛选条件 - await browserAction('click', '#month-picker'); - await browserAction('type', '#month-input', month); +6. 形成观察结果 +说明:根据 `success`、`data`、`aom_snapshot` 和 `timing` 形成下一步输入或最终结果。 - if (department) { - await browserAction('click', '#dept-selector'); - await browserAction('type', '#dept-search', department); - await browserAction('click', `.dept-option[data-name="${department}"]`); - } - - // Step 3: 选择导出格式 - await browserAction('select', '#export-format', format); - - // Step 4: 点击导出 - await browserAction('click', '#export-btn'); - - // Step 5: 等待导出完成 - await browserAction('waitForSelector', '.export-success', 30000); - - // Step 6: 获取结果信息 - const resultText = await browserAction('getText', '.export-result'); - - return { - success: true, - data: { - message: resultText, - month: month, - department: department || '全部', - format: format - } - }; - - } catch (error) { - return { - success: false, - error: `导出报表失败: ${error.message}` - }; - } -} -``` - -### 3.2 Skill 仓库结构 - -``` -sgclaw-skills/ -├── registry.json # 技能清单 (签名 + 哈希索引) -├── builtin/ # 内置技能 (随产品交付) -│ ├── erp-monthly-report.js # ERP 月度报表导出 -│ ├── erp-anomaly-check.js # ERP 异常交易检查 -│ ├── oa-approval.js # OA 审批单处理 -│ ├── oa-meeting-schedule.js # OA 会议日程管理 -│ ├── finance-compliance.js # 财务合规线索提报 -│ ├── finance-reconciliation.js # 财务对账 -│ ├── hr-social-insurance.js # 人力社保申报 -│ ├── hr-salary-check.js # 薪酬数据核验 -│ ├── legal-contract-monitor.js # 合同履约监测 -│ └── cross-system-sync.js # 跨系统数据同步 -│ -├── custom/ # 用户自定义技能 -│ └── (用户创建的 .js 文件) -│ -└── keys/ - └── skill_verify.pub # Ed25519 公钥 (校验签名) -``` - -**registry.json 格式**: - -```json -{ - "version": "1.0", - "updated_at": "2026-03-03T00:00:00Z", - "skills": [ - { - "name": "erp-monthly-report", - "file": "builtin/erp-monthly-report.js", - "version": "1.0.0", - "hash": "sha256:a1b2c3d4e5f6...", - "signature": "ed25519:x7y8z9...", - "enabled": true - }, - { - "name": "oa-approval", - "file": "builtin/oa-approval.js", - "version": "1.2.0", - "hash": "sha256:f6e5d4c3b2a1...", - "signature": "ed25519:z9y8x7...", - "enabled": true - } - ] -} -``` - -### 3.3 Skill 生命周期 - -``` - ┌─────────────┐ - │ 开发阶段 │ - │ (JS 编写) │ - └──────┬──────┘ - │ - ▼ - ┌─────────────┐ - │ 签名阶段 │ - │ 构建系统 │ - │ Ed25519 签名│ - │ SHA-256 哈希│ - └──────┬──────┘ - │ - ▼ - ┌─────────────┐ - │ 发布阶段 │ - │ 更新 │ - │ registry │ - │ .json │ - └──────┬──────┘ - │ - ▼ - ┌─────────────┐ - │ 部署阶段 │ - │ 放入 │ - │ sgclaw- │ - │ skills/ │ - └──────┬──────┘ - │ - ▼ - ┌─────────────┐ - │ 加载阶段 │ - │ sgClaw 启动 │ - │ 校验签名 │ - │ 校验哈希 │ - │ 解析元数据 │ - │ 注册到 Agent│ - └──────┬──────┘ - │ - ▼ - ┌─────────────┐ - │ 执行阶段 │ ← Agent ReAct 循环中 LLM 选择使用 - │ Agent 调用 │ - │ 传入 params │ - │ + browser │ - │ Action 引用 │ - └──────┬──────┘ - │ - ▼ - ┌─────────────┐ - │ 沉淀阶段 │ ← 执行结果存入 Memory - │ 记录经验 │ - │ 成功率统计 │ - │ 供后续复用 │ - └─────────────┘ -``` - -### 3.4 从现有 JS 场景代码迁移到 Skill - -SuperRPA 已有大量 agent-vue 中的 JS 场景代码(49 个文件,208+ 个调用点)。 -这些代码可以迁移为 sgClaw Skill,实现复用。 - -**迁移策略**: - -| 阶段 | 内容 | 说明 | -|------|------|------| -| **Phase 1: 直接复用** | 现有 JS 代码通过 BrowserAction API 调用 | sgClaw 发送 pipe 命令 → Browser 执行 → JS SDK 代码无需改动 | -| **Phase 2: 技能化封装** | 将高频场景代码提取为 Skill | 添加元数据头、参数 schema、错误处理 | -| **Phase 3: LLM 增强** | Skill 作为 Agent 的工具选项 | LLM 根据用户指令自动选择合适的 Skill | - -**迁移示例**:将 agent-vue 中的 OA 审批代码迁移为 Skill - -现有代码(agent-vue 中): - -```javascript -// agent-vue/src/scenes/oa-approval.js -async function approveAll() { - await sgBrowser.page.navigate('https://oa.example.com/approval/pending'); - await sgBrowser.page.waitForSelector('.approval-list'); - const items = await sgBrowser.page.getText('.approval-list .item'); - for (const item of items) { - await sgBrowser.input.click(`.item[data-id="${item.id}"] .approve-btn`); - await sgBrowser.page.waitForSelector('.confirm-dialog'); - await sgBrowser.input.click('.confirm-dialog .ok-btn'); - } -} -``` - -迁移后的 Skill: - -```javascript -/** - * @skill oa-approval - * @version 1.0.0 - * @description OA系统待审批单据批量处理。支持查看待审批列表、 - * 批量审批、批量驳回、添加审批意见。 - * @domains oa.example.com, oa-test.example.com - * @params { - * "type": "object", - * "required": ["action"], - * "properties": { - * "action": { "enum": ["list", "approve_all", "reject", "approve_one"] }, - * "item_id": { "type": "string", "description": "单据ID (approve_one/reject 时需要)" }, - * "opinion": { "type": "string", "description": "审批意见 (可选)" } - * } - * } - */ -async function execute(params, browserAction) { - const { action, item_id, opinion } = params; - - // 导航到审批页面 - await browserAction('navigate', 'https://oa.example.com/approval/pending'); - await browserAction('waitForSelector', '.approval-list', 5000); - - switch (action) { - case 'list': { - const text = await browserAction('getText', '.approval-list'); - return { success: true, data: { items: text } }; - } - case 'approve_all': { - // 获取所有待审批项 - const snapshot = await browserAction('getAomSnapshot', '.approval-list'); - let count = 0; - - // 逐个审批 (带错误处理) - for (const item of snapshot) { - try { - await browserAction('click', `.item[data-id="${item.name}"] .approve-btn`); - await browserAction('waitForSelector', '.confirm-dialog', 3000); - if (opinion) { - await browserAction('type', '.opinion-input', opinion); - } - await browserAction('click', '.confirm-dialog .ok-btn'); - await browserAction('waitForSelector', '.success-toast', 3000); - count++; - } catch (e) { - // 单条失败不影响整体 - continue; - } - } - - return { success: true, data: { approved: count, total: snapshot.length } }; - } - // ... 其他 action - } -} -``` - -**迁移改动点总结**: - -| 改动项 | 说明 | -|-------|------| -| 添加元数据头 | `@skill`, `@version`, `@description`, `@domains`, `@params` | -| 函数签名统一 | `async function execute(params, browserAction)` | -| API 调用方式 | `sgBrowser.page.navigate(url)` → `browserAction('navigate', url)` | -| 错误处理 | 添加 try/catch,返回统一格式 `{ success, data, error }` | -| 参数化 | 硬编码值改为 params 输入 | - -### 3.5 Skill 执行沙箱 - -Skill 的 JS 脚本需要在受限环境中执行,防止恶意代码突破安全边界。 - -**沙箱约束**: - -| 能力 | 是否允许 | 说明 | -|------|---------|------| -| `browserAction()` | 允许 | 唯一的外部交互方式,受 MAC 策略约束 | -| `console.log/error` | 允许 | 输出到 Agent 日志 | -| `JSON.parse/stringify` | 允许 | 数据处理必需 | -| `Promise / async-await` | 允许 | 异步控制流必需 | -| `setTimeout / setInterval` | 允许 (受限) | 最大延迟 30s,用于等待 | -| `fetch / XMLHttpRequest` | **禁止** | 网络请求必须通过 browserAction | -| `require / import` | **禁止** | 不允许加载外部模块 | -| `process / child_process` | **禁止** | 不允许访问系统进程 | -| `fs / path` | **禁止** | 不允许访问文件系统 | -| `eval / Function()` | **禁止** | 不允许动态代码执行 | - -**实现方案**: - -sgClaw 使用轻量级 JS 引擎(如 Boa 或 embedded V8 via Rusty_V8)运行 Skill 脚本, -在创建执行上下文时仅注入允许的全局对象: - -```rust -// Skill 沙箱执行 (概念代码) -fn execute_skill(script: &str, params: Value, browser_tool: &BrowserPipeTool) -> Result { - let mut context = JsContext::new(); - - // 仅注入允许的全局对象 - context.register_global("browserAction", |args| { - // 代理到 BrowserPipeTool.execute() - browser_tool.execute(args) - }); - context.register_global("console", ConsoleProxy::new()); - context.register_global("JSON", JsonGlobal::new()); - context.register_global("Promise", PromiseGlobal::new()); - - // 禁止所有其他全局对象 - // (JsContext 默认不提供 Node.js / Browser API) - - // 执行技能脚本 - context.eval(script)?; - - // 调用 execute 函数 - let result = context.call("execute", &[params, browser_action_ref])?; - - Ok(result) -} -``` +这意味着“智能体行为”和“浏览器动作执行”之间的接口已经被压缩到非常薄的一层,这是 ZeroClaw 重构最有价值的结构变化。 --- -## 4. 感知层数据格式 +## 4. 日志与结果流 -### 4.1 AOM(Accessibility Object Model)快照 +当前会对宿主输出两类业务级反馈: -AOM 快照是 Agent 理解页面状态的核心数据源。每次浏览器操作后,响应中附带当前页面的 -AOM 快照,供 Agent 的 OBSERVE 阶段使用。 +### 4.1 `log_entry` -**AOM 快照格式**: +用途: -```json -{ - "aom_snapshot": [ - { - "role": "navigation", - "name": "主导航栏", - "bounds": [0, 0, 1920, 60], - "children": [ - { "role": "link", "name": "首页", "bounds": [20, 10, 60, 40] }, - { "role": "link", "name": "财务报表", "bounds": [100, 10, 80, 40], "focused": true }, - { "role": "link", "name": "系统设置", "bounds": [200, 10, 80, 40] } - ] - }, - { - "role": "main", - "name": "报表筛选区", - "bounds": [0, 60, 1920, 200], - "children": [ - { - "role": "combobox", - "name": "月份选择", - "value": "2026-03", - "bounds": [20, 80, 200, 40], - "selector": "#month-picker" - }, - { - "role": "combobox", - "name": "部门筛选", - "value": "", - "bounds": [240, 80, 200, 40], - "selector": "#dept-selector" - }, - { - "role": "button", - "name": "导出报表", - "bounds": [460, 80, 100, 40], - "selector": "#export-btn", - "disabled": false - } - ] - }, - { - "role": "table", - "name": "报表数据", - "bounds": [0, 260, 1920, 600], - "row_count": 25, - "children": [ - { - "role": "row", - "name": "表头", - "children": [ - { "role": "columnheader", "name": "科目编号" }, - { "role": "columnheader", "name": "科目名称" }, - { "role": "columnheader", "name": "借方金额" }, - { "role": "columnheader", "name": "贷方金额" } - ] - } - ] - } - ] -} -``` +- 向上层 UI 或调试台报告过程信息。 +- 对齐 ZeroClaw 的 `TurnEvent` 与 fallback 步骤日志。 -**AOM 快照字段说明**: +典型内容: -| 字段 | 类型 | 说明 | -|------|------|------| -| `role` | string | ARIA 角色 (button, link, textbox, table, etc.) | -| `name` | string | 元素的可访问名称 (label text, aria-label, etc.) | -| `bounds` | [x, y, w, h] | 元素的视口坐标和尺寸 (px) | -| `value` | string | 元素当前值 (input, select 等) | -| `selector` | string | CSS 选择器 (供后续操作使用) | -| `focused` | boolean | 是否获得焦点 | -| `disabled` | boolean | 是否禁用 | -| `checked` | boolean | 是否选中 (checkbox, radio) | -| `children` | array | 子元素列表 | -| `row_count` | number | 表格行数 (仅 table 角色) | +- 当前准备执行的动作。 +- compat runtime 中转译出的事件摘要。 +- 执行中的信息性提示。 -**AOM 快照与 LLM 的关系**: +### 4.2 `task_complete` -AOM 快照被格式化为结构化文本后,作为 observation 的一部分发送给 LLM: +用途: -``` -操作结果: 点击"财务报表"链接成功。 +- 明确任务是否成功。 +- 返回最终摘要文案。 -当前页面状态: -- 导航栏: 首页 | [财务报表] (当前) | 系统设置 -- 报表筛选区: - - 月份选择: 2026-03 - - 部门筛选: (未选择) - - [导出报表] 按钮 (可用) -- 报表数据: 25行数据已加载 - - 表头: 科目编号 | 科目名称 | 借方金额 | 贷方金额 -``` - -### 4.2 SoM(Set-of-Mark)标注 - -在需要视觉辅助时,sgClaw 可以请求带 SoM 标注的页面截图。SoM 在页面截图上为每个 -可交互元素叠加数字标签,便于 LLM 通过编号引用元素。 - -**请求方式**: - -```json -{ - "seq": 10, - "type": "command", - "action": "pageScreenshot", - "params": { - "full_page": false, - "som_overlay": true - }, - "security": { "expected_domain": "erp.example.com", "hmac": "..." } -} -``` - -**响应**: - -```json -{ - "seq": 10, - "type": "response", - "success": true, - "data": { - "image_base64": "/9j/4AAQSkZJRg...", - "som_labels": [ - { "id": 1, "selector": "#month-picker", "name": "月份选择", "bounds": [20, 80, 200, 40] }, - { "id": 2, "selector": "#dept-selector", "name": "部门筛选", "bounds": [240, 80, 200, 40] }, - { "id": 3, "selector": "#export-btn", "name": "导出报表", "bounds": [460, 80, 100, 40] } - ] - } -} -``` - -**LLM 使用 SoM 的方式**: - -LLM 看到截图后可以引用标签编号: - -``` -我看到页面上有以下可交互元素: -[1] 月份选择 - 当前值 2026-03 -[2] 部门筛选 - 未选择 -[3] 导出报表按钮 - -我需要点击 [3] 导出报表按钮来导出数据。 -``` - -**SoM 使用策略**: - -| 场景 | 使用方式 | 优先级 | -|------|---------|--------| -| 正常操作 | AOM 快照(文本) | 默认,token 开销低 | -| AOM 不可用或不完整 | SoM 截图 | 兜底方案 | -| 复杂视觉布局 | AOM + SoM 结合 | 特殊场景 | -| 表格/图表分析 | SoM 截图 | 视觉信息丰富时 | - -### 4.3 感知数据选择策略 - -Agent 在 OBSERVE 阶段根据当前状态自动选择感知方式: - -``` -OBSERVE(pipe_response): - │ - ├── 1. 解析 pipe_response.aom_snapshot - │ │ - │ ├── AOM 不为空且完整度 > 80%? - │ │ → 使用 AOM 文本格式作为 observation - │ │ - │ └── AOM 为空或不完整? - │ → 请求 SoM 截图作为 observation - │ - ├── 2. AOM 完整度判断 - │ ├── 页面有可交互元素但 AOM 未列出 → 不完整 - │ ├── AOM 元素数为 0 但页面非空白 → 不完整 - │ └── 其他情况 → 完整 - │ - └── 3. 格式化 observation - ├── AOM: 结构化文本描述 - └── SoM: 截图 (base64) + 标签列表 -``` +这是上层产品最稳定的完成态信号,不应依赖 stderr 日志或内部推理文本。 --- -## 5. LLM 集成 +## 5. Skill 体系的当前定义 -### 5.1 Provider 适配层 +“L3 是灵魂”的前提,不是把 Skill 写得越来越玄,而是把 Skill 在当前阶段的真实语义说清楚。 -sgClaw 通过 ZeroClaw 的 Provider trait 抽象对接不同的 LLM 服务。 -每个 Provider 实现 HTTP 调用、streaming 解析、错误重试等逻辑。 +### 5.1 当前不存在独立 Skill 引擎 -**Provider 统一行为要求**: +当前仓库中没有独立的: -| 行为 | 要求 | 说明 | -|------|------|------| -| 超时 | 连接 10s,首 token 30s,总体 120s | 防止挂起 | -| 重试 | 最多 3 次,指数退避 (1s, 2s, 4s) | 仅重试 5xx 和网络错误 | -| Streaming | 必须支持 | 用于实时日志显示 | -| Tool-use | 必须支持 | Agent ReAct 的核心能力 | -| Token 计量 | 每次调用后上报 usage | 审计和成本控制 | -| 错误分类 | 区分可重试/不可重试错误 | 401/403 不重试 | +- Skill 脚本目录加载流程 +- Skill 注册表 +- Skill 沙箱执行器 +- Skill 版本与签名校验主链路 -### 5.2 Claude Provider 实现要点 +因此不能再把 Skill 描述为已落地子系统。 -```rust -pub struct ClaudeProvider { - client: reqwest::Client, - api_key: String, - model: String, - base_url: String, -} +### 5.2 当前可以保留的 Skill 语义 -impl ClaudeProvider { - const DEFAULT_BASE_URL: &'static str = "https://api.anthropic.com"; - const API_VERSION: &'static str = "2023-06-01"; +在 ZeroClaw 重构版里,Skill 更准确的含义是: - /// 将 sgClaw 的 Message 格式转换为 Claude API 格式 - fn convert_messages(messages: &[Message]) -> Vec { - // Message::User → { role: "user", content: [...] } - // Message::Assistant → { role: "assistant", content: [...] } - // Message::Tool → { role: "user", content: [{ type: "tool_result", ... }] } - } +- 面向未来的“可复用任务模式”抽象。 +- 可能由提示词、模板、预设工具组合或 planner 规则来承载。 +- 最终仍要落到统一的 `browser_action` 契约。 - /// 将 sgClaw 的 ToolDefinition 转换为 Claude tool 格式 - fn convert_tools(tools: &[ToolDefinition]) -> Vec { - // ToolDefinition → { name, description, input_schema } - } -} -``` +换句话说,当前 Skill 不是一个运行时目录,而是一种产品与执行层之间的抽象语言。 -### 5.3 输出约束 +### 5.3 Skill 演进约束 -LLM 的输出必须遵循以下约束: +后续如果重新引入 Skill 子系统,必须满足: -**Tool-use 输出格式** (Claude API): - -```json -{ - "role": "assistant", - "content": [ - { - "type": "thinking", - "thinking": "用户要导出本月合规报表。我需要先导航到 ERP 系统的报表模块..." - }, - { - "type": "tool_use", - "id": "toolu_01xyz", - "name": "browser_action", - "input": { - "action": "navigate", - "params": { - "url": "https://erp.example.com/report/compliance" - }, - "expected_domain": "erp.example.com" - } - } - ] -} -``` - -**输出校验规则**: - -``` -LLM 输出校验: -│ -├── 1. 是否为合法 JSON? -│ → 否: 请求 LLM 重新生成 (最多 2 次) -│ -├── 2. tool_call 格式是否正确? -│ ├── name 必须是 "browser_action" 或已注册的 MCP 工具 -│ ├── input 必须包含 action 字段 -│ └── action 必须在 Action 枚举中 -│ -├── 3. 参数是否通过 JSON Schema 校验? -│ → 否: 将校验错误信息反馈给 LLM,请求修正 -│ -├── 4. 是否包含 expected_domain? -│ → 否: 自动从上下文推断 (当前页面域名) -│ -└── 5. 通过所有校验 - → 交给 BrowserPipeTool 执行 -``` - -### 5.4 System Prompt 中的工具描述 - -提供给 LLM 的工具描述需要精确、简洁,帮助 LLM 正确选择操作: - -```json -{ - "name": "browser_action", - "description": "在浏览器中执行操作。可以点击元素、输入文本、导航页面、获取页面内容等。每次调用需要指定 action 类型和对应参数。", - "input_schema": { - "type": "object", - "required": ["action", "expected_domain"], - "properties": { - "action": { - "type": "string", - "enum": ["click", "type", "navigate", "getText", "getHtml", "waitForSelector", "pageScreenshot", "select", "scrollTo", "getAomSnapshot", "storageSet", "storageGet", "zombieSpawn", "zombieKill"], - "description": "要执行的操作类型" - }, - "params": { - "type": "object", - "description": "操作参数,根据 action 类型不同而不同" - }, - "expected_domain": { - "type": "string", - "description": "操作目标页面的域名(安全校验用)" - } - } - } -} -``` +- Skill 的输出仍服从 `browser_action` 或其后继正式工具契约。 +- Skill 不能绕过 `rules.json` 的安全边界。 +- Skill 文档不能先于代码宣称“已具备自治学习能力”。 --- -## 6. 记忆与自进化 +## 6. 配置与记忆的当前状态 -### 6.1 记忆分层架构 +### 6.1 配置 -``` -┌─────────────────────────────────────────────────────────────┐ -│ 记忆系统架构 │ -│ │ -│ ┌─ L0: 即时记忆 ─────────────────────────────────────────┐ │ -│ │ LLM 上下文窗口内的消息历史 │ │ -│ │ 生命周期: 单次 LLM 调用 │ │ -│ │ 容量: max_tokens (如 4096) │ │ -│ │ 用途: 当前步骤的推理依据 │ │ -│ └────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─ L1: 短期记忆 (Ring Buffer) ────────────────────────────┐ │ -│ │ VecDeque │ │ -│ │ 生命周期: 单次任务 (execute_task 调用) │ │ -│ │ 容量: 50 条消息 / 8000 tokens │ │ -│ │ 用途: 当前任务的完整对话历史 │ │ -│ │ 淘汰策略: FIFO,超限时压缩最早的消息为摘要 │ │ -│ └────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─ L2: 长期记忆 (SQLite) ─────────────────────────────────┐ │ -│ │ 持久化存储 │ │ -│ │ 生命周期: 跨任务、跨会话 │ │ -│ │ 容量: 磁盘空间限制 (建议 < 100MB) │ │ -│ │ 用途: 任务经验、用户偏好、技能执行记录 │ │ -│ │ 检索: 语义相似度 (向量) + 关键词匹配 │ │ -│ └────────────────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────┘ -``` +当前真正参与执行的关键配置来自 [`src/config/settings.rs`](/home/zyl/projects/sgClaw/claw/src/config/settings.rs): -### 6.2 记忆读写流程 +- `DEEPSEEK_API_KEY` +- `DEEPSEEK_BASE_URL` +- `DEEPSEEK_MODEL` -**写入流程**(任务执行过程中): +这些配置决定是否启用 compat runtime,以及模型请求如何路由。 -``` -Agent 每步操作后: -│ -├── 1. 写入短期记忆 (L1) -│ ├── 追加 thinking 消息 -│ ├── 追加 action 消息 -│ └── 追加 observation 消息 -│ -├── 2. 检查短期记忆容量 -│ ├── 消息数 > 50? → 压缩最早 10 条为摘要 -│ └── token 数 > 8000? → 压缩直至 < 8000 -│ -└── 3. (任务结束时) 写入长期记忆 (L2) - ├── 保存任务摘要 (type: TaskResult) - ├── 保存成功步骤序列 (type: SkillExperience) - └── 更新技能执行统计 (skill_executions 表) -``` +### 6.2 记忆 -**读取流程**(新任务开始时): +ZeroClaw compat 路径中已经接入 memory adapter,但在产品能力层面仍应描述为: -``` -execute_task(instruction): -│ -├── 1. 清空短期记忆 (新任务) -│ -├── 2. 从长期记忆检索相关经验 -│ ├── 语义搜索: embedding(instruction) vs memory_entries -│ ├── 取 top-3 相关条目 -│ └── 格式化为 "历史经验" 上下文 -│ -├── 3. 检查是否有精确匹配的 Skill 经验 -│ ├── 查询 skill_executions 表 -│ ├── 找到成功执行记录? -│ │ → 作为推荐步骤加入 system_prompt -│ └── 未找到? -│ → 不影响执行 -│ -└── 4. 组装初始上下文 - ├── system_prompt + 长期记忆检索结果 - ├── 用户指令 - └── 开始 ReAct 循环 -``` - -### 6.3 自进化学习机制 - -sgClaw 的自进化核心思想:每次成功执行的任务都是一个学习样本。 -通过记录和检索这些样本,Agent 在后续遇到相似任务时可以更快、更准确地完成。 - -**自进化循环**: - -``` - ┌─────────────────────────────┐ - │ 首次执行新任务 │ - │ │ - │ LLM 从零推理 │ - │ 多步试探 │ - │ 可能遇到错误和回退 │ - │ 平均 8-15 步完成 │ - └──────────┬──────────────────┘ - │ 成功完成 - │ - ▼ - ┌─────────────────────────────┐ - │ 经验沉淀 │ - │ │ - │ 记录成功步骤序列 │ - │ 记录关键决策点 │ - │ 计算向量嵌入 │ - │ 存入长期记忆 (L2) │ - └──────────┬──────────────────┘ - │ - ▼ - ┌─────────────────────────────┐ - │ 再次执行相似任务 │ - │ │ - │ 检索到历史经验 │ - │ LLM 参考已有路径 │ - │ 跳过试探阶段 │ - │ 平均 4-6 步完成 │ - └──────────┬──────────────────┘ - │ - ▼ - ┌─────────────────────────────┐ - │ 技能提炼 (可选) │ - │ │ - │ 高频任务 (>5 次相似执行) │ - │ 提取为正式 Skill 脚本 │ - │ 后续直接调用,1-2 步完成 │ - └─────────────────────────────┘ -``` - -**经验记录格式**: - -```json -{ - "id": "exp-2026-03-03-001", - "type": "task_result", - "content": "任务: 导出本月ERP合规报表\n\n执行路径:\n1. navigate → erp.example.com/report\n2. click → #month-picker → 设置为2026-03\n3. click → #compliance-tab\n4. click → #export-btn\n5. waitForSelector → .export-success\n\n结果: 成功导出,文件名 compliance-2026-03.xlsx", - "metadata": { - "task_instruction": "导出本月合规报表", - "steps": 5, - "duration_ms": 12500, - "domains_visited": ["erp.example.com"], - "skills_used": [], - "success": true - }, - "embedding": [0.12, -0.34, 0.56, ...], - "created_at": "2026-03-03T10:30:00Z", - "session_id": "trace-abc123" -} -``` - -### 6.4 向量检索实现 - -长期记忆的语义检索使用简单的余弦相似度计算。在数据量较小时(< 10000 条), -线性扫描足够快(< 10ms)。 - -**嵌入向量生成**: - -``` -文本 → 嵌入方式: -│ -├── 在线模型可用时: -│ └── 调用 LLM Provider 的 embedding API -│ ├── Claude: 不提供独立 embedding API,使用 summarize + hash -│ ├── OpenAI: text-embedding-3-small (1536 维) -│ └── Ollama: nomic-embed-text (384 维) -│ -└── 离线/无 embedding API 时: - └── 简单 TF-IDF 向量 + 关键词匹配 - ├── 中文分词 (jieba-rs) - ├── 计算词频向量 - └── 余弦相似度排序 -``` - -**检索优化策略**: - -| 策略 | 说明 | 适用场景 | -|------|------|---------| -| 类型过滤 | 先按 entry_type 过滤,减少扫描量 | 总是使用 | -| 时间窗口 | 优先检索最近 30 天的记忆 | 默认策略 | -| 域名过滤 | 按当前任务涉及的域名过滤 | 域名已知时 | -| 混合排序 | 0.7 * 向量相似度 + 0.3 * 时间衰减 | 综合排序 | +- 已为记忆能力预留接入位。 +- 当前主要价值在于兼容运行时需要,而非对外主卖点。 +- 还不能把它描述成稳定的长期知识库产品能力。 --- -## 7. 审计与追溯 +## 7. L3 结论 -### 7.1 Trace ID 体系 +L3 的核心不是“把所有未来能力都放进一个宏大数据流图”,而是说明当前系统如何把自然语言任务压缩成可验证、可回包、可受控的浏览器动作。 -每次 Agent 会话分配唯一的 `trace_id`,贯穿所有模块和组件,用于事后审计追溯。 +重构后的灵魂有三点: -**trace_id 格式**: - -``` -sgclaw-{date}-{random} -示例: sgclaw-20260303-a1b2c3d4 -``` - -**trace_id 传播路径**: - -``` -SgClawProcessHost::Start() - │ 生成 trace_id - │ - ├─→ init message: { trace_id: "sgclaw-20260303-a1b2c3d4" } - │ - ├─→ sgClaw Runtime: 所有日志附带 trace_id - │ ├─→ LLM 调用记录 - │ ├─→ Pipe 命令记录 - │ └─→ Memory 条目关联 - │ - ├─→ PipeListener: 所有 pipe 消息日志附带 trace_id - │ - └─→ CommandRouter: 操作审计日志附带 trace_id -``` - -### 7.2 审计日志格式 - -**sgClaw 端日志** (输出到 stderr,结构化 JSON): - -```json -{ - "timestamp": "2026-03-03T10:23:05.123Z", - "level": "INFO", - "trace_id": "sgclaw-20260303-a1b2c3d4", - "module": "agent::runtime", - "event": "step_completed", - "data": { - "step": 3, - "action": "click", - "selector": "#export-btn", - "domain": "erp.example.com", - "success": true, - "duration_ms": 245 - } -} -``` - -**Browser 端日志** (SuperRPA 已有日志系统): - -``` -[2026-03-03 10:23:05.123] [sgclaw] [trace:sgclaw-20260303-a1b2c3d4] - PIPE_CMD seq=3 action=click selector=#export-btn domain=erp.example.com - MAC_CHECK: ALLOW - CMD_EXEC: OK (245ms) -``` - -### 7.3 日志采集与存储 - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ 日志采集架构 │ -│ │ -│ sgClaw (Rust) Browser (C++) │ -│ ┌───────────┐ ┌───────────┐ │ -│ │ tracing │ │ LOG() │ │ -│ │ → stderr │ │ → file │ │ -│ └─────┬─────┘ └─────┬─────┘ │ -│ │ │ │ -│ ▼ ▼ │ -│ sgclaw.log chrome_debug.log │ -│ (JSON Lines) (SuperRPA 格式) │ -│ │ │ │ -│ └───────────┬───────────────────┘ │ -│ │ │ -│ ▼ │ -│ 审计查询接口 │ -│ (按 trace_id 关联检索) │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -**日志保留策略**: - -| 日志类型 | 保留时长 | 存储位置 | -|---------|---------|---------| -| sgClaw 操作日志 | 90 天 | 本地文件 + 可选远程上传 | -| Pipe 通信记录 | 30 天 | 本地文件 | -| LLM 调用记录 | 90 天 | 本地文件 (含 token 用量) | -| 长期记忆 (SQLite) | 永久 | 本地数据库 | -| 浏览器审计日志 | 按已有策略 | SuperRPA 日志系统 | - ---- - -*文档结束。本文档为 sgClaw L3 层数据流与 Skill 体系参考。Skill 开发者应重点关注 -第 3 节(Skill 体系)和第 4 节(感知层数据格式),高级开发者应关注第 2 节(Agent 循环) -和第 6 节(记忆与自进化)。* +- 任务入口统一。 +- 动作契约统一。 +- 执行路径可替换,但协议和安全边界不变。 diff --git a/docs/L4-工程实现与部署拓扑层.md b/docs/L4-工程实现与部署拓扑层.md index 422cdc2..8492097 100644 --- a/docs/L4-工程实现与部署拓扑层.md +++ b/docs/L4-工程实现与部署拓扑层.md @@ -1,1577 +1,223 @@ -# L4 -- 工程实现与部署拓扑层 +# L4 — 工程实现与部署拓扑层 -**文档版本**: 1.0 -**适用项目**: sgClaw (业数融合一平台 AI Agent 底座) -**编制日期**: 2026-03-03 +**文档版本**: 2.0 +**适用项目**: sgClaw(ZeroClaw 重构版) +**编制日期**: 2026-03-26 -**读者**: 开发者、DevOps、测试工程师 -- 需要搭建开发环境、理解构建流程、执行测试、部署发布。 +**读者**: 开发者、测试工程师、联调工程师 --- -## 1. 仓库结构 +## 1. 当前仓库结构 -sgClaw 系统的代码分布在两个仓库中:独立的 sgClaw Rust 仓库和 SuperRPA Chromium 仓库。 -前者承载 Agent 核心逻辑,后者承载浏览器侧集成代码和前端 UI。 - -### 1.1 sgClaw 仓库 (Rust 端) +本仓库已经收敛为以 Rust Runtime 为主、文档为辅的产品内核仓库。 +不再把外部浏览器仓库和旧验证页当作本仓库的主实现面。 ``` -/home/zyl/projects/sgClaw/ -├── Cargo.toml # 项目配置、依赖声明、编译优化 -├── Cargo.lock # 依赖版本锁定 +claw/ +├── Cargo.toml +├── resources/ +│ └── rules.json ├── src/ -│ ├── main.rs # 入口: pipe I/O 初始化, tokio runtime 启动 +│ ├── main.rs +│ ├── lib.rs │ ├── agent/ -│ │ ├── mod.rs # Agent 模块导出 -│ │ ├── runtime.rs # ZeroClaw ReAct 循环 (think -> act -> observe) -│ │ └── critic.rs # 输出质量评估 + Circuit Breaker 熔断器 -│ ├── pipe/ -│ │ ├── mod.rs # Pipe 模块导出 -│ │ ├── protocol.rs # JSON Line 编解码, 消息类型定义 -│ │ ├── handshake.rs # 版本协商 + HMAC 密钥交换 -│ │ └── browser_tool.rs # BrowserPipeTool: 自定义 Tool trait 实现 -│ ├── skill/ -│ │ ├── mod.rs # Skill 模块导出 -│ │ ├── loader.rs # 技能发现 + 签名校验 + 沙箱加载 -│ │ └── registry.rs # 技能注册表 (名称 -> 技能映射) +│ ├── compat/ +│ ├── config/ │ ├── llm/ -│ │ ├── mod.rs # LLM 模块导出 -│ │ ├── provider.rs # Provider trait 定义 (统一接口) -│ │ ├── claude.rs # Claude API 实现 (streaming) -│ │ ├── openai.rs # OpenAI/兼容 API 实现 -│ │ └── ollama.rs # 本地 Ollama 实现 -│ ├── memory/ -│ │ ├── mod.rs # Memory 模块导出 -│ │ ├── short_term.rs # Ring Buffer 短期对话记忆 -│ │ └── long_term.rs # SQLite + 向量存储 长期知识库 -│ ├── security/ -│ │ ├── mod.rs # Security 模块导出 -│ │ ├── mac_policy.rs # 域名 / Action 白名单校验 -│ │ └── hmac.rs # HMAC-SHA256 消息签名与验证 -│ └── config/ -│ ├── mod.rs # Config 模块导出 -│ └── settings.rs # 配置文件加载 (TOML / 环境变量) -├── skills/ # 内置技能目录 -│ ├── builtin/ # 预置业务技能脚本 -│ └── registry.json # 技能清单 + 签名哈希 +│ ├── pipe/ +│ └── security/ ├── tests/ -│ ├── integration/ # 集成测试 (pipe 协议, 端到端) -│ └── fixtures/ # 测试数据 (mock LLM 响应, JSON 样例) -├── docs/ # 设计文档 (L0-L4 分层) -├── scripts/ -│ ├── build-linux.sh # Linux musl 静态链接构建脚本 -│ ├── build-windows.sh # Windows MSVC 交叉编译脚本 -│ └── install-to-superrpa.sh # 二进制部署到 SuperRPA 目录 -└── .github/ - └── workflows/ # CI/CD 流水线定义 +├── third_party/ +│ └── zeroclaw/ +├── docs/ +│ ├── L0-...md +│ ├── L1-...md +│ ├── L2-...md +│ ├── L3-...md +│ ├── L4-...md +│ ├── 浏览器对接标准.md +│ ├── plans/ +│ └── archive/ +└── frontend/ + ├── README.md + └── archive/ ``` -### 1.2 SuperRPA 新增文件 (C++ 端) - -在已有 SuperRPA 仓库中新增一个 `sgclaw/` 子目录,约 500-600 行 C++ 代码。 -所有新增文件位于 `src/chrome/browser/superrpa/sgclaw/` 下,与已有子系统平级。 - -``` -src/chrome/browser/superrpa/ -├── BUILD.gn # [修改] 新增 :sgclaw source_set 依赖 -├── sgclaw/ # [新增目录] -│ ├── sg_claw_process_host.h # 进程宿主: 生命周期管理 (Start/Stop/OnCrash) -│ ├── sg_claw_process_host.cc # ~200-300 行, Singleton, 管道创建与进程启动 -│ ├── pipe_listener.h # 异步读取循环: 解析 JSON Line 消息 -│ ├── pipe_listener.cc # ~150 行, base::FileDescriptorWatcher -│ ├── mac_whitelist_check.h # Pipe 来源 MAC 校验: action + domain 白名单 -│ ├── mac_whitelist_check.cc # ~100 行, 与已有 rules.json 集成 -│ └── BUILD.gn # 子模块构建声明 -``` - -已有文件的修改点 (最小侵入): - -| 文件 | 修改内容 | 行数变更 | -|------|---------|---------| -| `superrpa/BUILD.gn` | deps 新增 `":sgclaw"` | +1 行 | -| `ui/ui_page_controller.cc` | 新增 Agent 启停的 FunctionsUI handler | +~50 行 | - -### 1.3 Side Panel 新增文件 (前端) - -前端变更位于 agent-vue 应用中,新增一个 Vue 组件用于 Agent 控制面板。 -agent-vue 基于 Vue 2.6 + Element UI,构建产物部署到 Side Panel 的 agent/ 目录。 - -``` -agent-vue/src/ -├── components/ -│ └── SgClawControl.vue # [新增] Agent 启停控制 + 状态展示 + 任务输入 -``` - -构建产物部署位置: - -``` -src/chrome/browser/resources/superrpa/panels/apps/agent/ -├── css/ -├── js/ -├── index.html -└── ... # npm run build:production 输出 -``` +工程上应把 `third_party/zeroclaw` 理解为“已 vendored 的兼容依赖”,而不是单独维护的兄弟项目。 --- -## 2. 构建系统 +## 2. 关键实现文件 -### 2.1 Rust 构建 (sgClaw) +### 2.1 入口与装配 -#### 2.1.1 Cargo.toml 核心配置 +- [`src/main.rs`](/home/zyl/projects/sgClaw/claw/src/main.rs) +- [`src/lib.rs`](/home/zyl/projects/sgClaw/claw/src/lib.rs) -```toml -[package] -name = "sgclaw" -version = "0.1.0" -edition = "2021" -description = "AI Agent engine for SuperRPA browser" +职责: -[dependencies] -zeroclaw = { version = "0.x", features = ["react-loop", "mcp"] } -rmcp = { version = "0.x", features = ["client", "transport-stdio"] } -tokio = { version = "1", features = ["full"] } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -rusqlite = { version = "0.31", features = ["bundled"] } -hmac = "0.12" -sha2 = "0.10" -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["json"] } -clap = { version = "4", features = ["derive"] } -thiserror = "1" -anyhow = "1" +- 初始化二进制入口。 +- 建立标准输入输出 transport。 +- 完成握手。 +- 将消息循环交给 `agent`。 -[profile.release] -opt-level = "z" # 最小体积优化 -lto = true # Link-Time Optimization -codegen-units = 1 # 单 codegen unit, 更好的优化 -strip = true # 去除符号表 -panic = "abort" # abort 而非 unwind, 减小体积 -``` +### 2.2 协议与浏览器工具 -#### 2.1.2 构建命令 +- [`src/pipe/protocol.rs`](/home/zyl/projects/sgClaw/claw/src/pipe/protocol.rs) +- [`src/pipe/browser_tool.rs`](/home/zyl/projects/sgClaw/claw/src/pipe/browser_tool.rs) +- [`src/pipe/handshake.rs`](/home/zyl/projects/sgClaw/claw/src/pipe/handshake.rs) + +职责: + +- 定义 wire message。 +- 维护 `seq` 和 HMAC。 +- 提供命令发送与响应等待能力。 + +### 2.3 执行路径 + +- [`src/agent/mod.rs`](/home/zyl/projects/sgClaw/claw/src/agent/mod.rs) +- [`src/agent/runtime.rs`](/home/zyl/projects/sgClaw/claw/src/agent/runtime.rs) +- [`src/compat/runtime.rs`](/home/zyl/projects/sgClaw/claw/src/compat/runtime.rs) +- [`src/compat/browser_tool_adapter.rs`](/home/zyl/projects/sgClaw/claw/src/compat/browser_tool_adapter.rs) + +职责: + +- 决定 fallback 或 compat 执行。 +- 把统一工具契约映射到浏览器协议。 +- 在 ZeroClaw turn 事件与宿主日志之间做桥接。 + +### 2.4 安全与配置 + +- [`src/security/mac_policy.rs`](/home/zyl/projects/sgClaw/claw/src/security/mac_policy.rs) +- [`src/config/settings.rs`](/home/zyl/projects/sgClaw/claw/src/config/settings.rs) +- [`resources/rules.json`](/home/zyl/projects/sgClaw/claw/resources/rules.json) + +职责: + +- 维护运行时安全边界。 +- 从环境变量读取 provider 配置。 + +--- + +## 3. 构建与运行 + +### 3.1 本地构建 + +当前仓库以 Cargo 为主: ```bash -# --- 开发构建 (快速编译, 含调试信息) --- cargo build - -# --- Release Linux (银河麒麟 V10 目标) --- -# musl 静态链接, 无 glibc 依赖 -cargo build --release --target x86_64-unknown-linux-musl -strip target/x86_64-unknown-linux-musl/release/sgclaw - -# 验证产物 -file target/x86_64-unknown-linux-musl/release/sgclaw -# 预期输出: ELF 64-bit LSB executable, x86-64, statically linked -ls -lh target/x86_64-unknown-linux-musl/release/sgclaw -# 预期大小: ~8.8 MB - -# --- Release Windows --- -cargo build --release --target x86_64-pc-windows-msvc - -# 验证产物 -ls -lh target/x86_64-pc-windows-msvc/release/sgclaw.exe -# 预期大小: ~9.0 MB ``` -#### 2.1.3 构建产物位置 - -``` -target/ -├── debug/ -│ └── sgclaw # 开发构建 (~30-50 MB, 含调试符号) -├── x86_64-unknown-linux-musl/ -│ └── release/ -│ └── sgclaw # Linux release (~8.8 MB) -└── x86_64-pc-windows-msvc/ - └── release/ - └── sgclaw.exe # Windows release (~9.0 MB) -``` - -#### 2.1.4 交叉编译配置 - -在开发机上为 Linux musl 目标编译需要安装 musl 工具链: +发布构建: ```bash -# Ubuntu / 银河麒麟 -sudo apt install musl-tools - -# 添加 Rust target -rustup target add x86_64-unknown-linux-musl - -# 如果需要 Windows 交叉编译 (从 Linux 编译 Windows 产物) -# 需要 cargo-xwin 或在 Windows CI 上构建 -cargo install cargo-xwin -cargo xwin build --release --target x86_64-pc-windows-msvc +cargo build --release ``` -### 2.2 C++ 构建 (SuperRPA 新增部分) +如果需要做协议或兼容层改动,优先先跑测试,再谈部署。 -#### 2.2.1 BUILD.gn 配置 +### 3.2 运行前提 -新增 `sgclaw/BUILD.gn`: +sgClaw 不是独立交互式 CLI 产品,正常运行前提是: -```gn -# src/chrome/browser/superrpa/sgclaw/BUILD.gn +- 有浏览器宿主进程作为父进程。 +- 宿主通过 STDIO 与 sgClaw 通信。 +- 宿主实现 `init/submit_task/response` 协议。 -source_set("sgclaw") { - sources = [ - "sg_claw_process_host.cc", - "sg_claw_process_host.h", - "pipe_listener.cc", - "pipe_listener.h", - "mac_whitelist_check.cc", - "mac_whitelist_check.h", - ] - deps = [ - "//base", - "//content/public/browser", - ] -} +直接在终端里执行二进制,只能用于开发级调试,不代表真实产品启动方式。 -source_set("sgclaw_unit_tests") { - testonly = true - sources = [ - "sg_claw_process_host_unittest.cc", - "pipe_listener_unittest.cc", - "mac_whitelist_check_unittest.cc", - ] - deps = [ - ":sgclaw", - "//base", - "//base/test:test_support", - "//testing/gtest", - ] -} -``` +### 3.3 模型配置 -在父级 `superrpa/BUILD.gn` 中添加依赖: - -```gn -source_set("superrpa") { - # ... 已有 sources ... - deps = [ - ":ai", - ":sgclaw", # <-- 新增 - "//base", - # ... 已有 deps ... - ] -} -``` - -#### 2.2.2 构建命令 +启用 ZeroClaw compat runtime 的关键环境变量: ```bash -# 进入 Chromium 源码目录 -cd /home/zyl/projects/superRpa/src - -# 生成构建配置 (仅首次或 BUILD.gn 变更时) -gn gen out/Default - -# 增量编译 Chrome (24 并发) -autoninja -j 24 -C out/Default chrome - -# 单独编译 sgclaw 单元测试 -autoninja -j 24 -C out/Default sgclaw_unittests - -# 运行 sgclaw 单元测试 -./out/Default/sgclaw_unittests +DEEPSEEK_API_KEY=... +DEEPSEEK_BASE_URL=... +DEEPSEEK_MODEL=... ``` -### 2.3 前端构建 (agent-vue) - -agent-vue 使用 Vue CLI 构建,产物部署到浏览器资源目录。 - -```bash -# 进入 agent-vue 目录 -cd /home/zyl/projects/superRpa/agent-vue - -# 安装依赖 (首次) -npm install - -# 开发模式 -npm run serve - -# 生产构建 -npm run build:production - -# 构建产物位于 dist/ 目录 -ls dist/ -# css/ js/ index.html favicon.ico ... -``` - -前端技术栈: -- Vue 2.6.14 + Vue Router 3.5 + Vuex 3.6 -- Element UI 2.15 -- Axios 1.9 (HTTP 请求) -- 无新增依赖,SgClawControl.vue 使用已有框架组件 - -### 2.4 联合构建流程 - -完整的从零构建步骤,适用于全新开发环境或 CI 流水线: - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ 联合构建流程 │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ Step 1: 构建 sgclaw (Rust) │ -│ ┌──────────────────────────────────────────────────────────┐ │ -│ │ cd /home/zyl/projects/sgClaw │ │ -│ │ cargo build --release --target x86_64-unknown-linux-musl │ │ -│ │ strip target/x86_64-unknown-linux-musl/release/sgclaw │ │ -│ │ cargo test │ │ -│ └──────────────────────────────┬───────────────────────────┘ │ -│ │ sgclaw (~8.8 MB) │ -│ ▼ │ -│ Step 2: 复制二进制到 SuperRPA 构建目录 │ -│ ┌──────────────────────────────────────────────────────────┐ │ -│ │ cp target/x86_64-unknown-linux-musl/release/sgclaw \ │ │ -│ │ /home/zyl/projects/superRpa/repack_work/ │ │ -│ │ extract_YYYYMMDD/opt/chromium.org/chromium/sgclaw │ │ -│ └──────────────────────────────┬───────────────────────────┘ │ -│ │ │ -│ ▼ │ -│ Step 3: 构建 SuperRPA (C++) │ -│ ┌──────────────────────────────────────────────────────────┐ │ -│ │ cd /home/zyl/projects/superRpa/src │ │ -│ │ gn gen out/Default │ │ -│ │ autoninja -j 24 -C out/Default chrome │ │ -│ └──────────────────────────────┬───────────────────────────┘ │ -│ │ chrome (Chromium 主程序) │ -│ ▼ │ -│ Step 4: 构建 agent-vue (前端) │ -│ ┌──────────────────────────────────────────────────────────┐ │ -│ │ cd /home/zyl/projects/superRpa/agent-vue │ │ -│ │ npm install && npm run build:production │ │ -│ └──────────────────────────────┬───────────────────────────┘ │ -│ │ dist/ (HTML + CSS + JS) │ -│ ▼ │ -│ Step 5: 部署前端到 Side Panel 资源目录 │ -│ ┌──────────────────────────────────────────────────────────┐ │ -│ │ cp -r agent-vue/dist/* \ │ │ -│ │ src/chrome/browser/resources/superrpa/panels/ │ │ -│ │ apps/agent/ │ │ -│ └──────────────────────────────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────────┘ -``` - -自动化构建脚本 (`scripts/build-linux.sh`): - -```bash -#!/bin/bash -set -euo pipefail - -SGCLAW_DIR="/home/zyl/projects/sgClaw" -SUPERRPA_DIR="/home/zyl/projects/superRpa" -TARGET="x86_64-unknown-linux-musl" - -echo "=== [1/4] Building sgclaw (Rust) ===" -cd "$SGCLAW_DIR" -cargo build --release --target "$TARGET" -strip "target/$TARGET/release/sgclaw" -echo " Binary size: $(du -h target/$TARGET/release/sgclaw | cut -f1)" - -echo "=== [2/4] Running sgclaw tests ===" -cargo test --release --target "$TARGET" - -echo "=== [3/4] Building SuperRPA (C++) ===" -cd "$SUPERRPA_DIR/src" -autoninja -j 24 -C out/Default chrome - -echo "=== [4/4] Building agent-vue ===" -cd "$SUPERRPA_DIR/agent-vue" -npm run build:production - -echo "=== Build complete ===" -``` +若这些变量不存在或不完整,系统会退回 planner fallback。 --- -## 3. 依赖管理 +## 4. 测试拓扑 -### 3.1 Rust 依赖 (Cargo.toml) +当前测试覆盖重点是“协议与兼容性”,而不是 UI 演示。 -| 依赖 | 版本 | 用途 | 可选 | -|------|------|------|------| -| `zeroclaw` | latest | Agent Runtime: ReAct 循环, Tool/Provider trait | 否 | -| `rmcp` | latest | MCP Client: 连接外部 MCP Server 获取工具 | features: client, transport-stdio | -| `tokio` | 1.x | 异步运行时: 事件循环, I/O, 定时器 | features: full | -| `serde` | 1.x | 序列化框架: derive 宏 | features: derive | -| `serde_json` | 1.x | JSON 编解码: pipe 协议消息 | 否 | -| `rusqlite` | 0.31+ | SQLite 存储: 长期记忆, Skill 缓存 | features: bundled (内嵌 SQLite) | -| `hmac` | 0.12 | HMAC 消息认证码: pipe 消息签名 | 否 | -| `sha2` | 0.10 | SHA-256 哈希: 配合 hmac 使用 | 否 | -| `tracing` | 0.1 | 结构化日志: span, event, 链路追踪 | 否 | -| `tracing-subscriber` | 0.3 | 日志输出: JSON 格式, 文件/stderr 输出 | features: json | -| `clap` | 4.x | 命令行参数解析: 配置文件路径, 日志级别 | features: derive | -| `thiserror` | 1.x | 错误类型定义: 自定义 Error enum | 否 | -| `anyhow` | 1.x | 错误传播: 顶层错误处理 | 否 | +主要测试类别包括: -依赖锁定策略: -- `Cargo.lock` 提交到版本控制,确保可重复构建 -- 依赖更新通过 `cargo update` 手动触发,经 CI 验证后合并 -- `rusqlite` 使用 `bundled` feature,内嵌 SQLite 源码编译,避免系统库版本差异 +- `pipe_protocol_test.rs` +- `pipe_handshake_test.rs` +- `browser_tool_test.rs` +- `runtime_task_flow_test.rs` +- `agent_runtime_test.rs` +- `compat_runtime_test.rs` +- `compat_browser_tool_test.rs` +- `compat_config_test.rs` +- `compat_memory_test.rs` +- `compat_cron_test.rs` -### 3.2 C++ 依赖 - -sgClaw 的 C++ 部分仅使用 Chromium 已有的基础库,无新增第三方依赖: - -| 依赖 | GN 路径 | 用途 | -|------|---------|------| -| base | `//base` | 线程 (SequencedTaskRunner), 回调 (OnceCallback), 进程管理 (LaunchProcess), 文件监听 (FileDescriptorWatcher) | -| content | `//content/public/browser` | BrowserContext, WebContents 交互接口 | - -无需引入 Mojo IPC -- sgClaw 使用更轻量的 STDIO Pipe 通信。 -Side Panel UI 通过已有的 `rpa_page_handler` Mojo 接口发送启停命令, -该接口已在 SuperRPA 中实现,仅需新增 2 个 handler method。 - -### 3.3 前端依赖 - -无新增 npm 依赖。SgClawControl.vue 使用 agent-vue 已有的技术栈: - -| 依赖 | 版本 | 用途 | -|------|------|------| -| `vue` | 2.6.14 | 组件框架 | -| `element-ui` | 2.15.14 | UI 组件库 (Button, Input, Message) | -| `vuex` | 3.6.2 | 状态管理 (Agent 运行状态) | -| `axios` | 1.9.0 | HTTP 请求 (如需与 local_service 通信) | - ---- - -## 4. 打包与发布 - -### 4.1 Linux .deb 打包 - -SuperRPA 以 `.deb` 包形式发布到银河麒麟 V10 SP1。sgClaw 的产物集成到现有打包流程中。 - -当前 .deb 包结构 (`repack_work/extract_YYYYMMDD/`): - -``` -DEBIAN/ -├── control # 包元数据 (版本、大小、描述) -└── postinst # 安装后脚本 (chmod +x) -opt/chromium.org/chromium/ -├── chrome # Chromium 主程序 (~1.6 GB) -├── superrpa-chromium # 启动脚本 (wrapper) -├── node/ # Node.js 运行时 -├── local_service/ # 本地 HTTP 服务 -├── locales/ # 语言包 -├── *.pak # 资源文件 -├── sgclaw # [新增] AI Agent 引擎 -└── sgclaw-skills/ # [新增] 技能目录 - ├── builtin/ # 内置技能脚本 - └── registry.json # 技能清单 -usr/bin/ -└── superrpa-chromium # 系统级启动链接 -``` - -#### 4.1.1 修改 repack-with-service.sh - -在现有 `scripts/repack-with-service.sh` 中新增 sgclaw 安装步骤: +建议执行: ```bash -# --- 新增: Install sgclaw binary --- -echo "[N/N] Installing sgclaw AI Agent..." -SGCLAW_BIN="/home/zyl/projects/sgClaw/target/x86_64-unknown-linux-musl/release/sgclaw" -SGCLAW_SKILLS="/home/zyl/projects/sgClaw/skills" - -if [ -f "$SGCLAW_BIN" ]; then - cp "$SGCLAW_BIN" "$CHROMIUM_DIR/sgclaw" - chmod +x "$CHROMIUM_DIR/sgclaw" - echo " sgclaw binary: $CHROMIUM_DIR/sgclaw ($(du -h "$SGCLAW_BIN" | cut -f1))" -fi - -if [ -d "$SGCLAW_SKILLS" ]; then - mkdir -p "$CHROMIUM_DIR/sgclaw-skills" - cp -r "$SGCLAW_SKILLS/"* "$CHROMIUM_DIR/sgclaw-skills/" - echo " sgclaw skills: $CHROMIUM_DIR/sgclaw-skills/" -fi -``` - -#### 4.1.2 postinst 修改 - -```bash -#!/bin/bash -set -e - -CHROMIUM_DIR=/opt/chromium.org/chromium - -# 已有权限设置 -chmod +x "$CHROMIUM_DIR/node/bin/node" 2>/dev/null || true -chmod +x "$CHROMIUM_DIR/superrpa-chromium" 2>/dev/null || true - -# 新增: sgclaw 权限 -chmod +x "$CHROMIUM_DIR/sgclaw" 2>/dev/null || true - -echo "SuperRPA Chromium with LocalService installed successfully" -``` - -#### 4.1.3 包大小影响 - -``` -当前 .deb 包大小: ~447 MB (含 Node.js local_service) -sgclaw 二进制: + ~8.8 MB -sgclaw-skills/: + ~0.2 MB (JSON + JS 技能脚本) -──────────────────────────────────────── -预计新 .deb 包大小: ~456 MB (增加约 2%) -``` - -### 4.2 Windows 安装包 - -Windows 端的 sgclaw.exe 放置在 SuperRPA 浏览器安装目录下: - -``` -C:\Program Files\SuperRPA Chromium\ -├── chrome.exe -├── sgclaw.exe # [新增] ~9 MB -├── sgclaw-skills\ # [新增] 技能目录 -│ ├── builtin\ -│ └── registry.json -└── ... -``` - -安装程序修改要点: -- 在 NSIS/Inno Setup 脚本中新增 sgclaw.exe 和 sgclaw-skills/ 的文件拷贝项 -- 无需注册服务或添加注册表项 -- sgclaw 由 chrome.exe 按需启动 -- 卸载时一并删除 sgclaw 相关文件和 SQLite 数据库 - -### 4.3 升级策略 - -#### 4.3.1 sgclaw 二进制升级 - -sgclaw 二进制本身无状态(运行时状态在内存中,持久状态在 SQLite 中), -升级策略为直接覆盖: - -```bash -# 停止 Agent (如果正在运行,由 SgClawProcessHost::Stop() 完成) -# 替换二进制 -cp sgclaw_new /opt/chromium.org/chromium/sgclaw -chmod +x /opt/chromium.org/chromium/sgclaw -# 下次用户点击 [启动] 时加载新版本 -``` - -#### 4.3.2 Skills 仓库更新 - -技能文件支持增量更新: - -``` -更新流程: - 1. 下载新版 registry.json (含每个技能的 SHA-256 哈希) - 2. 对比本地 registry.json, 识别变更的技能文件 - 3. 仅下载变更的 .js 文件 - 4. 校验每个文件的 SHA-256 签名 - 5. 原子替换 (写入临时文件 -> rename) -``` - -#### 4.3.3 数据库迁移 - -SQLite 数据库使用 schema 版本管理: - -```sql --- 内置 user_version pragma 记录 schema 版本 -PRAGMA user_version; -- 返回当前版本号 - --- sgclaw 启动时检查并执行迁移 --- migration_001.sql: 初始 schema --- migration_002.sql: 新增索引 --- migration_003.sql: 新增表 -``` - -迁移规则: -- 向前兼容: 新版 sgclaw 可读取旧版数据库 -- 自动迁移: 启动时检测 user_version,依次执行未应用的迁移脚本 -- 备份优先: 迁移前自动备份 `.db` 文件为 `.db.bak.{timestamp}` - ---- - -## 5. 测试策略 - -### 5.1 测试金字塔 - -``` - ┌───────────────────┐ - │ E2E 验收测试 │ 少量, 模拟完整用户场景 - │ (mock LLM) │ 确保端到端可用 - ├───────────────────┤ - │ │ - │ Pipe 协议集成 │ 真实 sgclaw 进程 - │ 测试 │ 验证 pipe 通信正确性 - ├───────────────────┤ - │ │ - │ C++ 单元测试 │ SgClawProcessHost - │ sgclaw_unittests│ PipeListener / MAC Check - ├───────────────────┤ - │ │ - │ Rust 单元测试 │ 大量, 覆盖核心逻辑 - │ cargo test │ mock LLM + mock pipe - │ │ - └───────────────────┘ -``` - -测试比例指导: -- Rust 单元测试: ~70% (快速、隔离、可重复) -- C++ 单元测试: ~15% (进程管理、协议解析) -- Pipe 协议集成测试: ~10% (真实进程间通信) -- E2E 验收测试: ~5% (端到端场景,mock LLM 保证可重复) - -### 5.2 Rust 单元测试 - -#### 5.2.1 Agent Runtime 测试 - -```bash -# 运行全部 Rust 测试 cargo test - -# 运行特定模块测试 -cargo test agent::runtime -cargo test agent::critic ``` -测试内容: -- ReAct 循环: mock LLM 返回固定输出, 验证 think -> act -> observe 流转 -- Circuit Breaker: 模拟连续失败, 验证熔断触发与恢复 -- 最大步数限制: 验证超出 50 步自动终止 - -```rust -// 测试示例: Circuit Breaker 在连续 10 次失败后触发 -#[tokio::test] -async fn test_circuit_breaker_triggers_after_threshold() { - let mut breaker = CircuitBreaker::new(10); - for _ in 0..10 { - breaker.record_failure(); - } - assert!(breaker.is_open()); -} -``` - -#### 5.2.2 BrowserPipeTool 测试 - -测试内容: -- 命令序列化: Rust struct -> JSON Line 格式正确 -- 响应反序列化: JSON Line -> Rust struct 解析正确 -- 未知 action 拒绝: 非枚举值被正确拒绝 -- HMAC 签名: 签名生成与校验一致 - -```bash -cargo test pipe::protocol -cargo test pipe::browser_tool -``` - -#### 5.2.3 MAC Policy 测试 - -测试内容: -- 域名白名单: 允许 / 拒绝 / 通配符匹配 -- Action 白名单: 允许的 action 通过, eval/executeJsInPage 被拒绝 -- 空白名单: 默认拒绝所有 - -```bash -cargo test security::mac_policy -``` - -#### 5.2.4 Memory 测试 - -测试内容: -- 短期记忆 Ring Buffer: 容量溢出时正确淘汰最旧条目 -- 长期记忆 SQLite: CRUD 操作, schema 迁移, 并发读写安全 -- 向量搜索: 相似度计算正确性 - -```bash -cargo test memory::short_term -cargo test memory::long_term -``` - -### 5.3 C++ 单元测试 - -新增 `sgclaw_unittests` target, 集成到 SuperRPA 现有测试体系。 - -```bash -# 构建 -autoninja -j 24 -C out/Default sgclaw_unittests - -# 运行 -./out/Default/sgclaw_unittests -``` - -#### 5.3.1 SgClawProcessHost 测试 - -``` -测试用例: -├─ Start() 在二进制存在时成功启动子进程 -├─ Start() 在二进制不存在时返回错误 -├─ Start() 重复调用不创建多个进程 (Singleton 保证) -├─ Stop() 发送 shutdown 命令后等待退出 -├─ Stop() 超时后强制 kill -├─ OnProcessCrash() 记录崩溃日志, 不自动重启 -└─ 析构函数确保清理子进程 -``` - -#### 5.3.2 PipeListener 测试 - -``` -测试用例: -├─ 正确解析单行 JSON 消息 -├─ 正确解析多行连续消息 (JSON Line 流) -├─ 拒绝超过 1 MB 的消息 (防内存 DoS) -├─ 拒绝非 JSON 格式的行 -├─ 管道断开时触发 OnPipeDisconnected 回调 -└─ sequence_id 乱序时触发告警 -``` - -#### 5.3.3 MAC Whitelist Check 测试 - -``` -测试用例: -├─ 允许列表内的 action (click, type, navigate) 通过 -├─ 禁止列表的 action (eval, executeJsInPage) 被拒绝 -├─ expected_domain 与当前页面域名匹配时通过 -├─ expected_domain 与当前页面域名不匹配时拒绝 -├─ 速率限制: 同一域超过 10 次/秒后拒绝 -└─ rules.json 加载失败时默认拒绝所有 -``` - -### 5.4 Pipe 协议集成测试 - -集成测试启动真实的 sgclaw 进程,通过 pipe 发送命令并验证响应。 -位于 `tests/integration/` 目录。 - -```bash -# 运行 Rust 集成测试 (需要先构建 sgclaw) -cargo test --test integration -``` - -#### 5.4.1 测试场景 - -``` -┌─────────────────────────────────────────────────────────┐ -│ Pipe 协议集成测试架构 │ -│ │ -│ Test Harness (Rust) │ -│ ┌───────────────────────────────────────────────┐ │ -│ │ │ │ -│ │ 1. 创建 pipe pair │ │ -│ │ 2. spawn sgclaw 子进程 │ │ -│ │ 3. 发送 handshake init 消息 │ │ -│ │ 4. 验证 init_ack 响应 │ │ -│ │ 5. 发送 command 消息 │ │ -│ │ 6. 验证 response 格式和内容 │ │ -│ │ 7. 发送 shutdown │ │ -│ │ 8. 验证进程正常退出 │ │ -│ │ │ │ -│ │ sgclaw 使用 mock LLM (--llm-mock 标志) │ │ -│ │ mock LLM 返回固定 action 序列 │ │ -│ │ │ │ -│ └───────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────┘ -``` - -测试用例: -- Handshake 成功: init -> init_ack, 版本匹配 -- Handshake 版本不匹配: sgclaw 返回错误并退出 -- 命令执行: command -> response, 验证 seq 匹配 -- 错误处理: 发送格式错误的 JSON, 验证 error response -- 管道断开: 关闭写端, 验证 sgclaw 退出码 0 -- 大消息拒绝: 发送 > 1 MB 的消息, 验证被丢弃 - -### 5.5 E2E 验收测试 - -E2E 测试覆盖完整的用户场景: 从浏览器启动 Agent 到任务执行完成。 -使用 mock LLM 确保测试可重复、无外部依赖。 - -#### 5.5.1 测试环境 - -``` -┌─────────────────────────────────────────────────────────┐ -│ E2E 测试环境 │ -│ │ -│ SuperRPA Chrome (headless 模式) │ -│ ├─ SgClawProcessHost 启动 sgclaw │ -│ ├─ sgclaw 使用 mock LLM (固定输出) │ -│ └─ 目标页面: 本地 test HTTP server (固定 HTML) │ -│ │ -│ 验证链: │ -│ 用户输入 -> Agent 理解 -> 生成 action -> Pipe 传输 │ -│ -> MAC 校验 -> CommandRouter 执行 -> 页面 DOM 变更 │ -│ -> 响应返回 -> Agent observe -> 任务完成 │ -└─────────────────────────────────────────────────────────┘ -``` - -#### 5.5.2 验收场景 - -| 场景 | 用户输入 | 预期行为 | 验收标准 | -|------|---------|---------|---------| -| 基本点击 | "点击提交按钮" | Agent 生成 click action | 按钮状态变为 disabled | -| 表单填写 | "在用户名框输入 admin" | Agent 生成 type action | input.value === "admin" | -| 页面导航 | "打开审批列表页面" | Agent 生成 navigate action | URL 变更为目标地址 | -| 域名拦截 | "访问 evil.com" | MAC 拒绝, Agent 报告失败 | 未发生导航 | -| 熔断触发 | 连续 10 次无效 action | Circuit Breaker 打开 | Agent 自动停止 | - -### 5.6 测试运行汇总 - -```bash -# === Rust 全量测试 === -cd /home/zyl/projects/sgClaw -cargo test # 单元测试 + 集成测试 -cargo test --release # Release 模式测试 (更贴近生产) - -# === C++ 全量测试 === -cd /home/zyl/projects/superRpa/src -autoninja -j 24 -C out/Default sgclaw_unittests -./out/Default/sgclaw_unittests - -# === 已有 SuperRPA 测试 (回归验证) === -autoninja -j 24 -C out/Default superrpa_unittests -./out/Default/superrpa_unittests # 14 test files - -autoninja -j 24 -C out/Default superrpa_ai_unittests -./out/Default/superrpa_ai_unittests # 3 test files - -# === 代码质量检查 === -cargo clippy -- -D warnings # Rust lint -cargo fmt -- --check # Rust 格式化检查 -cd /home/zyl/projects/superRpa/src && git cl format # C++ 格式化 -``` +这组测试表达了一个重要工程事实:当前系统的稳定核心是协议、runtime 选择和 compat 适配,而不是旧版前端验证页。 --- -## 6. 开发环境搭建 +## 5. 部署边界 -### 6.1 Rust 开发环境 +### 5.1 本仓库负责什么 -#### 6.1.1 基础安装 +- 提供 sgClaw Rust 二进制。 +- 提供规则文件。 +- 提供协议文档和测试基线。 -```bash -# 安装 Rust 工具链 (stable channel) -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -source ~/.cargo/env +### 5.2 外部宿主负责什么 -# 验证安装 -rustc --version # 预期: rustc 1.7x.x (stable) -cargo --version # 预期: cargo 1.7x.x +- 拉起并托管 sgClaw 进程。 +- 提供页面执行能力。 +- 实现命令落地、响应回传和宿主侧校验。 -# 安装编译目标 -rustup target add x86_64-unknown-linux-musl # Linux 静态链接 -rustup target add x86_64-pc-windows-msvc # Windows 交叉编译 (可选) +### 5.3 不在本仓库内交付的内容 -# 安装 musl 工具链 (Linux 静态链接依赖) -sudo apt update && sudo apt install -y musl-tools +- Chromium 工程源码与 BUILD 配置。 +- Side Panel 成品前端。 +- 生产部署脚本、安装包、发布流水线。 -# 安装开发工具 -rustup component add clippy # Lint 工具 -rustup component add rustfmt # 格式化工具 -``` - -#### 6.1.2 项目克隆与首次构建 - -```bash -# 克隆项目 -git clone /home/zyl/projects/sgClaw -cd /home/zyl/projects/sgClaw - -# 开发构建 (首次编译需下载依赖,约 2-5 分钟) -cargo build - -# 运行测试 -cargo test - -# 运行代码检查 -cargo clippy -- -D warnings - -# 格式化代码 -cargo fmt -``` - -#### 6.1.3 开发模式运行 - -sgclaw 通过 STDIO 与浏览器通信,开发时可直接在终端模拟 pipe 输入: - -```bash -# 方式一: 直接运行,手动输入 JSON Line -cargo run - -# 在终端中输入 (模拟 Browser 发来的 init 消息): -{"type":"init","version":"1.0","hmac_key":"dev-test-key"} - -# 方式二: 使用文件作为输入 -cargo run < tests/fixtures/sample_session.jsonl - -# 方式三: 使用 echo + pipe -echo '{"type":"init","version":"1.0"}' | cargo run -``` - -### 6.2 C++ 开发环境 - -C++ 开发依赖已有的 SuperRPA 开发环境。以下假设 depot_tools 和 Chromium 源码已就绪。 - -```bash -# 确认 depot_tools 在 PATH 中 -which gn # /path/to/depot_tools/gn -which autoninja # /path/to/depot_tools/autoninja - -# Chromium 源码目录 -ls /home/zyl/projects/superRpa/src/chrome/browser/superrpa/ -# 预期看到: BUILD.gn, ai/, cdp/, router/, session/, zombie/, ... - -# 新增 sgclaw 文件后,重新生成构建配置 -cd /home/zyl/projects/superRpa/src -gn gen out/Default - -# 增量编译 (仅编译变更的文件) -autoninja -j 24 -C out/Default chrome - -# 编译并运行 sgclaw 单元测试 -autoninja -j 24 -C out/Default sgclaw_unittests -./out/Default/sgclaw_unittests -``` - -### 6.3 联合调试 - -#### 6.3.1 sgclaw 独立调试 (Rust 侧) - -```bash -# 使用 RUST_LOG 控制日志级别 -RUST_LOG=debug cargo run 2>sgclaw-debug.log - -# 使用 lldb 或 gdb 调试 -cargo build -lldb target/debug/sgclaw - -# VS Code 调试 (需要 CodeLLDB 扩展) -# launch.json 配置见 6.4 节 -``` - -#### 6.3.2 附加到浏览器进程调试 (C++ 侧) - -```bash -# 启动 SuperRPA 浏览器 -cd /home/zyl/projects/superRpa/src -./out/Default/chrome --no-sandbox - -# 在另一终端查找 sgclaw 子进程 PID -pgrep -a sgclaw - -# 使用 gdb 附加 -gdb -p - -# 或使用 gdb 附加到 chrome 主进程,在 sgclaw 相关代码设断点 -gdb -p -(gdb) break SgClawProcessHost::Start -(gdb) continue -``` - -#### 6.3.3 日志查看 - -```bash -# sgclaw Rust 日志 (输出到 stderr, 不干扰 pipe 通信) -# 日志格式: JSON (tracing-subscriber json feature) -RUST_LOG=sgclaw=debug ./sgclaw 2>agent.log - -# 实时查看日志 -tail -f agent.log | python3 -m json.tool - -# Chrome 日志 (含 SgClawProcessHost 日志) -./out/Default/chrome --no-sandbox --enable-logging --v=1 2>&1 | grep -i sgclaw -``` - -### 6.4 IDE 配置 - -#### 6.4.1 VS Code + rust-analyzer (推荐) - -`.vscode/settings.json`: - -```json -{ - "rust-analyzer.cargo.target": "x86_64-unknown-linux-musl", - "rust-analyzer.check.command": "clippy", - "rust-analyzer.check.extraArgs": ["--", "-D", "warnings"], - "rust-analyzer.inlayHints.typeHints.enable": true, - "rust-analyzer.inlayHints.parameterHints.enable": true, - "[rust]": { - "editor.formatOnSave": true, - "editor.defaultFormatter": "rust-lang.rust-analyzer" - } -} -``` - -`.vscode/launch.json` (调试配置): - -```json -{ - "version": "0.2.0", - "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "Debug sgclaw", - "cargo": { - "args": ["build", "--bin=sgclaw"] - }, - "args": [], - "env": { - "RUST_LOG": "debug" - }, - "stdio": [null, null, null] - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests", - "cargo": { - "args": ["test", "--no-run"] - } - } - ] -} -``` - -推荐扩展: -- `rust-lang.rust-analyzer` -- Rust 语言支持 -- `vadimcn.vscode-lldb` -- LLDB 调试器 -- `tamasfe.even-better-toml` -- TOML 语法高亮 -- `serayuzgur.crates` -- Cargo.toml 依赖版本提示 - -#### 6.4.2 CLion + Rust 插件 - -CLion 原生支持 Rust (通过内置插件)。打开 `Cargo.toml` 即可识别项目。 - -关键配置: -- File -> Settings -> Languages -> Rust -> Cargo target: `x86_64-unknown-linux-musl` -- Run Configuration -> Cargo Command: 选择 `run` 或 `test` -- External Tool: 可配置 `cargo clippy` 为保存时自动运行 +L4 的工程边界必须按仓库现实写清楚,否则会把“外部依赖”误写成“本仓库已交付”。 --- -## 7. 代码规范 +## 6. 部署建议拓扑 -### 7.1 Rust 规范 - -#### 7.1.1 格式化 - -使用 `rustfmt` 统一代码格式。配置文件 `rustfmt.toml`: - -```toml -edition = "2021" -max_width = 100 -tab_spaces = 4 -use_field_init_shorthand = true -use_try_shorthand = true -``` - -执行命令: - -```bash -# 格式化所有代码 -cargo fmt - -# 检查格式 (CI 中使用) -cargo fmt -- --check -``` - -#### 7.1.2 Lint - -使用 `clippy` 进行静态分析,CI 中以 `-D warnings` 模式运行 (warnings 即 error): - -```bash -cargo clippy -- -D warnings -``` - -#### 7.1.3 命名约定 - -| 元素 | 风格 | 示例 | -|------|------|------| -| 变量 / 函数 | snake_case | `process_message`, `pipe_reader` | -| 类型 / Trait | CamelCase | `BrowserPipeTool`, `MacPolicy` | -| 常量 | SCREAMING_SNAKE_CASE | `MAX_MESSAGE_SIZE`, `DEFAULT_TIMEOUT` | -| 模块 | snake_case | `browser_tool`, `mac_policy` | -| 文件名 | snake_case | `browser_tool.rs`, `mac_policy.rs` | - -#### 7.1.4 错误处理 - -- 库级别错误: 使用 `thiserror` 定义具体的 Error enum -- 应用级别传播: 使用 `anyhow::Result` 简化错误链 -- 禁止 `unwrap()` / `expect()` 出现在非测试代码中 (clippy 规则) - -```rust -// 正确: 定义具体错误类型 -#[derive(thiserror::Error, Debug)] -pub enum PipeError { - #[error("message too large: {size} bytes (max {max})")] - MessageTooLarge { size: usize, max: usize }, - - #[error("invalid JSON: {0}")] - InvalidJson(#[from] serde_json::Error), - - #[error("pipe disconnected")] - Disconnected, -} - -// 正确: 使用 ? 传播 -fn read_message(reader: &mut BufReader) -> anyhow::Result { - let line = reader.read_line()?; - let msg: PipeMessage = serde_json::from_str(&line)?; - Ok(msg) -} -``` - -#### 7.1.5 日志 - -使用 `tracing` 框架,提供结构化日志和链路追踪: - -```rust -use tracing::{info, warn, error, debug, instrument}; - -#[instrument(skip(self), fields(seq = msg.seq))] -async fn handle_message(&self, msg: PipeMessage) -> Result { - info!(action = %msg.action, "processing command"); - // ... - if let Err(e) = result { - error!(error = %e, "command failed"); - } -} -``` - -### 7.2 C++ 规范 (延续 SuperRPA) - -延续 Chromium / SuperRPA 现有编码风格: - -| 规则 | 说明 | -|------|------| -| 缩进 | 2 空格 | -| 命名 | CamelCase (类型), lower_case (变量), kCamelCase (常量) | -| 头文件 | `#ifndef` 守卫,使用 `#pragma once` 亦可 | -| 智能指针 | `std::unique_ptr` 优先,`scoped_refptr` 用于引用计数对象 | -| 线程安全 | `base::SequencedTaskRunner` 绑定,避免直接使用锁 | -| 格式化 | `git cl format` (调用 clang-format) | - -```bash -# 格式化 C++ 代码 -cd /home/zyl/projects/superRpa/src -git cl format -``` - -### 7.3 Git 规范 - -#### 7.3.1 分支策略 +一个最小可工作的部署拓扑如下: ``` -main (保护分支, 始终可部署) - │ - ├── feature/sgclaw-pipe-protocol # 功能分支 - ├── feature/sgclaw-mac-check # 功能分支 - ├── fix/sgclaw-crash-on-large-msg # 修复分支 - └── release/v1.0.0 # 发布分支 +Browser Host Process + ├─ launches sgclaw binary + ├─ writes init / submit_task to stdin + ├─ reads command / log / task_complete from stdout + └─ executes page actions in host environment + +sgclaw binary + ├─ loads resources/rules.json + ├─ verifies action/domain + ├─ optionally calls provider API + └─ waits for browser response ``` -规则: -- `main` 分支受保护,仅通过 PR 合并 -- 功能分支从 `main` 创建,完成后合并回 `main` -- 命名格式: `{type}/{scope}-{brief-description}` -- type: feature, fix, refactor, test, docs - -#### 7.3.2 Commit Message 格式 - -采用 Conventional Commits 规范: - -``` -(): - - - -