@eddyskywalker/dsh-chatgpt-subscription 0.22.0 → 0.24.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +39 -12
  3. package/lib/client.js +114 -17
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +7682 -7147
  6. package/lib/types/client/glm-coding-plan/GlmCodingPlanSection.d.ts.map +1 -1
  7. package/lib/types/client/glm-coding-plan/locales.d.ts +8 -11
  8. package/lib/types/client/glm-coding-plan/locales.d.ts.map +1 -1
  9. package/lib/types/client/index.d.ts.map +1 -1
  10. package/lib/types/client/ollama/OllamaSection.d.ts.map +1 -1
  11. package/lib/types/client/ollama/api.d.ts +13 -0
  12. package/lib/types/client/ollama/api.d.ts.map +1 -1
  13. package/lib/types/client/ollama/locales.d.ts +24 -0
  14. package/lib/types/client/ollama/locales.d.ts.map +1 -1
  15. package/lib/types/client/step-code/locales.d.ts +2 -2
  16. package/lib/types/compat.d.ts +9 -0
  17. package/lib/types/compat.d.ts.map +1 -1
  18. package/lib/types/host/agent-preset.d.ts.map +1 -1
  19. package/lib/types/host/antigravity/account-pool.d.ts +43 -0
  20. package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
  21. package/lib/types/host/antigravity/adapter.d.ts +28 -0
  22. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  23. package/lib/types/host/antigravity/catalog-limits.d.ts +23 -0
  24. package/lib/types/host/antigravity/catalog-limits.d.ts.map +1 -0
  25. package/lib/types/host/antigravity/client.d.ts.map +1 -1
  26. package/lib/types/host/antigravity/image-tool.d.ts +65 -0
  27. package/lib/types/host/antigravity/image-tool.d.ts.map +1 -0
  28. package/lib/types/host/antigravity/mapper.d.ts +30 -1
  29. package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
  30. package/lib/types/host/antigravity/routes.d.ts.map +1 -1
  31. package/lib/types/host/antigravity/token-store.d.ts +4 -0
  32. package/lib/types/host/antigravity/token-store.d.ts.map +1 -1
  33. package/lib/types/host/antigravity/types.d.ts +15 -3
  34. package/lib/types/host/antigravity/types.d.ts.map +1 -1
  35. package/lib/types/host/glm-coding-plan/adapter.d.ts +1 -14
  36. package/lib/types/host/glm-coding-plan/adapter.d.ts.map +1 -1
  37. package/lib/types/host/glm-coding-plan/client.d.ts.map +1 -1
  38. package/lib/types/host/glm-coding-plan/types.d.ts +0 -10
  39. package/lib/types/host/glm-coding-plan/types.d.ts.map +1 -1
  40. package/lib/types/host/ollama/adapter.d.ts +26 -2
  41. package/lib/types/host/ollama/adapter.d.ts.map +1 -1
  42. package/lib/types/host/ollama/client.d.ts +16 -1
  43. package/lib/types/host/ollama/client.d.ts.map +1 -1
  44. package/lib/types/host/ollama/routes.d.ts +1 -1
  45. package/lib/types/host/ollama/routes.d.ts.map +1 -1
  46. package/lib/types/host/ollama/types.d.ts +74 -8
  47. package/lib/types/host/ollama/types.d.ts.map +1 -1
  48. package/lib/types/index.d.ts +1 -1
  49. package/lib/types/index.d.ts.map +1 -1
  50. package/lib/types/shared/ollama-contracts.d.ts +30 -0
  51. package/lib/types/shared/ollama-contracts.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/presets/dispatch/README.md +22 -0
  54. package/presets/dispatch/agent.cordis.yml +41 -15
  55. package/lib/types/host/glm-coding-plan/signing.d.ts +0 -323
  56. package/lib/types/host/glm-coding-plan/signing.d.ts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,61 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.24.0 - 2026-10-14
