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
16 changes: 15 additions & 1 deletion src/proxy/__tests__/codex-api-headers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,27 @@ 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 body and maps service_tier fast→priority", async () => {
const api = await createApi();
await api.createResponse(
makeRequest({ turnState: "abc", service_tier: "fast" }),
);
const body = JSON.parse(transport.lastBody!) as Record<string, unknown>;
expect(body.turnState).toBeUndefined();
expect(body.service_tier).toBe("priority");
});

it("passes non-fast service_tier as-is", 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 not set", async () => {
const api = await createApi();
await api.createResponse(makeRequest({}));
const body = JSON.parse(transport.lastBody!) as Record<string, unknown>;
expect(body.service_tier).toBeUndefined();
});
});
Expand Down
14 changes: 11 additions & 3 deletions src/proxy/codex-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ import {
type CodexUsageResponse,
} from "./codex-types.js";

/**
* Map user-facing service_tier to Codex backend value.
* Desktop codex-rs sends "fast" → "priority" (see codex-rs client.rs:740).
*/
function mapServiceTier(tier: string): string {
return tier === "fast" ? "priority" : tier;
}

export class CodexApi {
private token: string;
private accountId: string | null;
Expand Down Expand Up @@ -212,7 +220,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 = mapServiceTier(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 @@ -240,8 +248,8 @@ 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: rawSt, ...bodyFields } = request;
const body = JSON.stringify(rawSt ? { ...bodyFields, service_tier: mapServiceTier(rawSt) } : 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 @@ -49,6 +49,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