@eddyskywalker/dsh-chatgpt-subscription 0.38.0 → 0.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +142 -1
- package/README.md +48 -11
- package/lib/client.js +805 -151
- package/lib/client.js.map +1 -1
- package/lib/index.js +2174 -700
- package/lib/types/client/CodexSubscriptionSection.d.ts +1 -1
- package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +16 -1
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/cline-pass/ClinePassSection.d.ts.map +1 -1
- package/lib/types/client/cline-pass/api.d.ts +16 -1
- package/lib/types/client/cline-pass/api.d.ts.map +1 -1
- package/lib/types/client/cline-pass/locales.d.ts +144 -18
- package/lib/types/client/cline-pass/locales.d.ts.map +1 -1
- package/lib/types/client/cline-pass/styles.d.ts.map +1 -1
- package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
- package/lib/types/client/kimi-code/locales.d.ts +8 -17
- package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
- package/lib/types/client/locales-ru/cline-pass.d.ts.map +1 -1
- package/lib/types/client/locales-ru/hub.d.ts.map +1 -1
- package/lib/types/client/locales-ru/kimi-code.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +43 -1
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/minimax-code/commands-contract.d.ts +14 -4
- package/lib/types/client/minimax-code/commands-contract.d.ts.map +1 -1
- package/lib/types/client/minimax-code/locales.d.ts +2 -2
- package/lib/types/client/progress-updates/settings-binding.d.ts +8 -1
- package/lib/types/client/progress-updates/settings-binding.d.ts.map +1 -1
- package/lib/types/client/progress-updates/settings-section.d.ts.map +1 -1
- package/lib/types/client/styles.d.ts.map +1 -1
- package/lib/types/compat.d.ts +33 -0
- package/lib/types/compat.d.ts.map +1 -1
- package/lib/types/host/agent-preset.d.ts +5 -0
- package/lib/types/host/agent-preset.d.ts.map +1 -1
- package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
- package/lib/types/host/antigravity/mapper.d.ts +0 -1
- package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
- package/lib/types/host/antigravity/types.d.ts +1 -2
- package/lib/types/host/antigravity/types.d.ts.map +1 -1
- package/lib/types/host/claude/mapper.d.ts +5 -7
- package/lib/types/host/claude/mapper.d.ts.map +1 -1
- package/lib/types/host/claude/model-catalog.d.ts.map +1 -1
- package/lib/types/host/cline-pass/adapter.d.ts +1 -1
- package/lib/types/host/cline-pass/adapter.d.ts.map +1 -1
- package/lib/types/host/cline-pass/client.d.ts +16 -3
- package/lib/types/host/cline-pass/client.d.ts.map +1 -1
- package/lib/types/host/cline-pass/engine.d.ts +11 -3
- package/lib/types/host/cline-pass/engine.d.ts.map +1 -1
- package/lib/types/host/cline-pass/line.d.ts +1 -1
- package/lib/types/host/cline-pass/line.d.ts.map +1 -1
- package/lib/types/host/cline-pass/protocol.d.ts +18 -0
- package/lib/types/host/cline-pass/protocol.d.ts.map +1 -1
- package/lib/types/host/cline-pass/routes.d.ts +2 -0
- package/lib/types/host/cline-pass/routes.d.ts.map +1 -1
- package/lib/types/host/cline-pass/store.d.ts +2 -0
- package/lib/types/host/cline-pass/store.d.ts.map +1 -1
- package/lib/types/host/cline-pass/token-store.d.ts +11 -0
- package/lib/types/host/cline-pass/token-store.d.ts.map +1 -1
- package/lib/types/host/cline-pass/tools.d.ts.map +1 -1
- package/lib/types/host/cline-pass/types.d.ts +24 -2
- package/lib/types/host/cline-pass/types.d.ts.map +1 -1
- package/lib/types/host/codex-account-pool.d.ts +3 -0
- package/lib/types/host/codex-account-pool.d.ts.map +1 -1
- package/lib/types/host/common/account-pool.d.ts +59 -5
- package/lib/types/host/common/account-pool.d.ts.map +1 -1
- package/lib/types/host/common/credential-read-cache.d.ts +11 -1
- package/lib/types/host/common/credential-read-cache.d.ts.map +1 -1
- package/lib/types/host/common/credentials-compat.d.ts +73 -0
- package/lib/types/host/common/credentials-compat.d.ts.map +1 -0
- package/lib/types/host/common/pool-storage-settings.d.ts +41 -0
- package/lib/types/host/common/pool-storage-settings.d.ts.map +1 -0
- package/lib/types/host/common/pool-storage.d.ts +143 -0
- package/lib/types/host/common/pool-storage.d.ts.map +1 -0
- package/lib/types/host/credential-store-secret-service.d.ts +27 -0
- package/lib/types/host/credential-store-secret-service.d.ts.map +1 -1
- package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
- package/lib/types/host/kimi-code/cache-hint.d.ts +29 -15
- package/lib/types/host/kimi-code/cache-hint.d.ts.map +1 -1
- package/lib/types/host/kimi-code/mapper.d.ts +34 -31
- package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
- package/lib/types/host/kimi-code/model-catalog.d.ts +32 -0
- package/lib/types/host/kimi-code/model-catalog.d.ts.map +1 -1
- package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
- package/lib/types/host/kimi-code/token-store.d.ts +1 -11
- package/lib/types/host/kimi-code/token-store.d.ts.map +1 -1
- package/lib/types/host/kimi-code/types.d.ts +38 -14
- package/lib/types/host/kimi-code/types.d.ts.map +1 -1
- package/lib/types/host/oauth-service.d.ts +83 -1
- package/lib/types/host/oauth-service.d.ts.map +1 -1
- package/lib/types/host/preset-sync.d.ts +2 -2
- package/lib/types/host/preset-sync.d.ts.map +1 -1
- package/lib/types/host/qoder/account-pool.d.ts +4 -0
- package/lib/types/host/qoder/account-pool.d.ts.map +1 -1
- package/lib/types/host/qoder/client.d.ts +24 -2
- package/lib/types/host/qoder/client.d.ts.map +1 -1
- package/lib/types/host/qoder/oauth.d.ts +17 -0
- package/lib/types/host/qoder/oauth.d.ts.map +1 -1
- package/lib/types/host/qoder/routes.d.ts.map +1 -1
- package/lib/types/host/routes.d.ts +10 -0
- package/lib/types/host/routes.d.ts.map +1 -1
- package/lib/types/host/subagent-model-authorization.d.ts +20 -5
- package/lib/types/host/subagent-model-authorization.d.ts.map +1 -1
- package/lib/types/host/token-store-linux.d.ts.map +1 -1
- package/lib/types/host/token-store.d.ts +16 -0
- package/lib/types/host/token-store.d.ts.map +1 -1
- package/lib/types/index.d.ts +26 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/cline-pass-contracts.d.ts +48 -2
- package/lib/types/shared/cline-pass-contracts.d.ts.map +1 -1
- package/lib/types/shared/contracts.d.ts +86 -0
- package/lib/types/shared/contracts.d.ts.map +1 -1
- package/lib/types/shared/kimi-code-contracts.d.ts +0 -16
- package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -1
- package/package.json +37 -37
- package/presets/dispatch/agent.cordis.yml +25 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,138 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.39.0 - 2026-10-24
|
|
6
|
+
- **[dispatch] 调度模式按行为实测重写纪律:限额写成上限、任务书带限额台账、注意到风险必须处置、路由三态可读**
|
|
7
|
+
- **背景**:一份对 `deepseek-v4.1-flash-1017` 的路口调度基准对比报告(三局均值 567.98 vs 旧版 687.30)连同其后的定向行为探针(超市盲盒、路口日志复演、团队采购荷兰拍,共三个 POV、86 局以上)把结论收敛成几条可迁移的行为事实:规则写明时照做、没写明的取最严解读且不去验证;写明的代价会提前处理,要从环境动态推出来的二阶后果不处理;预算靠心算且几乎总是零余量收尾;把事后才到的信号当事前保护。本 preset 是一份纯提示词契约,这些点逐条落在它上面。
|
|
8
|
+
- **改法(限额写死,R0/R5)**:`L1 Moderate: 2–5 files` 与 `Ask at most 1–2 key questions` 改成 `edits at most 5 files (5 is a cap, not a range and not a target)` 与 `Ask at most 2 key questions (no full interview; 2 is the cap)`——探针里 `At most 2 per cycle` 被 9/9 局读成「每周期只开 2 个」、18/18 个周期都没验证过,区间写法会把 L1 压到下限、把问题数压到 1。重派预算从 `Re-dispatch the same task brief at most twice`(可读成「总共跑两次」)改成 `1 first attempt + at most 2 re-dispatches = at most 3 runs total`,并写明 `Count runs, not failures`;R8 的对应条件同步改为 `has still not passed review after its third run under R6`。
|
|
9
|
+
- **改法(任务书第六要素,R5)**:五要素扩为六要素,新增 `Limits`——每条数值限额写清「限制什么、什么单位、上限多少、是否可累积」,最小覆盖重试次数、改动文件数、命令数、以及任何按周期刷新的配额及其重置规则(按周期刷新的额度不用即作废、不累积);某维度真的不限就显式写 `unlimited`(沉默会被读成上限 0)。同时写死一条反向纪律:不要让子代理复述规则来纠错——探针里它复述出来的正是误读本身;有疑问时花一次最小工具调用去验证,歧义避不开时把这条逃生指令写进任务书。
|
|
10
|
+
- **改法(注意到必须处置,R6)**:新增 `[Noticed but not handled]`——复审发现的缺陷只有两条出路(带证据重派 / 用 `ask_user_question` 交给用户定范围),「写进交付摘要然后照常交付」不再是可选结果。这是路口那份报告里最大的单项损失(点名了会闯红灯的车、之后一辆没放、最后 6 辆全部卷入连环事故)在本模式里的等价物。同时把完成通知定性为**事后信号**:它只说孩子停了、不说明活对了,事前控制是 R5 写进任务书的验收标准。
|
|
11
|
+
- **改法(轮前扫描,R7)**:任务清单项自带运行次数(重派预算变成「读」而不是「记」),并新增 `[Before every turn]`:先找「本轮不做就会升级/过期/超时」的项,优先于「只是量大」的项;每条未结项带滞留轮数,超过任务书自己的上限就处置或升级。这一句是探针里唯一实测把升级从每局 3.67 次降到 0 的提示。
|
|
12
|
+
- **改法(路由三态,R2)**:原文写「工具在场与路由参数总是一起出现,所以这一个信号就够了」——**这是错的**。`modelSelectionSettings: true` 让 `list_subagent_models` 与 `provider`/`model` 参数静态挂载,因此即使会话没有记录任何允许清单它们也在场;而守卫读的是会话记录的策略事件(`effectiveAllowedRoutes`),没有记录时 `[]` 在 `delegationDenialReason` 里等于**完全不校验**、在 `post-execute` 增强里等于**不加任何说明**。现在分成三态:`[State: Listed]`(输出列出授权路由,校验生效)、`[State: Unlisted]`(工具在场但没有允许清单,不校验一切、省略路由是正当选择、不得声称任何路由「已授权」)、`[State: Unmounted]`(工具根本没挂载,继承父路由)。R8 相应收紧:只有 `[State: Unmounted]` 能作为 fallback 理由,`[State: Unlisted]` 不行——那里委派照常可用,只是不受限。
|
|
13
|
+
- **改法(空清单可见化,`src/host/subagent-model-authorization.ts`)**:`enrichListSubagentModelsOutput` 在 `allowed.length === 0` 时不再静默返回,改为追加新导出常量 `UNRESTRICTED_ROUTING_NOTICE`——写明「本会话没有允许清单生效、路由不受限、省略 provider/model 是正当的、如需按任务治理请在 Settings → Subagents 启用并新建会话」;`post-execute` 监听器里对应的提前返回一并删除,两种姿态都走同一条注入路径。这是全插件已在用的同一种模式:把状态塞进工具结果,而不是让模型去猜或去查一次。新增 Anti-Pattern 17–20 分别盯住「只记不处置」「用区间写下限」「让子代理复述规则」「在没有允许清单时声称已授权」,并把第 4 条从「model selection is available」改成按三态表述。
|
|
14
|
+
- **测试**:`test/agent-preset.test.ts` 由 33 例增至 38 例——`agent-presets` 段新增五条把新纪律钉住(三态判据与反 `single signal` 措辞、区间改上限且旧形态不得回归、任务书 Limits 六要素、风险必须处置且通知是事后信号、轮前扫描与清单自带运行次数),并把 R8 用例从 `two re-dispatches` 更新为 `third run` + 「只有未挂载才能 fallback」。`test/subagent-model-authorization.test.ts` 27 例内扩充:空清单不再原样返回而带 `UNRESTRICTED_ROUTING_NOTICE`、幂等、空输出时通知是唯一内容、有清单时不得出现「No allowlist is in force」,并新增一条 `post-execute` 钩子级用例证明未记录允许清单的会话真的从同一条路径读到这条事实。
|
|
15
|
+
- **验证**:`npm run typecheck` 三工程 0 错误;`npx vitest run test/agent-preset.test.ts test/subagent-model-authorization.test.ts` 共 65 例全绿;全量 `LANG=C.UTF-8 npm test` **287 文件通过 / 2 skipped,4756 passed / 8 skipped / 0 failed**;`rm -rf lib && npm run build` 干净构建通过。
|
|
16
|
+
- **依据与边界**:结论来自 `karminski/deepseek-v4.1-flash-1017-issue-pov` 的三次 POV 与其对比报告第 11 节的定向实测。其中「不核实」「风险厌恶」两条假设已被该仓库自己推翻,本改动因此**没有**往「更谨慎、多核对」的方向加训诫,只搬了三类机制性做法:把歧义写死、把状态塞进工具结果、把记账从模型记忆挪到外部载体。未搬的是「更敢试错」的方向——路口基准奖励激进试错,而本模式的复审、重派、子代理运行都有真实成本,同一偏好在两个域里方向相反。
|
|
17
|
+
- **[kimi-code] 撤除缓存 TTL 选择,缓存过期提示改用实测的 30 分钟**
|
|
18
|
+
- **现象**:设置页让用户在 5 分钟 / 1 小时两档之间选缓存写入时长,并把「1h 写入单价约 5m 的两倍」当既定事实写进说明;而缓存过期提示在空闲第 6 分钟就开始报「缓存已过期」。
|
|
19
|
+
- **根因(两层)**:一是**档位本身没有依据**。5m / 1h 只写在 Moonshot **开放平台**文档(`docs/api/chat`、`platform.kimi.com/docs/guide/context-caching`),Kimi Code 订阅端点(`api.kimi.com/coding`)没有任何缓存 TTL 文档;官方 CLI 2.0.0 的代码路径里只有 `prompt_cache_key`、**没有** `prompt_cache_options`,第三方因此没有可抄的样本。`MoonshotAI/kimi-code#3942` 专门请求暴露该档位,并附带问「如果 coding 端点不认这个字段,请明确写出来」——该 issue 至今 open、0 评论、无标签。二是**阈值取的是档位的名字而不是寿命**:`CACHE_TTL_MS['5m']` 被当成 5 分钟,而该端点的默认档实测能热约 25 分钟。
|
|
20
|
+
- **实测依据**:两份独立数据互相印证。`pi-provider-kimi-code` 给出 `[300s, 1800s)`(300s 命中、1800s / 3600s / 7200s 全部未命中);更严格的一份(11 个端点横评,每个年龄 3 个副本、**每条前缀只探一次**以免探针自己续命)给出 Kimi coding plan 的存活曲线 —— 5–25 分钟 3/3 命中、30 分钟 1/3、35 分钟 0/3。两份在 30 分钟这个边界上对上了。
|
|
21
|
+
- **改法(撤档位)**:`cacheTtl` 从存储层(`token-store.ts` 的 schema 与文件存储)、`KimiCodeModelSettings` / `KimiCodeWebStatus` / `KimiCodeSettingsUpdateDto` 三个契约、`RequestMediaOptions`、`routes.ts` 的 status 与 settings 分支、`adapter.ts` 的请求构建、以及设置页的下拉框里**全部移除**;`KimiCacheTtl` / `KimiCodeCacheTtl` / `isKimiCacheTtl` 与 mapper 的两个缓存字段构造函数一并删除。两条 wire 现在都**不发任何缓存字段**,`buildRequest` 的返回值与引入该设置之前逐字节相同。
|
|
22
|
+
- **改法(阈值)**:`CACHE_TTL_MS` 由 `Record<'5m'|'1h', number>` 改为单个常量 `30 * 60 * 1000`;`CacheHintInput` 去掉 `cacheTtl`,`evaluateCacheHint` 不再按档位查表。取 30 分钟(首个多数副本已失效的年龄)而不是 25 分钟(最后一个全热年龄),因为该模块自己的原则是宁漏报不误报:25 分钟会在缓存仍更可能有效时开火,代价是真正过期后最长晚 5 分钟提示。
|
|
23
|
+
- **改法(文案三语)**:`locales.ts`(zh + en)与 `locales-ru/kimi-code.ts` 的 `cacheTtl` / `cacheTtlHint` / `cacheTtlDefault` / `cacheTtl5m` / `cacheTtl1h` 五个键合并为 `cacheNote` / `cacheNoteHint` 两个,写明「不发送任何缓存时长字段、档位无从选择、过期提示按 30 分钟判定」;俄语键集仍由 `Record<KimiCodeLocaleKey, string>` 在编译期强制。
|
|
24
|
+
- **测试**:`test/kimi-code-cache-hint.test.ts` 由 14 例增至 15 例——新增两条把实测值钉住:`CACHE_TTL_MS` 逐值等于 30 分钟(改回 5 分钟立刻红),以及空闲 25 分钟**不得**报警(该年龄实测 3/3 命中,报警即误报);原「按档位区分 5m / 1h」的用例随档位一并删除。`test/cache-ttl.test.ts` 的 Kimi 段由「各线路如何发档位」改写为「两条 wire 都不发缓存字段」的回归守卫(含「传了其它 media 选项也不能捎带缓存字段」),Claude 段一行未动——那条线路的 1h 有官方文档与 beta 头背书。`test/kimi-code-cache-write.test.ts` 的「把配置的档位带上请求」改为「不发送缓存字段」。10 个测试夹具里的 `cacheTtl: null` 随之清理(脚本误删了 `line-locale.test.tsx` / `russian-locale.test.tsx` 两处 **Claude** 状态里的同名字段,已恢复)。
|
|
25
|
+
- **验证**:`npx tsc -b --force` 与 `tsc -p test/tsconfig.json` 均 0 错误;`npm test` **282 文件通过 / 2 skipped,4657 passed / 8 skipped / 0 failed**;`test/kimi-code*` + `cache-ttl` 35 文件 **522 例全绿**。
|
|
26
|
+
- **文档**:README 的 Kimi 缓存小节把「TTL 实测在 300–1800 秒之间」改为「实测约 25–35 分钟」并写明两份实测的方法与数值,删掉「写入时长可手动选择」与「1h 写入约为 5m 两倍价」两条无依据表述,新增「本线路不发送任何缓存时长字段」及其依据(含 #3942)、「过期提示按 30 分钟判定」及其取舍,并标注写入分档响应头同样只有开放平台文档背书、订阅端点无实测样本。
|
|
27
|
+
- **仍未验证**:显式带 `ttl: '1h'` 在订阅端点是否生效,公开数据里不存在(官方 CLI 发不出这个字段,第三方无样本可抄)。若将来需要定论,四次请求即可:同一固定前缀带 `ttl: '1h'` 写一次,在 6 / 16 / 40 分钟各重放一次。
|
|
28
|
+
- **[storage] 号池存储后端可选:新增 `poolStorage: keyring | credentials`(默认 `keyring`),无桌面密钥环的 Linux 服务器不再存不下账号,设置卡里直接切换**
|
|
29
|
+
- **现象**:Linux 上号池后端被写死成 Secret Service(libsecret / `org.freedesktop.secrets`)。桌面机正常,但服务器上通常根本没有 secret service:OAuth 令牌交换成功、凭据存不下来,登录一律以「ChatGPT credentials could not be saved securely」收场。唯一的老办法是装 `gnome-keyring` 并用空密码解锁运行——那除了文件权限外没有任何加密,还把一整套桌面栈拖上服务器。
|
|
30
|
+
- **改法(选择)**:`createPoolBackend` 换成 `src/host/common/pool-storage.ts` 的 `resolvePoolStorage()`,`AccountPoolCore` **惰性解析一次并缓存整个进程生命周期**(读、写、刷新回写走同一个 resolve 出来的 store;只有设置变更时 `poolStorageChanged()` 才让下一次读取重新解析——按请求重新探测等于每次模型请求多一次 `secret-tool` 启动,还可能让同一轮里两个请求用上两个不同的存储)。两个值:`keyring`(默认,桌面平台存储:DPAPI / 钥匙串 / Secret Service)与 `credentials`(DSH 自己的凭据库)。**没有 `auto`**:按守护进程是否应答自动挑存储会让同一个号池在两个存储之间漂移,而漂移看起来和「账号全没了」一样。
|
|
31
|
+
- **改法(后端)**:`credentials` 走 DSH 凭据库(`$DSH_HOME/.credentials.yaml`;POSIX 上强制 `0600`、文件对他人可读时该 provider 拒绝启动;Windows 上只有 profile ACL,没有权限位可强制),用法是 seam 的**记录半边** `readRecord/modifyRecord/deleteRecord`(`describeRecord` 不用,就不写进形状要求里),文档以 `{kind:'grant', payload}` 存放——payload 是 owner 自己的 JSON,seam 不解释,比塞进环境变量形状的字符串槽更贴切;写入只走 `modifyRecord`。**写入语义是如实的 last-writer-wins**:`modifyRecord` 的锁让一次写是原子的,但整份号池文档是按一份内存副本写回的,另一个进程在这中间保存的内容会被覆盖——和密钥环后端一直以来的保证一样,代码注释里也这么写了,不再宣称「两个进程不会互相吞掉账号」。`credentials` 不绑定平台,Windows / macOS 选它时 DPAPI 与钥匙串完全不参与。`SecretServiceCredentialStore` 新增 `ping()`:回答「这台机器到底有没有 keyring」(`lookup` 返回「没有这条」=应答;锁着或没有会话总线=不应答)。
|
|
32
|
+
- **选错就报错,不静默换地方**:`keyring` 在不可达的主机上返回一个「不可用」store,任何读写都以一句写明「把 Account storage 改成 DSH 凭据库」的话失败,并在卡片上标为 `unavailable: 'keyring-unreachable'`;`credentials` 在没有 `ctx.credentials` 的宿主上同理(`no-credentials-service`)。相应地,**不变量**:Windows 仍是 DPAPI、macOS 仍是 Keychain,默认值下桌面凭据路径零变化;单凭据镜像仍走平台存储。
|
|
33
|
+
- **界面**:设置页 ChatGPT 账号卡片新增 `Account storage` 选择器(`Desktop keyring` / `DSH credential store`),每个选项下一句说明(桌面密钥环仅限桌面安装、服务器上会失败;DSH 凭据库是 `$DSH_HOME/.credentials.yaml`、静态不加密靠权限保护),下面是「当前实际使用:…」(写的是真实 resolve 出来的后端,DPAPI / 钥匙串 / Secret Service 分别列出)、选中的存储不可用时的红色原因行,以及一句「另一个存储里的账号留在那里,切回去之前不显示,不做迁移」。选择通过 `POST /storage` 写入插件自己的文档 `storages/dsh-chatgpt-subscription-pool-storage.json`(原子写)并立刻让所有池重新解析,profile 里的 `poolStorage` 只是没在卡片里选过时的默认值。新增 13 个键,中/英/俄三份语言包同步(俄语包键集全覆盖由既有用例守着)。
|
|
34
|
+
- **测试**:`test/pool-storage.test.ts` 32 例(评审新增 6 例:非法记录 key 到不了 seam、以数字/字母开头的摘要都生成合法 key、不可用存储的 `load()` 报错而不是回退、晚挂载的 `credentials` 服务被接上、只给 `hooks.backend` 时按平台报告后端;审计新增 4 例:读失败时 `setStrategy` 不落盘、读失败时 `addAccount` 不覆盖活文档、读路径报出存储原因而不是「没有账号」、坏文档仍可恢复且下一次写入即修复)。`test/credential-read-cache.test.ts` 新增 1 例(`invalidate()` 之后才结束的旧读取不进快照);`test/oauth-service.test.ts` 新增 1 例(读到不了的存储 → 状态里 `poolStorage.unavailable: 'store-unreadable'`,账号列表为空但原因可见)——默认 `keyring` 在三个平台各自解析成 DPAPI / 钥匙串 / Secret Service、`credentials` 在 win32/darwin 上可用且完全不碰 DPAPI 与钥匙串、`keyring` 在不可达主机上给出带切换提示的明确错误且**不**回落到凭据库、`credentials` 在真实 `spawn ENOENT`(没有 secret-tool)下照常保存与读取、`ping()` 区分「没有这条」与「没有应答」、`credentials` 往返读写(含非 grant 记录拒绝、写入失败必须报错)、读路径与刷新回写各一例(带「只要被碰就抛错」的 keyring 三脚架,证明没有任何路径绕回 Secret Service)、以及缓存语义(三次请求只探测一次 keyring;只有 `poolStorageChanged()` 让下一次读取重新解析)。`test/routes.test.ts` 新增 2 例:`POST /storage` 写入并返回已经切换好的状态、未知值回 400 且不写文件。`test/oauth-service.test.ts` 另有 1 例:池写入失败仍是 `storage-failed` / 「ChatGPT credentials could not be saved securely.」,不会假装成功。
|
|
35
|
+
- **评审修复**:① 号池在凭据库里的地址改成 `dsh-chatgpt-subscription/pool-<路径摘要>`——seam 要求每段匹配 `/^[a-z][a-z0-9-]*$/`,裸 sha256 摘要里 62.5% 以数字开头,那样的 key 写入会成功、**下次启动**解析整份凭据文档时判非法,把宿主上所有凭据(DeepSeek key、Telegram token)一起带走;`credentialsRecordKey()` 现在自己按同一条规则校验两个段,非法 key 到不了 seam,测试替身也按这条规则拒绝 key(过去两处断言是同一个表达式自己跟自己比,构造上看不见违规)。② 号池测试不再读 ambient `process.platform`:`AccountPoolHooks` 增加 `platform` 并由 `resolveBackend()` 转发,断言某平台分类的用例显式钉住平台(resolver 里没有 Linux 特判)。③ `test/antigravity-proxy.test.ts` 的内存存储 helper 补上 `SecretServiceCredentialStore.prototype.ping` 的桩(返回「可用」),这个文件继续只测代理路由,不再在没装 `secret-tool` 的 CI 上因探测失败而红。④ `credentials` 服务改成每次解析时用 getter 读(`ctx.get('credentials')`),晚挂载不再让 `poolStorage: 'credentials'` 永久停在 `no-credentials-service`。⑤ 存储不可用时 `load()` 的错误不再被吞:池子如实报「不可用」,而不是退回单凭据镜像那批账号。⑥ `POST /storage` 在没接这个设置的宿主上明确回 404(注释与行为一致,不再是 500)。⑦ 只给 `hooks.backend` 不给 `hooks.storage` 时按平台报 DPAPI / 钥匙串 / 密钥环,不再编出 `backend: 'keyring', encrypted: false` 这种自相矛盾的值。⑧ 文档口径改成「POSIX: 0600 强制;Windows: profile ACL,不强制权限位」,并写明 profile 里的 `poolStorage` 要重新挂载插件才生效。
|
|
36
|
+
- **审计修复(同一批)**:① **读失败不再等于空池**:`AccountPoolCore` 以前把 `store.load()` 的任何错误都吞掉、退回单凭据投影,接着第一笔写(切轮换策略、加账号、刷新回写)就把一份空文档存回去——一次 `secret-tool`/`powershell` 抽风就抹掉全部账号,用户只看到「读取失败」。现在只对**解析失败**(`CorruptStoredDocumentError`:JSON 坏了、字段不合法、不是 grant 记录)做兼容恢复;运行期读失败(keyring 解析时还应答、读的时候不应答)一律抛出,状态接口把它报成 `poolStorage.unavailable: 'store-unreadable'`,不再伪装成「没有账号」;而解析时就被判定**不可用**的存储保留既有读语义(线路照旧投影环境变量 Key / 单凭据镜像——线上服务器靠它才不至于整条线路不可用),但**写一律拒绝**:`saveVerified` 改成**先读再写**,读不通就不写,所以任何一份用失败读出的草稿都不会覆盖活文档。② **读缓存加代号(generation)**:`invalidate()` 之后才结束的旧读取不再写回快照,原先在 15 秒 keyring 桶内能把刚消耗掉的 refresh token 再喂回去一次(就是 single-flight 想避免的二次花费),现在下一次 `load()` 必然重新读盘。③ Secret Service 条目的 `--label` 改为按条目自己的 service 生成(`DSH <service>`),不再所有线路都挂「DSH Antigravity OAuth」——在 seahorse/密码本里能看出这是哪个 secret(label 只是显示,旧条目照常可读)。④ 旧的无前缀记录 key 的迁移:DSH 凭据 provider 在 key 非法时根本起不来,插件内部无从迁移,README 给出一次性 `sed` 改名步骤(没有任何发布版本写过旧形态)。
|
|
37
|
+
- **验证(rebase 到 0.37.0 之后重跑)**:`npm run typecheck` 三工程 0 错误;定向 `npx vitest run test/pool-storage.test.ts test/antigravity-proxy.test.ts test/credential-read-cache.test.ts test/oauth-service.test.ts test/routes.test.ts test/credential-store-secret-service.test.ts test/russian-locale.test.tsx` 123 例全绿;全量 `npm test`(`LANG=C.UTF-8`)280 文件:**4619 passed / 16 skipped / 0 failed**;同一份套件在干净 `upstream/master`(`bade32e`,独立 worktree)上是 **4581 passed / 16 skipped / 0 failed**(本轮另有一条 `command-code-oauth` 的 `ECONNRESET` 抖动,单跑 13/13 通过),差额 38 例就是本改动新增的测试。本机 `ru_RU` 下不设 `LANG=C.UTF-8` 会有约 7 例 `Intl` 格式断言台账式失败,纯属环境;`npm run build` 通过。
|
|
38
|
+
- **关联 issue**:`Refs #70` —— 存储口径的统一(全插件共用 DSH 凭据库,或把开关提升到 Subscriptions 页并让所有线路都支持两种存储)是那份 issue 在谈的事;这个 PR 只是 ChatGPT 一条线路的临时解法,不是最终形态。
|
|
39
|
+
- **[qoder] 修掉 PAT 兑换永远 400 `BadRequest`:区域选错时自动改试另一区,并让 `machine_id` 按官方 CLI 的形状发出去**
|
|
40
|
+
- **现象**:设置卡片里粘贴 PAT 点「粘贴并登录」,只得到一句 `Qoder(订阅) PAT 兑换失败(HTTP 400):{"errorCode":"BadRequest","errorMessage":"Bad request","requestId":"…"}`。上游没有说任何一句可行动的话,用户只能反复重新生成 PAT。
|
|
41
|
+
- **根因一(区域)**:区域是凭据的属性,`pt-` 串本身不自述区域,而卡片上的区域选择器默认停在全球区。中国站的 PAT 拿到 `openapi.qoder.sh` 兑换,上游回的就是这个不带 `rawMessage` 的 400——它已经读完了 `personal_token`(缺字段、字段名拼错、空体同样是 400,但那种响应带 `rawMessage`),只是不认这把 token。原来的实现**只试用户点的那个区**,于是「选错一次」等于「永久失败」。
|
|
42
|
+
- **根因二(请求体形状)**:请求体只发 `personal_token`,而官方 CLI 1.1.74 的 `getMachineIdentityRequestFields` 会给 exchange/refresh 一并带上既有 `machine_id`(qodercli2api `docs/oauth.md` §3;同一节明确「没有真实 UMID 时省略 `machine_token`,不用 `machine_id` 冒充它」)。实测两种形状对同一把 token 的回答相同,所以这不是这次 400 的直接原因,但没有理由继续少发一个官方字段。
|
|
43
|
+
- **改法(区域自愈)**:`qoderCredentialsFromPat` 把首选区域排在候选表首位、另一区紧随其后,仅在**明确的 token 被拒状态**(400 / 401 / 403 / 404,见 `qoderPatRejectionStatus`)下换区重试;429 / 5xx / 网络错误一律如实上抛——那些是瞬时故障,换区只会把一次可重试的问题变成两次打上游。命中的区域写进凭据,`region` 因此反映**真正认账的那一区**而不是用户点的那个。
|
|
44
|
+
- **改法(刷新同步自愈)**:`refreshQoderCredential` 的 PAT 分支走同一个函数,所以落盘里区域记错的旧账号会在下一次刷新时自己搬到正确区域——只修首次登录的话,那些账号会一直刷不上。
|
|
45
|
+
- **改法(可行动的错误)**:兑换失败不再只回上游 JSON。两个区都拒时文案先给下一步(「最可能已撤销或过期,请到 Integrations 页重新生成」)再附技术详情;`pt-` 前缀的形状检查提前到发请求之前,粘贴时带上引号或多余空白会在本地就被点出来,不必等一次往返。
|
|
46
|
+
- **改法(凭据分类)**:`qoderRefreshFailureStatus` 认识 `QoderPatExchangeError` 的被拒状态,PAT 来源的 400 现在也归为 `'expired'`(这个账号需要重新登录),而不是当成瞬时故障一直重试。
|
|
47
|
+
- **改法(文案)**:设置卡片的区域说明(zh / en / ru 三语)补一句「粘贴 PAT 时不用纠结区域,会自动改试另一区,落盘的是真正认这把 PAT 的那一区」——否则用户看到账号行显示中国站而选择器停在全球区,会以为记错了。
|
|
48
|
+
- **验证**:`npx tsc -b` 与 `npx tsc -p test/tsconfig.json` 均 0 错误;`test/qoder-oauth.test.ts` 新增 4 例(首选区被拒 → 改试另一区且凭据记的是认账那一区、两区都拒 → 文案含「重新生成」并保留上游详情、429 不触发换区且只打一次上游、非 `pt-` 前缀在发请求前被拒),原有 PAT 用例的请求体断言改为 `personal_token` + `machine_id` 形状;全量 `npx vitest run` **282 文件通过 / 2 skipped,4655 passed / 8 skipped / 0 failed**;`npm run build` 通过。
|
|
49
|
+
- **真实上游探测(本次修法的判据,可复现)**:`{"personal_token":…,"machine_id":…}` 与只发 `{"personal_token":…}` 对同一把 token 在两个区都返回 `HTTP 400` 且响应**不含** `rawMessage`;而 `{}`、`{"token":…}`、`{"personal_token":…}` 之外的字段名、以及 form 编码的请求**都带** `rawMessage`。这条差异证明服务端是「读完 `personal_token` 之后拒绝这把 token」,而不是「不认识这个请求形状」——所以修法针对的是 token 与区域的归属,不是编码。
|
|
50
|
+
- **未验证的边界**:真实账号的兑换成功路径仍未联调(本仓库测试全部走 mock,探测用的是合成 token);用户需要用自己的 PAT 实测一次。若换了两个区仍是同样的 400,那这把 PAT 本身已失效或生成在了第三个部署上。
|
|
51
|
+
|
|
52
|
+
- **[cline-pass] 上游钉选可读性大修:流式帧终于能读出真实服务渠道,匿名贡献者路由全链路标记**
|
|
53
|
+
- **现象**:钉选 deepseek「好像失效」——本机实测(2026-10-23,两个账号):`cline-pass/deepseek-v4.1-flash-1017` 被网关改指 VMC 匿名贡献者路由,`only: [deepseek]` 被静默忽略(连假渠道也返回 200);而同一时刻 `cline-pass/deepseek-v4-pro` 的 `only: [deepseek]` 被采纳(`Provider set restricted to: deepseek`)。网关按**模型 id** 分流且随时间翻转,插件无法左右;但插件侧有两个真实缺陷把「失效」放大了。
|
|
54
|
+
- **缺陷一:流式下钉选判定永远 `unresolved`**。网关把路由块放在**流式收尾帧**的 `choices[].delta.provider_metadata.gateway.routing`(内容之后、`[DONE]` 之前),而 `parseRouting` 只读 `message.provider_metadata`——本机 history 里 19 条真实流式记录全部 `unresolved`,`provider` 字段只是钉选回显。改法:同时读 `delta` / `message` / 顶层,并对整块做**深度受限递归搜捕**(对齐 MIT 参考插件 `dsh-clinepass-deepseek` 的 `collectRouting` 行为);首个非空读取生效。
|
|
55
|
+
- **缺陷二:匿名路由无任何标记**。`openai-compatible-private`(VMC 贡献者回退网,回答可能用于训练、无 ZDR)此前被当成普通渠道芯片,用户甚至把它存成了钉选。改法:
|
|
56
|
+
- 新增共享判定 `isClinePassAnonymousUpstream()`(渠道名 + `private/…-contributor` 解析 slug);
|
|
57
|
+
- `pinWarnings` 新增两条:钉选**指向**匿名路由(`anonymousUpstream:`)、模型**只发现**匿名路由却钉了别的(`pinLikelyIgnored:`,即「钉了也会被静默忽略」);
|
|
58
|
+
- 渠道芯片带 `⚠` 与警示色、tooltip 说明;钉选区在「钉了匿名路由」或「该模型只剩匿名路由」时给出警告行;
|
|
59
|
+
- 请求历史与 probe/test 结果新增 `fingerprint` / `anonymous` 字段,strict 未采纳或落在匿名路由时写入 `pinNotAdopted:` / `anonymousServed:` 警告。
|
|
60
|
+
- **第一方指纹**:`RoutingFacts.fingerprint` 只认 `provider_metadata.deepseek.systemFingerprint`(顶层 `system_fingerprint` 是网关每请求现铸的,不算证据);适配器把最近一次指纹学到模型观察上,测试结果页直接展示。
|
|
61
|
+
- **模型目录**:`cline-pass/deepseek-v4.1-flash-1017` 快照 id 进入内置目录(921600 / 384000,数值转录自参考插件的实测卡片),不再只依赖实时扫描领养——网关对别名与快照的钉选行为不同,用户必须能选到那个刚被探针证明可钉的 id。
|
|
62
|
+
- **手动渠道钉选入口**:探测依赖网关在被不可能的 `only` 钉住时报错列出渠道;当模型被改指匿名路由时探测拿不到任何列表(实测 1017 只剩 `openai-compatible-private` 一枚芯片),此前 UI 上连「钉 deepseek 试试」都做不到。渠道名是**网关级词汇**(任何模型探测到的名字都是合法候选),钉选面板新增手动输入框(联想全模型已发现渠道),输入即可钉、可存、可用「测试」回读验证——这正是参考插件的做法:从不探测渠道列表,按名字钉、按指纹验。
|
|
63
|
+
- **不做的**:不在流中段按路由帧掐断响应(路由帧在内容之后才到,掐不断已交付内容),与参考插件「观察并如实报告、不改写请求」的立场一致。
|
|
64
|
+
- **测试**:`cline-pass-protocol.test.ts` +4 例(delta 帧读取、递归搜捕、指纹/匿名判定、两条新警告)、`cline-pass-adapter.test.ts` +2 例(采纳 + 指纹落库;匿名路由未采纳 + 警告 + 不误标渠道可用)、`cline-pass-routes.test.ts` +1 例(钉匿名路由返回警告)、`cline-pass-section.test.tsx` +1 例(芯片 ⚠ 标记与警告行)。
|
|
65
|
+
|
|
66
|
+
- **[cline-pass] `only` 之外补上模型能力过滤 `has`:1017 的钉选与渠道探测恢复**
|
|
67
|
+
- **实测结论(本机真实账号,2026-10-24)**:同一个 `cline-pass/deepseek-v4.1-flash-1017`、同一把账号、交替对照两遍:只发 `providerOptions.gateway.only:[deepseek]` 都落 `openai-compatible-private` 且无第一方指纹;追加 `has:[vision,implicit-caching]` 后都落 **`deepseek`**,`canonicalSlug=deepseek/deepseek-v4.1-flash-1017`,并带 `provider_metadata.deepseek.systemFingerprint`。假渠道加 `has` 会正确报错并列出可用渠道,不再被静默兜到匿名路由。
|
|
68
|
+
- **请求链路**:`ClinePassPinSettings` / `PinConfig` / `PinAttempt` 新增 `has`;`injectPrefs` 只把它写进 **Vercel 的 `providerOptions.gateway.has`**,不污染 OpenRouter 的 `provider` 字段。真实流式请求、非流式 Test、逐渠道 Validate、Probe 的 `__probe__` harvest 全部使用同一份过滤配置。
|
|
69
|
+
- **旧设置无缝继承**:1017 在内置目录声明 `gatewayHas:[vision,implicit-caching]`;读取缺少 `has` 的旧钉选时自动补该默认值,**显式保存的空数组仍表示用户主动清空**,其他模型默认完全不变。
|
|
70
|
+
- **可配置**:设置卡的钉选面板新增「能力过滤 (has)」输入框(逗号/空格分隔),保存与临时 Test 都可覆盖;HTTP `/models/pin`、`/models/test` 和 `cline_pass_pin` / `cline_pass_test` 管理工具同步支持;Test 结果回显实际发送的过滤。
|
|
71
|
+
- **集成实测**:用新引擎读取现有旧设置,Probe 从「只有匿名路由」恢复为发现 **18 个渠道**(含 deepseek/fireworks/baseten 等);Test 返回 `actual=deepseek`、`adherence=adopted`、`anonymous=false`、第一方指纹。
|
|
72
|
+
- **测试**:新增 `test/cline-pass-has.test.ts` 5 例(只写 Vercel 字段、无钉选也可过滤、其他模型不受影响、旧设置继承/显式清空、默认值按模型隔离);适配器新增真实 body 断言;路由新增持久化断言;设置卡新增 has 编辑/保存用例。另保留 `scripts/probe-cline-pass-has.probe.ts` 作为可重复的本机对照探针(不打印凭据)。
|
|
73
|
+
|
|
74
|
+
- **[cline-pass] 模型清单只保留内置 + 官方订阅 + 手动添加,完整网关目录改为搜索数据源**
|
|
75
|
+
- **原因**:此前 `catalog/refresh` 在 `exposeCatalog=true` 时把整个网关目录合并进 `catalogModels`,设置页和模型选择器因此铺开几百个模型。当前本机旧设置实测有 **492 条目录行**。
|
|
76
|
+
- **展示与选择器同步收敛**:`catalogModels` 新增 `origin: official | custom | gateway`;旧行没有 origin 时仅 `cline-pass/*` 视为官方订阅,其他旧网关行默认收起。`listedClinePassCatalogModels()` 统一应用到设置页、adapter 的模型广告、hub 与可见性工具;旧 `exposeCatalog` 即使仍为 true 也不再展开全量目录。
|
|
77
|
+
- **不删配置**:旧的目录行、启用列表、隐藏列表、钉选和上下文覆盖都保留,只是不再展示;本次实算 492 行中 472 行收起、20 行保留,另有随包内置表。
|
|
78
|
+
- **刷新只合并官方订阅**:`catalog/refresh` 和管理工具的 refresh 仍拉取完整网关目录,但只写入 `store.catalog()` 作为搜索索引;只有 `recommended-models` / models.dev 的订阅模型进入 `catalogModels` 并标记 `origin: official`。
|
|
79
|
+
- **按需搜索添加**:新增 `GET /cline-pass/api/catalog/search?q=...`(空查询不返回全量,最多 30 条)和 `POST /catalog/add`。添加时写入 `origin: custom`,从隐藏列表移除,并在显式启用列表存在时自动加入启用列表;设置页新增搜索框和紧凑结果行。
|
|
80
|
+
- **兼容清理**:高级设置里移除已经无意义的「展示完整网关目录」开关;配置字段保留以读取旧文件,但不再影响清单。
|
|
81
|
+
- **测试**:路由新增「全量目录不进入清单 + 搜索/添加 + 自动启用」用例;设置卡新增搜索添加用例;高级设置行数断言同步更新。全量 283 文件、4664 通过、0 失败。
|
|
82
|
+
|
|
83
|
+
- **[cline-pass] 按官方网关校正 `deepseek-v4.1-flash-1017` 的显示名和上下文,不改模型 id**
|
|
84
|
+
- **官方核对**:`recommended-models` 同时包含 `cline-pass/deepseek-v4.1-flash-1017` 和稳定别名;网关模型目录包含 `deepseek/deepseek-v4.1-flash-1017`;真实请求返回 `canonicalSlug=deepseek/deepseek-v4.1-flash-1017`,且在 `only + has` 下 `actual=deepseek`、`adherence=adopted`、有第一方指纹。说明 1017 是有效快照 id,不是探测误写。
|
|
85
|
+
- **真正写错的是内置元数据**:上一版从参考插件转录了 `DeepSeek V4.1 Flash (1017)` / 921600,而当前 Vercel 网关目录公布的是 **`DeepSeek V4.1 Flash 1017` / 1048576**。由于 `resolveModelInfo` 的内置表优先于同步目录,旧内置值覆盖了已经同步到本地的官方 1048576。
|
|
86
|
+
- **修正**:内置显示名去掉括号,`contextWindow` 改为 1048576;模型 id 保持 `cline-pass/deepseek-v4.1-flash-1017` 不变,现有钉选与启用列表无需迁移。`maxTokens` 继续沿用线路既有的 384000 输出预算上限,不把 Vercel 的 `max_tokens` 直接等同于订阅输出上限。
|
|
87
|
+
- **测试**:`cline-pass-plugin.test.ts` 新增 1017 官方显示名和上下文断言,防止内置表再次覆盖错官方值。
|
|
88
|
+
|
|
89
|
+
- **[cline-pass] 区分订阅模型与 marketplace 模型的计费,避免误扣 credits**
|
|
90
|
+
- **背景**:`catalog/search` 会把整个网关目录(含 `deepseek/…` 这类 marketplace id)当作普通候选;添加后立即启用,而这类 id 按 **Cline Credits** 计费、不占订阅额度,余额不足时上游返回 402。本机实测:添加 `deepseek/deepseek-v4.1-flash-1017` 后余额被扣到 **-$0.04**,同一账号的订阅模型不受影响。
|
|
91
|
+
- **契约**:`ClinePassCatalogSearchItemDto` 新增 `billing: 'subscription' | 'credits'`(`cline-pass/*` 为订阅,其余为 credits);新增 `ClinePassCatalogAddResultDto`。
|
|
92
|
+
- **服务端**:`POST /catalog/add` 对 credits 模型返回 **409 `credits_billing`**,必须带 `acknowledgeBilling: true` 才写入,返回体带 `billing`。
|
|
93
|
+
- **客户端**:搜索结果逐条显示计费标签;credits 模型第一次点击只展开警告,第二次才提交;`catalogSearchHint` 说明两种计费。
|
|
94
|
+
- **附带**:添加自定义模型时从已扫描目录复制 `name` / `contextWindow` / `maxTokens` / `input` / `efforts`,不再只写 id。
|
|
95
|
+
- **[cline-pass] 升级不再丢掉用户已启用的网关模型**
|
|
96
|
+
- 旧目录行没有 `origin`;原先一律按 gateway 收起,已在 `enabledModelIds`、`pins` 或 `contextWindowOverrides` 中的模型会从选择器消失。
|
|
97
|
+
- 读取设置时把这些行提升为 `origin: 'custom'`,其余仍作为隐藏搜索索引保留。
|
|
98
|
+
- **`enabledModelIds` 为 `null`(「不过滤」,即全部已启用)时同样全部视为在用**:这正是本次迁移最主要的那批人——`exposeCatalog` 打开过、但从没动过勾选清单的用户。按空选择处理等于把他们的所有网关行继续收起,与上面这条承诺相反。显式空数组仍是「全部关掉」,不会被读成「不过滤」。
|
|
99
|
+
- **[cline-pass] 合并后按审查修掉的四处真实缺陷**
|
|
100
|
+
- **添加的网关模型拿不到真实容量**:`catalog/add` 只从官方订阅扫描里复制元数据,而 marketplace id 只存在于网关目录,于是落到 128k 默认值——对一个 1M 模型低估 8 倍,宿主的补全预留与压缩点跟着全错。网关目录现在连元数据一起返回并写进 `store.catalog().models`(官方扫描同名时以官方为准);有测试钉住「不先刷新、直接搜索并添加」这条真实路径。
|
|
101
|
+
- **旧宿主配新客户端包会让整张设置卡崩掉**:`has` 是新加的必填 DTO 字段,浏览器按需加载客户端资源、宿主只在启动时加载,于是新包会碰到没有该字段的宿主;直接展开 `undefined` 会在渲染期抛错并卸载整个设置页。三处读取都改成缺省为空列表。
|
|
102
|
+
- **状态轮询会清掉半途输入的 `has`**:`projectModels` 每次都给新数组,按数组身份重设输入框等于每 60 秒把 `vision, ` 改回 `vision`。改为按值重设,并加测试钉住「保存钉选(无关动作)之后半途输入仍在」。
|
|
103
|
+
- **`has` 没有长度上限**:它会被复制进每个请求体,与已经受限的 `upstreams` 不同,原实现接受任意长度。新增 `MAX_GATEWAY_HAS`(16 条)与 `MAX_GATEWAY_HAS_LENGTH`(64 字符),读取与上线两处各夹一次。
|
|
104
|
+
- 另修:`cline_pass_status` 的 `catalogCount` 报的是搜索索引规模(本机 492)而不是可选模型数,与 HTTP 状态接口口径不一,现两者一致。
|
|
105
|
+
- **[cline-pass] 其他修复**
|
|
106
|
+
- Probe 的 `__probe__` 被网关忽略并返回 200 时,从响应 routing 学习实际渠道,而不是报告「没有渠道」。
|
|
107
|
+
- routing / fingerprint 的递归搜捕增加节点预算(4000),异常 payload 不再是无界遍历。
|
|
108
|
+
- 钉选失败且带能力过滤时,错误信息指出 `has` 并提示清空以放宽路由。
|
|
109
|
+
- 移除已失效的 `exposeCatalog` 客户端字段、locale 文案与 status DTO 字段(配置文件字段仍读取以兼容旧版本)。
|
|
110
|
+
- 补充 catalog 迁移、计费确认与搜索/添加测试。
|
|
111
|
+
- **[claude] 按官方文档修正 Opus 5 关闭思考和 Sonnet 4.5 标准上下文窗口**
|
|
112
|
+
- **Opus 5**:官方 thinking 故障表允许 `high` 及更低档位发送 `thinking: { type: 'disabled' }`。目录中的 `canDisableThinking` 改为 `true`,`mid-convo` 分支在该请求下返回不带 effort 的 `disabled`,并不再抬高 `max_tokens`;其它 `mid-convo` 模型仍保持 adaptive 与 block binding。同步移除 `pi-ai@1.3.0` 已失效的 Haiku 5.5 测试例外,Claude 相关 **144/144** 用例通过。
|
|
113
|
+
- **Sonnet 4.5**:官方上下文表给出的标准窗口为 **200K**,1M 属于另一项 beta 能力,而本适配器没有请求该能力。`claude-sonnet-4-5` 与 `claude-sonnet-4-5-20250929` 的默认窗口均由 1M 改为 **200K**,保留用户显式覆盖通道。
|
|
114
|
+
- **验证**:字段级参考比较全部一致,全量 **282 文件通过 / 2 skipped,4651 passed / 8 skipped / 0 failed**;三工程强制类型检查、构建、`npm ci --dry-run` 与打包通过。
|
|
115
|
+
- **[agent-preset] 修复 DSH 0.2.1-rc.3 下 dispatch 新建会话报 `tool-subagent-list-agents: never started`**
|
|
116
|
+
- **根因**:Harness 提交 `4df09d37d5` 删除 `@deepseek-ai/dsh-tool-subagent-control/list-agents` 导出,改由主入口统一注册 `list_agents`;本插件的 `dispatch` 仍保留旧的独立行,预设挂载因此失败,创建会话时报 `agent-preset/invalid`。
|
|
117
|
+
- **改法**:`resolveDispatchPreset` 按实际导出是否存在决定行集合——旧导出存在时原样保留,缺失时删除 `tool-subagent-list-agents`,主控制行和其它委派工具不变;`packageInstalled` 的回退探测同步改为检查精确的 `exports` 子路径,避免把“包存在”误判成“旧导出存在”。旧世代行为不变。
|
|
118
|
+
- **验证**:新增 2 个回归用例,均在修复前失败、修复后通过;预设相关 **69/69** 通过,三工程强制类型检查和构建通过。真实本地 `0.2.1-rc.3-22ddee3` 下新建 `dispatch` 会话成功,未再出现 `agent-preset/invalid` 或 `never started`。最终全量套件为 **4651 passed / 8 skipped / 0 failed**。
|
|
119
|
+
- **[harness] 新增 DSH 0.2.1-rc.3 支持,并补齐旧世代的客户端类型兼容**
|
|
120
|
+
- **基线**:18 个直接 DSH `devDependencies` 提升到 `^0.2.1-rc.3`,对应 peer 联合范围追加同项,npm 与 pnpm 锁文件同步更新;0.1.2-alpha.5 以来的旧范围全部保留。`rc.3` 对插件导入面的变化集中在 Conversation View 与右侧指南卡片的固定 / More 菜单,以及草稿初始化的追加模式;现有插槽、`setDraft`、LLM / 工具 / 设置 / WebServer 等接口无破坏变化,因此不新增版本分支,也不改变任何供应线路的请求行为。
|
|
121
|
+
- **旧世代类型桥**:`src/index.ts` 用本地结构类型表示 volatile 配置,避免直接依赖 Cordis 4.0.2 尚未导出的 `Volatile`;`minimax-code/commands-contract.ts` 在既有命令类型边界补充 `label` / `icon` / `SelectOptionGroup` 的兼容形状;进展更新设置改用本地 `ConfigForm` / `ConfigFormSnapshot` 结构类型,旧版没有 `configForms` 服务时仍按原逻辑降级,新版仍使用真实服务。以上均为类型适配,无运行时协议变化。
|
|
122
|
+
- **验证**:`rc.3` 三工程强制类型检查、构建、`npm ci --dry-run` 与打包通过,全量 **282 文件通过 / 2 skipped,4649 passed / 8 skipped / 0 failed**;精确 `rc.2` 隔离房间结果完全相同。`0.1.5-rc.1` 隔离房间强制类型检查通过,其余可运行套件 **281 文件通过 / 2 skipped,4644 passed / 9 skipped / 0 failed**;唯一不能加载的是该世代没有 `@deepseek-ai/dsh-ptc-runtime` 的 `subagent-model-authorization-ptc.test.ts`,与既有世代限定约定一致。
|
|
123
|
+
- **实机**:用 npm 发布的 `@deepseek-ai/dsh@0.2.1-rc.3` 在隔离 `DSH_HOME` 安装本次 tarball,启动无条目激活警告;插件管理页显示 1 个组件运行中,设置页确认版本为 `0.2.1-rc.3`,12 条订阅线路与进展更新设置均正常渲染。未使用真实订阅凭据或发起模型请求。
|
|
124
|
+
|
|
125
|
+
## 0.38.1 - 2026-10-24
|
|
126
|
+
- **[kimi-code] 请求体上限改成按模型分档:1M 档 8 MiB、256K 档 2 MiB(`DSH_KIMI_CODE_MAX_BODY_BYTES` 仍是全局强制覆盖)**
|
|
127
|
+
- **现象**:1M 上下文档位(`k3` / `k3.1-pro` / `k3.1-pro-highspeed` / `kimi-for-coding`)的会话把中文正文写到 3–4 MB 就被本线路的本地字节守卫拒绝,请求根本没发出去;宿主压缩也救不回来——压缩请求自己同样超过那个上限,于是长会话表现为「压缩一次后仍然失败」,而服务端从未拒绝过这个体积。
|
|
128
|
+
- **根因**:这条线路对**所有**模型套用同一个 `MAX_MESSAGE_BODY_BYTES`(2,097,152)。该数字来自官方错误参考里的通用示例(`total message size N exceeds limit 2097152`),**从未针对 1M 上下文档位实测**;而 1M 窗口的正文按英文约 4 MB、按密集中文约 4.5 MB,2 MB 必然先到。官方 `kimi-cli` 全仓库没有字节守卫,说明这个上限至少不是客户端必需的。
|
|
129
|
+
- **改法(分档)**:`model-catalog.ts` 的 `KimiCodeCatalogModel` 新增必填字段 `maxRequestBodyBytes`:`k3` / `k3.1-pro` / `k3.1-pro-highspeed` / `kimi-for-coding` = **8 MiB(8,388,608)**,`k3-256k` / `kimi-for-coding-highspeed` = **2 MiB(2,097,152,保持原值)**。8 MiB 的依据是「1M 窗口的正文大小」:一个 1M token 的请求体按英文约 4 MB、按密集中文约 4.5 MB,8 MiB 留出近一倍余量,所以**字节上限不会成为 1M 会话的实际瓶颈**;真正先到的是模型自身的 token 窗口——服务端回 `Your request exceeded model token limit`,该措辞已被 `common/context-overflow.ts` 归一到 `CONTEXT_WINDOW_EXCEEDED`,压缩与重试照旧生效。8 MiB 仍是**待实测的上界**,不是文档写明的网关上限。
|
|
130
|
+
- **改法(代码)**:`types.ts` 新增 `LONG_CONTEXT_MESSAGE_BODY_BYTES`(8 × 1024 × 1024,常量定义在 `model-catalog.ts`、由 `types.ts` 重新导出,避免 ESM 循环)与 `maxRequestBodyBytesFor(model, env)`,优先级为 **env → `model.maxRequestBodyBytes` → `DEFAULT_MAX_MESSAGE_BODY_BYTES`**(注册表不认识的 id 走最保守的 2 MiB);`maxMessageBodyBytes(env)` 与其语义**原样保留**(无模型上下文的调用方仍拿 2 MiB)。`mapper.ts` 的 `assertRequestBodyFits(body, carriesVideo = false, context?, limit?)` 新增可选 `limit`,拒绝文案引用生效上限,不传时逐字节等于旧行为。`adapter.ts` 的 `bodyLimit` 改为 `carriesVideo ? MAX_VIDEO_MESSAGE_BODY_BYTES : maxRequestBodyBytesFor(<该模型的注册表行>, process.env)`,并把这个 `bodyLimit` **显式传给两处** `assertRequestBodyFits`——此前这两处各自又算一遍上限,模型档位根本到不了守卫。注册表行按 id 从 `model-catalog.ts` 取,而不是直接用线上 `/v1/models` 的条目:线上目录只报能力、从不报字节额度。
|
|
131
|
+
- **改法(env)**:`DSH_KIMI_CODE_MAX_BODY_BYTES` 仍是**全局强制覆盖、优先级最高**;空串、非有限、`0`、负数一律回落到**该模型的默认值**而不是关闭守卫(合法值会 floor,前后空格容忍)。视频档 `MAX_VIDEO_MESSAGE_BODY_BYTES`(64 MiB)不受影响。
|
|
132
|
+
- **测试**:新增 `test/kimi-code-body-limit-per-model.test.ts`(16 例)——六个条目的 `maxRequestBodyBytes` 逐一切值(8 MiB ×4 / 2 MiB ×2)、8 MiB 对两种 1M 正文密度都留有余量、resolver 的三级优先级(env 双向覆盖、模型行、未知 id 回落 2 MiB、小数 floor、空白容忍)、非法值(`''`、纯空白、`abc`、`0`、`-1`、`-2097152`、`NaN`、`huge`)回落到模型默认值而不关守卫、端到端 3.5 MB 在 `k3.1-pro` 上**能发出**(fetch 调用 1 次)而在 `k3-256k` 上被拒(fetch 0 次、文案含 `2097152`、码为 `CONTEXT_WINDOW_EXCEEDED`)、4.5 MB 能发、8.5 MB 被拒且文案含 `8388608`、env 强制把 1M 档按回 2 MiB、env 拼错仍拒、13 MB 视频照旧走 64 MiB 档、以及 `assertRequestBodyFits(body)` 无参调用仍按 2 MiB 抛错。另修正两处**依赖旧的全局 2 MB**的既有用例(**没有删任何断言**):`kimi-code-capacity.test.ts` 的「2.1 MB 请求本地即拒」与 `kimi-code-adapter.test.ts` 的「不做没做过的省略」改跑 `k3-256k`——那两处的体积仍在该档 2 MB 之上,测的行为(本地拒绝、码、文案、fetch 零调用)一条未减。
|
|
133
|
+
- **验证**:`npm run typecheck` 三工程 0 错误(退出码 0);`npx vitest run test/kimi-code**` 34 文件 / 512 例全绿;全量 `npm test` 282 文件通过 / 2 skipped、4649 passed / 8 skipped / 0 failed;`npm run build` 通过。
|
|
134
|
+
- **文档**:README 的 Kimi Code 小节把「请求体超 2 MB 本地即拒绝」改写成「按模型分档:1M 档 8 MiB / 256K 档 2 MiB」,写明 8 MiB 是待实测上界与该口径的推导、env 仍为全局覆盖且非法值回落,「上下文窗口」段落与错误处理总表里的 2 MB 措辞同步更新,并注明 `DSH_KIMI_CODE_BYTES_PER_TOKEN` 的折算基准**刻意仍是不随模型变动的 2 MiB**。
|
|
135
|
+
- **已知边界**:`DSH_KIMI_CODE_BYTES_PER_TOKEN` 的窗口折算仍以那个与模型无关的 2 MiB(设了 env 则取 env)为基准,不跟随按模型档位——它是可选的提前压缩开关而不是守卫,本次刻意不动;不想提前压缩时不设该变量即可(默认就是不设)。
|
|
136
|
+
|
|
5
137
|
## 0.38.0 - 2026-10-24
|
|
6
138
|
- **[kimi-code] 新增 K3.1 Pro 系列(与其它模型同一 OpenAI 兼容 chat completions)、只支持思考的档位、以及缓存写入这个计费项**
|
|
7
139
|
- **现象**:`k3.1-pro` / `k3.1-pro-highspeed` 不在模型目录、设置卡与能力表里;「默认思考档位」永远列着 `low` / `high` / `max` 与「关闭思考」,而 K3.1 Pro 根本关不掉(服务端 400);缓存区块只有命中率、命中 / 新处理 / 输出 tokens 与请求数,**写入**这个独立计费项一个数字都没有,看不出 5m / 1h 两档各写了多少。
|
|
@@ -13,7 +145,16 @@
|
|
|
13
145
|
- **测试**:新增 `test/kimi-code-k31.test.ts`(17 例:两条条目的全部字段、thinking-only 语义、双值 wire 与视频按声明保留、卡片契约字段)、`test/kimi-code-k31-card-ui.test.tsx`(8 例)、`test/kimi-code-effort-ladder.test.ts`(6 例)与 `test/kimi-code-cache-write.test.ts`(9 例:chat wire 的 usage 三分解、Anthropic 不减、响应头分档、以及 thinking 闸门在 chat / Anthropic 两条 wire 上的行为);`test/kimi-code-capability-ui.test.tsx` 补「未公布倍率」与「只支持思考 + 400 脚注」两例。
|
|
14
146
|
- **验证**:`npm run typecheck` 三工程 0 错误;全量 `npm test` 281 文件通过 / 2 skipped,4633 passed / 8 skipped / 0 failed(删掉的用例全部只属于已撤除的 Responses 分支)。
|
|
15
147
|
- **文档**:README 的线路总览把 Kimi 的协议列改为「OpenAI 兼容 Chat Completions(可选 Anthropic Messages)」,模型目录由四款改为六款,补缓存写入那一行、倍率表里的两个「未公布」,并明确「本线路对全部模型使用 OpenAI 兼容 chat completions(与官方 agent 的 `type = "kimi"` 一致)」、视频清单加入 `k3.1-pro`,以及设置步骤里「默认思考档位跟随模型声明」。
|
|
16
|
-
|
|
148
|
+
- **[codex] 服务器上也能登录:设备码登录(设备授权流),不再需要 localhost 回调**
|
|
149
|
+
- **为什么**:浏览器登录把授权码重定向到**写死的** `http://localhost:1455/auth/callback`(这是 OpenAI OAuth 客户端注册的一部分,改不了)。在服务器/无头主机上没有人监听这个端口;而 HTTPS 页面连 `http://localhost` 本身就被混合内容策略挡掉。所以这条线路在服务器上唯一能走完的是设备码授权——和 Codex CLI 用的是同一个授权。
|
|
150
|
+
- **协议(对着 auth.openai.com 实测)**:`POST /api/accounts/deviceauth/usercode`(JSON `{client_id}`)拿 `{device_auth_id, user_code, interval, expires_at}`(`interval` 是**字符串** `"5"`,`expires_at` 是 ISO);用户在 `https://auth.openai.com/codex/device` 输入代码后轮询 `POST /api/accounts/deviceauth/token`(`{device_auth_id, user_code}`)——`403`/`404`(以及 `200`/`400` 的 body 里 status 说 pending)表示“还没确认”,`200` 给 `{authorization_code, code_verifier}`;其余状态码一律按失败处理,body 长得像 pending 不再压过 `401`/`429`/`500`(否则一个无效 user code 会被重试到 deadline,把错误藏 15 分钟,而不是立刻报出来);最后在普通令牌端点用 `grant_type=authorization_code` + `code_verifier` + `redirect_uri=https://auth.openai.com/deviceauth/callback` 换令牌。换回来的凭据形状与回调流一致,因此**走原来的号池写入路径,一行没改**。
|
|
151
|
+
- **节拍与边界**:两次轮询之间按授权给的 `interval` 等待(首次轮询也先等一个间隔);单次等待不超过剩余时间;到 `expires_at` 就停,且**在/过后截止时刻到达的授权一律拒绝**(`login-expired`),因为上游过期的授权换出来的不是登录。`interval` 两头都夹:下界 1 秒,上界是授权剩余寿命(防止 `"3600"` 这种值睡过截止时刻)。下界只对**小数**有意义——`0`、负数与解析不出的值早在 `parseGrantInterval` 里换成了 5 秒默认值,所以常量注释与旧版本的 CHANGELOG 描述的那条「`"0"` 会被 1 秒兜住」的路径并不存在(行为一直是对的,错的是描述)。拿不到 `interval` 时用默认 5 秒,拿不到 `expires_at` 时用默认 15 分钟。`usercode` 与 `user_code` 两种拼写都接受。
|
|
152
|
+
- **失败与取消**:`403`/`404` 之外的非 2xx 是**终止**错误,消息里带状态码与上游的错误码,不会一直重试;200 但没有 `access_token` 的令牌响应直接判失败,绝不落库成账号。用户点取消即 abort 轮询与在途请求,号池里不会留下任何东西:**落库路径在写入前最后一刻再查一次取消**(`persistCredentials` 拿 signal),并在确认应答与兑换之间再查一次——否则取消正好落在「令牌 200 已在手、账号还没写」这个窗口里时,宿主已经答了 `{cancelled:true}`、也发布了 `cancelled`,号池却会悄悄多一个账号。
|
|
153
|
+
- **界面**:号池卡的登录行现在三个按钮,顺序不变地插在中间——`[Add account]`(原浏览器 OAuth,未改动)、`[Add account with device code]`(新增)、`[Import the local Codex CLI sign-in]`(原有,未改动)。点第三个打开面板:等宽字体的代码块、指向 `https://auth.openai.com/codex/device` 的链接、`等待确认… 剩余 14:32` 的倒计时(每秒走;剩余量按宿主给的 `expiresAt - now` 算,再用浏览器自己的流逝时间递减,所以远程宿主与本机时钟差几小时也不会画出错的倒计时)、以及 Cancel。代码与链接各带一个**同一个组件**画出来的图标复制按钮(同一个 class,因此尺寸一致,22×22,与文字基线对齐;同一个 tooltip「复制到剪贴板」):点一下复制对应的值(代码会把空白全部去掉,粘到上游页面才不会被拒),图标换成勾号 1.5 秒后复原;`navigator.clipboard` 不存在或被拒时静默退出,值仍在屏幕上,面板不会崩。成功即关闭面板并把新账号读回号池;确认失败时面板**保持打开**并把错误写在代码下面,用户仍看得见那段代码。
|
|
154
|
+
- **并发与关闭(评审后修正)**:登录槽位现在在**第一个 `await` 之前同步占住**(`startPending` 标志,两种流派共用 `beginStart()`):原先占位检查在 `await requestDeviceGrant()` 之前、赋值在之后,两次点击都能过检查,第二个覆盖第一个,**第一个流程的 `AbortController` 从此不可达**——Cancel 只 abort 第二个,第一个继续每 5 秒打 `/deviceauth/token` 直到授权寿命耗尽(约 15 分钟)。设备码按钮同时改成 `disabled={busy !== null}`(原先 `busy !== 'device-login'`,等于在它自己的请求在飞时可点)。终态失败后宿主已无活跃登录、卡片也清了 id,此时 Cancel 不再空转,而是当「关掉面板」用(`setDeviceLogin(null); setDeviceError(null)`),否则过期代码只能靠再开一次登录顶掉。
|
|
155
|
+
- **不写日志的字段**:`code_verifier`、`device_auth_id`、`user_code`、令牌值一律不进日志(本线路的 OAuth 日志根本没有 secret 名单表,所以这里只记「登录开始/完成」这类事实,不记可以兑换登录的东西)。共享给界面的 DTO 里也只带 `user_code`/页面/截止时刻/宿主当前时间(`now`)——`device_auth_id` 与 verifier 不离开宿主。轮询节拍(`interval`)不进 DTO:它由宿主自己用,客户端倒计时只吃 `expiresAt`/`now`,一个没人读的字段只是给下一个人留的误会。
|
|
156
|
+
- **测试**:`test/codex-device-login.test.ts` 16 例(假 fetch + 假时钟,无真实网络):usercode→pending→pending→grant→token→账号入池(含请求体、`redirect_uri`、`code_verifier` 逐字校验)、`usercode` 别名、pending 后终止错误(带状态码与错误码、且之后不再轮询)、截止时刻到点停止且不轮询、截止时刻之后到达的授权被拒、取消后不再轮询且不写账号、200 无 `access_token` 判失败且不落库、`interval` 缺失回落默认值、`interval` 下界 1 秒、`interval` 超过寿命被夹到剩余时间、并发登录被拒(两种流互相排他)、日志不含四个敏感值;评审后补的四条钉住原来的假绿:**取消能打断在飞请求**(fetch 永不自行 resolve、只听 `init.signal`,断言请求被 abort 且存储为空——旧的替身立刻 resolve 且不看 signal,删掉整个 `AbortController` 套件仍然全绿)、**真正并发 start**(两个 start 都不 await,只有一个拿到授权、只发一次 usercode)、**令牌 200 之后写入之前取消**(在 `json()` 里取消,断言号池里没有账号、宿主答的是 `cancelled`)、**overlapping start 时浏览器流也被拒**、**`401` 带 `status:"pending"` 的 body 立刻判失败**(只轮询一次、不兑换、错误码读的是 body 里那个 `invalid_grant` 而不是状态词)。`test/codex-device-ui.test.tsx` 14 例:面板画出代码/链接/倒计时并在 61 秒后减少一分钟、确认后关闭并重读状态、失败时面板保持打开且错误可见、面板内 Cancel 走一次共享的取消路由、宿主发不出代码时错误进卡片错误条;复制代码进剪贴板且去掉空白、复制链接进剪贴板、两个图标按钮的 class 与 tooltip 完全相同、复制后面板不关且不会二次请求代码、勾号 1.5 秒后复原(两个按钮互不干扰)、没有 `navigator.clipboard` 时静默不崩。另加三条:**终态失败后 Cancel 仍然有作用**(关掉面板,且不发取消请求——旧代码在这里 `return`,面板只能靠再开一次登录顶掉)、**设备码按钮在自己的请求在飞时不可点**(只发一次 start)、**宿主时钟偏一小时时倒计时仍然是 14:5x**。`test/codex-local-signin-ui.test.tsx` 跟着改成三按钮布局(顺序断言)。
|
|
157
|
+
- **验证(rebase 到 0.37.0 之后重跑)**:`npm run typecheck` 三工程 0 错误;全量 `npm test`(`LANG=C.UTF-8`)281 文件:4613 passed / 16 skipped / 0 failed;同一份套件在干净的 `upstream/master`(`bade32e`)上是 4581 passed / 16 skipped / 0 failed(本轮另有一条 `command-code-oauth` 的 `ECONNRESET` 抖动,单独跑 13/13 通过)——多出的 31 例就是本改动新增的测试。本机 `ru_RU` 会让 `Intl` 格式化成另一种写法、不做 `LANG=C.UTF-8` 时有约 6 例台账式失败,与环境有关、与本改动无关;`npm run build` 通过,`lib/client.js` 与 `lib/index.js` 均含设备码字符串与路由。
|
|
17
158
|
## 0.37.0 - 2026-10-23
|
|
18
159
|
- **[progress-updates] 进展更新补上「开局」与「收尾」两条硬要求**
|
|
19
160
|
- **现象**:任务开始和结束都没有进展条目,整场只在被催到的时候冒出两三条;面板看着像「只有出结论才有动静」。
|
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- [功能特性](#功能特性)
|
|
11
11
|
- [模型目录](#模型目录)
|
|
12
12
|
- [环境要求](#环境要求)
|
|
13
|
+
- [号池存储后端(`poolStorage`)](#号池存储后端poolstorage)
|
|
13
14
|
- [安装](#安装)
|
|
14
15
|
- [使用](#使用)
|
|
15
16
|
- [推理塌缩守卫(熔断,默认关闭)](#推理塌缩守卫熔断默认关闭)
|
|
@@ -129,15 +130,15 @@
|
|
|
129
130
|
- **K3.1 Pro 只支持思考模式**:关闭思考(`none`)会被服务端以 `400` 拒绝,所以它的档位只有 `low` / `high` / `max`、默认 `max`;「默认思考档位」下拉只列出勾选模型真正声明的档位,任一勾选模型允许关闭思考时它才出现,被拒时卡片上直接写明原因;
|
|
130
131
|
- **本线路对全部模型使用 OpenAI 兼容 chat completions**(与官方 agent 的 `type = "kimi"` 一致):K3.1 Pro 系列与其它模型同一协议、同一端点(`/v1/chat/completions`),Anthropic Messages 只在实时目录为某个 id 声明时启用;视频输入按官方型号表声明走,K3.1 Pro 系列可用;
|
|
131
132
|
- **K3 的长思考不会被截断**:输出上限跟随上下文窗口(保留 4096 余量),因为 `reasoning_content` 计入输出,固定 32K 会把 `max` 档的长推理中途截断并返回 `length`;调用方已知 prompt 规模时上限会被下调到放得下,未知时不做猜测;
|
|
132
|
-
-
|
|
133
|
+
- **请求体上限按模型分档:1M 档 8 MiB / 256K 档 2 MiB,本地即拒绝**:该端点最常见的 400 是 `total message size N exceeds limit 2097152`,但 `2,097,152` 来自官方文档的通用错误示例,**从未针对 1M 上下文档位实测**——1M 档的真实会话(中文正文 3–4 MB)会被本地守卫提前拦下,而宿主压缩也救不回来(压缩请求自己同样超限);官方 `kimi-cli` 全仓库没有字节守卫,说明这个上限至少不是客户端必需的。现在按模型档位:`k3` / `k3.1-pro` / `k3.1-pro-highspeed` / `kimi-for-coding` = **8 MiB(8,388,608,待实测的上界)**,`k3-256k` / `kimi-for-coding-highspeed` = **2 MiB(保持原值,窗口与上限本就对齐)**。8 MiB 的依据是「1M 窗口的正文大小」:一个 1M token 的请求体按英文约 4 MB、按密集中文约 4.5 MB,8 MiB 留出近一倍余量,所以**字节上限不会成为 1M 会话的实际瓶颈**;真正先到的是模型自身的 token 窗口——服务端回 `Your request exceeded model token limit`,该措辞已被 `common/context-overflow.ts` 归一到 `CONTEXT_WINDOW_EXCEEDED`,压缩与重试照旧生效。拦截仍按真实序列化体积,并按「循环实际做了什么」给出处方(有图可丢但丢了也补不上缺口 / 图已丢完仍超限 / 本来无图,三种情况文案不同,不再声称发生了没发生的省略);`DSH_KIMI_CODE_MAX_BODY_BYTES` 仍是**全局强制覆盖、优先级最高**,确有实测上限的部署(前置代理/网关)用它指定该档上限,取值非正整数时**回落到该模型的默认值而不是关闭守卫**;带视频的请求走 64 MiB 档,不受该变量影响;**超限时报的是可恢复的溢出码**(`CONTEXT_WINDOW_EXCEEDED`):DSH 会对该码强制压缩本轮历史并重试同一步,所以长会话的表现是「压缩一次后继续」,而不是整轮失败——官方 `kimi-cli` 从不特殊处理 `2097152`,它靠 85% 提前压缩避开,详见下文「上下文窗口」那条;
|
|
133
134
|
- **缓存是自动的,且无法手动干预**:
|
|
134
135
|
- Kimi 按请求内容哈希命中前缀缓存。实测 `prompt_cache_key` 与 Anthropic `cache_control` 标记**均被忽略**(设与不设、同 key 与异 key 命中的是同一缓存),设备 id 与协议切换也不影响;
|
|
135
|
-
- TTL
|
|
136
|
+
- TTL **实测**约 25–35 分钟,按 256 token 对齐;`/messages` 与 `/chat/completions` **共享同一缓存**。两份独立实测互相印证:一份给出 `[300s, 1800s)`(300s 命中、1800s 未命中),另一份按每个年龄 3 个副本、每条前缀只探一次的方法给出存活曲线 —— 5–25 分钟 3/3 命中、30 分钟 1/3、35 分钟 0/3。所以「30 分钟」是首个多数副本已失效的年龄;
|
|
136
137
|
- 真正决定命中率的是**内容稳定性**:同一会话内 `system` 或工具列表一旦变化会使整个前缀缓存失效(实测归零)。因此应保持工具集合稳定、把新增内容追加在末尾;
|
|
137
138
|
- 卡片会显示滚动命中率,方便验证效果;
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
- 设置卡的缓存区块把**写入**单独列成一行(总量 + 5 分钟档 + 1 小时档):写入是独立计费项,折进「新处理 tokens」会让命中率说错话;某个分档是 0 时照实显示 0
|
|
139
|
+
- **本线路不发送任何缓存时长字段**,缓存写入与存活完全由服务端决定。这不是省略,而是唯一有依据的选择:5m / 1h 两档只写在 **Moonshot 开放平台**文档里,Kimi Code 订阅端点没有任何缓存 TTL 的文档,官方 CLI 2.0.0 的代码路径里也不存在 `prompt_cache_options`(只有 `prompt_cache_key`);[MoonshotAI/kimi-code#3942](https://github.com/MoonshotAI/kimi-code/issues/3942) 专门请求暴露该档位并附带问了一句「如果 coding 端点不认这个字段,请明确写出来」,至今 open、零回应。此前设置页提供的 5m / 1h 选择因此已**撤除**;
|
|
140
|
+
- **缓存过期提示按 30 分钟判定**(`cache-hint.ts` 的 `CACHE_TTL_MS`)。此前该阈值取的是 `5m` 档位的**名字**(5 分钟),在实测能热 25 分钟的端点上,从第 6 分钟起就开始误报、误报窗口长达 19 分钟 —— 恰好违反本模块自己写下的「宁漏报不误报,误报会训练用户忽略提示」。现在取首个多数副本已失效的年龄,代价是真正过期后最长晚 5 分钟才提示;
|
|
141
|
+
- 设置卡的缓存区块把**写入**单独列成一行(总量 + 5 分钟档 + 1 小时档):写入是独立计费项,折进「新处理 tokens」会让命中率说错话;某个分档是 0 时照实显示 0——响应头缺失只表示服务端没回报该档,不等于那里确实没写。注意这两个分档响应头同样只有开放平台文档背书,订阅端点尚无实测样本,恒为 0 时不要读成「确实没写入」;
|
|
141
142
|
- **视频输入可用**(`k3`、`kimi-for-coding`、`k3.1-pro`):
|
|
142
143
|
- DSH 的模态词表只有 `text`/`image`,但它是可合并扩展的接口,本插件用 TypeScript 模块增强把它扩到 `video`(**未改动 DSH 任何代码**),因此视频走 DSH 真实的能力通道,而不是只能显示在提示里;
|
|
143
144
|
- 适配器把视频映射为服务文档的 `{type:'video_url',video_url:{url:'data:…'}}`。视频与图片**各有独立预算**(图片 1.5 MB、视频 48 MiB base64,最旧优先省略),请求体校验只在确实带视频时才放宽到 64 MiB;
|
|
@@ -295,6 +296,38 @@ GPT-6 系列(6.1 Sol / 6 Astra / 6 Sol / 6 Luna)支持文本、图片输入
|
|
|
295
296
|
- 0.1.1-rc.2 不再声明支持——它既没有 preset 用到的 `present` 工具,`mode` 枚举那时也还写作 `code`。
|
|
296
297
|
- Node.js 与 npm。
|
|
297
298
|
|
|
299
|
+
### 号池存储后端(`poolStorage`)
|
|
300
|
+
|
|
301
|
+
号池(每个供应线路的账号文档)存在哪里是**一项配置**,不再由平台写死。原先 Linux 上恒为 Secret Service(libsecret / `org.freedesktop.secrets`):桌面机没问题,**服务器上通常根本没有 secret service**,令牌换成功了、凭据却存不下来,登录报「ChatGPT credentials could not be saved securely」。唯一的老办法是装 `gnome-keyring` 并用空密码解锁去跑——那除了文件权限之外没有任何加密,还把一整套桌面栈拖上了服务器。
|
|
302
|
+
|
|
303
|
+
| 值 | 存储位置 | 静态加密 |
|
|
304
|
+
| --- | --- | --- |
|
|
305
|
+
| `keyring`(默认) | 桌面密钥环:Windows 上是 DPAPI,macOS 上是钥匙串,Linux 上是 Secret Service | 是 |
|
|
306
|
+
| `credentials` | **DSH 自己的凭据库**:`$DSH_HOME/.credentials.yaml`(由 DSH 的 `dsh-credentials-local` 提供;POSIX 上强制 `0600`,文件对他人可读时该 provider 拒绝启动;**Windows 上没有权限位可强制**,只有 profile ACL) | 否(权限保护) |
|
|
307
|
+
|
|
308
|
+
**没有自动模式**:一个会按「守护进程是否应答」自己挑存储的 `auto`,等于让同一个号池在两个存储之间漂移,而漂移看起来和「账号全没了」一模一样。选错了就**如实报错**——卡片写明当前实际使用的存储、为什么选中的那个不可用,并把切换开关放在同一处;留在另一个存储里的账号仍然在(切回去就能看到),**不做迁移**。
|
|
309
|
+
|
|
310
|
+
- **默认 `keyring`**:现有安装零变化,桌面凭据路径完全没动。Linux 上如果密钥环不可达(没有 `secret-tool`、没有会话总线、或密钥环锁着),保存会失败,但报的是一句明确的、告诉你把「账号存储位置」改成 DSH 凭据库的话,而不是静默换地方、也不是一句没有上下文的错误。
|
|
311
|
+
- **服务器安装推荐 `poolStorage: "credentials"`**:唯一让本插件的账号和 DeepSeek、Telegram 等其它密钥躺在**同一个** DSH 凭据文档里的模式,不需要任何外部守护进程。
|
|
312
|
+
- **两个平台都可用**:`credentials` 不绑定平台,Windows / macOS 服务器也可以选;选它时 DPAPI 与钥匙串完全不参与。
|
|
313
|
+
- 该键只管**号池文档**;单凭据镜像(登录态预览用的那份)仍走平台存储,Linux 上本来就是 `0600` 文件。
|
|
314
|
+
- **改 profile 里的 `poolStorage` 要重新挂载插件才生效**(约等于重启):这个值在 `apply` 时读一次,池子只在插件重新应用时按它解析。设置页卡片上的选择是另一条路——它写进插件自己的存储文档、并立刻让所有池重新解析,所以两个入口的生效时机不同,别把它们当成一回事。
|
|
315
|
+
- 号池在 DSH 凭据库里的地址是 `dsh-chatgpt-subscription/pool-<路径的 sha256>`。`pool-` 前缀是必须的:seam 要求每段匹配 `/^[a-z][a-z0-9-]*$/`,而裸摘要里有 62.5% 以数字开头,那样的 key 会在**下一次启动**解析整份凭据文档时被判非法,把宿主上所有凭据一起带走。
|
|
316
|
+
- **如果曾经用本 PR 的未发布构建选过 `credentials`,旧的无前缀 key 要手工改一次**,自动迁移做不到:key 非法时 DSH 的凭据 provider 自己就起不来,插件手里根本没有可以拿来做迁移的 seam,而背着 provider 去改它的 `$DSH_HOME/.credentials.yaml` 比这个 bug 更危险。修法是改名,改完重启即可(账号一条不丢):
|
|
317
|
+
```sh
|
|
318
|
+
sed -i -E 's#(dsh-chatgpt-subscription)/([0-9a-f]{64})#\1/pool-\2#g' "$DSH_HOME/.credentials.yaml"
|
|
319
|
+
```
|
|
320
|
+
没有任何发布版本写过无前缀形态,所以这条只影响跑过本分支本地构建的机器。
|
|
321
|
+
- **设置页的账号卡片**里就是这条设置的界面:`Account storage` 选择器(带每个选项的说明)、一行「当前实际使用:…」、以及一句「另一个存储里的账号留在那里,切回去之前不显示,不做迁移」。选完立刻写进插件自己的存储文档(`<dshHome>/storages/dsh-chatgpt-subscription-pool-storage.json`),并以这份文档为准——profile 里的 `poolStorage` 只作为没有在卡片里选过时的默认值。
|
|
322
|
+
|
|
323
|
+
```yaml
|
|
324
|
+
# 服务器(主机专用于 DSH、没有桌面密钥环)
|
|
325
|
+
poolStorage: credentials
|
|
326
|
+
|
|
327
|
+
# 带桌面会话、密钥环已解锁的机器:保持默认即可
|
|
328
|
+
poolStorage: keyring
|
|
329
|
+
```
|
|
330
|
+
|
|
298
331
|
## 安装
|
|
299
332
|
|
|
300
333
|
### 方式 1:通过 DSH CLI 安装(推荐)
|
|
@@ -537,6 +570,8 @@ DSH 设置页的「Subagent」卡片会把勾选的模型写成会话级的允
|
|
|
537
570
|
|
|
538
571
|
改动只在设置卡片里保存过的勾选生效:设置改动只影响之后新建的会话(DSH 的会话快照语义),已运行的会话继续使用它自己记录的那份列表。
|
|
539
572
|
|
|
573
|
+
> **调度模式如何知道自己是哪种姿态。** `list_subagent_models` 与 `provider`/`model` 参数由 preset 行静态挂载(`modelSelectionSettings: true`),所以**工具在场不等于校验生效**——真正决定校验的是会话记录的那份允许列表,没有记录时守卫对一切放行。为了让模型**读到**这个事实而不是从「工具在」推断出「已生效」,`list_subagent_models` 的返回被 `tools/post-execute` 原地补一段:有列表时附上本会话全部 `{ provider, model }` 拆解对,没有列表时附上 `UNRESTRICTED_ROUTING_NOTICE`(写明「本会话没有允许清单生效、路由不受限、省略路由是正当的」)。调度模式的 R2 据此分成三态——`[State: Listed]` / `[State: Unlisted]` / `[State: Unmounted]`,只有 `[State: Unmounted]` 能作为 R8 fallback 的理由。
|
|
574
|
+
|
|
540
575
|
> 升级提示:从 0.3.2 起,带有允许列表的会话里**任何**未写明 `provider` + `model` 的委派都会被拒绝(此前只有写明且不在列表内的路由会被拒绝)。这是有意的行为变更——它消除了「子代理悄悄继承主代理模型」的漏洞;把 `subagentModelAuthorization` 设为 `false` 可回到 DSH 原始行为。
|
|
541
576
|
|
|
542
577
|
### Kimi Code
|
|
@@ -548,7 +583,7 @@ DSH 设置页的「Subagent」卡片会把勾选的模型写成会话级的允
|
|
|
548
583
|
|
|
549
584
|
`kimi-code` 会像其他 Provider 一样出现在 DSH 模型选择器中。**上下文窗口**默认取模型目录值,可逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 `1M` / `256K` / `200000` 等写法)——注意 `k3` 的 1M 上下文需要 Allegretto 及以上套餐,因此默认按 256K 计算,升级后再在此覆盖为 1M。
|
|
550
585
|
|
|
551
|
-
**申报的窗口默认就是目录值或你的覆盖值,不做折算**——`k3` 覆盖成 1M 就按 1M
|
|
586
|
+
**申报的窗口默认就是目录值或你的覆盖值,不做折算**——`k3` 覆盖成 1M 就按 1M 申报。撞上本档请求体上限时(1M 档 8 MiB、256K 档 2 MiB,见上一条),本地守卫抛的是 `CONTEXT_WINDOW_EXCEEDED`:DSH 会对该码**自动压缩本轮历史并重试同一步**,所以表现是「压缩一次后继续」,不是整轮失败。想要「撞墙之前就自动压缩」,可设 `DSH_KIMI_CODE_BYTES_PER_TOKEN` 启用窗口折算:申报值 = `min(声明值, floor(上限 / d))`——这里的「上限」是与模型无关的那个 2 MiB 守卫值(设了 `DSH_KIMI_CODE_MAX_BODY_BYTES` 则取它),它**刻意不跟随上面的按模型档位**:这个开关只决定「提前压缩落在哪里」,而真正兜底的仍是按模型档位的请求体守卫。取值按内容密度选——DSH 的 token 计量是固定密度(4 字符/token,见 `@deepseek-ai/dsh-token-meter`),看不见中文占 3 字节,所以「一个计量 token 占多少字节」= 4 × 每字符字节数:纯 ASCII 约 4、中英混合约 8、密集中文约 12;对应的字节墙分别是 524288 / 262144 / 174763 计量 token。实测:`d=4` → 524288(代码为主的会话在 1.68 MB 处压缩)、`d=8` → 262144(混合)、`d=12` → 174762(中文,三种密度都在墙前)。压力阈值是 `min(floor(0.8 × 窗口), 窗口 − 65536)`(`compaction-basic`:`thresholdRatio` 默认 0.8、`headroomTokens` 默认 65536、本线路不申报 `defaultMaxTokens` 故无输出预留)。该变量是**可选的提前压缩开关**而不是安全守卫:不设或拼错等于不启用,真正兜底的是上面那个恢复码。**默认思考档位**的选项跟随勾选模型自己声明的档位——`low` / `high` / `max`,以及在允许关闭思考的模型上才出现的「关闭思考」(服务对这些以外的取值直接报 400);K3.1 Pro 系列只支持思考模式,硬关会被拒(400),所以勾选它时这一档不出现,卡片上会写明原因;切换模型或切换档位都会使上下文缓存失效,建议在同一会话内保持一致。
|
|
552
587
|
|
|
553
588
|
**额度倍率**取自官方模型表并显示在设置页模型能力表的「说明」列(悬停可一并看到):`k3` = **2×**、`k3-256k` = **1×**、`kimi-for-coding` = **1×**、`kimi-for-coding-highspeed` = **3×**;`k3.1-pro` 与 `k3.1-pro-highspeed` 官方未公布相对倍率(后者只说了「约为常规版 2 倍」),因此显示为**未知**而不是猜成 2×。倍率绑定**模型 id**,与上下文长度、缓存命中率都无关——选 `k3` 就是 2×,哪怕只用几千 token。注册表不认识的新模型 id 显示为**未知**而不是猜成 1×。
|
|
554
589
|
|
|
@@ -994,9 +1029,10 @@ access token / refresh token / 授权码 / PKCE verifier**;诊断里提到某
|
|
|
994
1029
|
**能力**
|
|
995
1030
|
|
|
996
1031
|
- OpenAI Chat Completions 协议,流式输出;透传工具 schema、工具调用/结果,图片按 `image_url` 内联,`reasoning_effort` 原样下发;支持 `temperature`、`stop` 与 `max_tokens`;
|
|
997
|
-
- 模型目录:随包
|
|
1032
|
+
- 模型目录:随包 16 个 Cline Pass 模型是**兜底**(含 `deepseek-v4.1-flash-1017` 快照 id——网关对别名与快照的钉选行为不同)。点「刷新模型目录」会读官方 `/ai/cline/recommended-models`、models.dev 与上游网关目录,只增不减,并把每个模型的能力(上下文窗口、输出上限、图片、推理档位)一起补上;新发布、本版本不认识的模型按保守值录取,不会被隐藏;**设置页与模型选择器只列内置 + 官方订阅 + 手动添加的模型**,完整网关目录仅作为搜索索引(旧的 exposeCatalog 配置不再展开),其他模型可在卡片里按 id 搜索并添加,添加后自动启用;
|
|
998
1033
|
- **上游渠道可观测、可钉住**:同一模型可能由 OpenRouter(direct 管线)或 Vercel AI Gateway(planner 管线)转发。卡片可以对单个模型「探测」渠道、逐个「校验」、按顺序钉住或排除,并在**首个 token 之前**失败切换到下一个渠道;`strict` 只发允许列表,`preferred` 按顺序尝试。钉住字段默认**两种写法都写**(`provider.only/order/sort` 与 `providerOptions.gateway.*`),因为网关可以在两次请求之间换管线,只写一种会让钉住悄悄失效;
|
|
999
|
-
- **钉住是否被采纳以响应为准**:网关对未知/不可用的 `only`
|
|
1034
|
+
- **钉住是否被采纳以响应为准**:网关对未知/不可用的 `only` 不报错,直接从别的渠道服务。因此探测、校验与真实请求都会回读响应里的实际服务渠道(流式帧的路由块在 `delta.provider_metadata` 的收尾帧上,本线路也会读);「请求 baseten、实际 deepseek」会被明确标成未被采纳,而不是当成成功;
|
|
1035
|
+
- **匿名贡献者路由会被单独标记**:`openai-compatible-private`(VMC 回退网,回答可能用于训练、无 ZDR)在渠道芯片上是 `⚠` 警示色,钉选它或模型只发现它时卡片会给出警告;**探测不到渠道时可手动输入渠道名钉选**(渠道名是网关级词汇,输入框会联想其他模型已发现的渠道),是否生效以「测试」与历史回读为准;**1017 还需 `providerOptions.gateway.has:[vision,implicit-caching]` 能力过滤才会采纳钉选并恢复渠道探测**(本线路已默认补上,面板可编辑,其他模型默认不添加);第一方 DeepSeek 回答以 `provider_metadata.deepseek.systemFingerprint` 为准(顶层 `system_fingerprint` 是网关现铸的,不算证据),指纹会记录在测试结果与请求历史里。注意**钉选是否生效由网关按模型 id 决定且随时间变化**(实测 2026-10-23:`deepseek-v4.1-flash-1017` 被改指匿名路由忽略钉选,同刻 `deepseek-v4-pro` 正常采纳)——被忽略时历史与测试会明说,而不是静默兜底;
|
|
1000
1036
|
- **登录态**:设备码确认后账号自动入池;access token 以 `workos:` 前缀发送,到期前 5 分钟自动 refresh(refresh token 轮换并先落盘再使用);refresh 被上游判 `invalid_grant` 时账号标记为失效并提示重新登录,网络/5xx 只算瞬时失败,不会误登出;
|
|
1001
1037
|
- **号池**:多账号(OAuth)或 API Key、顺序/轮询/粘性三种调度、429 冷却、401/403 标记失效后换号;额度耗尽(`QUOTA`)与鉴权失败是**账号级**失败,会换账号;普通 429 是**渠道级**,只换渠道,不牺牲账号容量;
|
|
1002
1038
|
- **额度**:`GET /users/me/plan/usage-limits` 的 `five_hour` / `weekly` / `monthly` 三个窗口,**按账号**读取并显示;读取失败只报原因,不阻断请求;
|
|
@@ -1155,7 +1191,8 @@ Antigravity 的 Gemini 用量以流结束时的上游累计计数为准,缓存
|
|
|
1155
1191
|
| 方法 | 路径 | 说明 |
|
|
1156
1192
|
| --- | --- | --- |
|
|
1157
1193
|
| GET | `/status` | 查询账号、连接状态与额度;另带 `codexCliSignInAvailable`(本机是否有可导入的 Codex CLI 登录,**只 `stat` 不读取**)与 `codexCliSignInPath`(为此查看过的那个文件路径) |
|
|
1158
|
-
| POST | `/login/start` | 开始 OAuth
|
|
1194
|
+
| POST | `/login/start` | 开始 OAuth 登录(浏览器回调,需要本机能监听 `localhost:1455`) |
|
|
1195
|
+
| POST | `/login/device/start` | 开始设备码登录:立即答 `{loginId, userCode, verificationUrl, expiresAt, now}`,确认在后台等,进度走同一条 SSE;与 `/login/start` 互斥,同一时刻只允许一个 |
|
|
1159
1196
|
| GET | `/login/events?loginId=...` | SSE 订阅登录进度 |
|
|
1160
1197
|
| POST | `/login/cancel` | 取消登录任务 |
|
|
1161
1198
|
| POST | `/logout` | 注销并清除凭据与额度缓存 |
|
|
@@ -1166,7 +1203,7 @@ Antigravity 的 Gemini 用量以流结束时的上游累计计数为准,缓存
|
|
|
1166
1203
|
| POST | `/adopt` | 导入本机登录(body `{source:'codex'}`),**只读**:快照作为一行加入 ChatGPT 号池,不触碰当前登录,也不触碰 Codex CLI 的文件 |
|
|
1167
1204
|
| POST | `/adopt/disable` | 停止导入:清掉插件这边记录的导入快照;**不删除也不改写 Codex CLI 的文件** |
|
|
1168
1205
|
|
|
1169
|
-
状态响应只包含脱敏 email、套餐、账号 ID 后四位、token 到期时间和额度 DTO
|
|
1206
|
+
状态响应只包含脱敏 email、套餐、账号 ID 后四位、token 到期时间和额度 DTO。设备码登录在进行中时,`login.device` 还带**待输入的设备码** `userCode`、确认页地址、授权截止时刻与宿主当前的 `now`——这三样本来就是写在用户屏幕上的东西,用来兑换登录的 `device_auth_id` 与 PKCE `code_verifier` 始终留在宿主,不进 DTO、不进浏览器。
|
|
1170
1207
|
|
|
1171
1208
|
## 组件看板卡片(dsh-widget-board)
|
|
1172
1209
|
|
|
@@ -1204,7 +1241,7 @@ npm pack --dry-run
|
|
|
1204
1241
|
|
|
1205
1242
|
Kimi Code、MiniMax Code、Command Code、Claude 遇到“输入加输出预留超限”时,插件可在 HTTP 400/422 的完整 token 计数证明输入仍能放下、且上游确实采用了请求输出上限的情况下,仅降低输出上限重试一次。消息、工具和历史保持不变,摘要请求也适用。降低后的输出仍可能截断,截断不会冒充完整摘要。Codex 不支持该输出参数,不走此恢复;输入本身超限、模糊错误或流内错误仍交给 Harness 处理。这不是对所有压缩故障的通用修复。
|
|
1206
1243
|
|
|
1207
|
-
MiniMax、Kimi、Codex、Claude、Command Code 和 Antigravity 的错误处理会将明确的上下文超限错误交给 Harness 的溢出恢复机制。该机制需要宿主启用压缩后端;它不是无条件重发同一个超限请求。认证、配额和输出截断不会因此被当作上下文超限。**请求体字节限制是唯一按线路区分的**:Kimi Code
|
|
1244
|
+
MiniMax、Kimi、Codex、Claude、Command Code 和 Antigravity 的错误处理会将明确的上下文超限错误交给 Harness 的溢出恢复机制。该机制需要宿主启用压缩后端;它不是无条件重发同一个超限请求。认证、配额和输出截断不会因此被当作上下文超限。**请求体字节限制是唯一按线路区分的**:Kimi Code 把「请求体超过本档上限(1M 档 8 MiB / 256K 档 2 MiB)」的本地拒绝与网关原文 `total message size N exceeds limit 2097152` 都归入该码(压缩确实能缩小请求体,实测这是长会话最常见的 400),其余线路的请求体拒绝仍按普通错误呈现。手动压缩仍需生成完整摘要;如果摘要请求本身超限、被截断或缺少正文,修正错误分类也不能保证它成功。请保留失败会话中的 `compaction/end` 错误、provider/model、宿主及插件版本,以便定位。
|
|
1208
1245
|
|
|
1209
1246
|
| 现象 | 处理 |
|
|
1210
1247
|
| --- | --- |
|