文档
推荐给好友,福利领不停!好友同步开通最高 1000 万词元额度 · 后续消费分佣最高 30%。
+50万 Token生成链接

系统架构

Rust CLI + Go Gateway 双二进制架构详解

本文档描述当前 Rust + Go + TypeScript 混合架构的完整系统设计。 覆盖范围:Gateway 主进程、Agent 运行时、原生沙箱、太虚永忆记忆系统、委托合约、渠道接入、前端 UI 所有子系统。


一、技术栈总览

层次语言 / 运行时职责
前端 UITypeScript + Lit + Vite聊天界面、配置管理、状态渲染
Gateway(主进程)Go 1.22+所有业务逻辑、RPC 路由、事件广播
Agent 运行时GoLLM 调用、工具循环、Prompt 构建
原生沙箱Rust(oa-sandbox crate)OS 级隔离(Seatbelt/Landlock/AppContainer)
编程子智能体Rust(oa-coder crate)MCP Server,代码编辑/搜索
持久化 WorkerRust → Go bridgeJSON-Lines IPC 状态机
视觉子智能体(灵瞳)C++/Rust(Argus)+ Go 子智能体屏幕理解、视觉交互、独立 LLM session
记忆系统Go(uhms 包)压缩、VFS、向量检索

二、系统全局架构图

shell
┌─────────────────────────────────────────────────────────────────────┐
  用户端(飞书 / 钉钉 / 企微 / 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() 中按以下顺序初始化:

shell
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):

方法组示例方法文件
configconfig.get / config.apply / config.schemaserver_methods_config.go
modelsmodels.list / models.set / models.testserver_methods_models.go
agentsagents.list / agents.create / agents.deleteserver_methods_agents.go
agentagent.run / agent.abort / agent.statusserver_methods_agent.go
chatchat.send / chat.history / chat.compactserver_methods_chat.go
skillsskills.status / skills.distribute / skills.store.{browse,pull,refresh,link,status}server_methods_skills.go
memorymemory.search / memory.get / memory.uhms.*server_methods_memory.go / uhms.go
channelschannels.list / channels.connect / channels.sendserver_methods_channels.go
escalationescalation.request / escalation.grant / escalation.revokeserver_methods_escalation.go
exec_approvalsexec.approvals.list / exec.approvals.grantserver_methods_exec_approvals.go
securitysecurity.audit / security.policy.*server_methods_security.go
systemsystem.reset / system.statusserver_methods_system.go / reset.go
nodesnodes.list / nodes.run / nodes.connectserver_methods_nodes.go
browserbrowser.request(单 RPC 入口,body.method/path 路由)server_methods_browser.go
croncron.list / cron.create / cron.triggerserver_methods_cron.go
ttstts.speak / tts.stopserver_methods_tts.go
subagentsubagent.list / subagent.ctlserver_methods_subagent.go
argusargus.permission.checkserver_methods_argus.go
contractcontract.list / contract.get / contract.auditserver_methods_contracts.go
wizardwizard.start / wizard.next / wizard.cancel / wizard.statusserver_methods_wizard.go
packagespackages.catalog.browse / packages.catalog.detail / packages.install / packages.update / packages.remove / packages.installedserver_methods_packages.go
health / status内联注册

广播事件(前端订阅)