6
+ - **[Antigravity] 新增 Gemini 4 Argon(`gemini-4-argon`)并同步官方 2.23.0 客户端版本标识(2026-10-14 线上实测)**
7
+ - **版本门控(User-Agent)**:实测确认 `/v1internal:fetchAvailableModels` 对 `User-Agent` 版本存在门控——旧 `2.8.0` (`cl=963137146`) 仅下发 26 个模型且默认模型停留在 `gemini-3.8-flash-high`;升级为官方最新客户端 `2.23.0` (`cl=998057262`) 后服务端下发 29 个模型(新增 `gemini-4-argon-low` / `-medium` / `-high`),并将 `defaultAgentModelId` 切至 `gemini-4-argon-medium`。同步更新 `DEFAULT_ANTIGRAVITY_VERSION = '2.23.0'` 与 `DEFAULT_ANTIGRAVITY_CL = '998057262'`。
8
+ - **模型与路由**:在可选目录首位新增 `gemini-4-argon`(`Gemini 4 Argon`,上下文 `1048576`,最大输出 `65536`,支持文本与图片输入及 `low` / `medium` / `high` 三档思考);线上实测不存在裸 `gemini-4-argon` 或 `gemini-4-argon-tiered`(均返回 404),路由按档位映射至 `gemini-4-argon-low` / `gemini-4-argon-medium` / `gemini-4-argon-high`(默认 `gemini-4-argon-medium`,`off` 走 `gemini-4-argon-low` 并在 `thinkingConfig` 中设 `includeThoughts: false`)。
9
+ - **思考配置**:`mapper.ts` 的 `isGemini3` 扩展为 `isGemini3Or4`(`/^gemini-[34][.-]/`),覆盖 Gemini 4 系列运行时。
10
+ - **[调度模式] 与 Agent Teams 改为刻意互斥:检测到就停,不再「换一套词汇接着干」(现场问题:开了智能体团队后这套调度就不好使)**
11
+ - **现象**:组合了 `@deepseek-ai/dsh-experimental-agent-team-profile` 的部署里,调度模式「派得出去、回访不了」——`list_agents` 看不到 `subagent` 的孩子,`send_message` 只认成员名,`interrupt_agent` 同理。复审、返工、追问三条通道同时失灵。
12
+ - **根因(两层)**:① **时机**——`TeamRoster.tryMembership` 对任何「无 `parentSession`、且不是 subagent descriptor」的 Agent 直接判为 `lead`,不需要先有 teammate,于是 team 工具从会话第一轮就装在 Lead 上,顶替掉内置的 `send_message`/`list_agents`/`interrupt_agent`——**还没派发就已经失去协调工具**。② **组合非法**——team 的 scoped 注册与内置同名工具按「近的层遮蔽远的层」解析,而 `dispatch` 正是那组旧定义的持有者(0.1.7+ 由本插件在运行时注册里挂载四行,preset 每一代独立 `createScope`,与宿主组合里被 patch 置 `disabled` 的那四行不是同一批实例)。上游文档对此写得很直接:`tool-agent-team`「当同名的旧全局 subagent 工具必须继续可用时,请不要选择……想同时使用两者的组合必须禁用旧定义」。
13
+ - **原设计为什么不够**:R0.5 原本做的是「侦测协作模式 → 按模式换协调词汇」(原 R-T)。它在有 teammate 时让模型改用成员词汇继续编排,但遮蔽由 scope 链决定、persona 改不回注册表,于是「适配」只能改行为、改不了「哪些工具被顶替」这个事实。更糟的是它把失败**藏**起来了:roster 里查不到孩子 ≠ 孩子没了,模型会误判成子代理丢失并重复派发。第三,teammate 结构上拿不到 per-task 路由(`SpawnTeammateRequest` 无 model 字段,构造 `startContinuable` 时整段省略 `agentOptions`),组队等于自愿放弃 R2。
14
+ - **改法**:persona 的 R0.5 由「协作模式侦测」改写为**兼容性闸门**(每个新会话判一次,早于 R0 分诊):两个 team 工具都不存在 → 写一行「编排可用:subagent」后照常编排;任一存在 → 本会话**不可编排**,按顺序只做三件:一句话说明不兼容 → 一次 `ask_user_question` 给出三条出路(关掉 bundle 重启并新建会话 / 换 preset / 本次直接做)→ 用户答复前不分诊、不规划、不派发、不动文件。**原 R-T 整段删除**,teammate 词汇(`team_task_*`、`target: <成员名>`、`wait_agent()`)在两份 persona 里不再出现;R8 的 teammate 专属条款与反模式 11/12 一并重写为「停在闸门处把选择交给用户」。
15
+ - **边界不变的部分**:模型路由守卫不动。`spawn_teammate` 仍是 `subagentModelInheritTools` 的 inherit 成员(成员一律继承 Lead 路由,守卫校验它实际继承到的那条);README 新增一条建议——用调度模式时可把它从该列表去掉,误用即硬拒。插件默认值不改,因为那是全局设置、会波及不用调度模式的会话。
16
+ - **解除互斥的上游条件(尚未落地)**:① `agent-team/src/roster.ts` 构造 `startContinuable` 的 request 处补上 `agentOptions`,给 `SpawnTeammateRequest` 与工具 schema 加路由字段、创建前接 `assertAllowedModelSelection`;② 把 team 工具的安装条件从「是 team 成员」收紧为「**有 teammate**」——后者能直接消掉「Lead 第一轮就被顶替」。只做 ① 不够。
17
+ - **验证**:`npm run typecheck` 0 错误;`test/agent-preset.test.ts` 29 例全绿(新增「检测到不兼容就停、不适配」的用例,同时断言两份副本里 R-T / `team_task_*` / `wait_agent()` / 「说明你是子代理或 teammate」等降级措辞**一个都不剩**);全量 `npm test` **223 passed | 1 skipped(224 文件)、3706 passed | 7 skipped | 1 failed**——唯一失败是 `test/claude-oauth.test.ts` 的「占用端口时报告真实绑定的那个端口」,单跑该文件 43/43 通过。本轮三次全量里出现过两个**不同**的环境敏感用例偶发(本次是端口占用,上一轮是 `antigravity-token-store` 的真实 DPAPI 写入),二者都只依赖真实 OS 资源、与本次 diff 无交集;此前一次全量基线为 3708 passed | 0 failed,差的 2 例来自被合并掉的 teammate 词汇用例。
18
+ - **[调度模式] 新增规则段 R-W「回合边界」,一次修掉三处现场问题:占位长命令等待、目标续跑打断等待、需要拍板时用文字停下**
19
+ - **问题 1(等待 = 自己造一个)**:派出子代理后,模型会去跑一条长时间命令挂着等(`sleep`、轮询、`watch`)。子代理完成的通知本来就是自带的,这条命令换回来的信息量是零,却实打实烧掉上下文与预算,还把用户晾在一段沉默里。
20
+ - **问题 2(目标把等待从中间劈开)**:部分模型在任务开头主动创建目标。目标一旦激活,DSH 会自动续跑把主代理叫醒,而子代理何时返回不由它控制——于是主代理在半路被续跑打断,重新分诊、重新检查「还差什么」,一次干净的等待被拆成两段,附带每次续跑都要重载整段历史。
21
+ - **问题 3(该问的不问,该停的用文字停)**:收到子代理全部内容后需要用户决策时,模型用一段文字结尾就停下,等用户自己把那段话翻译成一次输入。提问本是代理的工具,不该转嫁给用户。
22
+ - **修法**:新增编号规则段 `R-W · 回合边界(等待 / 目标 / 提问)`,三件事放在一起是因为它们都落在回合边界上。① 等待:默认结束本轮回复、一个工具都不调,由完成通知唤醒;禁止 `sleep`/轮询/`watch` 等占位长命令;确实被阻塞时才用 `job_output({ wait: true })` 有界地等一次(teammate 模式对应 `wait_agent()`),并在停下前说清「派出去了谁、在等什么、拿到证据要做什么」。② 目标:除非用户明确要求,不调用 `create_goal` / `/goal`,任务清单一律落 `todo_write`(R7 同步改了措辞)。③ 提问:一切「我停在这里是因为缺一个决定」的停点都用 `ask_user_question` 递出去,含选项、推荐答案与自定义输入口子;例外只有 plan mode 的计划审批(走 `exit_plan_mode`)与任务完成后的收尾。
23
+ - **交叉引用**:反模式列表新增第 13–15 条,逐条对应上面三件事;`R-G` 的 G3 补一句「同一条要求覆盖访谈之外的每一个停点」;【角色识别】把 `R-W` 列入面向调度者、对子代理/teammate 不生效的规则清单。
24
+ - **两份副本**:persona 在 `src/host/agent-preset.ts`(0.1.7+ 运行时注册的声明)与 `presets/dispatch/agent.cordis.yml`(0.1.6 及以前的文件同步)里各存一份,`test/agent-preset.test.ts` 逐字节校验二者一致,因此本次两处同步修改;测试新增 1 例(30 例),文档同步更新 `presets/dispatch/README.md` 与根 `README.md`。
25
+ - **验证**:`npm run typecheck` 0 错误;`npm test` **223 passed | 1 skipped(224 文件)、3708 passed | 7 skipped | 0 failed**;`test/agent-preset.test.ts` 由 29 例增至 30 例(新增 1 例断言 R-W 的三条规则与反模式 13–15)。首次全量运行时 `test/antigravity-token-store.test.ts` 的真实 DPAPI 用例在并行下失败 1 次,单跑该文件(8/8)与第二次全量均全绿,属既有的偶发;本次 diff 只涉及 preset 文本、文档与该一个测试文件,与凭据存储无交集。
26
+ - **[Antigravity] 模型目录与路由对齐线上 `fetchAvailableModels`(2026-10-12 快照)**
27
+ - **目录**:删除已下线的 Claude Opus 4.6 / Sonnet 4.6(目录里 Claude 只剩 5.5);Gemini 3.7 Flash 改用目录中真实存在的 `-low/-medium/-high`,不再走未列出的 `gemini-3.7-flash-tiered`;修正 Gemini 3.5 Flash 错位一档(官方 “(Low)” 是 `extra-low`,选 low 原先拿到的是 Medium);新增 Gemini 3.5 Flash Lite、Gemini 3.1 Flash Lite;目录过滤掉 `tab_*` 编辑器补全模型。
28
+ - **生图模型下架**:`gemini-3.1-flash-image` 的产出是图片,而 Harness 只接受纯文本的助手输出(dsh-llm `ImageBlock` 注释),聊天线路只能丢掉图片;应改为图片生成工具承载。
29
+ - **不再静默跨模型降级**:每次请求只发用户所选模型对应的一个运行时 ID。原先 404/429 会悄悄换到 `off` 档或别的模型(3.8 → 3.7 → 3.6、3.1 Pro High → Low),用户拿到的并不是自己选的模型。
30
+ - **429 按配额族冷却**:Gemini 与 “Claude and GPT” 是分开计量的配额,一族耗尽不再让该账号另一族一起停用 15 分钟;冷却时长优先读 Google 错误体里的 `quotaResetTimeStamp` / `quotaResetDelay` / `RetryInfo.retryDelay`,最后才用 `Retry-After`。
31
+ - **Gemini 2.5 思考预算按模型收敛**:Flash/Lite 上限 24576(原先 high 发 32768),Pro 下限 128 且不能关闭。
32
+ - **异常结束原因不再当作正常结束**:`SAFETY`、`RECITATION`、`PROHIBITED_CONTENT`、`MALFORMED_FUNCTION_CALL` 等,以及 `promptFeedback.blockReason`(提示被拦截),都改为 error finish 并附上上游 `finishMessage`;原先会以空回复结束本轮。
33
+ - **[Antigravity] 新增生图工具 `antigravity_image_generate`(同 Codex 生图工具的形态)**
34
+ - 走已登录的 Antigravity 账号池调用 `gemini-3.1-flash-image`,参数 `prompt`(必填)与可选 `aspectRatio`;返回图片存为附件、渲染为图片块,嵌套调用时以 notice 注入下一轮请求。客户端复用 Codex 的生图卡片。
35
+ - 计入 Gemini 配额族:429 只冷却该账号的 Gemini 配额并换下一个账号;Antigravity 线路关闭时工具拒绝执行。
36
+ - 返回图片在入库前校验媒体类型白名单、base64、大小上限与文件头魔数,`thought: true` 的草稿图被跳过;无图时把 `finishReason` 与模型文字一并报出。
37
+ - **[Antigravity] Claude 工具调用使用 `VALIDATED` 模式**:带工具且未显式指定 `toolChoice`(或为 `auto`)的 Claude 请求发送 `functionCallingConfig.mode: VALIDATED`,显式 none/any 不变;Gemini 不受影响。若服务端以 400 拒绝该模式,同一模型去掉 `toolConfig` 重试一次,并在本进程内不再发送(协议回退,不换模型)。
38
+ - **[Antigravity] 上下文/输出上限改为优先读 `fetchAvailableModels`**:目录条目解析 `maxTokens`(或 `inputTokenLimit`)与 `maxOutputTokens`(或 `outputTokenLimit`),兼容 int64 字符串;一个可选模型对应多个运行时 ID 时取最小值,目录缺失时回落内置表;用户覆盖值仍然优先,设置页「默认上下文」随之一致。
39
+ - **诚实声明**:生图请求的 `requestType: 'image_gen'`、Claude 对 `VALIDATED` 的接受情况、目录上限字段名,均来自社区客户端与公开文档,**没有**用真实账号抓包或实测;三处都留了回退(生图失败如实报错、VALIDATED 被拒自动回退、字段缺失回落内置表)。
40
+
41
+ ## 0.23.0 - 2026-10-13
42
+ - **[Ollama] 思考档位从「猜白名单」改为「读模型自己声明的事实」,并接通设置页的默认档位(用户报障:ollama 线路缺少模型思考档位选择器)**
43
+ - **问题(三层各缺一环,不是 UI 漏做)**:本插件其余每条线路都在 `adapter.resolveModel()` 里返回 `reasoning: { efforts, defaultEffort }`,Harness 的模型选择器只在拿到它时才渲染档位下拉——Ollama 是唯一不返回的线路,所以下拉根本不出现。而 Harness 侧的行为不是「静默忽略」而是硬拒绝:`resolveCallWithInfo` 在 `reasoning === undefined` 且调用方传了 `reasoningEffort` 时抛 `UNSUPPORTED_REASONING_EFFORT`。同时设置页的 `defaultReasoningEffort` 是一个**写进去就没人读的死字段**——`token-store.ts` 读写完备,但 `/settings` 路由只处理 `enabled`,卡片没有下拉,`OllamaWebStatus` 里也没有这个字段。
44
+ - **第一处:档位阶梯改为由模型元数据驱动**。`POST /api/show` 返回的顶层 `thinking: { values, default }` 是该模型**唯一一处**自述其 `think` 接受值的来源(官方 thinking.mdx 逐字)。新增 `fetchModelThinking()` 读取它,`reasoningEffortsForModel()` 据此构建阶梯;原有的 `gpt-oss` / `deepseek-r1` / `qwq` / `qwen3` 四个前缀白名单**降级为回退**——只在元数据读不到时使用,无 `declared` 时行为逐字不变。于是白名单之外的家族(如 `glm-4.6:cloud` 若声明 `['low','high']`)也能拿到自己的正确阶梯。
45
+ - **第二处(本轮最关键的缺陷,验收阶段抓出并退回返工)**:档位集合与 wire 取值曾由**两张不同的表**产生——集合走 `reasoningEffortsForModel`,取值走 `thinkForModel`——于是对声明 `values: [true]` 的模型(支持思考、**不允许关闭**),集合仍无条件给出「关闭思考」位置,选中后发出 `reasoning_effort: 'none'`,而官方文档明写 `"none"` 请求 `false`:**等于对一个明确声明不接受 `false` 的模型发了 `false`**。同源漏洞是混合声明 `['low','high',false]` 被判成 `levels` 后 `false` 被字符串分支静默丢弃,该位置**选了什么也不发**。修法不是加特例,而是让正反两向由**同一张表** `{ value, id, name }` 导出:`true` → 开启思考、`false` → 关闭思考、字符串原样保留拼写与声明顺序。`values:[true]` 因此不再提供关闭位,`['low','high',false]` 则三项齐全且各自发出正确的 wire 值。
46
+ - **第三处:接通设置页默认档位**。`OllamaWebStatus` 增加 `defaultReasoningEffort`,`/settings` 与 `/models` 两个分支接受并校验它(只收 `null` 或四档词表,越界返回 400;校验前置到写入之前,避免带多个字段的请求被半应用),客户端新增 `setDefaultReasoningEffort()` 与一个下拉框,`null` 是「不指定」这一可撤销的真实取值而非缺省。
47
+ - **降级纪律**:探测的每一种失败形态(无凭据 / 网络错 / 401 / 500 / 代理 HTML / 结构不符 / 空 values)都返回 `undefined` 且**绝不抛错**——读不到元数据只是「少一个阶梯」,不能让设置页或聊天链路出错。请求侧同理:目标模型表达不出的档位**只丢档位、不丢回合**。探测按 modelId 记忆化(仅成功才缓存,并发合并为一次),且在 `requestStream` 内**惰性**发起——无条件探测会读空 `test/stream-activity-idle.test.ts` 手工喂的心跳流,该用例会变红(此约束写在 `adapter.ts` 注释里)。
48
+ - **验证**:`npm run typecheck` 0 错误;全量 `npm test` 220 passed | 1 skipped(221 文件)、**3670 passed | 7 skipped | 0 failed**。新增 `test/ollama-thinking.test.ts`(24 例,覆盖 `[true]` 无关闭位、两种布尔声明顺序、混合声明三位置各自的 wire 值、8 种探测失败形态、记忆化与并发合并、`:cloud` 后缀命中)与路由/卡片各 7 例。既有 20 例中 19 例一字未改;1 例按新语义重新锚定(`drops an unexpressible stored level...`:原断言 `reasoning_effort === 'auto'`,那正是「把 high 强扭成 true」的旧特例,改为 `toBeUndefined()`——新值更严格,用例主张不变)。
49
+ - **独立验证**:调度者另写一次性用例断言最强不变量——「每一个被提供的档位都能反查回一个声明过的 wire 值」,7/7 通过后删除。
50
+ - **诚实声明**:全部证据来自官方文档与桩测,**没有**对真实 Ollama Cloud 账号实测过各模型的 `/api/show` 返回;「档位会正确出现」是由文档加 444 例桩测推出的结论,不是眼见为实。
51
+
52
+ - **[GLM(ZCode 账号)] 删除客户端签名层(Client Signing V4),并把四条外部证据补进 README 已知限制**
53
+ - **问题**:签名层以「实现了但默认关闭 + 能力门控」的形态长期留在生产路径上——`signing.ts`、契约里的能力位、`DSH_GLM_*` 开关一应俱全,README 也照此写着「默认关、需要显式打开」。它本身是 C 级证据(社区经验 / 架构推断,无实测),按本仓库规则 C 级「不得进入默认路径」;而这一次连一份**能证明自己有用**的证据都没有。
54
+ - **后果**:一个逆向来的签名算法(移植自 MIT 的 `zcode-signer.ts`)留在仓库里、留在能力清单里、留在环境变量表里,此后每一轮改动都要再回答一次「这个开关要不要动」。唯一有实测记录的项目做过 A/B 对照,**带签名与不带签名的响应归一化后完全一致**(都是 429/1113);官方那个本可当作开关信号的 feature gate 端点 `/api/v1/agent/configs` **根本不校验凭据**,两类凭据拿到逐字相同的响应,答不了「签名是否启用」。README 里那句「默认关、需要显式打开」还会让读者以为存在一个可开启的官方机制。
55
+ - **修法**:**整层删除**——生产路径上不再有任何签名接线、能力门控或环境变量入口,能力清单里的对应条目一并去掉。**没被证明的那一半照记不误**:服务端是否真会因为缺签名返回签名错误,至今从未被观察到;这不是「已验证不需要签名」,而是「从未验证过」,两者的区别不因为实现被删掉而消失。
56
+ - **文档**:四条有外部证据的事实补进 README 的「已知限制」,逐字引用并注明来源与证据等级:① 签名层**已删除**及其依据(实测 A/B 归一化一致 + 官方 gate 不校验凭据);② 资源包 / 充值余额与套餐额度**互不消耗**,资源包的入口是通用面 `/api/paas/v4` + 开放平台 API Key,本线路不接(官方配置页 zcode.z.ai/cn/docs/configuration 逐字);③ 免费体验额度的**逐模型构成**(GLM-5.3 300 万 token / 日、GLM-5.3-Flash 500 万 token / 日)与**时限**(仅限 5 天、过期不再补发,官方配置页逐字);④ 本线路**直连** `api.z.ai/api/anthropic`,而官方客户端在 fetch 层把它重写到 `/api/v1/ultra*` 托管网关(官方开源仓库逐字),因此记为观察项而非缺陷。
57
+ - **测试**:删除 `test/glm-coding-plan-signing.test.ts`(原 514 行);不新增用例——被删掉的是一整条能力,生产面随之消失,没有留下需要新覆盖的分支。
58
+ - **验证:`npm run typecheck` 0 错误;全量 `npm test` 219 passed | 1 skipped(220 文件)、3632 passed | 7 skipped | 0 failed。** 改动前基线为 221 passed | 1 skipped(221 文件)、3653 passed | 7 skipped(3660):减少的 21 例与 1 个文件正是被删掉的 `test/glm-coding-plan-signing.test.ts`(21 例 / 514 行),其余用例计数未变。
59
+
5
60
  ## 0.22.0 - 2026-10-12
