@eddyskywalker/dsh-chatgpt-subscription 0.33.0 → 0.34.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 +45 -0
- package/README.md +51 -110
- package/lib/client.js +1483 -335
- package/lib/client.js.map +1 -1
- package/lib/index.js +5934 -1974
- package/lib/types/client/common/format.d.ts +10 -0
- package/lib/types/client/common/format.d.ts.map +1 -1
- package/lib/types/client/hub/brand-icons.d.ts +2 -2
- package/lib/types/client/hub/brand-icons.d.ts.map +1 -1
- package/lib/types/client/hub/providers.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +2 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/opendesign/OpenDesignComposerQuota.d.ts +20 -0
- package/lib/types/client/opendesign/OpenDesignComposerQuota.d.ts.map +1 -0
- package/lib/types/client/opendesign/OpenDesignSection.d.ts +18 -0
- package/lib/types/client/opendesign/OpenDesignSection.d.ts.map +1 -0
- package/lib/types/client/opendesign/api.d.ts +45 -0
- package/lib/types/client/opendesign/api.d.ts.map +1 -0
- package/lib/types/client/opendesign/locales.d.ts +689 -0
- package/lib/types/client/opendesign/locales.d.ts.map +1 -0
- package/lib/types/client/opendesign/styles.d.ts +11 -0
- package/lib/types/client/opendesign/styles.d.ts.map +1 -0
- package/lib/types/client/qoder/QoderSection.d.ts +12 -2
- package/lib/types/client/qoder/QoderSection.d.ts.map +1 -1
- package/lib/types/client/qoder/locales.d.ts +7 -1
- package/lib/types/client/qoder/locales.d.ts.map +1 -1
- package/lib/types/client/qoder/useQoderSection.d.ts.map +1 -1
- package/lib/types/host/common/model-request-control.d.ts +1 -1
- package/lib/types/host/common/model-request-control.d.ts.map +1 -1
- package/lib/types/host/common/request-diagnostics.d.ts +1 -1
- package/lib/types/host/common/request-diagnostics.d.ts.map +1 -1
- package/lib/types/host/kimi-code/adapter.d.ts +31 -0
- package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
- package/lib/types/host/kimi-code/mapper.d.ts +8 -0
- package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
- package/lib/types/host/kimi-code/types.d.ts +92 -0
- package/lib/types/host/kimi-code/types.d.ts.map +1 -1
- package/lib/types/host/opendesign/account-pool.d.ts +54 -0
- package/lib/types/host/opendesign/account-pool.d.ts.map +1 -0
- package/lib/types/host/opendesign/adapter.d.ts +69 -0
- package/lib/types/host/opendesign/adapter.d.ts.map +1 -0
- package/lib/types/host/opendesign/catalog.d.ts +44 -0
- package/lib/types/host/opendesign/catalog.d.ts.map +1 -0
- package/lib/types/host/opendesign/client.d.ts +148 -0
- package/lib/types/host/opendesign/client.d.ts.map +1 -0
- package/lib/types/host/opendesign/line.d.ts +49 -0
- package/lib/types/host/opendesign/line.d.ts.map +1 -0
- package/lib/types/host/opendesign/mapper.d.ts +128 -0
- package/lib/types/host/opendesign/mapper.d.ts.map +1 -0
- package/lib/types/host/opendesign/oauth.d.ts +105 -0
- package/lib/types/host/opendesign/oauth.d.ts.map +1 -0
- package/lib/types/host/opendesign/routes.d.ts +74 -0
- package/lib/types/host/opendesign/routes.d.ts.map +1 -0
- package/lib/types/host/opendesign/token-store.d.ts +154 -0
- package/lib/types/host/opendesign/token-store.d.ts.map +1 -0
- package/lib/types/host/opendesign/types.d.ts +180 -0
- package/lib/types/host/opendesign/types.d.ts.map +1 -0
- package/lib/types/host/qoder/adapter.d.ts +26 -2
- package/lib/types/host/qoder/adapter.d.ts.map +1 -1
- package/lib/types/host/qoder/client.d.ts +112 -0
- package/lib/types/host/qoder/client.d.ts.map +1 -1
- package/lib/types/host/qoder/model-catalog.d.ts +52 -6
- package/lib/types/host/qoder/model-catalog.d.ts.map +1 -1
- package/lib/types/host/qoder/routes.d.ts +23 -0
- package/lib/types/host/qoder/routes.d.ts.map +1 -1
- package/lib/types/host/qoder/token-store.d.ts +56 -7
- package/lib/types/host/qoder/token-store.d.ts.map +1 -1
- package/lib/types/index.d.ts +11 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/opendesign-contracts.d.ts +159 -0
- package/lib/types/shared/opendesign-contracts.d.ts.map +1 -0
- package/lib/types/shared/qoder-contracts.d.ts +40 -1
- package/lib/types/shared/qoder-contracts.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.34.0 - 2026-10-21
|
|
6
|
+
- **[Kimi Code] 长会话撞 2 MB 请求体上限整轮失败——现在撞墙交给压缩恢复,窗口折算降为可选**
|
|
7
|
+
- **现象**:中文长会话在 K3 线上整轮失败,报 `Kimi Code rejected the request before sending: the serialized body is 2107355 bytes, above the 2097152-byte limit this route enforces. Composition: images 0 bytes, tool schemas 2531 bytes, conversation text and system prompt 2104824 bytes`。图片 0 字节,也就是说这**不是读图问题**,上一版的「丢最旧的图」回收路径在这里丢无可丢,只能报错并建议压缩——而用户真正要做的是让这一轮活下来。
|
|
8
|
+
- **根因一(错误码不对,宿主接不上自愈)**:[mapper.ts](../src/host/kimi-code/mapper.ts) 的 `assertRequestBodyFits` 抛的是 `PROVIDER_ERROR`,而 DSH 的溢出恢复**只对 `CONTEXT_WINDOW_EXCEEDED` 生效**(`compaction-basic` 的 `agent/request-error` 监听器按该码强制压缩本轮历史、再重试同一步,重试上限默认 1 次)。于是唯一还能靠压缩救回来的场景——正文太大、图已丢完——恰好是唯一不会被救的那个。本线路服务端真返回 400 溢出的路径(`classifyKimiFailure`)早就用对了这个码,只有本地守卫没接上。
|
|
9
|
+
- **根因二(两个上限量不同的东西)**:DSH 用 adapter 申报的 `context.contextWindow` 算压缩阈值(`resolveCompactSpec`:`thresholdRatio` 默认 0.8、`headroomTokens` 默认 65536,本线路不申报 `defaultMaxTokens` 故无输出预留,即 `min(floor(0.8W), W − 65536)`),这是 **token** 口径;网关的 2 MB 是 **字节** 口径。而 DSH 的 token 计量是固定密度(`@deepseek-ai/dsh-token-meter` 的 `CHARS_PER_TOKEN = 4`,按 `text.length / 4` 计价,**看不见中日韩字符占 3 字节**)。所以「一个计量 token 占多少字节」= 4 × 每字符字节数:纯 ASCII 约 4、中英混合约 8、密集中文约 12。`kimi-for-coding` 申报 1M、阈值 85 万计量 token,而 2 MB 中文正文只有约 17.5 万计量 token——**压缩永远不会先触发**,字节墙先到。
|
|
10
|
+
- **根因三(网关原文没被认出来)**:`total message size 5943865 exceeds limit 2097152` 匹配不上 `common/context-overflow.ts` 里任何一条超限措辞,所以请求即便漏过本地守卫、由服务端拒绝,同样落进 `PROVIDER_ERROR`。
|
|
11
|
+
- **改法(兜底,本次的主修复)**:`assertRequestBodyFits` 的错误码从 `PROVIDER_ERROR` 改为 `CONTEXT_OVERFLOW_CODE`,文案与 `BodyFitContext` 一字未动;`classifyKimiFailure` 增加 `isKimiBodySizeRefusal`(认 `total message size … exceed(s) … limit`)归入同一码,message 明说是**字节上限**而不是 token 窗口。判定函数刻意写在 Kimi 自己的分类器里——共享的 `isContextOverflow` 被其它八条线路共用,把一句话加进去会连带改写别人的失败语义。
|
|
12
|
+
- **改法(窗口折算,默认关)**:[types.ts](../src/host/kimi-code/types.ts) 新增 `wireBytesPerToken(env)`、`byteDerivedTokenCap(env)` 与 `effectiveContextWindow(tokenWindow, env)`;[adapter.ts](../src/host/kimi-code/adapter.ts) 的 `contextWindowFor` 仍是「申报值与内部预算的唯一入口」,但**默认原样发布目录值或用户覆盖值**:2 MB 墙已经由恢复码接管,用户显式覆盖(例如把 `k3` 覆盖成 1,048,576)不该被插件悄悄压小——这条是本轮返工的核心,最初把 clamp 设成默认是错的。设 `DSH_KIMI_CODE_BYTES_PER_TOKEN` 才启用折算,申报值 = `min(声明值, floor(2MB / d))`:`d=4` → 524288、`5` → 419430、`8` → 262144、`12` → 174762。
|
|
13
|
+
- **为什么是这组数**:DSH 的 token 计量是固定密度(`@deepseek-ai/dsh-token-meter` 的 `CHARS_PER_TOKEN = 4`,按 `text.length / 4` 计价,**看不见中文占 3 字节**),所以「字节 / 计量 token」= 4 × 每字符字节数:纯 ASCII 约 4、中英混合约 8、密集中文约 12;2 MB 墙换算成计量 token 分别是 524288 / 262144 / 174763。压力阈值是 `min(floor(0.8 × 窗口), 窗口 − 65536)`(`compaction-basic/src/config.ts` 的 `resolveCompactSpec`,`thresholdRatio` 默认 0.8、`headroomTokens` 默认 65536,本线路不申报 `defaultMaxTokens` 故无输出预留)。选哪个 `d` 就是选「让哪一类会话在墙前压缩」。
|
|
14
|
+
- **旋钮语义(与守卫不同)**:该变量是**可选的提前压缩开关**,不是安全守卫——不设、空串、非正、非法一律等于**不启用**(真正的安全网是恢复码,它永远在);`DSH_KIMI_CODE_MAX_BODY_BYTES` 仍按旧约定(typo 回落默认值而不是关掉守卫)。
|
|
15
|
+
- **默认行为的代价(写成事实)**:不折算时,`k3`@1M 的压力阈值 `min(838860, 983040)` = 838860 计量 token,而字节墙只有 174763(中文)/ 262144(混合)/ 524288(ASCII)——**阈值永远够不到**,所以长会话走的是「撞墙 → 自动压缩 → 重试同一步」。想让压缩发生在墙前就开折算。设置卡片仍按用户配置值显示窗口(客户端展示层,未改动)。
|
|
16
|
+
- **佐证**:官方 `kimi-cli` 走的是同一条「预算前置」路线——`src/kimi_cli/soul/compaction.py::should_auto_compact` 只在「达窗口 85%」或「剩余不足 50K token」时压缩,**从不特殊处理 2097152**;它的 CHANGELOG 还记过一次同类缺陷(工具结果 token 没算进压缩触发 → 压缩不触发 → 直接 400),与本次的「计量口径没算字节」是同一类错误。
|
|
17
|
+
- **测试**:新增 `test/kimi-code-capacity.test.ts`(29 例),分三段钉住:`window folding is opt-in`(**默认无 env 时 `k3` 的 1M 覆盖与 `kimi-for-coding` 的 1M 都原样发布**、4/5/8/12 各自的 min 语义、非法值当未设、`min` 不会把 256K 放大);`what each density setting protects, when folding is on`(把三种密度的撞墙点 524288 / 262144 / 174763、压力阈值 `floor(min(0.8W, W − 65536))` 与各档的护住范围写成断言,并**明写默认不折算时三种密度都先撞墙、这不是缺陷而是恢复码接管**);以及「2.1 MB 正文在发请求前就以 `CONTEXT_WINDOW_EXCEEDED` 被拒」的端到端用例(`fetch` 零调用);另有「2.1 MB 正文在发请求前就以 `CONTEXT_WINDOW_EXCEEDED` 被拒」的端到端用例(`fetch` 零调用)、`k3`/`k3-256k` clamp 前后相等、以及网关原文归类与「无关 400 仍是 `PROVIDER_ERROR`」的用例。`test/kimi-code-adapter.test.ts`、`test/kimi-code-k3.test.ts`、`test/kimi-code-body-fit.test.ts`、`test/dynamic-output-reservation.test.ts` 按新语义更新。
|
|
18
|
+
- **验证**:`npm run typecheck` 0 错误;`npx vitest run test/kimi-code test/dynamic-output-reservation` **30 文件 / 475 条全过**;全量 `npm test` **290 文件通过 / 4751 条通过 / 0 失败**(7 skipped 为仓库既有平台跳过:`token-store-linux` 等)。
|
|
19
|
+
- **[qoder] 模型选择里 Qoder 整条线路消失、「全不选」等于「全选」、重启后先出现一大堆用不上的模型——三件事都出在「哪些模型算可用」这一条链上**
|
|
20
|
+
- **现象一(最严重)**:重启宿主后,模型快捷选择栏里**根本没有 Qoder 这个供应商**;要打开一次设置页才会出现。
|
|
21
|
+
- **现象二**:设置卡片上的「全不选」点下去与「全选」效果完全相同;计数行还字面显示「已选 {selected} / 2」(占位符没被替换)。
|
|
22
|
+
- **现象三**:进设置页先看到 15 个模型,其中大部分是当前套餐根本没有的,必须点一次「刷新目录」才缩到自己账号真实的 2 个。
|
|
23
|
+
- **真因一(白名单词汇表错配)**:[adapter.ts](../src/host/qoder/adapter.ts) 的 `listModels` 拿用户白名单去收敛随包兜底表,而两者**不是同一套 id**——白名单是实时目录的 `display_name` 去空白(`DeepSeek-Flash`),兜底表照录 pi-provider 的静态表(`DeepSeek-V4-Flash`)。冷启动时进程里没有实时目录,收敛结果必然是空数组,`listModels` 返回 0 个模型,DSH 于是把整个 provider 分组过滤掉。实测:白名单 `['DeepSeek-Flash']` + 兜底表 → 0 个模型。
|
|
24
|
+
- **真因二(三态缺失)**:`enabledModelIds` 只有「缺省或空数组 = 不过滤」一种读法,而旧版 `defaultQoderModelSettings()` 的出厂值**恰好就是 `[]`**。于是「全不选」提交的 `[]` 被读成「不过滤」,同时也意味着**每一个老用户的落盘文件里都写着 `[]`**——直接改语义会让他们升级后一个模型都不剩。
|
|
25
|
+
- **真因三(快照读写不互逆)**:目录快照的写入侧存上游原始条目(`{ key, display_name, context_config }`),读取侧却用只认 `{ chat: [...] }` 的 `parseQoderModelListing` 去解析它,**任何快照都解析成空数组**并被当作「没有可用快照」丢掉。那份 `qoder-global-catalog.json` 一直都在、内容也是对的,却从来没有被成功读回来过一次——所谓「打开设置页就恢复」,真相是「等了一次真实的上游刷新」。
|
|
26
|
+
- **真因四(刷新不发事件)**:目录刷新成功后没有发 `llm/adapters-updated`,所以即使真实目录已经到手,模型选择器的快照也不会重读,停在空分组上。
|
|
27
|
+
- **改法(三态)**:`enabledModelIds` 改成 `string[] | null`——`null` = 不过滤(出厂)、`[]` = 用户明确全关、非空 = 白名单。存储、适配器过滤、状态下发、hub 概览、客户端五处同步;`ModelChecklist` 的「全不选」不再在自己已是 0 时禁用(全关是合法终态)。
|
|
28
|
+
- **改法(迁移)**:新增 `selectionVersion` 迁移标记。无标记 + `[]` → 按旧版出厂值迁移成 `null` 并落盘;有标记 + `[]` → 尊重用户真实的全关。幂等,且 register 后端的 schema 缺省刻意写成 `0`(旧 `update()` 写的是 `?? []`,那个后端同样会留下无标记的 `[]`)。
|
|
29
|
+
- **改法(收敛口径)**:新增 `convergeQoderSelection(stored, live, catalog)`——**收敛只在实时目录上做**,兜底表阶段不按白名单筛(它是能力占位,且与白名单不是同一套词汇);`[]` 在两种阶段下都生效。`listModels`、状态面勾选标记、hub 概览三处读同一个函数。
|
|
30
|
+
- **改法(预热与事件)**:新增 `persistedQoderModelRecord` / `parsePersistedQoderModelEntries` 这一对互为反函数的序列化器(顺带修掉 `is_reasoning` 按 `reasoningEfforts.length > 0` 写、会把 toggle 形态推理模型抹成不推理的问题);启动时 `void warmQoderCatalogOnStartup(...)` 非阻塞预热,先读磁盘快照回填、再让上游刷新跑在背后;`refreshCatalog` 改为返回「目录有没有真的换掉」,只有变了才 `ctx.emit('llm/adapters-updated')`。
|
|
31
|
+
- **改法(自动取目录)**:`GET /status` 在应答背后自动触发一次目录刷新(复用 `QuotaRefresh`,用 `force: false` 让 30 分钟 TTL 与 in-flight 去重生效);客户端首屏拿到 `catalogRefreshing` 就静默补拉一次,最多一次,不设 busy、不弹错。「刷新目录」按钮保留为强制出口。
|
|
32
|
+
- **验证**:`npm run typecheck` 0 错误;全量 `npx vitest run` **282 文件 / 4626 passed / 7 skipped**;`npm run build` 通过。冷启动回归用例**验证过先红后绿**(把规则改回旧实现时它报 `expected 0 to be greater than 0`);快照读写不对称用真实文件对拍过(旧解析器 0 条 / 新解析器 2 条);三态迁移用真实落盘文件跑过完整往返(迁移 → 幂等 → 全关不被翻回 → 全选回到 `null`)。
|
|
33
|
+
|
|
34
|
+
- **[qoder] 模型行只有名字:窗口、是否收图、思考档位、输出预算现在逐行写在勾选行下面**
|
|
35
|
+
- **现象**:Qoder 卡的模型清单每一行只有一个模型名,用户勾选时看不出这个模型能收多长的上下文、收不收图、有几档思考——与同一屏里的 OpenDesign 卡形成反差(那边一行写全)。
|
|
36
|
+
- **真因**:不是 host 没数据。[useQoderSection](../src/client/qoder/useQoderSection.ts) 拿到的 `QoderModelOption` 里 `contextWindow` / `supportsImages` / `reasoningEfforts` / `defaultMaxTokens` 都在(能力字段一律来自目录端点,随包兜底表也有逐模型事实),而是 [QoderSection.tsx](../src/client/qoder/QoderSection.tsx) 当时**刻意不把 hint 传给 ModelChecklist**——那次的需求是「模型行下面不需要介绍文字」,被误读成了「不要任何能力行」。
|
|
37
|
+
- **改法**:新增 `qoderModelRowHint()`,由 DTO 字段生成一行**数据**(`1M · text+image · 档位 low/high · 输出 131k`)并传给共享 ModelChecklist;散文式介绍仍然不进这一行。目录不给档位的模型写「无档位」而不是留空或套默认三档。共用新增的 `formatTokenCount()`(百万位保留两位、千位取整),二进制窗口不再渲染成 `1048576` 或 `131.1k`。
|
|
38
|
+
- **顺带修掉一个真 bug**:落盘快照的写入侧只写了 `is_reasoning`,没写 `thinking_config`,而回读侧的档位只从 `thinking_config.enabled.efforts` 取——于是**重启后所有推理模型都变成「无档位」**(模型是真推理模型,档位在磁盘上被丢了;重启前一切正常,所以只在冷启动那一眼看得出来)。现在写入侧按上游 effort 形态把梯子写回去(toggle 形态写 `enabled: {}`,不可关闭的写不带 `disabled`),读写仍是同一个 `readQoderThinkingConfig`,互为反函数。
|
|
39
|
+
- **验证**:`test/qoder-ui.test.tsx` 新增一例,钉住三行不同能力的摘要(单模态两档 / 多模态两档 / 无档位)与用户覆盖窗口按覆盖值显示;`test/qoder-model-catalog.test.ts` 新增两例,用生产写入侧 → 生产读取侧往返,断言梯子、可关闭性、图片与窗口都不丢(老快照缺字段时仍是原来的兜底,不炸);全量 typecheck 与 vitest 通过。
|
|
40
|
+
|
|
41
|
+
- **[opendesign] 新增第十三条订阅线路:OpenDesign(open-design.ai 订阅,浏览器设备授权 + API Key)**
|
|
42
|
+
- **协议面**:OpenAI Chat Completions 流式对话,网关 `https://amr-link.open-design.ai/v1`,`Authorization: Bearer` 鉴权。网关主机与 `/v1` 拼写转录自官方 Cloud 控制台的 quick-setup 包(它给 DeepSeek Harness 推荐的正是 Chat Completions),四个协议端点均经未认证探测确认(401 包络符合各自协议)。
|
|
43
|
+
- **登录一:浏览器设备授权(主路径)**。按官方 `vela login` 的公开 HTTP 契约重写:`POST /api/v1/cli/device-authorizations`(`{host, profile, cliVersion}`,**实测** 201 返回 deviceId / userCode / deviceSecret / activationUrl / pollIntervalSeconds),用户在浏览器确认后 `POST …/{deviceId}/token` 轮询取回 `vela_ctrl_…` 控制 Key + `sk-amr-…` 运行时 Key + 账号身份(字段名据上游 issue #8870;pending 帧的 null 形状也是实测的)。判定凭证「到位」看**字段在不在**,不看 status 字符串;取消过的流程绝不因迟到的确认而落号;宿主自身不打开浏览器(`test/login-opens-browser-once.test.ts` 钉住)。
|
|
44
|
+
- **登录二:粘贴 API Key(回退)**。控制台(工作区 → API Keys)签发,仅用于对话。`OPENDESIGN_API_KEY` 环境变量可投射首个账号;Key 测试读免费的目录端点,不花额度。
|
|
45
|
+
- **模型目录**:随包 37 个聊天模型(id、显示名、美元单价逐字转录自官方公开价目接口 `/api/v1/public/model-prices`),登录成功或添加 Key 后自动同步一次实时目录(`GET /v1/models`),同步条目持久化进设置文档,重启无需网络;目录真的变了才发 `llm/adapters-updated`。官方不公布各模型上下文窗口,默认 128k,卡片可按模型覆盖。
|
|
46
|
+
- **每模型能力(窗口 / 输出上限 / 是否收图 / 推理档位)**:原先一律 128k + 固定三档,现在随包表按模型带上真实取值——转录自本仓库已核对的同族模型表(command-code 官方注册表、cline-pass、Claude、Antigravity;冲突以 cline-pass 为准,注册表的 `off` 译成 DSH 的 `none`)。**浏览器授权账号还会读 AMR 控制面目录**(`GET /api/v1/models`,`metadata.contextWindowTokens`,`public_model_*` id 按字母数字归一),把上游真实窗口写回;用户覆盖值 > 实时目录 > 随包表 > 默认。`minimax-m3.1-flash`、`muse-wonder` 无同族表可核对,保留默认并在计划文档列名,不猜。
|
|
47
|
+
- **额度(钱包余额)**:只有浏览器授权账号带控制 Key,故只有它们能读 `GET /api/v1/wallet/balance`(`balanceUsd` 字符串);余额显示在账号行与输入框胶囊(胶囊只显示主账号,$0 才转红)。上游只给当前余额、没有可对照的总额,所以**不画百分比额度条**;钱包 401/403 按上游语义(OPEND-3553)只作「读不到」显示,绝不标记账号、绝不影响对话。粘贴 Key 的账号没有控制 Key,卡片会说明并指向控制台。
|
|
48
|
+
- **验证**:`npm run typecheck` 0 错误;新增 7 个 opendesign 套件(设备流 / 路由 / 适配器 / 映射 / 目录 / 契约 / UI)并给 `login-opens-browser-once` 与既有计数断言(TAB_IDS、卡片名、开关数、槽位 order 46)各追加一项;全量 `npx vitest run` 与 `npm run build` 通过。**未用真实订阅联调**:设备授权的创建/轮询响应是实测的,批准后的帧未观察到(据 #8870 推断且以字段存在为准),对话链路未与真实 Key 联调——清单见 `docs/opendesign-line-plan.md` §5。
|
|
49
|
+
|
|
5
50
|
## 0.33.0 - 2026-10-20
|
|
6
51
|
- **[qoder] 看板上的 Qoder 卡片用的是字母 Q,不是官方标志——现在换成官方那张 412×412 应用图标**
|
|
7
52
|
- **现象**:设置页订阅列表里其余线路都是自家标志,只有 Qoder 是一个灰底字母方块。
|
package/README.md
CHANGED
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
- [使用](#使用)
|
|
15
15
|
- [推理塌缩守卫(熔断,默认关闭)](#推理塌缩守卫熔断默认关闭)
|
|
16
16
|
- [Command Code 线路](#command-code-线路)
|
|
17
|
-
- [WorkBuddy 线路](#workbuddy-线路)
|
|
18
17
|
- [Claude(订阅)线路](#claude订阅线路)
|
|
19
18
|
- [GLM(ZCode 账号)线路](#glmzcode-账号线路)
|
|
20
19
|
- [Step Code(Step Plan 订阅)线路](#step-codestep-plan-订阅线路)
|
|
21
20
|
- [Cline Pass(OAuth 订阅)线路](#cline-passoauth-订阅线路)
|
|
22
21
|
- [Qoder(订阅)线路](#qoder订阅线路)
|
|
22
|
+
- [OpenDesign(订阅,API Key / 浏览器授权)线路](#opendesign订阅api-key--浏览器授权线路)
|
|
23
23
|
- [子代理模型授权](#子代理模型授权0215-起032-起强制指定模型)
|
|
24
24
|
- [随包分发的 Agent Preset](#随包分发的-agent-preset)
|
|
25
25
|
- [本机登录](#本机登录)
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
| `codex-chatgpt` | ChatGPT(Plus / Pro / Business…) | Responses | 浏览器 OAuth(localhost:1455 回调),或导入本机 Codex CLI 登录 | **实时** `/backend-api/codex/models` |
|
|
38
38
|
| `kimi-code` | Kimi 会员 | Anthropic Messages | **设备码**(RFC 8628) | 实时 `/v1/models` + 本地兜底 |
|
|
39
39
|
| `command-code` | Command Code | Anthropic / OpenAI 双轨 | 浏览器 OAuth 或粘贴 API Key | 实时 `/provider/v1/models` |
|
|
40
|
-
| `workbuddy-subscription` | 腾讯 WorkBuddy / CodeBuddy | OpenAI 兼容(仅流式) | 扫描桌面端凭据或官方浏览器授权 | 实时 `/v3/config` |
|
|
41
40
|
| `claude-subscription` | Claude Pro / Max | Anthropic Messages | 手动粘贴 / loopback 回调 | 实时 `/v1/models` + 本地兜底 |
|
|
42
41
|
| `minimax-code` | MiniMax Code 编程订阅 | Anthropic Messages | **复用桌面端登录态** 或设备码 | **硬编码**(见下) |
|
|
43
42
|
| `antigravity` | Google Antigravity | Gemini | Google OAuth | 内置表 |
|
|
@@ -45,6 +44,7 @@
|
|
|
45
44
|
| `step-code` | StepFun Step Plan 订阅(国区 api.stepfun.com / 国际区 api.stepfun.ai)或开放平台 API Key | OpenAI Chat Completions | **云端轮询**浏览器授权(不开本地回调端口)/ 手工粘贴 Platform API Key / 只读导入本机 `~/.stepcode/auth.json` | **实时运行时发现**(随包表刻意为空) |
|
|
46
45
|
| `cline-pass` | Cline Pass | OpenAI Chat Completions | **浏览器设备码 OAuth**(WorkOS,账号入池、自动续期);API Key 仅作兼容回退 | 随包表兜底 + 官方 `recommended-models` / models.dev / 上游网关目录补全 |
|
|
47
46
|
| `qoder` | Qoder 订阅(全球区 qoder.com / 中国站 qoder.com.cn) | Qoder 自有(COSY 签名 + 信封 SSE) | **浏览器设备流**(仅全球区)/ 手工粘贴 PAT(两区)/ 只读导入本机 `~/.qoder/.auth/user` | **实时运行时发现**(COSY 签名 GET)+ 随包能力兜底表 |
|
|
47
|
+
| `opendesign` | OpenDesign 订阅(Go / Plus / Pro / Max) | OpenAI Chat Completions | **浏览器设备授权**(AMR 设备流,签发控制 Key + 运行时 Key);粘贴 Cloud 控制台的 API Key 作回退 | 随包表兜底(源自官方公开价目)+ 实时 `GET /v1/models` |
|
|
48
48
|
|
|
49
49
|
> **只有 minimax-code 是硬编码目录,而且是有意的**:该端点的 `GET /v1/models` **未对订阅流量开放**(返回 503 `direct_route_not_configured`),任何「实时目录」都只会是一个必然失败的请求。其取值转录自本机官方客户端的 `config.yaml`。
|
|
50
50
|
>
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
- 工具调用 id 截断到 64 字符;
|
|
127
127
|
- `stop` 按上限裁剪为最多 5 条、每条 ≤32 字节,超长整条丢弃(截断的停止串会在错误位置终止生成);
|
|
128
128
|
- **K3 的长思考不会被截断**:输出上限跟随上下文窗口(保留 4096 余量),因为 `reasoning_content` 计入输出,固定 32K 会把 `max` 档的长推理中途截断并返回 `length`;调用方已知 prompt 规模时上限会被下调到放得下,未知时不做猜测;
|
|
129
|
-
- **请求体超 2 MB 本地即拒绝**:该端点最常见的 400 是 `total message size N exceeds limit 2097152`,官方文案不给建议,这里直接按真实序列化体积拦截,并按「循环实际做了什么」给出处方(有图可丢但丢了也补不上缺口 / 图已丢完仍超限 / 本来无图,三种情况文案不同,不再声称发生了没发生的省略);确有实测上限的部署(前置代理/网关)可设 `DSH_KIMI_CODE_MAX_BODY_BYTES` 指定该档上限,取值非正整数时**回落到默认值而不是关闭守卫**;带视频的请求走 64 MiB
|
|
129
|
+
- **请求体超 2 MB 本地即拒绝**:该端点最常见的 400 是 `total message size N exceeds limit 2097152`,官方文案不给建议,这里直接按真实序列化体积拦截,并按「循环实际做了什么」给出处方(有图可丢但丢了也补不上缺口 / 图已丢完仍超限 / 本来无图,三种情况文案不同,不再声称发生了没发生的省略);确有实测上限的部署(前置代理/网关)可设 `DSH_KIMI_CODE_MAX_BODY_BYTES` 指定该档上限,取值非正整数时**回落到默认值而不是关闭守卫**;带视频的请求走 64 MiB 档,不受该变量影响;**超限时报的是可恢复的溢出码**(`CONTEXT_WINDOW_EXCEEDED`):DSH 会对该码强制压缩本轮历史并重试同一步,所以长会话的表现是「压缩一次后继续」,而不是整轮失败——官方 `kimi-cli` 从不特殊处理 `2097152`,它靠 85% 提前压缩避开,详见下文「上下文窗口」那条;
|
|
130
130
|
- **缓存是自动的,且无法手动干预**:
|
|
131
131
|
- Kimi 按请求内容哈希命中前缀缓存。实测 `prompt_cache_key` 与 Anthropic `cache_control` 标记**均被忽略**(设与不设、同 key 与异 key 命中的是同一缓存),设备 id 与协议切换也不影响;
|
|
132
132
|
- TTL 实测在 300–1800 秒之间,按 256 token 对齐;`/messages` 与 `/chat/completions` **共享同一缓存**;
|
|
@@ -142,42 +142,6 @@
|
|
|
142
142
|
- **`dynamically_loaded_tools`(仅 K3)已实现**:K3 接受**消息级工具声明**(`messages[].tools`),可在会话中途用「无 `content` 字段的 system 消息」注入完整工具定义。官方把「保持顶层 `tools` 字节稳定」列为该特性的目的之一——中途修改/删除已发出的声明会使缓存从该点起失效,而在末尾追加不影响已缓存前缀,所以这是提升缓存命中的正道。声明按请求重发(服务端不保留),且仅在模型声明该能力时发送;
|
|
143
143
|
- 额度卡片区分 **5 小时 / 7 天 / 月度(会员共享池)/ 月度(Kimi Code 池)** 四个窗口并显示重置时间,另可显示加油包余额;设置页为「设置 → 订阅服务 → Kimi Code」标签页,对话输入框右侧有该线路的额度胶囊。
|
|
144
144
|
|
|
145
|
-
### WorkBuddy 线路
|
|
146
|
-
|
|
147
|
-
- 注册 `workbuddy-subscription` Provider,接入腾讯 **WorkBuddy / CodeBuddy 订阅**。
|
|
148
|
-
- 该 ID 特意与用户常用的自定义 OpenAI 兼容线路 `workbuddy` 分开,安装插件不会覆盖或隐藏原有自定义 API;
|
|
149
|
-
- 可直接扫描 CodeBuddy 桌面端已登录的 `*.info` 凭据,也可从设置页选择国区/国际区并通过官方浏览器授权添加账号;
|
|
150
|
-
- 插件添加的凭据保存在系统加密存储中(Windows DPAPI / macOS Keychain / Linux Secret Service),token 只留在 Host 进程内,不进入浏览器;
|
|
151
|
-
- **多账号号池,与其它线路同源**:走共享内核 `AccountPoolCore` 并复用同一张设置卡片,具备顺序耗尽 / 轮询调度 / 粘性会话、429 冷却换号、账号级失效保留、设为主账号与备注;
|
|
152
|
-
- **账号身份是两层**:不可变的 `internalId` 是唯一路由键,`identityKeys`(uuid / email / 派生 seed)是**只增不换**的别名集,同一账号再次登录会**合并**而不是产生幽灵账号;
|
|
153
|
-
- **唯一例外的诚实说明**:当服务端既没返回 uuid 也没返回 email 时无法自动识别同一账号,卡片会把该账号标注出来并提供**手动合并**;
|
|
154
|
-
- **顺序耗尽 / 轮询调度 / 粘性会话**三种策略;
|
|
155
|
-
- 429 冷却换号、401/403 账号级失效(保留账号、重新登录即恢复);
|
|
156
|
-
- 设为主账号、账号备注、清除冷却与重新登录;
|
|
157
|
-
- 桌面端扫描到的账号与插件内添加的账号**在同一号池里参与调度**;
|
|
158
|
-
- **桌面账号归 IDE 所有,不可删除**:卡片只对插件自己添加的账号显示「删除」,桌面账号显示「隐藏 / 恢复」——隐藏只把它移出本插件的调度,绝不改动 CodeBuddy 的凭据文件;号池层同样拒绝删除桌面账号(双保险,均有测试);
|
|
159
|
-
- **续期后原子写回**原凭据文件(只改 `auth` 块),以免桌面端掉线——桌面账号的 refresh token 会轮换,若只写进插件自己的加密存储,IDE 手里就只剩一个已作废的 token。同一进程内的并发调用**共用一次刷新**,且不会二次刷新;
|
|
160
|
-
- 上游是 OpenAI 兼容的 `POST {backend}/v2/chat/completions`,但有两条硬约束:**只支持流式**(`stream:false` → 400 `code 11101`),且**首条消息必须是 system**(否则国际区返回 400 `code 11128`)。因此请求构造器始终发送 `stream:true`,并在调用方没给系统提示时补一条中性的,避免手搓的一次性请求踩到这条规则;
|
|
161
|
-
- **区域是凭据属性,不是请求属性**:`*.workbuddy.ai` / `*.codebuddy.ai` 走国际区 `https://www.<apex>`,其余走国区 `https://copilot.tencent.com`;
|
|
162
|
-
- 账号卡片逐条标注每个账号的**国区 / 国际区**并允许选择;切换后,模型目录、额度和后续对话都使用该账号;历史凭据快照按账号身份自动去重;
|
|
163
|
-
- 插件托管账号可真正删除;桌面扫描账号只能从本插件隐藏/恢复,永不删除 CodeBuddy 的原文件;
|
|
164
|
-
- 两区模型清单不同,把模型发到不服务它的区会返回 400 `code 11102`,因此模型选择器**按当前账号区域过滤**;
|
|
165
|
-
- **模型目录取自网关自己的 `/v3/config`**(官方 CLI 启动时读的就是它):每个模型的真实上下文上限、输出上限、是否接受图片、以及可用的思考档位都在这里,不做任何按模型名猜测。`/v1/models` 在这条线路上是 404,所以此前只能靠内置表——现在内置表只作为离线兜底,且是**从真实 `/v3/config` 转录**的(早期手写版本把 `glm-5.3`、`kimi-k3` 的窗口猜成 200K/256K,实际都是 1M);
|
|
166
|
-
- **目录不是服务全集,模型必须实测**:实测国际区的 `gpt-6-sol`、`gpt-6-luna`、`gemini-3.8-flash` 都能正常返回 200,却**完全不在 `/v3/config` 里**(该接口只公布 `gpt-6-astra`)。而联网时目录会**整体替换**内置表,只加进内置表等于加了个看不见的模型——所以这三个单列一份实测表(`UNPUBLISHED_MODELS`),并合并进实时目录。存在性、思考档位、图片支持是**打接口量出来的**(`gpt-6-sol` 只收 `low`/`medium`/`high`/`xhigh`/`max`,`minimal` 被拒);上下文与输出上限**继承同族已公布的兄弟模型**(`gpt-6-astra` / `gemini-3.5-flash`),因为网关对这些 id 不公布任何信息,而 `max_tokens` 也不受窗口约束(连 `gpt-6-astra` 自己都接受远超其公布上限的值),无从反推。三者仍可在设置页逐模型覆盖;判定一个 id 是否存在只有一条路——直接问:`code 11102` 是没有这个模型,`code 11133` 是模型存在但参数被拒;
|
|
167
|
-
- 目录同时区分**默认服务的上下文长度**与**模型上限**(如 `deepseek-v4.1-flash` 默认 300K、最大 1M)。本线路不发送显式长度参数,所以 DSH 的压缩与溢出判断按**默认服务长度**计算,不会让请求越过后端实际接受的窗口;
|
|
168
|
-
- 思考档位**逐模型**取目录声明的档位表,回落顺序为「调用方显式指定 → 用户配置的默认档 → 目录为该模型声明的默认档」;
|
|
169
|
-
- **最后一档不能省**:上游在请求不带 `reasoning_effort` 时返回**空的 `reasoning_content`**(实测同一提示:不带字段 0 字符,带字段 130–215 字符)——不发送等于静默丢弃模型的思考;
|
|
170
|
-
- 目录里的单个 `effort` 字段是**默认值**,既不是完整档位表也不是「只此一档」:实测这类模型接受 `low` / `high` / `max`(其余取值被上游收敛到最近档),因此使用这三档的标准表(`WORKBUDDY_STANDARD_EFFORTS`);显式声明了 `supportedEfforts` 的模型则原样采信;
|
|
171
|
-
- 目录给出的**默认档也可能落在档位表之外**(`minimax-m3`、`kimi-k3`、国区 `glm-5.3` 都报 `medium` 却只有三档),这种值会收敛到最近档——否则默认档被判不支持而丢弃,退化成上一条的空 `reasoning_content`;
|
|
172
|
-
- 不在该模型档位集合内的取值会被**忽略而不是发出去**(上游对不支持的档位返回 `code 11150`);
|
|
173
|
-
- **瞬时失败按错误类别重试**(`src/host/workbuddy/adapter.ts`):
|
|
174
|
-
- 上游 5xx 与 `code 11134` 归为 `SERVER` 并走有界退避(最多 3 次,1.5s 起步、15s 上限、0.2 抖动);
|
|
175
|
-
- 额度耗尽(429 / `code 6004` / `code 14003`,其中 6004 的正文带重置时刻)归为 `RATE_LIMIT` 并遵守 `Retry-After`;
|
|
176
|
-
- 401/403、跨区模型、不可用图片、历史形状错误都**不重试**,并给出可操作的提示(换模型 / 换图片 / 重新登录桌面端);
|
|
177
|
-
- **流中断即失败**:上游必然以 `finish_reason` 或 `data: [DONE]` 结束,两者都缺失说明连接中途断开,此时抛出错误而不是把半截文本当成完整回答;
|
|
178
|
-
- 额度来自 `/billing/meter/get-user-resource`,卡片展示套餐名、本周期已用/上限、剩余额度与重置时间;设置页为「设置 → 订阅服务 → WorkBuddy」标签页,对话输入框右侧有该线路的额度胶囊。
|
|
179
|
-
|
|
180
|
-
|
|
181
145
|
### MiniMax Code(编程订阅)线路
|
|
182
146
|
|
|
183
147
|
- 注册 `minimax-code` Provider,接入 **MiniMax Code 编程订阅**。它与 MiniMax 开放平台(按量计费的 API Key)是两套互不通用的系统:
|
|
@@ -189,7 +153,7 @@
|
|
|
189
153
|
- **不创建、不删除、不等待** `auth.lock`(那是桌面端自己的刷新锁,第二方碰它就可能打断官方客户端的刷新);
|
|
190
154
|
- **两种登录来源互不覆盖**:
|
|
191
155
|
- 桌面端的 `auth.json` 归桌面端所有,本插件只读;若本机没有它,才在设置页用 **RFC 8628 设备码流程**(PKCE S256)登录,凭据存到本插件自己的 `$DSH_HOME/storages/minimax-code-credentials.json`;
|
|
192
|
-
- **登出只作用于本插件自己那份凭据**:桌面端的登录态会被续期写回(只读优先),但**绝不撤销、绝不删除**,登出请求对它会被拒绝并说明原因(撤销它等于把你从正在跑的 MiniMax Code
|
|
156
|
+
- **登出只作用于本插件自己那份凭据**:桌面端的登录态会被续期写回(只读优先),但**绝不撤销、绝不删除**,登出请求对它会被拒绝并说明原因(撤销它等于把你从正在跑的 MiniMax Code 里踢下线);
|
|
193
157
|
- **区域是凭据属性**:`cn` 用 `account.minimax.cn` / `agent.minimax.cn`,`global` 用对应 `.io` 域名。两个区域的目录都会被探测,因此国际区账号不会因为没有国区文件而「未登录」;读回凭据时**以记录里存的区域为准**,而不是拿默认区域覆盖它;
|
|
194
158
|
- **模型目录是硬编码的,而且必须硬编码**(`src/host/minimax-code/model-catalog.ts`):
|
|
195
159
|
- 该端点的 `GET /v1/models` **未对订阅流量开放**(503 `"{\"errorCode\":50115,\"errorReason\":\"direct_route_not_configured\"}"`),所以任何「实时目录」都只会是一个必然失败的请求;
|
|
@@ -574,7 +538,9 @@ DSH 设置页的「Subagent」卡片会把勾选的模型写成会话级的允
|
|
|
574
538
|
3. 点击 **设备码登录**,在弹出的浏览器页面确认授权(页面已预填用户码;也可手工复制用户码到 `verification_uri`);
|
|
575
539
|
4. 登录完成后按需勾选模型、设置默认思考档位与上下文窗口。
|
|
576
540
|
|
|
577
|
-
`kimi-code` 会像其他 Provider 一样出现在 DSH 模型选择器中。**上下文窗口**默认取模型目录值,可逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 `1M` / `256K` / `200000` 等写法)——注意 `k3` 的 1M 上下文需要 Allegretto 及以上套餐,因此默认按 256K 计算,升级后再在此覆盖为 1M
|
|
541
|
+
`kimi-code` 会像其他 Provider 一样出现在 DSH 模型选择器中。**上下文窗口**默认取模型目录值,可逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 `1M` / `256K` / `200000` 等写法)——注意 `k3` 的 1M 上下文需要 Allegretto 及以上套餐,因此默认按 256K 计算,升级后再在此覆盖为 1M。
|
|
542
|
+
|
|
543
|
+
**申报的窗口默认就是目录值或你的覆盖值,不做折算**——`k3` 覆盖成 1M 就按 1M 申报。撞上 2 MB 请求体上限时,本地守卫抛的是 `CONTEXT_WINDOW_EXCEEDED`:DSH 会对该码**自动压缩本轮历史并重试同一步**,所以表现是「压缩一次后继续」,不是整轮失败。想要「撞墙之前就自动压缩」,可设 `DSH_KIMI_CODE_BYTES_PER_TOKEN` 启用窗口折算:申报值 = `min(声明值, floor(2MB / d))`。取值按内容密度选——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);切换模型或切换档位都会使上下文缓存失效,建议在同一会话内保持一致。
|
|
578
544
|
|
|
579
545
|
**额度倍率**取自官方模型表并显示在设置页模型能力表的「说明」列(悬停可一并看到):`k3` = **2×**、`k3-256k` = **1×**、`kimi-for-coding` = **1×**、`kimi-for-coding-highspeed` = **3×**。倍率绑定**模型 id**,与上下文长度、缓存命中率都无关——选 `k3` 就是 2×,哪怕只用几千 token。注册表不认识的新模型 id 显示为**未知**而不是猜成 1×。
|
|
580
546
|
|
|
@@ -678,69 +644,6 @@ DSH 设置页的「Subagent」卡片会把勾选的模型写成会话级的允
|
|
|
678
644
|
|
|
679
645
|
与 `codex-chatgpt` 线路一样,所有修改状态的路由只接受同源 JSON POST,并校验 `Origin` 与 `Host`。
|
|
680
646
|
|
|
681
|
-
## WorkBuddy 线路
|
|
682
|
-
|
|
683
|
-
1. 重启 DSH,让 Host 加载本插件;
|
|
684
|
-
2. 打开 **设置 → WorkBuddy**;
|
|
685
|
-
3. 二选一:登录 CodeBuddy 桌面端后点「重新扫描」,或点「账号管理」右上角的「添加国区账号 / 添加国际区账号」并在官方页面完成浏览器授权;
|
|
686
|
-
4. 在「账号管理」里选择账号(每条都标注国区 / 国际区),再按需勾选模型、设置默认思考深度与上下文窗口。
|
|
687
|
-
|
|
688
|
-
`workbuddy-subscription` 会像其他 Provider 一样出现在 DSH 模型选择器中,并可与名为 `workbuddy` 的自定义 API 同时存在。**上下文窗口**默认取网关 `/v3/config` 声明的**默认服务长度**,可逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 `1M` / `300K` / `200000` 等写法);**默认思考深度**逐模型生效,选项由当前账号各模型**实际声明的档位**取并集(仅部分模型支持的档位会标注数量),档位不在该模型集合内时不会被发送。
|
|
689
|
-
|
|
690
|
-
**消耗倍率**也来自同一份目录:每个模型在 `/v3/config` 里带一个 `credits` 字符串(如 `x0.79 credits`、`x6.67`),就是该模型消耗套餐额度的相对速率——官方 CodeBuddy 客户端把它渲染成 `6.67x` 显示在模型下拉里。设置页的模型行末尾会以 `倍率 0.79x` 的形式给出,**两区不一致时把两区都写出来**(实测国际区 `deepseek-v4.1-flash` 是 `0.00`、国区是 `0.11`),账号区域已知时只显示该区的值,**绝不拿另一个区的数字顶上**(跨区调用本来就会被上游以 400 `code 11102` 拒绝)。`x0.00` 是真实声明(该模型不消耗额度),照常显示;网关没给倍率的模型(如 `default-model`)则**整项不出现在提示里**,而不是编一个 0。
|
|
691
|
-
|
|
692
|
-
**凭据目录**按平台解析,可用 `CODEBUDDY_AUTH_DIR` 覆盖(与官方工具链一致):
|
|
693
|
-
|
|
694
|
-
| 平台 | 默认目录 |
|
|
695
|
-
| --- | --- |
|
|
696
|
-
| Windows | `%LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth` |
|
|
697
|
-
| macOS | `~/Library/Application Support/CodeBuddyExtension/Data/Public/auth` |
|
|
698
|
-
| Linux | `$XDG_DATA_HOME/CodeBuddyExtension/Data/Public/auth`(默认 `~/.local/share`) |
|
|
699
|
-
|
|
700
|
-
目录里通常同时存在当前凭据与若干带时间戳的历史快照。插件**优先取 `workbuddy-desktop.info` / `codebuddy-desktop.info` 这类规范文件名**,其余按 token 剩余有效期取最长的一个——只按文件 mtime 选会选到过期快照。卡片会列出目录里所有可用凭据,标明各自区域。
|
|
701
|
-
|
|
702
|
-
**失败分类与重试**:这条线路把失败分成「换号能解决」与「换号也一样」两类,判据不是状态码本身。
|
|
703
|
-
|
|
704
|
-
- **401 不等于凭据失效**:实测同一枚 bearer 在 `GET /v3/config` 上是 200、在 `POST /v2/chat/completions` 上是 401(APISIX 生成的 HTML 拒绝页)。本线路的 access token 有效期约 28 天,本地时钟**几乎永远不会**在 401 时触发续期,因此这类 401 多半是会话被顶掉或网关/路由层拒绝。收到 401 时先对**同一个账号**强制续期一次(`POST /v2/plugin/auth/token/refresh`)并用新 token **原样重放同一份请求体**:续期成功即说明凭据还活着,不写任何账号状态;**只有续期本身被上游拒绝**才把该账号记为需要重新登录,此时才换号。
|
|
705
|
-
- **请求期不写「需要重新登录」**:401 只让该账号退出**本次请求**的轮换,不写号池状态。此前一次 lane 级的 401 会在同一个请求里把每一个账号依次写成 `expired`,而号池没有任何清除路径,于是整条线路要求全部重新登录。
|
|
706
|
-
- **自愈**:被标记的账号在**每个请求前**与卡片列表前都会重新对照权威存储(桌面账号看 CodeBuddy 自己的凭据文件、托管账号看插件的加密存储);换了另一枚**未过期** token 就清掉标记并采用新凭据,仍持着被拒那枚的账号保留标记。
|
|
707
|
-
- **429 冷却换号**:按 `Retry-After`(缺省 5 分钟,上限 10 分钟)冷却该账号,并用同一份 body 换下一个账号重试。
|
|
708
|
-
|
|
709
|
-
**上游接口**:
|
|
710
|
-
|
|
711
|
-
| 用途 | 路径(前缀为区域后端) |
|
|
712
|
-
| --- | --- |
|
|
713
|
-
| 模型生成 | `POST /v2/chat/completions`(仅流式) |
|
|
714
|
-
| 模型目录 | `GET /v3/config` |
|
|
715
|
-
| 浏览器授权 | `POST /v2/plugin/auth/state` + `GET /v2/plugin/auth/token` |
|
|
716
|
-
| 令牌续期 | `POST /v2/plugin/auth/token/refresh` |
|
|
717
|
-
| 额度 | `POST /billing/meter/get-user-resource` |
|
|
718
|
-
| 签到状态 | `POST /billing/meter/checkin-activity-status`(仅国区) |
|
|
719
|
-
| 每日签到 | `POST /billing/meter/daily-checkin`(仅国区) |
|
|
720
|
-
|
|
721
|
-
两区后端分别是 `https://copilot.tencent.com`(国区)与 `https://www.workbuddy.ai` / `https://www.codebuddy.ai`(国际区)。**请求身份统一使用 CLI UA**(`CLI/2.63.2 CodeBuddy/2.63.2`):实测 `CodeBuddyIDE` 被 `/v3/config` 以 400 `code 12403` 拒绝,国际区对话端点也直接返回 401,因此不做按端点切换。
|
|
722
|
-
|
|
723
|
-
**每日自动签到**(仅国区;语义与 workbuddy2api 的 `daily_checkin.py` 对齐):DSH 启动时自动签到一轮,运行期间每 10 分钟幂等补检(当日已签的账号不再发请求);签到前先查签到状态,token 过期会自动续期并回写(桌面账号写回 CodeBuddy 自己的凭据文件)。失败当天最多自动重试 3 次;**活动尚未开启的账号不会当天放弃**——首次签到状态若报无权益,之后每小时复查一次,避免开机早于活动开放时间就错过当天。国际区账号不参与(国际后端没有签到活动)。**DSH 没开机的当天不会签到**——插件不是常驻服务。设置页「每日签到」区块可开关自动签到、查看「今日已签 x/y · 无活动 z · 失败 w」并手动「立即签到」(手动会重跑一轮并绕过开关与重试上限)。签到状态存在 `storages/workbuddy-checkin.json`,token 不出 Host。
|
|
724
|
-
|
|
725
|
-
### 插件路由(WorkBuddy)
|
|
726
|
-
所有路由都以 `/workbuddy/api` 为前缀:
|
|
727
|
-
|
|
728
|
-
| 方法 | 路径 | 说明 |
|
|
729
|
-
| --- | --- | --- |
|
|
730
|
-
| GET | `/status` | 账号、额度、模型目录与路由归属(每次都重扫凭据目录) |
|
|
731
|
-
| GET | `/accounts` | 列出桌面扫描及插件托管账号(不含 token) |
|
|
732
|
-
| POST | `/accounts/login` | 按国区/国际区启动官方浏览器授权 |
|
|
733
|
-
| GET | `/accounts/login/status` | 读取授权轮询状态(不含 token) |
|
|
734
|
-
| POST | `/accounts/action` | 删除插件托管账号,或隐藏/恢复桌面账号 |
|
|
735
|
-
| POST | `/rescan` | 清缓存并重扫凭据目录 |
|
|
736
|
-
| GET / POST | `/quota` | 强制刷新额度(POST)或读取当前状态(GET) |
|
|
737
|
-
| GET / POST | `/models`、`/settings` | 读取或更新勾选模型、上下文窗口与默认思考深度 |
|
|
738
|
-
| POST | `/catalog/refresh` | 强制刷新网关模型目录 |
|
|
739
|
-
| POST | `/connection/test` | 用已识别凭据向上游发一次最小请求测试连接 |
|
|
740
|
-
| POST | `/checkin/now` | 立即执行一轮每日签到(忽略开关与重试上限、不受无活动复查节流限制;当日已签的账号仍跳过) |
|
|
741
|
-
|
|
742
|
-
与其它线路一样,所有修改状态的路由只接受同源 JSON POST,并校验 `Origin` 与 `Host`。
|
|
743
|
-
|
|
744
647
|
## Claude(订阅)线路
|
|
745
648
|
|
|
746
649
|
### 风险须知(请先读)
|
|
@@ -848,7 +751,7 @@ adaptive 分支对这类模型额外发送 `block_binding: drop_block`(**不**
|
|
|
848
751
|
### 插件路由(MiniMax Code)
|
|
849
752
|
|
|
850
753
|
所有路由都挂在本线路自己的 `/minimax-code/api` 前缀下(与 antigravity / claude / command-code /
|
|
851
|
-
kimi-code
|
|
754
|
+
kimi-code 一致),**不**占用 Codex 那条线路的 `/api/dsh-chatgpt-subscription` 前缀。
|
|
852
755
|
|
|
853
756
|
| 方法 | 路径 | 说明 |
|
|
854
757
|
| --- | --- | --- |
|
|
@@ -858,7 +761,7 @@ kimi-code / workbuddy 一致),**不**占用 Codex 那条线路的 `/api/dsh-
|
|
|
858
761
|
| POST | `/login/cancel` | 取消授权 |
|
|
859
762
|
| POST | `/logout` | 注销**本插件自己那份**凭据;桌面端的登录态会拒绝并说明原因 |
|
|
860
763
|
| POST | `/test` | 向上游发一次最小 Messages 请求测试连接 |
|
|
861
|
-
| GET / POST | `/models`、`/settings` | 读取或更新启用开关、勾选模型、上下文窗口覆盖与默认思考深度;两个路径等价(kimi/claude 叫 `/models`,
|
|
764
|
+
| GET / POST | `/models`、`/settings` | 读取或更新启用开关、勾选模型、上下文窗口覆盖与默认思考深度;两个路径等价(kimi/claude 叫 `/models`,command-code 叫 `/settings`) |
|
|
862
765
|
| GET / POST | `/accounts` | 号池动作:`set-primary` / `set-alias` / `delete` / `clear-cooldown` / `strategy` / `relogin` / `adopt`(`adopt` = 把桌面端当前登录态导入号池,只读、不改动官方客户端文件) |
|
|
863
766
|
| GET / POST | `/quota` | 读取用量快照(POST 强制刷新):Token Plan 的 5 小时与每周窗口。**上游读失败不算请求失败**——`quota` 是可选字段,失败时卡片显示“暂无数据”,对话不受任何影响 |
|
|
864
767
|
|
|
@@ -1034,6 +937,9 @@ access token / refresh token / 授权码 / PKCE verifier**;诊断里提到某
|
|
|
1034
937
|
|
|
1035
938
|
**能力**:Qoder 自有对话面(OpenAI 形状的消息数组包在 \`RemoteChatAsk\` 信封里,过自定义 body codec,COSY 头签名,应答是信封 SSE)。模型目录**运行时发现**(COSY 签名的 \`GET /algo/api/v2/model/list?Encode=1\`)+ 随包能力兜底表;能力(上下文窗口 / 图片输入 / 思考档位)全部来自目录字段(\`context_config\` / \`is_vl\` / \`thinking_config\`),**不从模型名推断**,目录里那个 \`max_input_tokens\` 陈旧地板值明确不信。档位在本地先收敛到**模型真实梯子**再发出去;toggle 形态的模型只发开关。输出上限取上游文档化的 128K(目录不报输出上限)。
|
|
1036
939
|
|
|
940
|
+
|
|
941
|
+
**模型行**:勾选行下面一行写清能力——上下文窗口、是否收图、思考档位、输出预算(例:`1M · text+image · 档位 low/high · 输出 131k`),全部取自目录字段(`context_config` / `is_vl` / `thinking_config`)与随包兜底表的逐模型事实,客户端不按模型名推断。
|
|
942
|
+
|
|
1037
943
|
**缓存与用量**:响应 usage 里读缓存命中(\`prompt_tokens_details.cached_tokens\`,顶层 \`cached_tokens\` 兜底),缓存写入读 \`cache_write_tokens\`(上游不报就是 0,不做「恒零」声明)。**整页不出现任何金额**:订阅没有公开的 token 单价,Credits 与金额之间没有官方汇率——只显示 token 与 Credits 数字。
|
|
1038
944
|
|
|
1039
945
|
**已知限制**:
|
|
@@ -1125,6 +1031,43 @@ OAuth 是默认入口;「使用 API Key」按钮保留为兼容回退,部署
|
|
|
1125
1031
|
|
|
1126
1032
|
见上表;与其它线路一样,路由表在 `src/host/cline-pass/routes.ts` 与客户端 `api.ts` 各有一份手写副本,集成结束时逐条对照。设置卡在「设置 → 订阅服务 → Cline Pass」,对话输入框右侧有该线路的额度胶囊(显示当前已读账号中最紧张的窗口)。
|
|
1127
1033
|
|
|
1034
|
+
## OpenDesign(订阅,API Key / 浏览器授权)线路
|
|
1035
|
+
|
|
1036
|
+
`opendesign`(显示名 **OpenDesign**)接入 [OpenDesign](https://open-design.ai/) 订阅(开源项目 [nexu-io/open-design](https://github.com/nexu-io/open-design))。OpenDesign 的付费计划(Go / Plus / Pro / Max)含模型额度,官方明确支持第三方 Agent 使用其 API,并点名支持 Codex、Claude Code、**DSH**、OpenCode 等客户端。
|
|
1037
|
+
|
|
1038
|
+
**登录有两条路,共用同一个号池**:
|
|
1039
|
+
|
|
1040
|
+
1. **浏览器授权(推荐)** — 点「登录 OpenDesign 账号」,宿主向 `POST /api/v1/cli/device-authorizations` 申请一次设备授权并给出激活地址与授权代码;在浏览器确认后,查询接口 `POST /api/v1/cli/device-authorizations/{deviceId}/token` 会返回一对 Key:`vela_ctrl_…` 控制 Key 与 `sk-amr-…` 运行时 Key,外加账号身份(邮箱 / 名称 / 套餐)。运行时 Key 走对话,控制 Key 读钱包余额。签发的 Key 不过期,失效只能重新登录;**宿主自身不打开浏览器**,由卡片 `window.open` 打开激活页(与本插件其它线路同一条规则)。
|
|
1041
|
+
2. **粘贴 API Key(回退)** — 在 Cloud 控制台(工作区 → API Keys)创建后粘贴,仅用于对话(没有控制 Key,因此读不了余额)。
|
|
1042
|
+
|
|
1043
|
+
号池支持多账号轮换;部署也可以用 `OPENDESIGN_API_KEY` 提供第一把 Key(号池为空时投射为首要账号,不写入凭据库)。
|
|
1044
|
+
|
|
1045
|
+
**能力**:OpenAI Chat Completions 流式对话(官方给 DeepSeek Harness 推荐的正是这个协议形态),工具调用、图片输入、推理档位透传。网关是 `https://amr-link.open-design.ai/v1`,Bearer 鉴权。
|
|
1046
|
+
|
|
1047
|
+
**模型目录**:随包内置 37 个聊天模型,每个都带 id、显示名、美元单价,以及**上下文窗口、最大输出、输入模态(是否收图)与推理档位**——价目来自官方公开价目接口,能力字段转录自本仓库已核对过的同族模型表(command-code 官方注册表、cline-pass、Claude 与 Antigravity 目录;两处冲突以 cline-pass 为准)。登录成功或添加 Key 后自动同步实时目录:**浏览器授权账号(带控制 Key)还会读 AMR 控制面目录**,那里有上游真实的 `metadata.contextWindowTokens`,会覆盖随包表;网关自己的 `/v1/models` 提供该 Key 实际可见的模型清单。同步条目持久化在设置文档里,重启无需网络即可恢复。**`minimax-m3.1-flash` 与 `muse-wonder` 没有任何同族表可核对**,按 128k / 默认三档处理并在文档里列名,不猜数字;任何模型都能在卡片的「上下文窗口」里按模型修正,覆盖值优先于以上全部来源。
|
|
1048
|
+
|
|
1049
|
+
**额度(钱包余额)**:只有浏览器授权登录的账号带控制 Key,因此只有它们能读余额(`GET /api/v1/wallet/balance`,返回 `balanceUsd` 字符串);粘贴的 API Key 没有控制 Key,卡片会说明并建议去控制台查看。余额按账号显示在账号行,对话输入框右侧的胶囊显示主账号的余额;读不到时显示原因而不是 0。**本线路不画百分比额度条**——上游只给当前余额,没有可对照的总额,编一个比例就是编数据。
|
|
1050
|
+
|
|
1051
|
+
### 插件路由(OpenDesign)
|
|
1052
|
+
|
|
1053
|
+
所有路由都以 `/opendesign/api` 为前缀:
|
|
1054
|
+
|
|
1055
|
+
| 方法 | 路径 | 用途 |
|
|
1056
|
+
| --- | --- | --- |
|
|
1057
|
+
| GET | `/status` | 卡片状态:开关、号池、模型、目录同步、余额读数、登录流程 |
|
|
1058
|
+
| POST | `/settings` | 线路开关与高级设置(网关地址、默认窗口、并发、空闲超时) |
|
|
1059
|
+
| GET\|POST | `/accounts` | 账号增删、主账号、别名、轮换策略、Key 测试(用免费的目录读取验证,不花额度) |
|
|
1060
|
+
| POST | `/login/start` | 申请设备授权,应答激活地址与授权代码(不含 deviceSecret) |
|
|
1061
|
+
| GET | `/login/status?id=` | 轮询一次登录流程(宿主按服务给出的间隔节流) |
|
|
1062
|
+
| POST | `/login/cancel` | 取消登录;迟到的确认不会落号 |
|
|
1063
|
+
| GET\|POST | `/models` | 模型勾选(三态:不筛选 / 显式清单 / 全不选) |
|
|
1064
|
+
| POST | `/models/visibility`、`/models/visibility-all` | 单个/批量隐藏 |
|
|
1065
|
+
| POST | `/models/context-window` | 单模型上下文窗口覆盖 |
|
|
1066
|
+
| POST | `/catalog/refresh` | 用号池里可用的 Key 同步实时目录;目录真的变了才通知模型选择器重建 |
|
|
1067
|
+
| GET\|POST | `/usage` | 读取每个 OAuth 账号的钱包余额(每账号一次请求);失败作为数据显示,绝不标记账号 |
|
|
1068
|
+
|
|
1069
|
+
协议事实与未验证项的完整证据记录见 `docs/opendesign-line-plan.md`:设备授权的创建与轮询响应是**实测**的,批准后的字段名来自上游 issue #8870;本次接入没有真实订阅账号,对话链路未与真实 Key 联调。
|
|
1070
|
+
|
|
1128
1071
|
## 本机登录
|
|
1129
1072
|
|
|
1130
1073
|
**每条线路只在自己的详情页里回答关于本机的问题**。ChatGPT(Codex)线路的 ChatGPT 卡片里,「登录」按钮**旁边**就是「导入本机 Codex CLI 登录」——与 Claude 页面上那个收编按钮同样的位置、同样的次要样式;点它可以省掉再走一次 ChatGPT 授权。Claude Code 与 MiniMax Code 各自的设置页里本来就各有一个导入入口,不在这里重复。
|
|
@@ -1170,8 +1113,6 @@ OAuth 是默认入口;「使用 API Key」按钮保留为兼容回退,部署
|
|
|
1170
1113
|
|
|
1171
1114
|
Antigravity 的 access token / refresh token 使用独立的系统凭据存储:Windows 使用 CurrentUser DPAPI(`$DSH_HOME/storages/antigravity-oauth.json.dpapi`),macOS 使用登录钥匙串,Linux 使用 Secret Service。macOS / Linux 的服务名为 `dsh-antigravity`,账号键按旧凭据文件的绝对路径生成,隔离不同的 `DSH_HOME`。
|
|
1172
1115
|
|
|
1173
|
-
**WorkBuddy token 仅在 Host 内处理,从不进入浏览器**(`/workbuddy/api` 响应不含 `accessToken` / `refreshToken`,有测试锁定)。桌面扫描账号仍使用 CodeBuddy 自己的登录态文件:续期只原子写回其 `auth` 块;从本插件删除时只隐藏/恢复,绝不删除原文件。通过浏览器授权添加的账号归本插件所有,保存在独立系统凭据存储中:Windows CurrentUser DPAPI(`$DSH_HOME/storages/workbuddy-accounts.json.dpapi`)、macOS 登录钥匙串、Linux Secret Service;这类账号可在设置页真正删除。
|
|
1174
|
-
|
|
1175
1116
|
**MiniMax Code 的 access token / refresh token 同样只在 Host 内处理,从不进入浏览器**(`/minimax-code/api` 的响应只含非机密事实,有测试锁定)。号池的**身份键也刻意不含机密**:桌面端凭据用 `recordKey`(路径摘要)、插件凭据用 `loginEpoch`,**不是**刷新令牌的哈希——用令牌做键在每次轮换后都会把同一账号看成新账号。它的凭据**不是本插件自持的**:正常路径是**只读复用** MiniMax Code 桌面端自己的 `~/.minimax/auth/<buildEnv>/<region>/mcode-public/auth.json`,续期时通过「同目录临时文件 + `rename`」原子写回,**不创建、不删除、不等待**桌面端的 `auth.lock`,也**不留任何旁路副本**——不会在桌面端的目录里写出明文 `.dsh-bak` 之类的第二份凭据。只有本机没有桌面端凭据时,本插件才把设备码登录得到的凭据存到自己的 `$DSH_HOME/storages/minimax-code-credentials.json`;**登出只删这一份**,桌面端的登录态绝不撤销、绝不删除(撤销它等于把用户从正在运行的官方客户端踢下线)。诊断中提及令牌时只输出 SHA-256 指纹前缀,不含令牌原文。
|
|
1176
1117
|
|
|
1177
1118
|
**Claude 订阅的 access token / refresh token 同样只在 Host 内处理,从不进入浏览器**(`/claude/api` 的响应只含非机密事实,有测试锁定)。它保存在独立系统凭据存储中:Windows CurrentUser DPAPI(`$DSH_HOME/storages/claude-credentials.json.dpapi`)、macOS 登录钥匙串、Linux Secret Service;号池另用一份同样加密的文件 `$DSH_HOME/storages/claude-pool.json`。凭据文档是**多账号**结构,账号身份由不可变的 `internalId` 与只增不换的别名集共同表达,**任何路由键都不是令牌或其摘要**(令牌会轮换,用它做键会产生幽灵账号)。每次写入都**先读回校验再落盘**,校验失败会抛错且不破坏既有数据。
|
|
@@ -1238,9 +1179,9 @@ npm pack --dry-run
|
|
|
1238
1179
|
|
|
1239
1180
|
### 压缩失败
|
|
1240
1181
|
|
|
1241
|
-
Kimi Code、MiniMax Code、Command Code、Claude
|
|
1182
|
+
Kimi Code、MiniMax Code、Command Code、Claude 遇到“输入加输出预留超限”时,插件可在 HTTP 400/422 的完整 token 计数证明输入仍能放下、且上游确实采用了请求输出上限的情况下,仅降低输出上限重试一次。消息、工具和历史保持不变,摘要请求也适用。降低后的输出仍可能截断,截断不会冒充完整摘要。Codex 不支持该输出参数,不走此恢复;输入本身超限、模糊错误或流内错误仍交给 Harness 处理。这不是对所有压缩故障的通用修复。
|
|
1242
1183
|
|
|
1243
|
-
MiniMax、Kimi、Codex、Claude、Command Code
|
|
1184
|
+
MiniMax、Kimi、Codex、Claude、Command Code 和 Antigravity 的错误处理会将明确的上下文超限错误交给 Harness 的溢出恢复机制。该机制需要宿主启用压缩后端;它不是无条件重发同一个超限请求。认证、配额和输出截断不会因此被当作上下文超限。**请求体字节限制是唯一按线路区分的**:Kimi Code 把「请求体超过 2 MB」的本地拒绝与网关原文 `total message size N exceeds limit 2097152` 都归入该码(压缩确实能缩小请求体,实测这是长会话最常见的 400),其余线路的请求体拒绝仍按普通错误呈现。手动压缩仍需生成完整摘要;如果摘要请求本身超限、被截断或缺少正文,修正错误分类也不能保证它成功。请保留失败会话中的 `compaction/end` 错误、provider/model、宿主及插件版本,以便定位。
|
|
1244
1185
|
|
|
1245
1186
|
| 现象 | 处理 |
|
|
1246
1187
|
| --- | --- |
|