DSH Plugins Marketplace

DSH Plugins

Plugins

/

Tools & Capabilities

/

dsh-model-failover

d

dsh-model-failover

Manifest valid

Model failover router that queues all connected DSH models, retries with continue text on failure, switches to next model, and quarantines failing models for the day.

UI (client)hasBundlePatch

模型接力 · dsh-model-failover

把 已经接入 dsh 的全部模型排成一条优先级队列,然后把这个插件本身当成一个「模型」。 用户在模型选择里挑 模型接力,任务就会按你排好的顺序去跑:靠前的先上,不行就自动往下换, 直到任务跑完。

它解决什么

一个模型不能输出,往往是这几种:额度用尽、余额不足、key 失效、路由挂了、上游 5xx。 以前遇到这些,任务当场就断了。现在:

  1. 先用第一个模型跑;
  2. 它出问题 → 用同一个模型补一句「继续」,再试一次;
  3. 还是不行 → 换第二个模型,补一句「继续」,接着跑;
  4. 依次往下,直到某个模型把任务跑完;
  5. 某个模型今天出过这种问题 → 今天所有任务都不再从它开始,直接用排在它后面、 已经验证过能用的那个;
  6. 到了第二天设定时间(默认 01:00,可改),隔离自动清空,重新从第一个开始试。

另外,整轮以失败告终、或被 token 上限截断时(模型自己没坏,只是这一轮没跑完), 插件会替你自动补一句「继续」接着做 —— 见下面的「自动『继续』」。

装好之后长什么样

模型选择器里多一项 模型接力(provider model-failover,模型 auto)。 选了它,你发任何消息都由接力逻辑接管。

设置 → 模型接力(在「模型」那一节下面)。同一类设置放在一起,从上到下依次是:

区块作用
今日状态今天是哪天、距下次重置还有多久、当前起点、今天隔离了几个(重置时间就在这里)
优先级队列全部已接入模型的候选清单,每行一个思考强度下拉框,↑ ↓ 排序,✕ 移除;下面可以从目录里加回来
今日隔离名单今天判断「不行」的模型,带错误码和原因;点左边的箭头摊开完整报错
接力规则总开关、是否「先重试同一个模型」、补发的那句话的内容、全部隔离时要不要硬试
自动「继续」总开关、两种触发、次数上限、每次失败后等多久再补(见下)
事件日志每次隔离/复活/回滚/自动补发都留一条;记不记、留多少条也在这里

隔离中的模型会带一个红色徽标(鼠标停上去能看到错误码),今天验证过能用的带绿色徽标。

隔离名单里的报错可以摊开看。 每一行默认只给摘要 —— 错误码、一句人话、报错正文的前 160 字符 —— 因为它们动辄几百字符(ENOTFOUND、tunnel_destination_denied 这类本机网络 故障尤其啰嗦),铺在列表里会把整页撑得没法看。点行首的 ▸ 摊开,能看到完整的报错原文、 路由、尝试次数和判定时间;▾ 再点一下收回。宿主落盘时就把报错截到 400 字符,点开看到的 就是留下的全文,不会二次截断 —— 点开本来就是为了看被截掉的那半句。

自动「继续」

上一节说的是「这个模型这次没能输出」。但有两种情况是整轮结束才看得见的, 模型自己没坏:

  • 输出撞到 token 上限被截断 —— 它写到一半没词了,等的是你再说一句;
  • 这一轮以报错告终 —— 队列里所有候选都试完了还是不行。

这两种情况下插件会替你把「继续」再发一句,接着往下做。它走的就是你自己敲回车的那条路 (agent.followup),所以你看到的是一条真的用户消息:计数、上下文、渲染都和手打的一模一样。 中途你按了停止、或是那一轮正常做完了,它都绝不会多嘴。

「继续」不会被无限重发:同一段连续失败里最多补 autoContinueLimit 次(默认 3), 用满就停手等你;你自己发下一句话、或某一轮正常做完,计数就重新开始。 上下文超长、没挂适配器、凭证失效这三类错误直接跳过 —— 重发一遍只会撞同一堵墙。

