# FFAI Agent 实现方案对比矩阵（v0.2 决策实施指南）

> **本文档定位**：在 [`02-architecture.md`](./02-architecture.md) 顶层架构定稿后，**逐个功能点**对比 CC / OC / OCW 三家源码级实现，给出 FFAI v0.2 的实施选择 + 理由。
>
> **目的**：把"业界怎么做、为什么、我们怎么做、为什么"全部理清楚，让每个 PR 实现时能直接对照源码 + 选型 + 取舍。
>
> **源码事实源**：
> - CC = [`claude-code-reference.md`](./claude-code-reference.md)（Claude Code 2.1.88 sourcemap 还原）
> - OC = [`openclaude-reference.md`](./openclaude-reference.md)（OpenClaude 0.11.0 MIT）
> - OCW = [`openclaw-reference.md`](./openclaw-reference.md)（OpenClaw v2026.5.14 MIT）
>
> **使用方式**：实现某个 PR 前先翻到对应功能点章节，看三家源码做法 + FFAI 选型，再写代码。

---

## 0. 维度说明

每个功能点用统一表格 + 决策三段式：

```
| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
```

- **CC**：闭源精品（单租 / Anthropic 直连 / TUI 主入口）
- **OC**：CC fork + 多 provider 散弹（11 vendor × 18 gateway）
- **OCW**：完全另一方向（CLI 宿主 + 多渠道 IM + A2UI + cron 隔离）
- **FFAI v0.2**：多组织 ToB Web 工作台 + Lark DS + 原生 mobile

**决策依据强度**（标在每个 FFAI 单元格里）：
- 🟢 **业界事实标准**（≥2 家做法一致）
- 🟡 **我们场景特化**（基于 G1-G9 推导）
- 🔴 **新选择**（无业界对标，调研推荐）

---

## 1. Surfaces / 接入面

### 1.1 主入口形态

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 主入口 | CLI Ink TUI | CLI Ink TUI（继承） | 任意（Gateway 中枢，多 surface 平等）| **Web 三栏 UI** 🟡 |
| 次入口 | IDE bridge + WS remote | + gRPC + Web 子项目 + Python SDK | + macOS/iOS/Android native + 25+ IM | Electron Desktop(P2) + Teams(P2) + CLI(P2) + 原生 iOS/Android(P3) |
| 端共代码 | 部分（SDK 抽象）| ❌ Web 子项目独立 | ✅ 同份 Web UI 跑多原生壳 | Web/Desktop 共用 React；Mobile 独立原生 |

**FFAI 理由**：
- 主入口 Web：G1 要求 agent = 工作台首页，业务用户场景 CLI 不适用
- React 共用 Web/Desktop：借鉴 OCW pattern，规避 OC 教训（OC 把 web 写两遍）
- Mobile 独立原生：调研发现 ChatGPT/Claude/Perplexity 全原生（强证据），G9 不计代码成本

### 1.2 流式传输协议

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 主协议 | WebSocket（CCR 远程）| SSE + WS | **WebSocket 唯一**（不用 SSE）| **SSE 主**（NestJS 自然支持）🟡 |
| 备用 | HybridTransport（读 WS / 写 HTTP）| polling bridge | polling 补漏 | 接口预留切 WS |
| 重连策略 | 指数退避 + 断线状态机 | 同 | 同 + heartbeat | 借鉴 OCW heartbeat |
| 帧格式 | Anthropic event stream | 同 | JSONL 自定义 | **JSONL（SDKMessage）** |

**FFAI 理由**：
- SSE 满足 day-1 需求，NestJS 现成；Anthropic 业界主流也是 SSE
- 留 WS 切换接口位（HybridTransport 思路在企业代理场景值得）
- 帧用 JSONL 跟 SDKMessage 对齐，方便 A2UI 增量推送

#### 1.2.x SSE 选型详解（why not WebSocket）

业界 LLM API 流式协议 95%+ 都是 SSE，**不是 WebSocket**：

| 产品 | 流式协议 |
|---|---|
| OpenAI Chat Completions stream | **SSE** |
| Anthropic Messages API | **SSE** |
| Google Gemini stream | **SSE** |
| Vercel AI SDK | **SSE**（可切 WS）|
| ChatGPT Web / Claude Web | **SSE** |

**为什么 SSE 优于 WS**（4 个理由）：

| 维度 | SSE | WebSocket |
|---|---|---|
| 方向 | server → client 单向 | 双向 |
| 协议 | 标准 HTTP（长连接 + chunked transfer）| HTTP upgrade → WS 帧 |
| 自动重连 | **浏览器 EventSource 内置** | 自己写 |
| 企业代理 | ✅ 普通 HTTP，防火墙不挡 | ❌ 部分代理要特殊配置 |
| NestJS 支持 | ✅ `@Sse` 装饰器 + RxJS | 装 `@nestjs/websockets` |
| HTTP/2 复用 | ✅ 同 TCP 跑多路 | 独立 TCP 连接 |

**Agent 数据流本质单向**：用户 POST 一次性发完 → server 持续流式输出。中止操作走独立 `POST /abort` 端点，不需要双向通道。

**WebSocket 何时该用**（FFAI 都不撞）：
- 真正双向：金融实时报价 / 协作编辑 / 在线游戏（OCW 用 WS 因为 IM 双向）
- 二进制流：实时语音 / 视频
- 极低延迟（< 50ms 互动）

**接口预留切换位**：`QueryEngine.submitMessage()` 返回 `AsyncGenerator<SDKMessage>` 这层不变，只换 Controller adapter（SSE → WS），1-2 天工作量。未来如需 agent 主动推送高频通知 / 协作场景再切。

### 1.3 多端 UI 复用策略

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 共享单元 | SDK 类型 | 各自写 | **共享 Web UI 编译产物** | **`packages/agent-renderer-lark/`** 🟢 |
| 共享物 | TS types | 各自 fork | Lit Web Components | React 组件 + JSON schema 渲染器 |
| 原生壳 | N/A | N/A | Swift/Compose 套 WebView | Electron Node（Desktop）+ Swift/Kotlin（Mobile 原生独立） |
| 协议契约 | SDK | 各自 | sdk-types/ 包 | **`packages/agent-protocol/`** + codegen Swift/Kotlin |

**FFAI 理由**：直接借鉴 OCW；OC 那种 Web 子项目独立写一份是反例。

### 1.4 IM 渠道适配（Inbox 抽象）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 是否抽象 | N/A | N/A | ✅ 25+ 渠道 normalize | ✅ day-1 入架构 🟢 |
| 首批渠道 | — | — | Discord/Slack/WhatsApp 等 | **Teams 优先**（公司内部）🟡 |
| 消息归一 | — | — | `src/channels/plugins/normalize/` | 参考 OCW + Adaptive Card 投影 |
| Turn 状态机 | — | — | `src/channels/turn/kernel.ts` 9-stage | 借鉴 9-stage |
| 配对挑战 | — | — | DM 配对码 + allowlist | AAD ↔ FFAI 邮箱兜底 + 配对 |

**FFAI 理由**：OCW 是唯一做过多渠道 inbox 的，直接借鉴 9-stage Turn 状态机 + normalize + 配对模型。

---

## 2. QueryEngine 主循环

### 2.1 TAOR 状态机

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 模式 | Think→Act→Observe→Repeat | 同 | 不自跑（CLI 宿主）| **TAOR 自跑** 🟢 |
| 单文件大小 | `query.ts` ~unknown | `query.ts` 1914 行 + `QueryEngine.ts` 1430 行 | `agents/cli-runner.ts` | NestJS `QueryEngine` service |
| 入口 | `submitMessage()` AsyncGenerator | 同 | enqueueCliRun | `*submitMessage(): AsyncGenerator<SDKMessage>` |
| 会话状态 | 内存 + JSONL | 内存 + JSONL → SQLite | 内存 + transcript 事件流 | **per-session 实例 + PG 持久化** |

**FFAI 理由**：CC/OC 路线（自实现 loop）跟我们多组织审计/quota/隔离需求契合；OCW "宿主第三方 CLI"模式是个人 gateway 妥协，不适用 SaaS。