6
61
  - **[WorkBuddy / 共享号池] 非鉴权的 403 不再误杀整个账号池;「全部账号不可用」不再伪造 429 与 15 分钟冷却(issue #53)**
7
62
  - **问题 1(403 一律=凭据失效)**:WorkBuddy 的 `classifyFailure` 只看状态码,`401 || 403` 无条件返回 `INVALID_CREDENTIAL`。代理 / lane 策略 / 同 lane 其它插件合成的应用层拒绝(issue 给出的实测体:`{"error":{"type":"server_error","code":"dsh_compaction_refused","retryable":false}}`)因此被当成 token 失效,账号池把**每一个**账号依次 `markAuthFailed` → `authStatus="expired"`——拒绝属于 lane 而不属于某个账号,所以三个账号无一幸免——此后每个请求在发出前即失败,且**不会自愈**,只有重新登录才能恢复。
package/README.md CHANGED
@@ -452,7 +452,7 @@ DSH 模型选择器应显示 **“Codex(ChatGPT 订阅)”**。GPT-6 系列
452
452
 
453
453
  > 路径解析不写死相对路径:`src/host/preset-sync.ts` 从模块位置向上查找最近的 `package.json` 作为包根,因此 `src/` 布局、打包后的 `lib/` 布局,以及通过 pnpm symlink / Windows junction 安装都能正确解析。注意 `fs.cpSync({ recursive: true })` 在 Node 22 + Windows 上遇到含非 ASCII 的源路径会直接崩进程(nodejs/node#54476),所以复制是逐条目实现的。
454
454
 
455
- ### 协作模式自适应(teammate / subagent)
455
+ ### 与 Agent Teams 不兼容(刻意互斥)
456
456
 
457
457
  DSH 的 Agent Teams(bundle `@deepseek-ai/dsh-experimental-agent-team-profile`)会在**每个会话自己的作用域**里注册一套与内置**同名**的协调工具。工具注册表按作用域链解析、**近的层遮蔽远的层**,所以一旦该 bundle 被组合进来,会话里的 `send_message`、`list_agents`、`interrupt_agent` 就都换成了 teammate 版:
458
458
 
@@ -460,18 +460,42 @@ DSH 的 Agent Teams(bundle `@deepseek-ai/dsh-experimental-agent-team-profile`
460
460
  - `send_message` 的 `target` 只接受成员名,把子代理的 session id 传进去会抛 `active teammate "…" not found`(实测);
461
461
  - 于是「派得出去、回访不了」——`subagent` 的孩子只能等完成通知,无法追问。
462
462
 
463
- `dispatch` preset 现在**每个任务开始时先侦测一次协作模式**(persona 的 R0.5),再按模式选择协调词汇(R-T):
463
+ **坏消息在时机上**:Agent Teams 的 `agent-team/src/roster.ts` 里 `tryMembership` 对任何「无 `parentSession`、且不是 subagent descriptor」的 Agent 直接判为 `lead`,**不需要先有 teammate**。于是 team 工具从会话第一轮起就装在 Lead 上,调度模式还没派发第一个子代理,复审与返工所依赖的三个工具已经没了。
464
464
 
465
- | 侦测为 | 判据 | 协调词汇 | 派发 |
466
- |---|---|---|---|
467
- | teammate | `spawn_teammate` / `wait_agent` 存在 | `list_agents()`、`send_message({ target: <成员名> })`、`wait_agent()`、`team_task_*` | `spawn_teammate`(无路由参数,继承主代理路由)或 `subagent`(按 R2 显式路由) |
468
- | subagent | 二者都不存在 | `list_agents()`、`send_message({ agent_id })`、`interrupt_agent` | `subagent` / `subagent_fork` |
465
+ 上游对此的立场是明确的:`tool-agent-team` 的文档写着「当同名的旧全局 subagent 工具必须继续可用时,请不要选择……**想同时使用两者的组合必须禁用旧定义**」。而 `dispatch` preset 恰恰是那组旧定义的持有者——0.1.7+ 的运行时注册里由本插件自己挂了 `tool-subagent-control` / `tool-subagent-list-agents` / `tool-subagent` / `tool-subagent-fork` 四行(preset 每一代都是独立 `createScope`,与宿主组合里被 profile patch 置 `disabled` 的那四行不是同一批实例)。所以这不是「可以调好的配置」,而是一个上游明确不承诺的组合。
469
466
 
470
- 两种模式下 R0 分诊、R1 职责边界、R3 自治、R6 验收都照常执行;**模型路由守卫(`subagentModelAuthorization`)不变**——它默认把 `spawn_teammate` 与 `subagent_fork` 同为 **inherit 模式**(见下),校验的是成员实际继承到的路由,而不是要求它给出并不存在的路由参数。
467
+ `dispatch` 的处理是**停,不降级**(persona 的 R0.5 兼容性闸门,每个新会话判一次,早于 R0 分诊):
471
468
 
472
- > **不要**把 `spawn_teammate` 加进 `subagentModelTools`。该列表是 **explicit** 模式:要求每次调用成对给出 `provider` + `model`,而 `spawn_teammate` 的参数里根本没有这两个字段(DSH 设计如此:成员一律继承 Lead 的路由),结果是每一次 teammate 创建都会被硬拒,且模型无法通过补参数自救。它的正确归属是 `subagentModelInheritTools`(默认已包含)。
469
+ | 判据 | 行为 |
470
+ |---|---|
471
+ | `spawn_teammate` 与 `wait_agent` 都不存在 | 编排可用,写一行「编排可用:subagent」后按 R0 → R-G → R5 → R6 正常走 |
472
+ | 任一存在 | 本会话**不可编排**:一句话说明 → 一次 `ask_user_question` 给出三条出路 → 用户答复前**不分诊、不规划、不派发、不动文件** |
473
473
 
474
- ### 已知上游限制:teammate 不能选模型
474
+ 三条出路是:① 关掉 Agent Teams bundle、重启 Host 后**新建会话**;② 换用别的 preset,本会话不编排;③ 本次直接做,不进编排流程。**都要新建会话**——工具面在会话启动时就定死了,改完配置在旧会话里也不会回来。
475
+
476
+ 刻意**没有**保留「切到 teammate 词汇继续编排」这条分支(原 R-T)。三条理由:
477
+
478
+ 1. 遮蔽由 scope 链决定,persona 改不回工具注册表——「适配」只能改行为,改不了「哪些工具被顶替」这个事实;
479
+ 2. 那条分支把「回访不了」从**明摆着的失败**变成**看不见的失败**:roster 里查不到孩子 ≠ 孩子没了,模型会误判并重复派发,白烧一轮预算;
480
+ 3. teammate 结构上拿不到 per-task 路由(见下节),而 R2 显式路由正是这套设计里最值钱的部分——组队等于自愿放弃它。
481
+
482
+ > 想把误用也用机制挡掉:把 `spawn_teammate` 从 inherit 清单去掉即可,配置 `subagentModelInheritTools: ['subagent_fork']`,该工具在守卫里就变成**硬拒**(拒绝理由指向 `subagent`),而不是让它悄悄按 Lead 的路由跑完整轮。插件默认值不动——那是全局设置,改它会波及不使用调度模式的会话。
483
+
484
+ ### 回合边界纪律(R-W)
485
+
486
+ 调度模式的 persona 里有一条专门管「回合边界」的规则 `R-W`,约束三件最容易把编排拖慢、拖贵的事:
487
+
488
+ | 场景 | 规则 | 为什么 |
489
+ |---|---|---|
490
+ | 等子代理返回 | 默认**结束本轮回复**、一个工具都不调,由完成通知唤醒主代理;禁止 `sleep`、轮询循环和任何只为占位存在的长命令。确实被阻塞时才用 `job_output({ wait: true })` 有界地等一次 | 子代理完成通知是自带的;占位长命令不产出信息,只烧上下文和预算,还把用户晾在一段沉默里 |
491
+ | 任务开始建目标 | 除非用户明确要求,否则**不调用 `create_goal` / `/goal`**,任务清单一律走 `todo_write` | 机制性的:目标一旦激活,DSH 会自动续跑唤醒主代理,而子代理何时返回不由它控制——等待被从中间劈开,模型重新分诊、重新检查「还差什么」,每次续跑还要重载整段历史 |
492
+ | 需要用户拍板 | 一切「我停在这里是因为缺一个决定」的停点(收到子代理结果要选下一步、验收不过要定返工范围、前提被推翻要改计划)都用 `ask_user_question` 递出去,并给出选项与推荐答案 | 提问是代理的工具,不是用户的义务:否则用户得先替模型把那段话翻译成一次输入。例外是 plan mode 的计划审批(走 `exit_plan_mode`)与任务完成后的收尾 |
493
+
494
+ 三条各自对应 persona 反模式列表里的第 13–15 条。
495
+
496
+ ### 为什么不降级:teammate 不能选模型
497
+
498
+ 这是上面第三条理由的技术底座,也是上游修好之后才谈得上重新评估兼容性的前提。
475
499
 
476
500
  `spawn_teammate` 目前**无法**指定 `provider`/`model`,这不是插件的问题,而是 Agent Teams 有意不做 per-teammate 路由。三层都已核对:
477
501
 
@@ -485,7 +509,7 @@ DSH 的 Agent Teams(bundle `@deepseek-ai/dsh-experimental-agent-team-profile`
485
509
 
486
510
  **插件侧无法绕过**,四条路都已验证死:pre-execute 明确排除输入改写(参数已被记录与呈现,`PreToolDecision` 只有 allow/deny/cancel/ask);`agentTeams` 服务在内部丢弃后包装不到;注册自定义 subagent provider 也拿不到路由(`agentOptions` 在 continuation manager 就已解析完,provider 只返回 `seed`);唯一能改子会话路由的 `selectForNextRequest` 只作用于「下一个请求」,而 teammate 创建后立刻开跑,抢不进去。
487
511
 
488
- **上游正路**:在 `packages/experimental/agent-team/src/roster.ts` 构造 `startContinuable` 的 `request` 处补上 `agentOptions`,并给 `SpawnTeammateRequest` 加字段、给工具 schema 加参数、创建前接 `assertAllowedModelSelection`。**该改动落地后**,`spawn_teammate` 就应从 `subagentModelInheritTools` 移到 `subagentModelTools`(explicit)——否则它会变成「能选模型却没人管」。
512
+ **上游正路**:在 `packages/experimental/agent-team/src/roster.ts` 构造 `startContinuable` 的 `request` 处补上 `agentOptions`,并给 `SpawnTeammateRequest` 加字段、给工具 schema 加参数、创建前接 `assertAllowedModelSelection`。**该改动落地后**,`spawn_teammate` 就应从 `subagentModelInheritTools` 移到 `subagentModelTools`(explicit)——否则它会变成「能选模型却没人管」。只补这一条还不足以解除互斥:team 工具的遮蔽发生在会话第一轮(见上节),要真正共存还需要把安装条件从「是 team 成员」收紧成「**有 teammate**」,让没有队友的会话保留内置的 subagent 协调工具。
489
513
 
490
514
  > 实践提醒:inherit 模式校验的是**当前会话路由**。若当前会话跑在允许清单之外的路由上(例如默认模型与勾选清单不是同一条),teammate 与 `subagent_fork` 都会被拒绝——拒绝文案会指出恢复路径(改用显式路由的 `subagent`,或先把会话切到清单内的模型)。`subagent` 的显式路由不受影响。
491
515
 
@@ -860,9 +884,12 @@ access token / refresh token / 授权码 / PKCE verifier**;诊断里提到某
860
884
  确切错误码与重置节奏;
861
885
  - 「闲时任务」类免费算力(welcome 页所述)本线路**未接入**,它属于另一条调度路径。
862
886
  - **上游没有 refresh_token 交换接口。** 官方客户端对刷新直接抛「OAuth 暂未提供 refresh token 交换接口,请重新登录」。因此 `access_token` 过期**只能重新登录**;插件能自动重取的只有业务 JWT 这一层(提前 120 秒 + 0~60 秒抖动防尖峰),而且**它只服务国际区**。账号行上的「重新登录」在 host 这一侧只做两件事:撤掉鉴权失败标记与冷却,让这一行重新参与轮转;真正的登录要由卡片再开一次流程。
863
- - **客户端签名层(Client Signing V4)默认关闭。** 唯一有实测记录的项目做过 A/B 对照:**带签名与不带签名的响应完全一致**(都是 429/1113),从未观察到服务端因为缺签名而拒绝请求。没有证据表明缺签名会被拒时,默认开启一个逆向来的签名算法只会平白增加故障面,因此它默认关、需要显式打开。反过来,**服务端是否真会因为缺签名返回签名错误,至今从未被观察到**——这条不是「已验证不需要签名」,而是「从未验证过」。
887
+ - **客户端签名层(Client Signing V4)已从本线路删除——不是默认关闭,也没有可显式打开的开关。** 生产路径上不再有任何签名接线、能力门控或环境变量入口,一个逆向来的签名算法连同它自己那份故障面一起被移除。删它的理由是它**从未有过能支撑上线的证据**:唯一有实测记录的项目做过 A/B 对照,**带签名与不带签名的响应归一化后完全一致**(都是 429/1113),从未观察到服务端因为缺签名而拒绝请求;而官方那个本可当作开关信号的 feature gate 端点 `/api/v1/agent/configs` **根本不校验凭据**——两类凭据拿到逐字相同的响应,所以它答不了「签名是否启用」,拿它当证据等于把一份不区分凭据的响应读成了区分。留下这条限制是为了同时记着**没被证明的那一半**:服务端是否真会因为缺签名返回签名错误,**至今从未被观察到**——这不是「已验证不需要签名」,而是「从未验证过」,两者的区别不因为实现被删掉而消失。
888
+ - **资源包 / 充值余额与套餐额度互不消耗,本线路两边都碰不到用户充的钱。** 官方文档 zcode.z.ai/cn/docs/configuration 把资源包写成**与 Coding Plan 并列的另一个入口**:一节标题就是『资源包 / 充值余额』,正文『使用开放平台模型资源包或充值余额等通用 API 场景,填写 OpenAI 接口地址即可』,给的地址是通用面 `https://open.bigmodel.cn/api/paas/v4`(国际区 `https://api.z.ai/api/paas/v4`)。同一页逐字:『Anthropic 接口不适用于资源包 / 余额场景:只有从未购买过 Coding Plan 的账号,走 Anthropic 接口时才会消耗余额;只要买过套餐(无论是否用完、是否到期),该接口都不会走余额,需要额外加白处理』;『Coding 端点仅限 Coding 场景,与通用端点不可互相替代,也不会互相消耗额度』。因此本线路的模型面(Anthropic)与套餐面在结构上就不触及资源包:**资源包的入口是上面那个通用面,凭据是开放平台的 API Key**——官方在这一节的措辞是「API Key 模式」,与「编程套餐」授权绑定账号的**非 API Key 模式**相对,**不是本线路换出来的那把 Coding Plan Key,本线路根本不接这类 Key**。用户在这条线路上**不会**误烧充值余额;要确实用资源包,请走 DSH 自带的「自定义模型 API」,那是另一个面、另一把 Key。
889
+ - **免费体验额度的逐模型构成与时限(只补上一条已有条目没写的两项,不重复它)。** 上一条只写了体验额度存在,没写它由哪几个模型、各多少、什么时候失效。官方配置页(逐字:zcode.z.ai/cn/docs/configuration):『每日体验额度由两类模型额度组成…… GLM-5.3 300 万 token / 日;GLM-5.3-Flash 500 万 token / 日』;『注意:体验额度仅限 5 天。每日额度只在这 5 天内发放,体验期结束后即失效,并非长期每天都有』。两者相加正好是那句「每天 800 万 token」——但**这是两个模型各自的份额,不是所有 GLM 模型共享的一口池子**,也只有 GLM-5.3 / GLM-5.3-Flash 沾得到;体验期一过额度**不再补发**,卡片上「免费体验额度」那一档不能读成长期权益。**仍未验证(拿到账号后请先复验)**:这两个日额度用尽后服务端返回的确切业务码、以及每日重置发生在什么钟点,仍没有实机样本。
890
+ - **与官方路径的形态差异:本线路直连 `api.z.ai/api/anthropic`,官方客户端却在 fetch 层把同一个 URL 重写到托管网关。** 官方开源仓库 `zai-org/ZCode` 的 `apps/zcode-cli/packages/adapters/src/model/official-coding-plan-gateway.ts` 里,`GATEWAY_PATH_BY_ENDPOINT` 把 `'https://api.z.ai:443/api/anthropic/v1/messages'` 映射到 `'/api/v1/ultra-zai/anthropic/v1/messages'`、把 `'https://open.bigmodel.cn:443/api/anthropic/v1/messages'` 映射到 `'/api/v1/ultra/anthropic/v1/messages'`。也就是说官方那一侧**不打这个基址**,而是在 fetch 层改写到 `/api/v1/ultra*` 网关前缀下;本线路照抄的是前一个形状。这记为**观察项而不是缺陷**:两个独立的第三方实现直连该基址都成功过(能拿到 1113 业务码恰恰说明认证这一关已经过了),而网关前缀是官方托管面自己的编排,本线路不复刻它、也不需要它。**仍未验证**:托管网关是否会在某些请求特征上施加通用面没有的额外策略。
864
891
  - **国区兑换链未验证。** 证据来自三个社区实现(等级 B,逆向实测而非官方契约),三者**都以国际区为主**,国区业务面的形状是否同构没有实测样本。国区兑换失败会带上明确说明与下一步建议(改用国际区,或用 `DSH_GLM_CN_BUSINESS_HOST` 等环境变量指向实测过的部署),**不静默失败**。同理,国区配额到底打 `bigmodel.cn` 还是官方文档里那句「亦可用 `open.bigmodel.cn`」也没有实测,本插件取 `bigmodel.cn`。
865
- - **兑换链的所有端点都可用 `DSH_GLM_*` 环境变量覆盖**(两区的业务 host、模型面 host、授权入口、appId / client_id、Key 名、OAuth 控制面基址,签名层开关也在其中)。这是为等级 B 的兑换链准备的退路:上游一次变更让整条链失效时,回滚是改一个环境变量,而不是发一个版本。
892
+ - **兑换链的所有端点都可用 `DSH_GLM_*` 环境变量覆盖**(两区的业务 host、模型面 host、授权入口、appId / client_id、Key 名、OAuth 控制面基址)。这是为等级 B 的兑换链准备的退路:上游一次变更让整条链失效时,回滚是改一个环境变量,而不是发一个版本。
866
893
 
867
894
  ## Step Code(Step Plan 订阅)线路
868
895
 
package/lib/client.js CHANGED
@@ -58,6 +58,14 @@ window.__ModuleLoader__.load({
58
58
  const ROUTE_PREFIX = "/api/dsh-chatgpt-subscription";
59
59
  const CODEX_CHATGPT_PROVIDER_ID = "codex-chatgpt";
60
60
  const CODEX_IMAGE_TOOL_NAME = "codex_image_generate";
61
+ /**
62
+ * The Antigravity image tool and the runtime it calls.
63
+ *
64
+ * `gemini-3.1-flash-image` is listed by `fetchAvailableModels`, but its product
65
+ * is an image and the harness accepts text-only assistant output, so it is
66
+ * served as a tool (like Codex images) rather than as a chat model.
67
+ */
68
+ const ANTIGRAVITY_IMAGE_TOOL_NAME = "antigravity_image_generate";
61
69
  //#endregion
62
70
  //#region src/client/common/use-store.ts
63
71
  /**
@@ -3511,7 +3519,7 @@ window.__ModuleLoader__.load({
3511
3519
  * Display label per reasoning level. The locale dictionary only accepts flat
3512
3520
  * string values, so this nested table lives with the control that renders it.
3513
3521
  */
3514
- const EFFORT_LABELS$2 = {
3522
+ const EFFORT_LABELS$3 = {
3515
3523
  none: "Off",
3516
3524
  minimal: "Minimal",
3517
3525
  low: "Low",
@@ -3995,7 +4003,7 @@ window.__ModuleLoader__.load({
3995
4003
  children: t.defaultEffortAuto
3996
4004
  }), COMMAND_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3997
4005
  value: effort,
3998
- children: EFFORT_LABELS$2[effort]
4006
+ children: EFFORT_LABELS$3[effort]
3999
4007
  }, effort))]
4000
4008
  })]
4001
4009
  })]
