npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@eddyskywalker/dsh-chatgpt-subscription

v0.29.0

Published

DSH provider plugin for Codex access through a ChatGPT subscription.

Readme

DSH ChatGPT Subscription

让 DSH(DeepSeek Harness)通过 ChatGPT 订阅使用 Gpt 系列模型的插件。

插件注册 codex-chatgpt Provider(显示名 “Codex(ChatGPT 订阅)”),以当前 Host 用户的 ChatGPT OAuth 登录态访问模型,并在设置页展示账号信息、连接状态与订阅额度。支持 Windows 与 Linux。

目录

线路总览

本插件同时接入 9 条订阅线路,每条各自独立注册 Provider、独立登录、独立额度卡片。

| Provider ID | 订阅 | 协议 | 登录方式 | 模型目录来源 | | --- | --- | --- | --- | --- | | codex-chatgpt | ChatGPT(Plus / Pro / Business…) | Responses | 浏览器 OAuth(localhost:1455 回调),或导入本机 Codex CLI 登录 | 实时 /backend-api/codex/models | | kimi-code | Kimi 会员 | Anthropic Messages | 设备码(RFC 8628) | 实时 /v1/models + 本地兜底 | | command-code | Command Code | Anthropic / OpenAI 双轨 | 浏览器 OAuth 或粘贴 API Key | 实时 /provider/v1/models | | workbuddy-subscription | 腾讯 WorkBuddy / CodeBuddy | OpenAI 兼容(仅流式) | 扫描桌面端凭据或官方浏览器授权 | 实时 /v3/config | | claude-subscription | Claude Pro / Max | Anthropic Messages | 手动粘贴 / loopback 回调 | 实时 /v1/models + 本地兜底 | | minimax-code | MiniMax Code 编程订阅 | Anthropic Messages | 复用桌面端登录态 或设备码 | 硬编码(见下) | | antigravity | Google Antigravity | Gemini | Google OAuth | 内置表 | | glm-coding-plan | GLM Coding Plan(ZCode 账号,国区 BigModel / 国际区 Z.ai) | Anthropic Messages + OpenAI Chat Completions(按模型声明) | ZCode 账号 OAuth(浏览器中转轮询)+ 可选导入本机 ZCode 登录态 | 随包目录(源自官方 zcode-builtin.json) | | step-code | StepFun Step Plan 订阅(国区 api.stepfun.com / 国际区 api.stepfun.ai)或开放平台 API Key | OpenAI Chat Completions | 云端轮询浏览器授权(不开本地回调端口)/ 手工粘贴 Platform API Key / 只读导入本机 ~/.stepcode/auth.json | 实时运行时发现(随包表刻意为空) |

只有 minimax-code 是硬编码目录,而且是有意的:该端点的 GET /v1/models 未对订阅流量开放(返回 503 direct_route_not_configured),任何「实时目录」都只会是一个必然失败的请求。其取值转录自本机官方客户端的 config.yaml。

线路之间互不影响:某条线路的登录失败、额度耗尽或上游故障都不会波及其它线路;它们共用同一套号池内核与账号卡片,但不是同一个池。

⚠️ 合规提示:claude-subscription 使用的订阅凭据转发方式与 Anthropic 现行条款存在冲突(详见该章节开头的「风险须知」),且插件未获官方授权;antigravity 线路的用户亦有账号被限制的公开报告。请自行评估风险。

功能特性

登录与会话

  • Authorization Code + PKCE(S256)登录,一次性 localhost 回调;
  • 支持 token 刷新、登录取消与账号注销;
  • Windows 使用 CurrentUser DPAPI 加密存储 token;Linux 使用当前用户独占的 0600 文件存储;明文不发送给 Client;
  • 设置页会明确显示当前存储类型,并在 Linux 上提示文件存储未额外加密。
  • 本机已经登录过 Codex CLI 的用户可以不再走一次 OAuth(详见「本机登录」):ChatGPT 卡片的账号池里,「登录」按钮旁边还有一个「导入本机 Codex CLI 登录」按钮——两者是同一件事的两种做法,布局与 Claude 页面上那个收编按钮一致。它只看凭据文件是否存在、从不读取令牌,且要你显式点那个导入按钮之后才会读取。导入得到的是一份快照,永不由本插件刷新——ChatGPT 的 refresh token 会轮换,而 CLI 会在原地刷新自己的文件,两个进程各自刷新会互相作废,最后是你被本插件的好意踢出 Codex CLI,而进程内的单飞解决不了这个跨进程竞态。快照过期后请回 Codex CLI 重新登录后再导入;本插件绝不写入或删除 Codex CLI 的任何文件。

