dsh-subagent-routes:按工作区目录给子智能体路由 provider、模型与思考等级

前言

DSH 里给子代理选模型,原本只有三档:工具实例的静态 agentOptions、会话级的 subagent-model-selection 白名单、具名子代理库的逐条目配置。这三档都表达不了一件事:你在哪个项目目录里干活,子代理就用那个项目配好的模型。结果是每次派活都要手动挑一遍,或者干脆将就。

dsh-subagent-routes 就是补这一档的插件。它由 zdt3476 维护,仓库为 zdt3476/dsh-subagent-routes,社区目录分类归在「模型推理」。插件按工作区的目录做最长前缀匹配,把匹配到的 provider / model / 思考等级注入子代理的 agentOptions,并提供可视化设置页。下面介绍它的能力与用法。

这是什么

一句话定位:一个 DSH 插件,根据子代理派活时父会话所在的工作区目录,为子代理指定 provider、模型与思考等级。

它解决的痛点是「项目级路由」。前端项目想找强模型、长文档研究想固定最大思考等级、临时脚本想用便宜模型、一个仓库里不同子目录用不同策略——这些都无法用现有三档配置表达。插件用一张最长前缀匹配的路由表覆盖这些场景,同时提供一个设置页,避免手写 YAML。

社区目录页的分类是「模型推理」,仓库当前为 1 stars,属于小体量个人项目。

核心功能

路由只作用于新派活的子代理,对已经在跑的会话不做任何改动。

插件介入的位置很单一:所有创建子代理的入口(subagent、subagent_fork、workflow、agent-team、具名子代理库的 delegate)最终都会调用 ctx.subagents.startActivation,插件只在这一处拦截。因此它天然覆盖全部派活路径,不需要改 DSH 本体。

处理流程是:

  1. 读父会话的当前工作目录(workingDirectory 投影优先,回落到会话头 cwd);
  2. 在路由表里做最长前缀匹配;
  3. 把匹配到的 provider / model / reasoningEffort 合并进 request.agentOptions;
  4. 按需调用 llm.resolveCallConfig() 预检,路由非法时在派活处直接失败。

派活时不写会话事件、不改 profile;只有用户保存基础配置时,才通过宿主 configEditor.edit 持久化到当前 profile,并校验、重载插件。

设置页提供三级联动选择:Provider、Model、思考等级全部从宿主已探测的列表里选,不用背 ID。私有通道支持「手动输入」。未选 Provider 时 Model 下拉按厂商分组列出全部模型,选项内部同时编码 provider + model,不同厂商的同名模型不会互相覆盖。思考等级跟随所选模型的真实元数据:模型不支持推理时选项置灰并清空;支持时只列出该模型的专属档位;手动输入的未知模型 ID 会保留已选等级,插件不擅自改写。

项目规则里的「项目根目录」默认从宿主已登记的工作区里挑(显示为「标题 — 路径」),需要 ~/... 或更细的子目录时可切「手动输入」。偏好直接编辑时,右上角可切「原始 YAML 模式」,可视化表单与 YAML 双向同步,保存时校验结构。

此外,会话页面输入区有一个状态药丸(子 provider / model ▾),点击可就地临时切换本会话的 provider / model,用于临时拔高或降配,而不必改规则。右侧栏仍保留一个更接近配置表单形态的「子代理」tab,两处共用同一份优先级判定与数据面。

安装与启用

安装命令来自仓库 README:

# 从本地目录安装
dsh plugin --profile desktop add /path/to/dsh-subagent-routes

# 或从 npm 安装(发布后)
dsh plugin --profile desktop add @zdt3476/dsh-subagent-routes

首次安装、或从没有 client 的旧实现升级后,需重载插件或重启 DSH,确保宿主加载新的 client 能力;仅打开旧设置页不会补载新入口。若重载后仍无设置入口,请重启 DSH。

安装后设置入口出现在「插件管理 → 本插件 → 设置」,bundle 卡片与 patch 插件行均提供入口。会话页右侧栏 tab 与输入区药丸由同一份 client 产物注册;若右侧栏没出现「子代理」,同样先重载插件,仍不行再重启 DSH(客户端插件的 Slot 注册只在插件加载时进行)。

典型用法

三步即可跑起来,全程不需要手写 YAML:

  1. 打开设置页:插件管理 → 本插件 → 设置。
  2. (可选)设全局默认模型:没匹配到任何项目时用它兜底,留空则继承父会话模型。
  3. 添加项目规则:点「+ 添加项目规则」→ 从工作区下拉选项目 → 从模型下拉选模型 → 思考等级自动跟着模型联动 → 「确认保存规则」→ 底部「保存所有更改」。

保存后下一次新派活立即生效,不需要重启 DSH。

也可以直接手写路由表。默认位置是 $DSH_HOME/subagent-routes.yaml(通常是 ~/.dsh/subagent-routes.yaml),可视化设置页就是它的编辑器:

default:
  provider: openai
  model: gpt-4.1
  reasoningEffort: medium

routes:
  - path: ~/Code/frontend-app
    provider: anthropic
    model: claude-sonnet-4
    reasoningEffort: high
  - path: ~/Code/frontend-app/legacy    # 更长前缀优先
    provider: deepseek
    model: deepseek-chat
  - path: ~/Code/research
    reasoningEffort: max                # 只改等级,provider/model 继承父会话

字段规则:path 必填,绝对路径或以 ~ 开头,尾部分隔符会被规范化掉;provider 与 model 必须同时出现或同时省略;reasoningEffort 使用适配器自有的等级 id(low / medium / high / max 等,取决于模型);三者至少要有一个。

改路由表后,下一次新派活即生效,每次派活都会重读文件,不需要重启。

优先级规则

从高到低:

调用方显式指定 > 本会话选择 > 项目规则 > 全局兜底 > 全局默认策略

具体行为:

  • 调用方显式给了 provider + model → 插件完全让位,连思考等级也不追加(这是给工作区模型配的等级,套到另一个模型上可能不被支持)。
  • 调用方只给了 reasoningEffort → 插件补 provider / model,保留其等级。
  • 本会话选了「继承主代理」→ 直接让位,项目规则与全局策略都不介入。
  • 本会话选了「指定一套」→ 覆盖项目规则。
  • 本会话未做选择(界面默认态,存储层记为 follow)→ 继续按上述层次判定。
  • 全局策略是「继承主代理」→ 让位,不查路由表。
  • 全局策略是「使用路由规则」→ 按目录匹配项目规则,未命中时用全局兜底。
  • 所有层都没有内容 → 插件不注入任何字段,子代理保持 DSH 原生的继承行为。

会话级切换存在 $DSH_HOME/subagent-routes.overrides.json,与路由表同目录,原子写入、保留最近 100 个会话。注意「继承主代理」没有可写入路由表的 provider / model,该状态下「固化为项目规则」按钮会置灰;固化到某目录时该目录已有条目会被替换,不会追加成第二条。

插件配置项

在 profile 的 cordis.patch.yml 里按 id 覆盖。同 id 的 override 会替换整个 config,三个字段要写全:

- id: subagent-routes
  config:
    routesFile: ~/.dsh/subagent-routes.yaml
    enabled: true
    preflight: true
    fallbackPolicy: rules
字段 默认 说明
routesFile $DSH_HOME/subagent-routes.yaml 路由表路径,留空用默认位置
enabled true 路由注入开关,false 时停止注入,设置入口仍保留
preflight true 注入前用 llm.resolveCallConfig 校验路由,关掉则把错误留到子会话首轮
fallbackPolicy rules inherit = 没有更具体来源时继承主代理模型;rules = 按路由表注入

这四项在设置页里分别对应「已启用 / 已暂停」开关、「全局默认策略」卡片与折叠的「高级选项」,改完点底部「保存所有更改」即可,无需手工编辑 profile。fallbackPolicy 写了未知值时按 rules 处理,并在日志里保持可解释。

适用场景与注意

适合需要项目级模型路由的 DSH 用户,尤其是一个 profile 下同时维护多个项目、对成本与能力档位有差异化要求的开发者,或想按目录固定思考等级的长文档研究场景。

使用时要清楚几点:

  • 插件只影响新派活,正在运行中的子代理不会被重新路由。
  • fork 同样适用,但 fork 会继承父会话的对话前缀,换模型会让这段前缀的 provider 侧缓存失效,属于预期代价。
  • 前缀匹配是纯字符串的,不做 realpath,符号链接和 .. 不会自动归一。
  • 工作区与模型列表来自宿主;宿主没提供对应服务或该 profile 尚未登记工作区时,设置页会自动退回手动输入。
  • 会话指定必须成对给模型,只指定 provider 或只指定思考等级会被拒绝。
  • 路由表写错时日志会给出行号级说明,该次派活按「无路由」继续,不会阻塞工作。

还需要说明的是,插件以当前 dsh 进程的权限运行,安装前应检查源码与许可证。仓库声明为 MIT 许可(见 package.json 的 license),要求 Node ^22.19.0 || >=24.0.0、DSH >=0.2.1-0。

结尾

dsh-subagent-routes 做的事情很窄:把子代理的模型路由从「全局一个选择」细化到「按工作区目录一条路由」。它的价值在于不需要改 DSH 本体、原生覆盖全部派活入口,并提供可视化设置页降低维护成本。项目当前星标不多,功能边界写在「已知边界」一节,是否有自己需要的行为,建议对照后再看是否采用。

目录页:https://www.skillhub.cn/plugins/zdt3476/dsh-subagent-routes

GitHub:https://github.com/zdt3476/dsh-subagent-routes

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