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
68 changes: 66 additions & 2 deletions src/proxy/__tests__/codex-api-headers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,37 @@ describe("codex-api headers", () => {
expect(transport.lastHeaders!["x-codex-turn-state"]).toBeUndefined();
});

it("excludes turnState and service_tier from JSON body", async () => {
it("excludes turnState from JSON body", async () => {
const api = await createApi();
await api.createResponse(
makeRequest({ turnState: "abc", service_tier: "fast" }),
makeRequest({ turnState: "abc" }),
);
const body = JSON.parse(transport.lastBody!) as Record<string, unknown>;
expect(body.turnState).toBeUndefined();
});

it("maps service_tier 'fast' to 'priority' in JSON body", async () => {
const api = await createApi();
await api.createResponse(
makeRequest({ service_tier: "fast" }),
);
const body = JSON.parse(transport.lastBody!) as Record<string, unknown>;
expect(body.service_tier).toBe("priority");
});

it("passes non-fast service_tier through unchanged", async () => {
const api = await createApi();
await api.createResponse(
makeRequest({ service_tier: "flex" }),
);
const body = JSON.parse(transport.lastBody!) as Record<string, unknown>;
expect(body.service_tier).toBe("flex");
});

it("omits service_tier from body when null", async () => {
const api = await createApi();
await api.createResponse(makeRequest({ service_tier: null }));
const body = JSON.parse(transport.lastBody!) as Record<string, unknown>;
expect(body.service_tier).toBeUndefined();
});
});
Expand Down Expand Up @@ -148,5 +172,45 @@ describe("codex-api headers", () => {
);
expect(headers["x-codex-turn-state"]).toBe("ws_turn_abc");
});

it("maps service_tier 'fast' to 'priority' in WS request", async () => {
mockCreateWebSocketResponse.mockResolvedValue(
new Response("data: {}\n\n", {
headers: { "content-type": "text/event-stream" },
}),
);

const api = await createApi();
await api.createResponse(
makeRequest({
previous_response_id: "resp_prev",
useWebSocket: true,
service_tier: "fast",
}),
);

const wsRequest = mockCreateWebSocketResponse.mock.calls[0][2] as Record<string, unknown>;
expect(wsRequest.service_tier).toBe("priority");
});

it("passes non-fast service_tier through in WS request", async () => {
mockCreateWebSocketResponse.mockResolvedValue(
new Response("data: {}\n\n", {
headers: { "content-type": "text/event-stream" },
}),
);

const api = await createApi();
await api.createResponse(
makeRequest({
previous_response_id: "resp_prev",
useWebSocket: true,
service_tier: "flex",
}),
);

const wsRequest = mockCreateWebSocketResponse.mock.calls[0][2] as Record<string, unknown>;
expect(wsRequest.service_tier).toBe("flex");
});
});
});
8 changes: 5 additions & 3 deletions src/proxy/codex-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export class CodexApi {
if (request.tools?.length) wsRequest.tools = request.tools;
if (request.tool_choice) wsRequest.tool_choice = request.tool_choice;
if (request.text) wsRequest.text = request.text;
// service_tier is stripped — Codex backend rejects it ("Unsupported service_tier")
if (request.service_tier) wsRequest.service_tier = request.service_tier === "fast" ? "priority" : request.service_tier;
if (request.prompt_cache_key) wsRequest.prompt_cache_key = request.prompt_cache_key;
if (request.include?.length) wsRequest.include = request.include;

Expand Down Expand Up @@ -243,8 +243,10 @@ export class CodexApi {
headers["x-client-request-id"] = crypto.randomUUID();
if (request.turnState) headers["x-codex-turn-state"] = request.turnState;

const { previous_response_id: _pid, useWebSocket: _ws, turnState: _ts, service_tier: _st, ...bodyFields } = request;
const body = JSON.stringify(bodyFields);
const { previous_response_id: _pid, useWebSocket: _ws, turnState: _ts, service_tier, ...bodyFields } = request;
const body = JSON.stringify(
service_tier ? { ...bodyFields, service_tier: service_tier === "fast" ? "priority" : service_tier } : bodyFields,
);

let transportRes;
try {
Expand Down
1 change: 1 addition & 0 deletions src/proxy/ws-transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface WsCreateRequest {
strict?: boolean;
};
};
service_tier?: string;
prompt_cache_key?: string;
include?: string[];
// NOTE: `store` and `stream` are intentionally omitted.
Expand Down
Loading