Skip to content

dsh-key-fallback

Verified

@omdp/dsh-key-fallback · v3.3.3 · MIT · Web UI

API Key 回退轮换插件:多 key 池 + 自动轮换(触发码可配置,含 LlmError 标准码全集)+ 环境密钥编辑 + 明文揭示 + 短 ref 迁移。同时兼容 DSH 0.1.5-rc.3(settings.yaml 后端)与 0.1.7+(profile entry config 后端)。Settings → API Key 回退 UI. v7.

Install

dsh plugin add @omdp/dsh-key-fallback

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Published to npm without a public repository. Inspect the package contents before installing.

Readme

@omdp/dsh-key-fallback

English | 简体中文

为 DeepSeek Harness (DSH) 提供多 key 池 + 自动轮换——插件挂在 DSH 的凭证接缝 credentials.resolve 上:每次适配器取 key 时,若该 ref 属于已配置的池,就返回池的当前 key;遇到配置的触发错误时,把失败 key 标记为冷却(固定 cooldownMs,无指数退避)并前进到下一把。重发完全交给 DSH 自带的 dsh-llm-retry——本插件从不自行重发,只负责换 key,重试策略由 retry policy 决定。

当前版本:v3.3.2(v7 UI 代)。

v3.3.2 新增

  • peer 声明改用三元组区间 >=0.2.0-rc.1 <0.2.1-0——代码零改动(2026-09-30)。 背景:DSH 0.2.0-rc.2 发布后,门禁把 3.3.1 拦下的方式与当初把 3.2.4 在 0.2.0-rc.1 上拦下 完全一致——已是连续第三轮同型故障(设置项消失、路由 404/405)。根因从来不是不兼容,而是 逐版本枚举在每次 rc 迭代下必然过时。核查依据:0.2.0-rc.1 → rc.2 全量 20 包逐文件 SHA256 对比显示,本插件声明的六个 peer 只有 package.json 版本号变化;再用真门禁跑全版本矩阵—— 0.2.0-rc.1 / rc.2 / rc.3 / rc.9 / 正式版 0.2.0 全 放行, 0.2.1-rc.1 / 0.3.0-rc.1 全 拦截。 ⚠️ 本条同时收窄支持面:不再声明 0.1.7 线,需要在 0.1.7 上运行请装 3.3.1。 ⚠️ 上界必须写 <0.2.1-0 而非 <0.2.1:semver 里预发布排在正式版之前, 0.2.1-rc.1 < 0.2.1 成立,写 <0.2.1 会漏放行下一个三元组的 rc。

环境要求

  • DeepSeek Harness 带 web profile GUI(npx @deepseek-ai/dsh web)
  • Node.js ^22.19 或 >=24
  • peer 范围用按三元组划分的区间(自 3.3.2 起;此前为逐版本枚举)——@deepseek-ai/dsh / @deepseek-ai/dsh-credentials / @deepseek-ai/dsh-llm / @deepseek-ai/dsh-settings 四条均声明 >=0.2.0-rc.1 <0.2.1-0:实测该三元组的首个 rc 即自动放行其后续 rc(0.2.0-rc.2/rc.3…)与正式版 0.2.0,跨三元组(如 0.2.1-rc.1)仍会被门禁拦下、须重新核查。上界写 -0 是必须的:semver 里预发布排在正式版之前,写 <0.2.1 会漏放行下一个三元组的 rc(规范见 AGENTS.md 规范 3)。@deepseek-ai/cordis 4.0.1 || 4.0.2 || 4.0.4、@deepseek-ai/schemastery 3.18.1 || 3.18.2 || 3.18.4 仍精确枚举(两者不进版本门禁——门禁只检查 @deepseek-ai/dsh 与 dsh-*——且版本稀疏无预发布链)。插件只使用 credential-reference 半边(resolve/describe/set/unset/credentialRef,自 0.1.0-rc.6 起稳定)与 agent/request + agent/request-error waterfall(载荷跨各版本未变);isCredentialRefName(rc.8 新增)本地实现兜底。注意 0.1.7 线自 3.3.2 起不再声明,需要它请装 3.3.1。

