源码逐层解剖 · FFAI Agent(backend/src/modules/agent)· 对照 Claude Code v2.1.88

FFAI Agent 实现架构全解剖

姊妹篇《Claude Code 源码架构全解剖》讲的是「一条消息在 CC 里的一生」;本文用同样的解剖刀切开我们自己的系统:FFAI Agent(NestJS 后端 254 个 TS 文件 / 约 4.5 万行),逐层拆解实现,并在每一层与 Claude Code 做机制级对比。所有结论标注 文件:行号(相对 backend/src/modules/agent/),来自 2026-07-07 对真实代码的核验。

254 源文件 · ~44.6K 行 messages.service.ts 2947 行 85 个 @AgentTool 47 条跨 Epic 不变量 5 家 provider + IR

00全景架构:六层 vs 六层

CC 是「React 渲染到终端的前端 + while(true) 引擎 + 工具执行器」;FFAI 是「多组织服务端的同一个 while(true),外面包一圈企业治理」。

两者内核惊人一致:没有计划器,只有一个 while(true)——模型不停要工具,循环不停喂结果。根本差异只有一个:信任边界的位置。CC 跑在用户自己的机器上,信任边界是「这台机器的主人」,安全靠权限弹窗;FFAI 跑在公司服务端、服务全组织员工,信任边界是「RBAC + 多组织隔离 + 不可篡改审计」,安全必须焊死在代码结构里(收口点、fail-closed、哈希链),不能依赖任何人点弹窗。

L0 SurfacesWeb SSE · Teams Bot · Electron Desktop · cron

API-first 多端平行;CC 对应层 = Ink 终端 UI + print 模式 + Agent SDK(单机单用户)

↓ POST /agent/messages(/stream) · Teams webhook · WS
L1 Gatewaycontrollers/ · teams/ · desktop/

SSE Controller、Teams webhook、Desktop WS 桥;actor 解析(JWT → userId/orgId)+ 设备绑定校验。CC 对应 = entrypoints/cli.tsx 的 flag 分流

L2 Agent Core(心脏)services/messages.service.ts · engine/query-engine.service.ts

runTurnStream = 真正的 TAOR while(true)(≈ CC queryLoop);QueryEngine 只做历史 compaction(早期 TAOR 骨架已删)。子 agent 同层递归(delegate_task)

↓ tool_use / ↑ tool_result
L3 Registriestools/tool-registry.service.ts · registry/ · skills/ · hooks/

ToolRegistry(85 个 @AgentTool + MCP 动态)、SkillLoader(4 层 scope)、HooksRegistry(13 事件)。CC 对应 = tools.ts 注册表 + skills/ + hooks

L4 Adaptersproviders/ · protocols/ · router/ · sandbox/ · client/

四轨执行器(service/mcp/cli/client)+ 5 家 provider 经厂商中立 IR + ★ModelRouter(CC 完全没有的一层)+ per-user Docker 沙箱

↓ HTTPS/SSE 到上游厂商
L5 Displayartifact/ · A2UI

Canvas artifact(13 类型 + append-only 版本链 + 自动存盘工作区)。CC 对应 = 终端里的工具卡片折叠 + StreamingMarkdown

横向插入所有层
L6 Cross-cuttingtrajectory/ · quota/ · storage/ · memory · devices/

HMAC 审计哈希链、org/user 双 scope 月度配额、blob 存储、文件化记忆、设备管理。CC 对应 = cost-tracker + transcript 落盘(本地 JSONL,无审计语义)

三个最重要的文件:如果只看三个文件,看 services/messages.service.ts(2947 行,主循环 + failover + 上下文组装全在这)、tools/tool-registry.service.ts(工具怎么被治理着执行——所有调用的唯一收口)、protocols/(厂商中立 IR + 双协议编解码,多 provider 的地基)。对应 CC 的 query.ts / toolExecution.ts / claude.ts。

01一条消息的一生 ★

与 CC 篇同构的主线:从前端 POST 到 SSE 流回完整回复,共 12 站。每站底部灰绿色小字是 CC 的对应站点。

1

HTTP 入站:SSE Controller

前端 POST /agent/messages/stream。Controller 设 SSE 头(X-Accel-Buffering: no + flushHeaders)、每 15s 写 : ping 心跳注释行;resolveActor 从 JWT 解出 userId/orgId,devices.touchAndAssert 校验设备未被撤销(撤销 → 403)。

controllers/messages.controller.ts:124,146-172 · devices/devices.service.ts:31

CC 站 1-3:终端按键 → Ink 事件总线 → processUserInput 分流。CC 没有「设备」概念——终端就是设备。

2

前置门:hook 拦截 → 超长守卫 → 配额

fireUserPromptSubmit(hook 可 reject 或改写 prompt)→ 输入超长边界(MAX_USER_PROMPT_CHARS=50000,超了回提示气泡拒绝而非静默截断,不调 LLM 不计 quota,I-24)→ quota.assertAllowed(org+user 双 scope 月度配额,超硬限 403)。

messages.service.ts:1084-1191 · utils/prompt-size-guard.util.ts · quota/quota.service.ts:45,81

CC 站 3:UserPromptSubmit hook exit 2 拦截——同一个钩子位。CC 无配额层(个人订阅限流在 API 侧)。

3

历史加载:树形消息沿 active path 回溯

消息是不是链(编辑/重生成 = append 兄弟节点 + 移 activeLeafMessageId 指针,append-only,I-14)。buildActivePath 沿 parentMessageId 从叶子回溯得到喂模型的单链;大字段经 blobService.hydrateMessages 从 MinIO 还原(>64KB 的 content 落 blob,行内只存 ref)。

messages.service.ts:694,1253-1270 · core/storage/platform-storage.service.ts:48-53

CC:本地 JSONL transcript 顺序读,无树形分支。CC 的「大输出落盘」对应 FFAI 的 blob(CC 落文件系统,FFAI 落 MinIO + org 隔离 sha256 去重)。

4

组装 system prompt:八段拼接

buildSystemContent 拼:BASE_SYSTEM_PROMPT(身份+工具规则)→ persona 指令 → org 记忆段(usage 衰减选材)→ 环境段(日期只到「日」,避免 bust prompt cache)→ coordinator 段 → skills 清单 → Canvas artifactRefs(cap 5)+ storageFileRefs(cap 10)→ 会话工作区文件 manifest(根治「附件只活一轮」失忆)→ 个人记忆快照(USER.md + MEMORY.md,共享上下文时跳过——隐私边界 I-31)。

messages.service.ts:2541-2697 · services/memory-snapshot-cache.service.ts

CC 站 4/6:system prompt 数组分段缓存 + CLAUDE.md。关键差异:CC 把 CLAUDE.md 拼在消息数组最前而非 system prompt;FFAI 全部进 system content。CC 的静态段打全局缓存断点,FFAI 靠「日期粒度到日」保前缀稳定。