@@ -5912,7 +5920,7 @@ window.__ModuleLoader__.load({
5912
5920
  * Display label per reasoning level. The locale dictionary only accepts flat
5913
5921
  * string values, so this nested table lives with the control that renders it.
5914
5922
  */
5915
- const EFFORT_LABELS$1 = {
5923
+ const EFFORT_LABELS$2 = {
5916
5924
  minimal: "Minimal",
5917
5925
  low: "Low",
5918
5926
  medium: "Medium",
@@ -6228,11 +6236,11 @@ window.__ModuleLoader__.load({
6228
6236
  }),
6229
6237
  strayEffort !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6230
6238
  value: strayEffort,
6231
- children: `${EFFORT_LABELS$1[strayEffort]} (${t.effortUnsupported})`
6239
+ children: `${EFFORT_LABELS$2[strayEffort]} (${t.effortUnsupported})`
6232
6240
  }) : null,
6233
6241
  effortChoices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6234
6242
  value: choice.value,
6235
- children: choice.models.length === allModels.length ? EFFORT_LABELS$1[choice.value] : `${EFFORT_LABELS$1[choice.value]} (${choice.models.length}/${allModels.length})`
6243
+ children: choice.models.length === allModels.length ? EFFORT_LABELS$2[choice.value] : `${EFFORT_LABELS$2[choice.value]} (${choice.models.length}/${allModels.length})`
6236
6244
  }, choice.value))