v3.3.1 新增

  • 文档更正——代码零改动(2026-09-29)。v3.3.0 的发布说明断言「本插件从来没真正换过 key,因为写 process.env 到不了凭证层」。该断言是错的,在此撤回。 真正把 key 交给 provider 的 credentials.resolve 包装自 v3.0.0 就存在 (git log -S 'credSvc.resolve =' -- dsh-key-fallback/lib/index.js → 75ea76a);从 registry 下载 已发布的 3.2.4 tarball 核对,lib/index.js:298 就是该包装、:305 是它的 pool-hit 诊断。 也就是说:轮换一直在生效,那几处 process.env 写入是与可用包装并存的冗余,而不是机制本身。 v3.3.0 的真实内容见下一节的准确清单。
  • 轮换生效的实机证据 —— 在真实桌面端(DSH 0.2.0-rc.1 + 插件 v3.3.0)会话走池中 provider 时, 取 GET /dsh-key-fallback/diag:200 条(resolve 57 / agent/request 51 / request-error 90), 池里两把 key 分别被用了 26 次 / 25 次,每次失败即交替: PICK key_fallback_sensenova_key1 → RATE_LIMIT → marked key_fallback_sensenova_key1 → PICK SENSENOVA_API_KEY → … → pool-hit SENSENOVA_API_KEY -> key_fallback_sensenova_key1。 每条 pool-hit 都写明当时实际生效的那把 —— 正是适配器在网络上真正拿去鉴权的那把。

v3.3.0 新增

  • 四项真实修复(2026-09-29)。注意:v3.3.0 最初的说明声称本版才让「换 key 第一次真正到达 provider」,那是错的——更正见上方 v3.3.1。v3.3.0 实际改的是:
    • activeRef 不再报错当前 key。 /pools 原先用 process.env[<池 env>] 的值去池里反查成员、 只在没匹配到时才回退 currentRef——所以可能高亮错误的那把。实机(0.2.0-rc.1)上它报 activeRef=SENSENOVA_API_KEY,而 currentRef 是 key_fallback_sensenova_key1。现在 activeRef 直接等于 currentRef,两者永不矛盾。
    • 删除 5 处冗余的 process.env 写入。 DSH 在启动时把 { ...process.env } 冻结成「启动环境快照」 (dsh-app-boot),dsh-launch-environment 把它拷进 Map,dsh-credentials-local.inherited() 只读这个快照——启动之后写 process.env 对凭证层不可见。因此这些写入对鉴权是死代码(真正供 key 的是 resolve 包装);删掉同时避免插件改写宿主进程环境。行为提示:继承 process.env 启的子进程 现在看到的是启动时的值而非轮换后的值——没有任何凭证消费者依赖它,因为它们全部都经 credentials.resolve 取值,而那正是包装拦截的地方。
    • 失败归因加了守卫。 agent/request-error 原先在无法确定当前 key 时会退化成归咎 keyValues[0];现在只标记它真能指名的那把。
    • 卸载会还原原始 resolve(经 ctx.effect),并带身份校验,绝不覆盖「在我们之后安装的」包装层—— 热重载/fiber 重建不再层层叠加、留下持有过期 service 的闭包。
  • 未改动:重发仍归 DSH 管。轮换处理只改池的当前 ref,并且仍然调用 next(),由 dsh-llm-retry 继续决定是否/重发几次。实测:每条轮换路径都调用了 next()。
  • 验证方式(全部实测,无推断):在进程内用真实的官方 @deepseek-ai/dsh-llm-pi-ai 适配器 + 真实 LocalCredentialProvider + 本地 mock 上游,从真实出站 HTTP Authorization 头里抓 key —— 装插件前 Bearer STORED-ENV-KEY,预选后 Bearer KEY-ONE-111,RATE_LIMIT 轮换后 Bearer KEY-TWO-222,dispose() 后回到 STORED-ENV-KEY。另有两套边界用例(enabled:false、空池、 env 解析不到、useKeyRef 锁定、HTTP 上 activeRef/currentRef 一致、dispose 幂等、不匹配的错误码) ——14/14 与 9/9 全绿。实机时间线见上方 v3.3.1。

