npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-shift-router

v0.7.4

Published

Two-tier model router for DeepSeek Harness: an LLM Judge sends each turn to the cheap Fast chain or the Smart chain by expected cost, with multi-model fallback chains, exponential-backoff failover, cache-aware switching and task-level orchestration. A DSH

Readme

English · 简体中文

dsh-shift-router

面向 DeepSeek Harness 的双层模型路由器 —— LLM 裁判按期望成本把每一轮交给便宜的 Fast 层或 Smart 层,并配以多模型回退链、指数退避故障转移、缓存感知切换,以及「Smart 规划、Fast 执行」的任务级编排。

由 pi-shift-router 适配到 DSH 的版本。 本项目分叉自上游 v1.0.0(本仓库首个提交与上游该 tag 同日,均为 2026-08-14,因此上游若干版本 的内容在此本就存在),此后重新对齐到上游 v1.6.0 —— 逐版本状态(已对齐/已适配/刻意不移植) 见 ROADMAP.md 的 Upstream alignment 表,契约见 SPEC.md。

License npm DSH Node Tests Coverage DSH plugin

日常对话不该花旗舰模型的钱;真正重要的对话也不该交给便宜模型。

在每个顶层 Agent 的每一轮开始之前,一个轻量的 LLM 裁判(默认运行在你的 Fast 层模型链上,见 routing.judge.mode)会把用户消息判定为 fast(日常)或 smart(重要)。被选中的层随后通过 harness 自身的 agent/request 管线驱动整轮——思考、工具调用、代码编辑。裁判只做判定,从不干活。

🦾 [deepseek-flash]     → fix the failing test
🧭 judging…
🧠 [deepseek-v4-pro]    ← "design the auth flow" → 立即升级
⚠️ deepseek-flash 429 → 冷却中,同层故障转移 — 1 分钟后重试
🦾 [deepseek-v4-flash]  ← Fast 链中的下一个健康模型

特性

  • 期望成本路由(EV) —— 当且仅当 pSmart ≥ θ 时走 Smart,其中 θ = 1/reworkPenalty:这条门槛与模型价格无关,所以唯一的旋钮就是"错误降级有多痛"。升级是即时的;降回来需要 downgradeMemory 次连续的决定性 fast 判定。判定不确信时一律保持原位,绝不猜测。
  • 可插拔的裁判来源 —— 判定默认来自 Fast 链;routing.judge.mode 可以把它指向一条专用裁判链(custom),或指向决策模型(decision —— TypeSafe Jev / System One 这一类,Beta):它返回的是带类型的选项与概率而不是散文,因此没有回复解析步骤,也不存在"回复格式坏了"这一类失败。本部署对真实端点的实测:协议正确、每次判定 1.4–5.7 秒(15 秒下限是实测需要——5 秒默认值会把其中两次直接掐断),且 4 个 prompt 的档位判定全部是完全确定的结果,所以请把它当作硬分类器而不是细腻的连续判断;只有编排信号是连续的(0.10–0.83)。任何已配置的来源不可用时都会回落 Fast 链;而完全没有裁判时路由器就停止路由——本轮改用你自己选定的模型、编排被清除,且每个会话只提示一次。
  • 缓存感知路由 —— 当 Fast 与 Smart 共享同一 provider 时,决策门槛会除以 sameFamilyPenalty(默认 1.5),并在 prompt 缓存仍热时抑制降级,避免切到便宜模型反而更贵。
  • 运行时故障转移 —— 429 / 402 / 5xx / 配额 / 用量上限 / 模型下线 等失败会把模型置入指数退避冷却(1m → 4m → 16m → 1h04m → 4h16m,上限 6h;客户端侧限流从 16m 起步),并在同一层内重新解析到下一个健康模型——同一轮内重试,绝不跨层。
  • 任务级编排 —— 复杂任务会让 Smart 层担任 CTO:规划、通过 harness 的 subagent 工具把实现委派给 Fast 层工程师子代理、逐个审查结果并迭代。硬上限由插件强制执行而非仅靠提示词:每次委派计一轮、连续工作代理失败计一次升级,一旦触顶 subagent 工具会被直接拒绝、系统提示词切换为"立即收尾"通知。
  • 成本遥测 —— 按层统计 token,可选的 USD 计价表(/router status 会显示"本次会话若全程使用 Smart 模型将花费多少")。吞吐速率不在此列:DSH 原生已在消息页脚与 trajectory 面板显示 tok/s,且按解码时间计算,口径更准。
  • 动作可见 —— 切换档位或模型时会往对话里写一条 [shift-router] Fast → Smart · … 通知(harness 没有给插件预留状态栏座位),所以插件启用后不会"静默地什么都没发生"。把 ux.routerLogVerbose 打开,则每一轮判定都会有一条通知,而不只是切换时。
  • 零配置启动 —— 未配置分层前完全无操作;配置完成后路由立即生效。配置可通过 GUI 设置面板 和 /router config 命令实时编辑(持久化,无需重启)。

