- ホーム
- プラグイン
- モデルとプロバイダー
- dsh-quota-takeover
dsh-quota-takeover
puppy-bai/dsh-quota-takeover
Quota takeover for DeepSeek Harness on top of Our Free Model: compiles your platform order and pinned model tiers into one ordered fallback chain, skipping platforms that lack the model, sit in cooldown or are out of quota, writes the result back as Our Free Model combos, and after a quota or rate-limit failure re-plans and injects a follow-up continue message into the interrupted session so the turn resumes on the next platform; the chain ends with your configured aggregate fallback model or the official DeepSeek quota.
インストール
dsh plugin --profile web add github:puppy-bai/dsh-quota-takeoverREADME
dsh-quota-takeover · 额度接力
在 Our Free Model 之上加一层「接力」: 一个平台额度不够就按你设定的顺序换下一个平台;某个平台没有你要的模型就跳过; 全都没有就换下一档模型再遍历一遍;实在不行用你指定的兜底模型。 任务因额度中断时,自动切到新平台并往中断的会话里发一条「继续」。
设计文档(含需求分析、失败分类表、风险对策、能力边界、终局兜底):
docs/quota-takeover-plugin-design.md
上架市场的步骤:docs/SUBMISSION.md
它做什么
| 你的需求 | 本插件的实现 |
|---|---|
| 平台额度不够 → 按我设定的顺序换下一个 | 把「平台顺序 × 模型档」编译成一条有序候选链,写回 OFM 的 combo(auto:main),由 OFM 的 fallback 策略逐项尝试 |
| 我一直用的模型,别的平台没有就跳过 | 每个「模型档」有别名表;平台模型清单里匹配不到 → 记为 missing 并跳过 |
| 全都换完还没有 → 换模型再遍历一遍 | 遍历形状 tier-major(档优先):先全平台找第 1 档,再全平台找第 2 档…… |
| 最后兜底 | finalResort.fallbackModels(如 groq/llama-3.3-70b)非空 → 编译兜底链;为空 → 进入「等待恢复」 |
| 因额度中断 → 自动换平台并续跑 | 监听 llm/stream 的错误终点,分类为额度/限流后写冷却、重编译计划、向该会话 agent.followup(一条「继续」消息) |
| 新接入的平台自动出现 | 平台表有三处来源:channel-pack 账号池、OFM 聚合渠道 /providers、catalog 里的新通道(如 subscription:magpie/siliconflow/… → 「Magpie(硅基流动等)」);每轮同步重新读 |
| 撤掉的平台自动消失 | 连续 platformPolicy.pruneAfterMisses(默认 3)轮读不到就从顺序里清掉;关掉 pruneMissing 则只标记不删 |
| 0 账号的空渠道自动消失 | platformPolicy.pruneZeroAccounts(默认开):账号数为 0 的渠道直接隐藏;哪天给它加了账号,会自动放回来(只自愈「自动隐藏」的,用户手动删的保持删除) |
| 手动删除任意平台 | 每行常驻红色「删除」;写进 hiddenPlatforms + excludePlatforms,底部「已隐藏 N 个」点 ↺ 可放回 |
两个半身(为什么必须这样)
浏览器(带 DSH 认证 cookie) 插件 host 进程
│ ① GET /api/our-free-model/combos │
│ ① GET /api/our-free-model/subscriptions │
│ ② POST /api/quota-takeover/snapshot ────▶│ 编译计划(平台顺序 × 模型档 × 额度 × 冷却)
│ ③ GET /api/quota-takeover/pending ◀──────│ 待写回的 combos
│ ④ POST /api/our-free-model/combos │ (只有浏览器有写权限)
│ ⑤ POST /api/quota-takeover/applied ─────▶│ 记录已写回
OFM 的 API 挂在 harness 的信任围栏后,插件进程内的 fetch 一律 401(实测,见设计文档 §12.1)。
所以读账号/额度、写 combos 这两件事只能由浏览器半身代劳;续跑不受影响——它是进程内
agent.followup(),不经过 HTTP。
安装
前提:先装好 Our Free Model。本插件从它那里取「平台 × 模型 × 剩余额度」,并把接力链写回它的 combos;没有 OFM 时只剩续跑能力,没有可接力的平台。
从市场装(发布后可用):
DSH → Plugins → Discover 里搜 quota-takeover
手动装(开发/未发布时):
cd ~/.dsh/profiles/desktop
npm i /path/to/dsh-quota-takeover-0.1.1.tgz # 或把源码目录拷到 node_modules/dsh-quota-takeover
# 然后在 package.json 的 dsh.profile.bundles 数组里追加 "dsh-quota-takeover"
# 被 bundles 引用的包,其自带 cordis.patch.yml 自动生效;
# 别再往 cordis.patch.yml 手写同名条目,否则报 duplicate loader entry id
最后完全退出 DeepSeek Harness 再打开——host 半身只在进程启动时 apply 一次,刷新页面只重载浏览器半身。
装好后的三个检查点:
| 检查点 | 期望 |
|---|---|
| 设置 → 「额度接力」 | 页面出现,且没有红色「宿主半身没有加载」告警 |
| 平台顺序 / 模型档 | 列出 channel-pack 里启用的平台与它们的真实模型 |
~/.dsh/quota-takeover/journal.jsonl | 有 api-mounted;发生过失败时有 failure / resume |
运行期数据:~/.dsh/quota-takeover/{config,plan,bench,resume,platforms}.json + journal.jsonl
配置
~/.dsh/quota-takeover/config.json(也可由设置页「额度接力」写入):
{
"enabled": true,
"platformOrder": ["trae", "minimax", "zcode", "loomy", "raccoon", "gemini"],
"platformPolicy": {
"unknownTail": true,
"excludePlatforms": [],
"pruneMissing": true, // 读不到的渠道自动从顺序里清掉
"pruneAfterMisses": 3, // 连续缺席几轮才清(防一次探测失败误删)
"pruneZeroAccounts": true // 0 账号的空渠道自动隐藏(有账号后自动回来)
},
"modelTiers": [
{ "id": "deepseek-flash", "label": "DeepSeek V4.1 Flash", "pinned": true,
"aliases": ["deepseek-v4.1-flash", "deepseek-v4-flash-0731", "deepseek-flash"] },
{ "id": "glm-flash", "label": "GLM 5.3 Flash", "aliases": ["glm-5.3-flash"] }
],
"traversal": { "order": "tier-major", "maxChainLength": 16, "optimisticOnUnknown": true },
"finalResort": { "fallbackModels": [], "retryAfterMinutes": 10 },
"resume": { "enabled": true, "onlyQuotaLike": true, "maxPerSession": 5, "requireCandidateChange": true }
}
platformOrder:没列出的平台排在后面(platformPolicy.unknownTail)。platformPolicy.pruneMissing/pruneAfterMisses:撤掉的渠道会一直留在顺序里,所以连续 若干轮读不到就自动清理(写入platforms.json记录缺席次数)。一轮读不到任何平台时整轮跳过, 因为那说明中继断了、不是渠道被删了。modelTiers:aliases是同一模型在各平台的叫法;匹配时先精确、再去-free/-preview/eac:前缀小写比较, 最后还能按 id 的最后一段比(聚合渠道的siliconflow/deepseek-ai/DeepSeek-V3能被DeepSeek-V3命中)。optimisticOnUnknown:平台模型清单未知时(本地state.json不存模型表)先把格子放进链, 真没有会让 OFM 的 combo 自然失败并前进——未知 ≠ 不存在。resume.requireCandidateChange:核心防呆,候选没变就不重复注入「继续」。
HTTP API(浏览器侧用,带 cookie)
| 方法 | 路径 | 作用 |
|---|---|---|
| GET | /api/quota-takeover/status | 计划 + 桥状态 + 配置 |
| POST | /api/quota-takeover/compile | 手动重编译 |
| POST | /api/quota-takeover/snapshot | 浏览器推账号/额度/模型快照 |
| GET | /api/quota-takeover/pending | 取待写回的 combos |
| POST | /api/quota-takeover/applied | 回报写回成功 |
| GET | /api/quota-takeover/bridge | 中继健康状况 |
| POST | /api/quota-takeover/config | 改配置(合并后重编译) |
| POST | /api/quota-takeover/bench/clear | 清空冷却表 |
开发
node --test tests/*.test.js # 32 个单测(编译器 / 分类器 / 续跑状态机)
node probes/smoke-host.mjs # 假 ctx 装载 host 半身,跑通中继闭环
node probes/plan-preview.mjs # 用本地 state.json 预演一次编译
node probes/ofm-probe.mjs <gui 地址> # 探针:OFM API 可达性(预期 401)
已知限制
- 写回依赖 GUI 打开:浏览器关掉时链停在旧计划上(候选里已带 resolved 模型 id,旧链仍能跑)。
- 不直接改 OFM 的 settings.json(除显式
writeBack.mode: "file"):OFM 把设置常驻内存,改盘不热生效且会被下次保存覆盖。 - 续跑只在「额度/限流」类失败上生效(
onlyQuotaLike);用户主动 abort 绝不续跑。 llm/stream目前只观察不改道(探针 4 未验),改道能力留作 M2。