dsh-preset-route
DiscoveredDSH agent preset: reads the live agent-preset roster, picks the preset a task should go to, and drafts a paste-ready task brief in that preset's real input contract. Read-only by construction.
dsh-preset-route
一个 DSH agent preset,只做两件事:ROUTE(判断该由哪个 preset 接这个任务)和 DRAFT(为那个 preset 写一份可以直接粘贴、自包含的任务简报)。它不执行任务,也不替你按下发送。
- 包名:
dsh-preset-route,版本0.3.1,MIT。 - 装上之后 roster 里多一个 preset:id
route,显示名Route,order: 20。 - 零依赖:不 import 任何
@deepseek-ai/*,也不 import 任何第三方包;只用 Node 内置能力。这样任何 profile(哪怕没有@deepseek-ai/*依赖树)都能装、都能挂载。
为什么需要它
DSH 的 session 会挂载一个 agent preset,而 preset 的真实能力面(有哪些工具、能不能写盘、能不能起子 agent、会不会中途反问、什么时候失败)写在它的 composition 行里,不在描述文案里。人挑 preset 时靠印象,写任务时又常把"刚才那个判定""如上"这类只有当前对话里才成立的话留在简报里——换到另一个 session 就全失效。
这个 preset 把两件事固化下来:先按能力面裁决,再按目标 preset 真实的输入契约写简报。
同类插件对照(调研时间 2026-10-29)
DSH 生态里叫「router」的插件分三类,本插件只在第三类里;详细逐仓对照见 docs/COMPARISON.md。
| 品类 | 代表仓库 | 路由对象 | 读 live roster 的 composition 行 | 产出自包含 brief | 输出形态 |
|---|---|---|---|---|---|
本插件 dsh-preset-route | 本仓库 | 跨 preset 选一个 | ✅ 按行推导能力 | ✅ 按目标 preset 输入契约 | 一行 PRESET: + prompt 围栏 |
| 本会话内行为路由 | dsh-routing-suite、dsh-router-flash、router-evo、router-trio | 单个 preset 内的 persona / 首轮工具面 | ❌ 关键词正则 + 写死表 | ❌ | 无文本契约,代码内自动应用 |
| 代码内自动切 preset | dsh-auto-preset-router、dsh-agent-preset-router、dsh-preset-run | 跨 preset(自动) | ❌ 最多取列表存在性 | ❌ | 无,直接切换并执行 |
| 交付/写作辅助(相邻) | glm-routing-suite(交付证据门)、dsh-routing-suite 的 P1–P30 度量、dsh-prompt-layers(prompt 分层) | 交付物或 prompt 层 | ❌ | 仅自然语言提及 | 与 preset 选择正交 |
调研结论一句话:读 live roster 的真实 composition 行做硬排除、按目标 preset 的输入契约写 brief、输出前自校验这三件事,在上述同期仓库里没有同时出现的实现。
安装
要求:DSH >= 0.2.1-rc.2(实测版本见 CHANGELOG),Node >= 22。
# 一条命令装好(从仓库 clone,按 tag 钉版本)
dsh plugin --profile <profile> add -w git+https://github.com/Milliontimes/dsh-preset-route.git#v0.3.1
# 或者从本地 checkout 装
dsh plugin --profile <profile> add -w /path/to/dsh-preset-route
-w 不能省:profile 目录的 package.json 同时是 pnpm workspace 根,pnpm 会把不带 -w 的添加当成"往根上加依赖"并拒绝(ERR_PNPM_ADDING_TO_ROOT)。
dsh plugin add 除了装依赖,还会把包的 bundle 名写进 profile 的 dsh.profile.bundles(实测 0.2.1-rc.2 两次:全新 profile 一次命令后 bundles = ["@deepseek-ai/dsh-base", "dsh-preset-route"]),所以不需要手改 JSON,也不需要重启——Loader 会热挂载新行。装完确认:
dsh --profile <profile> --dump-config | grep -A2 preset-route
期望看到 - id: preset-route 与 - id: preset-route-tools / name: dsh-preset-route/tools。
若只用裸 pnpm add 装(绕开 dsh plugin),bundle 名不会被写进 dsh.profile.bundles,preset 不会出现在 roster 里——那才需要手工补一行。
dsh plugin --profile <p> add dsh-preset-route@0.3.1 这种 registry 形式要先把包发到 npm 兼容 registry,当前版本只发布了 git tag,没有发 registry。
desktop profile 由 Electron 独占,dsh plugin --profile desktop 会被拒绝(profile "desktop" is managed exclusively by the Electron application);那种情况下用应用内的插件面板安装本地 bundle 目录,它会同时完成装包和选中 bundle。
卸载
dsh plugin --profile <profile> remove dsh-preset-route
卸载会同时清掉 dependencies、dsh.profile.bundles 和 node_modules 里的条目(实测),profile 目录里不留 dsh-preset-route 痕迹。
用法
在挂载了 route 的 session 里,直接用自然语言说任务:
帮我把 C:\work\repo 的测试修到全绿,改完给我一份变更说明。
它会先读一次 live roster,然后只输出两样东西(格式是硬约束,见 presets/route/plugins/protocol.js):
- 第 1 行,围栏外面:
PRESET:+ 反引号里的 preset 名字(没有显示名就写 id) - 第 2 段:一个 ```prompt 围栏,围栏里是完整 brief
形状:
PRESET:`standard`
```prompt
(brief 正文,可以很多行、Markdown 标题、列表、表格)
```
三种变体仍然只有一行 PRESET:
- 并列:PRESET:
a(并列b,推荐a) - 无匹配:PRESET:
NONE(最接近standard,缺 web) - 名册不可读:PRESET:
NONE(roster 不可读:<原因>)
brief 内部不许再出现三反引号围栏(要贴命令或代码就用 4 空格缩进或行内反引号)——嵌套围栏会让整段无法复制,这是 0.3.0 修掉的返工点。
除这一行和这个围栏之外不输出任何东西:没有判定解释、没有置信度、没有候选排名、没有失败诊断(名册不可读时只在那行括号里写一句原因),围栏前后也没有「以下是简报」这类说明句。判定过程是内部推理,不是交付物。
替换掉的旧格式(ROUTE/TASK/DECISION/CONFIDENCE/EVIDENCE/WOULD FLIP IF/BRIEF-NOTES)在 0.2.0 起不再输出;替用户做的假设改为写在简报末尾的 ## 假设与待确认 里,跟着简报一起进目标 preset。
判定规则
ROUTE 的顺序固定,不允许跳过:
- 能力归约:把任务拆成动作需求——读文件、写文件、执行命令、持久/长跑、外部检索、多 agent 编排、需要人工确认、需要审计留痕。
- 硬排除:某项需求在某个 preset 的 composition 里没有对应行(或该行被禁用、平台条件不满足)→ 直接出局。硬排除不看描述文案,只看行。
- 软排序:都满足时按工具冗余(用不到的高权限工具是风险面)、上下文成本(启用行数、是否有常驻 shell/web/委派)、额外插件依赖、失败模式可接受度排序。
- 三种结论,只有三种:唯一匹配 / 并列(给推荐顺序)/ 无匹配(给最接近的 preset + 缺的能力)。
判不准时不硬选:能力面等价、软排序也分不出高下就输出 TIE;关键事实缺失且猜错代价高,先用 ask_user_question 一次问完(≤3 个),再输出两样东西;roster 降级就输出 NONE。
conditional 的意思是:那一行带 !!js 的 disabled 表达式,只有挂载时才知道真假。这种行一律按"条件支持"看待并记住条件原文,绝不猜成可用。
数据源:live roster,不缓存
- 每次调用都从 Host 的
agentPresets服务重新读:list()、逐 presetreadDocument()、compositionInventory()/inspectCompositions()。 - 结果里带
read_at和单调递增的read_seq,同一轮对话里两次调用的read_seq不同就证明确实重读过。改动 roster(加 preset、删 preset)后无需重启,下一次调用就能看到。 - 读不到时(服务不存在、文档解析失败)降级不臆造:返回
ok:false、code:"ROSTER_UNREADABLE"、paths_checked、lookup_attempts,协议要求第一行输出PRESET: NONE(roster 不可读:<原因>),不写别的诊断。hint明确禁止"凭记忆列 preset id"。 - roster 里
broken非空的 preset(激活失败)照常出现在列表里,但不会被当作确定候选:判定会避开它,或在同一行括号里说明它坏了。
工具(4 个,全部只读)
| 工具 | 作用 |
|---|---|
route_list_presets | 读 live roster:每个 preset 的能力模型、逐条证据、输入契约、成本画像。可选 include / include_rows / include_documents。 |
route_read_preset | 读单个 preset,可带原始声明 YAML,用来核对某一行或引用确切的 module/条件。 |
route_capability_check | 把动作需求(fs_read、fs_write、shell、shell_persistent、web、subagent、workflow、jobs、ask_user、goal、plan_mode、skills、present、plugin_admin、cordis)逐项对每个 preset 判定 supported / partial / missing,附支持行。 |
route_validate_output | 输出前自检:PRESET 行里的 preset id 必须在 live roster 上(TIE 至少两个、NONE 放行)、简报 ≥200 字符、简报里不许出现跨会话指代和 PRESET/ROUTE/DECISION/CONFIDENCE/EVIDENCE 这类路由词汇。 |
这个 preset 自己的工具面也是可核对的:read/read_image/glob/grep + ask_user_question + 上面四个 route_*,没有 write/edit、没有 shell、没有 web、没有 subagent/workflow、没有 todo/goal。ROUTE 只读这条约束由 composition 保证,不靠提示词自律。
输入契约决定简报形状
简报不是套模板。每个目标 preset 的 input_contract 由它的 composition 行推出,至少覆盖:
- 交付物是写文件还是只能在回复里给文本(
tool-fs.write/edit的真假); - 会不会中途反问(有没有
tool-ask-user)——没有就写成一次性无人值守任务; - 要不要先立 goal(有没有
tool-goal/command-goal); - 命令执行是一次性还是持久 shell(
timeoutMs默认 300000,超时即失败); - 有没有外部检索、有没有委派能力、有没有 plan mode。
所以同一个任务给 standard(可写盘、可起子 agent、有 web)和给 minimal(tool-fs 只读、没有 web/委派、只有持久 shell)写出来的简报,结构、步骤数、验收方式都会明显不同。
简报的八个要素:① 目标(带判别器:"若 A 成立期望 X,若 B 成立期望 Y")② 约束 ③ 输入(路径、凭据位置、已知事实、排除项)④ 交付物与落盘位置 ⑤ 验收方式与验收人 ⑥ 停止条件 ⑦ 预算/时限及超限处理 ⑧ 禁止事项。按目标 preset 增删时必须写明删了哪条、为什么。
反例:哪种简报是废的
任务:按前面说的方案把那个清单整理好,格式如上所述,写完告诉我。
为什么废:
- 跨会话指代:"前面说的方案""如上所述"只在当前对话成立。目标 preset 是另一个 session,看不到这些,收到后只能反问或瞎猜。
- 没有落盘位置:说"整理好"却不说写到哪个文件。若是"会话销毁只剩文件"的那类 preset,等于没交付。
- 没有验收口径:怎么样算"整理好"没有定义,执行者只能自定标准。
- 没有边界:没说能不能改源文件、能不能顺手做别的,等于把越权空间留给执行者。
- 带了路由词汇:如果把"按上面的判定"也抄进简报,等于把路由推理泄漏给执行者——执行者不需要知道为什么选它。
route_validate_output 会把第 1、5 类问题直接判成 ok:false(跨会话指代正则 + 路由词汇正则),第 2、3、4 类由协议里的八要素清单拦截。
已知限制
- registry 形式需要先发包:
dsh plugin add dsh-preset-route@0.3.1走 pnpm 的 registry 解析,目前只发布了 git tag,所以用git+https://…#v0.3.1或本地 checkout。要发 registry(npm 兼容 registry),属于包名与凭据的决策,需先确认。 - desktop profile 不能用 CLI 装:Electron 独占,
dsh plugin --profile desktop直接报错,必须走应用内插件面板。 headlessprofile 挂不了 preset:@deepseek-ai/dsh-headless的 one-shot runner 不 compose preset(它agents.create时压根不传 preset,且assertAdoptable拒绝接管跑过 preset 的 session),所以dsh --profile headless永远只有 host 面工具,roster 也不含 shipped preset(那些声明来自@deepseek-ai/dsh-web-appbundle)。- 自定义 profile 默认没有 registry 行:
agent-preset-registry只由@deepseek-ai/dsh-web-appbundle 插入。base + 本插件的 profile 里所有 preset 行会停在pending (waiting for service: agentPresets),preset 不会挂载(验收里用test/fixtures/preset-hosting.patch.yml补上这一行)。 - 第三方 JS 插件 preset 的工具面不可静态判定:如果某个 preset 用 JS 插件在运行时注册工具(像 clearai 的 kernel),roster 的行列表看不出它最终暴露什么。这种情况能力模型会标
notes,判定最多给medium。 !!js条件不猜:只在挂载时能求值的行报conditional+ 条件原文。- platform 条件只认字面形式:
process.platform === 'win32'/!== 'win32'这类能静态判定;更复杂的表达式一律conditional。 - roster 的 name/description 是插件自己给的:Host 不做本地化;
description必须是块标量或加引号,否则 YAML 会解析成映射,roster 静默退化成"没有元数据"。 - 简报的落盘位置要在会话工作区内:preset 的
tool-fs受 profile 的 file policy(默认workspace-write+cwd作为 workspaceRoot)约束,写到工作区外会触发沙箱拒绝,而一次运行往往没有审批通道。DRAFT 会把绝对路径写进简报,但路径是否可写由运行环境决定——这类外部依赖会写进简报末尾的## 假设与待确认。
回滚
# 一条命令回滚
dsh plugin --profile <profile> remove dsh-preset-route
# 确认 roster 回到安装前(期望 0 行输出)
dsh --profile <profile> --dump-config | grep -c 'preset-route'
route 不写宿主配置、不改别的 preset、不碰 sandbox/approval/model 路由,所以卸载即回到原状;如果把 preset 设成了默认(agent-preset-registry 的 config.default: route),记得改回原值。
凭据
本仓库不含任何 token、密码、私钥、内网主机名或地址。Brief 只允许写凭据的位置(环境变量名、凭据服务名、页面路径),禁止把值写进简报、日志或提交信息。scripts/verify.mjs 与验收记录里的 grep 结果可复核。
开发
node --test test/ # 用真实 patch 文件跑 scanner/能力模型测试
node scripts/verify.mjs # 静态自检:清单、只读面、声明行、section 顺序、locale、icon
License
MIT,见 LICENSE。
Comments
Loading…
Similar plugins
by sherconan
Web mascot that acts out each live tool call (read, write, edit, search, run, plan, sub-agent, wait, error) with matching step cards in chat; ships two swappable character packs.
★ 0
JavaScript
Oct 23, 2026
dsh plugin --profile web add dsh-task-mascotby svgop
Agent instruction manager for DSH — edit and template the AGENTS.md files the harness actually reads (global + per-workspace)
★ 0
MIT
JavaScript
Oct 5, 2026
dsh plugin --profile web add dsh-rich-contextby QlzqQlzq
Installs two selectable Agent Presets: a shell-restricted general-purpose agent and a repository-focused coding agent.
★ 1
MIT
JavaScript
Aug 15, 2026
dsh plugin --profile web add dsh-dual-agent-presetsby Neo65536-engineer
Read-only work reports for DeepSeek Harness: reconstruct what an agent task actually did from session logs — tools used, files read/written, commands run, test results, failures, token usage, and whether it finished. Fully offline, no API key, no data leaves your machine.
★ 1
MIT
JavaScript
Sep 26, 2026
dsh plugin --profile web add dsh-agent-logby datit309
Auto-monitor and reveal active file operations and changes in DeepSeek Harness (DSH) right sidebar
★ 2
JavaScript
Sep 29, 2026
dsh plugin --profile web add dsh-live-inspectorby HaoyanZhang123
DSH skill provider bundle for live agent-preset switching guidance
★ 0
MIT
JavaScript
Sep 11, 2026
dsh plugin --profile web add dsh-live-preset-switch