安装

本包是一个 DSH bundle:cordis.patch.yml 会把插件行插入任何声明了它的 profile。下面每条通道最后都是同一条 dsh plugin --profile <name> add …——它在 profile 目录里转发给 pnpm。

从 npm 安装(推荐)

dsh plugin --profile web add dsh-shift-router

安装的是预构建产物:不会在你的机器上运行任何构建脚本,因此无需任何授权。

从 tarball 安装

npm pack      # 或下载 release 里的 tarball
dsh plugin --profile web add ./dsh-shift-router-0.7.0.tgz

同样是预构建产物;无法访问 registry 时用这条。

从 git 安装

dsh plugin --profile web add github:green-dalii/dsh-shift-router#v0.7.0

git 安装拉到的是源码而非构建产物,因此由包的 prepare 脚本构建 dist/。pnpm ≥ 10 默认拒绝 git 依赖的 prepare——若第一次 add 失败,把 pnpm 打印的确切包键复制进 profile 的 pnpm-workspace.yaml 后重新执行:

allowBuilds:
  dsh-shift-router: true

这等于允许该包的代码在安装时于你的机器上执行,且不在 agent 沙箱内。请锁定 tag 或 commit(…#v0.7.0、…#<sha>),避免后续 push 悄悄改变你实际运行的内容。

从本地检出安装(开发用)

git clone https://github.com/green-dalii/dsh-shift-router.git
cd dsh-shift-router && npm install && npm run build
dsh plugin --profile web add /path/to/dsh-shift-router

确认这一层已生效

dsh --profile web --dump-config | grep -A3 'id: shift-router'

插件无需任何配置即可加载(所有默认值都安全);分层模型来自设置卡片(SPEC §12)或 profile 的 patch 行。后应用的层胜出,且 patch 会替换目标行的整个 config 值——覆盖本行的 patch 必须重述它需要的每一个键(SPEC §10)。

热重载

DeepSeek Harness 通过 @deepseek-ai/cordis-plugin-hmr 支持热重载,但有两点需要了解:

  1. 官方 Web bundle 默认禁用了共享 HMR 行(packages/bundle/web-app/cordis.patch.yml 中是 - id: hmr, disabled: true,上游 TODO:"在 Web 的重载生命周期测试通过后重新启用共享 HMR")。在 profile patch 中重新启用它——这是文档化的覆盖机制:

    # ~/.dsh/profiles/<name>/cordis.patch.yml
    - id: hmr
      disabled: false
  2. 哪些能热重载、哪些不能(已对照当前实现实测):

    • ✅ 配置改动 —— 编辑 profile patch(或 home patch)会以新配置重新执行受影响插件的 apply(),无需重启。插件自身配置也通过 settings 命名空间热生效(/router config set 与 GUI 卡片本来就不依赖 HMR)。
    • ❌ 模块(代码)改动 —— 当前 HMR 的 accepted 依赖图只覆盖 harness 自身模块;修改外部插件的编译产物(如 dist/index.js)在现行版本中不会触发重载,因此代码改动仍需重启。这正是上游 TODO 所指的未经测试的 "reload lifecycle",不是本插件的局限。
    • ❌ client 包元数据 —— dsh.client manifest 与 exports["./client"] 在进程内缓存,新增/修正后必须重启 profile;仅 dist/client.js 内容变化可走 client HMR 重建链。

    实践建议:用 /router config / 设置面板做配置(始终实时);改模型就编辑 patch(开启 HMR 后实时);只有改动插件代码时才需要重启。

配置

配置位于 shift-router settings 命名空间:可在 GUI 的 左侧栏「插件」 → dsh-shift-router → shift-router 行 → 配置中编辑、用 /router config 命令修改,或通过 profile patch 行配置。所有字段都有安全的默认值。

唯一必须由你决定的是档位模型:docs/MODELS.zh-CN.md 说明如何挑选 Fast 与 Smart 模型(Fast 链默认同时充当裁判链)、什么样的模型适合做回退、以及哪些模型能接收图片。

| 字段 | 默认值 | 说明 | |------|--------|------| | enabled | true | 总开关 | | tiers.fast.models | [] | Fast 层模型链(provider/model + priority);同时也是裁判的默认来源 | | tiers.smart.models | [] | Smart 层模型链 | | routing.mode | auto | auto(默认):裁判 + 路由 + 故障转移 + 编排;manual:无裁判,仅显式 /route-force 覆盖;off:模型选择完全被动(命令/遥测仍可用) | | routing.judgeTimeout | 5000 | 裁判调用超时(毫秒)。decision 模式下下限被抬高到 15000——实测一次决策判定需要 1.4–6.6 秒 | | routing.judgeMaxTokens | 4000 | 单次裁判调用最大输出 token | | routing.judgePromptCap | 6000 | 发送给裁判的最大 prompt 字符数(限制裁判成本) | | routing.judge.mode | fast-chain | 判定来自哪里:fast-chain(Fast 链)、custom(routing.judge.models)、decision(决策模型)。只写了 models 而没有 mode 时会迁移为 custom;无法识别的取值回落 fast-chain 并记日志 | | routing.judge.models | [] | custom 模式下的专用裁判链(provider/model + priority,priority 升序)。绝不用更便宜的模型替代——链不可用时回落到 Fast 链 | | routing.judge.decision.baseUrl | '' | 决策模型的基础 URL,会拼接 /v1/systemone。空 = 未配置 | | routing.judge.decision.model | jev-latest | 向决策端点请求的模型。响应会回报解析后的真实 id,变化时会记日志——别名正是这样才能保持可观测 | | routing.judge.decision.apiKeyRef | '' | 保存该端点密钥的凭据名,每次调用都通过 harness 凭据 seam 解析(轮换后的密钥下一次判定即可生效)。空 = 使用环境自带认证 | | routing.economics.reworkPenalty | 3 | R —— 一次错误降级的返工代价(以价差为倍数)。当且仅当 pSmart ≥ θ 时走 Smart,θ = 1/R:R 越大 θ 越小,越黏在 Smart | | routing.economics.downgradeMemory | 2 | Smart → Fast 所需的连续决定性 fast 判定次数(hold 或 smart 判定都会打断连击) | | routing.economics.mode | (未设置) | 命名档位预设,优先级高于 reworkPenalty:eco(R=2, θ=0.5) / default(R=3, θ≈0.33) / sport(R=5, θ=0.2) | | routing.window.size | 5 | 决策记忆窗口大小 | | routing.window.threshold | (未设置) | 遗留原始 θ 覆盖值。EV 之前的默认值 0.6 已失效;只有不同取值才生效(并在 /router status 标记 ⚠ legacy) | | routing.window.minConfidence | 0.5 | 低于此置信度的判定按 hold 处理(不切换、不计入连击) | | routing.cacheAware.enabled | true | 同 provider 缓存保护 | | routing.cacheAware.sameFamilyPenalty | 1.5 | 两层共享 provider 时对 θ 的除数——门槛更低意味着降级更少,热缓存存活更久 | | routing.cacheAware.idleBoundaryMs | 300000 | 热缓存被认为变冷前的空闲间隔 | | routing.cacheAware.sameFamilyThreshold | (未设置) | 遗留哨兵。EV 之前的默认值 0.9 已失效;不同取值等价于 sameFamilyPenalty = 3.0 | | orchestration.mode | auto | auto:复杂任务 → Smart CTO;off:仅普通双层路由 | | orchestration.maxRounds | 3 | 委派→审查轮次硬上限(强制执行:每次 subagent 委派计一轮;触顶后拒绝 subagent 工具) | | orchestration.escalationThreshold | 2 | 连续工作代理失败计一次升级;工作代理成功会清零连击。达到上限后 Smart 必须亲自接管,且 subagent 工具被拒绝(强制执行) | | orchestration.maxSpendUsd | 0 | 单个编排任务的硬预算(USD);0 表示不启用。它是 capHit 的一部分,触顶即拒绝继续委派。需要 pricing 才有意义——未配置定价时花费合理地保持为 0 | | orchestration.workerLedgerCap | 20 | 状态报告保留的每 worker 成本行数(超出丢最旧)。任务总额是权威值、不受影响 | | orchestration.audit.enabled | true | 在一次确实委派过的运行结束后审计验收声明:每个 worker 是否都回报、是否存在 CTO 总结,以及(一次小的 Fast 档调用)声明是否有 worker 结果支撑 | | orchestration.audit.timeoutMs | 5000 | 审计调用预算。免费的确定性检查总会执行 | | orchestration.audit.promptCap | 6000 | 审计提示词字符上限——既是成本上限,也决定保留多少 worker 证据 | | failover.baseMs | 60000 | 5xx 失败的冷却基础延迟(1 分钟) | | failover.maxMs | 21600000 | 退避阶梯硬上限(6 小时) | | failover.startAttempts4xx | 3 | 4xx(429/402/配额)失败从该尝试次数起步(16 分钟),客户端限流通常比服务端抖动更持久 | | telemetry.callLogCap | 1000 | 基线成本计算保留的最大逐条消息归属记录数 | | ux.routerLogVerbose | false | 把路由决策打印到本插件的 ctx.logger,并在每一轮判定后写一条路由通知(包括保持原位的轮次;而 release——完全没有裁判——每个会话只通知一次,不是每轮一次)。DSH 自带 profile 未挂载任何日志导出器,所以日志只在额外挂载导出器的部署可见;通知与 /router status 才是始终可用的界面 | | ux.promptSectionOrder | 150 | 编排器系统提示词段落的排序位置。DSH 集中分配提示词顺序(SECTION_ORDERS),未给第三方段落预留槽位,因此这是配置项而非常量 | | pricing | [] | 可选 {provider, model, input, output, cacheRead?, cacheWrite?} 每百万 token 的 USD 计价表,用于成本遥测 |

所有数字字段都经 schema 范围校验(如 window.minConfidence 必须在 [0,1]、window.size 必须是正整数);非法值在加载 / set 时被拒绝,绝不静默接受。

从 v0.5.0 升级: 路由决策会立即发生变化(无需改配置)——决策规则从"数窗口票数"改为"权衡期望成本",另有两个遗留旋钮的含义变更。详见 SPEC.md §15 与 CHANGELOG.md 的 [0.6.0] 段。

GUI 配置卡片

插件随包构建一个浏览器端(client)模块,在 GUI 的设置页注册一张 「Shift-Router」 卡片:

  • 位置(DSH 0.2.0-rc.2 及以后):左侧栏 「插件」 页 → dsh-shift-router 卡片 → shift-router 行 → 该行的「配置」按钮。完整表单同时出现在 bundle 自己的页面上,两条路径都能到。卡片注册进 plugins.row.config(键 dsh-shift-router#shift-router)与 plugins.bundle.config(键 dsh-shift-router),两者都由官方 dsh-client-ui-plugin-manager 声明;设置传输用 ctx.configForms。
  • 位置(≤ 0.1.5-rc.x):设置 → 内置插件 → 可配置页;卡片占用 keyed 的 settings.plugin.item 单元格(key: 'shift-router'),传输用 ctx.settingsScope。每一代只声明三个槽位里的一个,所以面向另一代的注册保持静止。
  • 能力:以表单编辑全部标量叶子字段(开关、数字、枚举)以及模型链(两层,外加一条专用裁判链),分七个分组(通用 / 模型 / 路由 / 编排 / 故障转移 / 遥测 / 日志与体验),路由分组下再分子组(裁判 / 裁判来源 / 决策窗口 / 缓存感知)。控件只在与当前选择相关时出现——选定裁判来源就只显示该来源自己的设置,其余隐藏——且任何下拉都不会出现原始配置取值。标量字段采用紧凑的「设置行」版式——左侧标签 + 说明,右侧同行右对齐控件——每个字段只占一行,不再上下堆叠三层。控件全部使用宿主平面设计令牌:开关用拨动开关(浅色/深色主题下对比度都清晰)、枚举用带箭头的下拉、数字输入框内嵌单位后缀(ms、tokens、0–1 等)、模型链用有序行编辑器——行的顺序就是层内回退顺序:优先命中排在最前的可用模型,其余作为后备。provider/model 下拉自动载入 DSH 运行时模型目录(llm.models,与设置页模型目录同源):只列出当前有模型清单的 provider,无休眠目录噪音,且插件不硬编码任何模型,跟随任何部署的 DSH 实际配置。另有「自定义…」入口填写目录之外的取值。分段保存、单字段恢复默认与覆盖标记与官方卡片完全一致。
  • 边界:仅 pricing(可选的 USD 计价表)仍由 /router config 或 patch 行编辑;模型链——两层以及裁判那条——都可以在卡片中直接编辑。
  • 构建:npm run build 会同时产出 host 产物(dist/index.js)与 client 产物(dist/client.js)。client 模块通过 dsh.client manifest 被 dsh-client-modules 扫描,要求插件以包名(dsh-shift-router)挂载——源码检出式 patch(name: '/path/dist/index.js')不会提供卡片。

仅旧版 harness 需要:Web 设置白名单(≤ 0.1.0-rc.x)

0.1.0-rc.x 及更早的 harness 会把第三方 settings 命名空间从浏览器的 settings.describe 响应里过滤掉,除非它出现在 WEB_SETTINGS_NAMESPACES 中——这正是 scripts/expose-gui-settings.mjs 存在的原因:它修改 profile 里已安装的 dsh-host-apiproxy(幂等;升级依赖后重跑)。从本项目的基线 0.1.5-rc.2 起,该包与白名单 均已移除,命名空间原生暴露,脚本会输出「不需要」并以 0 退出。该脚本不在发布包内 (files),只能从源码检出获得。

命令

| 命令 | 作用 | |------|------| | /router | 简洁状态 | | /router status / /router stats | 完整状态:档位(R → θ)、分层、决策窗口(hold 显示为 h)、上一次判定及其原因、实际运行的模型 vs 路由器意图、切换记录、冷却、token、成本遥测 | | /router on / /router off | 启用 / 停用(会话级) | | /router verbose / /router log | 详细日志开关 | | /router orchestrate auto\|off | 编排模式 | | /router allow-workers [on\|off] | 把本插件的 Fast 链写入 harness 的 subagent-model-selection-settings 白名单,使 worker 可被固定到 Fast(off 只撤销授权、保留路由)。会如实回报写入内容或失败原因 | | /router eco / /router default / /router sport | 档位预设:设置 routing.economics.mode(持久化)——更省 ↔ 更黏在 Smart | | /router config | 交互式编辑器:带编号的字段列表(含当前值)+ 可用 providers + 用法 | | /router config get <N\|path> | 显示单个字段当前值,如 get 4 或 get routing.judgeTimeout | | /router config set <N\|path> <value> | 设置单个字段(持久化),如 set 4 8000、set tiers.fast.models [...](JSON 值自动解析) | | /router config unset <N\|path> | 清除用户覆盖——字段回退到组合默认值 | | /router config diff | 列出用户层当前持有的覆盖项 | | /router config set-fast <provider/model> | 用单个模型替换 Fast 层模型链 | | /router config set-smart <provider/model> | 用单个模型替换 Smart 层模型链 | | /router config reset | 恢复组合默认值 | | /route-force <fast\|smart\|auto\|provider/model> | 强制下一轮走某层/某模型(一次性) |

工作原理(DSH 集成)

机制到机制的逐项映射是规范,只在 SPEC.md §1.1。这里有两点 值得单独说明,因为它们不在那张表里:

  • 吞吐速率刻意不在此列。 DSH 原生渲染 tok/s(消息页脚、trajectory 面板),口径是解码时间; 路由器负责路由决策与花费,不负责速率展示。
  • 子代理永不被路由。 subagent 工具派生出的 worker 带 session.header.origin === 'subagent' 并保持其被钉住的模型;路由器只驱动顶层 agent 的轮次。

任务级编排

轮次级路由决定用哪个模型跑这一轮;任务级编排决定复杂任务怎么执行。当裁判判定 smart 且 orchestration.mode 为 auto(默认)时,路由器把这一轮交给 Smart 层担任 CTO:它制定计划、 通过 harness 的 subagent 工具把实现委派给 Fast 层 worker、逐个审查结果并迭代——最后由一次独立的 验收审计核对它的说法。fast 判定永远不会触发这些。

一轮编排是怎么跑的

  1. 进入 —— 决策档位是 Smart、subagent 工具存在、模式为 auto;编排器指令以系统提示词段落 注入(SPEC §7.2)。
  2. 委派 —— CTO 调用 subagent;每次调用算一轮,且在派发时计数(派发出去的委派已经花掉了 预算,这样 maxRounds 才是真正的上限)。
  3. 审查与迭代 —— worker 失败会推进失败连击;收敛协议要求每次重派都携带结构化的 ## Failure report(什么失败、在哪、用哪个验收测试复测),重复同一反馈即触发接管 (SPEC §7.2.1)。
  4. 停止 —— 触顶后 tools/pre-execute 直接拒绝 subagent 工具、提示词段落切换为「立即 收尾」;agent/turn-stopping 释放状态。编排是单轮的:不跨轮,泄漏的运行会在下一轮开始时清扫。

硬上限(由路由器强制执行,而非仅写在提示词里)

| 设置 | 默认值 | 作用 | |---|---|---| | orchestration.maxRounds | 3 | 每个任务的委派轮数 | | orchestration.escalationThreshold | 2 | 连续多少轮 worker 失败后,Smart 层自己接管该阶段 | | orchestration.maxSpendUsd | 0(不设闸) | 达到 USD 预算即停止委派,按 pricing 表计价 | | orchestration.workerLedgerCap | 20 | 保留用于展示的每 worker 成本行数 |

验收审计(安全网,从不是门禁)

硬上限能防止跑飞,防不住 CTO 声称验收了却其实没核对。因此真正委派过的运行会被审计:确定性 检查总是跑(每个派发出去的 worker 都回报了、存在 CTO 总结、没有被上限截断),并在 orchestration.audit.enabled 时追加一次小的 Fast 层复核,读取目标、总结与 worker 结果。它从不 阻塞轮次:LLM 那一半是分离执行的,结论以 Last audit: 出现在 /router status。

worker 的模型需要授权

上游把「每 worker 的模型钉定」称为强制:worker 若继承父会话的模型,编排中途那已是 Smart, 经济学前提直接崩塌。DSH 里这个钉定居于宿主持有的白名单之后(subagent-model-selection-settings,默认 关闭)。/router allow-workers 帮你把 Fast 链写进去;未授权时路由器会在 Worker delegation: 行里如实说明,而不是假装可以(SPEC §7.4)。

怎么知道它发生了

/router status 会显示 🪄 active (round x/y, esc a/b, fail streak n),worker 回报后追加 Orchestration spend: $X · N/M workers reported,审计结束后还有 Last audit: …。进入编排时还会 往对话里写一条路由通知(SPEC §13.1),所以不必去读计数器也能看出这一轮的形态。

什么时候不触发

fast 判定;orchestration.mode: off(或 /router orchestrate off);组合里没有 subagent 工具;或解析不到 Smart 模型——这些情况下这一轮就只是跑在 Smart 上,没有委派、也没有审计。

开发

npm run build       # tsc(host → dist/)+ tsc client + tsdown(client bundle → dist/client.js)
npm test            # vitest(24 个文件、429 个测试:EV 路由 / 故障转移签名 / 裁判解析与提示词契约 / 裁判来源与可用性阶梯与决策协议 / 编排 / 配置 schema 与迁移 / 遥测 / 路由通知 / release 装配 / 配置注册表与 GUI 表单模型 + 卡片 UX + 模型目录 / 打包安装契约)
npm run typecheck

端到端测试(无需凭证)

npm run test:e2e

该脚本会建一个临时 DSH_HOME,把本检出作为 bundle 装进派生出的 headless profile,用假适配器跑一轮,并断言:

  • ROUTER-E2E: turn ran on fake/fake-smart notice=yes —— 裁判确实跑了、EV 规则确实升级了、真的切换了上线模型到 Smart 层,并且 [shift-router] 路由通知确实进入了模型请求(SPEC §13.1);
  • 在 e2e/legacy-config-overlay.yml 下(对齐前配置:遗留旋钮处于旧默认值 + 已被移除的 requireSmartModel 键)结果相同 —— 覆盖的是升级路径,不只是全新安装;
  • 在 e2e/orchestration-overlay.yml 下结果相同 —— 使用插件的默认编排模式(auto),并挂载 web 专属的 subagent-model-selection-settings 行,即曾经导致启动失败的那个组合;
  • shift-router settings 命名空间能完成一次写入并读回,且 Host 模型目录确实广告出该部署配置的路由(e2e/settings-probe.mjs);
  • 打包产物安装(npm pack → tarball → 第二个 scratch profile)能带着插件启动,浏览器端被提供给 client 模块加载器,且 profile 里没有任何 @deepseek-ai/* 副本 —— 那里没有 devDependencies,因此"运行时导入了未向消费者声明的包"会在 e2e 失败,而不是在用户机器上失败。

它不会碰你真实的 DSH_HOME,跑完自行清理(加 --keep 可保留现场)。手工复现:

DSH_HOME=/tmp/scratch dsh plugin --profile tmp add /path/to/dsh-shift-router
DSH_HOME=/tmp/scratch dsh --profile tmp --patch e2e/overlay.yml "design a migration plan"

架构

仓库结构与模块地图(纯逻辑/接线分工、测试分层)以 CONTRIBUTING.md 的 Repository layout 一节 为唯一权威, 这里只留指针:src/ 是 host 半边(纯决策模块 + index.ts 里的 DSH 接线),src/client/ 是 浏览器半边(设置卡片),tests/ 覆盖两者,e2e/ 启动 scratch profile——包括打包产物。

另见

  • pi-shift-router —— 本插件所适配的上游项目: 同一套双层架构(LLM 裁判、回退链、指数退避故障转移、任务级编排),面向 pi-coding-agent。 行为对齐与刻意不对齐之处记录在 ALIGNMENT.md。
  • dsh-plugin-dev-skill —— 开发 DSH 插件的 Agent 技能:工具(defineTool)、LLM 适配器、服务、事件、配置与打包,含 Cordis 心智模型与验证 清单。本项目遵循它;可在 DSH、Claude Code 或 Codex 中安装。
  • obsidian-llm-wiki —— 把笔记与 PDF 变成互链、 可查询知识库的 Obsidian 插件(实体页与概念页、图检索问答、本地优先、无后端)。同一作者的另一条 产品线。

许可证

MIT © 2026 green-dalii and contributors.