业务平台 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(本人终端登录) │
└──────────────────────────────────────────────────────────────────┘
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/
interface AgentProvider {
readonly id: 'claude' | 'codex'
capabilities(): ProviderCapabilities // 模型列表、是否支持图片/思考/提问等
health(): Promise<ProviderHealth> // 登录状态、限额
startRun(ctx: RunContext): RunHandle
}
interface RunContext {
session: SessionRecord // 含 providerSessionId(用于 resume)
input: UserInput // 文本 + 图片 + 附件引用
profile: ResolvedProfile // 已合并的模型、提示词、权限、工具、连接器
workspaceDir: string
access: ResolvedAccessPolicy // 合并后的文件访问策略(06 §4)
interact: (req: InteractionRequest) => Promise<InteractionResponse> // 挂起等待人工
signal: AbortSignal
}
interface RunHandle {
events: AsyncIterable<AgentEvent>
interrupt(): Promise<void>
}
interact 是两个引擎交互能力的统一出口:Claude 的 canUseTool 回调、Codex 的审批请求、MCP Gateway 的写操作审批,最终都调用它,由 Interaction Service 发出 interaction.required 事件,并挂起 Promise 等待前端回复。
queued ──► running ──► completed
│ │ ├──► failed
│ │ └──► interrupted (用户中断 / 服务重启 / 超时)
│ └──► waiting_input ──► running (有未决交互时)
└──► cancelled
409(后续可改为排队)。waiting_input 状态不计入并发配额以外的超时;交互超时(默认 10 分钟,可配)按"拒绝"处理。Adapter 产出 AgentEvent
→ Run Manager 分配 seq(会话内单调递增)
→ Event Store 写入 SQLite(events 表)
→ Event Bus 广播(进程内 EventEmitter)
→ SSE 连接按 sessionId / runId 过滤推送
先落库、再推送;SSE 重连时依据 Last-Event-ID(= seq)从库中补发。message.delta 这类高频事件在落库时按 100ms 窗口合并,推送不合并。
| 引擎 | 进程 | 说明 |
|---|---|---|
| Claude | 每个活动 Run 一个 claude 子进程(由 SDK 拉起),Run 结束退出 |
会话状态由 CLI 自身持久化到 ~/.claude/projects/,下次用 resume 继续 |
| Codex | 一个常驻 codex app-server,内部管理多个 thread |
进程异常退出自动重启,并把关联的活动 Run 标记 interrupted |
并发控制:全局上限(默认 4)+ 每引擎上限(默认 2),使用进程内队列(p-queue),上限在后台设定。注意服务与你在终端中的使用共享同一份订阅额度。
| 层 | 选型 | 理由 |
|---|---|---|
| 运行时 | 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 |