### 2.2 stop_reason 处理

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| `end_turn` | 出循环返回用户 | 同 | N/A | 同 🟢 |
| `tool_use` | 等工具完成回灌下轮 | 同 | N/A | 同 🟢 |
| `max_tokens` | 触发 reactive_compact | 同 | N/A | 同 + 推 `compact_boundary` SDKMessage |
| `stop_sequence` | 自定义 stop | 同 | N/A | 同 |
| post_sampling hook | end_turn 后调钩子决定继续 | 同 | N/A | **取**（自动 verify / 自动重试场景）|

**FFAI 理由**：CC 的 stop_reason 路由就是工业标准，不需要重新设计。

### 2.3 流式工具执行（Streaming Tool Executor）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 边流边执行 | ✅ TrackedTool 状态机 | ✅ StreamingToolExecutor | N/A | ✅ 取 CC pattern 🟢 |
| 状态机 | queued/executing/completed/yielded | 同 | — | 同 |
| 并发分批 | partitionToolCalls 提前分批 | 依赖图分析（Bash↔FileEdit 串行）| — | 借鉴 OC 依赖图（更智能）|
| 互斥 | concurrency-safe 标志 | 同 | — | 取 |
| 错误级联取消 | siblingAbortController | 同 | — | 取（一个失败可选取消同批）|

**FFAI 理由**：Streaming + 并发是体感快的关键。CC 的 TrackedTool 状态机 + OC 的依赖图分析结合用。

### 2.4 turn 内串行化

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 防同会话并发 turn | 单进程天然 | 同 | enqueueCliRun（per-session 队列） | **Redis lock per-session** 🟡 |
| 多实例部署 | 无（单租）| 无 | 文件锁 | NestJS 多实例必须 Redis lock |

**FFAI 理由**：多实例部署（k8s 多 pod）必须分布式 lock，单进程 mutex 不够。

---

## 3. Tool 系统

### 3.1 Tool 接口形状

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 接口 | `Tool.ts` 8 生命周期方法 | 同（fork） | `ToolDescriptor` 元模型 + Plan | **结合：CC Tool 接口 + OCW Descriptor** 🟢 |
| 字段 | name / desc / inputSchema / call / render×2 / isReadOnly / isEnabled / isConcurrencySafe | 同 | + owner / executor / availabilityExpr / surfaces | 取超集 |
| 内置工具数 | 43+ | 49 | 100+（含 channel/provider 等扩展）| 按域裁剪到 ~20（见 §3.7）|

**FFAI 理由**：CC/OC 接口是工业标准；OCW 加的 availabilityExpression + owner/executor 拆分对多组织灰度上线 + 工具路由特别契合。

#### 3.1.x FFAI 四轨 executor 的业界定位

业界 agent 框架的"工具"定义方式：

| 框架 | "工具"形态 | 是否显式分 executor 类型 |
|---|---|---|
| LangChain / LangGraph | Python 函数 | ❌ |
| Vercel AI SDK | `tool({ execute: async () => ... })` | ❌ |
| OpenAI Functions/Tools | JSON schema + 任意 backend 实现 | ❌ |
| Anthropic Claude Agent SDK | TS/Python 函数 | ❌ |
| OpenAI Apps SDK | MCP server | ❌（单一协议）|
| Microsoft Copilot Studio | Topic / Plugin / Connector | ✅ 部分 |
| Salesforce Agentforce | Apex / Flow / External Service | ✅ |
| **CC / OC** | Tool.ts 函数 + MCP client | 部分（内置 vs MCP）|
| **OCW** | **ToolDescriptor owner/executor 拆分** | ✅ 最结构化 |
| **FFAI v0.2** | **四轨：service / mcp / cli / client** | ✅ |

**业界事实标准（90% 框架）就两轨**：
- **In-process 函数**（业界主流）= FFAI 的 `service:`
- **MCP server**（Anthropic 推的新协议）= FFAI 的 `mcp:`

FFAI **独特处**：把 `cli:` 和 `client:` 单独建模成 executor 类型。理由：

| 不显式建模（业界主流） | 显式建模（FFAI） |
|---|---|
| service 内部 spawn 子进程跑 CLI | `cli:` executor 独立路径 |
| 每个 service 自己处理沙盒/超时/参数白名单 | **Dispatcher 统一 Docker 沙盒 + 命令白名单** |
| 安全策略散落各处 | **集中策略，多组织内部审计可控** |
| 误操作风险高（直接 shell exec） | **强制走 Docker per-user + network 限制** |

`client:` 同理——业界除了 Claude Code / Cursor / Cline 这类 IDE agent，几乎没人做（大部分 agent 不操作用户本地机器）。FFAI G3（Desktop + Mobile）+ G4 本地能力使其必备。

#### 3.1.y `service:` Executor 实现细节

**核心设计理念**：业务规则 source of truth 在 NestJS Service，**agent 调跟 REST API 调走同一条路径**，自动复用事务 / 审计 / 权限 / 事件。

**1. 工具注册（启动一次，装饰器自动扫描）**

```typescript
// backend/src/projects/projects.service.ts
@Injectable()
export class ProjectsService {
  @AgentTool({
    name: 'Project.search',
    description: '按关键词搜索项目，返回最多 20 条',
    inputSchema: z.object({
      query: z.string().min(1).max(100),
      status: z.enum(['active', 'archived', 'all']).optional(),
    }),
    isReadOnly: true,
    isConcurrencySafe: true,
  })
  async search(input, ctx: AgentContext) {
    return this.prisma.project.findMany({
      where: {
        organizationId: ctx.currentOrg.id,  // ← DataScope 自动应用
        OR: [
          { title: { contains: input.query } },
          { code: { contains: input.query } },
        ],
      },
      take: 20,
    })
  }
}
```

启动钩子反射所有 `@AgentTool` → 注册到 `ToolRegistry`。

**2. System prompt 构造**

LLM 看到的 tools：

```json
[
  {
    "name": "Project.search",
    "description": "按关键词搜索项目...",
    "input_schema": { "type": "object", "properties": {...}, "required": ["query"] }
  }
]
```

LLM **完全不知道 ProjectsService 类存在**，只看工具名 + schema。

**3. Dispatcher 路由**

```typescript
async dispatch(toolUse: ToolUseBlock, ctx: AgentContext) {
  const desc = this.toolRegistry.get(toolUse.name)
  await this.checkAvailability(desc, ctx)
  const input = desc.inputSchema.parse(toolUse.input)
  await this.checkPermissions(desc, input, ctx)
  
  if (desc.executor.type === 'service') {
    const service = this.moduleRef.get(desc.executor.class, { strict: false })
    return service[desc.executor.method](input, ctx)
  }
  // ... mcp / cli / client
}
```

NestJS DI 容器拿 service 实例，`ctx` 携带 `currentUser` / `currentOrg` / `requestId`，**RBAC / DataScope / 审计 interceptor 全部白嫖现成机制**。

**4. 跟 MCP 的关键区别**

| 维度 | `service:` 直接调 | `mcp:` 走协议 |
|---|---|---|
| 性能 | 函数调用零序列化 | JSON 序列化 + IO |
| 事务 | ✅ Prisma transaction | ❌ 跨进程边界 |
| 上下文 | 直接传 currentUser | 要重做鉴权 |
| 审计 / 钩子 | ✅ 复用 NestJS interceptor | 要在 MCP server 重做 |
| 错误传播 | exception stack 完整 | 序列化错误 |
| 外部 agent 可调 | ❌ 不可达 | ✅ 标准协议 |

**5. 同名工具双注册**

业界 LangChain / Vercel AI 做不到——一个工具就一个 execute 函数。

FFAI 可以：

```typescript
@AgentTool({
  name: 'Project.search',
  executors: ['service', 'mcp'],  // 双源
})
async search(args, ctx) { /* 业务逻辑只写一份 */ }
```

- 内部 agent 调 → 走 `service:`，零开销
- 外部 Claude Code 接 FFAI MCP server → 走 `mcp:`

业务规则**只写一次**，对外接口形态有两个。

### 3.2 ToolDescriptor 扩展字段（OCW 借鉴）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| availabilityExpression | ❌ | ❌ | ✅ `allOf/anyOf` + 6 signal | ✅ 取 🟢 |
| owner vs executor 分离 | ❌ | ❌ | ✅ core/plugin/channel/mcp × core/plugin/mcp | ✅ + cli + client 共四 executor |
| 协议投影 | 私有 schema | 同 | ✅ toToolProtocolDescriptor | ✅ 取 |
| 不可用诊断 | text "tool not available" | 同 | 结构化 signal | ✅ 取（multi-tenant 灰度场景必备）|

