# 02 总体架构 ## 1. 架构总览 ``` 业务平台 A/B/C (Vue) 管理后台 (Vue, 同源静态托管) │ @agent-server/client │ │ REST + SSE (/v1) │ REST + SSE (/v1 + /admin/v1) ┌──▼────────────────────────────────▼──────────────────────────────┐ │ HTTP 层 (Fastify):鉴权(API Key/AdminSession) · 校验(Zod) · 限流 │ ├──────────────────────────────────────────────────────────────────┤ │ Session Service Run Manager Interaction Service │ │ Workspace Service Profile Service Settings Service │ │ Access Policy Knowledge Service Usage/Audit Event Store/Bus │ ├──────────────────────────────────────────────────────────────────┤ │ Provider Adapter 层(统一 AgentEvent) │ │ ├─ ClaudeAdapter ── @anthropic-ai/claude-agent-sdk ──► claude CLI 子进程(每会话)│ │ └─ CodexAdapter ── JSON-RPC(stdio) ──► codex app-server 常驻进程(单个) │ ├──────────────────────────────────────────────────────────────────┤ │ MCP Gateway (/mcp):web_fetch · 资料库检索 ·(预留)内部平台连接器 │ ├──────────────────────────────────────────────────────────────────┤ │ SQLite (Drizzle) 文件系统:/srv/agent-server/{workspaces,knowledge,skills,runtime}│ │ CLI 登录态:~/.claude、~/.codex(本人终端登录) │ └──────────────────────────────────────────────────────────────────┘ ``` ## 2. 工程结构(pnpm monorepo) ``` apps/ server/ Node 22 + TS + Fastify src/ http/ 路由:v1/、admin/v1/、mcp/ services/ session, run, interaction, workspace, profile, settings, access-policy, knowledge, usage, audit providers/ types.ts AgentProvider 接口、AgentEvent 定义(从 shared 引入) claude/ Agent SDK 适配、消息→事件映射、canUseTool 桥接 codex/ app-server 进程管理、JSON-RPC 客户端、通知→事件映射、审批桥接 mcp-gateway/ MCP Server 实现、内置工具(web_fetch、kb_*) connectors/ (预留)内部平台连接器 db/ Drizzle schema、迁移 admin/ Vue 3 + TS + UnoCSS + Vite + Vue Router + Pinia packages/ shared/ AgentEvent、API DTO、Zod schema(前后端共享类型) client/ TS 客户端 SDK(会话、SSE 订阅、断线续传、交互回复、上传) chat-ui/ Vue 对话组件(消息时间线、工具卡片、交互卡片、输入框),Playground 与业务平台共用 ui-tokens/ UnoCSS preset:VS Code 风格设计令牌(亮/暗) docs/ ``` ## 3. 核心抽象 ### 3.1 Provider 接口 ```ts interface AgentProvider { readonly id: 'claude' | 'codex' capabilities(): ProviderCapabilities // 模型列表、是否支持图片/思考/提问等 health(): Promise // 登录状态、限额 startRun(ctx: RunContext): RunHandle } interface RunContext { session: SessionRecord // 含 providerSessionId(用于 resume) input: UserInput // 文本 + 图片 + 附件引用 profile: ResolvedProfile // 已合并的模型、提示词、权限、工具、连接器 workspaceDir: string access: ResolvedAccessPolicy // 合并后的文件访问策略(06 §4) interact: (req: InteractionRequest) => Promise // 挂起等待人工 signal: AbortSignal } interface RunHandle { events: AsyncIterable interrupt(): Promise } ``` `interact` 是两个引擎交互能力的统一出口:Claude 的 `canUseTool` 回调、Codex 的审批请求、MCP Gateway 的写操作审批,最终都调用它,由 Interaction Service 发出 `interaction.required` 事件,并挂起 Promise 等待前端回复。 ### 3.2 Run 生命周期 ``` queued ──► running ──► completed │ │ ├──► failed │ │ └──► interrupted (用户中断 / 服务重启 / 超时) │ └──► waiting_input ──► running (有未决交互时) └──► cancelled ``` - 一个会话同一时刻只允许一个活动 Run,新消息在 Run 进行中提交时返回 `409`(后续可改为排队)。 - `waiting_input` 状态不计入并发配额以外的超时;交互超时(默认 10 分钟,可配)按"拒绝"处理。 ### 3.3 事件管道 ``` Adapter 产出 AgentEvent → Run Manager 分配 seq(会话内单调递增) → Event Store 写入 SQLite(events 表) → Event Bus 广播(进程内 EventEmitter) → SSE 连接按 sessionId / runId 过滤推送 ``` 先落库、再推送;SSE 重连时依据 `Last-Event-ID`(= seq)从库中补发。`message.delta` 这类高频事件在落库时按 100ms 窗口合并,推送不合并。 ## 4. 进程模型 | 引擎 | 进程 | 说明 | |---|---|---| | Claude | 每个活动 Run 一个 `claude` 子进程(由 SDK 拉起),Run 结束退出 | 会话状态由 CLI 自身持久化到 `~/.claude/projects/`,下次用 `resume` 继续 | | Codex | 一个常驻 `codex app-server`,内部管理多个 thread | 进程异常退出自动重启,并把关联的活动 Run 标记 `interrupted` | 并发控制:全局上限(默认 4)+ 每引擎上限(默认 2),使用进程内队列(p-queue),上限在后台设定。注意服务与你在终端中的使用共享同一份订阅额度。 ## 5. 技术栈 | 层 | 选型 | 理由 | |---|---|---| | 运行时 | Node.js 22 LTS + TypeScript | 两个引擎的官方集成以 TS 生态最完善(ADR-0001) | | Web 框架 | Fastify | 性能好、原生 schema 校验、插件体系成熟 | | 校验 | Zod(经 `fastify-type-provider-zod`) | 类型与 schema 一处定义,前后端共享 | | 存储 | SQLite(better-sqlite3)+ Drizzle ORM | 单机足够;WAL 模式支撑并发读写 | | 队列 | p-queue(进程内) | 单实例无需 Redis | | MCP | `@modelcontextprotocol/sdk`(Streamable HTTP) | 两个引擎都支持 HTTP MCP | | 前端 | Vue 3 + TS + UnoCSS + Vite + Pinia + Vue Router | 与业务平台一致(ADR-0007) | | 图标 | `@vscode/codicons` | 与 VS Code 视觉一致,开源许可 | | Markdown | markdown-it + Shiki | 代码高亮主题可跟随亮/暗 | | 日志 | pino | Fastify 内置,结构化 JSON |