DSH 快速参考手册

DSH 快速参考手册

便于快速回忆 dsh 的核心概念、架构和插件开发流程。


一、dsh 是什么

dsh(DeepSeek Harness)是一个基于 Cordis 插件框架的 agent 运行时

核心思想:一切都是插件——模型适配器、工具注册表、会话管理、agent 循环本身都是插件,都可以替换。

与 Cordis 的关系

概念类比
CordisLinux 内核(IoC 容器 + 插件生命周期 + 事件系统)
dshUbuntu(在 Cordis 之上组装了一套 agent 系统)
dsh 的各个包Ubuntu 预装的软件
dsh --profileapt install + 启动脚本

dsh 插件 = Cordis 插件,没有独立的插件规范。

与 Codex 的类比

dsh 是 C/S 架构:

  • 服务端:Cordis 插件树(agent-loop、tools、llm 等)
  • 客户端dsh web(浏览器 GUI)、dsh headless(CLI)、ACP、JSON-RPC
  • 外部客户端:open-design、Python SDK 等通过协议调用

二、核心概念:Profile / Bundle / Patch

三者关系

Profile = 多个 Bundle 的有序叠加 + 配置覆盖层
Bundle  = 1 个 Patch + 代码 + package.json
Patch   = 1 个 YAML 配置文件(引用插件,不含代码)

配置层叠顺序(后者覆盖前者)

1. Bundle 1 的 cordis.patch.yml(dsh-base)
2. Bundle 2 的 cordis.patch.yml(dsh-web-app)
3. ...
4. Profile 自己的 cordis.patch.yml
5. $DSH_HOME/cordis.patch.yml(机器级全局偏好)
6. --patch <path> overlay(命令行临时覆盖)

官方 Profile

Profile组成用途
webdsh-base + dsh-web-app浏览器 GUI
headlessdsh-base + dsh-headless命令行一次性运行
dsh web                    # 启动浏览器 GUI
dsh --profile headless "任务描述"  # 命令行执行

三、插件开发

3.1 最简方式(不需要 clone 仓库)

在任意目录创建 TypeScript 文件,使用 --patch 加载:

// my-plugin.ts
import type { Context } from '@deepseek-ai/cordis'  // type-only,运行时擦除

export const name = 'greet-tool'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register({
    name: 'greet',
    description: 'Greet someone by name.',
    parameters: {
      type: 'object',
      properties: {
        name: { type: 'string', description: 'The name to greet' },
      },
      required: ['name'],
    },
    async execute(args: { name: string }) {
      return `Hello, ${args.name}!`
    },
  })
}
# my-patch.yml
- insert:
    - id: greet-tool
      name: '/absolute/path/to/my-plugin.ts'
dsh web --patch ./my-patch.yml

关键点

  • import type 运行时擦除,不触发模块解析
  • ctx.tools.register() 接受原始 JSON Schema,不需要 defineTool
  • 不需要 package.json,不需要 node_modules

3.2 defineTool vs 原始 JSON Schema

defineTool原始 JSON Schema
来自@deepseek-ai/dsh-tools无需导入
类型安全✅ args 有完整类型❌ args 需手动标注
运行时效果完全一样完全一样
是否必须

defineTool 是编译时的类型辅助函数,不是运行时必需品。

3.3 正式 Bundle 开发

// package.json
{
  "name": "dsh-my-plugin",
  "type": "module",
  "dsh": {
    "bundle": {
      "patch": "./cordis.patch.yml"
    }
  },
  "dependencies": {
    "@deepseek-ai/dsh-tools": "^0.1.0"
  }
}
# cordis.patch.yml
- insert:
    - id: my-plugin
      name: 'dsh-my-plugin'
# 安装到 profile
dsh plugin --profile demo add ./my-plugin

# 或从 GitHub
dsh plugin --profile demo add github:you/my-plugin

# 或发布到 npm 后
dsh plugin --profile demo add dsh-my-plugin

3.4 判断一个项目是否是 dsh 插件

检查三点:

  1. package.json 中有 @deepseek-ai/cordis 依赖
  2. 入口文件导出 apply(ctx: Context) 函数
  3. (可选)package.json 中有 dsh.bundle 声明
grep -r "apply(ctx" src/ --include="*.ts"
grep "@deepseek-ai/cordis" package.json
grep "dsh.bundle" package.json

四、插件类型

4.1 工具插件(Tool)

给模型暴露可调用的工具:

ctx.tools.register({
  name: 'greet',
  parameters: { type: 'object', properties: { ... }, required: [...] },
  async execute(args) { return 'result' },
})

4.2 Hook 插件