事件触发时机
chat.messageAgent 流式回复 + 异步完成结果回填(asyncResult: true
chat.progress长任务中途进度推送(summary/phase/percent,8 秒节流 + 指纹去重)
channel.message.incoming渠道新消息
argus.status.changedArgus 状态变化
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 个阶段:

shell
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(SetWriteDeadlineBufferedAmount 恒返回 0,不再使用累计字节(原实现单调递增必然误杀)
Ping 保活30s ticker + pingDone channelselect 双路监听 ticker.C 和 pingDone,连接关闭时 close(pingDone) 通知退出,防止 goroutine 泄漏
写并发保护writeMu sync.MutexsendRaw / ping goroutine 共用同一把锁
ClientIP 解析ResolveGatewayClientIPStripOptionalPort(remoteAddr)NormalizeIP → trusted proxy 匹配 → X-Forwarded-For / X-Real-IP 回退

3.4 HTTP 服务启动(server.go)

StartGatewayServer 返回 (*GatewayRuntime, error)

shell
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/completionsOpenAI Chat Completions(stream/non-stream)openai_http.go
POST /v1/responsesOpenResponses 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 回调,实现长任务中途进度推送:

shell
                        ┌─ 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 主运行循环

shell
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 结构

shell
[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 完整路径):

shell
用户输入 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 行)

六级意图分类(优先级从高到低):

层级工具数历史裁剪典型触发
greeting0不加载"你好"、"hi" (≤10 字符)
question5最近 4 条疑问标记 + 无祈使前缀
task_light12全量默认 fallback
task_write15+全量"创建"/"写"/"发送" 等
task_delete5全量"删除"/"清理"/"rm" 等
task_multimodal全部全量"截屏"/"浏览器"/"argus"

五维联动关系

shell
意图分类 (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
Shellbash沙箱执行(原生 or Docker)
记忆memory_search / memory_get太虚永忆 VFS
技能lookup_skill / search_skillsSkillsCache + VFS
网络web_fetch / web_searchguarded_fetch + 搜索 API
媒体send_mediaChannelMgr 适配器(file_path 优先 / target 默认当前频道 / MIME 自动检测 / 30MB 限制)
浏览器browser(14 种 action)CDP 直连(PlaywrightBrowserController),三层控制模型:CSS 选择器 / ARIA ref / AI Browse。详见 架构-浏览器自动化.md
会话sessions_list / sessions_send / sessions_spawnSessionManager
视觉argus_*Argus Bridge IPC(子智能体内部工具)
远程 MCPremote_*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)的端到端持久化:

shell
前端 {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 架构概览

shell
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 值沙箱网络文件系统触发方式
L0deny❌ 无只读配置 / 合约约束
L1allowlist⚠️ 受限(公网 TCP+DNS)工作区读写默认
L2sandboxed✅ 全网络工作区 + 按任务临时挂载(MountRequests)mount_access 审批(task-scoped)
L3full❌ 裸机✅ 全网络全权限向导/配置永久授权,零审批

Rust 枚举 ↔ Go 映射config.rs L14-30):

Rust 枚举serde 主名serde aliasGo 字符串
L0Deny"deny""deny"
L1Allowlist"allowlist""sandbox""allowlist"
L2Sandboxed"sandboxed""full""sandboxed"

Rust Worker CLI 仍兼容旧 alias:sandbox -> L1full -> L2。 Go 控制面以 NormalizeExecSecurityValue() 为权威归一化:sandbox/sandboxed -> L2full -> 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

shell
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 常驻避免重复启动沙箱开销。

NativeSandboxRouternative_bridge.go L565-610)— 按安全级别路由:

shell
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)— 双路径设计:

shell
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 架构

shell
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 后)

shell
用户请求代码任务

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 → 重新委托):

shell
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/&#123;status&#125;/&#123;contractID&#125;/(l0=摘要, l1=合约 JSON, l2=ThoughtResult)
  • TTL 自动清理: 已完成合约 >24h 删除(1h/次 goroutine, 可取消)
  • edit 工具 9 层模糊匹配确保高成功率:
    1. 精确匹配 → 2. 首尾空白归一化 → 3. 全空白归一化 → 4. 行级 diff → 5. Levenshtein → 6-9. 渐进宽松策略

6.3 独立 Provider/Model 配置

Open Coder 支持独立于主 agent 的 LLM 配置(provider/apiKey/model/baseURL 四件套):

shell
配置类型: 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 爆炸和跨会话记忆两大核心问题:

shell
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 压缩管线

shell
消息流入(超 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/&#123;category&#125;/&#123;name&#125;/

7.4 向量检索

shell
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 核心数据结构

go
// 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 权限单调衰减验证

shell
 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=[] (全局) → VIOLATION

8.3 NoNetwork 强制链路

shell
合约 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)

shell
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)

shell
 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)

shell
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)

shell
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(权限升级系统)

shell
L0:拒绝执行
L1:受限执行,按 allowlist / ask 规则决定是否需要确认
L2:沙箱内执行默认放行;仅工作区外挂载走 `mount_access` 审批,按任务自动回收
L3:永久授权,开启后不再进入审批链

持久化:pending EscalationRequest 落盘 RestoreFromDisk(跨重启恢复)
前端:escalation-status-panel.ts + escalation-popup.ts + escalation-audit-log.ts
飞书卡片:审批请求以互动卡片形式推送,按钮点击触发 grant/deny RPC
L0:拒绝执行
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 渠道架构

shell
backend/internal/channels/
├── registry.go 渠道插件注册表
├── channels.go 频道接口定义
└── {渠道}/
    ├── feishu/ 飞书(WebSocket 长连接)
    ├── dingtalk/ 钉钉
    ├── wecom/ 企业微信
    ├── discord/ Discord
    ├── telegram/ Telegram
    ├── slack/ Slack
    ├── whatsapp/ WhatsApp
    ├── signal/ Signal
    ├── imessage/ iMessage
    └── line/ Line
