4. 整体架构
4.1 架构风格
从源码和文档可以判断,这不是传统 MVC,而是:
- 插件化微内核 / 可组合运行时:所有产品能力都通过插件挂到
ctx。 - 事件驱动与事件溯源混合:typed events 负责扩展点,Session log 负责持久真相。
- capability seam 分层:Service Definition / Provider / Consumer 分离。
- Host / Browser 双插件树:同一套 Cordis 思想贯穿后端和前端。
- 类型安全 RPC:Typert 从 Host 类型生成客户端契约。
判断依据:
docs/architecture.md明确 “There is no privileged core to patch”。packages/core/agent-loop/src/index.ts:349-350用ctx.effect()注册 factory。packages/core/session/src/index.ts:417-425将 Session 定义为 event-sourced log。.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md:15说明两端都跑 cordis。
4.2 模块划分
| 模块名称 | 主要职责 | 对外接口 | 上游依赖 | 下游依赖 | 核心 | 主要源码位置 |
|---|---|---|---|---|---|---|
core/session | append-only 会话日志与内存 store | ctx.sessions、Session、SessionEvent | dsh-llm、dsh-scope | 几乎所有模块 | 是 | packages/core/session/src/ |
core/system-prompt | 组装 prompt、context、tool schema、变量 | ctx.systemPrompt | dsh-scope、dsh-llm | agent-loop、tools | 是 | packages/core/system-prompt/src/index.ts |
core/tools | 工具注册、展示、执行管线 | ctx.tools | dsh-system-prompt、dsh-scope | agent-loop、所有 dsh-tool-* | 是 | packages/core/tools/src/index.ts |
core/agent | Agent 公共接口、registry、事件词汇 | ctx.agents | dsh-session、dsh-llm | UI、protocol、loop | 是 | packages/core/agent/src/index.ts |
core/agent-loop | 默认 Agent 驱动器 | ctx.agentLoop | agents、sessions、llm、tools、systemPrompt | 无(实现) | 是 | packages/core/agent-loop/src/ |
core/scope | per-agent scoped registration 原语 | library,无 ctx key | 无 | session、system-prompt、tools | 是 | packages/core/scope/src/ |
llm/llm | 模型消息、stream、adapter registry | ctx.llm | Cordis | agent-loop、llm-deepseek、llm-pi-ai | 是 | packages/llm/llm/src/index.ts |
session/session-persistence | 持久化 seam 和 coordinator | ctx.sessionPersistence | dsh-session | JSONL/SQLite 后端 | 是 | packages/session/session-persistence/src/ |
session/session-projection | 从事件流驱动纯投影 | ctx.sessionProjections | dsh-session | token meter、UI carriers | 重要 | packages/session/session-projection/src/index.ts |
boot/app-boot | profile 发现、patch 组合 | 函数 API | Cordis loader | CLI | 是 | packages/boot/app-boot/src/profile.ts |
apps/cli | dsh 启动器 | CLI | app-boot、bundles | 无 | 是 | apps/cli/src/bin.ts |
api/session-controller | Host 分页/跟随传输、Client Session 与快照 | page/follow、client services | Session Log、wire/RPC | UI 插件 | 是 | packages/api/session-controller/src/ |
client/ui-conversation + ui-renderer | 对话节点装配、React 外部 Store 桥与 keyed Slot | assembler、slot renderer | Client Session、ui-slots | React UI | 是 | packages/client/ui-conversation/src/、packages/client/ui-renderer/src/ |
client/ui-slots | slot registry 核心与 props 类型 | slot API | runtime | UI 插件 | 是 | packages/client/ui-slots/ |
typert/* | 类型图生成、加载、运行时 registry | Typert | TypeScript AST/type system | API gateway、SDK | 重要 | packages/typert/ |
sdk/* | JSON-RPC 协议、server、TS client | SDK | dsh-agent、Typert | 外部自动化 | 重要 | packages/sdk/ |
bundle/* | 安装式 profile patch layers | bundle patch | base + mode | 无 | 重要 | packages/bundle/base/cordis.patch.yml |
4.3 架构图
4.4 核心数据流
选择最典型的 dsh --profile headless "run the tests",因为它绕过 Web UI 和 ACP,最能直接暴露核心 loop。
- CLI 解析命令:
apps/cli/src/bin.ts:27-53。 - profile 组合:
apps/cli/src/profile-boot.ts:207-259。 dsh-headless的 runner 创建 Agent、提交任务、等待空闲:packages/bundle/headless/README.md:7-11。ReactLoopAgent.turn()打开 turn,preStep()组装请求,step()派生历史并调用模型。- 模型返回工具调用时,
executeToolCalls()调用ctx.tools。 - 每一步都写
turn/start、step/start、user/message、assistant/message、tool/result、step/end、turn/end等 Session event。 - headless runner flush 后从持久事件区间提取最后 assistant 文本并退出。
4.5 启动流程
关键源码:
packages/boot/app-boot/src/profile.ts:371-403解析 profile 和 bundle patch。packages/boot/app-boot/src/profile.ts:413-419将 layers 合并成 entry list。apps/cli/src/profile-boot.ts:248-259调用boot()并注入 commandline/env。packages/core/agent-loop/src/index.ts:349-381注册 factory 和配置驱动 agents。
4.6 关键调用链
入口:
text
agent.followup(userMessage)调用链:
text
packages/core/agent-loop/src/agent.ts:122
-> Agent.send(message, 'next-turn', true)
-> packages/core/agent-loop/src/agent.ts:113-120
-> Inbox.splice + wakeDriver
-> packages/core/agent-loop/src/agent.ts:172-193
-> withInitiator -> kick()
-> packages/core/agent-loop/src/agent.ts:210-223
-> turn()
-> packages/core/agent-loop/src/agent.ts:246-330
-> preStep()
-> packages/core/agent-loop/src/agent.ts:225-243
-> ctx.systemPrompt.assemble(assembleContextFor(this, signal))
-> runtimeContext.project(joinContextSections(sections), sections)
-> ctx.waterfall('agent/pre-step')
-> session.append('step/start')
-> session.append('user/message')
-> step(assembly)
-> packages/core/agent-loop/src/agent.ts:332-401
-> buildRequest()
-> session.deriveMessages()
-> ctx.llm.prepareCall()
-> preparedCall.stream(request) or ctx.llm.stream(request)
-> for await chunk -> session.append('assistant/chunk')
-> assembler.finish -> createAssistantMessage
-> session.append('assistant/message')
-> if tool calls -> executeToolCalls()
-> packages/core/agent-loop/src/tool-calls.ts:67-204
-> ctx.tools scheduler prepare/dispatch/finalize
-> session.append('tool/result')
-> repeat step while tools owe request or steering arrives
-> session.append('step/end')
-> dispatch.serial('agent/turn-stopping')
-> session.append('turn/end')每一步的依据都在上述行号附近,属于已验证源码结构。