Files
OmniRoute/tests/unit/executor-codex.test.ts
Davy Massoneto 872e597512 fix(codex): update client version for gpt-5.5 (#1578)
Integrated into release/v3.7.0
2026-04-25 07:46:13 -03:00

537 lines
16 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import {
CodexExecutor,
encodeResponseSseEvent,
getCodexModelScope,
getCodexRateLimitKey,
getCodexResetTime,
parseCodexQuotaHeaders,
} from "../../open-sse/executors/codex.ts";
import {
DEFAULT_THINKING_CONFIG,
setThinkingBudgetConfig,
ThinkingMode,
} from "../../open-sse/services/thinkingBudget.ts";
test.afterEach(() => {
setThinkingBudgetConfig(DEFAULT_THINKING_CONFIG);
});
async function withEnv(entries, fn) {
const previous = new Map();
for (const [key, value] of Object.entries(entries)) {
previous.set(key, process.env[key]);
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
try {
return await fn();
} finally {
for (const [key, value] of previous.entries()) {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
}
}
test("Codex helper functions isolate rate-limit scopes and parse quota headers", () => {
const quota = parseCodexQuotaHeaders(
new Headers({
"x-codex-5h-usage": "100",
"x-codex-5h-limit": "500",
"x-codex-5h-reset-at": new Date(Date.now() + 60_000).toISOString(),
"x-codex-7d-usage": "1000",
"x-codex-7d-limit": "5000",
"x-codex-7d-reset-at": new Date(Date.now() + 120_000).toISOString(),
})
);
assert.equal(getCodexModelScope("codex-spark-mini"), "spark");
assert.equal(getCodexModelScope("gpt-5.3-codex"), "codex");
assert.equal(getCodexRateLimitKey("acct-1", "codex-spark-mini"), "acct-1:spark");
assert.equal(quota.usage5h, 100);
assert.equal(quota.limit7d, 5000);
assert.ok(getCodexResetTime(quota) >= new Date(quota.resetAt7d).getTime());
});
test("CodexExecutor.buildUrl honors /responses subpaths and compact mode", () => {
const executor = new CodexExecutor();
assert.equal(
executor.buildUrl("gpt-5.3-codex", true, 0, {}),
"https://chatgpt.com/backend-api/codex/responses"
);
assert.equal(
executor.buildUrl("gpt-5.3-codex", true, 0, { requestEndpointPath: "/responses" }),
"https://chatgpt.com/backend-api/codex/responses"
);
assert.equal(
executor.buildUrl("gpt-5.3-codex", true, 0, { requestEndpointPath: "/responses/compact" }),
"https://chatgpt.com/backend-api/codex/responses/compact"
);
});
test("CodexExecutor.buildHeaders binds workspace ids and disables SSE accept for compact responses", () => {
const executor = new CodexExecutor();
const standardHeaders = executor.buildHeaders(
{
accessToken: "codex-token",
providerSpecificData: { workspaceId: "workspace-1" },
},
true
);
const compactHeaders = executor.buildHeaders(
{
accessToken: "codex-token",
requestEndpointPath: "/responses/compact",
},
true
);
assert.equal(standardHeaders.Authorization, "Bearer codex-token");
assert.equal(standardHeaders.Accept, "text/event-stream");
assert.equal(standardHeaders["chatgpt-account-id"], "workspace-1");
assert.equal(standardHeaders.Version, "0.125.0");
assert.equal(standardHeaders["User-Agent"], "codex-cli/0.125.0 (Windows 10.0.26100; x64)");
assert.equal(compactHeaders.Accept, "application/json");
});
test("CodexExecutor.buildHeaders honors safe env overrides for Version and User-Agent", async () => {
const executor = new CodexExecutor();
await withEnv(
{
CODEX_CLIENT_VERSION: "0.120.0-alpha.3",
CODEX_USER_AGENT: undefined,
},
() => {
const headers = executor.buildHeaders({ accessToken: "codex-token" }, true);
assert.equal(headers.Version, "0.120.0-alpha.3");
assert.equal(headers["User-Agent"], "codex-cli/0.120.0-alpha.3 (Windows 10.0.26100; x64)");
}
);
await withEnv(
{
CODEX_CLIENT_VERSION: "bad version value",
CODEX_USER_AGENT: "custom-codex/9.9.9",
},
() => {
const headers = executor.buildHeaders({ accessToken: "codex-token" }, true);
assert.equal(headers.Version, "0.125.0");
assert.equal(headers["User-Agent"], "custom-codex/9.9.9");
}
);
});
test("CodexExecutor.transformRequest injects default instructions, clamps reasoning and strips unsupported fields", () => {
const executor = new CodexExecutor();
const body = {
model: "gpt-5-mini",
messages: [{ role: "user", content: "hello" }],
prompt: "legacy",
stream_options: { include_usage: true },
instructions: "",
reasoning_effort: "xhigh",
service_tier: "fast",
temperature: 0.4,
user: "cursor",
};
const result = executor.transformRequest("gpt-5-mini-xhigh", body, false, {
requestEndpointPath: "/responses",
});
assert.equal(result.stream, true);
assert.equal(result.store, true);
assert.equal(result.instructions.length > 0, true);
assert.equal(result.reasoning.effort, "high");
assert.equal(result.service_tier, "priority");
assert.equal(result.messages, undefined);
assert.equal(result.prompt, undefined);
assert.equal(result.temperature, undefined);
assert.equal(result.user, undefined);
assert.equal(result.stream_options, undefined);
});
test("CodexExecutor.transformRequest preserves compact requests and native passthrough semantics", () => {
const executor = new CodexExecutor();
const body = {
_nativeCodexPassthrough: true,
instructions: "keep this",
stream: false,
};
const result = executor.transformRequest("gpt-5.3-codex", body, false, {
requestEndpointPath: "/responses/compact",
providerSpecificData: {
requestDefaults: { serviceTier: "priority" },
},
});
assert.equal(result._nativeCodexPassthrough, undefined);
assert.equal(result.stream, undefined);
assert.equal(result.service_tier, "priority");
assert.equal(result.reasoning.effort, "medium");
assert.equal(result.store, true);
assert.equal(result.instructions, "keep this");
});
test("CodexExecutor.transformRequest preserves store-enabled responses state when explicitly enabled", () => {
const executor = new CodexExecutor();
const body = {
_nativeCodexPassthrough: true,
_omnirouteResponsesStore: true,
instructions: "keep this",
previous_response_id: "resp_prev_123",
stream: false,
};
const result = executor.transformRequest("gpt-5.3-codex", body, false, {
requestEndpointPath: "/responses/compact",
providerSpecificData: {
openaiStoreEnabled: true,
requestDefaults: { serviceTier: "priority" },
},
});
assert.equal(result._omnirouteResponsesStore, undefined);
assert.equal(result.store, true);
assert.equal(result.previous_response_id, undefined);
});
test("CodexExecutor.transformRequest applies per-connection reasoning and service tier defaults", () => {
const executor = new CodexExecutor();
const result = executor.transformRequest(
"gpt-5.3-codex",
{ model: "gpt-5.3-codex", input: [] },
false,
{
providerSpecificData: {
requestDefaults: {
reasoningEffort: "high",
serviceTier: "priority",
},
},
}
);
assert.equal(result.reasoning.effort, "high");
assert.equal(result.service_tier, "priority");
});
test("CodexExecutor.transformRequest keeps explicit request values ahead of connection defaults", () => {
const executor = new CodexExecutor();
const result = executor.transformRequest(
"gpt-5.3-codex",
{
model: "gpt-5.3-codex",
input: [],
reasoning_effort: "none",
service_tier: "standard",
},
false,
{
providerSpecificData: {
requestDefaults: {
reasoningEffort: "high",
serviceTier: "priority",
},
},
}
);
assert.equal(result.reasoning.effort, "none");
assert.equal(result.service_tier, "standard");
});
test("CodexExecutor.transformRequest lets model suffix beat connection reasoning defaults", () => {
const executor = new CodexExecutor();
const result = executor.transformRequest(
"gpt-5.3-codex-high",
{ model: "gpt-5.3-codex-high", input: [] },
false,
{
providerSpecificData: {
requestDefaults: {
reasoningEffort: "low",
},
},
}
);
assert.equal(result.model, "gpt-5.3-codex");
assert.equal(result.reasoning.effort, "high");
});
test("CodexExecutor.transformRequest keeps gpt-5.5 as the model and applies xhigh reasoning", () => {
const executor = new CodexExecutor();
const result = executor.transformRequest(
"gpt-5.5",
{ model: "gpt-5.5", input: [], reasoning_effort: "xhigh" },
false,
{}
);
assert.equal(result.model, "gpt-5.5");
assert.equal(result.reasoning.effort, "xhigh");
});
test("CodexExecutor maps Codex websocket error events to response.failed SSE", () => {
const raw = JSON.stringify({
type: "error",
status_code: 429,
error: {
type: "usage_limit_reached",
message: "The usage limit has been reached",
},
});
const result = encodeResponseSseEvent(raw);
assert.equal(result.terminal, true);
assert.match(result.sse, /^event: response\.failed/m);
const dataLine = result.sse.split("\n").find((line) => line.startsWith("data: "));
assert.ok(dataLine);
const payload = JSON.parse(dataLine.slice("data: ".length));
assert.equal(payload.type, "response.failed");
assert.equal(payload.response.status, "failed");
assert.equal(payload.response.error.code, "usage_limit_reached");
assert.equal(payload.response.error.status_code, 429);
});
test("CodexExecutor.transformRequest does not apply connection reasoning defaults when Thinking Budget is not passthrough", () => {
const executor = new CodexExecutor();
setThinkingBudgetConfig({ mode: ThinkingMode.AUTO });
const noDefaults = executor.transformRequest(
"gpt-5.3-codex",
{ model: "gpt-5.3-codex", input: [] },
false,
{
providerSpecificData: {
requestDefaults: {
reasoningEffort: "high",
},
},
}
);
const explicit = executor.transformRequest(
"gpt-5.3-codex",
{ model: "gpt-5.3-codex", input: [], reasoning_effort: "high" },
false,
{
providerSpecificData: {
requestDefaults: {
reasoningEffort: "low",
},
},
}
);
assert.equal(noDefaults.reasoning, undefined);
assert.equal(explicit.reasoning.effort, "high");
});
test("CodexExecutor.refreshCredentials refreshes OAuth tokens and returns null without a refresh token", async () => {
const executor = new CodexExecutor();
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url) => {
assert.match(String(url), /auth\.openai\.com\/oauth\/token$/);
return new Response(
JSON.stringify({
access_token: "new-token",
refresh_token: "new-refresh",
expires_in: 3600,
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
};
try {
assert.equal(await executor.refreshCredentials({}, null), null);
const refreshed = await executor.refreshCredentials({ refreshToken: "refresh-me" }, null);
assert.deepEqual(refreshed, {
accessToken: "new-token",
refreshToken: "new-refresh",
expiresIn: 3600,
});
} finally {
globalThis.fetch = originalFetch;
}
});
test("CodexExecutor.transformRequest preserves image_generation hosted tool for Codex CLI", () => {
const executor = new CodexExecutor();
const body = {
_nativeCodexPassthrough: true,
input: [],
tools: [{ type: "image_generation", output_format: "png" }],
};
const result = executor.transformRequest("gpt-5.3-codex", body, true, {
requestEndpointPath: "/responses",
});
assert.deepEqual(result.tools, [{ type: "image_generation", output_format: "png" }]);
});
test("CodexExecutor.transformRequest preserves web_search and file_search hosted tools", () => {
const executor = new CodexExecutor();
const body = {
_nativeCodexPassthrough: true,
input: [],
tools: [
{ type: "web_search" },
{ type: "file_search" },
{ type: "image_generation", output_format: "png" },
],
};
const result = executor.transformRequest("gpt-5.3-codex", body, true, {
requestEndpointPath: "/responses",
});
assert.deepEqual(result.tools, [
{ type: "web_search" },
{ type: "file_search" },
{ type: "image_generation", output_format: "png" },
]);
});
test("CodexExecutor.transformRequest drops unknown hosted tool types", () => {
const executor = new CodexExecutor();
const body = {
_nativeCodexPassthrough: true,
input: [],
tools: [{ type: "made_up_tool" }, { type: "image_generation", output_format: "png" }],
};
const result = executor.transformRequest("gpt-5.3-codex", body, true, {
requestEndpointPath: "/responses",
});
assert.deepEqual(result.tools, [{ type: "image_generation", output_format: "png" }]);
});
test("CodexExecutor.transformRequest keeps valid function tools and drops empty-named ones", () => {
const executor = new CodexExecutor();
const body = {
_nativeCodexPassthrough: true,
input: [],
tools: [
{ type: "function", function: { name: "" } },
{ type: "function", function: { name: " " } },
{ type: "function", function: { name: "shell", parameters: {} } },
],
};
const result = executor.transformRequest("gpt-5.3-codex", body, true, {
requestEndpointPath: "/responses",
});
assert.equal(result.tools.length, 1);
assert.equal(result.tools[0].function.name, "shell");
});
test("CodexExecutor.transformRequest leaves hosted tool_choice untouched and strips stale function tool_choice", () => {
const executor = new CodexExecutor();
const hostedChoice = executor.transformRequest(
"gpt-5.3-codex",
{
_nativeCodexPassthrough: true,
input: [],
tools: [{ type: "image_generation", output_format: "png" }],
tool_choice: { type: "image_generation" },
},
true,
{ requestEndpointPath: "/responses" }
);
assert.deepEqual(hostedChoice.tool_choice, { type: "image_generation" });
const staleChoice = executor.transformRequest(
"gpt-5.3-codex",
{
_nativeCodexPassthrough: true,
input: [],
tools: [{ type: "function", function: { name: "shell" } }],
tool_choice: { type: "function", name: "ghost" },
},
true,
{ requestEndpointPath: "/responses" }
);
assert.equal(staleChoice.tool_choice, undefined);
});
test("CodexExecutor.transformRequest drops hosted tools that also declare name or function properties", () => {
const executor = new CodexExecutor();
const body = {
_nativeCodexPassthrough: true,
input: [],
tools: [
{ type: "image_generation", name: "img", output_format: "png" },
{ type: "image_generation", function: { name: "img" }, output_format: "png" },
{ type: "image_generation", output_format: "png" },
],
};
const result = executor.transformRequest("gpt-5.3-codex", body, true, {
requestEndpointPath: "/responses",
});
assert.deepEqual(result.tools, [{ type: "image_generation", output_format: "png" }]);
});
test("CodexExecutor.transformRequest defaults store to false when image_generation tool is present", () => {
const executor = new CodexExecutor();
const withImageGen = executor.transformRequest(
"gpt-5.3-codex",
{
_nativeCodexPassthrough: true,
input: [],
tools: [{ type: "image_generation", output_format: "png" }],
},
true,
{ requestEndpointPath: "/responses" }
);
assert.equal(withImageGen.store, false);
const withoutImageGen = executor.transformRequest(
"gpt-5.3-codex",
{
_nativeCodexPassthrough: true,
input: [],
tools: [{ type: "function", function: { name: "shell" } }],
},
true,
{ requestEndpointPath: "/responses" }
);
assert.equal(withoutImageGen.store, true);
const explicitTrue = executor.transformRequest(
"gpt-5.3-codex",
{
_nativeCodexPassthrough: true,
input: [],
store: true,
tools: [{ type: "image_generation", output_format: "png" }],
},
true,
{ requestEndpointPath: "/responses" }
);
assert.equal(explicitTrue.store, true);
});