backend/internal/channels/
├── registry.go 渠道插件注册表
├── channels.go 频道接口定义
└── {渠道}/
    ├── feishu/ 飞书(WebSocket 长连接)
    ├── dingtalk/ 钉钉
    ├── wecom/ 企业微信
    ├── discord/ Discord
    ├── telegram/ Telegram
    ├── slack/ Slack
    ├── whatsapp/ WhatsApp
    ├── signal/ Signal
    ├── imessage/ iMessage
    └── line/ Line

9.2 飞书渠道(深度集成)

shell
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,防火墙内可用。

消息接收流

shell
larkws OnP2MessageReceiveV1 feishuDispatch Agent.Run()
 广播到其他渠道
larkws OnP2MessageReceiveV1 feishuDispatch Agent.Run()
 广播到其他渠道

卡片审批流(Escalation 提权)

shell
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 操作确认)

shell
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 RPC
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 RPC

会话隔离feishu:<chatID> 每个聊天独立会话,跨会话事件通过 channel.message.incoming 广播。

9.3 渠道插件注册

Gateway 在 server.go 中按配置动态注册渠道插件:

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:&#123;contractID&#125;spawn_coder_agent 触发时
任务频道task:&#123;runID&#125;首次工具调用时(懒创建),TaskStore 独立存储

复用 channel.message.incoming 广播机制,前端按 session key 前缀自动分组到"智能体"/"任务"频道标签。

工具事件增强: 频道中广播结构化工具事件([工具] name: args + [结果] result (Nms)),通过 OnToolEvent 回调从 attempt_runner.go 工具循环注入,经 DispatchInboundParamsGetReplyOptions(any) → pipelineDispatcher(type-assert) → ModelFallbackExecutorRunEmbeddedPiAgentParams 透传链到达广播闭包。参数/结果均 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 条目)。

go
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:fsread_file, write_file, list_dir文件系统
group:runtimebash命令执行
group:uibrowser, canvas浏览器与画布
group:webweb_search, web_fetch网页搜索
group:memorymemory_search, memory_get记忆调用
group:sessionssessions_list, sessions_history, sessions_send, sessions_spawn, session_status会话管理
group:automationcron, gateway自动化
group:messagingmessage消息推送
group:nodesnodes节点管理

数据流: 前端 selectedSkillswizard.v2.applyapplySkillsConfig()ToolsConfig.Allow: ["group:fs", ...] → 运行时 ExpandToolGroups() 展开为具体工具名。

10.4 技能文档加载流程

shell
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 字符串存入 ParsedSkillFrontmattermap[string]string)。

技能绑定验证门控ResolveToolSkillBindings):

shell
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)

shell
技能条目(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 注入

go
// 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
Google备选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 过滤)&#123;items: PackageCatalogItem[], total, page&#125;
packages.catalog.detail获取单个包详情&#123;item: PackageCatalogItem&#125;
packages.install安装包(id + kind)&#123;record: PackageInstallRecord&#125;
packages.update更新包(等同重新安装)&#123;record: PackageInstallRecord&#125;
packages.remove移除包&#123;success: true&#125;
packages.installed列出已安装包(可选 kind 过滤)&#123;records: PackageInstallRecord[]&#125;

核心类型定义: backend/pkg/types/types_packages.go(详见 arch-package-schema-v1.md)。

前端三平面(Phase 3B):

平面入口实现
macOSSettingsRootView → "App Center" tabSkillsSettings.swift 双面板(Installed/Cloud),CloudPackagesModel 消费 requestRaw(method:params:)
Web UIplugins 页面 → "应用中心" sub-tab(位列首位)controllers/packages.ts + views/plugins.ts::renderPackagesPanel() 消费 client.request()
CLIcrabclaw packages &#123;browse,detail,install,remove,installed&#125;oa-cmd-packages crate 消费 call_gateway()

数据流:

shell
用户操作(点击安装/筛选/搜索)

前端控制器 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 架构层次

shell
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)

yaml
subAgents:
  screenObserver:
    provider: "anthropic"      # LLM provider
    model: "claude-sonnet-4"   # 灵瞳独立模型
    apiKey: "sk-..."           # 独立 API key(自动脱敏)
    baseUrl: ""                # OpenAI 兼容端点
    # 以下为传统视觉观测器配置(非 LLM)
    enabled: true
    intervalMs: 1000
    changeThreshold: 0.02
