Skip to content

0.3 运行机制初探:profile 与配置树

本章概览:DSH 的"组合式运行"是如何发生的——Harness home、profile、组合包(bundle)、patch 层,以及如何用 --dump-config 观察组合结果。这是后续理解一切扩展机制的基础。

从一条命令到一个插件树

dsh --profile web 这条命令,最终会启动一棵插件树:空配置根之上,按固定顺序叠加多个配置层,每层是一份 cordis.yml(或 YAML 数组),声明要挂载的插件及其配置。启动器(launcher,apps/cli)只做三件事:

  1. 解析自己的 flag;
  2. 定位并初始化 profile;
  3. 调用 dsh-app-bootboot() 把配置树挂载成 Cordis 上下文。

出处:packages/boot/app-boot/README.mddeepseek-harness-src/packages/boot/app-boot/README.md)与 apps/cli/README.md

Harness home 与 profile

Harness home

Harness home 是 DSH 的"用户机器上的家",通过 resolveDshHome 解析:优先 $DSH_HOME 环境变量,否则 ~/.dsh。它存放 profile、用户级 patch 层与机器级偏好。

出处:packages/util/home-paths/README.md

profile 是什么

profile 是存放在 $DSH_HOME/profiles/<name> 下的具名组装,包含:

文件/目录作用
package.json记录树外插件依赖(dependencies)+ profile manifest dsh.profile
dsh.profile元数据清单,其中 bundles有序的组合包名称列表
cordis.patch.yml用户自己的 patch 层
node_modules/pnpm 安装的树外插件

webheadless 是随发行版交付的模板 profile,首次使用时自动初始化;其他名字必须通过 dsh plugin --profile <name> 创建。

组合包(bundle)

组合包是 Cordis 配置项及其挂载代码的分发格式:一个 npm 包,其 package.json 声明 "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }。因为组合包的内容是可 patch 的配置项,其上方任何层都能覆盖它。

出处:docs/architecture.mddeepseek-harness-src/docs/architecture.md

三个内置组合包:

组合包内容
dsh-base每个 profile 的第一层:模型适配器、工具、持久化、沙箱与审批策略、设置、凭据、遥测
dsh-web-app在 base 之上增加浏览器应用(webserver、API gateway、workspace、客户端插件)
dsh-headless在 base 之上增加一次性运行器,完全不带服务器

配置层的叠加顺序

配置树以空根为起点,依次叠加:

1. dsh.profile.bundles 中各组合包的 patch(按 bundle 列表顺序)
2. profile 自身的 cordis.patch.yml
3. home 级 $DSH_HOME/cordis.patch.yml
4. --patch 指定的覆盖层

一条 patch 按 id 定位某个条目并替换其整个 config,或插入新条目。注意:替换是整个 config 替换,没有深层合并——profile 覆盖一个条目时,必须重述该条目保留的所有字段。

出处:packages/boot/app-boot/README.md#profilesdeepseek-harness-src/packages/boot/app-boot/README.md)与 @deepseek-ai/dsh-base/README.md

解析锚点

dsh.profile.bundles 中列出的组合包,先从 dsh 安装目录解析(@deepseek-ai/dsh-basedsh-web-appdsh-headless),再从 profile 自身的 node_modules 解析;healProfilesModuleFallback 维护 $DSH_HOME/profiles/node_modules 平面目录(每包一个符号链接),使任何 profile 的裸插件名都能通过 Node 普通父级查找解析。

观察组合结果

不启动即可查看组合后的配置树:

sh
dsh --profile web --dump-config

它打印出的任何条目都可以被你的 patch 替换--dump-default-config 则打印默认配置。renderConfigDump 会为每段同源、同 patch 层的行组标注 # == 注释,标明来源文件与叠加的层,并保留 !!js 表达式原样输出。

出处:packages/boot/app-boot/README.mddeepseek-harness-src/packages/boot/app-boot/README.md

!!js 表达式:条件组合

配置条目中允许 !!js 表达式(永远不是 !js),用于求值型字段:

  • 条目 config:在声明注入激活后、对插件上下文求值(ctx.serviceName);
  • 条目 disabled:在每次挂载决策时、对 loader 上下文求值。

典型例子(dsh-base 的 patch 用平台表达式选择 shell 栈):

yaml
# 示例语义:Windows 上禁用 bash 栈,POSIX 上禁用 pwsh 栈
- id: bash-sandbox
  name: '@deepseek-ai/dsh-bash-sandbox'
  disabled: !!js process.platform === 'win32'

出处:docs/cordis-primer.md#loader-configurationdeepseek-harness-src/docs/cordis-primer.md)与 packages/bundle/base/cordis.patch.yml

启动失败行为(fail loud)

DSH 对配置错误采取响亮失败策略:无效命令、来自其他模式的选项、配置错误、启动失败都以非零状态退出。dsh-app-bootassertEntriesLoaded / assertEntriesActivated 会审计:启用的条目若没有 fiber(插件解析失败)或激活失败,会在启动时以明确报错列出每个未解析插件或未满足服务;boot() 失败时先 dispose 部分上下文(让终端类表面先恢复终端)再以带标签的报错退出。

出处:packages/boot/app-boot/README.md

小结

profile + 组合包 + patch 层构成 DSH 的"组合机制":产品形态(web / headless / 自定义)由 profile 决定,能力集合由组合包决定,用户定制由 patch 层决定。下一部分将深入组合机制赖以运行的框架——Cordis(1.1 一切皆插件)。

参考资料

本文档为学习用途的原创讲解,基于 MIT 许可的开源项目 deepseek-ai/deepseek-harness 编写;所有引用均注明出处。