每次失败之后会先等一会儿再补。 等待时长是 continueDelaySec(默认 5 秒,0 = 不等), 第一次失败也一样等。这一等不是拖延:刚撞完限流或上游抖动的模型,隔 0.2 秒再戳一次 只会再撞一次,除了把队列挨个隔离掉没有任何收益(实测里最难看的一段是 9 秒内落了 12 条隔离)。 等待期间你按了停止、自己先发了一句、或者那一轮已经跑完,插件就收手不再补。 等待同样管着适配器里「换个候选 / 同模型重发」那一跳,所以整个接力的节奏都被这一个数字管着。

本机网络没通的时候也不会补发。 这条单独拿出来说,是因为本机网络故障在 DSH 里 没有专属错误码:DNS 解析不了、代理没起来、证书被本机拦截,各家适配器会分别报成 SERVER、TRANSPORT、UNKNOWN。所以插件不认错误码,而是认报错文本里的本机特征 (ENOTFOUND / EAI_AGAIN / ECONNREFUSED / socket hang up / fetch failed / local name resolution failed / tunnel_destination_denied / 证书拦截等)。 网线没通的时候,补一句「继续」既救不回来、又要白烧一次上限,还会把整个接力队列 一个个隔离掉 —— 所以这时插件停下来,只在事件日志里记一条 「本轮是本机网络问题(SERVER),没有补发『继续』」,让你知道是网络的事、不是插件坏了。

反过来,远端的问题照旧会补「继续」:上游 5xx、限流、模型太慢都还是要救的。 判据特意写得很具体(upstream returned 502 Bad Gateway、request timed out 这些 都不会被误判成本机网络),宁可漏判也不误判。

自动补发会在事件日志里记成一条「本轮…,自动补发『继续』」。

只要一轮是接力跑的,那一轮的轮尾就多一行小字,写明这一轮是哪个模型跑的,比如 「本轮:Code99 · Beta One」。之所以要它:接力一换人,屏幕上就再没有别的地方告诉你 「现在是谁在答」了 —— 模型名字原本只在你发送时选中的那一个上,换人之后它就不作数了。 判定的是「这一轮有没有真的走接力」,不是「接力有没有换过人」:顺序表里排第一的模型 接下了这一轮也一样显示。你在模型设置里手动挑了具体模型、压根没走接力的轮上不会有, 免得每一条回答下面都挂一行废话。

宿主侧是两段式配对的:适配器看得见 sessionId(DSH 在 GenerateOptions 里给)但看不见轮号, 而 turn/end 反过来。所以适配器负责按会话记下「最后真正产出内容的那个模型」, 监听器在 turn/end 时补上轮号,再用一个轻量端点 GET /notes?sessionId=… 交给前端 —— 前端只为这一句小字去拉几十 KB 的 /state 并不划算。这份便签是纯显示用的,不落盘。 会话标题、上下文压缩这类内部调用与用户看到的那一轮无关,不会被记进去。

监听器判断「这一轮是不是接力跑的」靠的是对象比对:turn/start 时记下当时那份便签, turn/end 时看它有没有被换成新的 —— 适配器每试一个候选都会写一份新的。不能只看 「便签里有没有模型」,否则上一轮接力跑过之后,你下一轮手动挑个具体模型时, 那行小字会继续拿着上一轮的结论指错人。

每个模型的思考强度

顺序表里每一行都有一个档位下拉框,档位就是那个模型自己在模型设置页里的那几档 (插件向宿主问 resolveModelInfo 拿到的 reasoning.efforts,不是插件自己编的枚举)。 默认停在「默认档位」,也就是你平时直接用这个模型时的表现。

  • 这个模型不支持思考强度 → 那一行显示「无档位」,不画控件;
  • 还没问到档位表(刚装好、刚扫过目录)→ 显示「档位未知」的禁用控件,扫到之后自动可点, 点「重新扫描」可以立刻催一次;
  • 换模型接力时,用的是那个模型自己的档位,不会被上一个模型的档位带过去;
  • 某个模型收到一个它不认识的档位会以 UNSUPPORTED_REASONING_EFFORT 拒掉整个请求, 那等于把一个好好的模型判成「今天不行」—— 所以插件只发目标模型自己声明过的档位, 认不出来就干脆不发,让它用自己的默认档位。

顺带一提:在模型选择器里给「模型接力」这条路由本身选档位也是可以的,插件对外声明的是 队列里所有已知档位的并集,轮到一个候选时再按它自己的表过滤一遍(用户给某个模型 单独设过的档位优先于路由档位)。

几个刻意的设计