5

入循环前压缩 + 每轮 context_usage

turn 起点跑 summarizeOldHistory(超 8000 token 让 qwen-turbo 把旧历史压成一条 9 段摘要)+ compactHistory(预算 12000,保护当前 ask 不截断)。循环内每 iter 发 context_usage 事件(percentUsed + ok/warn/auto/critical 四档),达到 autoCompactThreshold 触发全量压缩(连续失败 3 次熔断)。

messages.service.ts:1334-1345,1565-1703 · engine/query-engine.service.ts:128-189,173-185

CC 站 5:queryLoop 每轮开头四连(裁剪+microcompact+auto-compact 检查)。阈值公式两边一致到常量级:都是 window − 20000(摘要预留)− 13000(缓冲)。这不是巧合——FFAI 显式对标了 CC autoCompact.ts。

6

★ ModelRouter 决策(CC 没有这一站)

modelRouter.decide:并发拉 PROJECT → USER → ORG 三层规则,按 priority 内存匹配(AND 语义 + 数值比较);无规则命中走 default tier(openai 可用则 gpt-5.5),轻 turn(无媒体 + 上下文 ≤1500 + 非 code/reasoning)自动降 small 档省钱。决策连同 reasoning 落 ModelRoutingDecision 表(管理员 dashboard 可审计),并 yield routing 事件给前端。

router/model-router.service.ts:61,89-121,552 · messages.service.ts:1414-1471

CC:单 provider(Anthropic),模型由用户 /model 手选,无路由层。这是 FFAI 的 G10 核心差异化。

7

调模型:候选链 + IR 编码 + SSE 消费

buildStreamCandidates 组 [primary, ...fallbacks](剔 mock、剔不可服务组合);请求经厂商中立 Normalized IR 编码成 Anthropic Messages 或 OpenAI Chat Completions wire 格式,SSE 逐行解码回 IR chunk。45s stall watchdog:距上个业务 chunk 超时(心跳「:」刻意不续命)→ reader.cancel() + 抛 stream_stalled

messages.service.ts:2933,1733-1745 · protocols/sse-line-reader.ts:30-100 · protocols/protocol-client.ts:25

CC 站 7:官方 SDK 单厂商,90s idle watchdog + 30s stall 日志。CC 不用 SDK 的 BetaMessageStream(O(n²)),FFAI 干脆整个 SSE 解析自研(要伺候 4 种 wire 方言)。

8

流式出流:text_delta 边收边 yield

每个 IR chunk 立即转 SSE 事件推给前端:text_delta(打字机)、tool_args_delta(Canvas 工具的 content 字段流式预览——artifact 在右栏「长」出来)、routing/compact_warning/context_usage。前端 EventSource 消费,React 渲染。

messages.service.ts:386-420,1756-1788

CC 站 8:StreamingMarkdown + Ink 帧 diff 只重画变化的终端单元格。同一个「边流边渲染」思想,画布从终端换成浏览器。

9

tool_use → 治理流水线(唯一收口)

凡工具调用必经 ToolRegistry.invoke(零绕过,I-21):zod 校验 → IAM 授权 hook → destructive 二次确认(返 PERMISSION_REQUIRED 中断 turn)→ 幂等去重(写工具 Redis 120s dedup)→ 执行 → 异常三档分类 → 出口脱敏(sk-/AKIA/PEM/JWT/连接串掩码,开关 import 时冻结防注入关闭)→ 超 50000 字符落盘换 preview。