**FFAI 理由**：多组织灰度（feature flag / role gate / org policy）必须结构化诊断。

### 3.3 Tool Dispatcher / 权限

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 权限三态 | allow/deny/ask | 同 + 多组织审计 | + Approval 多路由 | ✅ 三态 + 多租审计 🟢 |
| 权限规则语法 | `Bash()` / `Read()` / `Write()` 格式 | 同 | + plan/apply 凭据矩阵 | 取 CC 语法 + OCW plan/apply |
| canUseTool hook | ✅ | ✅ | ✅ | 取 |
| PreToolUse hook 短路 | ✅ | ✅ | ✅ | 取 |
| ToolPermissionContext | 模式 default/bypass/auto/scripted/ask | 同 | + DM Approval | 取 + per-org 配置 |

**FFAI 理由**：CC 的权限规则语法是业界 de facto；ToolPermissionContext 模式给运维灵活度。

### 3.4 Tool 沙盒执行

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| OS 沙盒 | macOS sandbox-exec / Linux landlock / Docker | 同 + Termux/proot | 非 OS（同进程 + 软约束）| **看 executor 类型** 🟡 |
| service: | N/A 不存在 | N/A | N/A | 进程内 |
| mcp: | MCP server 自管 | 同 | 同 | MCP server 自管 |
| cli: | N/A | N/A | N/A | **Docker per-user + 白名单 + network 限制** 🟡 |
| client: | N/A | N/A | N/A | **OS 沙盒**（macOS sandbox-exec / Win AppContainer / iOS App Sandbox / Android scoped storage）|

**FFAI 理由**：四轨执行器不同沙盒策略；内部多用户场景 Docker 已够，不需要 E2B/Firecracker。

### 3.5 MCP 集成

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| MCP Client | stdio/SSE/HTTP/WS/SDK 五 transport | 同 | 部分 | 取四 transport（不要 SDK）🟢 |
| MCP Server 形态 | 客户端连第三方 | 同 | 包装 channel 暴露 | **我们暴露**（FFAI 业务 service → MCP server，给外部 agent 用）|
| 工具命名 | `mcp__<server>__<tool>` | 同 | 同 | 同 |
| Resources / Prompts | 部分 | 同 | 同 | day-1 只做 tools，后期 resources |

**FFAI 理由**：FFAI 既是 MCP client（消费第三方）也是 MCP server（暴露业务工具给外部 agent 客户端），双向。

### 3.6 工具发现（OC 独有）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| DiscoveryService | ❌ | ✅ 三层缓存（静/新鲜/过期降级）| ❌ | **简化版** 🟡 |
| 动态发现 | ❌ | ollama /api/tags + openai /models + custom | ❌ | day-1 只 mcp:list_tools 远程发现 |
| TTL | — | 1d / 1h 可配 | — | 5 分钟（day-1）|
| 离线降级 | — | ✅ | — | 取（断网时用 cache）|

**FFAI 理由**：day-1 只对动态 MCP server 做发现；其他静态注册。

### 3.7 内置工具清单（FFAI 选取）

| 工具 | CC | OC | OCW | FFAI Phase |
|---|---|---|---|---|
| `AskUserQuestion` | ✅ | ✅ | ✅ | **P1 必备** |
| `Display.render` / `Display.snapshot` (A2UI) | ❌ | ❌ | ✅ Canvas | **P1 必备** 🟢 |
| `Agent.spawn` | ✅ AgentTool | ✅ | ✅ | **P1 必备** |
| `Skill.invoke` | ✅ | ✅ | ✅ | **P1 必备** |
| `TaskCreate/Update/List` | ✅ 7 任务类型 | ✅ | ✅ | **P1 必备**（简化为 3 类）|
| `ToolSearch` | ✅ | ✅ | ❌ | **P1 必备**（大工具集时 relevance 筛选）|
| `Project.*` (MCP) | N/A 业务工具 | N/A | N/A | **P1 必备** |
| `Approval.*` (MCP) | N/A | N/A | N/A | **P1 必备** |
| `Knowledge.search` (MCP) | N/A | N/A | N/A | **P1 必备** |
| `WebSearch` / `WebFetch` | ✅ | ✅ | ✅ | **P1**（org policy 门控）|
| `Monitor` / `Sleep` | ✅ | ✅ | ✅ | **P2** |
| `ScheduleWakeup` / `CronCreate` | ✅ | ✅ | ✅ cron 中枢 | **P2** |
| `EnterPlanMode` / `ExitPlanMode` | ✅ | ✅ | ❌ | **P2** |
| `SendMessage` | ✅ | ✅ | ❌ | **P3** |
| `LocalFile.read/write/list` (client) | Read/Edit/Write | 同 | N/A | **P2 (PR12)** 🟡 |
| `Clipboard.*` (client) | ❌ | ❌ | ❌ | **P2 (PR12)** 🔴 |
| `Notify.push` (client) | ❌ | ❌ | ✅ | **P2 (PR12)** |
| `LocalShell.exec` (client) | Bash | 同 | ❌ | **P2 (PR13 单独)** 🟡 |
| `Git.*` / `Kubectl.*` (cli + Docker) | Bash 包装 | 同 | ❌ | **P2 (PR15)** 🟡 |
| Voice / Realtime transcription | ❌ | ❌ | ✅ | **不做** |
| `EnterWorktree` / `ExitWorktree` | ✅ | ✅ | ❌ | **不做**（FFAI 不是 git agent）|
| `TeamCreate/Delete` | ✅ | ✅ | ❌ | **不做**（YAGNI）|

---

## 4. Provider 抽象

### 4.1 Registry / ProfileResolver

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| Registry | 隐式（单 provider）| ✅ 全局单例 5 Map | ✅ | ✅ 取 OC 🟢 |
| ProfileResolver | 配置 | ✅ 字符串 → ResolvedProfileRoute | ✅ | ✅ 取 OC，**per-tenant + per-user-override** 🟡 |
| Preset | 直绑 | ✅ 向后兼容 | ✅ | day-1 不做 preset，per-org 配置 |
| 配置位置 | env var | ~/.openclaude/profile.json | ~/.openclaw/auth-profiles/ | **`AgentProviderProfile` PG 表 per-org** |

**FFAI 理由**：多组织必须 per-org profile；OC 的 per-user JSON 不适用。

### 4.2 协议归一 / OpenAI Shim

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 内部 IR | Anthropic Messages | **OpenAI Chat/Responses** | OpenAI 兼容 | **OpenAI 协议作 IR** 🟢 |
| Shim 实现 | 不需要（只接 Anthropic）| `openaiShim.ts` 双向转换 | 借鉴 OC | 借鉴 OC + 简化 |
| OpenAI → Claude tools | ❌ | ✅ | 同 | 取 |
| 推理内容映射 | ❌ | ✅ DeepSeek thinking → Claude thinking block | 同 | 取（Anthropic extended thinking 也走这条）|
| 流式 delta 差异 | Anthropic 一种 | ✅ delta vs chunk_type 适配 | 同 | 取 |

**FFAI 理由**：内部 IR 用 OpenAI 协议是业界共识（LiteLLM / OpenRouter / Continue / Cline 都这样）；Anthropic 当作"特殊 provider"通过 capability 位暴露独门特性。

### 4.3 ModelProvider 接口

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 接口字段 | name / stream / cost / context | + capabilities + models | 类似 | 取 OC + 加 capabilities 🟢 |
| Capabilities 位 | 部分 | 部分 | 部分 | streaming / toolCalling / parallelToolCalls / promptCaching / extendedThinking / jsonMode / structuredOutputs / visionInput / audioInput |
| 实现矩阵 | Anthropic | 11 vendor × 18 gateway | 40+ extension | **OpenAI + Anthropic + Mock**（day-1）+ LiteLLM 兜底 |

**FFAI 理由**：day-1 接 2 家就够验证抽象；LiteLLM 兜底覆盖未来。

### 4.4 Failover / 故障转移

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 错误结构化 | 一般 Error | 一般 Error | **FailoverError**（reason/provider/model/profileId/status/code/sessionId/suspend）| ✅ 取 OCW 🟢 |
| 转移链 | ❌ | 部分 cooldown | ✅ priority 链 + cooldown | ✅ priority 链 |
| Cooldown 探测 | ❌ | ✅ | ✅ | 取 |
| Quota 跨账号轮转 | ❌ | ❌ | ✅ multi-account OAuth 池 | 后期（如果接 ChatGPT/Claude 个人订阅会用到）|