拦截 agent 生命周期,返回决策:

ctx.on('tools/pre-execute', async (exec, next) => {
  if (!allowed(exec)) return { kind: 'deny', reason: 'Denied' }
  return next() // 放行
})

可用拦截点:agent/session-startagent/pre-stepagent/requesttools/pre-executetools/post-executeagent/turn-stopping

4.3 Service 插件

暴露新服务 ctx.xxx 给其他插件使用:

import { Service, type Context } from '@deepseek-ai/cordis'

export default class MyService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'myService')  // 注册为 ctx.myService
  }
  doSomething() { /* ... */ }
}

4.4 提示词插件

往系统提示词注入内容:

ctx.systemPrompt.section({
  id: 'my-context',
  content: '注入到系统提示词中的内容',
  order: 100,
})

4.5 UI 插件

监听会话事件,渲染界面(详见第五节)。

4.6 LLM 适配器插件

ctx.llm.registerAdapter(new MyCustomAdapter())

4.7 协议驱动插件

对接外部协议(ACP、JSON-RPC)到 ctx.agents

4.8 MCP 插件

每个 MCP server 一个插件:发现工具 → ctx.tools.register()


五、UI 插件与 Slot 系统

核心思路

数据驱动渲染,不是 DOM 操作。

Session 事件流 → 插件匹配事件 → 构建状态 → 生成视图数据 → React 组件渲染

Slot(插槽)机制

UI 不是"到处放扩展点",而是用 slot 系统——只有关键区域有 slot:

// 注册组件到插槽
ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({
  name: 'conversation.chat.node',
  key: 'my-thing',
}, MyComponent))

已有插槽列表

对话区域conversation.chat.node(消息节点)、conversation.composer(输入框)、conversation.input.model(模型选择)、conversation.details.tool(工具详情)等

侧边栏sidebar.settingssidebar.workspaces

设置页面settings.sectionsettings.general.itemsettings.plugins.tab

工具相关tool.call.toolview

插槽的限制

操作能否通过插件实现
往已有插槽添加新组件✅ 能
修改已有组件的渲染逻辑❌ 不能,要 fork
修改已有组件收到的数据✅ 能(通过事件拦截)
移除已有组件❌ 不能,要 fork
改 CSS 样式✅ 能(注入 style)

六、TypeScript 结构化类型(给 Java 程序员)

TypeScript 的类型检查是结构化类型(类似 Go 的隐式接口),不是 Java 的名义类型:

interface Person { name: string; age: number }

function greet(p: Person) { ... }

// 以下全部合法,不需要 implements 声明:
greet({ name: 'Alice', age: 30 })           // 对象字面量
const dog = { name: 'Rex', age: 5, breed: 'Husky' }
greet(dog)                                   // 多了字段也行

只要结构匹配,就是合法的。 所以 ctx.tools.register() 可以接受任何结构匹配的对象,不需要通过 defineTool 创建。


七、dsh 与外部工具的集成

双向调用关系

方向 A: 外部工具驱动 dsh
open-design ──stdio 协议──→ dsh

方向 B: dsh 调用外部工具
dsh ──MCP 协议──→ open-design / 其他 MCP server

使用方式决定入口

使用方式入口谁启动谁
直接用 dshdsh web / dsh headless你启动 dsh
通过 open-designopen-design 桌面应用open-design 启动 dsh 子进程
通过 Python SDKPython 脚本SDK 启动 dsh 子进程

MCP 是核心标准

当前主流 agent 工具(dsh、Claude Code、Codex、Cursor 等)都在往"既能独立用,又能被别人调用"的方向走。MCP 协议是这个趋势的核心——它让 agent 和工具之间的关系变成"插头和插座",谁都能连谁。


八、常用命令速查

# 启动
dsh web                                    # 浏览器 GUI
dsh --profile headless "任务"              # 命令行执行
dsh --profile web --dump-config            # 查看组合配置

# 插件管理
dsh plugin --profile demo add ./my-plugin  # 安装插件到 profile
dsh plugin --profile demo remove my-plugin # 移除插件
dsh --profile demo --patch ./extra.yml     # 临时叠加配置

# 从源码运行(在 deepseek-harness 仓库内)
pnpm dsh web --patch ./scratch-plugin/cordis.yml

九、文档索引

主题链接
架构总览docs/architecture.md
第一个插件docs/user/develop/basic/index.md
工具开发docs/user/develop/basic/tool.md
Bundle/Profiledocs/user/develop/basic/publish.md
Extension Cookbookdocs/cookbook/extension-cookbook.md
Cordis 教程docs/cordis-tutorial/index.md
Slot 系统.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md