subAgents:
  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:

  1. subAgents.screenObserver 显式配置(最高优先级)
  2. agents.defaults.model.primary(主 agent 默认)
  3. 硬编码默认值(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.check RPC:前端可查询当前权限状态 + 恢复指引

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 安全分层

shell
第一层: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)

shell
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 → 系统恢复刷新

十四、配置系统

shell
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.goGatewayState 初始化(含 ArgusBridge/SetArgusBridge RWMutex),所有子系统引导~430
internal/gateway/server.goRPC 注册,渠道插件注册,HTTP 启动(listenErrCh)~1720
internal/gateway/ws_server.goWebSocket 连接生命周期(6 阶段),ping 保活,慢消费者写超时~537
internal/gateway/openai_http.goOpenAI Chat Completions API 兼容(流式/非流式)~554
internal/gateway/openresponses_http.goOpenResponses SSE 完整协议实现~837
internal/gateway/net.goIP 解析工具(StripOptionalPort + NormalizeIP + ResolveGatewayClientIP)~433
internal/agents/runner/attempt_runner.goAgent 运行主循环 + 三层死循环防护 + 工具失败指导注入~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.gospawn_coder_agent 工具+协商循环+恢复上下文~280
internal/agents/runner/coder_confirmation.go命令审批+ApprovalRouter 合约审批路由~440
internal/gateway/contract_persistence.goVFS 合约持久化适配器(SaveContract/LoadContract/TransitionStatus)~280
internal/gateway/server_methods_contracts.gocontract.list/get/audit RPC~150
internal/gateway/wizard_open_coder.goOpen Coder 配置向导(3 步 Provider/Key/Model)~260
internal/agents/prompt/prompt_sections.goSystem Prompt 构建~185
internal/agents/capabilities/registry.go工具能力注册表(30 条目)+ LookupByToolName~320
internal/agents/scope/tool_policy.go工具组定义(9 组)+ 展开/规范化/插件组~399
internal/agents/skills/frontmatter.goSKILL.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.goOnProgress 回调工厂(远程频道+WebSocket chat.progress)~162
internal/memory/uhms/manager.go太虚永忆主管理器~1100
internal/sandbox/native_bridge.goRust Worker 桥接(状态机+健康监控)~570
internal/channels/feishu/client.go飞书 WebSocket 客户端~400
internal/gateway/task_events.gotask.* 事件常量 + 5 结构体~73
internal/gateway/chat.goChatRunState + async CAS 并发守卫~408
internal/gateway/server_methods_packages.gopackages.catalog.browse/detail + packages.install/update/remove/installed RPC~226

Rust(cli-rust/)

crate职责
oa-sandbox4 平台原生沙箱 + Docker fallback + 持久化 Worker
oa-coderMCP Server,6 工具,9 层模糊编辑
oa-cmd-browserBrowser 自动化 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.tsWebSocket 客户端,事件路由
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 组件

十六、构建与部署

本地开发

bash
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)

状态目录

shell
~/.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`

系统恢复

bash
# RPC: system.reset
# 效果:清除会话历史、重置技能分发状态、清除 escalation 记录
# 不重启 Gateway,运行时热恢复
# 完成后广播 system.reset.done 事件
# RPC: system.reset
# 效果:清除会话历史、重置技能分发状态、清除 escalation 记录
# 不重启 Gateway,运行时热恢复
# 完成后广播 system.reset.done 事件

十七、设计原则

  1. 安全默认:沙箱优先(原生 > Docker),NoNetwork 传播到 --network=none,exec 审批 fail-closed
  2. 能力单调衰减:子 Agent 权限永远不超过父 Agent(委托合约)
  3. 防御纵深:OS 隔离 + 合约约束 + Exec Approvals + Escalation + 命令规则 + 写操作检测 八层叠加
  4. 可选子系统:Argus / 太虚永忆 / 原生沙箱均为可选,不可用时优雅降级
  5. 中文优先:文档、日志、技能描述均使用中文减少 token 消耗
  6. 零 panic 策略:Rust 侧 unsafe_code=forbid + unwrap_used=deny,Go 侧显式错误传播
  7. 审计完整性:所有权限操作记录审计日志,持久化到 VFS
  8. 意图驱动路由:六级意图分类 → 渐进式工具暴露 + 行为指引注入(五维联动)

文档维护:每次重大架构变更后更新 last_updated 并同步 MEMORY.md 架构知识章节。