From 996772dc024369326a47eea6f2a5afc55ed84b96 Mon Sep 17 00:00:00 2001 From: Chlorek Date: Fri, 10 Jul 2026 22:23:59 +0200 Subject: [PATCH] fix(opencode): send Codex-compatible OAuth request identity headers --- packages/opencode/src/plugin/openai/codex.ts | 6 ++++-- packages/opencode/test/plugin/codex.test.ts | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/plugin/openai/codex.ts b/packages/opencode/src/plugin/openai/codex.ts index f14d1269769e..747c6de2c863 100644 --- a/packages/opencode/src/plugin/openai/codex.ts +++ b/packages/opencode/src/plugin/openai/codex.ts @@ -12,6 +12,8 @@ const ISSUER = "https://auth.openai.com" const CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses" const OAUTH_PORT = 1455 const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000 +const CODEX_ORIGINATOR = "codex_cli_rs" +const CODEX_USER_AGENT = `codex_cli_rs/0.0.0 (OpenCode/${InstallationVersion}) (${os.platform()} ${os.release()})` const ALLOWED_MODELS = new Set(["gpt-5.5", "gpt-5.3-codex-spark", "gpt-5.4", "gpt-5.4-mini"]) const DISALLOWED_MODELS = new Set(["gpt-5.5-pro"]) @@ -539,8 +541,8 @@ export async function CodexAuthPlugin(input: PluginInput, options: CodexAuthPlug }, "chat.headers": async (input, output) => { if (input.model.providerID !== "openai") return - output.headers.originator = "opencode" - output.headers["User-Agent"] = `opencode/${InstallationVersion} (${os.platform()} ${os.release()}; ${os.arch()})` + output.headers.originator = CODEX_ORIGINATOR + output.headers["User-Agent"] = CODEX_USER_AGENT output.headers["session-id"] = input.sessionID // Temporary fetch-layer hack: title generation currently shares the conversation // session ID, so the OpenAI plugin marks it for HTTP fallback until transport diff --git a/packages/opencode/test/plugin/codex.test.ts b/packages/opencode/test/plugin/codex.test.ts index 7142bb3e20c9..22552d4e0f8c 100644 --- a/packages/opencode/test/plugin/codex.test.ts +++ b/packages/opencode/test/plugin/codex.test.ts @@ -1,4 +1,6 @@ import { describe, expect, test } from "bun:test" +import { InstallationVersion } from "@opencode-ai/core/installation/version" +import os from "os" import { CodexAuthPlugin, parseJwtClaims, @@ -149,6 +151,18 @@ describe("plugin.codex", () => { await enabled.dispose?.() }) + test("sends Codex-compatible request identity headers", async () => { + const hooks = await CodexAuthPlugin({} as never) + const output = { headers: {} as Record } + + await hooks["chat.headers"]?.({ model: { providerID: "openai" } } as never, output) + + expect(output.headers.originator).toBe("codex_cli_rs") + expect(output.headers["User-Agent"]).toBe( + `codex_cli_rs/0.0.0 (OpenCode/${InstallationVersion}) (${os.platform()} ${os.release()})`, + ) + }) + test("deduplicates concurrent Codex token refreshes", async () => { let auth = { type: "oauth" as const,