6237
6245
  ]
6238
6246
  })]
@@ -7822,7 +7830,7 @@ window.__ModuleLoader__.load({
7822
7830
  saved: "已保存",
7823
7831
  invalidCapacity: "容量格式无效:{value}",
7824
7832
  quotaSection: "用量与配额",
7825
- quotaDesc: "数据来自 Coding Plan 的配额接口(该接口用裸 Key 鉴权,不加 Bearer)。",
7833
+ quotaDesc: "数据来自 Coding Plan 的配额接口,页面可见时最多每 60 秒刷新一次。",
7826
7834
  quotaRefresh: "刷新用量",
7827
7835
  quotaRefreshing: "刷新中...",
7828
7836
  quotaSignedOut: "未登录,先在上方完成登录授权。",
@@ -7832,14 +7840,13 @@ window.__ModuleLoader__.load({
7832
7840
  quotaRenews: "续费时间",
7833
7841
  quotaReadAt: "读取时间",
7834
7842
  quotaSources: "数据源",
7835
- quotaWindowNames: "窗口名按窗口长度本地化(5 小时 / 1 周 / 1 月),不在本页硬编码;每个账号自己的进度条画在它的账号卡片里。",
7836
7843
  quotaRefreshingNote: "正在后台刷新配额,下方是上一次读到的数字。",
7837
7844
  quotaErrorLabel: "配额读取失败",
7838
7845
  quotaAllowance: "额度类型",
7839
7846
  quotaAllowancePlan: "付费套餐",
7840
7847
  quotaAllowanceFreeTrial: "免费体验额度",
7841
7848
  quotaAllowanceUnknown: "未判定",
7842
- quotaAllowanceHint: "登录时探活认定的额度来源。「免费体验额度」按官方文档指新用户注册即自动获得、首次使用起 5 天内每天 800 万 token 的体验额度;额度耗尽时由上游返回 429,本线路不预判。"
7849
+ quotaAllowanceHint: "登录时探活认定的额度来源。「免费体验额度」指新用户注册后自动获得、首次使用起 5 天内每天 800 万 token 的体验额度。"
7843
7850
  };
7844
7851
  const en$4 = {
7845
7852
  ...accountPoolEn,
@@ -7917,7 +7924,7 @@ window.__ModuleLoader__.load({
7917
7924
  saved: "Saved",
7918
7925
  invalidCapacity: "Invalid capacity: {value}",
7919
7926
  quotaSection: "Usage & quota",
7920
- quotaDesc: "Read from the Coding Plan quota endpoint, which authenticates with the bare key and no Bearer prefix.",
7927
+ quotaDesc: "Read from the Coding Plan quota endpoint; refreshes at most once every 60 seconds while visible.",
7921
7928
  quotaRefresh: "Refresh usage",
7922
7929
  quotaRefreshing: "Refreshing...",
7923
7930
  quotaSignedOut: "Not signed in — finish the sign-in above first.",
@@ -7927,14 +7934,13 @@ window.__ModuleLoader__.load({
7927
7934
  quotaRenews: "Renews",
7928
7935
  quotaReadAt: "Read at",
7929
7936
  quotaSources: "Sources",
7930
- quotaWindowNames: "Window names are localized from the window length (5 hours / 1 week / 1 month) rather than hardcoded here; each account's own progress bar is drawn on its account card.",
7931
7937
  quotaRefreshingNote: "Quota is refreshing in the background; the figures below are the last read.",
7932
7938
  quotaErrorLabel: "Quota read failed",
7933
7939
  quotaAllowance: "Allowance",
7934
7940
  quotaAllowancePlan: "Paid plan",
7935
7941
  quotaAllowanceFreeTrial: "Free trial allowance",
7936
7942
  quotaAllowanceUnknown: "Undetermined",
7937
- quotaAllowanceHint: "The allowance source established by the sign-in probe. “Free trial allowance” is what official docs describe as 8M tokens per day for 5 days from first use, granted automatically to new accounts; once it runs out the upstream answers 429, which this line does not pre-empt."
7943
+ quotaAllowanceHint: "The allowance source established by the sign-in probe. “Free trial allowance” means 8M tokens per day for 5 days from first use, granted automatically to new accounts."
7938
7944
  };
7939
7945
  const dictionaries$4 = {
7940
7946
  zh: zh$4,
@@ -8788,10 +8794,6 @@ window.__ModuleLoader__.load({
8788
8794
  className: "dsha-muted",
8789
8795
  children: poolLabels.quotaFactsScope
8790
8796
  }),
8791
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8792
- className: "dsha-muted",
8793
- children: t.quotaWindowNames
8794
- }),
8795
8797
  status?.quotaRefreshing === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8796
8798
  className: "dsha-notice",
8797
8799
  children: t.quotaRefreshingNote
@@ -9632,7 +9634,7 @@ window.__ModuleLoader__.load({
9632
9634
  * Every level the wire can name is listed, 'xhigh' included: filtering a level
9633
9635
  * out here would hide a choice the host would accept and a catalog may expose.
9634
9636
  */
9635
- const EFFORT_LABELS = {
9637
+ const EFFORT_LABELS$1 = {
9636
9638
  low: zh$3.effortLow,
9637
9639
  medium: zh$3.effortMedium,
9638
9640
  high: zh$3.effortHigh,
@@ -9915,7 +9917,7 @@ window.__ModuleLoader__.load({
9915
9917
  children: t.defaultEffortAuto
9916
9918
  }), CLAUDE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
9917
9919
  value: effort,
9918
- children: EFFORT_LABELS[effort]
9920
+ children: EFFORT_LABELS$1[effort]
9919
9921
  }, effort))]
9920
9922
  })]
9921
9923
  }),
@@ -10116,6 +10118,29 @@ window.__ModuleLoader__.load({
10116
10118
  });
10117
10119
  }