tools/tool-registry.service.ts:175-275 · tools/governance/*

CC 站 9:Zod → PreToolUse hook → 权限弹窗三道关。CC 的「权限」是问用户;FFAI 的「治理」是问制度——RBAC、幂等、脱敏、审计都是无人值守也必须成立的关。

10

四轨执行:进程内 / MCP / Docker / 桌面 RPC

service: 直接调 NestJS 业务方法(继承 RBAC+DataScope);mcp: 官方 SDK callTool(stdio env 剥离宿主凭据);cli:/沙箱轨进 per-user Docker 容器(network=none + cgroup 2g/2cpu/512pids);client: 经 WS 双向 RPC 派发到用户桌面(30s 超时,本地层可独立拒绝 I-28)。读工具并发批、写工具串行——与 CC 完全同款调度。

messages.service.ts:266-283,2326-2340 · services/mcp-manager.service.ts:219 · sandbox/session/docker-sandbox-environment.ts:390 · desktop/desktop-bridge.gateway.ts:178

CC 站 10:所有工具都跑本机(spawn 进程 / Seatbelt/bwrap 沙箱),只读并发 10 个。FFAI 把「本机」拆成了四个不同信任级的执行域。

11

结果回填,回到第 5 站

tool_result 按原序 yield + 以 role:'tool' 追加进 loopMessages,iter += 1; continue。上限 MAX_ITER=100;每 25 iter 复查配额;iter 末跑 microCompact(折叠旧的可再生工具输出,保护最近 3 轮 + cache 前缀)。

messages.service.ts:1541-1551,2346-2469 · engine/query-engine.service.ts:125-171

CC 站 11:state = next; continue。CC 无迭代上限(靠 maxTurns 参数),FFAI 硬编码 100 兜底。

12

收尾:落库 → 审计链 → 成本 → done

无 tool_use 的一轮是终点:fireStop hook(可注入 prompt 逼模型续推——CC Stop hook exit 2 的同款语义)→ 落 ASSISTANT_TEXT + TURN_DONE 消息 → trajectory 哈希链记 TURN_DONE → recordOutcome(回填路由决策真实 cost/latency)+ quota.recordUsage(org+user 双计)→ yield done,前端收流。

messages.service.ts:1953-1994,2472-2537 · trajectory/trajectory.service.ts:52

CC 站 12:Stop hooks → transcript 落盘 → 成本汇总。FFAI 多出的是「审计哈希链」和「路由学习数据」两笔账。

02TAOR 主循环:runTurnStream

整个产品的心脏。2947 行的 messages.service.ts 里是一个 while(true),每次迭代 = 一次「调模型 + 执行工具」的回合。

2.1 调用栈对照

FFAI vs CC 调用关系
── FFAI ────────────────────────────────────────────────── POST /agent/messages(/stream) └─ MessagesController.postMessageStream() [messages.controller.ts:124] SSE 壳 + 心跳 └─ runTurnStream() [messages.service.ts:1024] AsyncGenerator,真正的 while(true) ├─ QueryEngine(只做 compaction) [engine/query-engine.service.ts] └─ runTurn() = 同步 wrapper 内部 drain 同一个 generator [:965,Teams/cron 用] ── Claude Code ─────────────────────────────────────────── 用户输入 └─ QueryEngine.submitMessage() [QueryEngine.ts:209] 会话经理 └─ query() [query.ts:219] 薄壳生成器 └─ queryLoop() [query.ts:241] while(true)
vs Claude Code

结构同构:都是 async generator 流式吐消息、外壳可换(CC:REPL/headless/SDK;FFAI:SSE/同步 runTurn 给 Teams 和 cron)。历史趣闻:FFAI 曾计划让 QueryEngine 承载 TAOR(对齐 CC 命名),但那份 runStreaming 骨架从未接线,2026-07-02 作为零调用伪代码删除——主循环事实上长在 messages.service。CC 的分层更干净(会话经理/干活分离),FFAI 的主循环和会话管理耦合在一个 2947 行的 service 里,这是已知的结构债。

2.2 一轮迭代的完整步骤

阶段做什么位置(messages.service.ts)
A 取消检查signal.aborted → finalStopReason='cancelled' break:1542-1545
B 配额复查每 25 iter 一次 quota.assertAllowed:1548-1551
C 占用观测calculateTokenUsageInfo → yield context_usage(四档):1564-1577
D 自动压缩≥ autoCompactThreshold 触发;失败 3 次熔断;压完 reattach 工作内存(mode/skills/persona/最近 5 文件):1581-1703
E 调模型候选链逐个 invokeStream(signal 透传);只在未流出任何 chunk 时才切下一候选:1724-1836
F 流式解析text_delta 累积+yield;tool_call_delta 拼 args + Canvas 预览;stop 取 stopReason/usage:1756-1795
G max_tokens 抢救stopReason='max_tokens' 且未试过 → 摘要+丢最老 4 条 → continue 重试一次:1891-1950
H 终点判断非 tool_use → fireStop(hook 可续推)→ 落 ASSISTANT_TEXT → break:1953-1994
I 执行工具先串行 yield TOOL_USE 卡片 → 读写分批并发执行 → 按原序 yield TOOL_RESULT + 回填:2014-2438
J halt 分支PERMISSION_REQUIRED / pendingQuestion(ask_user) → break 等用户:2441-2458
K microcompactiter 末折叠旧工具输出(白名单 9 类可再生工具):2460-2469

终止条件汇总:end_turn(无 tool_use)/ MAX_ITER=100 / cancelled / permission_required / ask_user / turn 硬超时。ask_user 是 FFAI 特有的第一类终态——CC 的 AskUserQuestion 是阻塞式弹窗(循环原地等),FFAI 的 ask_user 直接结束 turn、把问题作为事件推给前端/Teams 卡片,用户回答开启新 turn。这是「终端同步交互」与「Web/IM 异步交互」的形态差异。

2.3 取消、硬超时与多副本

  • 取消广播:CC 是单进程,ESC → abortController.abort() 就完了。FFAI 部署多副本(pm2 cluster),取消要跨进程:TurnCancelBroker 本地 Map 命中直接 abort,miss 则 publish Redis 频道 agent:turn:cancel 广播其他副本;跨 org 取消被 CrossOrgCancelError 拒绝。services/turn-cancel-broker.service.ts:82-108
  • 端到端穿透(I-40):signal 透传到 LLM 流(4 家 provider)、web_fetch/web_search(AbortSignal.any 合并)、cli 容器(abort → container.kill())、MCP(RequestOptions.signal)。CC 同款设计(signal 传 API + 所有工具),两边都补了「合成收尾」——CC 给未执行工具补 is_error tool_result 保消息序列合法,FFAI 把 partial text 落库标 partial:true
  • turn 硬超时FFAI_AGENT_TURN_HARD_TIMEOUT_MS 默认 15 分钟,setTimeout 到期 abort 复用取消清理路径——防「idle watchdog 每次都差一点不触发但累积挂一小时」。CC 无此层(终端用户自己会按 ESC)。messages.service.ts:83-90,1067-1076
  • 无 session 级互斥锁:并发写靠 @@unique([sessionId,sequence]) + P2002 jitter 重试(最多 24 次)原子分配 sequence,而非 Redis 锁。messages.service.ts:625-661

03上下文组装与压缩

FFAI 的 compaction 设计了 5 层,实装 4 层;CC 是 3 级机制。两边的 auto-compact 阈值常量逐字相同。

3.1 压缩层级对照

FFAI(engine/query-engine.service.ts)Claude Code对比
L1 budget trim:硬 token 预算 + 保护当前 ask(超专属预算 31250 token 才 truncateMiddle):222-269工具结果预算裁剪(query.ts:379)同思路;FFAI 多了「当前输入超长直接拒绝不静默截断」的 I-24 前置门
L2 单条 tool_result 上限 2000 token 中间截断 :199-209maxResultSizeChars 30000 字符落盘CC 落盘给路径可 Read 回;FFAI 的落盘在治理 stage 9(50000 字符),L2 是喂模型前的第二道
L3 semantic summary:超 8000 token 让 qwen-turbo(便宜小模型)压 9 段摘要 :128-189auto-compact:让主对话同一个模型写 analysis+summary 9 小节(可复用缓存前缀)摘要小节结构同款(9 段);CC 用主模型换缓存命中,FFAI 用便宜模型换成本——多 provider 才有的选项
L4 pin working set:未实现(YAGNI 注释):110压缩后重注入读过的文件(最多 5 个/50K)FFAI 用「post-compact reattach 工作内存」(mode+skills+persona+最近 5 文件,PER_FILE 20K)实现了等价物 :1626-1657
L5 sliding window 默认保最近 20 对 :211-220compact 边界切断旧历史等价:都保证「摘要 + 近期」
micro iter 末折叠 9 类可再生工具输出,保护最近 3 轮 + cache 前缀 2 条 :125-171microcompact:清 Read/Bash/Grep 等可再生结果 + cache_edits 服务端增量删白名单思路一致;CC 多一个 API 侧原生 context_management(服务端 KV 缓存编辑),FFAI 没有(多厂商没这个 API)
vs Claude Code · 阈值公式

FFAI:autoCompactThreshold = contextWindow − 20000(摘要预留)− 13000(缓冲),老 session 每小时再让 2K(最多 10K);连续失败 3 次熔断。CC:window − 20000 − 13000,同样 3 次熔断。常量逐字对齐——Active Context 里明写「对齐 CC autoCompact.ts」。三层 env 开关(FFAI_DISABLE_COMPACT / FFAI_DISABLE_AUTO_COMPACT / 默认全开)也是照 CC 的 autoCompact 开关语义做的。

3.2 CLAUDE.md 的对应物是什么

CC 的分层记忆(Managed → ~/.claude → 项目逐级向上)在 FFAI 里被拆成了结构化的几段,全部进 system prompt:

≈ 项目 CLAUDE.md

Persona 指令 + 项目上下文

AgentSession 挂 personaId/projectId,persona instructions 注入 system prompt;项目工具白名单过滤工具集。

≈ ~/.claude/CLAUDE.md

个人记忆三件套(E26)

USER.md(8KB)+ MEMORY.md(16KB)+ memory/*.md 单条文件——照 CC memory 目录 + Hermes 移植,详见第 7 章。

≈ Managed settings

Org 记忆(DB)+ OrganizationAgentSettings

组织共享记忆按 usage 衰减选材注入(200 行/25KB——与 CC memdir 双重截断常量一致);org 级 allowedPermissionModes 白名单收紧。

04工具系统:四轨 + 装饰器注册

85 个 @AgentTool 装饰器(35 个文件)+ MCP 动态注册。一个工具 = 元数据 + 执行 + 可用性 + 治理标志,与 CC 的 Tool 对象同构。

4.1 ToolDescriptor vs CC Tool 接口

关注点FFAI ToolDescriptor(tools/tool.types.ts)CC Tool(Tool.ts:362-695)
身份name(OpenAI 最严正则)/ aliases / searchHint / userFacingName :12-124name / aliases / searchHint
输入扁平 inputSchema 或 inputJSONSchema 或 zodSchema(优先级递增):35-144Zod v4 单一真值
行为标志readOnly / concurrencySafe / writeAction(CI 强制显式声明,I-18) / destructive / idempotent / controlTool :65-116isReadOnly / isConcurrencySafe / isDestructive(默认 fail-closed)
可见性availability{surface[] / permissions[] / requiredCapabilities[]} + exposure 三态(direct/deferred/model_only,借 Codex):49-107被 deny 的工具在模型看到前剔除;shouldDefer 延迟加载
结果maxResultSizeChars(默认 50000 落盘)/ getToolResultText / outputFields :87-139maxResultSizeChars 30000 / mapToolResultToToolResultBlockParam
UIrenderingHint + streamingContentField(Canvas 流式长出)renderToolUseMessage / renderToolResultMessage(终端卡片)
vs Claude Code · 注册方式

CC 是静态注册表(tools.ts 编译期 feature() 摇树 + 运行期条件展开);FFAI 是 @AgentTool 方法装饰器写 reflect-metadata + AgentToolsModule.forFeature([Service]) 显式收集(static Set 绕开 NestJS @Global 多实例坑)+ bootstrap 统一 adapt 注册、重名 fail-fast。registry/agent-tool.decorator.ts:40 · agent-tool-bootstrap.service.ts:55。业务模块(合同/表单/审批/采购/M365)用一个装饰器就把方法暴露给 agent——这是「agent 长在业务系统里」的接线方式,CC 无对应(CC 的业务接入走 MCP)。

4.2 四轨执行器(CC 只有一轨:本机)

跑在哪代表工具安全边界
service:后端进程内artifact_create/patch、knowledge_query、web_search/fetch、form_*、approval_*、po_*、m365_*、memory、CronCreate、delegate_task…(最大轨)继承 RBAC + DataScope,orgId/userId 从 ctx 取、不接受 LLM 传入
mcp:后端 → MCP server(stdio/SSE)运行时按 agentMcpServer 表动态注册 mcp:<server>:<tool>stdio env 剥离宿主凭据(sanitizeEnvVars)+ 治理收口 + writeAction 保守置 true
cli:/沙箱Docker 容器cli_exec(git.log/kubectl.get/adp.cli 白名单 argv 模板)、cloud_code_exec、code_session_exec、sql_read_queryper-user 容器 network=none + capDrop ALL + cgroup 2g/2cpu/512pids;主机零执行(I-33)
client:用户桌面(Electron)file_read/write/edit/list、fs_glob/grep、clipboard_*、notify_push、shell_exec(11 个,服务端 invoke 一律拒绝)WS 双向 RPC + 本地强制层独立校验(scope+realpath+授权弹窗,I-28);shell.exec 在能力协商白名单里被服务端剔除

4.3 治理流水线:ToolRegistry.invoke 的 11 个 stage

这是 FFAI 相对 CC 最大的结构增量——所有工具调用(业务/MCP/子 agent/桥接)必经这一条收口,不存在旁路(I-21,Hermes 踩过「裸 dispatch 绕过治理」的坑后焊死):

tools/tool-registry.service.ts:175-275
stage 0 解析工具(NotFound throw) stage 1 zod 入参校验(bootstrap adapter 内,失败返 INPUT_INVALID 给模型自修) stage 3 PreHook(占位 → E20 S5) stage 4 IAM 授权 hook(AIToolGrant,flag 控 fail-open 渐进;LOCKED_SET 4 项恒放行) stage 4b destructive 二次确认 → 返 PERMISSION_REQUIRED(不执行,turn 中断等用户) stage 5 幂等去重(写且非幂等:Redis 120s,key 含 org+user+turnId+sha256(入参)) stage 7 执行(dispatchKey→桌面 WS / 否则 tool.invoke)+ 异常三档分类 (Forbidden→security / BadRequest→business / 其余→system,真实 message 都回模型) stage 8 出口脱敏 redactSensitiveText/redactDeep(sk-/ghp_/AKIA/PEM/JWT/DB 连接串, force 模式,REDACT_ENABLED import 时冻结——prompt injection 关不掉) stage 9 超 50_000 字符 → 全文落 org 隔离 blob,LLM 只拿 <persisted-output> preview
vs Claude Code

CC 的对应链是 toolExecution.ts 的三道关(Zod → PreToolUse hook → canUseTool 权限),错误同样包成 <tool_use_error> 喂回模型自修——两边连这个 XML 标签的用法都一致。CC 没有的:IAM 按人授权、幂等去重、出口脱敏、审计三档。原因还是信任边界:CC 的输出只回到机主自己的终端,FFAI 的输出会进多租户 DB、进审计链、可能被复述给别人。

4.4 四个代表性工具(对照 CC 的四个)

cli_exec —— 对照 BashTool:不是「跑什么都行的 shell」,是白名单 argv 模板
  • CC BashTool:模型给任意命令 → 权限规则匹配(prefix/exact/wildcard + 复合命令拆分 + 环境变量剥离)→ 本机 spawn(可选 Seatbelt/bwrap)。安全边界 = 权限提示系统(问机主)。
  • FFAI cli_exec:模型只能选白名单命令 + 填参数(['git','log','--oneline','-n','{count}'],count 1-1000、path 正则防注入),服务端校验后进 Docker(git 轨 network=none、128m、30s、readonly)。安全边界 = 容器 + 模板(不问任何人)。tools/cli-executor.types.ts:100-163
  • 任意命令的口子是 code_session_exec(per-user 持久容器:suspend=docker stop 保卷、resume ~1s、暖池 32、idle 10min suspend、30 天 GC 保卷)——「谁控制命令谁进容器」(I-32)。
  • 反面教材:psql.query 曾是白名单轨的一员,2026-07-02 安全审计发现 SELECT-only 只有注释没有代码(任意 SQL + COPY TO PROGRAM RCE 面)→ 移除,终态做成 sql_read_query:服务端 replica allowlist + BEGIN READ ONLY + 文本层 fail-closed 拒非 SELECT——三层强制只读(I-45)。
file_edit(client 轨)—— 对照 FileEditTool:同款「oldString 必须唯一」,校验位置搬到了用户机器

CC FileEditTool 的三重校验(必须先 Read / mtime 时间戳 / oldString 唯一性)在服务端做;FFAI 的 file_edit 是 client 工具,descriptor 声明 destructive + oldString 须唯一,但真正的强制在桌面壳层:scope 收敛(默认 ~/FFAI Workspace/)+ realpath 防符号链接 + per-capability OS 授权弹窗——「服务器已鉴权所以本地直通」被明令禁止(I-28),威胁模型是「服务器 loop 被 prompt injection 时,本地层是最后防线」。CC 不需要这层,因为 CC 的「服务器」和「本地」是同一台机器。

delegate_task —— 对照 AgentTool:CC 同步递归,FFAI 异步 spawn + 轮询
  • CC AgentTool:for await (query({...})) 递归调同一个主循环,父循环原地等子 agent 流完。
  • FFAI delegate_task:立即返回 taskId,后台 runChildAgentInBackground(建独立 child session),LLM 用 TaskGet/TaskOutput 轮询、TaskStop 真 abort。并发 cap FFAI_MAX_CONCURRENT_CHILDREN=3(对齐 Hermes),生命周期总量 20,child 硬超时 10min,结果 tail 截 8000 字符防父 context 被日志污染。services/sessions.service.ts:142-376
  • 隔离设计两边一致:child 独立 session/abortController、结束清理、父 close 遍历 abort children;差异是 CC 子 agent 砍 CLAUDE.md 省 token,FFAI 子 agent 走独立 persona + 工具子集。
  • coordinator mode(SetCoordinatorMode)注入 system prompt 让 LLM 同轮 fan-out 多个 delegate_task——2026-07-03 改异步后「真并行」才首次成立。
artifact_create —— CC 无进程内对应(harness 的 Artifact 是产品级能力)

13 种类型(MARKDOWN/HTML/CODE/MERMAID/SVG/IMAGE/FORM/APPROVAL…);streamingContentField:'content' 让前端在工具参数还在流式拼接时就把 artifact「长」出来;版本链 append-only(version+parentArtifactId 自引用,回滚=新建拷贝不删历史,I-11);MARKDOWN/HTML/CODE 自动存盘 ~/files/ 防丢失,显式 sourcePath 走 file-first(文件是单一事实源,HEAD 从文件 hydrate,D58)。artifact/artifact.service.ts:56,264,596-704

05权限、沙箱与审计

CC 的问题是「模型想做 X,允许吗?→ 问用户」;FFAI 的问题是「这个员工的这个 agent 想做 X,制度允许吗?→ 查 RBAC/配额/审计,实在要问才问」。

5.1 协作模式两轴(直接借 CC)

FFAI 明确选了 CC 的两轴正交而非 Codex 的一维 4 模式:planMode(OFF/REQUIRED,REQUIRED 时 writeAction 工具全不可见)× permissionMode(DEFAULT / ACCEPT_EDITS / BYPASS / READ_ONLY / ASK_EVERY_TIME),session 级字段 + org 级 allowedPermissionModes 白名单(admin 可禁 BYPASS)。切换走 EnterPlanMode/ExitPlanMode/SetPermissionMode 工具(controlTool 不受自身 mode 过滤——否则切不回去)。tools/tool-registry.service.ts:502-520 · prisma platform_ai.prisma:57-58

vs Claude Code · 确认弹窗的形态

CC:canUseTool 返回 Promise → 待确认项 push 进 React state 队列 → 终端弹对话框 → 用户点允许 resolve Promise → 循环原地继续。FFAI:destructive 确认返回 PERMISSION_REQUIRED errorCode → turn 直接结束,事件推给前端/Teams,确认后是新 turn。同一个「写动作前要 ask」,同步会话 vs 异步多端的两种解法。

5.2 双层授权门(CC 无对应)

  • RBAC 权限码门(恒 fail-closed,I-41):声明 availability.permissions 的工具(agent_tools:web/cli/cloud_exec/sql_read…),ctx.permissions 缺省即不可见。#1887 修的正是旧 fail-open 让主 chat 流绕过全部权限门的洞;配套 seed:web/knowledge 授全员 Employee,cli/cloud_exec 仅 Administrator。
  • IAM 逐工具 grant/revoke 门(flag 控 fail-open 渐进,I-22):AIToolGrant 按角色/用户 grant∪revoke,allow 姿态只拦显式 revoke——让授权机制先安全上线再运营收紧。LOCKED_SET 4 项(sessions_send 等)任何姿态恒放行——源自 openclaw「admin 误关 sessions_send,Teams 机器人连『无权限』都发不出」的一年踩坑。

5.3 沙箱对照

维度Claude CodeFFAI
形态本机进程 + 可选 macOS Seatbelt / Linux bwrap;源码注释直言「真正的安全边界是权限提示系统」per-user Docker 容器:network=none、capDrop ALL、no-new-privileges、cgroup fail-safe 默认(2g/2cpu/512pids/禁 swap)——「永不信任 LLM 自我约束,约束由容器机制强制」(I-33)
生命周期命令级:每次 spawn 新进程(cwd 持久是 pwd 回读技巧)用户级持久:suspend=docker stop(RAM/CPU=0 只占磁盘)、resume ~1s、暖池 32、idle 10min suspend、30 天 GC 销容器保卷(I-34「持久 ≠ 运行」)
凭据隔离MCP 子进程继承用户完整 env(机主自己的机器)MCP stdio env 剥离(BLOCKED:ANTHROPIC/OPENAI/AWS/GH token 等 pattern + 通配 *_SECRET;strict 白名单 PATH/HOME/LANG…)sandbox/backend/sanitize-env-vars.ts:2-36
SSRF不设防(本机工具)三处:图片 ingress 拒收裸远端 URL(I-38)、hook webhook assertPublicHost + redirect:manual 防 DNS rebind、web fetch bounded reader 5MiB 封顶(I-39)

5.4 审计:HMAC 哈希链(CC 完全没有的一层)

每个关键事件(TURN_STARTED / ROUTING_DECIDED / TOOL_CALL / STREAM_STALLED… 17 类)append-only 落 agent_trajectory_eventseventHash = HMAC-SHA256(macKey, prevHash + canonicalJson(payload)),macKey 从 KMS root HKDF 派生。用 HMAC 不用裸 sha256:裸哈希链持 DB 写权限者可改 payload 顺链重算蒙混,HMAC 把「能改数据」与「能伪造审计」解耦(对齐 CloudTrail);verifyChain 不做 legacy 回退防 downgrade。trajectory/trajectory.service.ts:42-137 · GET /agent/trajectory/verify/:sessionId。CC 的 transcript 是本地 JSONL——可读、可回放,但无防篡改语义(也不需要:机主改自己的日志没有审计意义)。

06模型侧:Provider / IR / 路由 / 配额

CC 是「一家厂商 × 四条认证路径」;FFAI 是「五家厂商 × 一个中立 IR × 两个协议编解码器 × 一个路由器」。

6.1 Provider 与协议层

providers/ + protocols/ 结构
Provider 层(5 家 + mock) OpenAIProvider gpt-5.5/5.4/5/5-mini/4o… openai.provider.ts:29 AnthropicProvider claude-opus-4-7/sonnet/haiku anthropic.provider.ts:25 GeminiProvider (走 Google 的 OpenAI 兼容端点) gemini.provider.ts:28 QwenProvider (走 dashscope 兼容端点) qwen.provider.ts:28 MockProvider mock-echo/fast/strong mock.provider.ts:23 │ 每家静态声明 14 项 ProviderCapabilities(vision/audio/pdf/thinking/caching…) ▼ Normalized IR(厂商中立,protocols/types.ts) NormalizedRequest / NormalizedMessage / ContentPart(text|image|audio|document) ProviderStreamChunk: text_delta · tool_call_start/args_delta/done · thinking_* · usage · stop │ ▼ 仅 2 个 ProtocolClient 承载全部 5 家 OpenAIProtocolClient → OpenAI / Qwen / Gemini(+DeepSeek/Moonshot 预留) AnthropicProtocolClient → Anthropic(+Bedrock/Vertex 预留) 共用 sse-line-reader(45s stall watchdog)+ retry.ts(5 次指数退避 ±25% jitter)
  • 出网合规门:openai/anthropic/gemini 的 isAvailable() 要求 API key FFAI_LLM_EGRESS_COMPLIANCE_CLEARED='true';qwen(国内)只查 key。CC 无此概念。
  • 错误归一化:13 个 NormalizedErrorCode(rate_limit/overloaded/auth_failed/context_overflow/stream_stalled…),HTTP 分类器 429→rate_limit、529→overloaded、400 body 关键词升级 context_overflow/content_filter。CC 的 withRetry 做同样的分类,但不需要归一化——只有一家的错误格式。
  • 重试对照:FFAI 5 次 / base 500ms / 2^n / ±25% jitter / Retry-After 优先 / background 遇 overloaded 直接 bail / 连续 3 次 overloaded 触发降级 hook。CC 10 次 / 500ms / 2^n / 0-25% jitter / Retry-After 优先 / 后台请求 529 放弃 / 连续 3 次 529 触发模型 fallback。连「后台请求不重试防容量雪崩」和「3 次过载换模型」这两个细节都对齐了。流式都遵守「已 yield 过就不再重试」(流不幂等)。
  • failover 形态:CC 是同厂商换模型(FallbackTriggeredError → fallbackModel);FFAI 是跨厂商候选链(RoutingDecision.fallbacks),只在 pre-first-chunk 降级、mid-stream 不重放,mock 候选被剔除防「真故障返假输出」。messages.service.ts:2933-2945,1729-1836

诚实的实现缺口(写文档时的代码核验发现):① ProviderRequest.effort 注释声称映射 Anthropic thinking.budget_tokens,但 anthropic-encoder 只读 thinking.budgetTokens,effort 在 Anthropic 侧是死字段;② RoutingRequest 的「历史信号」(recentSuccessRate/recentP50Latency)声明了但决策链未消费;③ LLM-routed 策略(B 策略)代码在但主链停用(交互路径 +3.7s 性价比差,#876)。

6.2 ModelRouter:CC 没有的一整层(G10)

1

三层 scope 规则匹配

并发拉 PROJECT → USER → ORG 三层 ModelRoutingRule(priority 升序),pattern AND 语义匹配(标量等值 / 数组 includes / 数值 >=<)。PROJECT/USER 命中记 SCOPE_OVERRIDE,ORG 记 RULE。

router/model-router.service.ts:89-121 · router/pattern-matcher.ts:9

2

default tier + 轻 turn 降档(D64)

无规则命中 → openai 可用则 gpt-5.5;「轻 turn」(无媒体 + 上下文 ≤1500 token + 非 code/reasoning)自动降 provider small 档(gpt-5-mini/haiku),fallback 补 medium 升档兜底——保守不误降。capability 过滤:hasImage→visionInput 等硬过滤。

model-router.service.ts:352-386,552-555,598

3

决策落库 + 学习回路

每次决策(含 BLOCKED)写 ModelRoutingDecision(request/decision/reasoning/matchSource),turn 结束 recordOutcome 回填真实 cost/latency——admin dashboard 可查「上周走了哪些模型/哪条规则/花了多少」。region-aware 模式(env 开)按数据驻留选:CN→qwen、US→anthropic、EU→当前无签约端点只有 mock。

model-router.service.ts:166-226 · router/model-router-region.ts:52-90

6.3 配额与成本(CC cost-tracker 的企业版)

  • 双 scope 月度配额:USER + ORG 并查(USER 拒绝优先),三维额度 tokens/costUsd/containerSeconds(沙箱机时单独记账——换模型不减机时所以不入软上限);软上限不拒绝只降级(degradeRequested → costPriority='budget' → 路由选便宜模型),硬上限 403。quota/quota.service.ts:45-218
  • 预算告警:hitRatio ≥ softLimitRatio 发 soft、≥1.0 发 hard;Redis setNx 去重(同月同档只发一次),USER 走邮件+Teams 私聊、ORG 走 admin 邮箱。CC 无告警(成本显示在 /status)。
  • 计价:MODEL_PRICING 前缀匹配价目表(USD/1M token,4 类 token 累加——input/output/cacheRead/cacheCreation,与 CC calculateUSDCost 同款拆分);未知模型 fallback gpt-4o 量级 + warn 提示补表。sub-agent 成本自动上溯 parent session(CC 的 sidechain 成本也归并主会话——同思路)。quota/model-pricing.ts:33-86 · quota/cost-tracker.service.ts:38-66

07记忆系统:文件化个人记忆 + DB 组织记忆

这一章 FFAI 是 CC 的「学生」——E26 明写移植 Hermes / 对齐 CC memdir,连截断常量都一样;差异全部来自多租户。

维度Claude CodeFFAI
个人记忆载体memory 目录:MEMORY.md 索引 + 单文件单事实(frontmatter + [[链接]])工作区三件套:~/USER.md(8KB,偏好+观察两段)+ ~/MEMORY.md(16KB,curator 巩固 SoT)+ ~/memory/*.md 单条(8KB)——唯一事实源=文件,DB 列已 drop(schema 兜底防双写,I-30)services/memory-file.service.ts:27-62
注入方式MEMORY.md 索引进 context,双重截断 200 行 / 25KB个人:快照全文注入(轮内冻结 + 写盘即失效的 LRU 快照缓存);组织:按 usage 衰减选材注入,同款 200 行 / 25KB 双重截断services/memories.service.ts:48-51
选材算法无(索引全塞)org 记忆 score = (usageCount+1) × 0.5^(ageDays/14天半衰期),被注入即 bump——Codex 式 usage 衰减,暂不上 embedding(5 家头部 3 家记忆召回不用向量)
写入模型直接 Write 文件memory 工具 add/replace/remove(Hermes substring 范式,oldText 必须唯一命中);写前 prompt-injection 扫描拒收;memory_search grep 有界(300 条 / 5s 预算,I-39)
巩固无(人工/模型自发)Curator 每日 03:30 cron:memory/ → MEMORY.md 巩固,铁律「只 archive 不删、pinned 跳过、幂等」
隐私边界不需要(单用户)三层护栏(I-31):共享上下文(Teams 群聊)下 prompt 层不注入 + memory 工具 fail-closed 403 + 通用 file 工具对个人记忆路径 403——少任一层 = 同等泄漏面

08扩展生态:同样的机制,收紧的口径

CC 的七种扩展机制收敛为两种本质(注入文本 / 可调工具),FFAI 全盘继承了这个收敛,然后把每个口子按多租户标准收紧。

8.1 总表对照

机制Claude CodeFFAI收紧点
Hooks27 种事件 × 4 后端(shell 命令/LLM/HTTP/agent),exit 2 阻断语义13 种事件(on_turn_start/pre_tool_use/…/stop/notification),DB 表 agent_hooks 装配,仅 http_webhook 真执行(agent_skill 留 P2);PreToolUse/UserPromptSubmit 可 reject,Stop 可续推——阻断语义同款hooks/hooks.types.ts:161 · hooks-loader.service.ts:38禁 command transport(admin 权限 → 后端 RCE 面);webhook 过 SSRF guard + redirect:manual;抛错 fail-soft 只 warn
SkillsSKILL.md 三来源(managed/user/project),inline 注入或 fork 子 agent4 层 scope:PLATFORM(git 文件)+ ORG/PROJECT/USER(DB),USER>PROJECT>ORG>PLATFORM 同名覆盖且记 shadowed;LLM 经 skill_<name> 工具触发,inline 贴 body($ARGUMENTS 替换)或 fork 真 sub-agent——两种执行方式同款skills/skill-loader.service.ts:143-255allowed-tools 白名单激活后过滤 LLM 可见工具集(CC 同有);frontmatter hooks/shell 永久声明性 NOP(I-17/I-23——CC 的内联 shell 执行语义在多租户是后门)
Sub-agent递归 query(),同步等delegate_task 异步 spawn + Task 轮询(见 4.4)并发 3 / 总量 20 / 硬超时 10min / tail 8000 字符
MCP官方 SDK,5 种 transport,工具名 mcp__server__tool官方 SDK,stdio/SSE 两种,工具名 mcp:server:tool,DB 表管理 + admin APIstdio env 剥离宿主凭据;工具经治理收口;writeAction 保守 true;server 删除同步 unregisterPrefix
斜杠命令 / 插件 / SDK60+ 内置命令、插件目录、stdin/stdout 控制协议不做(Web 产品无命令行心智;插件 = 多租户审计成本;SDK 位由 REST+SSE 承担)

另有 CC 没有的一个内置 hook:audit.hook 给全部 13 事件挂 priority 10 的审计钩子,writeAction 工具执行一对一 emit 审计事件(destructive→HIGH),输入截断 4000 字符 + 敏感键 REDACT。hooks/audit.hook.ts:69-138

09多端通道:CC 没有的整个 L0

CC 的 surface 是终端(+SDK);FFAI 的 surface 是 Web、Teams、桌面、定时任务——同一个 runTurnStream,四种消费方式。

web

SSE 流

EventSource 消费 14 种 StreamEvent;15s 心跳;断线靠 lastMessageId 拉取。三栏布局:Chats/Workspace/Agents 侧栏 + 对话 + Canvas。

teams

Bot Framework webhook

入站 @Public + Bot JWT 自验 → 后台跑 turn(webhook 不被 TAOR 拖住);出站默认原生文本(GFM 表格转围栏 + 长文分块),仅 ask_user 发 Adaptive Card 按钮;群聊 isSharedContext fail-closed(个人记忆不注入);proactive 私聊推送靠 conversationRef 捕获。teams/teams-webhook.controller.ts:65-215

desktop

Electron WS 桥

user 级常驻 WS(/agent/desktop/bridge),首帧 capability 协商(shell.exec 被服务端白名单剔除)、30s/75s 保活、client 工具 30s RPC、断连按 socket 降级 pending。服务器 loop + 本地强制层(I-28)。

cron

定时任务(E22/E23)

30s 心跳扫描 + updateMany 原子抢占防多实例双投递;skipHistory:true 每次干净起跑(防跨触发历史污染成簇漏投);两段式任务 deliverResult=false 采集段只写工作区不投递;投递失败落 lastError 可见告警不静默(I-26)。配额 per-user 10 / per-org 50。services/crons.service.ts:276-404

CC 侧最接近的对应物:print 模式(headless 消费同一引擎)≈ FFAI 的 runTurn 同步 wrapper;Agent SDK 控制协议 ≈ FFAI 的 REST+SSE 契约;CronCreate/ScheduleWakeup ≈ FFAI 的 AgentCron(但 CC 的 cron 由 harness 宿主执行,FFAI 是产品功能带投递可靠性不变量)。

10逐层对比总表

一屏看完。粗体 = 该侧独有或明显更强。

维度Claude Code v2.1.88FFAI Agent
形态 / 信任边界单用户本地 CLI;边界=机主+权限弹窗多组织服务端;边界=RBAC+隔离+审计
主循环query.ts queryLoop(1729 行文件);needsFollowUp 唯一判据messages.service runTurnStream(2947 行文件);stop_reason 判据 + ask_user/permission_required 异步终态 + MAX_ITER=100
UI自研 Ink fork(React→Yoga→ANSI 帧 diff)Next.js Web + Canvas artifact 流式长出 + Teams 卡片
Provider1 家 ×4 认证路径,官方 SDK5 家 × 中立 IR × 2 协议编解码 + 出网合规门
模型选择用户 /model 手选 + 529 fallbackModelRouter:三层 scope 规则 + 轻 turn 降档 + 决策审计落库
流健壮性90s idle watchdog + 30s stall 日志 + 非流式降级45s stall watchdog(心跳不续命)+ pre-stream 跨厂商 failover + 15min turn 硬超时
重试10 次指数退避;429 订阅不重试;529×3→fallback5 次指数退避 ±25% jitter;background bail;overloaded×3→降级 hook(同款设计语言)
Prompt cache4 断点精细管理 + 全局 scope 静态段 + sticky beta latch靠前缀稳定性(日期到日、快照冻结);无显式断点管理(多厂商 API 不一致)
压缩3 级:auto-compact(主模型摘要)+ microcompact + API 侧 context_management5 层设计 4 层实装:L3 用便宜模型(qwen-turbo)写摘要 + microcompact;阈值常量与 CC 逐字一致
工具注册静态注册表 + 编译期摇树@AgentTool 装饰器 ×85 + forFeature 收集(业务模块一行接入)
工具执行域1 轨(本机,可选 OS 沙箱)4 轨:进程内 / MCP / Docker / 桌面 RPC
工具治理Zod → hook → 权限弹窗;tool_use_error 反馈闭环11-stage 收口流水线:+IAM +幂等 +出口脱敏 +审计;同款 tool_use_error
Bash/执行任意命令 + 规则匹配 + 拆复合命令防绕过白名单 argv 模板(cli_exec)+ per-user 持久容器(code_session_exec);主机零执行
子 agent同步递归 query();父批准不泄漏给子异步 spawn + Task 轮询;并发 3/总量 20/超时 10min/tail 8000
记忆memory 目录 + MEMORY.md 索引(200 行/25KB)同构文件三件套 + usage 衰减选材 + curator cron + 共享上下文三层隐私护栏(截断常量同款)
Hooks27 事件 ×4 后端(含本机 shell)13 事件 ×1 后端(http_webhook+SSRF guard);禁 command
审计本地 transcript JSONL(无防篡改)HMAC-SHA256 哈希链 + verify API(17 类事件)
配额/成本会话成本统计 + OTelorg/user 双 scope 月度配额(含容器机时)+ 软限降级 + 预算告警
多端终端 + print + SDK + IDE 扩展Web SSE + Teams Bot + Electron WS + cron(同一引擎四消费)
消息持久化本地 JSONL;resume 恢复PG 树形消息(append-only 编辑分支 + activeLeaf 指针)+ blob 分层(64KB 阈值 MinIO + org 隔离去重)

一句话总结:FFAI 的内核(TAOR 循环 / 压缩阈值 / 重试语言 / 记忆截断 / tool_use_error 闭环 / 两轴协作模式)是对 CC 的有意识临摹——设计文档里每一处都标了出处;FFAI 的增量全部长在 CC 不需要的地方:多厂商(IR+路由)、多租户(RBAC+隔离+配额)、多端(SSE/Teams/WS/cron)、可审计(HMAC 链)。反过来,CC 在单机体验上的深度(Ink 渲染管线、prompt cache 断点精算、权限规则语法、bash 防绕过)是 FFAI 形态不需要、也确实没有做的。

11文件索引速查

按「我想看 X」检索,路径相对 backend/src/modules/agent/。

我想看…去这里
HTTP/SSE 入口 · 心跳 · 取消端点controllers/messages.controller.ts:89,124,205
主循环 · failover · 上下文组装services/messages.service.ts:1024(runTurnStream)· :2541(buildSystemContent)· :2933(候选链)
压缩五层 · 阈值 · microcompactengine/query-engine.service.ts:75-269 · :173(阈值)· :125(micro)
取消广播 · turn 硬超时services/turn-cancel-broker.service.ts:82 · messages.service.ts:83,1067
工具接口 / 注册 / 装饰器tools/tool.types.ts:12-146 · registry/agent-tool.decorator.ts:40 · registry/agent-tool-bootstrap.service.ts:55
治理流水线 · 脱敏 · 幂等 · 落盘tools/tool-registry.service.ts:175-275 · tools/governance/*
RBAC 权限门 · IAM hooktools/tool-registry.service.ts:583-627 · tools/iam-authorization-hook.service.ts:63-106
CLI 白名单 · Docker 底座 · 会话沙箱 · 暖池/GCtools/cli-executor.types.ts:100 · tools/docker-orchestrator.service.ts:118 · sandbox/session/docker-sandbox-environment.ts:390 · sandbox-orchestrator.service.ts:78 / sandbox-session-reaper.service.ts:50
sql_read_query 三层只读tools/postgres-read-query.service.ts:46,116,197
Client 工具 · 桌面 WS 桥client/client-tools.service.ts:31-239 · desktop/desktop-bridge.gateway.ts:96,178,352
MCP 管理 · env 剥离services/mcp-manager.service.ts:109,177,219 · sandbox/backend/sanitize-env-vars.ts:2
Provider ×5 · capabilitiesproviders/{openai,anthropic,gemini,qwen,mock}.provider.ts
IR 类型 · 协议编解码 · SSE 读流 · 重试protocols/types.ts:17,93,179 · protocols/{openai,anthropic}/ · protocols/sse-line-reader.ts:30 · protocols/retry.ts:39
ModelRouter · pattern · region · tierrouter/model-router.service.ts:61,352,461,552 · router/pattern-matcher.ts:9 · router/model-router-region.ts:52
配额 · 成本 · 价目 · 告警quota/quota.service.ts:45 · cost-tracker.service.ts:38 · model-pricing.ts:33 · budget-alert.service.ts:96
个人记忆 · 快照缓存 · curator · org 记忆services/memory-file.service.ts:55,148,494 · memory-snapshot-cache.service.ts · memory-curator.service.ts · memories.service.ts:93,182
Hooks 事件/registry/loader/webhook 执行器hooks/hooks.types.ts:161 · hooks.registry.ts:111-197 · hooks-loader.service.ts:38 · http-hook-executor.ts:67
Skills 加载 · scope 冲突 · 注入skills/skill-loader.service.ts:66,143,187,241
子 agent · 并发 registry · scratchpadservices/sessions.service.ts:142,259 · subagent/subagent-inflight-registry.ts:16 · scratchpad/scratchpad.service.ts:23
审计哈希链 · verifytrajectory/trajectory.service.ts:52,88,131 · controllers/trajectory.controller.ts:27
Teams webhook · 卡片 · proactiveteams/teams-webhook.controller.ts:65,126,355,388 · teams/teams-proactive.service.ts
cron 心跳 · 原子抢占 · 两段式services/crons.service.ts:276,306,358
Artifact 类型/版本/自动存盘artifact/artifact.service.ts:56,264,596,663
工作区 ~/ 路由 · manifest · binding 三层storage/storage.service.ts:73,143,190,579 · controllers/workspace.controller.ts:32
Prisma schema(session/message/blob/trajectory/hook/skill)backend/prisma/schema/platform_ai.prisma:44,249,397,590,1160,1401
设计事实源docs/modules/agent/:02-architecture.md(六层+四轨+G 原则)· invariants.md(I-1~I-47)· decisions.md · references/claude-code-reference.md