v3.2.4 新增

  • peer 枚举追加 DSH 0.2.0-rc.1(2026-09-28)——代码零改动。DSH 桌面端升到 0.2.0-rc.1 后, 0.1.7-rc.2 的声明再次过时:门禁跳过 bundle(设置页里本插件整项消失、/dsh-key-fallback/* → 404; 是优雅跳过而非崩溃)。声明前核查四步:
    1. tarball 逐文件 diff(0.1.7-rc.2 → 0.2.0-rc.1):dsh-credentials、dsh-llm、dsh-settings、 dsh-shell、dsh-tools、dsh-mcp-client、dsh-web、dsh-agent 的全部 lib/ 文件 SHA1 一致—— 本插件用到的整个调用面(credentials.resolve/describe/set/unset、agent/request + agent/request-error waterfall、settings.describe/replace)逐字节未变(变化的只有 dsh-session 的附加式新增与 dsh-app-boot 门禁本体)。
    2. 门禁执行:用 0.2.0-rc.1 的 evaluatePluginCompatibility() 跑新声明 → 放行; 跑 3.2.3 的旧声明 → 四条 peer 全部拦截。
    3. 真机装配:沙箱安装官方 @deepseek-ai/[email protected](542 包)+ 独立 DSH_HOME, dsh --profile smoke --dump-config → 插件入树、零门禁拦截、零错误。
    4. 发布件复核:npm pack 产物内 package.json 已含新枚举。

v3.2.3 新增

  • peer 枚举追加 DSH 0.1.7-rc.2(2026-09-25)——代码零改动。DSH 桌面版(DeepSeek Harness desktop,运行时 0.1.7-rc.2)上线后,精确到 rc.1 的声明一夜过时:门禁把 bundle 跳过 (skipping profile bundle,插件列表徽标「异常」)。声明前核查三步:
    1. tarball 逐文件 diff(rc.1 → rc.2):dsh-credentials 的 lib/ 逐字节一致(只改了 README 与 package.json);dsh-llm 只新增内容类型与 ACCOUNT_QUOTA 错误码(本插件用到的 agent/request waterfall、credential-reference API 签名均未变);dsh-shell / dsh-settings 的 lib/ 逐字节一致。
    2. 门禁执行:用 rc.2 的 evaluatePluginCompatibility() 跑新声明 → 在 0.1.7-rc.1 与 0.1.7-rc.2 上均返回 undefined(放行)。
    3. 真机回归:scratch profile(@deepseek-ai/[email protected] + 插件 3.2.2 + 精确版本豁免)真机启动 → 池页 HTTP 200(scratch profile 无池配置,[] 属预期)。

v3.2.2 新增

  • 声明 DSH 版本支持(2026-09-24):新增 @deepseek-ai/dsh peer 条目(0.1.7-rc.1,逐版本枚举), 把「支持的运行时」写成显式契约。该声明由 DSH 自己的 evaluatePluginCompatibility()(dsh-app-boot 的 公开导出)在安装时与每次启动时校验:命中未实测的新运行时,bundle 会被优雅跳过 (stderr 打 skipping profile bundle,DSH 照常启动),而不是以某种未定义方式崩掉。这个门禁 只有 DSH 0.1.7 起才存在,所以 ≤0.1.6 的运行时只是看到一条不认识的 peer,不受影响 (本插件在那些版本上本来就走 settings.yaml 文件后端,一直可用)。只列实测版本,不用开放范围(仓库规范 3)。

v3.2.1 新增

  • 救回滞留在 settings.yaml.imported 里的池(2026-09-24)。0.1.7 的一次性导入器会在写入任何东西之前 先把 settings.yaml 改名为 settings.yaml.imported——所以某段导入失败时(典型:目标条目没声明 volatile 字段) 它永远不会重试,池子会永久留在 .imported 里。表现恰是:徽标显示 「尚未启用」、页面显示 「还没有任何池,点上方「启用新 provider 池」开始。」,尽管池子就在磁盘上。 注意文件回退在 v3.2.0 里本来就写了(readSettingsFromFile() 会在 settings.yaml 缺失时退读 settings.yaml.imported)——但在 0.1.7 上它永远轮不到:只要 _liveRef 非空, readSettings() 第一行就从 live-ref 分支返回,而 ref 里是 {}。真正缺的不是又一个读回退, 而是两个后端之间的一座桥。 v3.2.1 在首个 HTTP 请求时做一次性显式搬运(不在 apply() 里——原因见下): 当 live 配置里 provider 数为 0 且 旧文件里有池时,经 settings.replace() 写进 profile 条目。 标记文件(<DSH_HOME>/.key-fallback-migrated)保证「真正只做一次」,因此有意删光所有池后不会在下次启动被复活。
    • 为什么不能放在 apply(): settings.replace() 走 configEditor.edit(),要求本 entry 的 fiber 已 ACTIVE——describe() 会跳过 fiber.state !== 2 的条目,而 apply() 执行时 fiber 还在创建中, 调用必抛 No configurable plugin entry。首个 UI 请求(/pools)才是最早的安全时机。
    • 标记只在落盘成功之后才写,因此写失败会在下次启动重试。

v3.2.0 新增

  • 声明支持 DSH 0.1.7-rc.1,同时保留 0.1.5-rc.3(2026-09-24)。这是本插件首个需要改动代码的版本,原因是 DSH 0.1.7 改变了插件配置的存放位置——详见下节。

两种配置后端,同一份构建

自 DSH 0.1.7 起,插件配置不再位于 <DSH_HOME>/settings.yaml。首次启动时 0.1.7 会把该文件 改名成 settings.yaml.imported,并把每个段的内容写入 profile 补丁 (~/.dsh/profiles/<profile>/cordis.patch.yml)中对应 loader 条目的 config:;此后由 settings 服务托管, 插件通过注入的 config 参数读取,而不再自行读写该 YAML。rc.x 时代的 ctx.settings.get() / register() / installSection() 在 0.1.7 上已不存在。

因此本插件在启动时自动判别后端,两条路径同时可用:

DSH 0.1.5-rc.3(及更早 rc.x) DSH 0.1.7-rc.1(及更新)
池配置位置 <DSH_HOME>/settings.yaml 的 key-fallback: 段 profile 补丁中 key-fallback 条目的 config
插件如何读写 直接读写该 YAML 文件(附时间戳备份) config.providers 是活的 volatile ref;写入走 settings.replace()
判别方式 无 volatile schema 支持 ⇒ 文件后端 Config 声明了 volatile 字段 ⇒ 后端来自 config

移植该模式时有两个关键点:

  1. 必须声明 Config,否则迁移会静默丢弃配置。 0.1.7 的导入路径调用 settings.update(ns, values),若该条目没有声明 volatile 字段就会抛错,仅打印 settings: section ... was not imported,配置只残留在 settings.yaml.imported 里。因此 v3.2.0 导出 Config = z.object({ providers: <dict>.volatile() })。
  2. volatile API 在两种 schemastery 构建上不同。 .volatile() 在 schemastery 3.18.4(0.1.7)上可用, 但在 3.18.2(rc.3)上不存在——在那里调用会得到 undefined,而若据此注册一个无 volatile 的 schema 就会改变 rc.3 的行为。故导出做了守卫: typeof field.volatile === 'function' ? z.object({ providers: field.volatile() }) : undefined—— rc.3 拿到 没有 Config(行为与 v3.1.x 逐字节一致),0.1.7 拿到含 volatile 的那一份。

config.providers 的值被 DSH 深度冻结,故 readSettings() 向调用方返回可变深拷贝;写入先乐观地更新内存副本 再经 settings.replace() 落盘(未决写入计数避免 UI 短暂读回写入前的旧树)。

两条后端均已在真实安装上端到端实测:读取(两个 provider 都出现在 /dsh-key-fallback/pools,含 env key 实时值)、 增删改(POST/DELETE 往返并落盘)、以及 rc.3 回归(settings.yaml 未被改名也未改内容、cordis.patch.yml 仍为 []、备份照旧生成)。

v3.1.7 新增

  • 声明支持 DSH 0.1.5-rc.2(2026-09-15)。源码核查:@deepseek-ai/dsh-credentials / dsh-llm / dsh-settings 从 0.1.5-rc.1 到 rc.2 只有 package.json 变化——lib/文档逐文件 SHA256 全一致。运行时核查:对真实 [email protected] web profile 严格模式安装 peer(不加 --legacy-peer-deps)零告警通过,启动零浏览器控制台错误,/dsh-key-fallback/* 路由服务,设置页「API Key 回退」渲染。
  • 声明支持 DSH 0.1.6-alpha.1(2026-09-15,源码级逐文件哈希比对 + 真实运行时冒烟:在临时安装的 0.1.6-alpha.1 上以 web profile 实测加载)。未改动任何代码:@deepseek-ai/dsh-credentials 与 @deepseek-ai/dsh-settings 的 lib/ 相对 0.1.5-rc.2 逐字节一致(仅版本号/文档变化),@deepseek-ai/dsh-llm 的删除项(priceImages、projectImagesForTextModel/request-image-offload 系列)均在本插件调用面之外——本插件调用的 credentialRef、credentials.resolve/set/unset/describe、llm.listProviders/listConfigurableProviders、agent/request、agent/request-error、settings、webServer 全部实测保留(webServer 提供方 dsh-host-webserver 整包字节一致)。运行时验证:插件激活、/dsh-key-fallback/* 路由服务、设置页「API Key 回退」渲染。旧版本继续兼容——0.1.5-rc.2 与 0.1.6-alpha.1 均为追加进枚举,未删除任何版本。

v3.1.6 新增

  • 声明支持 DSH 0.1.5-rc.1(2026-09-10 源码级兼容性核查)。未改动任何代码:@deepseek-ai/dsh-credentials 与 @deepseek-ai/dsh-settings 相对 0.1.2-rc.1 只有 package.json 版本号变化(代码逐文件哈希一致),@deepseek-ai/dsh-llm 的变化是附加式(新增 FileBlock / fileHandleText / assistant-stream 等),本插件调用的 API 全部保留:credentialRef、credentials.resolve/set/unset/describe、llm.listProviders/listConfigurableProviders、agent/request、agent/request-error、settings、webServer;agent/pre-step waterfall 载荷两版逐行相同。旧版本继续兼容——0.1.5-rc.1 是追加进枚举,未删除任何版本。
  • 注:DSH 0.1.5-rc.1 移除了 ctx.agent 并调整 Inbox/Session API,本插件从未使用这些接口。

v3.1.4 新增

  • env 名自动派生已消毒:为 id 含非法字符(b-ai、B.AI 等)的 provider 建池不再报 env must be POSIX identifier——自动派生的 env 名(<PROVIDER>_API_KEY)现在会把 -/. 等转成 _(b-ai → B_AI_API_KEY)。显式传入的 env 仍按原规则校验。修复"选择 LLM provider → 启用"对此类 provider 的 400 报错。

v3.1.3 提供什么

设置 → API Key 回退 —— 顶层设置页,全新 UI(状态点、徽章、渐变池卡片、逐 key 行):

  • 可配置且真正生效的轮转触发码(rotateOn):点选 chips 决定哪些错误码触发轮换。预设 chips 覆盖 DSH LlmError 标准码全集——QUOTA / AUTH / RATE_LIMIT / TIMEOUT / TRANSPORT / SERVER / EMPTY_RESPONSE / INVALID_CREDENTIAL——也可添加非标准/自定义错误码(与 provider 的 failure.code 精确匹配)。你保存什么就执行什么:不存在"把选中的三个码偷偷变回六码超集"的魔法。ABORTED(用户取消)永不触发轮换。
  • 真实当前使用 key 显示:页面显示当前真正在用哪把 key(池的当前 ref —— 正是凭证接缝返回给适配器的那把)——不是截断的哈希,不是猜的名字。
  • 短 ref 命名:新 key 自动命名为 key_fallback_<provider>_key1、key_fallback_<provider>_key2、…,UI 显示干净的短名(key1、key2、…或你的自定义 label)。已有旧长 ref 一次性、幂等地自动迁移(写新 ref → 持久化配置 → best-effort 删旧 ref;任何一步失败即中止、安全可重试)。
  • 明文揭示:每行有眼睛开关(👁 / 🙈),经 GET /keys/plain 显示真实值(仅限本池的 key 或本池 env key)。env key 行也会显示明文——不会被只读说明吞掉。
  • 环境密钥可编辑:池的 env key(AGNES_API_KEY 等)在凭证文件可写时可直接在页面里改。若由启动环境提供(只读),UI 会说明并拒绝编辑(HTTP 400)。
  • 逐 key 控制:更新值、设置"失败后→"下一把(nextRef)、锁定到某把 key("设为当前")、删除 key(env key 不可删)。
  • 池级控制:启用开关、冷却显示、"↺ 重置冷却"、池锁定/自动轮换、逐池状态(live / cooling / recovered)。

轮换语义

  • key 到底怎么被用上:DSH 的凭证接缝是 credentials.resolve(ref)。每个模型适配器都经它取 key(dsh-llm-pi-ai、dsh-llm-deepseek-api-key,以及任何解析凭证引用的插件),且每次请求都会调用一次。本插件包装的就是这一个方法:当解析的 ref 属于已配置的池时,包装层返回池的当前 key,而不是存储里的值。所以"换 key"就是改池的当前 ref —— 下一次请求立刻生效,无需重启。
    • 写 process.env 不管用:凭证 provider 读的是 DSH 启动时冻结的「启动环境快照」(dsh-app-boot 里的 {...process.env},由 dsh-launch-environment 拷进 Map),启动之后再改 process.env 对它不可见。DSH 自己在 provider 条目上的注释也写着 managed document "is never materialized into the process environment"。历史说明:3.2.4 及之前插件也会写 process.env[<池 env>],但它始终与上面的包装并存——那个写入是冗余的,不是机制本身,所以轮换一直照常工作。v3.3.0 出于整洁删掉了这些写入。若你看到旧笔记声称轮换「从未生效」,那是错的,见 v3.3.1 一节。
  • pick(agent/request,预选):先尊重 useKeyRef 锁定(但冷却中的锁定 key 会跳过,避免池在某把坏 key 上死锁),否则按游标在 live key 上轮询。选中的 ref 成为池的当前 ref —— 也就是凭证接缝下一次 resolve 交给适配器的那把。
  • fail(agent/request-error,注册 prepend 保证先于 dsh-llm-retry 看到错误):仅当错误匹配本池 rotateOn 时才处理——按 failure.code(精确)、按 HTTP 状态映射(429→RATE_LIMIT、401/403→AUTH、402→QUOTA、5xx→SERVER)、或按消息关键字。把失败 key 标记为固定 cooldownMs(默认 30 s),然后切到 nextRef(若配置)否则下一把 live key。
  • re-send 完全交给 DSH 的 dsh-llm-retry 与用户自己的 per-provider 重试策略。两者独立互补:重试插件决定"同一把 key 重发几次"(retryPolicy.retryableCodes 默认 EMPTY_RESPONSE/RATE_LIMIT/SERVER/TIMEOUT/TRANSPORT——注意不含 AUTH/QUOTA);本插件决定"换下一把 key"。例如 AUTH 失败(重试本来也不会重发,重发也白搭)仍会轮换到下一把——下一次请求就会用新 key 鉴权。

诊断

  • client 会把运行时异常 POST 到 POST /dsh-key-fallback/diag。
  • GET /dsh-key-fallback/diag 返回内存缓冲(最近 200 条)JSON。

安装

# 从 npm(推荐)
cd ~/.dsh/profiles/web
pnpm add @omdp/dsh-key-fallback

# 或从本地 checkout
dsh plugin --profile web add link:D:/WorkSpace/omdp/dsh-key-fallback

# 重启 DSH,然后打开 设置 → API Key 回退

注意:该 profile 目前从 npm(^3.x)安装到 ~/.dsh/profiles/web/node_modules/@omdp/dsh-key-fallback;把新版 lib/index.js + lib/client.js 复制过去并重启 DSH 即可升级。包声明了 dsh.bundle.patch,自动激活——无需手动改 cordis.patch.yml。

HTTP API(host)

方法 路径 用途
GET /dsh-key-fallback/pools 列池:live 状态、activeRef、env 可写性/来源、逐 key 状态
POST /dsh-key-fallback/pools 创建/更新池(enabled、cooldownMs、rotateOn、useKeyRef、…)
DELETE /dsh-key-fallback/pools?provider= 删除池 + 其全部 key
POST /dsh-key-fallback/keys 加 key(自动短 ref key_fallback_<p>_keyN)
PATCH /dsh-key-fallback/keys 更新值 / label / nextRef / useKeyRef(env key 的值=改 env)
DELETE /dsh-key-fallback/keys?provider=&ref= 删 key(env key 拒绝)
GET /dsh-key-fallback/keys/plain?provider=&ref= 揭示真实值(仅本池 key / env key)
POST /dsh-key-fallback/reset 重置某池冷却状态
GET/POST /dsh-key-fallback/diag 诊断缓冲

已知限制

  • 冷却为每池固定 cooldownMs(无指数退避);冷却到期 key 自动恢复 live。
  • 轮换/冷却状态为内存态 + 持久化池配置;DSH 重启会重读配置并重算 live 状态。在 DSH 0.1.5-rc.3 及更早版本上,该配置是 <DSH_HOME>/settings.yaml 的 key-fallback 段;在 0.1.7+ 上则是 ~/.dsh/profiles/<profile>/cordis.patch.yml 中 key-fallback 条目的 config。
  • env key 不能通过 UI 删除(它是池的身份标识)。

License

MIT