Skip to content
Closed
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
7 changes: 7 additions & 0 deletions src/adapters/openai-responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2501,6 +2501,13 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
parsed.modelId,
);
if (isCanonicalOpenAiForwardProvider(provider)) {
// Spark closes Responses Lite streams before a terminal completion. Select compatibility
// from the final wire model so aliases cannot leave the caller or a static header enabled.
if (isPlainObject(finalBody) && finalBody.model === "gpt-5.3-codex-spark") {
for (const name of Object.keys(headers)) {
if (name.toLowerCase() === CODEX_RESPONSES_LITE_HEADER) delete headers[name];
}
}
const routingHeaders = new Headers(headers);
applyCodexRoutingHint(routingHeaders, finalBody);
// Static headers may use mixed casing. Remove every stale spelling
Expand Down
29 changes: 29 additions & 0 deletions tests/codex-integration/codex-metadata-integrity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,35 @@ describe("Codex request transport metadata", () => {
expect(new Headers(dropped.headers).get(hintHeader)).toBe("model=gpt-5.6-sol");
});

test("canonical adapter drops Lite only for the Spark wire model", async () => {
const adapter = createResponsesPassthroughAdapter({
adapter: "openai-responses", authMode: "forward", baseUrl: "https://chatgpt.com/backend-api/codex",
headers: { "X-OpenAI-Internal-Codex-Responses-Lite": "true" },
});

for (const [model, incomingLite, expectedLite] of [
["gpt-5.3-codex-spark", "true", null],
["gpt-5.3-codex-spark", undefined, null],
["gpt-5.6-sol", "true", "true"],
] as const) {
const parsed = minimalParsed();
parsed.modelId = model;
parsed._rawBody = { model, input: [], stream: true };
const incoming = new Headers();
if (incomingLite !== undefined) incoming.set(liteHeader, incomingLite);
const request = await adapter.buildRequest(parsed, {
headers: incoming,
});
expect(new Headers(request.headers).get(liteHeader)).toBe(expectedLite);
}

const routed = minimalParsed();
routed.modelId = "spark-alias";
routed._rawBody = { model: "gpt-5.3-codex-spark", input: [], stream: true };
const request = await adapter.buildRequest(routed, { headers: new Headers({ [liteHeader]: "true" }) });
expect(new Headers(request.headers).get(liteHeader)).toBeNull();
});

test("noncanonical adapters neither forward caller Lite nor synthesize a routing hint", async () => {
for (const authMode of ["forward", "key"] as const) {
const adapter = createResponsesPassthroughAdapter({
Expand Down
Loading