diff --git a/src/providers/proxies/codex-proxy.ts b/src/providers/proxies/codex-proxy.ts index 214973f..5c75402 100644 --- a/src/providers/proxies/codex-proxy.ts +++ b/src/providers/proxies/codex-proxy.ts @@ -88,15 +88,21 @@ export const transformCodexBodyJson = ( ...nextBody } = bodyJson; - // OpenCode injects instructions internally in its Codex/OAuth path: - // https://github.com/anomalyco/opencode/blob/d848c9b6a32f408e8b9bf6448b83af05629454d0/packages/opencode/src/session/llm.ts#L110-L112 - // Non-Codex clients won't, so we fall back to OpenCode's default instructions for Codex. - // https://github.com/anomalyco/opencode/blob/d848c9b6a32f408e8b9bf6448b83af05629454d0/packages/opencode/src/session/prompt/codex_header.txt + const incomingInstructions = trimString(nextBody.instructions); + const input = Array.isArray(nextBody.input) ? nextBody.input : []; + const firstInput = input[0]; + const promotedInstructions = + !incomingInstructions && + isObjectRecord(firstInput) && + (firstInput.role === "system" || firstInput.role === "developer") + ? trimString(firstInput.content) + : ""; const instructions = - trimString(nextBody.instructions) || CODEX_DEFAULT_INSTRUCTIONS; + incomingInstructions || promotedInstructions || CODEX_DEFAULT_INSTRUCTIONS; return { ...nextBody, + ...(promotedInstructions ? { input: input.slice(1) } : {}), instructions, store: false, ...(sessionId ? { prompt_cache_key: sessionId } : {}), diff --git a/tests/providers/proxy-contract.test.ts b/tests/providers/proxy-contract.test.ts index b717796..a9e4a01 100644 --- a/tests/providers/proxy-contract.test.ts +++ b/tests/providers/proxy-contract.test.ts @@ -338,6 +338,39 @@ describe("proxy contract: codex", () => { ); }); + test("promotes OpenCode developer input instead of adding fallback instructions", () => { + const headers = new Headers(); + const bodyJson = { + model: "gpt-5.6-sol", + input: [ + { + role: "developer", + content: "Current OpenCode GPT instructions", + }, + { + role: "user", + content: [{ type: "input_text", text: "hello" }], + }, + ], + }; + + const result = prepareCodexProxyRequest({ + headers, + accessToken: "codex-access", + accountId: "acct-fallback", + metadata: null, + bodyText: JSON.stringify(bodyJson), + bodyJson, + }); + + expect(JSON.parse(result.bodyText)).toEqual({ + model: "gpt-5.6-sol", + input: [bodyJson.input[1]], + instructions: "Current OpenCode GPT instructions", + store: false, + }); + }); + test("uses derived session headers and prompt cache key for codex requests", () => { const headers = new Headers({ session_id: "raw-session-underscore",