dsh-codex-subs-plugin

August 14, 2026 · View on GitHub

中文 | English

实验性的 DeepSeek Harness 主模型适配器:通过 ChatGPT OAuth 使用账号的 Codex 订阅能力,而不是 OpenAI Platform API Key。

Warning

OpenAI 官方只公开承诺 Codex 可以“Sign in with ChatGPT”访问订阅。这个项目跟随 OpenAI Codex 客户端和 OpenCode 的开源实现,依赖 auth.openai.com 设备码接口、ChatGPT-Account-Idchatgpt.com/backend-api/codex 等非公开稳定合约。服务端变化可能随时导致不兼容。订阅也不代表无限额度。

完整安装、登录、默认模型、代理、Headless 与 Web UI 操作见 USAGE 使用手册

实现原理、上游源码证据与风险分析见 OpenCode 如何使用 Codex 订阅

工作方式

ChatGPT OAuth(PKCE / device code)
  → access + refresh token + account id
  → DSH GenerateOptions 转为 Responses 请求
  → 固定发送到 chatgpt.com/backend-api/codex/responses
  → Responses SSE 转为 DSH StreamChunk
  → 保存 encrypted reasoning / tool replay state

它不会读取或复制 Codex CLI、OpenCode 的凭据,也不会把订阅“转换”为 API Key。凭据默认独立保存在:

$DSH_CODEX_SUBS_AUTH_FILE
  或 $DSH_HOME/codex-subs/auth.json
  或 ~/.dsh/codex-subs/auth.json

写入采用临时文件、fsync、原子 rename 和 0600 权限;刷新提前 60 秒并合并并发请求。传输层不提供自定义 endpoint,OAuth Bearer 只能发往代码中固定的 Codex 后端。

快速开始

需要 Node.js ^22.19.0>=24.0.0、pnpm 和已安装的 dsh CLI。

1. 安装

pnpm install
pnpm run check
dsh plugin --profile headless add .

本包的 bundle 是非侵入式的:它只注册 codex-subscription provider,不会覆盖 DSH 现有默认模型。下面的命令可选,只能确认 Cordis 组合层已经插入 llm-codex-subscription

dsh --profile headless --dump-config

--dump-config 不会加载 $DSH_HOME/settings.yaml 的运行时模型选择,因此不能证明请求会走本插件。

2. 登录

dsh plugin --profile headless exec dsh-codex-subs login

无桌面浏览器时使用有时限的设备码流程:

Device code 登录目前是 beta 功能:个人账户需先在 ChatGPT Settings → Security 启用,受管 workspace 则需管理员在 workspace permissions 中启用。详见 OpenAI authentication

dsh plugin --profile headless exec dsh-codex-subs login --headless

3. 显式选择默认模型

编辑 $DSH_HOME/settings.yaml;未设置 DSH_HOME 时默认是 ~/.dsh/settings.yaml

agent-default-model:
  provider: codex-subscription
  model: gpt-5.5
  reasoningEffort: medium

默认 catalog 只是当前兼容快照;未列出的 model id 仍会原样发送,实际模型权限以服务端为准。

4. 检查本地状态

dsh plugin --profile headless exec dsh-codex-subs status
dsh plugin --profile headless exec dsh-codex-subs doctor

status 读取本地凭据元数据。doctor 不刷新 token、不发网络请求,只报告 auth 是否存在/到期、account id 是否存在、profile 安装状态、插件/provider、settings.yaml 中声明的默认 provider/model、代理变量是否存在、Node 环境代理开关和固定 endpoint;它不会输出 token、account id、代理 URL 或代理变量值。两者都不能验证远端 entitlement,也不能证明 DSH 已在真实运行时选中该 route。

5. 完成最小请求闭环

dsh --profile headless "只回复:codex-subscription-ok"

这是当前真正的运行时验证:新的 headless agent 会读取有效默认模型并通过所选 adapter 发出请求。成功响应同时验证运行时选路、OAuth、网络和服务端权限;它会消耗订阅用量。

不用本插件时可删除它自己的本地凭据:

dsh plugin --profile headless exec dsh-codex-subs logout

logout 不会远程 revoke token,也不会退出 ChatGPT、Codex CLI 或 OpenCode。

代理环境

