架构
一个库,六个 Service,一层 dsh
@mc/dsh-agent-kit 是一组 DeepSeek Harness(dsh)插件 Service。业务包通过 cordis 的 inject 使用它们,自己只写协议、路由、模板和流程。运维工具放在另一个可选的包 @mc/dsh-agent-kit-admin 中。
两个包
| 包 | 作用 | 谁依赖它 |
|---|---|---|
@mc/dsh-agent-kit | 六个 Service,以及 /ws、/dingtalk、/feishu、/notify、/agent-tasks、/jev、/secrets、/testing 子路径。没有命令行,也没有设置页 | 业务包(peer 依赖) |
@mc/dsh-agent-kit-admin | 可选的运维工具:dsh-agent-kit doctor / setup 命令行、dsh Web「设置 → Agent Kit」页、agentKitAdmin 服务与业务包设置入口的登记(@mc/dsh-agent-kit-admin/entry) | 运维按需加入 Profile;业务包不依赖它 |
dsh plugin --profile my-agent add @mc/dsh-agent-kit @mc/dsh-agent-kit-admin bundle 与 patch 层
两个包都在 package.json 中声明为 dsh 的 bundle。dsh plugin add 之后,dsh 会把它们的 patch.yml 加入 Profile 的层叠配置。基础包的 patch 注册六行,admin 包的 patch 注册一行:
| 行 id | 模块 | Context 属性 | 默认 |
|---|---|---|---|
agent-kit-ws | @mc/dsh-agent-kit/ws | ctx.agentWs | 禁用 |
agent-kit-dingtalk | @mc/dsh-agent-kit/dingtalk | ctx.dingtalk | 禁用 |
agent-kit-feishu | @mc/dsh-agent-kit/feishu | ctx.feishu | 禁用 |
agent-kit-notify | @mc/dsh-agent-kit/notify | ctx.notify | 禁用 |
agent-kit-agent-tasks | @mc/dsh-agent-kit/agent-tasks | ctx.agentTasks | 禁用 |
agent-kit-jev | @mc/dsh-agent-kit/jev | ctx.jev | 禁用 |
agent-kit-admin | @mc/dsh-agent-kit-admin | ctx.agentKitAdmin | 常驻(仅装了 admin 包时) |
六个 Service 默认禁用:dsh 不会导入禁用行的模块,也不会校验它的配置,所以未启用的 Service 缺少配置不影响启动。在 Profile 的 cordis.patch.yml 中按 id 启用即可;按 id 修改 config 时整段替换,不与 bundle 中的值合并。
# Profile 的 cordis.patch.yml
- id: agent-kit-dingtalk
disabled: false
config:
identity: bot
robotCode: dingxxxx
defaultTarget: { chatId: cidxxxx }
admin 包的常驻行 agent-kit-admin 很轻,不连接任何外部服务。它挂载 AgentKitAdmin(dsh Web 设置页调用的服务端接口),并让 dsh 发现 admin 包的前端模块,也就是「设置 → Agent Kit」页。它不影响基础包各行的启停;不装 admin 包时没有这一行,六个 Service 照常工作。
业务包如何接入
业务包把 @mc/dsh-agent-kit 声明为 peer 依赖,保证一个 Profile 中只加载一份实例;开发期可以用 link: 指向本包的本地 checkout。业务包不需要依赖 admin 包;只有要把自己的配置登记到设置页时,才从 @mc/dsh-agent-kit-admin/entry 导入 defineEntry(放进 devDependencies 即可),运行时调用 ctx.agentKitAdmin.registerEntry() 的插件则要求 Profile 中装有 admin 包。
{
"name": "@your-org/dsh-agent-your-project",
"type": "module",
"peerDependencies": {
"@deepseek-ai/cordis": "4.0.2",
"@mc/dsh-agent-kit": "^0.1.0"
},
"devDependencies": {
"@deepseek-ai/cordis": "4.0.2",
"@mc/dsh-agent-kit": "^0.1.0"
},
"dsh": { "bundle": { "patch": "./patch.yml" } }
}
业务包的插件只 inject 用到的 Service,例如 export const inject = ['agentWs', 'notify']。Service 注册的连接、定时器、子进程都随业务包插件的生命周期释放。
只需要发通知时,推荐 inject notify 而不是 dingtalk 或 feishu。notify 不 inject 渠道 Service,而是在发送时查找它们:cordis 4 的 inject 都是必需的,如果 inject 了渠道,停用任一渠道都会连带卸载 notify 与依赖它的业务插件。现在启用、停用渠道行只影响发送结果;修改 notify 自己的 channel 时,notify 在自己的 internal/update 钩子里原地换上新值,拦截了 cordis 默认的重启。两种情况都不会重新加载 notify,也不会重新加载只 inject notify 的业务插件。
依赖与版本对齐
@deepseek-ai/cordis、@deepseek-ai/schemastery、@deepseek-ai/dsh-typert-protocol是 peer 依赖,版本与目标 dsh 对齐。dsh 会把它自己的依赖提供给 Profile,peer 声明保证只有一份实例;放进 dependencies 会装出第二份,破坏 Context 类型扩展和远程方法标记。@typesafe-ai/sdk是可选 peer 依赖,只有启用 Jev 时才需要安装。- 基础包自己的运行时依赖是
ws、ajv、yaml与@deepseek-ai/dsh-atomic-write;admin 包另外依赖@inquirer/prompts、diff、yaml,并把@mc/dsh-agent-kit声明为 peer 依赖。
配置从哪里来
配置只有一个来源:Profile 的 cordis.patch.yml。admin 包的 setup、Web 设置页和手动编辑读写的都是它。Profile 为 patchReload: live(web 模板的默认值)时,dsh 监视这个文件,修改后用新配置重新加载对应 Service(notify 例外:修改 channel 时原地生效,不重新加载);为 startup 时需要重启 dsh。密钥不写进这个文件,而是保存在环境变量、钥匙串或 dsh 凭据文件中。