10118
10120
  //#endregion
10121
+ //#region src/shared/ollama-contracts.ts
10122
+ /**
10123
+ * The thinking levels this line's card offers.
10124
+ *
10125
+ * Deliberately narrower than the union of what every model accepts. Ollama's
10126
+ * thinking control comes in three shapes (see {@link thinkingModeForModel} in
10127
+ * src/host/ollama/types.ts): gpt-oss takes low/medium/high, the boolean models
10128
+ * (deepseek-r1, qwq, qwen3) take only on/off, and every other model takes no
10129
+ * thinking control at all. These four strings are the vocabulary both shapes can
10130
+ * be expressed with, so one dropdown covers the whole line.
10131
+ *
10132
+ * Whether a given model can actually honour a level is decided by the host, not
10133
+ * by this list: {@link thinkForModel} in src/host/ollama/types.ts drops what a
10134
+ * model cannot express, so picking 'high' is safe for a user whose catalog holds
10135
+ * a mixture of families.
10136
+ */
10137
+ const OLLAMA_REASONING_EFFORTS = [
10138
+ "none",
10139
+ "low",
10140
+ "medium",
10141
+ "high"
10142
+ ];
10143
+ //#endregion
10119
10144
  //#region src/client/ollama/api.ts
10120
10145
  const API$1 = "/ollama/api";