模型接入

  • 固定 Codex Responses 地址,支持流式文本、reasoning summary、图片输入与工具调用/结果;
  • 模型目录来自订阅后端(GET /backend-api/codex/models):
    • 按账号缓存并持久化到本地快照,重启后无需等待网络即可渲染选择器;
    • 随包发布的模型表是兜底而非上限:取不到目录时选择器变宽,而不是消失;
    • 目录里本表没听过的模型照常出现,但未声明的能力按保守值回落,不会凭空多出图片或思考档位;
    • 只有目录确实列出的模型会进入选择器——它是「这个账号能调什么」的权威;
  • 请求带 openai-beta: responses=experimental:
    • 该订阅后端在 beta 标志下提供,官方 Codex CLI 一直发送这个头;
    • 缺它时请求面不同:当前后端宽容,但这正是收紧后会变成 400/403 的那一行;
  • 读取参数默认值与官方 Codex 一致(依据订阅目录 GET /backend-api/codex/models,与官方随包的 codex-rs/models-manager/models.json 同源):
    • 推理摘要默认不发:目录里每个模型都声明 default_reasoning_summary: none,官方以此为准。此前本插件在未配置时发 summary: auto,而摘要属于计费生成,等于每一轮都多花一块官方从不花的额度;现在默认省略该字段,用户显式选择 auto / concise / detailed 时照旧发送,选「无」也改为省略字段而不是发 summary: none(后者是让后端先生成再丢弃)。
    • 输出详细程度默认发目录值 low:官方客户端每轮都发送模型目录里的 default_verbosity(当前全部为 low)。此前本插件在未配置时整个不发 text 字段,于是服务端套用隐含的 medium——一个从未打开过该设置的用户,会拿到比官方客户端更啰嗦、也更贵的回答。现在未配置时按目录发 low,显式选择仍以用户为准。
    • 目录里没有记录的模型不猜:仅对该表声明了 supportsOutputVerbosity 的模型发送 text,避免把一个模型可能拒收的字段强加给它;
  • 多轮续传,避免每轮重发整个历史:
    • 每个会话发送稳定的 prompt_cache_key,让后端复用提示前缀;
    • 回传后端在响应头给出的 x-codex-turn-state,让它续接该轮;
    • 后端不再下发该头时立即停止回送——不重放过期值;
  • 对话报文绝不发送 max_output_tokens:订阅版 Responses 端点在部分账号/模型上直接以 400 Unsupported parameter: max_output_tokens 拒收该字段(#29,实测 gpt-6-sol / gpt-6.1-sol),官方 CLI 的请求结构里也没有这个字段;输出长度由服务端默认值决定,撞上限仍以 max-tokens 结束原因上报(详见「模型目录」);
  • 单次请求的图片负载有上限(2 MiB,可用 DSH_CODEX_MAX_IMAGE_BYTES 覆盖):历史里的每张图片每轮都会被重新内联,此前这条线路没有任何总量约束,长会话的请求体随读图数量单调增长,超过传输层能接受的体积后整轮失败,而报错只是一句没有信息量的「Codex could not be reached.」(#50)。现在按最旧优先把超出预算的图片替换为一条明确的占位文本,请求体因此有界,且模型知道那张图已经不在了;
    • 预算是在构造好的请求体上执行的,因为图片有两种到达方式:粘贴的附件是 { type: 'image', attachment } 块,而工具读取的本地图片是 ![](/describe-image/raw/sha256:…) 链接、由映射器在构造时才取回并内联。只扫消息块的方案看不到第二种;
    • 数字取自 #50 的实测(≤3 MB 全过、≥4 MB 全挂),而不是照搬别的线路:Kimi 的 1.5 MB 是按它自己的 2 MB 请求上限定的,用在这里会静默删掉本端点能接受的图片;MiniMax 的 16 MB 是按 64 MB 请求体定的,这里没有那个上限;
    • 只约束图片这部分。纯文本本身就超出传输层体积的请求仍然会被拒绝,任何图片预算都救不了它;
  • 请求路径的传输层失败会带上原因链:此前 request() 把任何失败都报成同一句 Codex could not be reached.,而 DSH 只持久化 {message, code},于是 NGHTTP2_ENHANCE_YOUR_CALM、ECONNRESET、UND_ERR_SOCKET 在界面和日志里长得一模一样——上面那条体积问题正是因此无法自助定位。现在与流中段断流(streamFailure)一致,把 cause 链拼进 message;
  • Antigravity(Gemini / Claude)线路同样接受图片输入:DSH 以 { type: 'image', attachment } 下发的粘贴图片会经附件服务读出字节并按 Gemini inlineData 发出,读不出的图片降级为一条可见的说明文本而不是被静默丢弃。单次请求的图片 base64 负载超过 12 MiB 时,最旧的图片按上游同款占位文案替换为文本,避免整条请求被体积上限拒绝;
  • 原样转发 DSH 暴露的工具 schema;命令工具兼容 pwsh / powershell、bash、sh 与 shell,并按 PowerShell、Bash 或 POSIX sh 注入对应说明;
  • 429/5xx 由 DSH retry policy 接管;401 只强制刷新并重试一次,支持 AbortSignal;
  • Codex、Code review 及上游返回的额外窗口额度,支持 Credits、月度消费控制与 reset credits 展示;60 秒缓存、15 秒上游节流并遵守 Retry-After;
  • 提供 ChatGPT 订阅侧 Codex 搜索 provider,可在设置页切换 DSH 默认搜索或 Codex 订阅搜索;
  • 新增 codex_image_generate 工具,生成图片后通过 DSH 附件系统保存并在会话中渲染;
  • 可选 composer 快捷用量徽标,按当前 codex-chatgpt 模型显示最紧张窗口的剩余额度。

Command Code 线路

  • 注册 command-code Provider,使用 Command Code 的 Provider API 与账户 API;模型 id 决定线路:claude-* 走 Anthropic Messages(/provider/v1/messages),其余模型走 OpenAI Chat Completions(/provider/v1/chat/completions),因为该 API 会拒绝把模型发到格式不符的端点;
  • 浏览器登录复刻官方 CLI 的回环回调契约(127.0.0.1:5959 起顺延,/callback 接受 Studio 页面的跨域 POST),也可在设置页手动粘贴 API Key;两条路径都先用 /alpha/whoami 验证再加密保存;
  • 模型目录取自公开的 /provider/v1/models,每个模型的 context_length 作为默认上下文窗口,可逐模型覆盖;
  • 模型能力逐模型查表(src/host/command-code/model-catalog.ts,转录自官方 CLI 的模型注册表):是否接受图片输入、支持哪些思考档位由该表决定,未知模型回落纯文本;
    • 图片能力不能靠厂商/模型名前缀推断——同厂商内部就会自相矛盾:deepseek/deepseek-v4.1-flash 与 deepseek/deepseek-v4-flash-vision-exp 支持图片,而 deepseek/deepseek-v4-flash、deepseek/deepseek-v4-pro 不支持;z-ai/glm-5.3-flash 支持而 zai-org/GLM-5.3 不支持;
  • 额度与用量来自账户 API 的账单/用量线路,任一条失败不影响其余;
  • 瞬时失败按 DSH retry policy 有界重试:command-code 路由显式声明 normal 策略(最多 3 次,1.5s 起指数退避、15s 上限、0.2 抖动),覆盖 RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT;
    • 上游模型供应商临时不可用(502/503/504/500,典型响应体是 "{\"error\":{\"type\":\"server_error\"}}")被归类为 SERVER 并自动重试;
    • 429 会带上上游的 Retry-After 让退避按对方的节奏走;401/403 与 ABORTED 明确不重试;
  • 模型勾选(含线路标签)、思考深度、上下文窗口覆盖与额度在「设置 → 订阅服务 → Command Code」标签页中配置,输入框右侧另有额度胶囊。

Kimi Code 线路

  • 注册 kimi-code Provider,接入 Moonshot 的 Kimi Code 订阅(https://www.kimi.com/code)。它与 Moonshot 开放平台(pay-as-you-go)是两套互不通用的系统:订阅的模型接口是 https://api.kimi.com/coding/v1,凭据只来自订阅 OAuth;把开放平台的 key 或 base URL 用在这里会被判为 401 Invalid Authentication;
  • 登录用 RFC 8628 设备码流程(auth.kimi.com):设置页点「设备码登录」后直接展示用户码与一次性链接(浏览器会自动打开),装好后无需回调端口、无浏览器环境也能手工完成;slow_down 会按 RFC 调宽轮询间隔,设备码过期会自动重新申请而不是直接失败;
  • 访问令牌到期前按 max(300s, expires_in×0.5) 自动续期,同进程并发调用共用一次刷新;被拒的 refresh token 进入冷却并提示重新登录;
  • 瞬时失败按错误类别重试(src/host/kimi-code/adapter.ts)。会重试(有界退避,最多 3 次,1.5s 起步、15s 上限、0.2 抖动,并遵守上游 Retry-After):
    • 上游模型供应商临时不可用(典型是 502 "{\"error\":{\"message\":\"Upstream model provider is temporarily unavailable. Please try again in a moment.\",\"type\":\"server_error\"}}");
    • 真正的 429 背压(too many requests / engine is currently overloaded)、连接失败与流停滞;
  • 不重试,直接给出可操作提示(换模型 / 降上下文 / 等窗口重置 / 重新登录):配额耗尽型的 429、403 的账号额度上限、401 里的套餐权限不足、400 请求格式错误;
    • 服务把这些含义压进同一个状态码,因此分类读响应正文而不只看状态码;
  • 模型目录为订阅侧的四款模型:k3(1M 上下文,需 Allegretto+;Moderato 上限 256K,故默认按 256K 计算,可用上下文覆盖升到 1M)、k3-256k、kimi-for-coding(K2.8 Preview)、kimi-for-coding-highspeed(约 6× 速度、3× 额度),运行时以 GET /v1/models 为准;
  • K3 行为按其官方文档实现:
    • 思考档位只发 low / high / max(其余写法收敛映射,未知档位不发送);关闭思考发 thinking:{type:"disabled"},开启时发 thinking:{type,effort,keep:"all"};
    • 开启思考时每条 assistant 消息都回传 reasoning_content(无推理则回传空串——服务要求的是空值而非省略,否则 400);
    • 不发送 temperature(采样参数按模型固定,显式值会报错);
    • 工具调用 id 截断到 64 字符;
    • stop 按上限裁剪为最多 5 条、每条 ≤32 字节,超长整条丢弃(截断的停止串会在错误位置终止生成);
  • K3 的长思考不会被截断:输出上限跟随上下文窗口(保留 4096 余量),因为 reasoning_content 计入输出,固定 32K 会把 max 档的长推理中途截断并返回 length;调用方已知 prompt 规模时上限会被下调到放得下,未知时不做猜测;
  • 请求体超 2 MB 本地即拒绝:该端点最常见的 400 是 total message size N exceeds limit 2097152,官方文案不给建议,这里直接按真实序列化体积拦截,并按「循环实际做了什么」给出处方(有图可丢但丢了也补不上缺口 / 图已丢完仍超限 / 本来无图,三种情况文案不同,不再声称发生了没发生的省略);确有实测上限的部署(前置代理/网关)可设 DSH_KIMI_CODE_MAX_BODY_BYTES 指定该档上限,取值非正整数时回落到默认值而不是关闭守卫;带视频的请求走 64 MiB 档,不受该变量影响;
  • 缓存是自动的,且无法手动干预:
    • Kimi 按请求内容哈希命中前缀缓存。实测 prompt_cache_key 与 Anthropic cache_control 标记均被忽略(设与不设、同 key 与异 key 命中的是同一缓存),设备 id 与协议切换也不影响;
    • TTL 实测在 300–1800 秒之间,按 256 token 对齐;/messages 与 /chat/completions 共享同一缓存;
    • 真正决定命中率的是内容稳定性:同一会话内 system 或工具列表一旦变化会使整个前缀缓存失效(实测归零)。因此应保持工具集合稳定、把新增内容追加在末尾;
    • 卡片会显示滚动命中率,方便验证效果;
    • 写入时长可手动选择(设置页):prompt_cache_options(OpenAI 兼容线路)或顶层 cache_control(Anthropic 兼容线路)控制缓存写入时长,与上面的「无法干预」不矛盾——那一条说的是缓存身份(由内容前缀哈希决定),TTL 管的是另一回事;
    • 档位在首次写入时锁定,之后无法改写、命中时按原档免费续期;1 小时写入约为 5 分钟的两倍价,只有同一前缀会在一小时内被反复读取才划算。不选择时不发任何缓存字段;
  • 视频输入可用(k3、kimi-for-coding):
    • DSH 的模态词表只有 text/image,但它是可合并扩展的接口,本插件用 TypeScript 模块增强把它扩到 video(未改动 DSH 任何代码),因此视频走 DSH 真实的能力通道,而不是只能显示在提示里;
    • 适配器把视频映射为服务文档的 {type:'video_url',video_url:{url:'data:…'}}。视频与图片各有独立预算(图片 1.5 MB、视频 48 MiB base64,最旧优先省略),请求体校验只在确实带视频时才放宽到 64 MiB;
    • 图片预算可用 DSH_KIMI_CODE_MAX_IMAGE_BYTES 覆盖(取值非正整数时回落到默认值)。视频预算没有环境变量出口,与 MiniMax 线路一致;
    • 以下情况会把视频降级为明确的文字说明而不是猜字段发出去:k3-256k 只接受图片、文档白名单外的容器、以及未文档化视频内容块的 Anthropic 线路;
  • dynamically_loaded_tools(仅 K3)已实现:K3 接受消息级工具声明(messages[].tools),可在会话中途用「无 content 字段的 system 消息」注入完整工具定义。官方把「保持顶层 tools 字节稳定」列为该特性的目的之一——中途修改/删除已发出的声明会使缓存从该点起失效,而在末尾追加不影响已缓存前缀,所以这是提升缓存命中的正道。声明按请求重发(服务端不保留),且仅在模型声明该能力时发送;
  • 额度卡片区分 5 小时 / 7 天 / 月度(会员共享池)/ 月度(Kimi Code 池) 四个窗口并显示重置时间,另可显示加油包余额;设置页为「设置 → 订阅服务 → Kimi Code」标签页,对话输入框右侧有该线路的额度胶囊。

WorkBuddy 线路

  • 注册 workbuddy-subscription Provider,接入腾讯 WorkBuddy / CodeBuddy 订阅。
    • 该 ID 特意与用户常用的自定义 OpenAI 兼容线路 workbuddy 分开,安装插件不会覆盖或隐藏原有自定义 API;
    • 可直接扫描 CodeBuddy 桌面端已登录的 *.info 凭据,也可从设置页选择国区/国际区并通过官方浏览器授权添加账号;
    • 插件添加的凭据保存在系统加密存储中(Windows DPAPI / macOS Keychain / Linux Secret Service),token 只留在 Host 进程内,不进入浏览器;
  • 多账号号池,与其它线路同源:走共享内核 AccountPoolCore 并复用同一张设置卡片,具备顺序耗尽 / 轮询调度 / 粘性会话、429 冷却换号、账号级失效保留、设为主账号与备注;
    • 账号身份是两层:不可变的 internalId 是唯一路由键,identityKeys(uuid / email / 派生 seed)是只增不换的别名集,同一账号再次登录会合并而不是产生幽灵账号;
    • 唯一例外的诚实说明:当服务端既没返回 uuid 也没返回 email 时无法自动识别同一账号,卡片会把该账号标注出来并提供手动合并;
    • 顺序耗尽 / 轮询调度 / 粘性会话三种策略;
    • 429 冷却换号、401/403 账号级失效(保留账号、重新登录即恢复);
    • 设为主账号、账号备注、清除冷却与重新登录;
    • 桌面端扫描到的账号与插件内添加的账号在同一号池里参与调度;
  • 桌面账号归 IDE 所有,不可删除:卡片只对插件自己添加的账号显示「删除」,桌面账号显示「隐藏 / 恢复」——隐藏只把它移出本插件的调度,绝不改动 CodeBuddy 的凭据文件;号池层同样拒绝删除桌面账号(双保险,均有测试);
  • 续期后原子写回原凭据文件(只改 auth 块),以免桌面端掉线——桌面账号的 refresh token 会轮换,若只写进插件自己的加密存储,IDE 手里就只剩一个已作废的 token。同一进程内的并发调用共用一次刷新,且不会二次刷新;
  • 上游是 OpenAI 兼容的 POST {backend}/v2/chat/completions,但有两条硬约束:只支持流式(stream:false → 400 code 11101),且首条消息必须是 system(否则国际区返回 400 code 11128)。因此请求构造器始终发送 stream:true,并在调用方没给系统提示时补一条中性的,避免手搓的一次性请求踩到这条规则;
  • 区域是凭据属性,不是请求属性:*.workbuddy.ai / *.codebuddy.ai 走国际区 https://www.<apex>,其余走国区 https://copilot.tencent.com;
    • 账号卡片逐条标注每个账号的国区 / 国际区并允许选择;切换后,模型目录、额度和后续对话都使用该账号;历史凭据快照按账号身份自动去重;
    • 插件托管账号可真正删除;桌面扫描账号只能从本插件隐藏/恢复,永不删除 CodeBuddy 的原文件;
    • 两区模型清单不同,把模型发到不服务它的区会返回 400 code 11102,因此模型选择器按当前账号区域过滤;
  • 模型目录取自网关自己的 /v3/config(官方 CLI 启动时读的就是它):每个模型的真实上下文上限、输出上限、是否接受图片、以及可用的思考档位都在这里,不做任何按模型名猜测。/v1/models 在这条线路上是 404,所以此前只能靠内置表——现在内置表只作为离线兜底,且是从真实 /v3/config 转录的(早期手写版本把 glm-5.3、kimi-k3 的窗口猜成 200K/256K,实际都是 1M);
  • 目录不是服务全集,模型必须实测:实测国际区的 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 是模型存在但参数被拒;
  • 目录同时区分默认服务的上下文长度与模型上限(如 deepseek-v4.1-flash 默认 300K、最大 1M)。本线路不发送显式长度参数,所以 DSH 的压缩与溢出判断按默认服务长度计算,不会让请求越过后端实际接受的窗口;
  • 思考档位逐模型取目录声明的档位表,回落顺序为「调用方显式指定 → 用户配置的默认档 → 目录为该模型声明的默认档」;
    • 最后一档不能省:上游在请求不带 reasoning_effort 时返回空的 reasoning_content(实测同一提示:不带字段 0 字符,带字段 130–215 字符)——不发送等于静默丢弃模型的思考;
    • 目录里的单个 effort 字段是默认值,既不是完整档位表也不是「只此一档」:实测这类模型接受 low / high / max(其余取值被上游收敛到最近档),因此使用这三档的标准表(WORKBUDDY_STANDARD_EFFORTS);显式声明了 supportedEfforts 的模型则原样采信;
    • 目录给出的默认档也可能落在档位表之外(minimax-m3、kimi-k3、国区 glm-5.3 都报 medium 却只有三档),这种值会收敛到最近档——否则默认档被判不支持而丢弃,退化成上一条的空 reasoning_content;
    • 不在该模型档位集合内的取值会被忽略而不是发出去(上游对不支持的档位返回 code 11150);
  • 瞬时失败按错误类别重试(src/host/workbuddy/adapter.ts):
    • 上游 5xx 与 code 11134 归为 SERVER 并走有界退避(最多 3 次,1.5s 起步、15s 上限、0.2 抖动);
    • 额度耗尽(429 / code 6004 / code 14003,其中 6004 的正文带重置时刻)归为 RATE_LIMIT 并遵守 Retry-After;
    • 401/403、跨区模型、不可用图片、历史形状错误都不重试,并给出可操作的提示(换模型 / 换图片 / 重新登录桌面端);
  • 流中断即失败:上游必然以 finish_reason 或 data: [DONE] 结束,两者都缺失说明连接中途断开,此时抛出错误而不是把半截文本当成完整回答;
  • 额度来自 /billing/meter/get-user-resource,卡片展示套餐名、本周期已用/上限、剩余额度与重置时间;设置页为「设置 → 订阅服务 → WorkBuddy」标签页,对话输入框右侧有该线路的额度胶囊。

MiniMax Code(编程订阅)线路

  • 注册 minimax-code Provider,接入 MiniMax Code 编程订阅。它与 MiniMax 开放平台(按量计费的 API Key)是两套互不通用的系统:
    • 订阅的模型接口是 Anthropic Messages 协议(https://agent.minimax.cn/mavis/api/v1/llm/v1/messages);
    • 只用 authorization: Bearer <accessToken> 认证——实测 x-api-key 一律返回 401 "{\"code\":401,\"message\":\"token is required\"}",因此本线路没有 x-api-key 回退分支(回退只会在每次请求上白花一个往返);
  • 复用桌面端登录态,而不是让你再登录一次:凭据就是 MiniMax Code 自己写的 ~/.minimax/auth/<buildEnv>/<region>/mcode-public/auth.json。
    • 只读优先:仍在有效期内(且距离到期还有 5 分钟以上)的令牌原样使用;
    • 进入续期窗口才轮换,并走原子替换(临时文件 + rename),失败或中断都让原文件保持逐字节不变;
    • 不创建、不删除、不等待 auth.lock(那是桌面端自己的刷新锁,第二方碰它就可能打断官方客户端的刷新);
  • 两种登录来源互不覆盖:
    • 桌面端的 auth.json 归桌面端所有,本插件只读;若本机没有它,才在设置页用 RFC 8628 设备码流程(PKCE S256)登录,凭据存到本插件自己的 $DSH_HOME/storages/minimax-code-credentials.json;
    • 登出只作用于本插件自己那份凭据:桌面端的登录态会被续期写回(只读优先),但绝不撤销、绝不删除,登出请求对它会被拒绝并说明原因(撤销它等于把你从正在跑的 MiniMax Code 里踢下线),这也是 WorkBuddy 对桌面账号的既有做法;
  • 区域是凭据属性:cn 用 account.minimax.cn / agent.minimax.cn,global 用对应 .io 域名。两个区域的目录都会被探测,因此国际区账号不会因为没有国区文件而「未登录」;读回凭据时以记录里存的区域为准,而不是拿默认区域覆盖它;
  • 模型目录是硬编码的,而且必须硬编码(src/host/minimax-code/model-catalog.ts):
    • 该端点的 GET /v1/models 未对订阅流量开放(503 "{\"errorCode\":50115,\"errorReason\":\"direct_route_not_configured\"}"),所以任何「实时目录」都只会是一个必然失败的请求;
    • 四款模型:M2.7 / M2.7 HighSpeed / M3 取自本机 ~/.minimax/config.yaml 的模型表;M3.1 Flash 是 2026-10-19 换上的正式版 id(MiniMax-M3.1-Flash,去掉了 -Preview 后缀),取自 MiniMax 自己的 Model Invocation 页 Supported Models 表并在该订阅端点上实测(正式 id、output_config.effort 的 low/max、内联图片)。无论哪一条,都不从不存在的接口推断;
  • 思考形态按模型表三态实现,且一律走 output_config,不发 thinking 对象(该字段从未被文档确认,发出去只是一种形状的猜测):M2.7 系列恒定开启且没有档位(不发送任何字段);M3 是开关二态(关闭时 output_config.effort: 'none');M3.1 Flash 强制开启并可指定档位(output_config.effort 取 low/medium/high/xhigh/max,省略即 max)。未知或越档的取值一律回落到该模型目录声明的默认档,不会把模型没有声明的档位发出去;
  • 视频不在能力声明里:模型表虽然给 M3 / M3.1 标了视频输入,但 DSH 的附件服务只存图片、本线路也没有安装视频字节读取器,映射器只能把它替换成一条说明文本。声明一个做不到的能力比不声明更糟(DSH 的能力闸门、模型选择器与子代理委派都会当它成立),所以这里只声明 text 与 image;要加 video 必须先有真正的读取器(对照 Kimi Code 线路的 video-store.ts);
  • 瞬时失败按错误类别重试(src/host/minimax-code/adapter.ts):上游模型供应商临时不可用(5xx)归为 SERVER、429 归为 RATE_LIMIT、连接未产出响应归为 TRANSPORT,走 DSH retry policy 的有界退避(最多 3 次,1.5s 起步、15s 上限、0.2 抖动);但 429 的正文若说的是余额/额度耗尽,则判为终局——重试只会推迟用户真正需要看到的提示;
  • 401 会强制续期一次再重试:本地时钟看着还有效、服务端却拒收的令牌(在桌面端被撤销、时钟偏移、桌面端已轮换)与「真的需要重新登录」在状态码上无法区分,所以第一次 401 会强制刷新一次并原样重试同一个请求体;重试再被拒才是终局;
  • 刷新令牌是单次使用的,因此续期提前 5 分钟、并全进程共用一次轮换:
    • 这是「每小时自己掉线、然后要求重新登录」的根因。access token 实测只有 1 小时,而原先的续期阈值是「到期前 60 秒」——等于每次都在令牌已经会被拒收的那一瞬间才去轮换;
    • 并发请求(状态卡轮询、签到、用量读取、模型请求)会各自拿同一枚刷新令牌去换,除第一个之外全部拿到 invalid_grant,而这条终局判定会被记成「该账号需要重新登录」并写进号池(重启也在);
    • 现在:① 续期窗口 PRE_EXPIRY_REFRESH_MS 为 5 分钟,轮换发生在服务端还没有拒收之前;② 同一份凭证的轮换按身份(recordKey / loginEpoch)单飞,后到的调用者要么加入在途轮换、要么采纳结果,绝不二次花费同一枚令牌;
    • ③ 轮换先看 storage 再相信终局判定——磁盘上的凭证若已前进(别人刚成功轮换,或桌面端自己刷新过),直接采纳,不记 tombstone、不报「重新登录」;
    • ④ 号池行上遗留的过期标记会在下次读取或请求时自动核对并清除;⑤ 卡片补上了「重新登录」按钮(onRelogin 此前未接线);⑥ 响应未返回新 refresh token 时沿用旧值,不再当作失败;
  • 请求体上限是本线路自己的 64 MB,不是 Kimi 线路的 2 MB(本条为修复项,详见 CHANGELOG):
    • 原缺陷:守卫直接复用了 Kimi 线路的 MAX_MESSAGE_BODY_BYTES(2,097,152),理由写着「两条线路上游都是同一族端点」。2,097,152 与 total message size N exceeds limit 2097152 是 Kimi Code 自己文档里的网关上限(见其错误参考),MiniMax 没有任何文档这样规定;
    • 代价:真实会话在 2,098,045 字节时被本地拒绝——请求根本没发出去,这一轮就失败了。该数字离 2,097,152 只差 893 字节,而超过 2 MB 本身不代表这个路由发不出去;
    • 更自相矛盾的地方:本线路的模型目录给 M3 标了 512K 上下文(可选 1M)、单张图片 10 MB——一个 2 MB 的整包上限与「单图 10 MB」根本不能共存,一张合法图片就能单独触发它;
    • 现在:上限改为本线路自己的 DEFAULT_MAX_MESSAGE_BODY_BYTES(64 MB,MiniMax 对带媒体请求自己公布的请求体量级),普通会话永远不会被本地拒绝,守卫只拦真正的失控请求(如每轮追加数 MB 工具结果的死循环),且仍在花掉连接之前拦下并给出同样的可操作提示;
    • 确有实测上限的部署(前置代理/网关)可设 DSH_MINIMAX_CODE_MAX_BODY_BYTES 指定;取值非正整数时回落到默认值而不是关闭守卫;
    • 同一个错误在图片预算上又犯了一次,而且更隐蔽(已一并修复):本线路调用的是 Kimi 的 offloadOldestRequestImages,其预算是 Kimi 的 1,500,000——那是为塞进 Kimi 自己的 2 MB 请求体上限而定的数字。MiniMax 的模型表允许单图 10 MB 原始字节(base64 约 13.3 MB),超出近 9 倍,于是一张普通截图就被换成占位文本;
      • 比拒绝更糟:omit 是静默替换——没有报错、没有计数,模型是在一个「图根本不存在」的对话上作答的,而现场没有任何线索指向原因。现在预算是本线路自己的 DEFAULT_MAX_REQUEST_IMAGE_BYTES(16 MB,装得下模型 10 MB 单图上限并留出余量,且远在 64 MB 请求体上限之内),可用 DSH_MINIMAX_CODE_MAX_IMAGE_BYTES 覆盖;
      • 改法:共享的是机制(度量、按最旧优先丢弃、不动持久历史),不是数字。offloadOldestRequestImages(options, maxBytes) 现把预算变成参数,缺省仍是 Kimi 的值,其余线路行为逐字节不变;
    • 守卫的形状仍与 Kimi 共用,数字不共用——字节上限是上游网关的属性,不是什么通用常量;
  • 额度面板有两套用量端点,第一轮打错了那一套:
    • 平台端点 /v1/token_plan/remains(api.minimax.cn / api.minimaxi.com / api.minimax.io)只接受平台 API 密钥:mcode-public 登录态在四种认证写法(Bearer / 原始 / x-api-key / 两者都带)下全部被拒,且是 HTTP 200 + base_resp.status_code: 1004——不是 401,很容易被误读为成功;
    • 官方 mmx CLI 能用该端点,是因为它的 OAuth 是平台登录,与本线路的 mcode 登录是两套身份;
    • mcode 自己的端点在官方客户端源码里(packages/tui/src/account/matrix-account-client.ts):GET https://agent.minimaxi.com/v1/api/openplatform/coding_plan/remains(国际 agent.minimax.io),路径与平台端点完全不同。本插件用的就是这条(本线路的 agent.minimax.cn 优先、官方主机兜底);
    • ⚠️ 但它带 yy / x-timestamp / x-signature / User-Agent: MiniMaxCode 四个「官方客户端标识头」——官方注释自己写明这些是「把请求标记为来自 MiniMax 第一方客户端」的字面量;
    • 本插件 types.ts 已明确决定不伪造官方客户端身份(伪造既失信,也可能是封号理由),因此默认不发,宁可拿到一个拒绝让卡片如实说明;
    • 确实要数字的用户可设 DSH_MINIMAX_CODE_QUOTA_ATTRIBUTION=1 显式选择该取舍;
  • 用量端点不在 MiniMax 的 API 文档里(文档只说「用量显示在控制台的用量条上」,这大概就是最初判定「没有端点」的原因),它来自官方 CLI——mmx quota show。返回的每个 model_remains 行带两个窗口(5 小时滚动 + 每周),卡片因此有两根条,各自显示重置时刻与「已用/总量」;
  • 三个必须照抄官方实现的解析细节:
    • ① *_usage_count 的语义是模糊的(老响应是「剩余」、新响应是「已用」),官方用显式百分比消歧——照抄,否则进度条会反过来;
    • ② 周窗口带显示倍率(返回的是百分比 × weekly_boost_permille,可超过 100%);
    • ③ status: 3 通常表示「不限量」,但两个总量都为 0 时它表示「当前套餐不含该模型」——渲染成不限量会凭空许诺额度;
  • 三处降噪防护:① base_resp 非 0 视为凭据被拒,只试一台就停并记住 30 分钟;② 其它失败按 unreachable 区分、记住 10 分钟;③ /status 只读缓存、绝不在轮询里发网络请求;
  • 读用量永远不影响对话:独立只读路径,失败只让卡片换一句话;
  • 设置面与其余各线路逐项对齐(该 PR 最初缺失这一整块,用户明确指出):
    • ① 「启用此供应商」总开关——关闭后适配器不暴露任何模型(包括已勾选的),因为「关掉」如果还能用就等于没关;
    • ② 模型勾选——只有勾选的模型进入对话页的模型选择列表,另有「全选 / 全不选」;
    • ③ 模型上下文窗口覆盖——每个已勾选模型可填自定义容量(接受 1M / 512K / 200000),「恢复默认」以 null 语义在 host 侧删除该键而不是写入 0;
    • ④ 默认思考深度——全局档位只在模型确实列了该档时生效,否则回落到该模型自己的默认档(广告一个模型会拒绝的档位只会让服务端拒掉请求),且「关闭思考」只对可关闭的模型生效;
    • ⑤ 号池管理(见下条);
  • 目录仍然硬编码,但「这一安装当前怎么用它」是用户设置:两者分开存储(目录随代码发布、设置随用户数据保存),因此一份用户数据不会看起来像一条已发布的目录项;
  • 号池与多账号登录:复用与其它线路同一个号池内核(src/host/common/account-pool.ts)与同一张共享账号卡片,具备顺序耗尽 / 轮询 / 粘性调度、429 冷却换号、设为主账号与备注。身份键不是令牌:桌面端凭据用它自己的 recordKey(同一个记录槽每次轮换都是同一账号,因此在池里原地更新),插件自持凭据用 loginEpoch(每次设备码登录就是一次独立会话)——用刷新令牌做键在每次轮换后都会把同一账号看成新账号;
  • 桌面端登录态可被显式「导入」为号池账号(POST /accounts {action:'adopt'}):只读取、只新增一行,不改动官方客户端的任何文件;重复导入按记录槽身份原地更新,不会产生重复账号。在设置页新发起的设备码登录会自动加入号池(pollWebLogin 的 onSave 钩子)——没有这个钩子,新登录只会写进镜像文件而号池看不见,这正是「多账号登录没配好」的根因;该钩子的失败不会让登录失败,因为凭据此时已经落盘。

Claude(订阅)线路

  • 注册 claude-subscription Provider,以 Claude Pro / Max 订阅的 OAuth 登录态访问 Claude 模型(Anthropic Messages 接口),不使用 API Key、也不按量计费;
  • ⚠️ 风险须知(插件不设确认步骤,但事实不变):Anthropic 现行条款明确写明不允许第三方应用提供 Claude.ai 登录、也不允许代用户经 Free / Pro / Max 凭据转发请求,并保留不经预告的执法权;已有开源项目被下架、有账号因此被限制。本插件未获 Anthropic 任何授权或认可,使用风险由使用者自行承担。此前版本在卡片上设有确认步骤与配套主机门禁,两者均已移除;移除的只是那一步交互,不改变上述事实;
  • 这不是抄一个 token 就能用:订阅令牌要求请求完整模仿 Claude Code 的身份,否则会被服务端拒绝或分类判别。这些都在代码里显式实现并有测试锁定:
    • Authorization: Bearer 且 x-api-key 必须缺省;
    • user-agent: claude-cli/<版本>、x-app: cli;
    • anthropic-beta 至少含 oauth-2025-04-20 与 claude-code-20250219;
    • system 的首个块必须是 Claude Code 身份声明;
  • OAuth 用 PKCE,且 state 与 verifier 独立生成。这一点特意不照抄参照实现:本机参照实现把 PKCE verifier 直接当作 OAuth state(state: verifier),那会把本应保密的 verifier 写进授权 URL、地址栏、浏览器历史乃至剪贴板。本线路是两次独立随机抽样,并有测试断言授权 URL 中不出现原始 verifier;
  • 两条登录路径,模式在流程开始时确定且不可中途切换:默认是手动粘贴(授权页把码显示在屏幕上,粘贴 <code>#<state>;也容错接受整条重定向 URL)。可选 loopback 回调,绑定 127.0.0.1 并顺序探测可用端口(Windows 的保留端口段会让固定端口绑定失败)。端口探测失败降级为手动而不是报错。切换模式等于作废当前流程并重新发起——授权码与签发它的那次请求的 redirect_uri 绑定,这是该流程最常见的失败;
  • 一次授权只兑换一次:浏览器回调与手动粘贴可能同时到达,用 compare-and-set 保证只有一方发起兑换(另一方得到「正在处理中」,已结算的流程得到 410 且不做任何兑换)。错误的 state 只拒绝那一个请求,不会终止正在进行的合法登录。回调服务器只绑 loopback、只应答 /callback、只接受本机来源;
  • 刷新是单飞的:并发请求共享同一次刷新。否则到期瞬间的一批请求会各自轮换刷新令牌,除第一个之外全部作废(上游会给出终局判定)。刷新令牌轮换后先读回校验再落盘;
  • 模型能力逐模型查表(src/host/claude/model-catalog.ts),不从模型名推断。该表转录自本机随 harness 安装的参照目录,只证明抄录忠实,不证明服务端提供这些模型——服务端自己的 GET /v1/models 才是权威,且它只覆盖上下文窗口,能力字段不被改写;
  • 思考形态有四类,顺序决定成败(thinkingMode):
    • mid-convo → {type:'adaptive', block_binding:{prefix_mismatch_behavior:'drop_block'}} 外加 output_config.effort;
    • adaptive → {type:'adaptive'};
    • budget → {type:'enabled', budget_tokens}(预算算术按参照实现转录;思考预算计入 max_tokens,必须为回答留出至少 1024 token);
    • none → 不发思考字段;
    • mid-convo 排在最前且无条件:claude-fable-5-1 与 claude-opus-5 同时带 forceAdaptiveThinking,把它们当成普通 adaptive 会静默丢掉 block_binding 与 output_config,而参照实现自己的注释写明该缺失会导致持续 400;
    • 反过来,block_binding 本身必须由 anthropic-beta: thinking-binding-controls-2026-08-01 授权(官方文档:缺该 beta 时返回 400 block_binding: Extra inputs are not permitted)。因此请求头从已构建的请求体读出是否带 block_binding,带则追加该 beta;
  • 思考块带签名则原样回放(这是思考模式下多轮工具调用的前提;redacted_thinking 同样回放),无签名则丢弃。工具名在出站时按 Claude Code 规范大小写归一化、入站时按大小写无关匹配回用户工具名;若两个工具归一化后碰撞,则放弃归一化原样发送,避免把结果投给错误的工具;
  • 多账号号池,与其它线路同源:复用与其它线路同一个号池内核(src/host/common/account-pool.ts)与同一张共享账号卡片,具备顺序耗尽 / 轮询 / 粘性调度、429 冷却换号、设为主账号与备注;
    • 身份键不是令牌:桌面端凭据用它自己的 recordKey(同一个记录槽每次轮换都是同一账号,因此在池里原地更新),插件自持凭据用 loginEpoch(每次设备码登录就是一次独立会话)——用刷新令牌做键在每次轮换后都会把同一账号看成新账号;
  • 可选择性收编本机已有的 Claude Code 登录(默认关闭):开启前只做一次「文件是否存在」的探测,不读取内容;只有你显式开启后才读取。收编得到的是一份快照,永不由本插件刷新——Claude Code 刷新的是同一枚轮换令牌,两个进程各自刷新会互相作废,而进程内的单飞解决不了跨进程竞态。快照过期后卡片会提示你回 Claude Code 重新登录后再收编,并且绝不会写入或删除 Claude Code 的任何文件;
  • 额度面有两个来源、两套单位,换算后有交叉测试证明它们描述同一状态:
    • 主来源 GET /api/oauth/usage 的 utilization 是已用百分比 0–100;
    • 而 /v1/messages 响应头 anthropic-ratelimit-unified-5h-utilization 是分数 0–1,重置时间是 epoch 秒;
    • 有真实流量时以响应头为准以降低查询频率,但卡片仍会按 QUOTA_FULL_REFRESH_MS 做一次完整读取;
  • 提示缓存时长可选择(设置页):本线路用订阅凭据,而 Claude Code 官方文档 写明订阅用户在套餐额度内对主对话使用 1 小时 TTL(超出额度改按用量计费后官方会降回 5 分钟)。此前固定使用 5 分钟默认值,与官方客户端行为不一致——同样的用量,官方用户享受 4 倍缓存窗口而本插件没有;
    • 1 小时是需要许可的能力:body 里写 ttl: '1h' 必须同时带 anthropic-beta: extended-cache-ttl-2025-04-11,否则被拒(与 block_binding 同理)。插件从已构建的请求体读出所选档位并据此发出该 beta,两者不可能不一致;
    • 写入 1 小时档价格更高,短会话不划算,因此设置项可覆盖为「跟随官方 / 1 小时 / 5 分钟」;
  • 换号的两条硬约束:只在凭据失败或账号级限流时换号——全局限流、过载与 5xx 绝不换号(其它账号共享同一全局限制)。一旦已有输出产出就绝不换号(否则会重复文本或重复工具调用),改为直接报错。换号最多 3 次;
  • 模型勾选、思考深度、上下文窗口覆盖与额度在「设置 → 订阅服务 → Claude」标签页中配置,输入框右侧另有额度胶囊(取剩余最紧的那个窗口)。

设置页

  • 展示账号(脱敏 email、套餐、账号 ID 后四位)、连接状态、额度与订阅增强功能开关;「输出详细程度」「推理摘要」两项的默认值即官方 Codex 客户端的取值;
  • 偏好落盘位置随 harness 生成:
    • 有 settings.register 的一代(≤0.1.6)仍写进 harness 的设置文档;
    • 0.1.7 起该 API 被 SettingsForms 取代,偏好改由插件自己持久化到 <dshHome>/storages/dsh-chatgpt-subscription-preferences.json(0600、原子写;读取失败或校验不过就回落默认值);
    • 首次运行会从旧设置文档里本插件的段一次性迁移;五条线路的模型开关同样从各自既有的 storages/*-models.json 水合,因此重启后不会像被重置;
  • 子代理的模型与思考深度沿用 DSH 自身设置:设置 → Subagent 卡片授权 Agent 可以为子代理挑选的模型(来自 DSH 已接入的全部 Provider,包含本插件的 Codex / Antigravity),新 Agent 的默认路由由 DSH 的 agent-default-model 设置提供;
  • 最大嵌套深度不在本插件设置内,由 DSH 侧决定:0.1.5 及以前是 preset 中 tool-subagent 行的 maxDepth(默认 3),0.1.6 起改由 subagent 服务的设置项提供(默认 1);provider-managed 表示把预算交给进程外提供方;
  • GPT-6 系列(6 Astra / 6 Sol / 6 Luna)默认使用 384K 有效上下文,可配置最高 872K;5.6 Sol / Terra / Luna 保持 272K,最高 1M,用于 DSH 压缩与溢出判断;其他模型保持目录声明值;
  • 单次输出上限按模型区分:GPT-6 系列为 128K(官方对 6 Astra / 6 Sol / 6 Luna 均标 128K),更早的模型保持 32768。这个数字只在本插件进程内使用,不会写进请求:订阅版 Responses 端点会以 400 Unsupported parameter: max_output_tokens 拒收该参数(#29),官方 Codex CLI 的 ResponsesApiRequest 里同样没有这个字段。它的实际用途是作为 DSH 侧的输出预留量(defaultMaxTokens),供压缩判定把完成部分计入上下文窗口;请求本身交给服务端决定长度。撞上服务端上限时该轮仍以 max-tokens 结束原因呈现(后端以 response.incomplete 收尾)。
  • 可访问的进度条、窄窗口/200% 缩放布局、深浅主题与 reduced-motion。

模型目录

| 显示名 | 模型 slug | | --- | --- | | 6.1 Sol | gpt-6.1-sol | | 6 Astra | gpt-6-astra | | 6 Sol | gpt-6-sol | | 6 Luna | gpt-6-luna | | 5.6 Sol | gpt-5.6-sol | | 5.6 Terra | gpt-5.6-terra | | 5.6 Luna | gpt-5.6-luna | | 5.5 | gpt-5.5 | | 5.4 | gpt-5.4 | | 5.4 Mini | gpt-5.4-mini | | 5.3 Codex Spark | gpt-5.3-codex-spark |

目录只用于展示;账号实际可用的模型由 ChatGPT 套餐、workspace 策略与上游兼容状态决定。

GPT-6 系列(6.1 Sol / 6 Astra / 6 Sol / 6 Luna)支持文本、图片输入和工具调用,默认思考档位为 medium,可选 low、medium、high、xhigh、max。从旧会话带入的 none / minimal 会按 OpenAI 官方迁移说明 转为 low。三个模型的默认 384K 与上限 872K 均取自 2026-09-23 的 Codex 模型目录(gpt-6-sol / gpt-6-luna 于 2026-09-22 发布,能力与 gpt-6-astra 一致;目录里的 context_window 是 272K,本插件把默认有效上下文提高到 384K,仍低于 872K 上限);Codex Ultra 涉及客户端的子代理编排,本插件不将它作为 Responses 思考参数暴露。

新配置默认显示 GPT-6 系列与 GPT-5.6 系列;已有配置保留原来的模型勾选,可在 设置 → Codex 订阅 → 可用模型 中勾选 6 Sol / 6 Luna。

环境要求

  • Windows 或 Linux;
    • Windows:系统需提供 Windows PowerShell,以使用 CurrentUser DPAPI;
    • Linux:Host 用户必须拥有可写的 ~/.dsh(或 $DSH_HOME),凭据文件会强制使用 0600、目录使用 0700;
  • 已安装 DSH:peer 范围覆盖 0.1.2-alpha.5 及以后的每一代,一直到 0.2.0-rc.2。构建与测试以 0.2.0-rc.2 为基线,旧版行为由版本兼容层保留,因此同一份代码可装在 0.1.2-alpha.5 以来的所有代上(用户分散在 npm 的 latest / next / alpha 三个标签上,多数人跑的是比 alpha 落后几个版本的 latest)。需要桥接的破坏性变更:
    • 0.1.7 重写了会话消息模型(工具结果由 tool-result 内容块改为 role: "tool" 消息)、删除了 settings.register(偏好改由插件自有存储落盘)、并让 agent preset 不再从 ~/.dsh/.agent-presets 读取。插件在请求边界、设置服务与 preset 注册三处同时适配。
    • 0.1.6 把 workflow 引擎改了包名,插件在 preset 同步时按当前安装自动适配(见「随包分发的 Agent Preset」)。
    • 0.1.1-rc.2 不再声明支持——它既没有 preset 用到的 present 工具,mode 枚举那时也还写作 code。
  • Node.js 与 npm。

安装

方式 1:通过 DSH CLI 安装(推荐)

直接从 npm 安装已发布的插件包:

# Windows PowerShell、Bash 和 POSIX sh 均可执行
# 如果全局安装了 dsh
dsh plugin --profile web add @eddyskywalker/dsh-chatgpt-subscription

# 或使用 npx 直接运行
npx @deepseek-ai/dsh plugin --profile web add @eddyskywalker/dsh-chatgpt-subscription

版本阶段:上面两条命令装到的是 npm latest 标签指向的版本(撰写时为 0.10.12)。包不预置 publishConfig.tag,因此稳定版一发布就落在 latest——也就是 npm install 与 dsh plugin add 解析到的那个标签;预发布版只进 alpha,需要显式带上标签或版本号:

dsh plugin --profile web add @eddyskywalker/dsh-chatgpt-subscription@alpha
npm install @eddyskywalker/dsh-chatgpt-subscription@alpha

方式 2:在 DSH 界面里安装

DSH 没有插件市场;Web 界面的 Plugins 页提供按包名安装的入口(底层与 dsh plugin add 相同):

  1. 打开侧栏的 Plugins 页;
  2. 在添加插件的输入框里填 @eddyskywalker/dsh-chatgpt-subscription 并安装;
  3. 重启 dsh web。

方式 3:本地开发调试(源码软链接)

如需进行二次开发或本地源码调试:

git clone https://github.com/Aa728848/dsh-chatgpt-subscription.git
cd dsh-chatgpt-subscription
npm install
npm run build

# Linux
npx @deepseek-ai/dsh plugin --profile web add "link:/absolute/path/to/dsh-chatgpt-subscription"

# Windows PowerShell
npx @deepseek-ai/dsh plugin --profile web add "link:C:\absolute\path\to\dsh-chatgpt-subscription"

使用

  1. 重启 dsh web;
  2. 打开 设置 → Codex 订阅;
  3. 完成 ChatGPT 登录;
  4. 执行 测试连接。

DSH 模型选择器应显示 “Codex(ChatGPT 订阅)”。GPT-6 系列与 GPT-5.6 系列的有效上下文窗口在“Codex 订阅 → 增强功能”中配置。子代理的模型与思考深度由 DSH 自身的设置决定(Subagent 卡片授权的模型清单,以及 agent-default-model 的默认路由;该卡片 0.1.5 及以前在「设置」页,0.1.6 起在 Plugins 页);最大嵌套深度由 DSH 侧决定(0.1.5 及以前取 preset 中 tool-subagent 的 maxDepth,默认 3;0.1.6 起取 subagent 服务的设置,默认 1)。

设置 → Codex 订阅 → 网络代理 同时控制 GPT 与 Antigravity(Gemini)的 Host 请求,可选择系统代理(自动检测)、自定义代理或直连。Gemini 模型生成、网页登录后的令牌交换、令牌刷新、账号信息、项目发现、配额与模型目录查询均使用此设置;修改后对后续请求生效,无需重启 DSH。浏览器中的 Google 授权页面使用浏览器自己的网络设置。

已经用官方 Codex CLI 登录过的用户可以跳过第 3 步的 OAuth:设置 → 订阅服务 → ChatGPT,在账号池卡片里点「登录」旁边的「导入本机 Codex CLI 登录」即可(见「本机登录」)。

Command Code

  1. 重启 dsh web;
  2. 打开 设置 → Command Code;
  3. 点击 浏览器登录(或把 Command Code Studio 里创建的 API Key 粘到「手动填写 API Key」里保存);
  4. 登录完成后按需勾选模型、设置上下文窗口与默认思考深度。

command-code 会像其他 Provider 一样出现在 DSH 模型选择器中。线路按模型 id 自动选择:claude-* 走 Anthropic Messages,其余走 OpenAI Chat Completions;设置卡片的模型标签会显示每个模型对应的线路。

路由归属:DSH 的 registerAdapter 对重复 Provider 是 all-or-nothing 并抛 DUPLICATE_ADAPTER,因此若 command-code 已被别的适配器占用(典型情况是内置 llm-pi-ai 用同一端点声明过同名 Provider),本插件不会加载失败,而是在卡片上显示“模型路由已被其他 Provider 占用”;从占用方的配置里移除该 Provider 后,插件会在下一次路由变更事件时自动接管,无需重启 DSH。

上下文窗口默认取 Command Code 模型目录的 context_length,可在卡片中逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 1M / 512K / 200000 等写法)。默认思考深度逐模型生效:下拉里列出的档位可按模型能力选用(minimal / low / medium / high / xhigh / max),实际发给上游前会按当前模型声明的档位取值——模型不声明该档位时不发送。对 Anthropic 线路映射为 thinking 预算(minimal 1K / low 2K / medium 8K / high 16K / xhigh 24K / max 32K),预算放不下时该请求不启用 thinking;对 OpenAI 线路映射为 reasoning_effort。

额度来自 /alpha/billing/credits、/alpha/billing/subscriptions 与 /alpha/usage/summary,三条线路相互独立容错,页面可见时最多每 60 秒刷新一次;解析不出有界额度时显示空态而不是 0%。

额度卡片展示:套餐名(由订阅返回的机器 id 查表得出,表在 src/host/command-code/plans.ts,按最长前缀匹配)、订阅状态与续费日期、滚动窗口用量(windowLimits 的 fiveHour / weekly,按官方 CLI 同款标签 5-hour / Weekly 显示,并各自带重置倒计时),以及余额明细(月度额度 / 已购额度 / 赠送额度,另附合计)。服务只回报数字不回报名称的字段一律补上可读标签——窗口按 key 命名,余额按池命名,实在没有名字的兜底为 Extra allowance 并注明来源,不会渲染成 meter-1 这类无意义编号。

搜索来源 切换 DSH 的搜索后端;网页抓取来源由下面的抓取模式决定。模式为 auto(默认)时跟随此处的搜索选择:选择 ChatGPT 来源后,网页也改由本插件在 Host 抓取,并使用上述网络代理设置;模式为 dsh 时即使选了 ChatGPT 搜索,抓取也仍由 DSH 原有来源完成。纯 TUN 模式可使用直连,流量由虚拟网卡接管。来源切换即时生效,DSH web 服务重载后会重新注册插件后端,并保留切回 DSH 默认来源所需的配置。设置页在该选择器下方只读展示 Host 上报的抓取来源、切换器状态、抓取模式与插件上限;Host 未提供这些字段(较旧的 Host)时整个区块不显示。

网页抓取后端(web_fetch) DSH 内置抓取 provider 会先解析域名、校验并固定解析结果,而且只在进程环境变量里读到代理时才走代理——系统代理对它不可见。代理工具(Clash/Mihomo 等)常把域名解析成自己的 fake-ip 地址(默认 198.18.0.0/15),于是内置 provider 直接以 WEB_BLOCKED_URL(resolves to a non-public IP address)拒绝,代理根本没被用上。因此在 auto 模式下,只要插件配置了可用代理(网络代理 选系统代理且检测到,或填写自定义代理),web_fetch 就改用本插件的 provider:由代理解析源站,与 DSH 对“走代理的请求”采用的语义一致;未配置代理时仍由 DSH 内置 provider 抓取,保留其解析与固定策略。若在纯 TUN 模式下把代理设为直连,内置 provider 会重新接管(auto 模式下),此时可改回系统代理让插件接管抓取。代理如果在 DSH 启动之后才可用(代理工具后启动,或首次探测失败),插件会在下一次探测到代理时重新选择抓取后端,不必重启或改设置。

抓取模式与上限(插件 Config)

抓取模式与上限属于插件部署配置,不在设置页的偏好里:设置页只读展示当前值,要改写在 profile 的 cordis.patch.yml 里,重载插件或重启 DSH 后生效。

写在安装时已有的那一条插件行上(id: dsh-chatgpt-subscription,包名 @eddyskywalker/dsh-chatgpt-subscription)的 config 片段:

# $DSH_HOME/profiles/<profile>/cordis.patch.yml
- id: dsh-chatgpt-subscription
  config:
    fetchProvider: auto              # auto | plugin | dsh
    fetchMaxBodyChars: 100000        # 解码后正文保留的字符数
    fetchMaxResponseBytes: 2097152   # 响应体保留的字节数(2 MiB)

patch 按 id 定位条目并整体替换它的 config,所以在这一行上追加字段时请保留原有的其它字段。

| 字段 | 默认 | 含义 | |---|---|---| | fetchProvider | auto | auto 跟随搜索来源(有可用代理或选了 Codex 搜索时用插件抓取);plugin 始终用本插件抓取;dsh 强制保留 DSH 原有的抓取来源,即使有代理或选了 Codex 搜索也不接管 | | fetchMaxBodyChars | 100000 | 解码后交给工具的正文上限(字符) | | fetchMaxResponseBytes | 2097152 | 进入解码前的响应体上限(字节) |

两者都必须是正安全整数,否则该配置不被接受(DSH 不会把非法值当成 0 使用)。

必须说清的四条边界:

  • fetchMaxResponseBytes 是“读进来之后再截断”,不是下载量或内存的硬上限。 实现仍是 response.arrayBuffer() 先把整个响应体读进内存,超出部分才被切掉;调小它省不下下载流量和峰值内存,只能限制进入解码与工具结果的内容量。
  • 工具层另有上限。 这两个数字只管本插件 provider 交给 web_fetch 的内容,DSH 工具结果本身还有自己的裁剪预算,因此调大它们并不保证取回完整页面。
  • 两个上限只在实际使用插件抓取时生效;走 DSH 原有抓取来源(dsh 模式,或 auto 模式下本次抓取没落到插件)时不适用。设置页会直接写明这一点。
  • plugin 抓取不做 DNS 固定(pinning)。 内置 provider 会解析并固定解析结果,而代理的 fake-ip DNS 让这一步无法照搬;本插件沿用既有安全模型——只做 http/https 与目标地址不得落在私网/回环的校验,域名交给解析它的代理解析,解析失败也放行。抬高上限不改变这条边界。

卸载前建议先在设置页点击 “注销”,它会删除当前平台的凭据和 Host 内存中的额度缓存。

若 DSH 已异常退出,可在确认路径后手动处理凭据文件:

  • Windows:%DSH_HOME%\storages\dsh-chatgpt-subscription\oauth.dpapi,未设置 DSH_HOME 时为 %USERPROFILE%\.dsh\storages\dsh-chatgpt-subscription\oauth.dpapi;
  • macOS:凭据位于登录钥匙串,可执行 security delete-generic-password -s dsh-chatgpt-subscription -a oauth 删除;
  • Linux:$DSH_HOME/storages/dsh-chatgpt-subscription/oauth.json,未设置 DSH_HOME 时为 ~/.dsh/storages/dsh-chatgpt-subscription/oauth.json。

Windows 文件只能由创建它的用户通过 DPAPI 解密。macOS 凭据由登录钥匙串在本机加密保存。Linux 文件是未额外加密的 JSON,依赖目录 0700 和文件 0600 隔离;不要复制、打印或提交该文件。跨平台迁移需要重新登录。

随包分发的 Agent Preset

插件自带一个 调度模式 agent preset(id dispatch),随 npm 安装一起分发:0.1.7 起 harness 不再从发现根目录读取 preset,插件改为运行时注册(src/host/agent-preset.ts:探测 @deepseek-ai/dsh-agent-preset 能否解析、agentPresets 服务是否在场,然后在 presets/dispatch/preset.yml 与 agent.cordis.yml 转录出的定义上调用 register(),注册失败只记 warn);0.1.6 及以前仍按老办法把包内 presets/dispatch/ 同步到 <dshHome>/.agent-presets/。两条路都让装了本插件的机器在新建会话时直接选到它,不需要手工拷贝文件。

为什么不用静态声明行:0.1.7 的 preset 声明要写进 bundle patch,而 assertEntriesLoaded 会把「无 fiber 且未 disabled」的条目判为启动失败——@deepseek-ai/dsh-agent-preset 在 ≤0.1.6 上并不存在,静态声明会让那些机器直接开不了机。声明行也不能按运行环境条件化,所以选择运行时注册 + 能力探测。

同步在每个 profile 启动时执行一次(幂等):

  • 目标树与包内副本逐字节相同时跳过,有差异时整体重写,并把包内已删除的多余文件清理掉;
  • 行里的包名按运行环境改写:preset 要挂载 @deepseek-ai/dsh-workflow-worker-thread,而 harness 0.1.6 把它改名成了 @deepseek-ai/dsh-workflow-ptc,指向不存在的包会让整个 preset 被判为 broken、既不可选也不可复制。同步时用 import.meta.resolve 探测当前安装能解析哪个名字(旧名仍在就保留,否则改写成新名;两个都不可用时不改写,因为改名只会掩盖试过哪个),所以同一份 preset 在 0.1.5 与 0.1.6 上都能挂载;
  • 只处理本包自己的 preset id(BUNDLED_PRESET_IDS),绝不改动用户手写的 preset 或其它插件的 preset;
  • 包内已不再随附的旧 id 会从目标根目录移除(retire);
  • 同步失败(例如 home 只读)只记一条 warn,不会导致插件加载失败——preset 是便利项,不是本插件提供的核心能力。

路径解析不写死相对路径:src/host/preset-sync.ts 从模块位置向上查找最近的 package.json 作为包根,因此 src/ 布局、打包后的 lib/ 布局,以及通过 pnpm symlink / Windows junction 安装都能正确解析。注意 fs.cpSync({ recursive: true }) 在 Node 22 + Windows 上遇到含非 ASCII 的源路径会直接崩进程(nodejs/node#54476),所以复制是逐条目实现的。

与 Agent Teams 不兼容(刻意互斥)

DSH 的 Agent Teams(bundle @deepseek-ai/dsh-experimental-agent-team-profile)会在每个会话自己的作用域里注册一套与内置同名的协调工具。工具注册表按作用域链解析、近的层遮蔽远的层,所以一旦该 bundle 被组合进来,会话里的 send_message、list_agents、interrupt_agent 就都换成了 teammate 版:

  • list_agents() 只列 Team 成员(Lead 自己显示为 lead),看不到 subagent 派出去的子代理;
  • send_message 的 target 只接受成员名,把子代理的 session id 传进去会抛 active teammate "…" not found(实测);
  • 于是「派得出去、回访不了」——subagent 的孩子只能等完成通知,无法追问。

坏消息在时机上:Agent Teams 的 agent-team/src/roster.ts 里 tryMembership 对任何「无 parentSession、且不是 subagent descriptor」的 Agent 直接判为 lead,不需要先有 teammate。于是 team 工具从会话第一轮起就装在 Lead 上,调度模式还没派发第一个子代理,复审与返工所依赖的三个工具已经没了。

上游对此的立场是明确的: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 的那四行不是同一批实例)。所以这不是「可以调好的配置」,而是一个上游明确不承诺的组合。

dispatch 的处理是停,不降级(persona 的 R0.5 兼容性闸门,每个新会话判一次,早于 R0 分诊):

| 判据 | 行为 | |---|---| | spawn_teammate 与 wait_agent 都不存在 | 编排可用,写一行「编排可用:subagent」后按 R0 → R-G → R5 → R6 正常走 | | 任一存在 | 本会话不可编排:一句话说明 → 一次 ask_user_question 给出三条出路 → 用户答复前不分诊、不规划、不派发、不动文件 |

三条出路是:① 关掉 Agent Teams bundle、重启 Host 后新建会话;② 换用别的 preset,本会话不编排;③ 本次直接做,不进编排流程。都要新建会话——工具面在会话启动时就定死了,改完配置在旧会话里也不会回来。

刻意没有保留「切到 teammate 词汇继续编排」这条分支(原 R-T)。三条理由:

  1. 遮蔽由 scope 链决定,persona 改不回工具注册表——「适配」只能改行为,改不了「哪些工具被顶替」这个事实;
  2. 那条分支把「回访不了」从明摆着的失败变成看不见的失败:roster 里查不到孩子 ≠ 孩子没了,模型会误判并重复派发,白烧一轮预算;
  3. teammate 结构上拿不到 per-task 路由(见下节),而 R2 显式路由正是这套设计里最值钱的部分——组队等于自愿放弃它。

想把误用也用机制挡掉:把 spawn_teammate 从 inherit 清单去掉即可,配置 subagentModelInheritTools: ['subagent_fork'],该工具在守卫里就变成硬拒(拒绝理由指向 subagent),而不是让它悄悄按 Lead 的路由跑完整轮。插件默认值不动——那是全局设置,改它会波及不使用调度模式的会话。

回合边界纪律(R-W)

调度模式的 persona 里有一条专门管「回合边界」的规则 R-W,约束三件最容易把编排拖慢、拖贵的事:

| 场景 | 规则 | 为什么 | |---|---|---| | 等子代理返回 | 默认结束本轮回复、一个工具都不调,由完成通知唤醒主代理;禁止 sleep、轮询循环和任何只为占位存在的长命令。确实被阻塞时才用 job_output({ wait: true }) 有界地等一次 | 子代理完成通知是自带的;占位长命令不产出信息,只烧上下文和预算,还把用户晾在一段沉默里 | | 任务开始建目标 | 除非用户明确要求,否则不调用 create_goal / /goal,任务清单一律走 todo_write | 机制性的:目标一旦激活,DSH 会自动续跑唤醒主代理,而子代理何时返回不由它控制——等待被从中间劈开,模型重新分诊、重新检查「还差什么」,每次续跑还要重载整段历史 | | 需要用户拍板 | 一切「我停在这里是因为缺一个决定」的停点(收到子代理结果要选下一步、验收不过要定返工范围、前提被推翻要改计划)都用 ask_user_question 递出去,并给出选项与推荐答案 | 提问是代理的工具,不是用户的义务:否则用户得先替模型把那段话翻译成一次输入。例外是 plan mode 的计划审批(走 exit_plan_mode)与任务完成后的收尾 |

三条各自对应 persona 反模式列表里的第 13–15 条。此外,本插件在运行时通过 system-prompt/assemble 原位重写 list_subagent_models 与 subagent 工具描述中的 "Catalog membership is advisory" / "Child LLM selection is optional..." 误导措辞,并通过 tools/post-execute 在每次 list_subagent_models 返回末尾直接附上本会话全部已授权的 { provider, model } 拆解对;R2 与 plan-mode 提示词也同步写明 list_subagent_models 是本会话允许清单的唯一真源,直接采信其输出即可,无需仅为了确认哪些子代理模型可用去翻找本地配置文件或工作区代码(对应 Anti-Pattern 第 16 条)。

为什么不降级:teammate 不能选模型

这是上面第三条理由的技术底座,也是上游修好之后才谈得上重新评估兼容性的前提。

spawn_teammate 目前无法指定 provider/model,这不是插件的问题,而是 Agent Teams 有意不做 per-teammate 路由。三层都已核对:

| 层 | 能否带路由 | 证据 | |---|---|---| | 工具入参 | ❌ | spawn_teammate 的 schema 只有 name/description/prompt/context | | Team 服务 | ❌ | SpawnTeammateRequest.provider 是 subagent 后端名(spawn/fork),不是 LLM provider;且无 model 字段 | | 底层 API | ✅ | ContinuableStartSpec.request 可带 agentOptions(含 provider/model/reasoningEffort),但 Team 服务构造 request 时只放 prompt 与 parent,整个省略 |

因此成员必然跑在 Lead 自己的路由上——这正是守卫把它归 inherit 模式的原因,也是不应把它加进 explicit 的 subagentModelTools 的原因。

插件侧无法绕过,四条路都已验证死:pre-execute 明确排除输入改写(参数已被记录与呈现,PreToolDecision 只有 allow/deny/cancel/ask);agentTeams 服务在内部丢弃后包装不到;注册自定义 subagent provider 也拿不到路由(agentOptions 在 continuation manager 就已解析完,provider 只返回 seed);唯一能改子会话路由的 selectForNextRequest 只作用于「下一个请求」,而 teammate 创建后立刻开跑,抢不进去。

上游正路:在 packages/experimental/agent-team/src/roster.ts 构造 startContinuable 的 request 处补上 agentOptions,并给 SpawnTeammateRequest 加字段、给工具 schema 加参数、创建前接 assertAllowedModelSelection。该改动落地后,spawn_teammate 就应从 subagentModelInheritTools 移到 subagentModelTools(explicit)——否则它会变成「能选模型却没人管」。只补这一条还不足以解除互斥:team 工具的遮蔽发生在会话第一轮(见上节),要真正共存还需要把安装条件从「是 team 成员」收紧成「有 teammate」,让没有队友的会话保留内置的 subagent 协调工具。

实践提醒:inherit 模式校验的是当前会话路由。若当前会话跑在允许清单之外的路由上(例如默认模型与勾选清单不是同一条),teammate 与 subagent_fork 都会被拒绝——拒绝文案会指出恢复路径(改用显式路由的 subagent,或先把会话切到清单内的模型)。subagent 的显式路由不受影响。

配置项

| 字段 | 默认 | 含义 | |---|---|---| | syncAgentPresets | true | 启动时是否把包内 preset 同步到 <dshHome>/.agent-presets;设为 false 则完全不写用户目录 |

手动安装(可选)

不想让插件写 home 目录时,可把 syncAgentPresets 设为 false,再自行拷贝包内的 presets/dispatch/ 到 <dshHome>/.agent-presets/dispatch/。

子代理模型授权(0.2.15 起,0.3.2 起强制指定模型)

DSH 设置页的「Subagent」卡片会把勾选的模型写成会话级的允许列表(会话日志事件 subagent/model-selection-policy)。DSH 内置委派工具只拒绝模型显式填写且不在列表内的路由;调用里不写 provider/model 时,子代理会继承父级模型,于是白名单之外的主模型(例如 deepseek-official/deepseek-flash)仍会被子代理使用。

插件在 Host 工具注册表上补一个单调守卫(ctx.tools.guard),在委派执行前要求每次委派都必须写明路由:

  • 调用会话(或最近的、记录了策略的祖先会话)带有允许列表时,provider 与 model 必须成对给出,且该路由必须落在列表内——缺省不再回退到配置默认值或父级模型;
  • 只写一半(例如只给 model)同样被拒绝,拒绝理由会指出缺的是哪一个字段;
  • 子代理永远和主代理同一个模型的历史行为由此消失:模型必须先用 list_subagent_models 查出已授权路由,再按拒绝理由里列出的路由(例如 antigravity/gemini-3.8-flash)重试;该工具也只展示已授权路由;
  • 未记录允许列表的会话(例如恢复的旧会话、未启用该设置的会话)保持 DSH 原有行为(继承父级模型)。

inherit 模式(subagentModelInheritTools,默认 ['subagent_fork', 'spawn_teammate']):有些委派工具按设计就没有路由参数,子代理必然跑在调用者自己的路由上——subagent_fork(复用对话与 KV Cache)与 Agent Teams 的 spawn_teammate(成员一律继承 Lead 的路由)都是这一类。「工具不能选」不等于「这个选择被授权」,所以守卫改为校验它实际继承到的路由:允许清单内有该路由就放行,没有就拒绝,并说明该工具无法改路由、要么改用能显式指定路由的 subagent、要么先把本会话切到清单内的模型。设为 [] 可关闭 inherit 模式的全部校验。

守卫装在 DSH 工具注册表的调度入口上,因此 run_code(代码模式 / PTC)里通过 SDK 调用的 tools["subagent"] 同样被拦截:该子调用走的是与直接调用相同的 prepare → guard → dispatch 流水线,拒绝理由以 ToolCallError 抛回程序。也就是说模型无法靠把委派写进代码里绕过白名单(test/subagent-model-authorization-ptc.test.ts 用真实 ToolRuntime + 假 code runtime 验证了放行、缺省拒绝与越权拒绝三条路径)。

配置项(插件行 config,全部可省略):

| 字段 | 默认 | 含义 | |---|---|---| | subagentModelAuthorization | true | 是否启用上述授权守卫;设为 false 回到 DSH 原有行为 | | subagentModelTools | ['subagent'] | 需要授权的委派工具名(explicit:必须成对给出 provider+model);preset 里自定义了 toolName 时在此列出 | | subagentModelInheritTools | ['subagent_fork', 'spawn_teammate'] | 按设计继承调用者路由的委派工具(校验实际继承到的路由);设 [] 关闭 | | subagentModelScope | session | session 只约束记录了允许列表的会话;preference 额外用当前设置卡列表约束未记录的会话 |

同一份插件行 config 里还有推理塌缩守卫的开关 reasoningCollapseGuard——默认 false(关闭),功能保留、将来需要时按推理塌缩守卫(熔断,默认关闭)一节显式打开。

改动只在设置卡片里保存过的勾选生效:设置改动只影响之后新建的会话(DSH 的会话快照语义),已运行的会话继续使用它自己记录的那份列表。

升级提示:从 0.3.2 起,带有允许列表的会话里任何未写明 provider + model 的委派都会被拒绝(此前只有写明且不在列表内的路由会被拒绝)。这是有意的行为变更——它消除了「子代理悄悄继承主代理模型」的漏洞;把 subagentModelAuthorization 设为 false 可回到 DSH 原始行为。

Kimi Code

  1. 重启 dsh web;
  2. 打开 设置 → Kimi Code;
  3. 点击 设备码登录,在弹出的浏览器页面确认授权(页面已预填用户码;也可手工复制用户码到 verification_uri);
  4. 登录完成后按需勾选模型、设置默认思考档位与上下文窗口。

kimi-code 会像其他 Provider 一样出现在 DSH 模型选择器中。上下文窗口默认取模型目录值,可逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 1M / 256K / 200000 等写法)——注意 k3 的 1M 上下文需要 Allegretto 及以上套餐,因此默认按 256K 计算,升级后再在此覆盖为 1M。默认思考档位只提供 low / high / max 三档与「关闭思考」(服务对这三档以外的取值直接报 400);切换模型或切换档位都会使上下文缓存失效,建议在同一会话内保持一致。

额度倍率取自官方模型表并显示在设置页模型能力表的「说明」列(悬停可一并看到):k3 = 2×、k3-256k = 1×、kimi-for-coding = 1×、kimi-for-coding-highspeed = 3×。倍率绑定模型 id,与上下文长度、缓存命中率都无关——选 k3 就是 2×,哪怕只用几千 token。注册表不认识的新模型 id 显示为未知而不是猜成 1×。

区域:默认使用中国大陆主机(auth.kimi.com / api.kimi.com)。国际账号可设置 DSH_KIMI_CODE_OAUTH_HOST=https://auth.kimi.ai 与 DSH_KIMI_CODE_BASE_URL=https://api.kimi.ai/coding 后重新登录;环境变量同时会钉住区域,设置页会显示当前解析到的主机。

推理塌缩守卫(熔断,默认关闭)

本线的“熔断器”就是推理塌缩守卫(src/host/reasoning-collapse-guard/index.ts)。一个长推理流可能退化成复读——反复绕过同一小撮短语、既不调工具也不收尾,一直到输出上限把这一轮截断(曾经有一次会话就这样烧掉 128,000 输出 token 并返回空答案)。守卫订阅 llm/stream 瀑布,对尾部推理窗口同时算两个信号:

  • 字面重复度:n-gram 唯一性,健康推理接近 0,退化流接近 1;
  • 语义复现度:每条句子有多强地重复了 semanticLag 句之前已经说过的内容——用来抓“换着词说同一件事”,这类流的字面分只有 0.48,永远碰不到 0.85 的阈值。

两个信号必须在同一个窗口同时越线,并且连续 semanticConfirmations 个窗口都如此,守卫才会切断本轮流;切掉之后它只做一件事:在 Agent 空闲时 steer 一条续跑,让这一轮在新的步骤上跑完。单个信号或单个异常窗口只记日志、放行——误杀一段健康回答的代价比放过一次失控更大。

现状:默认关闭。 这个熔断在生产轮次里已经没有需要,所以本线不再默认接电;功能、实现与全部测试都原样保留,等将来需要时再打开。

| 现象 | 关闭后 | |---|---| | llm/stream 订阅 | 不注册(守卫连 ctx.effect 都不装) | | 每回合的熔断簿记 | 不建立 | | 切断后那条续跑 | 不排队 | | 运行时开销 | 零:默认配置下这段代码根本不会进入执行路径 |

将来需要时怎么打开

守卫的开关是插件行 config 里的 reasoningCollapseGuard,写在 profile 的 cordis.patch.yml(与「抓取模式与上限」同一位置,重载插件或重启 DSH 后生效):

- id: dsh-chatgpt-subscription
  config:
    reasoningCollapseGuard: {}        # 空对象 = 用出厂默认值把熔断接回来

想调参就在这个对象里写字段;省略的字段取出厂默认值:

- id: dsh-chatgpt-subscription
  config:
    reasoningCollapseGuard:
      threshold: 0.85                 # 字面重复度阈值(默认 0.85)
      windowChars: 4096               # 每次参与评分的尾部推理字符数(默认 4096)
      maxBreaksPerTurn: 3             # 单回合最多切断几次(默认 3)
      cooldownMs: 30000               # 两次切断的最小间隔毫秒(默认 30000)
      semanticThreshold: 0.35         # 语义复现度阈值(默认 0.35)
      semanticConfirmations: 3        # 双信号需连续命中的窗口数(默认 3)
      includeModels: [gpt-6.1-sol]    # 只看这些模型;空数组 = 看全部(默认 [])

| 取值 | 含义 | |---|---| | 不写(缺省) | 关闭——2026-10 起的出厂默认 | | {} | 打开,全部取出厂默认值 | | 对象(含调参) | 打开,按对象覆盖默认值;数字由守卫自己的 fail-loud 校验,非法值会让插件加载失败而不是被静默忽略 | | false | 显式关闭(与缺省等价,写出来更自明) |

将来重新开启前先验证一件事:守卫与续跑队列共用 llm/stream 的外层位置,开启后它在切断时不会给出 finish chunk,因此 noAnswerResume(无答案续跑,默认仍开启)在那种被放弃的流上不结算、也不消耗预算——这条约束在 0.26.0 的续跑预算修复里已经落实并有回归用例(test/no-answer-resume.test.ts)。若将来改了守卫的切断方式,需要同时复查这条边界。

升级提示:默认安装的 Host 升级后不再有任何塌缩熔断与随之的续跑;依赖“死循环自动刹车”的部署按上面的 YAML 显式写回即可。新增回归用例 test/circuit-breaker-default.test.ts 钉住了“默认必须关闭”和“打开后仍可用”两半。

Command Code 线路

插件注册 command-code Provider,对接 Command Code 的两套接口:

| 用途 | 地址 | | --- | --- | | 模型生成(Anthropic 格式) | https://api.commandcode.ai/provider/v1/messages | | 模型生成(OpenAI 格式) | https://api.commandcode.ai/provider/v1/chat/completions | | 模型目录(公开) | https://api.commandcode.ai/provider/v1/models | | 账号信息 | https://api.commandcode.ai/alpha/whoami | | 额度与用量 | /alpha/billing/credits、/alpha/billing/subscriptions、/alpha/usage/summary | | 浏览器登录页 | https://commandcode.ai/studio/auth/cli |

模型 id 决定线路(claude-* 为 Anthropic),这也决定了请求体形态:Anthropic 线路的系统提示词放在顶层 system、工具用 input_schema、工具结果用 tool_result 内容块;OpenAI 线路的系统提示词是 messages[0]、工具用 function.parameters、工具结果用 role: "tool"。两条线路都只把 DSH 交付的可见文本、图片与工具调用发出去——reasoning 块不会被回放,因为这里的上游都不接受缺少签名的思考块。

模型能力表(src/host/command-code/model-catalog.ts)逐模型声明 inputModalities、reasoningEfforts、contextWindow 与可选的输出上限,内容转录自官方 CLI 的模型注册表——公开的 /provider/v1/models 只有 id、名称与 context_length,既不说模态也不说思考档位,而族级前缀推断在同一厂商内部就会出错(见上)。模型不在表内时按纯文本、无思考档位处理:DSH 会把图片转成一条可见的占位文本让用户改选模型,而反过来把图片发给不接受它的端点会让整个请求失败。

图片以 base64 内联(OpenAI 线路 image_url 的 data: URL,Anthropic 线路 image 块的 base64 source);单次请求的图片负载超过 12 MiB 时按最旧优先替换为本插件同款占位文案。读不出字节的图片降级为可见说明文本,不会被静默丢弃。

失败分类与重试:command-code 路由在注册时携带一份显式的 normal retry policy(maxRetries: 3、initialDelayMs: 1500、maxDelayMs: 15000、jitterRatio: 0.2),可重试码为 RATE_LIMIT、SERVER、TIMEOUT、TRANSPORT——与 codex-chatgpt 路由同源,只是未包含该路由的历史码 SERVER_ERROR/NETWORK。分类规则:HTTP 5xx(含上游 502)→ SERVER;连接层失败(fetch 抛错)→ TRANSPORT;429 → RATE_LIMIT 并附 Retry-After(上限 10 分钟);401/403 → INVALID_CREDENTIAL(换 Key,不重试);流式空闲超时由看门狗转成 TIMEOUT。策略由 DSH 的 dsh-llm-retry 插件在 agent/request-error 上执行,每次重试都会写入 llm/retry 会话事件。

凭据存储:API Key 使用与 Antigravity 相同的系统凭据存储——Windows 是 CurrentUser DPAPI($DSH_HOME/storages/command-code-credentials.json.dpapi),macOS 是登录钥匙串,Linux 是 Secret Service(服务名 dsh-command-code,账号键按旧凭据文件绝对路径生成)。旧版明文 JSON 只作为迁移来源,读取后加密回写、校验并删除;注销会同时清理两者。凭据只存在于 Host 内存与系统凭据存储中,不会进入浏览器、settings.yaml 或日志。

浏览器登录的回环服务器只在 127.0.0.1 上监听 5959 起的空闲端口,只接受与该次登录 state 匹配的回调,10 KB 请求体上限,5 分钟超时;回调成功后浏览器标签页会跳到 /callback/complete 上的人工可读页面。登录成功后 Studio 页面回传的 API Key 会先经 /alpha/whoami 验证,验证失败的 Key 不会被保存。

插件路由(Command Code)

所有路由都以 /command-code/api 为前缀:

| 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /status | 账号(脱敏)、额度、模型目录与路由归属 | | POST | /login | 开始浏览器登录,返回登录页地址 | | GET | /login/status | 查询登录进度 | | POST | /login/apikey | 校验并保存手动填写的 API Key | | POST | /logout | 注销并清理凭据与缓存 | | GET / POST | /quota | 强制刷新额度(POST)或读取当前状态(GET) | | GET / POST | /models | 读取或更新勾选的模型与上下文窗口 | | POST | /settings | 更新默认思考深度与上下文窗口覆盖 | | POST | /catalog/refresh | 强制刷新模型目录 | | POST | /connection/test | 用已存凭据调用 /alpha/whoami 测试连接 |

与 codex-chatgpt 线路一样,所有修改状态的路由只接受同源 JSON POST,并校验 Origin 与 Host。

WorkBuddy 线路

  1. 重启 DSH,让 Host 加载本插件;
  2. 打开 设置 → WorkBuddy;
  3. 二选一:登录 CodeBuddy 桌面端后点「重新扫描」,或点「账号管理」右上角的「添加国区账号 / 添加国际区账号」并在官方页面完成浏览器授权;
  4. 在「账号管理」里选择账号(每条都标注国区 / 国际区),再按需勾选模型、设置默认思考深度与上下文窗口。

workbuddy-subscription 会像其他 Provider 一样出现在 DSH 模型选择器中,并可与名为 workbuddy 的自定义 API 同时存在。上下文窗口默认取网关 /v3/config 声明的默认服务长度,可逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 1M / 300K / 200000 等写法);默认思考深度逐模型生效,选项由当前账号各模型实际声明的档位取并集(仅部分模型支持的档位会标注数量),档位不在该模型集合内时不会被发送。

消耗倍率也来自同一份目录:每个模型在 /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。

凭据目录按平台解析,可用 CODEBUDDY_AUTH_DIR 覆盖(与官方工具链一致):

| 平台 | 默认目录 | | --- | --- | | Windows | %LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth | | macOS | ~/Library/Application Support/CodeBuddyExtension/Data/Public/auth | | Linux | $XDG_DATA_HOME/CodeBuddyExtension/Data/Public/auth(默认 ~/.local/share) |

目录里通常同时存在当前凭据与若干带时间戳的历史快照。插件优先取 workbuddy-desktop.info / codebuddy-desktop.info 这类规范文件名,其余按 token 剩余有效期取最长的一个——只按文件 mtime 选会选到过期快照。卡片会列出目录里所有可用凭据,标明各自区域。

失败分类与重试:这条线路把失败分成「换号能解决」与「换号也一样」两类,判据不是状态码本身。

  • 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 原样重放同一份请求体:续期成功即说明凭据还活着,不写任何账号状态;只有续期本身被上游拒绝才把该账号记为需要重新登录,此时才换号。
  • 请求期不写「需要重新登录」:401 只让该账号退出本次请求的轮换,不写号池状态。此前一次 lane 级的 401 会在同一个请求里把每一个账号依次写成 expired,而号池没有任何清除路径,于是整条线路要求全部重新登录。
  • 自愈:被标记的账号在每个请求前与卡片列表前都会重新对照权威存储(桌面账号看 CodeBuddy 自己的凭据文件、托管账号看插件的加密存储);换了另一枚未过期 token 就清掉标记并采用新凭据,仍持着被拒那枚的账号保留标记。
  • 429 冷却换号:按 Retry-After(缺省 5 分钟,上限 10 分钟)冷却该账号,并用同一份 body 换下一个账号重试。

上游接口:

| 用途 | 路径(前缀为区域后端) | | --- | --- | | 模型生成 | POST /v2/chat/completions(仅流式) | | 模型目录 | GET /v3/config | | 浏览器授权 | POST /v2/plugin/auth/state + GET /v2/plugin/auth/token | | 令牌续期 | POST /v2/plugin/auth/token/refresh | | 额度 | POST /billing/meter/get-user-resource | | 签到状态 | POST /billing/meter/checkin-activity-status(仅国区) | | 每日签到 | POST /billing/meter/daily-checkin(仅国区) |

两区后端分别是 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,因此不做按端点切换。

每日自动签到(仅国区;语义与 workbuddy2api 的 daily_checkin.py 对齐):DSH 启动时自动签到一轮,运行期间每 10 分钟幂等补检(当日已签的账号不再发请求);签到前先查签到状态,token 过期会自动续期并回写(桌面账号写回 CodeBuddy 自己的凭据文件)。失败当天最多自动重试 3 次;活动尚未开启的账号不会当天放弃——首次签到状态若报无权益,之后每小时复查一次,避免开机早于活动开放时间就错过当天。国际区账号不参与(国际后端没有签到活动)。DSH 没开机的当天不会签到——插件不是常驻服务。设置页「每日签到」区块可开关自动签到、查看「今日已签 x/y · 无活动 z · 失败 w」并手动「立即签到」(手动会重跑一轮并绕过开关与重试上限)。签到状态存在 storages/workbuddy-checkin.json,token 不出 Host。

插件路由(WorkBuddy)

所有路由都以 /workbuddy/api 为前缀:

| 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /status | 账号、额度、模型目录与路由归属(每次都重扫凭据目录) | | GET | /accounts | 列出桌面扫描及插件托管账号(不含 token) | | POST | /accounts/login | 按国区/国际区启动官方浏览器授权 | | GET | /accounts/login/status | 读取授权轮询状态(不含 token) | | POST | /accounts/action | 删除插件托管账号,或隐藏/恢复桌面账号 | | POST | /rescan | 清缓存并重扫凭据目录 | | GET / POST | /quota | 强制刷新额度(POST)或读取当前状态(GET) | | GET / POST | /models、/settings | 读取或更新勾选模型、上下文窗口与默认思考深度 | | POST | /catalog/refresh | 强制刷新网关模型目录 | | POST | /connection/test | 用已识别凭据向上游发一次最小请求测试连接 | | POST | /checkin/now | 立即执行一轮每日签到(忽略开关与重试上限、不受无活动复查节流限制;当日已签的账号仍跳过) |

与其它线路一样,所有修改状态的路由只接受同源 JSON POST,并校验 Origin 与 Host。

Claude(订阅)线路

风险须知(请先读)

本线路以 Claude Pro / Max 订阅登录访问模型。Anthropic 现行条款写明不允许第三方应用提供 Claude.ai 登录、也不允许代用户经 Free / Pro / Max 凭据转发请求,并保留不经预告的执法权;本插件未获 Anthropic 任何授权或认可,你的账号可能因此被限制、暂停或终止。

此前版本在设置卡片上设有一个必须显式接受的确认步骤,并配套一条主机侧门禁;该步骤与门禁均已移除, 现在打开卡片即可直接使用。移除的只是那一步交互——上面这段事实、以及由此产生的风险,都不因移除而改变。 是否使用请自行判断并承担后果。

登录

  1. 订阅 Claude Pro 或 Max,并确保你能在浏览器里登录 claude.ai;
  2. 重启 DSH,让 Host 加载本插件;
  3. 打开 设置 → 订阅服务 → Claude;
  4. 点「登录 Claude 订阅」。默认走手动粘贴:浏览器打开授权页后会把授权码显示在屏幕上,把 <授权码>#<state> 整段复制粘贴回来即可(也接受直接粘贴整条重定向 URL)。若使用 loopback 回调模式, 本机一个可用端口会被自动探测并绑定 127.0.0.1;
  5. 按需勾选模型、设置默认思考深度与上下文窗口。

claude-subscription 会像其他 Provider 一样出现在 DSH 模型选择器中。上下文窗口默认取内置能力表声明的窗口, 可逐模型覆盖(用于 DSH 的压缩与溢出判断,支持 1M / 512K / 200000 等写法);默认思考深度只对声明了 档位的模型生效。档位原样透传(ReasoningEffortId 在 harness 里是无约束 brand,本仓库多条线路都直接使用 xhigh),不做任何收敛,以免把用户选的档位静默降级。

模型表共 17 条:15 条转录自本机随 harness 安装的参照目录(Claude Opus 5.5 已在参照目录中,只是 thinkingMode 一项按官方文档取值,见下),另加 2 条本地新增:Claude Sonnet 5.5 (claude-sonnet-5-5,官方 2026-09-28 发布,1M 上下文 / 128K 输出 / 支持图片;不支持 temperature、思考不可关闭; 官方默认档位为 high,且思考块与会话前缀绑定,因此走 mid-convo 分支并带 block_binding),以及 Claude Haiku 5.5(claude-haiku-5-5,官方 2026-10-07 发布,规格同上;固定 id,无日期后缀也没有别名)。 以下说明针对 Opus 5.5。 它有一条与其它模型不同的硬约束:思考永远开启、不能关闭——官方文档明确 thinking:{type:"disabled"} 与 {type:"enabled",budget_tokens:N} 都会返回 400,因此能力表把它标为不可关闭思考,档位表是控制思考深度的 唯一手段。它的默认档位是 medium(其余带 effort 的模型默认 high),这一点被刻意保留:本仓库有两类模型走 「强制 effort」分支,若把 Opus 5.5 一并归入,就会静默把每次请求抬高一档、花更多钱,因此它走的是普通 adaptive 分支。但它(与 Fable 5.1、Sonnet 5.5 一样)是官方文档列明的思考块前缀校验模型:2026-08-31 之后创建的账号,一旦 前缀变化(压缩、工具列表变化、图片卸载)回放思考块就会每次都 400,因此能力表用 bindsThinkingToPrefix 标记它, adaptive 分支对这类模型额外发送 block_binding: drop_block(不强制 effort)。

它还有一条版本门槛:上游要求申报的客户端版本 ≥ 2.1.280 才为该模型提供服务。能力表用 minCliVersion 记录这一点(只有这一行有门槛,其余 16 行缺省——缺省表示「未知」而不是「无门槛」,不臆造数字)。插件申报的 默认版本为 2.1.293(不低于首次提供 Sonnet 5.5 的 Claude Code 2.1.284,也不低于首次提供 Haiku 5.5 的 2.1.293—— 加这一行时 npm 的 stable 标签仍停在 2.1.285,所以这里必须读 latest 而不是 stable),并且在发出请求之前就本地校验「申报版本 vs 该模型门槛」,不满足时直接给出模型、当前 版本与要求版本,而不是白花一个往返让上游返回 400。测试另有一条不变量:申报的默认版本必须 ≥ 表中每个模型的 门槛——这条锁让「加了高门槛模型却忘了抬版本」无法通过 CI。

Claude Haiku 5.5 有三条与上面两个 5.5 不同的地方,都是照抄官方文档、不是从模型名推的:

  • 它可以关闭思考,但只在低档位。官方明确 thinking:{type:"disabled"} 在 low/medium/high 被接受,在 xhigh/max 是 400——因此能力表把它标为可关闭(canDisableThinking: true),这是本表里唯一一个为真的 本地新增行。这条线路只在调用方明确要求「关闭思考」时才发这个 form,且此时不申报任何档位,请求因此跑在 官方默认 medium 上——正落在被接受的一侧;而想用 xhigh/max 的人一定开着思考,走的是 adaptive form。
  • 它不能沿用 Haiku 4.5 的 budget 表。官方迁移指南写明手动预算形式 {type:"enabled",budget_tokens:N} 在 5.5 上是 400,所以这一行改走 adaptive;又因为官方默认档位是 medium(与 Opus 5.5 同列),它同样不进 mid-convo 分支——那一档会强制 effort: high,等于每次请求 都替用户多花一档。它同样是官方文档列明的思考块前缀校验模型,所以 bindsThinkingToPrefix 为真。
  • 它的思考块只在产出它的账号里有效。官方写明换账号回放会被静默丢弃(请求成功,模型看不到那段推理)。 Claude 号池会在多个账号之间轮换,所以长会话中途换号会表现为「同一段对话里答案质量忽高忽低」而不报错—— 这是换号的行为,不是模型不稳定。另外 5.5 与 4.7 之后的模型用同一个新 tokenizer,同样的文本约多 30% token。

收编本机已有的 Claude Code 登录(可选,默认关闭)

如果你本机已经登录过 Claude Code,可以点「收编本机登录」把它作为一条账号导入,省去再次登录。 两点必须清楚:

  • 开启前插件只探测文件是否存在,不读取内容;只有你显式开启后才读取;
  • 导入的是快照,本插件永不再刷新它。Claude Code 刷新的是同一枚轮换令牌,两个进程各自刷新会互相 作废,进程内的单飞机制解决不了跨进程竞态。快照过期后请回 Claude Code 重新登录,再收编一次;
  • 本插件绝不写入或删除 Claude Code 的任何文件;「停止收编」只移除插件这边的记录。

上游接口

| 用途 | 路径 | 鉴权 | | --- | --- | --- | | 模型生成 | POST https://api.anthropic.com/v1/messages?beta=true | Authorization: Bearer <access token>,且 x-api-key 必须缺省 | | 模型目录 | GET https://api.anthropic.com/v1/models | 同上 | | 订阅额度 | GET https://api.anthropic.com/api/oauth/usage | 同上,另带 user-agent: claude-code/<版本> | | 授权 / 令牌 | https://claude.ai/oauth/authorize、https://platform.claude.com/v1/oauth/token | PKCE S256(端点可用环境变量覆盖) |

请求带有 Claude Code 身份头(user-agent、x-app、anthropic-beta),并在 system 首块声明 Claude Code 身份。 这是订阅令牌被服务端接受的前提,已在代码与测试中显式锁定。

插件路由(Claude 订阅)

所有路由都以 /claude/api 为前缀:

| 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /status | 账号、额度、模型目录、登录流程与路由归属 | | POST | /login | 开始 OAuth 登录,立即返回流程状态(不阻塞) | | GET | /login/status | 轮询登录流程状态(客户端每 2 秒一次,无 SSE) | | POST | /login/cancel | 取消登录并释放回调端口 | | POST | /login/input | 提交手动粘贴的授权码 / 重定向 URL | | POST | /adopt | 收编本机 Claude Code 登录(只读,作快照入池) | | POST | /adopt/disable | 停止收编(不触碰 Claude Code 的文件) | | GET / POST | /quota | 读取或强制刷新额度;失败以 quotaError 呈现而非请求失败 | | GET / POST | /models、/settings | 读取或更新勾选模型、上下文窗口、默认思考深度与选中账号 | | POST | /catalog/refresh | 强制刷新模型目录 | | POST | /connection/test | 向上游发一次最小请求测试连接 | | POST | /accounts | 号池动作:set-primary / set-alias / delete / clear-cooldown / clear-auth-failed / strategy | | POST | /logout | 注销(号池感知) |

插件路由(MiniMax Code)

所有路由都挂在本线路自己的 /minimax-code/api 前缀下(与 antigravity / claude / command-code / kimi-code / workbuddy 一致),不占用 Codex 那条线路的 /api/dsh-chatgpt-subscription 前缀。

| 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /status | 账号、区域、凭据来源与路径、硬编码模型目录、路由归属(serving / conflict)与凭据归属(ownedByPlugin) | | POST | /login/start | 开始设备码授权(可带 region) | | POST | /login/poll | 轮询一次授权结果 | | POST | /login/cancel | 取消授权 | | POST | /logout | 注销本插件自己那份凭据;桌面端的登录态会拒绝并说明原因 | | POST | /test | 向上游发一次最小 Messages 请求测试连接 | | GET / POST | /models、/settings | 读取或更新启用开关、勾选模型、上下文窗口覆盖与默认思考深度;两个路径等价(kimi/claude 叫 /models,workbuddy/command-code 叫 /settings) | | GET / POST | /accounts | 号池动作:set-primary / set-alias / delete / clear-cooldown / strategy / relogin / adopt(adopt = 把桌面端当前登录态导入号池,只读、不改动官方客户端文件) | | GET / POST | /quota | 读取用量快照(POST 强制刷新):Token Plan 的 5 小时与每周窗口。上游读失败不算请求失败——quota 是可选字段,失败时卡片显示“暂无数据”,对话不受任何影响 |

与其它线路一样,所有修改状态的路由只接受同源 JSON POST,并校验 Origin 与 Host。响应里永远不含 access token / refresh token / 授权码 / PKCE verifier;诊断里提到某个令牌时只输出它的 SHA-256 指纹前缀(sha256:.../len:...),不是令牌的任何一段原文——早前版本会打印前 6 个字符, 那本身就是一次凭据泄露,因为同一个字符串会被渲染到设置卡片并写进 Host 日志(有测试锁定)。

GLM(ZCode 账号)线路

glm-coding-plan(显示名 GLM(ZCode 账号))接入 GLM Coding Plan 订阅:你在 ZCode 页面用自己的账号完成授权,插件用 ZCode 自己的 CLI OAuth 控制面换出 Coding Plan Key,再打套餐专用端点——不粘贴 API Key,也不需要你手工铸造 Key。国区(BigModel)与国际区(Z.ai)是两套互不连通的部署:各自独立登录、独立凭据、独立号池行,同一个号池里可以同时存在两区账号且互不串用。

⚠️ 本线路没有经过实机账号验证。 开发与验收环境不具备真实的 ZCode 账号,全部验收都是 mock 验收。下面「已知限制」逐条写明哪些上游行为仍未验证、以及拿到账号后必须先复验什么——那不是免责套话,是复审清单。

登录:

  1. 确认自己属于国区还是国际区。付费套餐与免费体验额度都可以登录:官方文档写明新用户连接 BigModel 账号后自动获得「体验套餐:无需付费,在首次使用起的 5 天内,每天提供 800 万 token 的 GLM 系列模型体验额度」,所以本线路不再要求必须先订阅 Coding Plan;
  2. 重启 DSH,打开 设置 → 订阅服务 → GLM(ZCode 账号);
  3. 选好区域后点「登录」:插件开一次 OAuth 流并自动打开授权页;浏览器打不开不是致命错误,授权链接始终显示在卡片上,可自行复制打开。卡片每 2 秒轮询一次进度;
  4. 授权完成后插件自动跑兑换链换出 Coding Plan Key、验一次活、加密落盘并加入号池。验活只回答「这把 Key 会不会被上游认出来」,不要求账号有付费套餐:认得出来就落盘,卡片上如实标出当前是「付费套餐」还是「免费体验额度」。浏览器没走通时可以「手工粘贴」回调链接或授权码——粘贴只是「去问一次上游」的信号,凭据仍然只来自上游轮询;
  5. 也可以点「导入本机 ZCode 登录态」省掉一次登录(见下)。

导入本机 ZCode 登录态(可选,只读):只读本机已登录的 ZCode 客户端凭据文件 ~/.zcode/v2/credentials.json(ZCODE_DATA_BASE_DIR 可覆盖),从不创建、修改或删除 ZCode 的任何文件。该文件的加密密钥可由「平台 + 用户名 + 主目录」推导,因此普通用户的导入不依赖额外密钥;设了 ZCODE_CREDENTIAL_SECRET 的用户会导入失败,此时回落浏览器登录、不阻断。导入到的凭据与浏览器登录走同一条兑换链,下游完全共用。

上游接口:

| 用途 | 路径 | 鉴权 | | --- | --- | --- | | OAuth 开流 | POST https://zcode.z.ai/api/v1/oauth/cli/init | Authorization: Bearer <pollToken>;pollToken 是本地 randomBytes(32) 生成的绑定令牌,不是登录凭据、不落盘 | | OAuth 轮询 | GET https://zcode.z.ai/api/v1/oauth/cli/poll/{flow_id} | 同一个 Bearer pollToken | | 业务 JWT(仅国际区) | POST {业务 host}/api/auth/z/login | 请求体带 OAuth access_token;响应给出业务 JWT 与 expires_in | | 兑换:默认机构与项目 | GET {业务 host}/api/biz/customer/getCustomerInfo | 国际区 Authorization: Bearer <业务 JWT>;国区是裸 access_token(见「两区差异」) | | 兑换:Key 列表 / 创建 | GET / POST {业务 host}/api/biz/v1/organization/{orgId}/projects/{projectId}/api_keys | 同上 | | 兑换:取 secretKey | GET {业务 host}/api/biz/v1/organization/{orgId}/projects/{projectId}/api_keys/copy/{apiKeyId} | 同上 | | 模型生成(Anthropic 面) | POST {api host}/api/anthropic/v1/messages | x-api-key 与 Authorization: Bearer 同值双头(该兼容网关两个都读) | | 模型生成(OpenAI 兼容面) | POST {api host}/api/coding/paas/v4/chat/completions | Authorization: Bearer <Coding Plan Key> | | 配额 | GET {业务 host}/api/monitor/usage/quota/limit | authorization: <id>.<secret> 裸 Key,不可加 Bearer(加了会鉴权失败,与模型面正好相反) |

模型面刻意不是通用开放平台的 /api/paas/v4:官方文档的 Common mistakes 段写明走那个面套餐额度不生效——用户会看到「买了套餐却在扣余额」。所以 glm-5.1 / glm-4.7 那批只挂在通用面上的模型不在本线路目录里;上游目录真出现、而本插件未转录过的 id 会作为「未声明模型」进入目录(不猜协议、不发思考档位、不认图),而不是凭空补一行能力。

轮换出来的 Key 落盘前会用配额接口验一次活,而这一步的两类失败处置相反:凭据本身无效(鉴权类业务码 1000 / 1001 / 1003)仍然在登录阶段报错——放行等于拿着一把废 Key 进对话,用户只会在某次请求里以一个莫名其妙的 401 看到它;凭据有效但没有付费套餐(配额面按余额 / 套餐 / 额度维度拒绝)则放行,并把额度类型如实记为「免费体验额度」。额度耗尽时由上游返回 429 告知,本线路不预判、也不绕过。

两区差异:

| | 国区 cn | 国际区 intl | | --- | --- | --- | | 业务 host(兑换链、配额) | https://bigmodel.cn | https://api.z.ai | | 模型面 host | https://open.bigmodel.cn | https://api.z.ai(国际区把控制台与模型面放在同一个源站上) | | 浏览器授权入口 | https://bigmodel.cn/login?appId=zcode | https://chat.z.ai/api/oauth/authorize?client_id=client_P8X5CMWmlaRO9gyO-KSqtg | | 开流请求里的 provider | bigmodel | zai | | 业务 JWT | 跳过 /api/auth/z/login,拿 OAuth access_token 当裸 Authorization 直接打 /api/biz/* | 先换业务 JWT,之后 /api/biz/* 带 Bearer <业务 JWT> |

两区共用同一个 OAuth 控制面(zcode.z.ai/api/v1/oauth/cli/*),分开的只有上面这几行。业务 JWT 的自动重取只服务国际区——国区没有这一层。授权参数里没有 PKCE(两个 provider 的授权参数只有 redirect / appId / state),本插件照抄上游形状,不自带 code_challenge。本仓库历史里那句「国区没有浏览器登录」是错的,本线路删除了它:国区有浏览器登录,只是入口与参数名都不同。

模型目录:随包目录 4 个模型(GLM-5.3 / GLM-5.3-Flash / GLM-5.2 / GLM-5-Turbo),逐模型事实转录自官方开源版内置配置 zai-org/ZCode 的 config/provider/zcode-builtin.json(revision 31)。能力逐模型查表,不从模型名推断,其中三处是被官方配置纠正过的历史值:

  • 输出上限:GLM-5.3 家族与 GLM-5.2 是 128000、GLM-5-Turbo 是 64000。历史转录引用的 docs.z.ai 通用参数表给的是 131072,按本仓库「取小值」的规则取 128000(高报会被网关拒,低报只是提前压缩);128000 也正是官方客户端自己在 Coding Plan 面上发的那个数。同一代模型上限差一倍,正是「不得按家族名推」的又一处证据;
  • 图片输入:四个模型的 supportsImages 全为 true——不是因为模型多模态,而是官方配置里两条 modelMatch: ".*" 的站点规则把 api.z.ai/api/anthropic 与 open.bigmodel.cn/api/anthropic 这两个 Coding Plan 基址的 supportsImage 打开成 true(基础规则对 GLM-5.3 / GLM-5.2 / GLM-5-Turbo 写的都是 false)。所以这条能力读作「经本线路这两个端点时收不收图」;
  • 套餐归属:这四个全部是 Coding Plan 模型;反倒是 Start Plan 缺 GLM-5.3。这一条曾被写反过,写反的代价是把两个确实在套餐里的模型判成未订阅、用户连试都不能试。留着它是为了让复审记住:套餐归属是账号的属性,不是模型的属性,同一个 id 在不同 provider 规则下启用的集合是不同的。

思考档位同样逐模型声明:GLM-5.3 / GLM-5.3-Flash 三档且不可关闭思考(上游把 thinking.type: "disabled" 当错误拒绝),GLM-5.2 两档(模型页面写的是更宽的词汇,但它同时写明套餐如何映射,真正能上线缆的只有这两级)且可关闭,GLM-5-Turbo 不收档位(梯子为空,请求里根本不发思考控制字段)。DSH 词汇表更宽的 minimal / medium / xhigh 先收敛到模型真实的梯子再发出去,平手时向上取。

瞬时失败按错误类别重试:glm-coding-plan 路由显式声明 normal 策略(最多 3 次,1.5s 起指数退避、15s 上限、0.2 抖动),覆盖 RATE_LIMIT / SERVER / TIMEOUT / TRANSPORT。分类不能停在状态行——冻结的错误码表里七条 429 中只有两条可重试(1302 频率限制、1305 瞬时过载),其余五条全是额度类,所以正文没给业务码的裸 429 一律判不可重试(Retry-After 仍然读取并下发,它不改变判定)。同一张表在两个协议面上是同一份取值,Anthropic 面与 OpenAI 面各有一份判读函数,改一处必须同时改另一处。

插件路由(GLM Coding Plan)

所有路由都以 /glm-coding-plan/api 为前缀:

| 方法 | 路径 | 说明 | | --- | --- | --- | | GET | /status | 账号、区域、配额快照、模型目录、登录流程与路由归属(serving / conflict);页面唯一的读口 | | POST | /settings | 启用开关、勾选模型、上下文窗口覆盖、默认思考深度、选中账号;先落盘再发 llm/adapters-updated | | POST | /accounts | 号池动作:set-primary / clear-cooldown / delete / relogin / strategy(sequential / round-robin / sticky) | | POST | /login/start | 按区域开一次 OAuth 流,立即返回流程状态(不阻塞) | | GET | /login/status | 轮询登录流程状态;只有这一条 GET 会推进状态机——host 刻意不在后台轮询,关掉设置页之后就不会继续打上游 | | POST | /login/cancel | 取消登录流程 | | POST | /login/manual | 手工粘贴回调链接或授权码 | | POST | /adopt | 导入本机 ZCode 登录态(只读,作快照入池);失败永不阻断,每种失败都是契约里的一个 reason,卡片据此回落浏览器登录 | | POST | /connection/test | 沿用兑换链验活那条路径(配额接口裸 Key):它答「这把 Key 还能不能读配额」,答不了「这个模型能不能被调用」——后者要花一次真实生成,交给用户发第一条消息 | | POST | /quota | 强制刷新配额;一次失败的配额读不是一次失败的请求,卡片照旧渲染 | | POST | /catalog/refresh | 强制刷新模型目录 |

与其它线路一样,所有修改状态的路由只接受同源 JSON POST,并校验 Origin 与 Host。/adopt 与 /connection/test 的 DTO 定在顶层(不带 {ok,value} 信封),其余一律走信封。响应里永远不含 access token、refresh token、业务 JWT 或 Coding Plan Key 的原文——登录状态 DTO 是逐字段显式投影出来的,而不是展开整个会话对象;将来给会话对象加字段会因此变成一次必须被看见的改动。

已知限制(拿到账号后请先复验这几条):

  • 本线路的全部验收都是 mock,没有任何实机账号验证。 开发与验收环境不具备真实的 ZCode 账号:下面每一条上游行为都是照官方源码、官方文档与社区逆向实现实现的,并由 mock 走通流程与分支,没有一条经过 live 验证。因此本节不是「已知问题」清单,而是拿到账号后的复审清单——先复验它们,再谈这条线路在你的账号上可用。同批仍未验证的细项还有:服务端实际下发的 poll_interval_sec(只见最小 1 秒的校验,无实测样本)、桌面回调中转路径里的握手标识是否会轮换、以及周度 / 月度配额窗口的长度(按词义取 7 天 / 30 天,上游只给了「周度」「月度」这个名称,缺一份真实配额响应样本里的窗口起止时刻;5 小时那一档有逐字证据,不受影响)。
  • 支持免费体验额度与付费套餐,但免费额度的具体行为未经验证。 本线路现在 「有额度就放行」:验活只判断这把 Coding Plan Key 会不会被上游认出来,不再要求账号 已订阅付费 Coding Plan。官方文档(逐字:zcode.z.ai/cn/docs/configuration)写明新用户 连接 BigModel 账号后自动获得「体验套餐:无需付费,在首次使用起的 5 天内,每天提供 800 万 token 的 GLM 系列模型体验额度」,welcome 页也写明「新用户可享受每日免费的 GLM 旗舰模型体验额度」——所以**「没有付费套餐」不等于「没有额度」**,登录阶段硬拒会把免费额度的 新用户全部挡在门外。卡片会如实区分「付费套餐 / 免费体验额度 / 未判定」,不把免费额度 渲染成套餐名。 仍未验证(拿到账号后请先复验):
    • 免费额度账号在配额接口上究竟返回什么形状——是 403 + 业务码(当前按「已知套餐类业务码」 与「裸 401/403」两支分别处理),还是能读出一份带窗口的快照。没有一份实机样本;
    • 「凭据无效」与「没有付费套餐」在上游是否一定可区分。当前只认三个鉴权类业务码 (1000 / 1001 / 1003)为凭据无效;分不出时按 unknown 放行——因为额度耗尽的 429 可恢复,而误拒一个有效账号不可恢复(用户再也登不进这条线路,且无从自查);
    • 免费额度是否真的能服务模型面(配额接口答得了不代表模型接口答得了),以及它耗尽时的 确切错误码与重置节奏;
    • 「闲时任务」类免费算力(welcome 页所述)本线路未接入,它属于另一条调度路径。
  • 上游没有 refresh_token 交换接口。