只在自己还没「说话」之前换模型。 模型的输出会先攒在手里:一旦有任何一个字、或一次工具调用准备交给用户,就立刻原样放出, 并且从这一刻起这个模型就锁定这次任务了。它之后再崩,报错就照实报错, 不会偷偷换一个模型接着写。理由很直接:两个模型各写半句话拼在一起, 用户读到的是一个人的口吻加上另一个人的结论,出了错也不知道该找谁。 攒着的那部分没交出去之前就失败,就整段丢掉换下一个模型 —— 用户从头到尾只看到一个模型的输出。

「继续」是补在原消息后面的,不是替换。所以下一个模型看到的是完整的用户请求 + 一句「继续」, 不会丢上下文。补发次数有上限(3 次),不会无限啰嗦。

撞到 token 上限不算「这个模型坏了」。 它明明在写,只是被截断在半句话上 —— 交出去的结局原样还是「撞上限」,不隔离、不换人, 所以下一轮补「继续」时用的还是原来那个模型。这一条看着琐碎,却是最容易写错的地方: 把「被截断」和「产不出内容」混成一个 NO_VISIBLE_OUTPUT,模型当场就被隔离掉, 接力起点从此换成队列里的下一个,「用原模型补继续」也就再也无从谈起。

但也不能在同一个模型上一直撞下去。 连着撞 2 次,下一次调用队列就往前挪一格,换队列里的下一个接手;再撞 2 次,再挪一格, 转完一圈从头接上(两个候选时是「甲 甲 乙 乙 甲 甲 …」)。账按会话累加而不是按模型 —— 按模型记的话,换到乙之后再撞一次就会「重置」,下一轮又回到甲,两个模型之间来回打转。 哪一轮正常写完了,账就一笔勾销,下一个任务还从队首开始。换人时事件日志里会留一条 ceiling-rotate,不然用户只看到排在最前面的模型莫名其妙被跳过。 「压缩会话」「起标题」这类内部调用跟用户看到的那一轮无关,不参与记账。

中止和上下文超长不算「模型坏了」。 用户自己按了停止 → 原样交回;上下文超长 → 交给 agent loop 去压缩,都不切换、不隔离。 只有额度/凭据/网络/上游这一类「这个模型现在就是不行」的错才触发接力。

隔离是按天记的,写在磁盘上,跨任务、跨重启都有效,到点自动清空。 判定「今天它不行」要等这个模型的「继续」也试完:失败一次、被一句「继续」叫起来接着写完的 模型是能用的,会被记成「已验证可用」而不是被隔离 —— 否则今天反而会绕开一个明明好好的模型。

所有状态都在你自己的机器上:C:\Users\superv\.dsh\dsh-model-failover\state.json(隔离与验证记录)、 settings.json(队列与开关)、log.json(事件日志)。删掉 state.json 就等于「立刻解除所有隔离」。

配置

设置页同一类设置放在一起,从上到下:今日状态(逻辑日、距重置、当前起点、隔离数, 以及「每天几点算新的一天」)、优先级队列、今日隔离名单、接力规则(启用、同模型重发、 重发内容、全部隔离时是否硬试)、自动「继续」(开关、两种触发、次数上限、等待秒数)、 事件日志(列表本身 + 记不记、留多少条)。设置页里能改的都存在 settings.json; 重置时间支持 0-23 的整点。默认值: resetHour: 1、retrySameModelOnce: true、continueText: "继续"、retryWhenAllQuarantined: true、 autoContinue: true、autoContinueOnFailure: true、autoContinueOnMaxTokens: true、autoContinueLimit: 3、 continueDelaySec: 5、keepEventLog: true、eventLogLimit: 200。

开发

node test/smoke.mjs        # 宿主半身:接力、隔离、复活、档位、契约、自动继续接线、补发节奏、轮尾便签、撞上限换人(44 项)
node test/client.mjs       # 浏览器半身:真渲染设置页 + 真发请求 + 轮尾小字 + 隔离名单展开(35 项)
node test/real-host.mjs    # 挂进真的 dsh-llm 注册表跑一遍,含档位校验(12 项)
node test/autocontinue.mjs # 自动「继续」的判定、节流与等待、本机网络判据、轮尾便签(51 项)

test/client.mjs 里有一个几十行的 React 替身,它把 client.js 当真实 bundle 加载 (走 window.__ModuleLoader__.load)、真的把设置页渲染出来、真的按按钮, 所以「页面会不会崩、按钮发的请求对不对」是断言出来的,不是看出来的。 改完 client.js 只要 node test/client.mjs,不用开浏览器。

