关键词:Codex Desktop、第三方 Provider、DeepSeek、ChatGPT 浏览器扩展、Computer Use、nodeRepl.fetch、代理

一、问题现象

环境:Windows 11 + Codex 桌面端 26.908.40834,模型走第三方 Provider(DeepSeek),本机用 Clash 提供本地 HTTP 代理 127.0.0.1:7890

表现是:模型对话、代码任务一切正常,但只要调用浏览器能力就失败。报错按修复进度依次出现过三种,正好对应三层互不相干的故障:

  1. Codex auth token is unavailable
  2. nodeRepl.fetch request failed
  3. Unable to load browser request-header policy. Retry the browser command.

这三条不是同一个问题的不同措辞,而是三个独立故障被依次揭开。下面逐层说明。

二、第一层:Codex auth token is unavailable

原因

Codex 桌面端里其实有两套彼此独立的认证:

用途认证来源
模型推理第三方 Provider 的 token
浏览器 / Computer Use 等插件能力ChatGPT 账号登录态(auth.json

第三方 API Key 只能证明你有权调用那个模型,不能代替 ChatGPT 账号态。当 Provider 配置里写的是 requires_openai_auth = false 时,Codex 的 app-server 在 getAuthStatus 里会返回:

{"authMethod": null, "authToken": null, "requiresOpenaiAuth": false}

浏览器运行时拿不到令牌,于是就报 Codex auth token is unavailable

错误的做法

直觉上会想把 requires_openai_auth 改成 true 就完事。但如果同时把第三方 token 手写在 http_headers.Authorization 里,会出现认证头互相覆盖的风险——最坏的情况是 ChatGPT 的 bearer token 被发到第三方模型端点,属于凭据外泄,绝对不能这么配。

正确的双轨配置

把第三方 token 放在 Provider 专属的 experimental_bearer_token 字段里,再打开 requires_openai_auth

model_provider = "custom"
model = "deepseek-v4-flash"

[model_providers.custom]
name = "deepseek"
base_url = "https://api.deepseek.com"
wire_api = "responses"
requires_openai_auth = true
experimental_bearer_token = "<你的第三方 API Key>"

关键点:不要再手写 [model_providers.custom.http_headers] Authorization

为什么这样不会把 ChatGPT 令牌发给第三方?见 Codex 官方源码 codex-rs/core/src/client.rs

fn uses_codex_backend(&self, auth: Option<&CodexAuth>) -> bool {
    let provider = self.state.provider.info();
    auth.is_some_and(CodexAuth::uses_codex_backend)
        && provider.is_openai()
        && provider.requires_openai_auth
        && provider.env_key.is_none()
        && provider.experimental_bearer_token.is_none()
        && provider.auth.is_none()
        && provider.aws.is_none()
}

只要 Provider 配了 experimental_bearer_token,模型请求就继续用第三方 token,账号凭据不会被挂上去;requires_openai_auth = true 只是让插件那一路能拿到 ChatGPT 账号态。

验证方法

# 确认是 ChatGPT 登录,而不是 API Key 登录
codex login status
# 期望输出:Logged in using ChatGPT

想直接确认 app-server 是否愿意发放令牌,可以手动起一个 app-server 并用 JSON-RPC 问它:

codex app-server --listen stdio://

然后依次发送:

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"clientInfo":{"name":"probe","title":"probe","version":"0.1.0"}}}
{"jsonrpc":"2.0","id":2,"method":"getAuthStatus","params":{"includeToken":true}}

修复后应返回 authMethod: "chatgpt" 且带真实令牌;修复前 authMethodnull。注意 includeToken 这个参数:不传它,authToken 字段会是 null

三、第二层:nodeRepl.fetch request failed

第一层修好后,报错变成 nodeRepl.fetch request failed,每次卡大约 21 秒才超时。这一步和认证已经无关了。

原因

浏览器控制后端需要访问 OpenAI 的端点来获取浏览器身份信息,而本机在特定网络环境下,直连这些端点是被阻断的。实测对比(curl):

直连 https://chatgpt.com/        -> Connection was reset(curl 35)
经 127.0.0.1:7890 代理           -> HTTP 403(链路可达,403 是服务端策略)
直连 https://api.openai.com/v1/models -> 12 秒超时
经 127.0.0.1:7890 代理           -> HTTP 401(链路可达,401 是缺凭据)

也就是说:只有让后端显式使用本地 HTTP 代理,这一步才能过。开着 TUN 模式之所以能正常,本质也是把所有流量强制导进了代理。

顺带一个容易走错的方向:~/.codex/config.toml 里的 [mcp_servers.node_repl.env] 改了没用。应用启动时会重写这个文件,改动会被抹掉。同理,插件目录下的 .mcp.json 也会被重新物化,改了同样会被覆盖。

有效的做法

真正的生效位置是拉起 node_repl 的启动脚本:

%LOCALAPPDATA%\OpenAI\Codex\runtimes\cua_node\<hash>\bin\node_modules\@oai\cua-repl\dist\lib\js\oai_js_cua_repl\src\launch.js

它里面用 spawn 拉起 node_repl.exe,env 是 {...process.env, ...}。在这个对象里补上代理变量即可:

// 原样:Object.assign(Object.assign({}, n.env), { CUA_REPL_ENABLED_SURFACES: ...
// 改成:
Object.assign(Object.assign({}, n.env), {
  NODE_USE_ENV_PROXY: "1",
  HTTP_PROXY: "http://127.0.0.1:7890",
  HTTPS_PROXY: "http://127.0.0.1:7890",
  http_proxy: "http://127.0.0.1:7890",
  https_proxy: "http://127.0.0.1:7890",
  NO_PROXY: "localhost,127.0.0.1,::1",
  no_proxy: "localhost,127.0.0.1,::1",
  CUA_REPL_ENABLED_SURFACES: ...
})

改完先做语法检查,再完全退出并重启 Codex:

node --check launch.js

NO_PROXY 里保留 localhost,127.0.0.1,::1 是必要的,否则本地回环的桥接请求会被绕进代理。

改完之后,nodeRepl.fetch request failed 消失,报错推进到第三层。

四、第三层:Unable to load browser request-header policy

这一层来自 browser-service.mjs 里的 Statsig 初始化逻辑:

if (await t.initialization, !(await Ck(t))?.success || t.client.loadingStatus !== "Ready")
  throw new Error("Unable to load browser request-header policy. Retry the browser command.");

它要取的特性开关是 codex_browser_use_agent_request_header。先排除网络因素:featureassets.orgapi.statsig.comprodregistryv2.org 直连与走代理均可响应,所以不是网络问题。

这一层是时序问题:Statsig 客户端初始化需要一点时间,刚重启完应用就去调浏览器能力会命中它。等一会再重试即可,不需要任何额外配置。实测重启后第一次调用失败,稍后重试就成功了。

如果反复重试仍然失败,那属于上游 bug。同版本已有多个公开报告,且官方订阅环境下同样复现,这类情况只能等应用更新。

五、最终验证

三层都通了之后,用只读方式验证最可靠。下面这段代码可以直接在 Codex 的 JavaScript 运行时里跑:

const mod = await import(
  "file:///<你的插件路径>/browser/26.908.40834/scripts/browser-client.mjs"
);
const rt = await mod.setupBrowserRuntime({ environment: "codex-app" });

// 1) 看有哪些浏览器后端
const list = await rt.browsers.list();
console.log(JSON.stringify(list));

// 2) 读取已打开标签页(只读,不点击不提交)
const edge = list.find((b) => b.type === "extension");
const eb = await rt.browsers.get(edge.id);
const tabs = await eb.tabs.list();
for (const t of tabs) console.log(t.title + " | " + t.url);

// 3) 新建标签页并导航
const tab = await eb.tabs.new({ url: "https://example.com" });
console.log(await tab.title(), await tab.url());

预期结果:能列出内置浏览器与 Edge 两个后端、能读到已打开的标签页、能新建并导航。实测输出类似:

Example Domain | https://example.com/

另外,聚合接口 cua.getState() 之前会跟着报错,三层修好后它也会一起恢复正常。

六、几个容易踩的坑

  1. provider 切换工具会清掉 ChatGPT 登录态。 例如 cc-switch 这类工具,如果「保留官方登录」开关没打开,切换 Provider 时会顺手把 auth.json 删掉。清了之后浏览器能力会立刻失效,表现就是又回到第一条报错。
  2. 密钥明文落盘。 experimental_bearer_token 会把 Key 明文写在 config.toml 里,建议把配置文件权限收紧。
  3. 补丁会被覆盖。 launch.js 在应用更新或运行时重新物化后可能被还原;config.toml 和插件 .mcp.json 则几乎每次启动都会被重写。更新应用后如果浏览器能力又坏了,先检查这几处。
  4. 代理端口要对得上。 上面写死的 7890 要和本机代理监听端口一致,换了端口记得同步修改。
  5. 平台层 fallback 只解决"打开"。 直接用系统调用打开 Edge 页面可以做到,但读不到页面内容、也点不了按钮,那类操作必须依赖扩展桥。

七、小结

整个过程的核心判断是:先把「模型认证」和「插件认证」两套链路分开,再按报错逐层推进

  • Codex auth token is unavailablerequires_openai_auth = true + experimental_bearer_token,双轨认证
  • nodeRepl.fetch request failed:在 launch.js 的 spawn 处注入代理环境变量,让后端走本地代理
  • Unable to load browser request-header policy:Statsig 初始化时序,稍等重试即可

只要记住「报错变了就是进展了」这条线索,这类多层故障其实很好拆——每一层的报错信息都会明确指向下一个待解的问题。

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