第二层 · 整体架构
分层组合:profile / bundle / patch
一个运行中的 dsh 是一棵从有序层在启动时装配出来的插件树。本章讲清这套组合机制——它是你理解"为什么改个配置就能换掉整个能力"的钥匙。依据 docs/architecture.md。
三个层次概念
| 概念 | 是什么 | 类比 |
|---|---|---|
| profile(配置档) | 存在 Harness home 里的命名组合;列出它叠加的 bundle、保留的树外插件、用户自己的 cordis.patch.yml | 一份"装机清单" |
| bundle(包) | Cordis 配置行 + 它们挂载的代码的分发格式;它的内容仍可被上层 patch 覆盖 | 清单里的一项"预置套餐" |
| patch(补丁层) | 按 id 瞄准某行、整体替换其 config,或插入新行 | 对套餐做"加料/换料" |
每个 bundle 在自己的 package.json 的 dsh 字段里声明:dsh.profile 列出 profile 叠加的 bundle,dsh.bundle 指向该 bundle 的 patch 文件。
官方自带的 bundle
dsh-base—— 每个 profile 的第一层:模型适配器、工具、持久化、沙箱与审批策略、settings、credentials、telemetry。dsh-web-app—— 加上浏览器应用(即你在http://127.0.0.1:3080看到的 GUI)。dsh-headless—— 加一个无服务器的一次性运行器(dsh --profile headless "task")。
web 和 headless 作为模板随仓库发布。
层的应用顺序
层叠加在一个空的 entry 列表上,顺序如下:
① profile 列出的每个 bundle(按列出顺序)
▼
② profile 的 cordis.patch.yml
▼
③ home 级的 cordis.patch.yml
▼
④ 任何 --patch 覆盖层
一条 patch 通过 id 瞄准某行,整体替换它的 config,或插入新行。所以你想改某项行为,不必改源码——写一条 patch 覆盖该行即可。
看你的机器实际启动了什么
# 打印当前 profile 真正装配出的整棵插件树
dsh --profile web --dump-config
它打印的每一行都能被你自己的 patch 替换。组合的完整机制在 packages/boot/app-boot/README.md;字段含义在生成的 docs/config-catalog.md。
这套设计为什么重要
可逐层打补丁
bundle 之上永远有更高层可覆盖它——所以升级一个 bundle 不会抹掉用户的定制,定制放在 profile/home 的 patch 层。这正是论文"时间可组合性"在产品层的体现:换实现 = 换一行配置,且可逆。
profile 即"部署形态"
同一套基础能力,web profile 长出带 GUI 的常驻服务,headless profile 长成跑完即退的 CLI。差异只是叠加了不同 bundle——没有任何"if GUI then ..."的硬编码分支。
下一节看这棵插件树里最核心的部件:Agent 循环如何驱动一次对话。