10121
10146
  /**
@@ -10144,6 +10169,21 @@ window.__ModuleLoader__.load({
10144
10169
  return post$1(`${API$1}/catalog/refresh`, {});
10145
10170
  }
10146
10171
  /**
10172
+ * Store the default thinking level, answering with the refreshed status.
10173
+ *
10174
+ * '/settings' replies with the stored settings document rather than with the
10175
+ * status the card renders, so the status is re-read behind the write. That is
10176
+ * the same shape {@link refreshCatalog} needs, and it is why the return type is
10177
+ * a status: handing the settings document to the renderer would blank the
10178
+ * model list the user just configured.
10179
+ *
10180
+ * null is a real value ('do not specify'), not an absent one, so it is sent
10181
+ * explicitly rather than left out of the body.
10182
+ */
10183
+ setDefaultReasoningEffort(effort) {
10184
+ return post$1(`${API$1}/settings`, { defaultReasoningEffort: effort }).then(() => this.status());
10185
+ }
10186
+ /**
10147
10187
  * Replace the enabled-model selection.
10148
10188
  *
10149
10189
  * The whole list is sent rather than a single id's new state, because the card
@@ -10242,6 +10282,10 @@ window.__ModuleLoader__.load({
10242
10282
  selectAll: "全选",
10243
10283
  unselectAll: "全不选",
10244
10284
  noneSelected: "未选择任何模型,该线路不会出现在模型选择器中。",
10285
+ enhanced: "增强功能",
10286
+ defaultReasoningEffort: "默认思考档位",
10287
+ defaultReasoningEffortHint: "只对支持思考控制的模型生效。具体可选档位由模型自身决定:gpt-oss 一类只接受 low / medium / high,deepseek-r1 一类只有开或关,其余模型不接受思考控制,Host 会按模型形态收敛。选「不指定」时使用模型自身的默认值。",
10288
+ defaultEffortAuto: "不指定",
10245
10289
  limitsSection: "能力边界",
10246
10290
  limitsHint: "以下为 Ollama Cloud 官方文档列出的限制,本线路不会绕过:",
10247
10291
  limitNoStateful: "不支持 Responses 的有状态会话(仅无状态形式)。",
@@ -10290,6 +10334,10 @@ window.__ModuleLoader__.load({
10290
10334
  selectAll: "Select all",
10291
10335
  unselectAll: "Clear all",
10292
10336
  noneSelected: "No models are selected, so this line will not appear in the model picker.",
10337
+ enhanced: "Enhanced",
10338
+ defaultReasoningEffort: "Default thinking level",
10339
+ defaultReasoningEffortHint: "Applies only to models that accept thinking control. The levels a model can take are its own: the gpt-oss family takes low / medium / high, the deepseek-r1 family takes only on or off, and the rest take no thinking control at all — the Host narrows the stored level to what the target model accepts. Choose \"Do not specify\" to leave each model on its own default.",
10340
+ defaultEffortAuto: "Do not specify",
10293
10341
  limitsSection: "Documented limits",
10294
10342
  limitsHint: "Ollama Cloud documents these limits; this line does not work around them:",
10295
10343
  limitNoStateful: "No stateful Responses (stateless only).",
@@ -10317,6 +10365,20 @@ window.__ModuleLoader__.load({
10317
10365
  //#region src/client/ollama/OllamaSection.tsx
10318
10366
  const API = new OllamaApi();
10319
10367
  /**
10368
+ * What each thinking level says in this card.
10369
+ *
10370
+ * 'none' is the only one that needs words, because it is not a weaker rung on
10371
+ * the same ladder: it means "send no thinking control", which for the boolean
10372
+ * families (deepseek-r1 and friends) is an explicit off, and for gpt-oss means
10373
+ * nothing at all. The other three are spelled the way the models spell them.
10374
+ */
10375
+ const EFFORT_LABELS = {
10376
+ none: "none(关闭思考)",
10377
+ low: "low(低)",
10378
+ medium: "medium(中)",
10379
+ high: "high(高)"
10380
+ };
10381
+ /**
10320
10382
  * A token count short enough to sit in an account card.
10321
10383
  *
10322
10384
  * Exact below a thousand, then thousands, then millions. A six-figure number with
@@ -10420,6 +10482,9 @@ window.__ModuleLoader__.load({
10420
10482
  const setAllModels = (0, react.useCallback)((selectAll) => {
10421
10483
  applyEnabled(selectAll ? null : []);
10422
10484
  }, [applyEnabled]);
10485
+ const setEffort = (0, react.useCallback)((value) => {
10486
+ run("effort", () => API.setDefaultReasoningEffort(value === "" ? null : value));
10487
+ }, [run]);
10423
10488
  const t = zh$2;
10424
10489
  const pool = status?.pool;
10425
10490
  const models = status?.models ?? [];
@@ -10593,6 +10658,32 @@ window.__ModuleLoader__.load({
10593
10658
  })] })
10594
10659
  ]
10595
10660
  }),
10661
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10662
+ className: "dsha-group",
10663
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10664
+ className: "dsha-grouphead",
10665
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.enhanced })
10666
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10667
+ className: "dsha-pref-row",
10668
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10669
+ className: "dsha-muted",
10670
+ children: t.defaultReasoningEffortHint
10671
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
10672
+ className: "dsha-select",
10673
+ "aria-label": t.defaultReasoningEffort,
10674
+ value: status?.defaultReasoningEffort ?? "",
10675
+ disabled: busy !== null,
10676
+ onChange: (event) => setEffort(event.currentTarget.value),
10677
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
10678
+ value: "",
10679
+ children: t.defaultEffortAuto
10680
+ }), OLLAMA_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
10681
+ value: effort,
10682
+ children: EFFORT_LABELS[effort]
10683
+ }, effort))]
10684
+ })]
10685
+ })]
10686
+ }),
10596
10687
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10597
10688
  className: "dsha-group",
10598
10689
  children: [
@@ -14808,6 +14899,12 @@ window.__ModuleLoader__.load({
14808
14899
  locale: NS,
14809
14900
  inject: (sessionId) => ({ loadImage: imageLoader(ctx, sessionId) })
14810
14901
  }, CodexImageToolView));
14902
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
14903
+ name: "tool.call.toolview",
14904
+ key: ANTIGRAVITY_IMAGE_TOOL_NAME,
14905
+ locale: NS,
14906
+ inject: (sessionId) => ({ loadImage: imageLoader(ctx, sessionId) })
14907
+ }, CodexImageToolView));
14811
14908
  }
14812
14909
  /**
14813
14910
  * The seats every composer badge is handed.