OAuth、refresh、设备码和 Responses 请求共用隔离的 proxy-aware transport。它读取 HTTP_PROXYHTTPS_PROXYNO_PROXY 及其小写形式;同名大小写变量同时存在时,小写优先。示例:

export HTTPS_PROXY=http://proxy.example:8080
export HTTP_PROXY=http://proxy.example:8080
export NO_PROXY=localhost,127.0.0.1
  • ALL_PROXY 既不被当前 transport 使用,也不计入 doctor 的 proxy presence;请按协议设置 HTTPS_PROXY/HTTP_PROXY
  • 未单独设置 HTTPS_PROXY 时,Undici 会把 HTTP_PROXY 作为 HTTPS 请求的回退代理;明确设置两者更易诊断。
  • 浏览器授权页由外部浏览器打开,使用浏览器/操作系统的网络路径;CLI 的 token 与模型请求使用本插件 transport,两者出口可能不同。
  • Node 24 提供 NODE_USE_ENV_PROXY=1 / --use-env-proxy 作为全局 HTTP(S) 客户端能力。这只是诊断背景;本插件在支持的 Node 22/24 版本上都使用自己的统一 transport,不依赖该开关。
  • transport 禁止自动跟随 redirect,并将网络错误脱敏。即使代理 URL 包含凭据,也不要把它或完整环境变量贴进日志、issue 或聊天。

unsupported_country_region_territory 排查

这类错误来自服务端;本插件会保留稳定错误码 UNSUPPORTED_COUNTRY_REGION_TERRITORY,但不能覆盖区域、账号或 workspace 策略:

  1. 先运行 statusdoctor,确认 auth、默认 provider/model 与代理变量状态;它们不会测试远端。
  2. 对照 OpenAI 的受支持国家和地区。该页面描述 API 服务;私有 ChatGPT Codex 后端的最终资格仍由服务端判断。
  3. 让网络或企业管理员确认 CLI 进程的公网出口国家/地区。不要假设浏览器登录成功就代表 CLI 请求使用同一出口。
  4. 检查冲突或陈旧的大小写代理变量:本实现小写优先;确认 NO_PROXY 没有意外绕过 auth.openai.comchatgpt.com;只设置 ALL_PROXY 对本 transport 无效。
  5. 在合规网络路径一致后重试最小请求;若失败阶段是 OAuth/device/refresh 或凭据已过期,再重新登录。若仍失败,保留错误阶段、HTTP 状态和 request id,删除 token、完整请求头与代理 URL 后联系 OpenAI 支持或 workspace 管理员。

不要通过伪造 client id/endpoint、复制他人凭据或规避区域限制来绕过服务端控制。

插件配置

在 profile 的 cordis.patch.yml 中覆盖 bundle 插入的行:

- id: llm-codex-subscription
  config:
    provider: codex-subscription
    displayName: OpenAI Codex Subscription
    reasoningEffort: medium
    textVerbosity: low
    streamIdleTimeoutMs: 300000

可选字段还有绝对路径 authFile 和 advisory models 列表。没有 baseURLendpoint 配置,这是令牌边界的一部分。

已实现

  • 浏览器 PKCE + state + 仅 127.0.0.1 回调,5 分钟超时并保证清理。
  • Headless device flow,15 分钟总超时。
  • refresh token 旋转的原子持久化、提前刷新和 single-flight。
  • OAuth、refresh、device 与 Responses 共用脱敏的环境代理 transport。
  • doctor 安全报告本地 auth、安装、默认模型与代理 presence,不发网络请求。
  • 首次 401 后强制刷新并安全重放一次,绝不循环。
  • Responses 的 text、reasoning summary、function call、usage、错误与 incomplete 映射。
  • store:false 下 encrypted reasoning 和工具调用的无状态 replay。
  • DSH usage → finish 顺序、abort 与 stream idle timeout 契约。

如果只需要把 Codex 当作子代理,优先使用 DeepSeek Harness 自带的 @deepseek-ai/dsh-subagent-codex:它调用官方 codex app-server 并使用 Codex 原生认证。本项目适用于需要把 Codex 订阅接到 DSH 主 LLM route 的场景。

开发验证

pnpm run typecheck
pnpm run test
pnpm run build
pnpm pack --dry-run

测试全部使用 mock OAuth / Responses 数据,不会读取真实凭据,也不会访问 OpenAI。