**FFAI 理由**：FailoverError 是 OCW 独门设计，结构化错误对运维 / cost 优化都关键。

---

### 4.5 ModelRouter（G10 核心差异化）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 模型路由 | ❌（单 provider）| ✅ `agentRouting` 配置（**仅 sub-agent type 1 信号**）| ❌（仅手动 model picker wizard）| **✅ 5 信号源 + 3 策略 + 学习反馈** 🟢 |
| 信号源数 | — | 1 | 0 | **5**（task / context / 偏好 / 历史 / 成本）|
| 路由策略 | — | rule-based | 手动 | **rule + LLM-routed + scope-override 三策略** |
| 透明度 | — | 配置 JSON 可见 | 用户手动选 | **admin Dashboard：每次决策 reasoning / cost / latency / success** |
| 学习反馈 | ❌ | ❌ | ❌ | **PR15.7 起：定期分析 ModelRoutingDecision 数据，输出规则调整建议** |
| Per-scope 配置 | ❌ | global 单层 | global 单层 | **三层 scope：project > user > organization** |

**OC `agentRouting` 配置示例**（FFAI 兼容并扩展）：

```json
{
  "agentModels": {
    "cheap-model": { "base_url": "...", "api_key": "..." },
    "strong-model": { "base_url": "...", "api_key": "..." }
  },
  "agentRouting": {
    "Explore": "cheap-model",
    "Plan": "strong-model",
    "default": "strong-model"
  }
}
```

OC 这套**只用 sub-agent type 1 个信号**做路由。FFAI 扩展：

```yaml
# FFAI rule-based 路由（多信号组合）
- pattern: { subAgentType: 'Explore' }                  # 兼容 OC 模式
  selectedModel: 'anthropic/claude-haiku-4.5'
  
- pattern: { taskType: 'vision', hasImage: true }       # 模态信号
  selectedModel: 'openai/gpt-4o'
  fallbacks: ['anthropic/claude-opus-4.7']
  
- pattern: { contextTokens: { '>': 200000 } }           # 上下文长度信号
  selectedModel: 'google/gemini-2.5-pro'
  
- pattern: { surface: 'mobile', latencyPriority: 'realtime' }  # 偏好信号
  selectedModel: 'anthropic/claude-haiku-4.5'
  
- pattern: { projectTag: 'confidential' }               # 合规信号
  selectedModel: 'azure-openai/gpt-5.4'                  # 仅 Azure 部署
```

**FFAI 跟 ProviderFailoverChain 联动**：`RoutingDecision.fallbacks` 直接喂给 FailoverChain，失败自动切下一个 model（不是手动重试）。

**学习反馈闭环**：
```
agent 每次调 ModelRouter
  → 写 ModelRoutingDecision 表（含 request 5 信号 + actualCost + latency + success）
  → 后台 Job 定期分析（PR15.7）：
     - "规则 R3 触发 100 次但成功率 70%，建议下调 model tier"
     - "task=translation 上 Opus 跟 Haiku 成功率一样，但 cost 高 10×"
     - 输出建议给 admin（Gitea issue / dashboard 提示）
  → 二期：自动调整规则（带 admin 审批）
```

**FFAI 实施关键**：`ModelRouter` 是 L4 Adapter；`ModelRoutingRuleRegistry` 是 L3；QueryEngine 在 L2 调用前先问 ModelRouter 拿模型。三层 scope 解析跟 StorageBinding 同模式（project > user > organization）。

## 5. 扩展机制

### 5.1 Skill 加载与匹配

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 格式 | markdown + YAML frontmatter | 同 | 同 + requires/install/allowed-tools | 取 OCW 🟢 |
| 加载源 | 文件 + bundled + plugin + MCP 四源 | 同 | bundled + plugin + managed + workspace 四源 | **文件系统 + DB 双源**（v0.1 Q6 已锁）|
| 路径匹配 | glob + realpath 去重 | 同 | 同 | 取 |
| frontmatter 字段 | name / description / whenToUse | 同 | + allowed-tools / user-invocable / requires | 取超集 |
| 启动加载策略 | 元数据 启动加载，内容按需 | 同 | 同 | 取 |
| 热加载 | 文件 watch | 同 | 同 | 文件 watch + DB PG NOTIFY |
| 匹配触发 | / 开头精确 + LLM whenToUse 匹配 | 同 | 同 | 取 |

**FFAI 理由**：OCW 的 allowed-tools 限权字段对多组织敏感工具特别重要；其他延续 CC。

### 5.2 Plugin

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 形态 | 聚合 skill+hook+mcp+tool | 同 | TypeScript 包 + manifest | **内部用，不开放第三方** 🟡 |
| 安装方式 | Git clone | npm + bundled | npm + bundled | 内部 monorepo |
| 激活 | 立即 | 同 | onStartup: false lazy | 取 lazy |
| 第三方市场 | ❌ | ❌ | 隐式 | **不做**（day-1 多组织审计成本高）|

**FFAI 理由**：plugin 概念内部用打包 FFAI 自家功能模块；不开放第三方市场。

### 5.3 Hook 系统

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 事件数 | 11 种 | 同 | 5 类 | **5 类**（PreToolUse/PostToolUse/SessionStart/SessionEnd/UserPromptSubmit）🟡 |
| 实现形式 | Command/Prompt/HTTP/Agent 四种 | 同 | 同 | **webhook + agent skill 两种**（Q15）|
| `if` 条件 | Permission 规则语法 | 同 | 同 | 取 |
| asyncRewake | ✅ 事件驱动重评估 | 同 | ❌ | 取 |
| 4 源优先级 | bundled < plugin < managed < workspace | 同 | 同 | bundled < plugin < per-org < per-user |
| FileChanged + watchPaths | ✅ | ✅ | ❌ | **不做**（不操作本地文件）|

**FFAI 理由**：CC 的 11 事件是 coding agent 场景；FFAI 业务场景 5 类够；Command 实现形态在多组织禁止（防任意 shell）。

### 5.4 协作模式（Q34 借鉴 CC + 对照 Codex）

| 维度 | CC（最终选用）| OC | OCW | Codex | FFAI v0.2 |
|---|---|---|---|---|---|
| 模式数 | **两根正交轴** | 同 CC | 不显式 | 一维 4 枚举 | **取 CC 两轴正交** 🟢 |
| 轴 1 | Plan/Execute（`EnterPlanMode` 工具）| 同 | — | PLAN ↔ DEFAULT/EXECUTE/PAIR | ✅ 取 |
| 轴 2 | Permission mode 5 态（default/acceptEdits/bypass/scripted/ask）| 同 | — | 一维内置 | ✅ 取 5 态 |
| 切换方式 | 工具调用（`EnterPlanMode` / `SetPermissionMode`）| 同 | 命令 | 启动时枚举 | 工具调用 + admin 限制 |
| 表达力 | **10+ 组合**（4 plan × 5 perm 减去无意义）| 同 | 弱 | 4 组合 | **取 CC 灵活性** |
| 业务场景 | dev tool 单用户 | 同 | 多渠道 | dev tool | **多组织 ToB**（需要 scripted CI 场景）|

**为什么 CC 两轴 > Codex 一维**：

| 业务场景 | CC 两轴解 | Codex 一维解 |
|---|---|---|
| 业务用户做审批 | Plan + ask | PAIR_PROGRAMMING（但不能先看 plan）|
| 业务用户查询 | Execute + bypass（只读） | EXECUTE |
| IT 做批量数据导入 | Execute + scripted | ❌ 没这模式 |
| 数据分析跑长任务 | Execute + acceptEdits | ❌ 没这模式 |
| 审计敏感操作 | Execute + ask | PAIR_PROGRAMMING |

**FFAI 实施关键**：

- `AgentSession.planMode` + `AgentSession.permissionMode` 两字段（详见 01 §5）
- 切换工具 exposure = `direct` 但受 RBAC 限制（普通用户不能切 `bypass`/`scripted`）
- `OrganizationAgentSettings.allowedPermissionModes` 让 admin 禁用某些 mode（如禁 bypass 防员工误操作）
- Plan mode 期间 ToolDispatcher 过滤掉 `isReadOnly=false` 工具
- 进/出 Plan + 切 mode 都写 TrajectoryEvent

