Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/opencode/src/plugin/openai/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"])

Expand Down Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions packages/opencode/test/plugin/codex.test.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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<string, string> }

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,
Expand Down
Loading