test/real-host.mjs 用的是真宿主:真的 @deepseek-ai/dsh-llm 注册表、真的 waterfall、 真的校验函数,只把外面两个模型换成脚本化的替身。它证明的不只是「逻辑对」,还包括 「这个适配器装得进去」—— 适配器返回值形状写错时 dsh 会抛 INVALID_ADAPTER / INVALID_CATALOG / INVALID_MODEL_INFO / INVALID_MODEL_CONTEXT,插件会装不上而不是跑错。 档位那部分同样交给真校验器判:队列的并集要过得了 normalizeModelInfo(档位没有 name 会被拒成 INVALID_MODEL_REASONING),不认识的档位要抛 UNSUPPORTED_REASONING_EFFORT。 它需要本机 _dsh-research/ 下那份从 app.asar 解出来的 dsh 包;找不到就整份跳过(退出码 0), 换位置用 DSH_LLM_HOST_DIR 指向包含 @deepseek-ai/ 的那个 node_modules。

边界

  • 只在没有可见输出之前切换模型(见上)。要跨过这条线,得等 dsh 给插件一个 能安全丢弃已发出内容的位置。
  • 自动「继续」需要 composition 里有 agents 服务(桌面/网页版都有)。没有它 (比如纯 TUI、离线测试)时这项功能静默关闭,插件的其余部分照常工作 —— 它走的是 ctx.inject(['agents']),不会因为缺这个服务而整个装不上。
  • 「本轮失败」判据是 turn/end 报的结局,所以只认真失败的轮。模型自己吐了一句 「抱歉我做不到」但正常收尾的轮,插件不会替你追问。
  • 候选清单来自宿主里已注册的模型;如果你想排除某个 provider,在设置页里把它移除、 或填进 hiddenProviders。
  • 插件自己的路由永远不会出现在候选里(否则会自我递归)。
  • 档位表是启动后异步问出来的(问一次记一次,不再重复问)。万一某次任务来得比 扫描还早,那一个模型这一轮会按「不知道它认什么档位」处理 —— 不发档位,用它自己的 默认档位。这是刻意的取舍:宁可按默认档位跑,也不能发一个它不认的档位把它误判成 「今天不行」而隔离掉。设置页里点一次「重新扫描」就会补齐。

Comments

Loading…

Similar plugins

dsh-model-router

by andrepontesmelo

DSH plugin: virtual model ids backed by pluggable routing algorithms (priority, round-robin) over real provider candidates, with transparent failover.

Tools & CapabilitiesDevelopment & InfrastructureManifest valid

★ 0

MIT

JavaScript

Oct 12, 2026

dsh plugin --profile web add @andrepontesmelo/dsh-model-router

by HB00

Automatic provider failover on rate limits or quota exhaustion: switch between providers with configurable per-provider models, a cooldown, and a permanent last-entry fallback.

Terminal & ClientsModels & ProvidersManifest valid

★ 0

MIT

JavaScript

Aug 15, 2026

dsh plugin --profile web add dsh-llm-failover

Adds routing groups to the session model picker and fails over to the next usable model once the current one exhausts every retry policy.

Models & ProvidersManifest valid

★ 0

dsh plugin --profile web add model-failover-manager

by Letter2025

Two-level model circuit breaker with failover for DeepSeek Harness: trip a model or a whole provider after repeated request failures and route the next request to a configured fallback

Workflow & AutomationManifest valid

★ 4

↓ 306/wk

MIT

TypeScript

Sep 28, 2026

dsh plugin --profile web add dsh-model-failover

by Harris-Logic

DSH 断点续接插件:模型回复因网络中断/超时半途失败时,自动把已生成的部分输出带进下一轮,让模型从中断处继续,而不是从零全量重跑。DSH plugin: on a mid-stream network failure, auto-resume the turn from its partial output instead of restarting from scratch.

Tools & CapabilitiesDevelopment & InfrastructureManifest valid

★ 0

MIT

JavaScript

Sep 10, 2026

dsh plugin --profile web add dsh-resume-turn

Governs multi-model access, monthly credits, manual/quality/credit/auto routing, failure rerouting, and usage auditing for DSH.

Models & ProvidersManifest valid

★ 0

dsh plugin --profile web add dsh-llm-governor