详见 [`02-architecture.md` §1.14](./02-architecture.md#114-协作模式)。

### 5.5 Slash Commands

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 来源 | 60+ 内置 + 67 目录 + plugin + skill + MCP | 118 个 | 130+ | **内置三件套（/help, /reset, /tasks）+ skill 触发** 🟡 |
| 类型 | PromptCommand / LocalJSXCommand / InteractiveCommand | 同 | 同 | 简化为 prompt + JSX（用 React 组件）|
| feature gate 控制 | ✅ GrowthBook | ✅ | ✅ availability expression | 取 |

**FFAI 理由**：CC/OC 多 surface 都需要丰富 slash（CLI 用户需要快捷指令），Web 用户对 slash 依赖度低，简化即可。

---

## 6. Sub-agent / 多 agent

### 6.1 Coordinator 模式

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 触发 | AgentTool | 同 | N/A | ✅ AgentTool 🟢 |
| 隔离 | 独立 QueryEngine 副本 | 同 | N/A | ✅ |
| 进程模型 | 同进程 + worktree + CCR 三种 | 同 + 同 | N/A | **同进程 day-1，接口预留 Temporal worker** 🟡 |
| 上下文隔离 | 主 agent 看不到子中间过程 | 同 | N/A | 取 |
| 子 → 父 总结 | 1-2k token 总结 | 同 | N/A | 取 |
| 工具子集 | INTERNAL_WORKER_TOOLS 黑名单 | ASYNC_AGENT_ALLOWED_TOOLS 白名单 | N/A | 黑名单更安全（取 CC）|

**FFAI 理由**：Q12 锁定同进程；接口设计要可未来切 Temporal worker。

#### 6.1.x "同进程 fork + resume" 详解

**名字拆开**：
- **同进程**：一个 Node 进程内，**不开新进程也不开新线程**（不是 OS `fork()` 系统调用）
- **fork**：借用 Unix 概念，实际是**创建一个新的 QueryEngine 对象**，跑在同一 event loop
- **resume**：主 agent `await` 子 agent 完成期间逻辑上"暂停"，子 agent 返回总结后主 agent "恢复"主循环

**代码示意**：

```typescript
async function* mainLoop(ctx) {
  for await (const block of llmStream) {
    if (block.type === 'tool_use' && block.name === 'Agent.spawn') {
      // Fork：创建独立 QueryEngine 实例
      const subEngine = new QueryEngine({
        sessionId: `${ctx.sessionId}_sub_${uuid()}`,
        history: [],                              // 独立空 history
        tools: filterTools(ctx.tools, BLACKLIST), // 工具子集
        tokenBudget: 50_000,                      // 独立预算
      })
      
      // 子 agent 跑自己的 TAOR 主循环
      let summary = ''
      for await (const msg of subEngine.submitMessage(block.input.prompt)) {
        if (msg.type === 'final_summary') summary = msg.content
      }
      
      // Resume：把总结回灌主 agent 继续
      yield { type: 'tool_result', toolUseId: block.id, output: summary }
    }
  }
}
```

**Token 经济学**（Anthropic Multi-agent research system 核心 insight）：

```
主 Agent ──"分析 Q3 项目延期"──▶
   │
   ├─Agent.spawn(子A 数据)──▶ 子A 跑 5 轮，消耗 10k token 探索
   │                          └─返回总结 "延期 5 个" (1k token)
   │
   ├─Agent.spawn(子B 上下文)─▶ 子B 跑 3 轮，消耗 8k token 探索
   │                          └─返回总结 "背景 Y" (1k token)
   │
   │ await Promise.all
   │
   ├─主 LLM 接到 2 份总结 (2k token)
   │
   └─▶ 用户

主 agent 增量 token：2k（两份总结）
子 agent 总消耗：18k（探索过程）
节省：主 context 不被 18k 探索污染 + 不撞主 agent token 上限
```

**对比三种 sub-agent 模式**（CC/OC 都做了三种）：

| 模式 | 在哪跑 | 通讯 | FFAI |
|---|---|---|---|
| **同进程 fork + resume** | 同 Node 进程 | await | **✅ day-1 选这个** |
| Worktree | 同进程但 cwd 不同（不同 git worktree）| 同上 | ❌（FFAI 不是 coding agent）|
| CCR / 远程 worker | 另一台机器 / 容器 | WS / RPC | 接口预留切 Temporal worker |

**FFAI day-1 选同进程的取舍**：

| 维度 | 同进程 | Temporal worker |
|---|---|---|
| 实现复杂度 | 🟢 简单 | 🟡 队列 + 序列化 |
| 启动延迟 | 🟢 0ms | 🟡 200-500ms |
| 单机 CPU 上限 | 🔴 N 个并发都吃这台 | 🟢 分布到 worker 池 |
| 长任务断电恢复 | 🔴 进程挂就丢 | 🟢 Temporal 续跑 |
| 跨实例负载均衡 | 🔴 各跑各的 | 🟢 队列分发 |
| 调试 | 🟢 stack 完整 | 🔴 跨进程难追 |

day-1 同进程足够（用户量小、并发不大）。**接口设计预留切换位**：`SubAgentExecutor` 接口隐藏"子 agent 跑在哪"，主 agent 只看到 `executor.run(input): AsyncGenerator<Summary>`，未来切 Temporal 不破代码。

### 6.2 Scratchpad（跨 worker 共享）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 实现 | 文件 `/tmp/claude-code-scratchpad` | 同 | N/A | **`AgentScratchpad` PG 表 per-session** 🟡 |

**FFAI 理由**：文件方案多实例部署会出问题；PG 行级隔离更可靠。

#### 6.2.x Scratchpad 详细用法 + PG 改造理由

**Scratchpad 解决什么问题**：sub-agent 之间想互相参考**完整数据**（不只是 1-2k 总结）的场景。

子 A 给主 agent 的 1k 总结 ≠ 子 A 能给同伴的 10k 详细数据。子 C 依赖 A/B 的发现时如果只能拿到主 agent 转发的 1k 总结 → **细节丢失**。

**典型用法**：

```typescript
// 子 A（data analyst）
async function runSubA(input, ctx) {
  const result = await analyzeDelayedProjects(...)
  
  // 详细数据写 scratchpad（同 session 内其他子可读）
  await ctx.scratchpad.write('delay-analysis', {
    projects: [...],          // 10k token 详细数据
    rootCauses: [...],
    timeline: [...],
  })
  
  return condensedSummary(result)  // 给主 agent 的 1k 总结
}

// 子 C（planner，依赖 A 的发现）
async function runSubC(input, ctx) {
  const aFindings = await ctx.scratchpad.read('delay-analysis')
  const bFindings = await ctx.scratchpad.read('business-context')
  return generatePlan(aFindings, bFindings)
}
```

**关键点**：
- A 给主 agent 的总结 ≠ A 写 scratchpad 的内容
- 总结是"给上司的浓缩"，scratchpad 是"给同事的完整数据"
- 主 agent 不感知 scratchpad

**FFAI 为什么改 PG（不用 OC 的 `/tmp` 文件）**：

| 问题 | `/tmp` 文件 | PG 表 |
|---|---|---|
| 多实例部署 | 🔴 pod-1 写的 pod-2 看不到 | 🟢 中心 PG 都读得到 |
| 断电恢复 | 🔴 /tmp 清空 | 🟢 持久化 |
| 审计 | 🔴 没 audit log | 🟢 可触发 TrajectoryEvent |
| 结构化查询 | 🔴 grep 文件 | 🟢 SQL + JSONB 索引 |

**PG 性能影响（实测数字）**：

| 操作 | `/tmp` 文件 | PG（同 VPC） | 差距 |
|---|---|---|---|
| 单次写 | ~0.5ms | ~2-5ms | +3-4ms |
| 单次读（缓存命中）| ~0.1ms | ~1-3ms | +2ms |

差距 3-5x，**但绝对值毫秒级**。在 agent 整体时间分布里：

```
LLM API 调用：    5000-30000ms      ████████████████████ 95%+
工具调用：        100-30000ms       ████ 4%
Compaction：      100-500ms         ▌ 0.5%
Scratchpad IO:    30-50ms           ▏ 0.1-0.5%  ← 这块
```

典型 sub-agent 任务里 scratchpad IO 占比 < 0.5%，**用户感知不到**。

**优化备选**（profile 发现真问题再上）：

```
日常负载（推荐 day-1）：PG 直接读写

profile > 50ms 延迟 → per-QueryEngine 内存缓存（几十行代码）
profile > 200ms 延迟 → 上 Redis 缓存层（读 Redis，写双写）
切 Temporal worker → 用 Temporal 内置 state store
```

**业界 reference**：Temporal workflow 引擎也是 PG 存所有 state，量比 FFAI 大几个数量级没问题。

**YAGNI 原则**：day-1 PG，**不上 Redis 不做缓存**，profile 触发再优化。

### 6.3 Task Tracker（后台任务）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 任务类型 | 7 种（local_bash/local_agent/remote_agent/in_process_teammate/local_workflow/monitor_mcp/dream）| 同 | task-notification | **3 类简化**（subagent / long_tool / workflow）🟡 |
| Task ID 类型前缀 | b/a/r/t/w/m/d | 同 | 无 | 取（便于诊断）|
| Watchdog | 45s 无输出 + 提示模式 | 同 | heartbeat | 取 |
| 持久化 | AppState + outputFile | 同 | 事件流 | **`AgentTask` PG 表 + S3 outputRef** |

**FFAI 理由**：CC 的 7 类任务是 coding agent 场景；FFAI 业务简化到 3 类。

### 6.4 Cron Isolated Agent（OCW 独有）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 调度 | ScheduleWakeup tool | 同 | **`src/cron/service.ts`** 5 段 cron + `every N` + `at <time>` | 取 OCW 表达式 🟢 |
| 隔离 | 同进程 | 同 | **每次触发起新 session 跑完销毁** | ✅ 取 + Temporal worker |
| Delivery plan | ❌ | ❌ | ✅ 多 channel 路由 | 取（发送到 Teams / email 等）|
| Heartbeat | ❌ | ❌ | ✅ | 取 |
| 防重入 + catchup + dedup | 简易 | 简易 | **严格** | 取（用 Temporal idempotency key）|

**FFAI 理由**：cron 是必备业务能力（"每天 9 点汇总待审批"）；OCW 的隔离 session 模式 + delivery plan 是最完整的设计。

---

## 7. Context 管理

### 7.1 History 持久化

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 存储 | JSONL 本地 | 同 → SQLite Phase 2 | transcript 事件追加 | **PG `AgentMessage` 表** 🟢 |
| 分页加载 | CCR fetchLatest/fetchOlderEvents | 同 | 事件流 cursor | cursor 分页（SQL OFFSET/LIMIT）|
| Compact 不删 | ✅ 仅标记 | 同 | ✅ | ✅ `compactedAt` 字段 |
| 大附件单独存 | outputFile | 同 | blob store | **S3/MinIO + DB 存引用** |

#### 7.1.x 三档写入时机（PG 写时机详解）

所有对话内容都存 `AgentMessage` 表，但**写入时机分三档**：

| 内容 | 写入时机 | 原因 |
|---|---|---|
| **用户消息** | HTTP 进 controller 后**立刻同步写**（开始 LLM 调用之前） | 用户输入是 source of truth，绝不能丢 |
| **Assistant 消息**（含 text + tool_use 块）| LLM 流式输出到 `message_stop` 事件时**一次性写整条** | 流式 token 太碎；按 message 边界写最合理 |
| **Tool result 消息** | 工具执行**完成后立刻写**（喂回下一轮 LLM 之前） | 工具结果是"事实"，要落 PG 才能 compact / 重放 |

**时序图**：

```
用户 ──POST /messages────▶ Controller
  │                          │
  │              ① INSERT user message (同步)
  │                          │
  │                  ┌───────▼────────┐
  │                  │ 调 OpenAI 流式 │
  │                  └───────┬────────┘
  │ ◀──SSE: text_delta...    │ (token 推前端，PG 不写)
  │ ◀──SSE: tool_use 块完整   │
  │                          │
  │                  message_stop 事件
  │              ② INSERT assistant message
  │                  (完整 text + tool_use blocks)
  │                          │
  │              ┌───────────▼──────────┐
  │              │ 分派工具 dispatcher  │
  │              └───────────┬──────────┘
  │              ③ INSERT tool_result message
  │                          │
  │                          │ 回灌下轮 LLM ↓
  │                          │
  │              ② INSERT assistant message (最终回答)
  │                          │
  │ ◀──SSE: result {usage, cost}
  │                          ▼ EOF
```

**一个典型对话最终 PG 行**：

| role | blocks | 写入时机 |
|---|---|---|
| user | `[{text:"查 ABC..."}]` | controller 收到立刻 ① |
| assistant | `[{text:"..."}, {tool_use: Project.search}]` | 第 1 轮 message_stop ② |
| tool_result | `[{tool_result: [{id,title,...}]}]` | 工具执行完 ③ |
| assistant | `[{text:"ABC 项目交付时间..."}]` | 第 2 轮 message_stop ② |

**边界场景**：

| 场景 | 处理 |
|---|---|
| Sub-agent 消息 | 落子 sessionId 下（`{parent}_sub_{uuid}`）；主 session 只看 tool_result 总结；前端"完整历史"可下钻到子 session |
| Compaction | **不删消息**，UPDATE `compactedAt` 字段；下次喂模型时 `WHERE compactedAt IS NULL` 过滤 |
| 流式期间前端崩溃 | 还没 `message_stop` 的内容会丢；前端用 `lastMessageId` 拉取已落库的；后端可选择继续跑完写 PG |
| Assistant message 写失败 | log + retry 1 次 + fallback 写 JSON 文件 + 不阻塞 SSE 推送 |
| Tool result 写失败 | retry 1 次 + 失败 abort turn |

**两层持久化关系（AgentMessage vs TrajectoryEvent）**：

| 事件 | AgentMessage | TrajectoryEvent |
|---|---|---|
| 用户消息 | ✅ 一条 message | ✅ 一条 event |
| LLM 开始/结束流 | ❌ | ✅ 两条（含 timing）|
| 工具调用前/后 | tool_use / tool_result block | ✅ 两条（含 latency / cost）|
| Compaction 触发 | ❌（除非写摘要 message）| ✅ 一条（哪层 / 输入输出 token）|
| Permission 弹窗 | ❌ | ✅ 一条 |
| Failover | ❌ | ✅ 一条 |
| Sub-agent spawn/返回 | tool_use / tool_result | ✅ 两条（含子 sessionId）|

**Message 看"对话是什么"，Trajectory 看"agent 干了什么"**。审计 / debug / 性能分析用 Trajectory；前端聊天界面渲染用 Message。

**性能考量**：单 turn PG 写入 < 20 行，PG 单连接每秒能扛几千 INSERT。**不是瓶颈**。唯一隐患是大量并发用户同时活跃 → 连接池压力 → PgBouncer + read replica（业界标准做法）。

### 7.2 五层 Compaction

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 层 1 文件去重 | ✅ | ✅ | N/A | ✅ 取 🟢 |
| 层 2 工具结果摘要 | ✅ | ✅ | N/A | ✅ |
| 层 3 旧轮摘要 | ✅ | ✅ | N/A | ✅ |
| 层 4 系统消息收敛 | ✅ | ✅ | N/A | ✅ |
| 层 5 硬截断 | ✅ | ✅ | N/A | ✅ |
| 触发阈值 | token 配额 80% | 同 | N/A | 取 + 可 per-org 配置 |
| contentReplacementState | ✅ 选择性替换 | 同 | N/A | 取 |

**FFAI 理由**：5 层 Compaction 是 CC 工业标准；day-1 五层全做。

### 7.3 Memory / memdir

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 分类 | user/feedback/project/reference | 同 | N/A | 取四类 🟢 |
| 索引 | MEMORY.md 索引 + body 按需展开 | 同 | N/A | 取（关键设计）|
| 截断 | 200 行 + 25KB 双重 | 同 | N/A | 取 |
| 优先级 | ~/.claude/memory / .claude/memory / memory/ | 同 | N/A | **per-user + per-org 两层 PG 表** 🟡 |
| 链接 | `[[other-slug]]` | 同 | N/A | 取 |
| 时机 | day-1 | day-1 | N/A | **day-1（Q14）** |

**FFAI 理由**：CC 的 memdir 模式是业界最完整 agent memory 设计；多组织改 PG 两层。

### 7.4 项目级配置（CLAUDE.md / AGENTS.md）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 存储 | 文件（CLAUDE.md / AGENTS.md） | 同 | 无 | **`OrganizationProfile` PG 表** 🟡 |
| 缓存 | bootstrap/state.ts memoize | 同 | N/A | NestJS cache + PG NOTIFY 失效 |
| 注入位置 | system prompt 顶部 | 同 | N/A | 同 |

---

## 8. SDKMessage 协议

### 8.1 字段设计

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 文本流 | text_delta | 同 | jsonl text | `assistant_text` + `thinking` 🟢 |
| 工具调用 | tool_use block | 同 | 同 | `tool_use { id, name, input }` 同构 Anthropic |
| 工具结果 | tool_result block | 同 | 同 | `tool_result { toolUseId, output, isError }` |
| 子 agent 事件 | subagent_started/completed | 同 | task event | 取 + condensed_summary 字段 |
| 任务事件 | task_created / task_updated | 同 | 同 | 取 |
| 工件 / Display | text 摘要 | text 摘要 | **A2UI JSONL ops** | **取 OCW A2UI** 🟢 |
| 权限请求 | permission_request | 同 | Approval routing | 取 |
| Compact 边界 | compact_boundary | 同 | N/A | 取 |
| Failover 事件 | ❌ | 部分 | ✅ | 取 OCW `failover { from, to, reason }` |
| Result 结束帧 | result { subtype, usage } | 同 | 同 | 取 + cost 字段 |

### 8.2 Anthropic 兼容性约束

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| tool_use 字段同构 | ✅ | ✅ | ✅ | ✅ 强制 🟢（为 Inbound 适配预留 Q18）|
| content block 模式 | Anthropic 一致 | 双向兼容 | 自定义 | **同构 Anthropic content block** |

**FFAI 理由**：Q18 inbound 适配预留要求 SDKMessage 结构同构 Anthropic，day-1 起字段命名 / 块结构必须 review。

### 8.3 A2UI Display 协议（取 OCW Canvas）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 增量协议 | ❌ | ❌ | ✅ JSONL ops（init/append/patch/data_update/hide）| ✅ 取 + Lark DS 组件 🟢 |
| 组件集 | ❌ | ❌ | Flutter 风格（Column/Text/Button 等）| **Lark DS 子集**（Card/Table/Form/Button/Markdown/Chart）🟡 |
| Snapshot 回灌 | ❌ | ❌ | ✅ | ✅ 取 |
| Capability-scoped URL | ❌ | ❌ | ✅ TTL token | ✅ 取（per-surface 安全）|
| 协议降级 | ❌ | ❌ | 不需要（只一种渲染）| **每组件必须带 `fallback: { text, url }`**（CLI/Teams 降级用）🟡 |

**FFAI 理由**：A2UI 是产品差异化关键；Lark DS 路线对标飞书消息卡片 v2 / 蚂蚁 Ant Design X。

---

## 9. 持久化

### 9.1 Sessions / Messages / Tasks / Artifacts

| 表 | CC 存哪 | OC 存哪 | OCW 存哪 | FFAI v0.2 PG 表 |
|---|---|---|---|---|
| Session | JSONL `~/.claude/sessions/` | 同 → SQLite | 内存 + 事件流 | **`AgentSession`** 🟢 |
| Message | 同上 | 同 | 同 | **`AgentMessage`**（不删，compactedAt 标记）|
| Task | AppState + outputFile | 同 | task event | **`AgentTask`** + S3 outputRef |
| Artifact | text 摘要 | 同 | per-surface | **`AgentArtifact`** 用户维度（v0.1 Q3）|

### 9.2 Settings 多源合并

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 来源 | .claude/config.json + settings.json + settings.local.json | 同 + `~/.openclaude/profile.json` | per-account/per-channel | **per-org PG + per-user PG + per-session 内存** 🟡 |
| 优先级合并 | 文件优先级 | 同 | 同 | SQL view 合并 |
| Migration | 11 个迁移脚本 | 继承 | N/A | **schemaVersion 字段 + 迁移机制 day-1 起步** |

### 9.3 Credentials Vault（Q16）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 凭据来源 | OS keyring / env | profile.json | **凭据矩阵 ref**（env/exec/secret_input/sibling_ref）| 取 ref 模式 🟢 |
| Plan/apply | ❌ | ❌ | ✅ 先预览再落地 | ✅ 取 |
| audit | ❌ | ❌ | ✅ 弱凭据扫描 | ✅ 取 |
| 后端存储 | OS | 文件 | 文件 + 加密 | **PG 加密列**（envelope encryption）🟡 |

**FFAI 理由**：Q16 PG 加密列足够；不引入 Vault；OCW 的 ref 模式 + plan/apply 值得借鉴。

### 9.4 TrajectoryEvent（OCW 独有，Q11 取）

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 事件流 | telemetry attributes | 同 | **完整 TrajectoryEvent** schema | ✅ 取 🟢 |
| 字段 | userId/sessionId/model/intent | 同 | traceId/sessionId/runId/source/seq/phase/payload | 取超集 |
| 用途 | Anthropic 后台 | Anthropic 后台 | replay/audit/debug | per-org 审计 + bug 回放 |
| 存储 | 上报 | 上报 | 本地事件流 | **`AgentTrajectoryEvent` PG 表 + 索引** |

**FFAI 理由**：多组织企业 SaaS 审计必备；CC 的 telemetry 上报模式不适用（数据要留在自家 PG）。

---

## 10. 可观测性

### 10.1 Cost Tracker

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| 字段 | totalCostUSD / modelUsage / cache create/read | 同 | + 多 vendor 计价表 | 取 OC 多 vendor 🟢 |
| 计价表 | hardcode | per-vendor 表 | per-vendor 表 | **`ModelPricing` PG 表** |
| Budget 控制 | maxBudgetUsd | 同 | quota 跟踪 | 取 + per-org 月度 quota |
| 实时累积 | costHook | 同 | 同 | 取 |

### 10.2 Telemetry / OTel

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| Meter | OpenTelemetry | 同 | OTel + proxy-capture | OTel 🟢 |
| 上报后端 | Anthropic | 用户自管 | 本地 | **自托管 OTel collector**（公司已有）|
| Feature gate | GrowthBook | 同 | availability expression | 简化（per-org config）|
| 属性 | userId/sessionId/model/intent | 同 | + phase/activity 三维度 | 取超集 |

### 10.3 Debug 工具

| 维度 | CC | OC | OCW | FFAI v0.2 |
|---|---|---|---|---|
| Doctor / 健康检查 | Doctor 命令 | 同 | doctor 45 个入口 | day-1 简版（/health endpoint）|
| Console capture | ❌ | ❌ | ✅ 第三方库 console.log 也捕获 | 后期 |
| Proxy-capture | ❌ | ❌ | ✅ 开发期 TLS 拦截回放 | **架构预留**（用 winston interceptor）|
| Perf-issue | ✅ ant-trace | 同 | trajectory 时间线 | 取 trajectory 时间线 |

---

## 11. 总对比矩阵（cheat sheet 一页式）

| # | 功能点 | CC | OC | OCW | **FFAI v0.2 选择** |
|---|---|---|---|---|---|
| 1.1 | 主入口 | CLI | CLI | 任意 | **Web** 🟡 |
| 1.2 | 流式协议 | WS | SSE+WS | WS only | **SSE 主** 🟡 |
| 1.3 | 多端代码共用 | SDK | ❌ | ✅ webview 复用 | **React 共用 + Mobile 独立** 🟢 |
| 1.4 | IM 适配 | N/A | N/A | 25+ 渠道 | **Inbox 抽象 + Teams 优先** 🟢 |
| 2.1 | TAOR 状态机 | ✅ | ✅ | 宿主 CLI | **自实现** 🟢 |
| 2.3 | 流式 tool 执行 | ✅ TrackedTool | ✅ | N/A | **取 CC** 🟢 |
| 2.4 | turn 串行化 | 进程 mutex | 同 | 文件锁 | **Redis lock** 🟡 |
| 3.1 | Tool 接口 | ✅ 8 方法 | ✅ | + Descriptor | **CC + OCW 超集** 🟢 |
| 3.2 | Availability Expression | ❌ | ❌ | ✅ | **取** 🟢 |
| 3.4 | 沙盒 | sandbox-exec/landlock | 同 | 软约束 | **Docker per-user**（cli）+ **OS 沙盒**（client）🟡 |
| 3.5 | MCP 集成 | client | 同 | 部分 | **client + server 双向** 🟢 |
| 4.1 | Provider Registry | 单 | OC 杀器 | 类似 | **取 OC** 🟢 |
| 4.2 | 内部 IR | Anthropic | **OpenAI** | OpenAI 兼容 | **OpenAI（取 OC）** 🟢 |
| 4.4 | Failover | ❌ | 部分 | **FailoverError** | **取 OCW** 🟢 |
| 4.5 | ModelRouter | ❌ | `agentRouting` 1 信号 | 手动 picker | **5 信号 + 3 策略 + 学习反馈（G10 核心）** 🟢 |
| 5.1 | Skill | md + 4 源 | 同 | + allowed-tools | **取 OCW 字段 + 双源** 🟢 |
| 5.3 | Hook | 11 事件 4 实现 | 同 | 5 类 | **5 类 + webhook+skill** 🟡 |
| 5.4 | 协作模式 | **Plan + Permission 5 态两轴** | 同 | 弱 | **取 CC 两轴正交**（vs Codex 一维 4 枚举）🟢 |
| 3.1+ | Tool Exposure | isReadOnly 2 态 | 同 | — | **direct/deferred/model_only 三态**（借 Codex）🟢 |
| 9.4+ | Trajectory 双职责 | telemetry 上报 | 同 | 完整事件流 | **取 OCW + Codex 三层启发**（audit + debug 共表 + PG 写约束）🟢 |
| 6.1 | Sub-agent | 同进程/worktree/CCR | 同 | N/A | **同进程 day-1** 🟡 |
| 6.4 | Cron isolated | ScheduleWakeup | 同 | **isolated session + delivery plan** | **取 OCW + Temporal** 🟢 |
| 7.2 | 5 层 Compaction | ✅ | ✅ | N/A | **取 CC** 🟢 |
| 7.3 | Memory（memdir）| ✅ 四类 + 索引 | 同 | N/A | **取 CC + per-user/per-org** 🟢 |
| 8.1 | SDKMessage | Anthropic 一致 | 双向 | 自定义 | **同构 Anthropic（Q18 预留）** 🟡 |
| 8.3 | A2UI Display | ❌ | ❌ | **JSONL 增量 + snapshot** | **取 OCW + Lark DS** 🟢 |
| 9.3 | Vault | OS keyring | 文件 | ref 矩阵 | **PG 加密列 + ref 模式** 🟡 |
| 9.4 | Trajectory | telemetry | 同 | **完整事件流** | **取 OCW PG 表** 🟢 |
| 10.1 | Cost Tracker | ✅ | + multi-vendor | 同 | **取 OC** 🟢 |

**图例**：🟢 业界共识 / 🟡 我们场景特化 / 🔴 新选择

---

## 12. 实施优先级与 PR 映射

| PR | 范围 | 涉及功能点 |
|---|---|---|
| PR1 | 三栏 UI 骨架 + SSE echo | §1.1 / §1.2 |
| PR2 | Prisma schema + InboxAdapter + AgentGateway Controller | §1.4 / §9.1 |
| PR3 | ModelProvider Registry + ProfileResolver + Shim + OpenAIProvider + MockProvider | §4.1-4.3 |
| PR4 | QueryEngine MVP + 5 层 Compaction + TrajectoryEvent + Memory | §2.1-2.4 / §7.1-7.3 / §9.4 |
| PR5 | ToolRegistry + Descriptor + AvailabilityExpression + MCP Client + 业务 MCP server | §3.1-3.6 |
| PR6 | A2UI 协议 + Lark DS renderer + ArtifactStore | §8.1-8.3 |
| PR7 | SkillRegistry + HookRegistry（5 事件）+ Slash Commands 内置三件套 | §5.1 / §5.3 / §5.4 |
| PR8 | Sub-agent dispatch (AgentTool 递归 QueryEngine) + Scratchpad + TaskTracker | §6.1-6.3 |
| PR9 | Cost Tracker + OTel + Failover 链路 | §4.4 / §10.1-10.2 |
| PR10 | Cron Isolated Agent（Temporal worker）+ Credentials Vault | §6.4 / §9.3 |
| PR11 | Electron Desktop + HostBridge + Capability 协商 | §1.1 / §1.3 |
| PR12 | Client Executor 轻量工具（LocalFile/Clipboard/Notify/LocalApp） | §3.7 |
| PR13 | LocalShell.exec + OS 沙盒（macOS sandbox-exec / Win AppContainer）+ 二次授权 | §3.4 / §3.7 |
| PR14 | TeamsInbox（Bot Framework）+ Identity 映射 + A2UI→Adaptive Card 投影 | §1.4 / §8.3 |
| PR15 | CLI Executor + Docker per-user 沙盒 + 第一批服务端 CLI 工具（git/kubectl/psql） | §3.4 / §3.7 |
| PR15.5 | monorepo 抽包（agent-protocol + agent-renderer-lark）| §1.3 |
| PR15.6 | thin CLI surface | §1.1 |
| PR16-17 | iOS / Android 原生 app 框架 + Swift/Kotlin HostBridge + 原生 A2UI renderer | §1.1 / §1.3 / §8.3 |
| PR18-19 | iOS Live Activity / Dynamic Island ; Android Material You / Quick Settings tile | §1.1 |
| PR20 | Mobile-specific client tools（相机 OCR / 位置 / 剪贴板） | §3.7 |

---

## 13. 关键源码路径速查（实现时翻一翻）

### CC
- 工具接口 → `Tool.ts` 8 生命周期方法
- 5 层 Compaction → 内部 `Compactor` 类
- 内置工具池 → `tools.ts` 注册 + 43+ 工具单文件
- Memory → `memdir/` + `MEMORY.md` 处理
- 多 surface 入口 → `bridge/`（IDE HTTP poll）/ `remote/`（WS 远程）

### OC
- query 主循环 → `query.ts` 1914 行
- 会话管理 → `QueryEngine.ts` 1430 行
- Provider Registry → `integrations/registry.ts`
- ProfileResolver → `integrations/profile-resolver.ts`
- DiscoveryService → `integrations/discovery.ts`
- OpenAI Shim → `integrations/openaiShim.ts`
- Streaming Tool Executor → `tools/streamingExecutor.ts`
- coordinator → `coordinator/`（同进程 fork+resume）

### OCW
- Turn 状态机 9-stage → `src/channels/turn/kernel.ts`
- 多渠道 normalize → `src/channels/plugins/normalize/`
- Cron isolated agent → `src/cron/service.ts`
- 凭据矩阵 → `src/secrets/` + auth-profiles/
- A2UI Canvas 协议 → `src/canvas/` + `tools/canvas/` 7 action
- ToolDescriptor + Availability → `src/tools/`（2026.5.14 新拆）
- FailoverError → `src/agents/cli-runner.ts`
- Plugin 边界 → `openclaw/plugin-sdk/`

---

## 14. 实现节奏建议

按 PR 顺序展开，每个 PR 前：

1. 翻到本文档对应章节，**先读 CC/OC/OCW 三家做法**
2. **看 FFAI v0.2 选择 + 理由**（理解 trade-off）
3. **打开源码路径**（§13）参考具体代码（不复制粘贴，吸收设计）
4. **写 PRD / API 契约 / 数据模型**（按 [`docs/standards/06-documentation-system.md`](../../standards/06-documentation-system.md) 模板）
5. 实现 + 集成测试 + 跑通

**总原则**（受 G7 + G9 指导）：
- 不直接 fork 任一开源仓库（避免单 maintainer 风险）
- 吸收设计，运行时自研
- 代码成本不是主要约束，**对的方案 > 省工时方案**
- 业界事实标准（≥2 家做法一致）优先采纳，特殊场景再特化

---

## 15. 更新触发

本文档需要更新的情况：
1. v0.2 任一决策修改（先改 `02-architecture.md`，再回来同步本表）
2. 新增收录的 agent 实现（如 OpenCode / Cline / Aider）—— 加列
3. 实现 PR 完成后发现源码理解有偏差 —— 修正对应章节
4. 业界出现新事实标准（新 LLM 协议 / 新 sandbox 技术 / 新组件库范式）—— 重新评估

> 本文档与 [`02-architecture.md`](./02-architecture.md) 同生命周期，是其实施层补充。
