系统架构
Rust CLI + Go Gateway 双二进制架构详解
本文档描述当前 Rust + Go + TypeScript 混合架构的完整系统设计。 覆盖范围:Gateway 主进程、Agent 运行时、原生沙箱、太虚永忆记忆系统、委托合约、渠道接入、前端 UI 所有子系统。
一、技术栈总览
| 层次 | 语言 / 运行时 | 职责 |
|---|---|---|
| 前端 UI | TypeScript + Lit + Vite | 聊天界面、配置管理、状态渲染 |
| Gateway(主进程) | Go 1.22+ | 所有业务逻辑、RPC 路由、事件广播 |
| Agent 运行时 | Go | LLM 调用、工具循环、Prompt 构建 |
| 原生沙箱 | Rust(oa-sandbox crate) | OS 级隔离(Seatbelt/Landlock/AppContainer) |
| 编程子智能体 | Rust(oa-coder crate) | MCP Server,代码编辑/搜索 |
| 持久化 Worker | Rust → Go bridge | JSON-Lines IPC 状态机 |
| 视觉子智能体(灵瞳) | C++/Rust(Argus)+ Go 子智能体 | 屏幕理解、视觉交互、独立 LLM session |
| 记忆系统 | Go(uhms 包) | 压缩、VFS、向量检索 |
二、系统全局架构图
┌─────────────────────────────────────────────────────────────────────┐
│ 用户端(飞书 / 钉钉 / 企微 / Discord / Telegram / Slack / 前端 UI) │
└─────────────┬───────────────────────────────────┬───────────────────┘
│ 即时通讯 WebSocket / Webhook │ WebSocket (RPC)
▼ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Go Gateway(主进程) │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ 渠道插件管理 │ │ RPC 路由层 │ │ WebSocket Broadcaster │ │
│ │ channels.Mgr │ │ (50+ 方法组) │ │ 事件广播 → 前端/渠道 │ │
│ └──────┬───────┘ └──────┬───────┘ └────────────────────────┘ │
│ │ │ │
│ ┌──────▼─────────────────▼────────────────────────────────────┐ │
│ │ GatewayState(中央状态) │ │
│ │ ChatRunState │ EscalationMgr │ ToolRegistry │ TaskPresetMgr │ │
│ │ NodeEventDispatcher │ Broadcaster │ ChannelMgr │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────▼──────────────────────────────────────────────────────┐ │
│ │ Agent 运行时(EmbeddedAttemptRunner) │ │
│ │ buildSystemPrompt → LLM API 流式调用 → 工具循环(最多30轮) │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ 工具执行层(tool_executor.go) │ │ │
│ │ │ bash │ read │ write │ search │ glob │ lookup_skill │ │ │
│ │ │ web_fetch │ web_search │ memory_* │ sessions_* │ │ │
│ │ │ browser(14 action) │ canvas │ cron │ image │ tts │ nodes │ │ │
│ │ │ argus_* │ remote_* │ spawn_coder_agent │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │ │ │ │
│ ┌──────▼───┐ ┌─────▼─────┐ ┌──▼──────┐ ┌─▼───────────────┐ │
│ │ 原生沙箱 │ │ 太虚永忆 │ │ Argus │ │ 委托合约系统 │ │
│ │ (Rust) │ │ 记忆系统 │ │ 视觉AI │ │ DelegationCtrl │ │
│ └──────────┘ └───────────┘ └─────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│ 原生 IPC(JSON-Lines)
▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ oa-sandbox(Rust) │ │ oa-coder(Rust MCP) │
│ 4 平台原生 OS 隔离 │ │ 编程子智能体 │
│ + 持久化 Worker │ │ JSON-RPC 2.0 stdio │
└─────────────────────────┘ └─────────────────────────┘┌─────────────────────────────────────────────────────────────────────┐
│ 用户端(飞书 / 钉钉 / 企微 / Discord / Telegram / Slack / 前端 UI) │
└─────────────┬───────────────────────────────────┬───────────────────┘
│ 即时通讯 WebSocket / Webhook │ WebSocket (RPC)
▼ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Go Gateway(主进程) │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ 渠道插件管理 │ │ RPC 路由层 │ │ WebSocket Broadcaster │ │
│ │ channels.Mgr │ │ (50+ 方法组) │ │ 事件广播 → 前端/渠道 │ │
│ └──────┬───────┘ └──────┬───────┘ └────────────────────────┘ │
│ │ │ │
│ ┌──────▼─────────────────▼────────────────────────────────────┐ │
│ │ GatewayState(中央状态) │ │
│ │ ChatRunState │ EscalationMgr │ ToolRegistry │ TaskPresetMgr │ │
│ │ NodeEventDispatcher │ Broadcaster │ ChannelMgr │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────▼──────────────────────────────────────────────────────┐ │
│ │ Agent 运行时(EmbeddedAttemptRunner) │ │
│ │ buildSystemPrompt → LLM API 流式调用 → 工具循环(最多30轮) │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ 工具执行层(tool_executor.go) │ │ │
│ │ │ bash │ read │ write │ search │ glob │ lookup_skill │ │ │
│ │ │ web_fetch │ web_search │ memory_* │ sessions_* │ │ │
│ │ │ browser(14 action) │ canvas │ cron │ image │ tts │ nodes │ │ │
│ │ │ argus_* │ remote_* │ spawn_coder_agent │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │ │ │ │
│ ┌──────▼───┐ ┌─────▼─────┐ ┌──▼──────┐ ┌─▼───────────────┐ │
│ │ 原生沙箱 │ │ 太虚永忆 │ │ Argus │ │ 委托合约系统 │ │
│ │ (Rust) │ │ 记忆系统 │ │ 视觉AI │ │ DelegationCtrl │ │
│ └──────────┘ └───────────┘ └─────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│ 原生 IPC(JSON-Lines)
▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ oa-sandbox(Rust) │ │ oa-coder(Rust MCP) │
│ 4 平台原生 OS 隔离 │ │ 编程子智能体 │
│ + 持久化 Worker │ │ JSON-RPC 2.0 stdio │
└─────────────────────────┘ └─────────────────────────┘三、Go Gateway 主进程
3.1 启动引导(boot.go)
GatewayState 是运行时所有子系统的单一持有者,在 NewGatewayState() 中按以下顺序初始化:
1. Broadcaster + EscalationManager + ToolRegistry 等核心组件
2. 沙箱初始化:
优先:oa-sandbox Rust 二进制 → NativeSandboxBridge.Start()
兜底:Docker 可用 → ContainerPool + Worker + ProgressHub
两者均不可用 → 无沙箱(记录警告)
3. Argus 视觉子智能体:
a. resolveArgusBinaryPath()(4 级优先级:$ARGUS_BINARY_PATH > .app bundle > ~/.crabclaw/bin > PATH 查找)
b. IsAvailable()(存在性 + 可执行权限 + 非目录检查)
c. EnsureCodeSigned()(macOS 裸二进制自动签名)
d. TCC 权限预检(macOS: Screen Recording + Accessibility + Sequoia 月度过期检测)
e. bridge.Start()(MCP 握手 5s 超时,失败保留 bridge 允许 UI 重试)
f. 启动失败 → 广播 argus.status.changed 事件(含 phase/reason/recovery)
4. 命令审批门控(CoderConfirmationManager,无条件初始化)
5. EscalationManager.RestoreFromDisk()(恢复未过期 pending 审批)
6. 太虚永忆记忆系统(配置启用则初始化)
7. 合约 VFS 持久化(UHMS VFS 可用则初始化 contractStore + TTL 清理 goroutine)
8. 浏览器控制器(CDP URL 配置存在则创建 PlaywrightBrowserController,支持 14 种 action + ARIA snapshot + AI Browse 循环)
9. 媒体发送器(ChannelMgr 存在则创建 mediaSenderAdapter → send_media 工具可用)1. Broadcaster + EscalationManager + ToolRegistry 等核心组件
2. 沙箱初始化:
优先:oa-sandbox Rust 二进制 → NativeSandboxBridge.Start()
兜底:Docker 可用 → ContainerPool + Worker + ProgressHub
两者均不可用 → 无沙箱(记录警告)
3. Argus 视觉子智能体:
a. resolveArgusBinaryPath()(4 级优先级:$ARGUS_BINARY_PATH > .app bundle > ~/.crabclaw/bin > PATH 查找)
b. IsAvailable()(存在性 + 可执行权限 + 非目录检查)
c. EnsureCodeSigned()(macOS 裸二进制自动签名)
d. TCC 权限预检(macOS: Screen Recording + Accessibility + Sequoia 月度过期检测)
e. bridge.Start()(MCP 握手 5s 超时,失败保留 bridge 允许 UI 重试)
f. 启动失败 → 广播 argus.status.changed 事件(含 phase/reason/recovery)
4. 命令审批门控(CoderConfirmationManager,无条件初始化)
5. EscalationManager.RestoreFromDisk()(恢复未过期 pending 审批)
6. 太虚永忆记忆系统(配置启用则初始化)
7. 合约 VFS 持久化(UHMS VFS 可用则初始化 contractStore + TTL 清理 goroutine)
8. 浏览器控制器(CDP URL 配置存在则创建 PlaywrightBrowserController,支持 14 种 action + ARIA snapshot + AI Browse 循环)
9. 媒体发送器(ChannelMgr 存在则创建 mediaSenderAdapter → send_media 工具可用)启动阶段枚举:init → starting → ready → stopping → stopped
3.2 RPC 方法注册(server.go)
Gateway 通过 MethodRegistry 统一注册所有 RPC 方法(WebSocket JSON-RPC):
| 方法组 | 示例方法 | 文件 |
|---|---|---|
| config | config.get / config.apply / config.schema | server_methods_config.go |
| models | models.list / models.set / models.test | server_methods_models.go |
| agents | agents.list / agents.create / agents.delete | server_methods_agents.go |
| agent | agent.run / agent.abort / agent.status | server_methods_agent.go |
| chat | chat.send / chat.history / chat.compact | server_methods_chat.go |
| skills | skills.status / skills.distribute / skills.store.{browse,pull,refresh,link,status} | server_methods_skills.go |
| memory | memory.search / memory.get / memory.uhms.* | server_methods_memory.go / uhms.go |
| channels | channels.list / channels.connect / channels.send | server_methods_channels.go |
| escalation | escalation.request / escalation.grant / escalation.revoke | server_methods_escalation.go |
| exec_approvals | exec.approvals.list / exec.approvals.grant | server_methods_exec_approvals.go |
| security | security.audit / security.policy.* | server_methods_security.go |
| system | system.reset / system.status | server_methods_system.go / reset.go |
| nodes | nodes.list / nodes.run / nodes.connect | server_methods_nodes.go |
| browser | browser.request(单 RPC 入口,body.method/path 路由) | server_methods_browser.go |
| cron | cron.list / cron.create / cron.trigger | server_methods_cron.go |
| tts | tts.speak / tts.stop | server_methods_tts.go |
| subagent | subagent.list / subagent.ctl | server_methods_subagent.go |
| argus | argus.permission.check | server_methods_argus.go |
| contract | contract.list / contract.get / contract.audit | server_methods_contracts.go |
| wizard | wizard.start / wizard.next / wizard.cancel / wizard.status | server_methods_wizard.go |
| packages | packages.catalog.browse / packages.catalog.detail / packages.install / packages.update / packages.remove / packages.installed | server_methods_packages.go |
| health / status | — | 内联注册 |
广播事件(前端订阅):
| 事件 | 触发时机 |
|---|---|
chat.message | Agent 流式回复 + 异步完成结果回填(asyncResult: true) |
chat.progress | 长任务中途进度推送(summary/phase/percent,8 秒节流 + 指纹去重) |
channel.message.incoming | 渠道新消息 |
argus.status.changed | Argus 状态变化 |
escalation.grant.created/expired | 权限升级审批 |
coder.confirm.requested/resolved | 命令审批 |
system.reset.done | 系统恢复完成 |
system.config.restored | 配置恢复 |
channel.message.incoming (coder:) | 子智能体对话频道事件(详见 架构-智能体任务频道.md) |
channel.message.incoming (task:) | 任务执行频道事件(详见 架构-智能体任务频道.md) |
task.queued/started/progress/completed/failed | 结构化任务看板事件(详见 架构-主动消息看板.md) |
3.3 WebSocket 连接生命周期(ws_server.go)
单连接 wsConnectionLoop 经 6 个阶段:
Phase 0: connect.challenge(发 nonce)
Phase 1: 等待 connect 帧(握手超时 30s,支持传统/UI req 两种格式)
Phase 1.5: nonce 验证(设备认证)
Phase 2: 认证(Token/Password + 设备签名校验)
Phase 3: hello-ok(返回协议版本、方法列表、策略)
Phase 4: 注册到 Broadcaster(WsClient 实例)
Phase 5: 请求-响应循环 + ping 保活Phase 0: connect.challenge(发 nonce)
Phase 1: 等待 connect 帧(握手超时 30s,支持传统/UI req 两种格式)
Phase 1.5: nonce 验证(设备认证)
Phase 2: 认证(Token/Password + 设备签名校验)
Phase 3: hello-ok(返回协议版本、方法列表、策略)
Phase 4: 注册到 Broadcaster(WsClient 实例)
Phase 5: 请求-响应循环 + ping 保活关键设计决策(2026-03-04 修复后):
| 机制 | 实现 | 说明 |
|---|---|---|
| 慢消费者检测 | 写超时 10s(SetWriteDeadline) | BufferedAmount 恒返回 0,不再使用累计字节(原实现单调递增必然误杀) |
| Ping 保活 | 30s ticker + pingDone channel | select 双路监听 ticker.C 和 pingDone,连接关闭时 close(pingDone) 通知退出,防止 goroutine 泄漏 |
| 写并发保护 | writeMu sync.Mutex | sendRaw / ping goroutine 共用同一把锁 |
| ClientIP 解析 | ResolveGatewayClientIP | StripOptionalPort(remoteAddr) → NormalizeIP → trusted proxy 匹配 → X-Forwarded-For / X-Real-IP 回退 |
3.4 HTTP 服务启动(server.go)
StartGatewayServer 返回 (*GatewayRuntime, error):
1. 初始化 GatewayState(boot.go)
2. 注册 50+ RPC 方法 + HTTP 路由(/v1/chat/completions, /v1/responses, /ws)
3. 启动 HTTP 监听(goroutine + listenErrCh channel)
4. select 等待: 500ms 超时 = 正常 | listenErrCh 错误 = return error
5. SetPhase(BootPhaseReady)1. 初始化 GatewayState(boot.go)
2. 注册 50+ RPC 方法 + HTTP 路由(/v1/chat/completions, /v1/responses, /ws)
3. 启动 HTTP 监听(goroutine + listenErrCh channel)
4. select 等待: 500ms 超时 = 正常 | listenErrCh 错误 = return error
5. SetPhase(BootPhaseReady)端口绑定失败时通过 error channel 向调用方传递错误(不再 os.Exit(1)),RunGatewayBlocking 检查返回值决定是否退出。
3.5 OpenAI 兼容 API(openai_http.go + openresponses_http.go)
两套协议共用相同模式:
| 端点 | 协议 | 文件 |
|---|---|---|
POST /v1/chat/completions | OpenAI Chat Completions(stream/non-stream) | openai_http.go |
POST /v1/responses | OpenResponses SSE 协议(完整事件序列) | openresponses_http.go |
流式处理关键机制:
- context 生命周期:
ctx, cancel = context.WithTimeout(Background, 5min)在 disconnect handler 之前创建 - 客户端断开:
r.Context().Done()触发 →cancel()(取消推理)+unsubscribe()(退订事件) - 双重保险: disconnect goroutine 和管线
defer cancel()都调用 cancel(context 包保证幂等) - CAS 互斥:
atomic.CompareAndSwapInt32(&closed, 0, 1)保证清理只执行一次
3.6 进度投递架构(progress_delivery.go)
所有入站路径均接线 OnProgress 回调,实现长任务中途进度推送:
┌─ chat.send ──────────┐
│ agent RPC ──────────┤ buildChatProgressCallback()
6 条入站路径: │ openai (non-stream) ─┤ → Broadcaster.Broadcast("chat.progress", ...)
│ openai (stream) ─────┤ → 8 秒节流 + 指纹去重
│ openresponses (non) ─┤
└─ openresponses (sse) ─┘
远程频道路径: buildRemoteProgressCallback()
(飞书/Discord 等) → ChannelMgr.SendMessage() 粗粒度文本 ┌─ chat.send ──────────┐
│ agent RPC ──────────┤ buildChatProgressCallback()
6 条入站路径: │ openai (non-stream) ─┤ → Broadcaster.Broadcast("chat.progress", ...)
│ openai (stream) ─────┤ → 8 秒节流 + 指纹去重
│ openresponses (non) ─┤
└─ openresponses (sse) ─┘
远程频道路径: buildRemoteProgressCallback()
(飞书/Discord 等) → ChannelMgr.SendMessage() 粗粒度文本两种回调工厂:
| 工厂函数 | 目标 | 节流间隔 | 去重方式 |
|---|---|---|---|
buildChatProgressCallback(broadcaster, sessionKey) | WebSocket chat.progress 事件 | 8 秒 | `summary |
buildRemoteProgressCallback(channelMgr, target) | 远程频道文本消息 | 8 秒 | 全文指纹 |
异步完成回填: 异步任务完成后,除原有 channel.message.incoming 通知外,新增 chat.message 回填(带 asyncResult: true),前端聊天区可直接 append 结果。
四、Agent 运行时(EmbeddedAttemptRunner)
核心文件:backend/internal/agents/runner/
4.1 主运行循环
RunEmbeddedAgent() ← gateway/server.go 调用
└─ runAttempt() ← run.go / attempt_runner.go
├─ 1. 加载历史消息
├─ 2. 检测会话状态
├─ 3. classifyIntent(prompt) ← intent_router.go(六级意图分类)
│
├─ 4. buildSystemPrompt(tier) ← prompt/prompt.go
│ ├─ 工具说明 + 安全规则
│ ├─ 技能索引 <available_skills>
│ ├─ 沙箱信息
│ ├─ 委托合约段(子智能体)
│ ├─ 太虚永忆记忆简报(L0 ~200 tokens)
│ └─ IntentGuidance(意图行为指引,按 tier 动态注入)
│
├─ 5. trimHistoryByIntent() ← 按意图裁剪历史
├─ 6. filterToolsByIntent() ← 按意图过滤工具(3-全量)
│
├─ 太虚永忆压缩(超阈值时) ← uhms.CompressChatMessages()
│
├─ LLM 流式调用 ← llmclient/
│ └─ 处理各 Provider 差异(Anthropic/OpenAI/Gemini/Ollama 等)
│
├─ 工具循环(最多 30 轮) ← tool_executor.go
│ ├─ 工具分发 + 执行
│ ├─ 写操作检测(looksLikeBashWrite — NativeSandbox 路径)
│ ├─ 连续全拒绝保护(3 轮上限)
│ ├─ 三层死循环防护:
│ │ ├─ L1: 同工具连续熔断(连续 5 次 → 终止 + 警告)
│ │ ├─ L2: per-tool 失败计数(累计 3 次 → 注入可操作修复指导,isToolSoftError 检测软错误)
│ │ └─ L3: 全局失败预算(净失败数 ≥ 8 → 终止循环,成功 -1 / 失败 +1 / 下限 0)
│ └─ 结果注入消息流
│
└─ 太虚永忆提交 ← uhms.CommitChatSession()RunEmbeddedAgent() ← gateway/server.go 调用
└─ runAttempt() ← run.go / attempt_runner.go
├─ 1. 加载历史消息
├─ 2. 检测会话状态
├─ 3. classifyIntent(prompt) ← intent_router.go(六级意图分类)
│
├─ 4. buildSystemPrompt(tier) ← prompt/prompt.go
│ ├─ 工具说明 + 安全规则
│ ├─ 技能索引 <available_skills>
│ ├─ 沙箱信息
│ ├─ 委托合约段(子智能体)
│ ├─ 太虚永忆记忆简报(L0 ~200 tokens)
│ └─ IntentGuidance(意图行为指引,按 tier 动态注入)
│
├─ 5. trimHistoryByIntent() ← 按意图裁剪历史
├─ 6. filterToolsByIntent() ← 按意图过滤工具(3-全量)
│
├─ 太虚永忆压缩(超阈值时) ← uhms.CompressChatMessages()
│
├─ LLM 流式调用 ← llmclient/
│ └─ 处理各 Provider 差异(Anthropic/OpenAI/Gemini/Ollama 等)
│
├─ 工具循环(最多 30 轮) ← tool_executor.go
│ ├─ 工具分发 + 执行
│ ├─ 写操作检测(looksLikeBashWrite — NativeSandbox 路径)
│ ├─ 连续全拒绝保护(3 轮上限)
│ ├─ 三层死循环防护:
│ │ ├─ L1: 同工具连续熔断(连续 5 次 → 终止 + 警告)
│ │ ├─ L2: per-tool 失败计数(累计 3 次 → 注入可操作修复指导,isToolSoftError 检测软错误)
│ │ └─ L3: 全局失败预算(净失败数 ≥ 8 → 终止循环,成功 -1 / 失败 +1 / 下限 0)
│ └─ 结果注入消息流
│
└─ 太虚永忆提交 ← uhms.CommitChatSession()4.2 System Prompt 结构
[System_Context] ← 状态机(COLD/WARM/NORMAL)+ 时间 + Boot Brief
[身份行] ← Crab Claw品牌 + 能力简述
[交互路由] ← Protocol A/B/C 状态机路由
[运行准则] ← 语言/行动/诚信/客观/范围/Emoji 规则
[任务执行] ← 阻塞条件 + 推断优先 + 不问许可式问题
[工具说明段] ← 可用工具列表 + 调用格式规范
[工具调用风格] ← 静默调用 + 叙述场景
[委派指引段] ← spawn_coder_agent 结果处理协议(仅 spawn_coder_agent 可用时注入)
[三级指挥段] ← 站长角色 + 流程 + 规则(仅 PlanConfirmationEnabled 时注入)
[安全规则段] ← exec approval / escalation 引导
[技能段] ← <available_skills> 索引(按需 lookup_skill)
[记忆段] ← 太虚永忆 L0 简报 + 相关记忆片段
[工作区段] ← workspace 路径 + 沙箱状态
[渠道段] ← 渠道特定指令(飞书/Discord/Telegram 等)
[意图行为指引段] ← IntentGuidance(按 classifyIntent 结果动态注入)
[Context Files] ← SOUL.md + 用户注入文件
[自定义追加] ← agents.defaults.systemPrompt 用户配置[System_Context] ← 状态机(COLD/WARM/NORMAL)+ 时间 + Boot Brief
[身份行] ← Crab Claw品牌 + 能力简述
[交互路由] ← Protocol A/B/C 状态机路由
[运行准则] ← 语言/行动/诚信/客观/范围/Emoji 规则
[任务执行] ← 阻塞条件 + 推断优先 + 不问许可式问题
[工具说明段] ← 可用工具列表 + 调用格式规范
[工具调用风格] ← 静默调用 + 叙述场景
[委派指引段] ← spawn_coder_agent 结果处理协议(仅 spawn_coder_agent 可用时注入)
[三级指挥段] ← 站长角色 + 流程 + 规则(仅 PlanConfirmationEnabled 时注入)
[安全规则段] ← exec approval / escalation 引导
[技能段] ← <available_skills> 索引(按需 lookup_skill)
[记忆段] ← 太虚永忆 L0 简报 + 相关记忆片段
[工作区段] ← workspace 路径 + 沙箱状态
[渠道段] ← 渠道特定指令(飞书/Discord/Telegram 等)
[意图行为指引段] ← IntentGuidance(按 classifyIntent 结果动态注入)
[Context Files] ← SOUL.md + 用户注入文件
[自定义追加] ← agents.defaults.systemPrompt 用户配置三级指挥段注入条件:PlanConfirmationEnabled=true(Gateway 注入 PlanConfirmationManager 时激活)。
内容由 buildPlanGenerationSection() 构建,描述站长(主智能体)管理 Open Coder + 灵瞳的流程。
三级门控链路(task_write 完整路径):
用户输入 → classifyIntent(task_write) → needsPlanConfirmation(true)
→ PlanConfirmation.RequestPlanConfirmation() [阻塞, 独立 context]
→ approve → LLM tool calls → spawn_coder_agent / spawn_argus_agent
→ SpawnSubagent() → 子智能体执行 → outcome
→ ReviewSubagentResult() [规则预检 + 可选 LLM 审核]
→ 通过 → ResultApprovalMgr.RequestResultApproval() [阻塞, 独立 context]
→ approve → contract.Status=Completed → formatSpawnResult() → 返回主智能体用户输入 → classifyIntent(task_write) → needsPlanConfirmation(true)
→ PlanConfirmation.RequestPlanConfirmation() [阻塞, 独立 context]
→ approve → LLM tool calls → spawn_coder_agent / spawn_argus_agent
→ SpawnSubagent() → 子智能体执行 → outcome
→ ReviewSubagentResult() [规则预检 + 可选 LLM 审核]
→ 通过 → ResultApprovalMgr.RequestResultApproval() [阻塞, 独立 context]
→ approve → contract.Status=Completed → formatSpawnResult() → 返回主智能体门控管理器(61 测试覆盖):
| 门控 | 管理器 | 超时策略 | 关键文件 |
|---|---|---|---|
| 方案确认 | PlanConfirmationManager | 超时→拒绝(fail-safe) | plan_confirmation.go |
| 质量审核 | ReviewSubagentResult() | 无超时(同步规则检查) | quality_review.go |
| 最终交付 | ResultApprovalManager | 超时→批准(已完成结果不丢弃) | result_approval.go |
| 异步通道 | AgentChannel | 双向 buffered(10), TOCTOU 防护 | agent_channel.go |
意图行为指引:intentGuidanceText(tier) 按意图分级动态生成,task_write 使用条件边界
(单文件 <50 行直接做 vs 多文件委派),避免 Claude 4.6 的过度委派倾向。
4.3 五维联动意图路由
核心文件:intent_router.go(381 行)
六级意图分类(优先级从高到低):
| 层级 | 工具数 | 历史裁剪 | 典型触发 |
|---|---|---|---|
| greeting | 0 | 不加载 | "你好"、"hi" (≤10 字符) |
| question | 5 | 最近 4 条 | 疑问标记 + 无祈使前缀 |
| task_light | 12 | 全量 | 默认 fallback |
| task_write | 15+ | 全量 | "创建"/"写"/"发送" 等 |
| task_delete | 5 | 全量 | "删除"/"清理"/"rm" 等 |
| task_multimodal | 全部 | 全量 | "截屏"/"浏览器"/"argus" |
五维联动关系:
意图分类 (classifyIntent)
├──▶ 工具树 (filterToolsByIntent) — 按 tier 过滤可用工具
├──▶ 技能树 (tierToolAllowlist) — 静态工具-技能绑定白名单
├──▶ 安全层 (command_rule_presets) — rm→ask, find~→deny 规则叠加
├──▶ 提示词 (intentGuidanceText) — 按 tier 注入行为指引
└──▶ 历史 (trimHistoryByIntent) — 按 tier 裁剪消息量意图分类 (classifyIntent)
├──▶ 工具树 (filterToolsByIntent) — 按 tier 过滤可用工具
├──▶ 技能树 (tierToolAllowlist) — 静态工具-技能绑定白名单
├──▶ 安全层 (command_rule_presets) — rm→ask, find~→deny 规则叠加
├──▶ 提示词 (intentGuidanceText) — 按 tier 注入行为指引
└──▶ 历史 (trimHistoryByIntent) — 按 tier 裁剪消息量关键设计:
isInterrogative() + !hasImperativePrefix()区分"谈论任务" vs "下达任务"- Stage 1 纯规则路由(零 LLM 成本,<1ms),Stage 2 LLM 分类预留接口
needsPlanConfirmation(tier): task_write/task_delete/task_multimodal 触发三级指挥方案确认门控- task_write 行为指引使用条件边界(非通用偏好):单文件 <50 行直接执行,多文件委派 Open Coder
4.4 工具执行层
tool_executor.go 统一分发所有工具调用:
| 分类 | 工具 | 实现 |
|---|---|---|
| 文件系统 | read / write / list_dir / glob / search | 本地 Go |
| Shell | bash | 沙箱执行(原生 or Docker) |
| 记忆 | memory_search / memory_get | 太虚永忆 VFS |
| 技能 | lookup_skill / search_skills | SkillsCache + VFS |
| 网络 | web_fetch / web_search | guarded_fetch + 搜索 API |
| 媒体 | send_media | ChannelMgr 适配器(file_path 优先 / target 默认当前频道 / MIME 自动检测 / 30MB 限制) |
| 浏览器 | browser(14 种 action) | CDP 直连(PlaywrightBrowserController),三层控制模型:CSS 选择器 / ARIA ref / AI Browse。详见 架构-浏览器自动化.md |
| 会话 | sessions_list / sessions_send / sessions_spawn | SessionManager |
| 视觉 | argus_* | Argus Bridge IPC(子智能体内部工具) |
| 远程 MCP | remote_* | RemoteMCPBridge IPC |
| 子智能体 | spawn_coder_agent / spawn_argus_agent | 委托合约 + SpawnSubagentFunc + 三级门控 |
| 其他 | canvas / cron / tts / image / nodes / message / gateway | 各子系统 |
4.5 聊天附件持久化(chat attachment persistence)
详细架构:
arch-chat-attachment-persistence.md
chat.send 支持 4 类型附件(image/video/audio/document)的端到端持久化:
前端 {text, attachments[]}
→ processAttachmentsForChat() # 4 类型处理 + STT/DocConv 文本增强
→ MsgContext.Attachments # []session.ContentBlock
→ FollowupRun → AttemptParams # 管线穿透(7 个接线点)
→ RunAttempt:
├─ image 附件 → LLM 多模态 ContentBlock 注入
└─ defer persistToTranscript → JSONL(text + 附件 blocks)前端 {text, attachments[]}
→ processAttachmentsForChat() # 4 类型处理 + STT/DocConv 文本增强
→ MsgContext.Attachments # []session.ContentBlock
→ FollowupRun → AttemptParams # 管线穿透(7 个接线点)
→ RunAttempt:
├─ image 附件 → LLM 多模态 ContentBlock 注入
└─ defer persistToTranscript → JSONL(text + 附件 blocks)数据模型: session.ContentBlock(Type/Text/Source/FileName/FileSize/MimeType),session.MediaSource(base64 媒体数据)。
双层空消息防护: handleChatSend 占位 [用户发送了附件] + get_reply_run 附件检查。
双层去重: persistToTranscript 检查文本匹配 + ensureUserTranscriptOnError 检查 role 匹配。
五、原生 Rust 沙箱(oa-sandbox)
5.1 架构概览
cli-rust/crates/oa-sandbox/
├── lib.rs ← 公开接口
├── config.rs ← SandboxConfig(安全级别/网络/文件权限)
├── output.rs ← SandboxOutput(stdout/stderr/exitCode/timeout)
├── platform.rs ← 平台 Runner 分发
├── error.rs ← 错误类型
├── macos/
│ ├── ffi.rs ← sandbox_init() FFI 绑定
│ └── seatbelt.rs ← Apple Seatbelt SBPL profile 生成 + 执行
├── linux/
│ ├── landlock.rs ← Landlock LSM 文件访问控制
│ ├── seccomp.rs ← Seccomp-BPF 系统调用过滤
│ ├── namespace.rs ← User/Network/Mount namespace 隔离
│ └── cgroup.rs ← Cgroup v2 资源限制
├── windows/
│ ├── job.rs ← Job Object(进程组限制)
│ ├── token.rs ← Token 权限降级
│ ├── acl.rs ← ACL 文件权限
│ └── appcontainer.rs ← AppContainer 低完整性沙箱
├── docker/ ← Docker Fallback Runner
└── worker/ ← 持久化 Worker(JSON-Lines 协议)
├── mod.rs ← Worker 事件循环
├── protocol.rs ← JSON-Lines IPC 协议定义
├── handle.rs ← Worker 进程 Handle(SIGKILL on Drop)
└── launcher.rs ← Worker 启动器cli-rust/crates/oa-sandbox/
├── lib.rs ← 公开接口
├── config.rs ← SandboxConfig(安全级别/网络/文件权限)
├── output.rs ← SandboxOutput(stdout/stderr/exitCode/timeout)
├── platform.rs ← 平台 Runner 分发
├── error.rs ← 错误类型
├── macos/
│ ├── ffi.rs ← sandbox_init() FFI 绑定
│ └── seatbelt.rs ← Apple Seatbelt SBPL profile 生成 + 执行
├── linux/
│ ├── landlock.rs ← Landlock LSM 文件访问控制
│ ├── seccomp.rs ← Seccomp-BPF 系统调用过滤
│ ├── namespace.rs ← User/Network/Mount namespace 隔离
│ └── cgroup.rs ← Cgroup v2 资源限制
├── windows/
│ ├── job.rs ← Job Object(进程组限制)
│ ├── token.rs ← Token 权限降级
│ ├── acl.rs ← ACL 文件权限
│ └── appcontainer.rs ← AppContainer 低完整性沙箱
├── docker/ ← Docker Fallback Runner
└── worker/ ← 持久化 Worker(JSON-Lines 协议)
├── mod.rs ← Worker 事件循环
├── protocol.rs ← JSON-Lines IPC 协议定义
├── handle.rs ← Worker 进程 Handle(SIGKILL on Drop)
└── launcher.rs ← Worker 启动器5.2 安全级别(四级模型)
| 级别 | CLI 值 | 沙箱 | 网络 | 文件系统 | 触发方式 |
|---|---|---|---|---|---|
| L0 | deny | ✅ | ❌ 无 | 只读 | 配置 / 合约约束 |
| L1 | allowlist | ✅ | ⚠️ 受限(公网 TCP+DNS) | 工作区读写 | 默认 |
| L2 | sandboxed | ✅ | ✅ 全网络 | 工作区 + 按任务临时挂载(MountRequests) | 仅 mount_access 审批(task-scoped) |
| L3 | full | ❌ 裸机 | ✅ 全网络 | 全权限 | 向导/配置永久授权,零审批 |
Rust 枚举 ↔ Go 映射(config.rs L14-30):
| Rust 枚举 | serde 主名 | serde alias | Go 字符串 |
|---|---|---|---|
L0Deny | "deny" | — | "deny" |
L1Allowlist | "allowlist" | "sandbox" | "allowlist" |
L2Sandboxed | "sandboxed" | "full" | "sandboxed" |
Rust Worker CLI 仍兼容旧 alias:
sandbox -> L1、full -> L2。 Go 控制面以NormalizeExecSecurityValue()为权威归一化:sandbox/sandboxed -> L2、full -> L3。 L3 不进入 Rust 沙箱(Go 侧SandboxMode=false,直接 spawn),无对应枚举值。
5.3 各平台隔离机制
macOS(Seatbelt):
- 调用
sandbox_init()FFI,传入动态生成的 SBPL profile - Profile 允许指定 workspace 路径读写 + 系统只读路径
- 启动延迟 ~65ms(持久化 Worker 模式下仅首次)
- 限制:SBPL 不支持 CIDR 网络规则
Linux(Landlock + Seccomp):
- Landlock:文件系统访问控制(LSM,内核 5.13+)
- Seccomp-BPF:系统调用白名单过滤
- User Namespace + Network Namespace:用户和网络隔离
- Cgroup v2:内存/CPU 配额
Windows(Job Object + AppContainer):
- Job Object:进程组资源限制和终止传播
- Token 降级:移除高权限特权
- AppContainer:低完整性等级 + ACL 文件权限
- CREATE_SUSPENDED 模式创建进程后注入沙箱
Docker Fallback:
docker run --rm+ security hardening--network=none(NoNetwork 约束时)- 启动延迟 ~215ms
5.4 持久化 Worker 与 NativeSandboxRouter
Go Gateway ──JSON-Lines──▶ Rust Worker 进程
├── 事件循环(状态机)
├── 健康心跳监控(30s 间隔 ping)
└── 崩溃自动恢复(exponential backoff, 最多 5 次)
Go 侧(sandbox/native_bridge.go,~700 行):
├── NativeSandboxBridge: 状态机 Init → Starting → Ready → Degraded → Stopped
├── readLocked 同步(F-01 修复)
├── read_line_limited 防 OOM(F-07 修复)
└── try_wait 轮询超时(非 SIGKILL 竞争)Go Gateway ──JSON-Lines──▶ Rust Worker 进程
├── 事件循环(状态机)
├── 健康心跳监控(30s 间隔 ping)
└── 崩溃自动恢复(exponential backoff, 最多 5 次)
Go 侧(sandbox/native_bridge.go,~700 行):
├── NativeSandboxBridge: 状态机 Init → Starting → Ready → Degraded → Stopped
├── readLocked 同步(F-01 修复)
├── read_line_limited 防 OOM(F-07 修复)
└── try_wait 轮询超时(非 SIGKILL 竞争)协议:每次命令一个 JSON-Lines 请求/响应,Worker 常驻避免重复启动沙箱开销。
NativeSandboxRouter(native_bridge.go L565-610)— 按安全级别路由:
NativeSandboxRouter.ExecuteSandboxed(securityLevel)
├── L1 (allowlist) → 持久 Worker IPC(l1Bridge.Execute,<1ms)
├── L2 (sandboxed) → 一次性 `sandbox run` CLI(executeOneShot,~50ms)
│ 支持 --mount host:sandbox:mode(临时挂载)
└── L3 (full) → 不经过此路由(SandboxMode=false,上层直接 spawn)NativeSandboxRouter.ExecuteSandboxed(securityLevel)
├── L1 (allowlist) → 持久 Worker IPC(l1Bridge.Execute,<1ms)
├── L2 (sandboxed) → 一次性 `sandbox run` CLI(executeOneShot,~50ms)
│ 支持 --mount host:sandbox:mode(临时挂载)
└── L3 (full) → 不经过此路由(SandboxMode=false,上层直接 spawn)设计理由:持久 Worker 的 Seatbelt/Landlock 策略在启动时固定,无法运行时变更。L2 的工作区外挂载改为任务级临时授权,一次性执行更容易与当前 run 生命周期绑定并在任务结束后自动回收。
Worker 自沙箱化(worker_cmd.rs L58-80)— 双路径设计:
Launcher 路径(Rust launcher.rs):
└── pre_exec 沙箱(Seatbelt/Landlock)→ 设 OA_SANDBOX_APPLIED=1
Go bridge 路径(Go 直接 spawn worker-start):
└── Worker 检测无 OA_SANDBOX_APPLIED → apply_sandbox_to_self()
(不可逆,子进程自动继承沙箱约束)Launcher 路径(Rust launcher.rs):
└── pre_exec 沙箱(Seatbelt/Landlock)→ 设 OA_SANDBOX_APPLIED=1
Go bridge 路径(Go 直接 spawn worker-start):
└── Worker 检测无 OA_SANDBOX_APPLIED → apply_sandbox_to_self()
(不可逆,子进程自动继承沙箱约束)六、oa-coder 编程子智能体
6.1 架构
cli-rust/crates/oa-coder/(2,394 LOC)
└── Rust MCP Server(JSON-RPC 2.0 via stdio)
├── edit — 9 层模糊匹配算法(精确→归一化→Levenshtein→...)
├── read — 文件读取(二进制前 8192 字节检测)
├── write — 原子写入(tempfile + rename)
├── grep — ripgrep 封装,MAX_LEVENSHTEIN_INPUT=10,000 防 DoS
├── glob — globset 文件模式匹配
└── bash — 调用 oa-sandbox 隔离执行
cli-rust/crates/oa-cmd-coder/(44 LOC)
└── CLI 入口(oa-coder 二进制)cli-rust/crates/oa-coder/(2,394 LOC)
└── Rust MCP Server(JSON-RPC 2.0 via stdio)
├── edit — 9 层模糊匹配算法(精确→归一化→Levenshtein→...)
├── read — 文件读取(二进制前 8192 字节检测)
├── write — 原子写入(tempfile + rename)
├── grep — ripgrep 封装,MAX_LEVENSHTEIN_INPUT=10,000 防 DoS
├── glob — globset 文件模式匹配
└── bash — 调用 oa-sandbox 隔离执行
cli-rust/crates/oa-cmd-coder/(44 LOC)
└── CLI 入口(oa-coder 二进制)6.2 调用流程(Phase 2A 后)
用户请求代码任务
↓
Agent 调用 spawn_coder_agent 工具
↓ (spawn_coder_agent.go)
创建 DelegationContract(scope/constraints/timeout)
↓ 合约写入 VFS active/(contract_persistence.go)
↓ (SpawnSubagentFunc 回调)
启动独立 LLM Session(RunEmbeddedPiAgent)
↓
子 Agent 获得委托合约约束的工具集(oa-coder 6 工具)
↓ 合约审批路由: 低风险自动放行,高风险询问用户(ApprovalRouter)
↓
执行代码任务 → ThoughtResult 返回父 Agent
↓ (subagent_announce.go:209-247)
解析 ThoughtResult + 状态广播
↓ 合约状态转换: completed/ | suspended/ | failed/用户请求代码任务
↓
Agent 调用 spawn_coder_agent 工具
↓ (spawn_coder_agent.go)
创建 DelegationContract(scope/constraints/timeout)
↓ 合约写入 VFS active/(contract_persistence.go)
↓ (SpawnSubagentFunc 回调)
启动独立 LLM Session(RunEmbeddedPiAgent)
↓
子 Agent 获得委托合约约束的工具集(oa-coder 6 工具)
↓ 合约审批路由: 低风险自动放行,高风险询问用户(ApprovalRouter)
↓
执行代码任务 → ThoughtResult 返回父 Agent
↓ (subagent_announce.go:209-247)
解析 ThoughtResult + 状态广播
↓ 合约状态转换: completed/ | suspended/ | failed/协商循环(needs_auth → 重新委托):
spawn_coder_agent → 子 Agent 返回 needs_auth
↓
合约转入 VFS suspended/(保存 ThoughtResult 到 l2)
↓
主 Agent 收到结构化可操作指引(scope 扩展/约束放宽/parent_contract 提示)
↓ prompt 委托引导段(buildDelegationGuidanceSection)
↓ LOW 风险: 直接重新委托 | HIGH 风险: 询问用户
二次 spawn_coder_agent(parent_contract="{uuid}")
↓ 加载父合约 ThoughtResult → 恢复上下文注入子 Agent 系统提示
↓
子 Agent 续接任务(不重做已完成工作)
↓
硬上限: 最多 3 轮协商(iterationIndex > 3 → 拒绝 spawn,升级到用户)spawn_coder_agent → 子 Agent 返回 needs_auth
↓
合约转入 VFS suspended/(保存 ThoughtResult 到 l2)
↓
主 Agent 收到结构化可操作指引(scope 扩展/约束放宽/parent_contract 提示)
↓ prompt 委托引导段(buildDelegationGuidanceSection)
↓ LOW 风险: 直接重新委托 | HIGH 风险: 询问用户
二次 spawn_coder_agent(parent_contract="{uuid}")
↓ 加载父合约 ThoughtResult → 恢复上下文注入子 Agent 系统提示
↓
子 Agent 续接任务(不重做已完成工作)
↓
硬上限: 最多 3 轮协商(iterationIndex > 3 → 拒绝 spawn,升级到用户)关键特性:
- 子 Agent 权限 ≤ 父 Agent(单调衰减)
- oa-coder 的 bash 工具通过 oa-sandbox 隔离
- 资源预算守恒:
child_budget ≤ parent_remaining(ResourceBudget, atomic 计数) - 合约 VFS 持久化:
_system/contracts/{status}/{contractID}/(l0=摘要, l1=合约 JSON, l2=ThoughtResult) - TTL 自动清理: 已完成合约 >24h 删除(1h/次 goroutine, 可取消)
- edit 工具 9 层模糊匹配确保高成功率:
- 精确匹配 → 2. 首尾空白归一化 → 3. 全空白归一化 → 4. 行级 diff → 5. Levenshtein → 6-9. 渐进宽松策略
6.3 独立 Provider/Model 配置
Open Coder 支持独立于主 agent 的 LLM 配置(provider/apiKey/model/baseURL 四件套):
配置类型: types.OpenCoderSettings(pkg/types/types_crabclaw.go)
存储路径: subAgents.openCoder.*(crabclaw.json)
三级 fallback(resolveOpenCoderConfig, server.go):
Level 1: subAgents.openCoder.* 显式配置(最高优先级)
Level 2: agents.defaults.model.primary(主 agent 配置)
Level 3: 硬编码 anthropic / claude-sonnet-4(默认值)
API Key 注入: SpawnSubagent 回调浅拷贝 Config → 覆盖目标 provider 配置
配置向导: wizard_open_coder.go(3 步: Provider → API Key/BaseURL → Model)
前端入口: SubAgents tab → open-coder 卡片 → "配置 open-coder" 按钮 → wizard overlay配置类型: types.OpenCoderSettings(pkg/types/types_crabclaw.go)
存储路径: subAgents.openCoder.*(crabclaw.json)
三级 fallback(resolveOpenCoderConfig, server.go):
Level 1: subAgents.openCoder.* 显式配置(最高优先级)
Level 2: agents.defaults.model.primary(主 agent 配置)
Level 3: 硬编码 anthropic / claude-sonnet-4(默认值)
API Key 注入: SpawnSubagent 回调浅拷贝 Config → 覆盖目标 provider 配置
配置向导: wizard_open_coder.go(3 步: Provider → API Key/BaseURL → Model)
前端入口: SubAgents tab → open-coder 卡片 → "配置 open-coder" 按钮 → wizard overlay七、太虚永忆(Unified Hierarchical Memory System)
详细架构参见:docs/claude/goujia/arch-uhms-memory-system.md
7.1 系统定位
太虚永忆解决长对话 token 爆炸和跨会话记忆两大核心问题:
backend/internal/memory/uhms/
├── manager.go ← DefaultManager(压缩/存储/检索/VFS 编排,~1100 LOC)
├── config.go ← UHMSConfig(向量模式/VFS路径/压缩阈值)
├── compression_prompts.go ← 13 个压缩 prompt 常量
├── claude_integration.go ← Anthropic Compaction API + Provider 感知
├── session_committer.go ← 会话提交管线
├── store.go ← SQLite + FTS5 持久化
├── vfs.go ← L0/L1/L2 三级 VFS 文件系统
├── cache.go ← LRU 内存缓存
├── dedup.go ← FTS5 去重
├── decay.go ← FSRS-6 记忆衰减算法
└── interfaces.go ← LLMProvider / VectorIndex / EmbeddingProvider 接口backend/internal/memory/uhms/
├── manager.go ← DefaultManager(压缩/存储/检索/VFS 编排,~1100 LOC)
├── config.go ← UHMSConfig(向量模式/VFS路径/压缩阈值)
├── compression_prompts.go ← 13 个压缩 prompt 常量
├── claude_integration.go ← Anthropic Compaction API + Provider 感知
├── session_committer.go ← 会话提交管线
├── store.go ← SQLite + FTS5 持久化
├── vfs.go ← L0/L1/L2 三级 VFS 文件系统
├── cache.go ← LRU 内存缓存
├── dedup.go ← FTS5 去重
├── decay.go ← FSRS-6 记忆衰减算法
└── interfaces.go ← LLMProvider / VectorIndex / EmbeddingProvider 接口7.2 压缩管线
消息流入(超 token 阈值)
↓
Observation Masking(遮蔽旧 tool_result,减少噪音)
↓
分割:旧消息段 | 保留最近 N 条
↓
Anchored Iterative Summary(锚定关键节点迭代摘要)
↓
摘要注入回消息流(替换旧消息段)
↓
压缩率:60-80% token 节省消息流入(超 token 阈值)
↓
Observation Masking(遮蔽旧 tool_result,减少噪音)
↓
分割:旧消息段 | 保留最近 N 条
↓
Anchored Iterative Summary(锚定关键节点迭代摘要)
↓
摘要注入回消息流(替换旧消息段)
↓
压缩率:60-80% token 节省7.3 VFS 三级存储
| 级别 | 容量 | 内容 | 用途 |
|---|---|---|---|
| L0 | ~100 tokens | 名称 + 描述 + tags | 系统 prompt 索引 |
| L1 | ~2K tokens | 完整信息概览 | 快速查询 |
| L2 | 无限制 | 完整原文 | 深度查询 |
技能分发(DistributeSkills)也写入此 VFS:_system/skills/{category}/{name}/
7.4 向量检索
backend/internal/memory/
├── vectoradapter/(~760 LOC,CGO FFI + 纯 Go fallback)
├── embeddings_*.go ← OpenAI / Gemini / Voyage / 本地嵌入
└── hybrid.go ← 混合检索(FTS5 + 向量)
向量后端:Qdrant(生产)/ sqlite-vec(嵌入式)/ builtin(纯 Go)/ 混合backend/internal/memory/
├── vectoradapter/(~760 LOC,CGO FFI + 纯 Go fallback)
├── embeddings_*.go ← OpenAI / Gemini / Voyage / 本地嵌入
└── hybrid.go ← 混合检索(FTS5 + 向量)
向量后端:Qdrant(生产)/ sqlite-vec(嵌入式)/ builtin(纯 Go)/ 混合八、委托合约系统(Delegation Contract)
基于 DeepMind arXiv:2602.11865 实现能力单调衰减 + Agent Contracts (arXiv:2601.08815) 资源预算守恒。
8.1 核心数据结构
// delegation_contract.go
DelegationContract {
ContractID string // UUID
ParentContract string // 父合约 ID(协商链追踪)
AgentID string // 子 Agent 标识
Status ContractStatus // pending/active/suspended/completed/failed/cancelled
TaskBrief string // 任务摘要
Scope ContractScope // 允许操作的路径/工具白名单
Constraints ContractConstraints {
SandboxRequired bool // 强制沙箱
NoNetwork bool // 禁止网络(→ Docker --network=none)
NoSpawn bool // 禁止再次生成子智能体
MaxDepth int // 委托链最大深度
AllowedCommands []string // bash 白名单(审批路由用)
}
Budget *ResourceBudget // 资源预算(可选)
TimeoutMs int64 // 合约超时(ms)
IssuedAt time.Time
}
ResourceBudget {
MaxBashCalls uint32 // bash 调用上限
UsedBashCalls uint32 // 已使用(atomic 递增)
MaxTimeMs uint64 // 时间预算(ms)
UsedTimeMs uint64 // 已用时间(atomic 读取)
}
CapabilitySet {
AllowWrite bool
AllowExec bool
AllowNetwork bool
MaxSecurityLevel string // "deny" < "allowlist" < "sandboxed"
ScopePaths []string
}// delegation_contract.go
DelegationContract {
ContractID string // UUID
ParentContract string // 父合约 ID(协商链追踪)
AgentID string // 子 Agent 标识
Status ContractStatus // pending/active/suspended/completed/failed/cancelled
TaskBrief string // 任务摘要
Scope ContractScope // 允许操作的路径/工具白名单
Constraints ContractConstraints {
SandboxRequired bool // 强制沙箱
NoNetwork bool // 禁止网络(→ Docker --network=none)
NoSpawn bool // 禁止再次生成子智能体
MaxDepth int // 委托链最大深度
AllowedCommands []string // bash 白名单(审批路由用)
}
Budget *ResourceBudget // 资源预算(可选)
TimeoutMs int64 // 合约超时(ms)
IssuedAt time.Time
}
ResourceBudget {
MaxBashCalls uint32 // bash 调用上限
UsedBashCalls uint32 // 已使用(atomic 递增)
MaxTimeMs uint64 // 时间预算(ms)
UsedTimeMs uint64 // 已用时间(atomic 读取)
}
CapabilitySet {
AllowWrite bool
AllowExec bool
AllowNetwork bool
MaxSecurityLevel string // "deny" < "allowlist" < "sandboxed"
ScopePaths []string
}8.2 权限单调衰减验证
父 Agent CapabilitySet
↓ ValidateMonotonicDecay()(5 维检查: write/exec/network/security/scope)
子 Agent CapabilitySet(只能 ≤ 父级)
违规示例:
parent.AllowNetwork=false → child.AllowNetwork=true → VIOLATION
parent.MaxLevel="allowlist" → child.MaxLevel="sandboxed" → VIOLATION
parent.ScopePaths=[src/] → child.ScopePaths=[] (全局) → VIOLATION父 Agent CapabilitySet
↓ ValidateMonotonicDecay()(5 维检查: write/exec/network/security/scope)
子 Agent CapabilitySet(只能 ≤ 父级)
违规示例:
parent.AllowNetwork=false → child.AllowNetwork=true → VIOLATION
parent.MaxLevel="allowlist" → child.MaxLevel="sandboxed" → VIOLATION
parent.ScopePaths=[src/] → child.ScopePaths=[] (全局) → VIOLATION8.3 NoNetwork 强制链路
合约 NoNetwork=true
↓ deriveMaxSecurityLevel()
→ securityLevel="allowlist"(宿主机模式无法网络隔离,强制降级)
↓ ApplyConstraints()(delegation_contract.go L448-454)
→ params.AllowNetwork=false
→ params.BrowserController=nil(禁用 browser 工具)
→ params.MediaSender=nil(禁用 send_media 工具)
→ params.MountRequests=nil(受限合约不应扩展文件系统)
↓ executeBashNativeSandbox() / executeBashSandboxed()
→ SandboxExecOptions.SecurityLevel="allowlist" → NativeSandboxRouter → L1 Worker IPC
→ cfg.NetworkEnabled=false(Docker 路径)
↓ DockerRunner.buildDockerArgs()(Docker fallback)
→ docker run --network=none ✅合约 NoNetwork=true
↓ deriveMaxSecurityLevel()
→ securityLevel="allowlist"(宿主机模式无法网络隔离,强制降级)
↓ ApplyConstraints()(delegation_contract.go L448-454)
→ params.AllowNetwork=false
→ params.BrowserController=nil(禁用 browser 工具)
→ params.MediaSender=nil(禁用 send_media 工具)
→ params.MountRequests=nil(受限合约不应扩展文件系统)
↓ executeBashNativeSandbox() / executeBashSandboxed()
→ SandboxExecOptions.SecurityLevel="allowlist" → NativeSandboxRouter → L1 Worker IPC
→ cfg.NetworkEnabled=false(Docker 路径)
↓ DockerRunner.buildDockerArgs()(Docker fallback)
→ docker run --network=none ✅8.4 合约 VFS 持久化(Phase 5)
VFS 路径: _system/contracts/{status}/{contractID}/
l0 = 任务摘要(≤80字符,搜索索引)
l1 = 合约 JSON(DelegationContract 完整序列化)
l2 = ThoughtResult JSON(挂起时保存,恢复时读取)
meta = {status, issuedBy, issuedAt, parentContract, updatedAt}
ContractPersistence 接口(runner 包,解耦 VFS 实现):
SaveContract / LoadContract / TransitionStatus / ListContracts / CleanupCompleted
VFSContractPersistence 适配器(gateway 包):
基于 uhms.LocalVFS 的 WriteSystemEntry/ReadSystemL1/DeleteSystemEntry
状态机(合法转换):
pending → active
active → suspended / completed / failed
suspended → active / cancelled
(其他转换均非法)
TTL 清理: 每小时自动清理 >24h 的 completed 合约
可取消 goroutine(contractCleanupDone channel → Close() 时关闭)
RPC 查询: contract.list / contract.get / contract.audit(server_methods_contracts.go)VFS 路径: _system/contracts/{status}/{contractID}/
l0 = 任务摘要(≤80字符,搜索索引)
l1 = 合约 JSON(DelegationContract 完整序列化)
l2 = ThoughtResult JSON(挂起时保存,恢复时读取)
meta = {status, issuedBy, issuedAt, parentContract, updatedAt}
ContractPersistence 接口(runner 包,解耦 VFS 实现):
SaveContract / LoadContract / TransitionStatus / ListContracts / CleanupCompleted
VFSContractPersistence 适配器(gateway 包):
基于 uhms.LocalVFS 的 WriteSystemEntry/ReadSystemL1/DeleteSystemEntry
状态机(合法转换):
pending → active
active → suspended / completed / failed
suspended → active / cancelled
(其他转换均非法)
TTL 清理: 每小时自动清理 >24h 的 completed 合约
可取消 goroutine(contractCleanupDone channel → Close() 时关闭)
RPC 查询: contract.list / contract.get / contract.audit(server_methods_contracts.go)8.5 协商循环(Phase 6)
子 Agent 返回 needs_auth → ThoughtResult 包含:
auth_request.reason 需要权限的原因
auth_request.risk_level 风险等级
auth_request.scope_needed 请求扩展的路径/工具
resume_hint 恢复提示(已完成的步骤)
iteration_count 当前迭代轮数
主 Agent 收到结构化指引 → prompt 委托引导段引导决策:
LOW 风险 → 直接重新委托(扩大 scope,设 parent_contract)
HIGH 风险 → 先询问用户
恢复流程:
二次 spawn_coder_agent(parent_contract=uuid)
→ LoadContract(uuid) 读取父合约 ThoughtResult
→ ResumeContext + IterationIndex 注入子 Agent 系统提示
→ 子 Agent 续接任务(不重做已完成工作)
硬上限: iterationIndex > 3 → 拒绝 spawn,升级到用户子 Agent 返回 needs_auth → ThoughtResult 包含:
auth_request.reason 需要权限的原因
auth_request.risk_level 风险等级
auth_request.scope_needed 请求扩展的路径/工具
resume_hint 恢复提示(已完成的步骤)
iteration_count 当前迭代轮数
主 Agent 收到结构化指引 → prompt 委托引导段引导决策:
LOW 风险 → 直接重新委托(扩大 scope,设 parent_contract)
HIGH 风险 → 先询问用户
恢复流程:
二次 spawn_coder_agent(parent_contract=uuid)
→ LoadContract(uuid) 读取父合约 ThoughtResult
→ ResumeContext + IterationIndex 注入子 Agent 系统提示
→ 子 Agent 续接任务(不重做已完成工作)
硬上限: iterationIndex > 3 → 拒绝 spawn,升级到用户8.6 集中审批路由(Phase 7)
ApprovalRouter: 规则评估(非 LLM 调用,零延迟)
合约存在时 → RequestConfirmation 前置路由
合约不存在时 → 退化到现有用户审批流程(向后兼容)
风险评估矩阵:
read/grep/glob/find/ls → auto_approved(只读操作)
edit 在 ScopePaths 内 → auto_approved
edit 在 ScopePaths 外 → ask_user
write → ask_user
bash 在 AllowedCommands 内 → auto_approved
bash 不在白名单 → ask_user
argus_* → 跳过(独立 actionRiskMap 审批)
命令白名单匹配(安全强化):
- 精确匹配或 "allowed " 前缀(要求词边界分隔)
- 预扫描拒绝 shell 操作符(&&, ||, ;, |, $(), `, \n)
- 防止 "git && rm -rf /" 绕过 "git" 白名单
审计链路:
每个审批决策记录 ApprovalAuditEntry(时间戳/工具/决策/原因/风险级别)
合约完成时 FlushAudit → VFS 或 contract.audit RPC 查询
线程安全:
RequestConfirmation 锁下快照 activeContract(防并发 ClearActiveContract 竞争)
SetActiveContract/ClearActiveContract 通过 mu 互斥ApprovalRouter: 规则评估(非 LLM 调用,零延迟)
合约存在时 → RequestConfirmation 前置路由
合约不存在时 → 退化到现有用户审批流程(向后兼容)
风险评估矩阵:
read/grep/glob/find/ls → auto_approved(只读操作)
edit 在 ScopePaths 内 → auto_approved
edit 在 ScopePaths 外 → ask_user
write → ask_user
bash 在 AllowedCommands 内 → auto_approved
bash 不在白名单 → ask_user
argus_* → 跳过(独立 actionRiskMap 审批)
命令白名单匹配(安全强化):
- 精确匹配或 "allowed " 前缀(要求词边界分隔)
- 预扫描拒绝 shell 操作符(&&, ||, ;, |, $(), `, \n)
- 防止 "git && rm -rf /" 绕过 "git" 白名单
审计链路:
每个审批决策记录 ApprovalAuditEntry(时间戳/工具/决策/原因/风险级别)
合约完成时 FlushAudit → VFS 或 contract.audit RPC 查询
线程安全:
RequestConfirmation 锁下快照 activeContract(防并发 ClearActiveContract 竞争)
SetActiveContract/ClearActiveContract 通过 mu 互斥8.7 资源预算守恒(Phase 8)
Agent Contracts 论文 (arXiv:2601.08815): child_budget ≤ parent_remaining
ResourceBudget:
MaxBashCalls / UsedBashCalls(atomic uint32)
MaxTimeMs / UsedTimeMs(atomic uint64)
IsExhausted() → (true, reason) 表示预算耗尽
执行守恒:
tool_executor.go bash handler → budget.IsExhausted() 检查
→ 耗尽: 返回 "[bash] Resource budget exhausted: {reason}"
→ 未耗尽: budget.IncrementBashCalls() 原子递增
RPC 仪表盘:
contract.list — 按状态过滤(白名单验证),limit 限制
contract.get — 完整合约 + ThoughtResult
contract.audit — 审批审计日志Agent Contracts 论文 (arXiv:2601.08815): child_budget ≤ parent_remaining
ResourceBudget:
MaxBashCalls / UsedBashCalls(atomic uint32)
MaxTimeMs / UsedTimeMs(atomic uint64)
IsExhausted() → (true, reason) 表示预算耗尽
执行守恒:
tool_executor.go bash handler → budget.IsExhausted() 检查
→ 耗尽: 返回 "[bash] Resource budget exhausted: {reason}"
→ 未耗尽: budget.IncrementBashCalls() 原子递增
RPC 仪表盘:
contract.list — 按状态过滤(白名单验证),limit 限制
contract.get — 完整合约 + ThoughtResult
contract.audit — 审批审计日志8.8 Escalation(权限升级系统)
L0:拒绝执行
L1:受限执行,按 allowlist / ask 规则决定是否需要确认
L2:沙箱内执行默认放行;仅工作区外挂载走 `mount_access` 审批,按任务自动回收
L3:永久授权,开启后不再进入审批链
持久化:pending EscalationRequest 落盘 → RestoreFromDisk(跨重启恢复)
前端:escalation-status-panel.ts + escalation-popup.ts + escalation-audit-log.ts
飞书卡片:审批请求以互动卡片形式推送,按钮点击触发 grant/deny RPCL0:拒绝执行
L1:受限执行,按 allowlist / ask 规则决定是否需要确认
L2:沙箱内执行默认放行;仅工作区外挂载走 `mount_access` 审批,按任务自动回收
L3:永久授权,开启后不再进入审批链
持久化:pending EscalationRequest 落盘 → RestoreFromDisk(跨重启恢复)
前端:escalation-status-panel.ts + escalation-popup.ts + escalation-audit-log.ts
飞书卡片:审批请求以互动卡片形式推送,按钮点击触发 grant/deny RPC九、渠道接入系统
9.1 渠道架构
backend/internal/channels/
├── registry.go ← 渠道插件注册表
├── channels.go ← 频道接口定义
└── {渠道}/
├── feishu/ ← 飞书(WebSocket 长连接)
├── dingtalk/ ← 钉钉
├── wecom/ ← 企业微信
├── discord/ ← Discord
├── telegram/ ← Telegram
├── slack/ ← Slack
├── whatsapp/ ← WhatsApp
├── signal/ ← Signal
├── imessage/ ← iMessage
└── line/ ← Linebackend/internal/channels/
├── registry.go ← 渠道插件注册表
├── channels.go ← 频道接口定义
└── {渠道}/
├── feishu/ ← 飞书(WebSocket 长连接)
├── dingtalk/ ← 钉钉
├── wecom/ ← 企业微信
├── discord/ ← Discord
├── telegram/ ← Telegram
├── slack/ ← Slack
├── whatsapp/ ← WhatsApp
├── signal/ ← Signal
├── imessage/ ← iMessage
└── line/ ← Line9.2 飞书渠道(深度集成)
backend/internal/channels/feishu/
├── client.go ← FeishuClient(larkws SDK 封装)
├── plugin.go ← 渠道插件实现 + 事件注册
└── sender.go ← 消息/卡片/图片发送封装backend/internal/channels/feishu/
├── client.go ← FeishuClient(larkws SDK 封装)
├── plugin.go ← 渠道插件实现 + 事件注册
└── sender.go ← 消息/卡片/图片发送封装连接模式:WebSocket 长连接(larkws.NewClient),无需公网 URL,防火墙内可用。
消息接收流:
larkws → OnP2MessageReceiveV1 → feishuDispatch → Agent.Run()
↘ 广播到其他渠道larkws → OnP2MessageReceiveV1 → feishuDispatch → Agent.Run()
↘ 广播到其他渠道卡片审批流(Escalation 提权):
EscalationMgr 生成审批请求
↓ broadcastCard(token, card, 去重后的 chat_id 集合优先;全部失败再回退 open_id)
发送互动卡片(含 Allow/Deny 按钮)
↓ 用户点击
OnP2CardActionTrigger(同一 WS 连接)
↓ 解析 card value = {action, id, ttl}
escalation.grant RPC → EscalationMgr.Grant()
↓ 广播 escalation.grant.created 事件EscalationMgr 生成审批请求
↓ broadcastCard(token, card, 去重后的 chat_id 集合优先;全部失败再回退 open_id)
发送互动卡片(含 Allow/Deny 按钮)
↓ 用户点击
OnP2CardActionTrigger(同一 WS 连接)
↓ 解析 card value = {action, id, ttl}
escalation.grant RPC → EscalationMgr.Grant()
↓ 广播 escalation.grant.created 事件卡片审批流(CoderConfirmation 操作确认):
CoderConfirmationManager 生成审批请求
↓ boot.go 回调获取 LastKnownUserID
↓ NotifyCoderConfirm(CoderConfirmCardRequest{OriginatorChatID, OriginatorUserID})
↓ SendCoderConfirmRequest → broadcastCard(token, card, 去重后的 chat_id 集合优先;全部失败再回退 open_id)
发送黄色操作确认卡片(含 批准/拒绝 按钮)
↓ 用户点击
OnP2CardActionTrigger → value.type="coder_confirm"
↓ coder.confirm.grant/deny RPCCoderConfirmationManager 生成审批请求
↓ boot.go 回调获取 LastKnownUserID
↓ NotifyCoderConfirm(CoderConfirmCardRequest{OriginatorChatID, OriginatorUserID})
↓ SendCoderConfirmRequest → broadcastCard(token, card, 去重后的 chat_id 集合优先;全部失败再回退 open_id)
发送黄色操作确认卡片(含 批准/拒绝 按钮)
↓ 用户点击
OnP2CardActionTrigger → value.type="coder_confirm"
↓ coder.confirm.grant/deny RPC会话隔离:feishu:<chatID> 每个聊天独立会话,跨会话事件通过 channel.message.incoming 广播。
9.3 渠道插件注册
Gateway 在 server.go 中按配置动态注册渠道插件:
// 示例:飞书注册流程
feishuPlugin := feishu.NewPlugin(cfg, state.Broadcaster())
state.ChannelMgr().Register("feishu", feishuPlugin)
feishuPlugin.Start(ctx) // 建立 WebSocket 长连接// 示例:飞书注册流程
feishuPlugin := feishu.NewPlugin(cfg, state.Broadcaster())
state.ChannelMgr().Register("feishu", feishuPlugin)
feishuPlugin.Start(ctx) // 建立 WebSocket 长连接9.4 智能体/任务独立频道
除了外部渠道(飞书/Discord 等),系统还为内部子智能体和任务执行提供独立频道:
| 频道类型 | Session Key 格式 | 创建时机 |
|---|---|---|
| 子智能体频道 | coder:{contractID} | spawn_coder_agent 触发时 |
| 任务频道 | task:{runID} | 首次工具调用时(懒创建),TaskStore 独立存储 |
复用 channel.message.incoming 广播机制,前端按 session key 前缀自动分组到"智能体"/"任务"频道标签。
工具事件增强: 频道中广播结构化工具事件([工具] name: args + [结果] result (Nms)),通过 OnToolEvent 回调从 attempt_runner.go 工具循环注入,经 DispatchInboundParams → GetReplyOptions(any) → pipelineDispatcher(type-assert) → ModelFallbackExecutor → RunEmbeddedPiAgentParams 透传链到达广播闭包。参数/结果均 rune-safe 截断(100/200 字符)。
详细架构: 架构-智能体任务频道.md
结构化任务看板事件: 除 channel.message.incoming 纯文本广播外,还并行广播 5 种 task.* 结构化事件(task.queued/started/progress/completed/failed),供前端看板 UI 消费。支持 async=true 异步任务队列,CAS 原子并发守卫(最多 5 个并发异步任务)。前端新增"任务看板"Tab(3 列:排队中/执行中/已完成)。
详细架构: 架构-主动消息看板.md
十、技能系统
10.1 三层架构
技能系统分为三个独立层次,各自职责明确:
| 层次 | 数据源 | 功能 | 控制方式 |
|---|---|---|---|
| 工具能力注册表 | capabilities/registry.go (30 条目) | 定义系统所有工具的元数据、分组、可绑定性 | 代码编译时确定 |
| 工具组权限门控 | scope/tool_policy.go (9 个 group) | 控制 AI 运行时可调用哪些工具 | Wizard V2 / 配置文件 |
| 技能文档注入 | docs/skills/ (62 份活跃 SKILL.md) | 注入工具使用知识到 system prompt | 启动时自动扫描加载 |
10.2 工具能力注册表(CapabilitySpec Registry)
internal/agents/capabilities/registry.go 是所有工具元数据的单一真相源(30 条目)。
type CapabilitySpec struct {
ID string // 唯一标识 "bash", "web_search"
Kind string // "tool" | "sub-agent-entry"
ToolName string // AI 调用时的工具名
ToolGroups []string // 所属组 ["group:runtime"]
RuntimeOwner string // "attempt_runner" | "gateway"
EnabledWhen string // 启用条件
PromptSummary string // prompt 中的一行描述
SkillBindable bool // 技能文档能否绑定此工具
}type CapabilitySpec struct {
ID string // 唯一标识 "bash", "web_search"
Kind string // "tool" | "sub-agent-entry"
ToolName string // AI 调用时的工具名
ToolGroups []string // 所属组 ["group:runtime"]
RuntimeOwner string // "attempt_runner" | "gateway"
EnabledWhen string // 启用条件
PromptSummary string // prompt 中的一行描述
SkillBindable bool // 技能文档能否绑定此工具
}关键函数:
LookupByToolName(name)— 按 ToolName 查找,技能绑定验证用ToolSummaries()— 返回 map[toolName]summary,prompt 构建用IsRegistered(toolName)— 快速检查工具是否存在
SkillBindable 规则: 只有 SkillBindable: true 的工具才能被 SKILL.md 的 tools: 字段绑定。
子智能体入口(spawn_coder_agent 等)和内部工具(report_progress 等)为 false。
10.3 工具组与 Wizard 映射
scope/tool_policy.go 定义 9 个工具组,Wizard V2 前端用复选框控制开关:
| 工具组 Key | 展开为 | Wizard 名称 |
|---|---|---|
group:fs | read_file, write_file, list_dir | 文件系统 |
group:runtime | bash | 命令执行 |
group:ui | browser, canvas | 浏览器与画布 |
group:web | web_search, web_fetch | 网页搜索 |
group:memory | memory_search, memory_get | 记忆调用 |
group:sessions | sessions_list, sessions_history, sessions_send, sessions_spawn, session_status | 会话管理 |
group:automation | cron, gateway | 自动化 |
group:messaging | message | 消息推送 |
group:nodes | nodes | 节点管理 |
数据流: 前端 selectedSkills → wizard.v2.apply → applySkillsConfig() → ToolsConfig.Allow: ["group:fs", ...] → 运行时 ExpandToolGroups() 展开为具体工具名。
10.4 技能文档加载流程
LoadSkillEntries()
1. {workspace}/.agent/skills/ ← Agent 专属(最高优先级)
2. bundledDir(二进制同级 skills/)← 生产包捆绑
3. extraDirs(config 配置) ← 额外目录
4. docs/skills/ 自动扫描 ← monorepo 开发环境主要来源
└── 扫描 tools/(47) / providers/(19) / general/(9) / official/(16) / media/(3)
deduplicateEntries() ← 同名技能保留首次加载者LoadSkillEntries()
1. {workspace}/.agent/skills/ ← Agent 专属(最高优先级)
2. bundledDir(二进制同级 skills/)← 生产包捆绑
3. extraDirs(config 配置) ← 额外目录
4. docs/skills/ 自动扫描 ← monorepo 开发环境主要来源
└── 扫描 tools/(47) / providers/(19) / general/(9) / official/(16) / media/(3)
deduplicateEntries() ← 同名技能保留首次加载者Frontmatter 解析: 使用 adrg/frontmatter 库(MIT,零外部依赖)解析 YAML frontmatter。
复杂值(嵌套对象/数组)序列化为 JSON 字符串存入 ParsedSkillFrontmatter(map[string]string)。
技能绑定验证门控(ResolveToolSkillBindings):
SKILL.md tools: web_search
↓ LookupByToolName("web_search")
↓ spec != nil && spec.SkillBindable == true → 绑定生效
↓ spec == nil → warn "unknown tool",跳过
↓ SkillBindable == false → warn "non-bindable",跳过SKILL.md tools: web_search
↓ LookupByToolName("web_search")
↓ spec != nil && spec.SkillBindable == true → 绑定生效
↓ spec == nil → warn "unknown tool",跳过
↓ SkillBindable == false → warn "non-bindable",跳过10.5 技能分发到 VFS(DistributeSkills)
技能条目(SkillEntry)
↓ generateSkillL0/L1/L2()
L0 摘要(name + description + tags,~100 tokens)
L1 概览(SKILL.md 前 8000 字符,~2K tokens)
L2 完整(全文)
↓ vfs.WriteSystemEntry("skills", category, name, L0, L1, L2, meta)
VFS: _system/skills/{category}/{name}/
↓ vectorIndex.Upsert(零向量,payload-only)
Qdrant: sys_skills collection(content_hash 增量去重)技能条目(SkillEntry)
↓ generateSkillL0/L1/L2()
L0 摘要(name + description + tags,~100 tokens)
L1 概览(SKILL.md 前 8000 字符,~2K tokens)
L2 完整(全文)
↓ vfs.WriteSystemEntry("skills", category, name, L0, L1, L2, meta)
VFS: _system/skills/{category}/{name}/
↓ vectorIndex.Upsert(零向量,payload-only)
Qdrant: sys_skills collection(content_hash 增量去重)10.6 System Prompt 注入
// prompt_sections.go:buildSkillsSectionFull()
"## Skills (mandatory)\n" +
"Before replying: scan <available_skills>...\n" +
"- 精确匹配一个技能 → lookup_skill(name) → 遵循指令\n" +
"- 多个候选 → 选最具体的 → lookup_skill\n" +
"- 无匹配 → 不查询\n" +
"<available_skills>\n- name: description(≤80字符)\n</available_skills>"// prompt_sections.go:buildSkillsSectionFull()
"## Skills (mandatory)\n" +
"Before replying: scan <available_skills>...\n" +
"- 精确匹配一个技能 → lookup_skill(name) → 遵循指令\n" +
"- 多个候选 → 选最具体的 → lookup_skill\n" +
"- 无匹配 → 不查询\n" +
"<available_skills>\n- name: description(≤80字符)\n</available_skills>"10.7 联网搜索 Provider 真相源
运行时联网搜索统一为两个 provider(消除历史遗留的 Brave/Perplexity/Grok 多源矛盾):
| Provider | 状态 | 配置 |
|---|---|---|
| Bocha | 默认 | webSearch.provider: "bocha" + webSearch.bocha.apiKey |
| 备选 | webSearch.provider: "google" + webSearch.google.apiKey + webSearch.google.searchEngineId |
已清理: WebSearchPerplexityConfig/WebSearchGrokConfig 类型已删除,schema hints 已对齐。
10.8 统一应用中心(App Center)
将 skill / plugin / bundle 三种包类型统一到一个浏览、安装、管理界面,跨三个平面(macOS / Web / CLI)消费同一套 Gateway RPC。
后端 RPC(Phase 3A):
| RPC 方法 | 功能 | 响应 |
|---|---|---|
packages.catalog.browse | 分页浏览目录(kind/keyword/category 过滤) | {items: PackageCatalogItem[], total, page} |
packages.catalog.detail | 获取单个包详情 | {item: PackageCatalogItem} |
packages.install | 安装包(id + kind) | {record: PackageInstallRecord} |
packages.update | 更新包(等同重新安装) | {record: PackageInstallRecord} |
packages.remove | 移除包 | {success: true} |
packages.installed | 列出已安装包(可选 kind 过滤) | {records: PackageInstallRecord[]} |
核心类型定义: backend/pkg/types/types_packages.go(详见 arch-package-schema-v1.md)。
前端三平面(Phase 3B):
| 平面 | 入口 | 实现 |
|---|---|---|
| macOS | SettingsRootView → "App Center" tab | SkillsSettings.swift 双面板(Installed/Cloud),CloudPackagesModel 消费 requestRaw(method:params:) |
| Web UI | plugins 页面 → "应用中心" sub-tab(位列首位) | controllers/packages.ts + views/plugins.ts::renderPackagesPanel() 消费 client.request() |
| CLI | crabclaw packages {browse,detail,install,remove,installed} | oa-cmd-packages crate 消费 call_gateway() |
数据流:
用户操作(点击安装/筛选/搜索)
↓
前端控制器 → Gateway RPC (packages.*)
↓
Gateway → PackageCatalog.Browse() / PackageInstaller.Install()
↓
响应 → 前端乐观更新 isInstalled 状态用户操作(点击安装/筛选/搜索)
↓
前端控制器 → Gateway RPC (packages.*)
↓
Gateway → PackageCatalog.Browse() / PackageInstaller.Install()
↓
响应 → 前端乐观更新 isInstalled 状态兼容性: 现有 skills.* 和 plugins.* RPC 完全不受影响。App Center 是纯增量平面。
十一、Argus 视觉子智能体(灵瞳)
11.1 架构层次
Argus/(独立子项目,C++/Rust 混合)
├── rust-core/ ← 核心逻辑(Rust)
├── build/Argus.app/ ← macOS App Bundle(本地运行)
└── MCP Bridge(IPC)
Gateway 侧(backend/internal/argus/):
├── bridge.go ← ArgusBridge(进程管理 + MCP 工具代理 + ResolveBinary + CheckBinary + ArgusStartError)
├── config.go ← BridgeConfig(路径/超时/状态回调)
├── available.go ← IsAvailable()(含可执行权限+目录排除检查)+ EnsureCodeSigned()
├── tcc_darwin.go ← macOS TCC 权限预检(Screen Recording + Accessibility + Sequoia 月度过期)
└── tcc_other.go ← 非 macOS TCC 存根(总返回 granted)
Runner 侧(Phase 5 — 完全子智能体化):
├── spawn_argus_agent.go ← spawn_argus_agent 工具定义 + 执行器
├── announce_argus.go ← 灵瞳专用系统提示词构建
└── (复用 delegation_contract / quality_review / agent_channel)Argus/(独立子项目,C++/Rust 混合)
├── rust-core/ ← 核心逻辑(Rust)
├── build/Argus.app/ ← macOS App Bundle(本地运行)
└── MCP Bridge(IPC)
Gateway 侧(backend/internal/argus/):
├── bridge.go ← ArgusBridge(进程管理 + MCP 工具代理 + ResolveBinary + CheckBinary + ArgusStartError)
├── config.go ← BridgeConfig(路径/超时/状态回调)
├── available.go ← IsAvailable()(含可执行权限+目录排除检查)+ EnsureCodeSigned()
├── tcc_darwin.go ← macOS TCC 权限预检(Screen Recording + Accessibility + Sequoia 月度过期)
└── tcc_other.go ← 非 macOS TCC 存根(总返回 granted)
Runner 侧(Phase 5 — 完全子智能体化):
├── spawn_argus_agent.go ← spawn_argus_agent 工具定义 + 执行器
├── announce_argus.go ← 灵瞳专用系统提示词构建
└── (复用 delegation_contract / quality_review / agent_channel)11.2 运行模式
灵瞳现为与 Open Coder 同级的完整子智能体(Phase 5),拥有:
- 独立 LLM session(可独立配置 provider/model/apiKey/baseURL)
- DelegationContract(合约约束、单调衰减、协商循环 3 轮上限)
- ThoughtResult 结构化返回
- 质量审核(Phase 2)+ 最终交付门控(Phase 3)
- 异步求助通道(Phase 4 AgentChannel)
直接 argus_* 工具仍保留供灵瞳子智能体内部使用,主智能体改为调 spawn_argus_agent 委派。
argus_capture_screen 作为例外保留给主智能体直接调用(简单截屏无需启动子智能体)。
11.3 模型配置(独立于 Open Coder)
subAgents:
screenObserver:
provider: "anthropic" # LLM provider
model: "claude-sonnet-4" # 灵瞳独立模型
apiKey: "sk-..." # 独立 API key(自动脱敏)
baseUrl: "" # OpenAI 兼容端点
# 以下为传统视觉观测器配置(非 LLM)
enabled: true
intervalMs: 1000
changeThreshold: 0.02subAgents:
screenObserver:
provider: "anthropic" # LLM provider
model: "claude-sonnet-4" # 灵瞳独立模型
apiKey: "sk-..." # 独立 API key(自动脱敏)
baseUrl: "" # OpenAI 兼容端点
# 以下为传统视觉观测器配置(非 LLM)
enabled: true
intervalMs: 1000
changeThreshold: 0.02解析函数 resolveArgusConfig(),三级 fallback:
subAgents.screenObserver显式配置(最高优先级)agents.defaults.model.primary(主 agent 默认)- 硬编码默认值(anthropic/claude-sonnet-4)
11.4 工具集
| 工具 | 类别 | 风险 |
|---|---|---|
| argus_capture_screen | 感知 | 低 |
| argus_describe_scene | 感知 | 低 |
| argus_locate_element | 感知 | 低 |
| argus_read_text | 感知 | 低 |
| argus_click / double_click | 交互 | 中 |
| argus_type_text | 交互 | 中 |
| argus_scroll | 交互 | 低 |
| argus_open_url | 交互 | 高(NoNetwork 可阻断) |
| argus_run_shell | 交互 | 高(NoSpawn 可阻断) |
macOS TCC 授权:
- 通过
EnsureCodeSigned()裸二进制自动签名,确保权限持久化 - TCC 权限预检(
CheckTCCPermissions()):启动前主动检测 Screen Recording + Accessibility 权限 - Sequoia (15+) 月度重新授权检测:读取
ScreenCaptureApprovals.plist计算到期天数,<=5 天预警 argus.permission.checkRPC:前端可查询当前权限状态 + 恢复指引
11.5 启动故障恢复
| 机制 | 实现 |
|---|---|
| 二进制发现 | 4 级优先级:$ARGUS_BINARY_PATH > .app bundle > ~/.crabclaw/bin > PATH(exec.LookPath) |
| 启动失败保留 | Start() 失败后保留 bridge 实例(SetArgusBridge),允许 UI 重试(subagent.ctl set_enabled) |
| 并发安全 | 包级 argusBridgeMu mutex 保护 set_enabled 的 bridge 创建路径(防 check-then-act 竞态) |
| 结构化错误 | ArgusStartError(Phase/Reason/Recovery),前端展示恢复指引 |
| 进程重启 | processMonitor 指数退避(1s→60s cap),maxRestartAttempts=5,快速崩溃熔断(3 次/60s) |
| 状态广播 | 启动失败 + OnStateChange → argus.status.changed 事件广播到前端 |
| GatewayState 并发 | ArgusBridge() 用 RLock,SetArgusBridge() 用 Lock(RWMutex 保护) |
Browser 工具 vs Argus:
- Browser:CDP 直连浏览器,14 种 action(navigate/click/click_ref/type/fill_ref/screenshot/evaluate/observe/wait_for/go_back/go_forward/get_url/get_content/ai_browse),三层控制模型(CSS 选择器 → ARIA ref → Intent-level AI Browse),
__MULTIMODAL__协议将截图注入 LLM 视觉通道,512KB 大小限制。- Argus(灵瞳):macOS Accessibility + 视觉模型,屏幕坐标级操控,适用于桌面应用、非 Web 场景。
- 选择策略:Web 自动化 → browser(更快、更精确);桌面应用 / 跨应用 → Argus。两者共存,互不排斥。
- 详细架构:
docs/claude/goujia/架构-浏览器自动化.md(含 14 action 表、RPC 路由表、Rust CLI 映射、安全约束)。
十二、安全架构
12.1 安全分层
第一层:OS 原生隔离(oa-sandbox)
└── Seatbelt / Landlock+Seccomp / AppContainer / Docker
第二层:委托合约(DelegationContract)
└── 能力单调衰减 + NoNetwork 强制 + 路径 scope + 资源预算守恒
第三层:合约审批路由(ApprovalRouter)
└── 规则评估(非 LLM):合约内低风险自动放行,高风险路由到用户
└── 命令白名单词边界匹配 + shell 操作符预扫描(防注入绕过)
└── 审批审计链路(contract.audit RPC 查询)
第四层:Exec Approvals(exec_approvals)
└── 宿主机命令执行必须明确授权,记录审计链路
第五层:Escalation(L0-L3 四级权限)
└── 多 active grants + task-scoped 挂载 + pending 落盘恢复 + 审计日志
第六层:SSRF 防护(security/ssrf.go)
└── validateMediaURL + 内网地址过滤
第七层:命令审批门控(CoderConfirmationManager)
└── Ask 规则 fail-closed:无审批则阻塞(60s 超时自动 deny)
第八层:命令规则预设(command_rule_presets)
└── find ~ → deny, find / → deny, rm → ask, rmdir → ask, gateway start/stop/restart → ask
第九层:Bash 写操作检测(looksLikeBashWrite)
└── NativeSandbox 路径的 redirect/tee/sed -i 检测 → CoderConfirmation 审批第一层:OS 原生隔离(oa-sandbox)
└── Seatbelt / Landlock+Seccomp / AppContainer / Docker
第二层:委托合约(DelegationContract)
└── 能力单调衰减 + NoNetwork 强制 + 路径 scope + 资源预算守恒
第三层:合约审批路由(ApprovalRouter)
└── 规则评估(非 LLM):合约内低风险自动放行,高风险路由到用户
└── 命令白名单词边界匹配 + shell 操作符预扫描(防注入绕过)
└── 审批审计链路(contract.audit RPC 查询)
第四层:Exec Approvals(exec_approvals)
└── 宿主机命令执行必须明确授权,记录审计链路
第五层:Escalation(L0-L3 四级权限)
└── 多 active grants + task-scoped 挂载 + pending 落盘恢复 + 审计日志
第六层:SSRF 防护(security/ssrf.go)
└── validateMediaURL + 内网地址过滤
第七层:命令审批门控(CoderConfirmationManager)
└── Ask 规则 fail-closed:无审批则阻塞(60s 超时自动 deny)
第八层:命令规则预设(command_rule_presets)
└── find ~ → deny, find / → deny, rm → ask, rmdir → ask, gateway start/stop/restart → ask
第九层:Bash 写操作检测(looksLikeBashWrite)
└── NativeSandbox 路径的 redirect/tee/sed -i 检测 → CoderConfirmation 审批12.2 隐私配置选项
| 需求 | 配置方案 |
|---|---|
| 本地推理(零外泄) | provider=ollama,本地 Llama/Qwen |
| 隐私云端 | provider=venice(服务端不留存) |
| 代码执行网络隔离 | 委托合约 NoNetwork=true → docker --network=none |
| 完全私有化部署 | 内网运行 Gateway 二进制,无强制外部依赖 |
| 敏感命令必须审批 | exec_approvals 策略配置 |
十三、前端 UI(TypeScript + Lit)
ui/src/ui/
├── app.ts ← 根组件(@state 响应式状态)
├── app-view-state.ts ← AppViewState 类型
├── app-gateway.ts ← WebSocket RPC 客户端 + 事件分发
├── app-render.ts ← 主视图渲染
├── app-render.helpers.ts ← 渲染辅助函数
├── app-settings.ts ← 设置面板
├── navigation.ts ← 路由导航
├── storage.ts ← 本地持久化
├── chat/
│ ├── grouped-render.ts ← 消息分组渲染
│ ├── agent-processing-card.ts ← Agent 处理状态卡片
│ └── tool-cards.ts ← 工具调用卡片
├── controllers/
│ ├── chat.ts ← 聊天状态控制器
│ ├── escalation.ts ← 权限升级状态控制器
│ ├── subagents.ts ← 子智能体状态控制器
│ ├── packages.ts ← 应用中心状态控制器(browse/install/remove)
│ ├── skills.ts ← 技能面板状态控制器
│ ├── plugins.ts ← 插件面板状态控制器
│ ├── task-kanban.ts ← 任务看板状态控制器
│ └── system-maintenance.ts ← 系统维护控制器
├── views/
│ ├── plugins.ts ← 插件/工具/技能/应用中心四面板视图
│ ├── escalation-popup.ts ← 权限升级弹窗
│ ├── escalation-status-panel.ts ← Security Tab 面板
│ ├── escalation-audit-log.ts ← 审计日志
│ ├── notification-center.ts ← 通知中心
│ └── system-maintenance.ts ← 系统维护视图
└── locales/
├── zh.ts ← 中文国际化
└── en.ts ← 英文国际化ui/src/ui/
├── app.ts ← 根组件(@state 响应式状态)
├── app-view-state.ts ← AppViewState 类型
├── app-gateway.ts ← WebSocket RPC 客户端 + 事件分发
├── app-render.ts ← 主视图渲染
├── app-render.helpers.ts ← 渲染辅助函数
├── app-settings.ts ← 设置面板
├── navigation.ts ← 路由导航
├── storage.ts ← 本地持久化
├── chat/
│ ├── grouped-render.ts ← 消息分组渲染
│ ├── agent-processing-card.ts ← Agent 处理状态卡片
│ └── tool-cards.ts ← 工具调用卡片
├── controllers/
│ ├── chat.ts ← 聊天状态控制器
│ ├── escalation.ts ← 权限升级状态控制器
│ ├── subagents.ts ← 子智能体状态控制器
│ ├── packages.ts ← 应用中心状态控制器(browse/install/remove)
│ ├── skills.ts ← 技能面板状态控制器
│ ├── plugins.ts ← 插件面板状态控制器
│ ├── task-kanban.ts ← 任务看板状态控制器
│ └── system-maintenance.ts ← 系统维护控制器
├── views/
│ ├── plugins.ts ← 插件/工具/技能/应用中心四面板视图
│ ├── escalation-popup.ts ← 权限升级弹窗
│ ├── escalation-status-panel.ts ← Security Tab 面板
│ ├── escalation-audit-log.ts ← 审计日志
│ ├── notification-center.ts ← 通知中心
│ └── system-maintenance.ts ← 系统维护视图
└── locales/
├── zh.ts ← 中文国际化
└── en.ts ← 英文国际化WebSocket 事件处理(app-gateway.ts):
esc_前缀事件 → Escalation 控制器coder.confirm.*→ 命令审批控制器chat.message→ 聊天渲染system.reset.done→ 系统恢复刷新
十四、配置系统
pkg/types/config.go ← CrabClawConfig(全局配置类型)
backend/internal/config/ ← 配置加载/验证/写入
├── loader.go ← ConfigLoader(热加载)
└── schema.go ← JSON Schema 生成
配置文件:~/.crabclaw/crabclaw.json(或 $CRABCLAW_STATE_DIR)
主要配置节:
agents.defaults.* ← 默认 Agent 配置
agents.list[] ← 多 Agent 配置
subAgents.openCoder.* ← Open Coder 独立 provider/apiKey/model/baseURL
subAgents.screenObserver.* ← 灵瞳配置(LLM provider/model/apiKey/baseURL + 视觉观察器参数)
memory.uhms.* ← 太虚永忆配置
skills.load.* ← 技能加载配置
skills.store.* ← 技能商店配置
channels.* ← 渠道配置(feishu/dingtalk 等)
providers.* ← LLM Provider 配置
security.* ← 安全策略
plugins.* ← 插件配置pkg/types/config.go ← CrabClawConfig(全局配置类型)
backend/internal/config/ ← 配置加载/验证/写入
├── loader.go ← ConfigLoader(热加载)
└── schema.go ← JSON Schema 生成
配置文件:~/.crabclaw/crabclaw.json(或 $CRABCLAW_STATE_DIR)
主要配置节:
agents.defaults.* ← 默认 Agent 配置
agents.list[] ← 多 Agent 配置
subAgents.openCoder.* ← Open Coder 独立 provider/apiKey/model/baseURL
subAgents.screenObserver.* ← 灵瞳配置(LLM provider/model/apiKey/baseURL + 视觉观察器参数)
memory.uhms.* ← 太虚永忆配置
skills.load.* ← 技能加载配置
skills.store.* ← 技能商店配置
channels.* ← 渠道配置(feishu/dingtalk 等)
providers.* ← LLM Provider 配置
security.* ← 安全策略
plugins.* ← 插件配置十五、关键文件索引
Go(backend/)
| 文件 | 职责 | LOC |
|---|---|---|
internal/gateway/boot.go | GatewayState 初始化(含 ArgusBridge/SetArgusBridge RWMutex),所有子系统引导 | ~430 |
internal/gateway/server.go | RPC 注册,渠道插件注册,HTTP 启动(listenErrCh) | ~1720 |
internal/gateway/ws_server.go | WebSocket 连接生命周期(6 阶段),ping 保活,慢消费者写超时 | ~537 |
internal/gateway/openai_http.go | OpenAI Chat Completions API 兼容(流式/非流式) | ~554 |
internal/gateway/openresponses_http.go | OpenResponses SSE 完整协议实现 | ~837 |
internal/gateway/net.go | IP 解析工具(StripOptionalPort + NormalizeIP + ResolveGatewayClientIP) | ~433 |
internal/agents/runner/attempt_runner.go | Agent 运行主循环 + 三层死循环防护 + 工具失败指导注入 | ~1720 |
internal/agents/runner/tool_executor.go | 工具分发执行(send_media 含可操作错误提示) | ~1845 |
internal/agents/runner/delegation_contract.go | 委托合约+能力集+单调衰减+ResourceBudget+ContractPersistence 接口 | ~580 |
internal/agents/runner/spawn_coder_agent.go | spawn_coder_agent 工具+协商循环+恢复上下文 | ~280 |
internal/agents/runner/coder_confirmation.go | 命令审批+ApprovalRouter 合约审批路由 | ~440 |
internal/gateway/contract_persistence.go | VFS 合约持久化适配器(SaveContract/LoadContract/TransitionStatus) | ~280 |
internal/gateway/server_methods_contracts.go | contract.list/get/audit RPC | ~150 |
internal/gateway/wizard_open_coder.go | Open Coder 配置向导(3 步 Provider/Key/Model) | ~260 |
internal/agents/prompt/prompt_sections.go | System Prompt 构建 | ~185 |
internal/agents/capabilities/registry.go | 工具能力注册表(30 条目)+ LookupByToolName | ~320 |
internal/agents/scope/tool_policy.go | 工具组定义(9 组)+ 展开/规范化/插件组 | ~399 |
internal/agents/skills/frontmatter.go | SKILL.md frontmatter 解析(adrg/frontmatter)+ 元数据 | ~338 |
internal/agents/skills/workspace_skills.go | 技能加载+过滤+格式化+SkillBindable 绑定验证 | ~360 |
internal/agents/skills/skill_distributor.go | 技能 VFS 分发+Qdrant 索引 | ~247 |
internal/gateway/progress_delivery.go | OnProgress 回调工厂(远程频道+WebSocket chat.progress) | ~162 |
internal/memory/uhms/manager.go | 太虚永忆主管理器 | ~1100 |
internal/sandbox/native_bridge.go | Rust Worker 桥接(状态机+健康监控) | ~570 |
internal/channels/feishu/client.go | 飞书 WebSocket 客户端 | ~400 |
internal/gateway/task_events.go | task.* 事件常量 + 5 结构体 | ~73 |
internal/gateway/chat.go | ChatRunState + async CAS 并发守卫 | ~408 |
internal/gateway/server_methods_packages.go | packages.catalog.browse/detail + packages.install/update/remove/installed RPC | ~226 |
Rust(cli-rust/)
| crate | 职责 |
|---|---|
oa-sandbox | 4 平台原生沙箱 + Docker fallback + 持久化 Worker |
oa-coder | MCP Server,6 工具,9 层模糊编辑 |
oa-cmd-browser | Browser 自动化 CLI(40+ 命令,RPC 到 Gateway browser.request) |
oa-cmd-packages | 应用中心 CLI(5 命令:browse/detail/install/remove/installed,RPC 到 Gateway packages.*) |
oa-runtime | 跨 crate 共享运行时 |
oa-types | 跨语言共享类型 |
oa-config | 配置解析(Rust 侧) |
TypeScript(ui/)
| 文件 | 职责 |
|---|---|
ui/src/ui/app.ts | 根组件,所有 @state 声明 |
ui/src/ui/app-gateway.ts | WebSocket 客户端,事件路由 |
ui/src/ui/app-render.ts | 主视图渲染树 |
ui/src/ui/controllers/task-kanban.ts | 任务看板状态控制器 |
ui/src/ui/controllers/packages.ts | 应用中心状态控制器(browse/install/remove) |
ui/src/ui/views/plugins.ts | 插件/工具/技能/应用中心四面板视图 |
ui/src/ui/views/task-kanban.ts | 任务看板 Lit 组件 |
十六、构建与部署
本地开发
make dev # Argus + Gateway 完整构建并启动(dev port 19001)
make gateway # 仅 Go Gateway 构建 + 启动
cd ui && npm run dev # 前端开发服务器
# Rust 组件
cd cli-rust && cargo build --workspace --release
./target/release/oa-cmd-sandbox list # 沙箱 CLI
./target/release/oa-cmd-coder # oa-coder MCP Server(stdio)make dev # Argus + Gateway 完整构建并启动(dev port 19001)
make gateway # 仅 Go Gateway 构建 + 启动
cd ui && npm run dev # 前端开发服务器
# Rust 组件
cd cli-rust && cargo build --workspace --release
./target/release/oa-cmd-sandbox list # 沙箱 CLI
./target/release/oa-cmd-coder # oa-coder MCP Server(stdio)状态目录
~/.crabclaw/(或 $CRABCLAW_STATE_DIR)
├── crabclaw.json ← 主配置
├── credentials/ ← Auth profiles + tokens
├── agents/<agentId>/
│ ├── sessions/ ← JSONL 会话历史(树状结构)
│ ├── store/
│ │ └── sessions.db ← SQLite(WAL 模式)会话索引 + runs 表
│ ├── tasks.json ← TaskStore 独立任务存储(过渡期)
│ ├── sessions.json.migrated ← JSON→SQLite 迁移后的备份(只读)
│ └── workspace/ ← Agent 工作区
├── memory/
│ ├── uhms.db ← SQLite(记忆 + FTS5 索引)
│ └── vfs/ ← L0/L1/L2 VFS 文件系统
└── extensions/ ← 已安装插件
> **Session Store 收敛**: sessions.json 已迁移到 SQLite(`modernc.org/sqlite` 纯 Go),
> 启动时自动迁移并备份为 sessions.json.migrated。SQLite 打开失败时自动降级到 JSON 模式。
> 详细架构: `arch-session-store-convergence.md`~/.crabclaw/(或 $CRABCLAW_STATE_DIR)
├── crabclaw.json ← 主配置
├── credentials/ ← Auth profiles + tokens
├── agents/<agentId>/
│ ├── sessions/ ← JSONL 会话历史(树状结构)
│ ├── store/
│ │ └── sessions.db ← SQLite(WAL 模式)会话索引 + runs 表
│ ├── tasks.json ← TaskStore 独立任务存储(过渡期)
│ ├── sessions.json.migrated ← JSON→SQLite 迁移后的备份(只读)
│ └── workspace/ ← Agent 工作区
├── memory/
│ ├── uhms.db ← SQLite(记忆 + FTS5 索引)
│ └── vfs/ ← L0/L1/L2 VFS 文件系统
└── extensions/ ← 已安装插件
> **Session Store 收敛**: sessions.json 已迁移到 SQLite(`modernc.org/sqlite` 纯 Go),
> 启动时自动迁移并备份为 sessions.json.migrated。SQLite 打开失败时自动降级到 JSON 模式。
> 详细架构: `arch-session-store-convergence.md`系统恢复
# RPC: system.reset
# 效果:清除会话历史、重置技能分发状态、清除 escalation 记录
# 不重启 Gateway,运行时热恢复
# 完成后广播 system.reset.done 事件# RPC: system.reset
# 效果:清除会话历史、重置技能分发状态、清除 escalation 记录
# 不重启 Gateway,运行时热恢复
# 完成后广播 system.reset.done 事件十七、设计原则
- 安全默认:沙箱优先(原生 > Docker),NoNetwork 传播到
--network=none,exec 审批 fail-closed - 能力单调衰减:子 Agent 权限永远不超过父 Agent(委托合约)
- 防御纵深:OS 隔离 + 合约约束 + Exec Approvals + Escalation + 命令规则 + 写操作检测 八层叠加
- 可选子系统:Argus / 太虚永忆 / 原生沙箱均为可选,不可用时优雅降级
- 中文优先:文档、日志、技能描述均使用中文减少 token 消耗
- 零 panic 策略:Rust 侧
unsafe_code=forbid+unwrap_used=deny,Go 侧显式错误传播 - 审计完整性:所有权限操作记录审计日志,持久化到 VFS
- 意图驱动路由:六级意图分类 → 渐进式工具暴露 + 行为指引注入(五维联动)
文档维护:每次重大架构变更后更新 last_updated 并同步 MEMORY.md 架构知识章节。