Files
diegosouzapw--omniroute/tests/unit/codex-effort-alias-priority.test.ts
2026-07-13 13:39:12 +08:00

114 lines
3.8 KiB
TypeScript

/**
* Issue #2331 — Codex model alias effort suffixes
* (`gpt-5.5-xhigh`, `-high`, `-medium`, `-low`) are the user's explicit
* routing choice and must override a client-injected `reasoning.effort`
* default. OpenCode auto-injects `reasoning.effort=medium` for GPT-5-family
* requests, which used to silently mask the suffix.
*
* The fix is in `open-sse/executors/codex.ts`: priority is
* modelEffort > explicitReasoning > requestReasoningEffort > fallback.
*
* These tests exercise the effort-resolution priority directly via a
* small re-implementation of the resolution chain so we don't have to
* spin up the full Codex executor (which talks to upstream).
*/
import test from "node:test";
import assert from "node:assert/strict";
// Replicate the priority chain that lives in
// open-sse/executors/codex.ts:1382-1402 so tests fail loudly if someone
// reverts the order.
type Inputs = {
modelEffort: string | null;
explicitReasoning: string | undefined;
requestReasoningEffort: string | undefined;
fallbackReasoningEffort: string | undefined;
};
function resolveEffort(i: Inputs): string | undefined {
return (
i.modelEffort ||
i.explicitReasoning ||
i.requestReasoningEffort ||
i.fallbackReasoningEffort ||
undefined
);
}
test("#2331 model suffix wins over client reasoning.effort default", () => {
const out = resolveEffort({
modelEffort: "xhigh",
explicitReasoning: "medium", // OpenCode default
requestReasoningEffort: undefined,
fallbackReasoningEffort: undefined,
});
assert.equal(out, "xhigh");
});
test("#2331 model suffix wins over body.reasoning_effort field too", () => {
const out = resolveEffort({
modelEffort: "low",
explicitReasoning: undefined,
requestReasoningEffort: "high",
fallbackReasoningEffort: undefined,
});
assert.equal(out, "low");
});
test("#2331 without suffix, explicit client effort still works (backward compat)", () => {
const out = resolveEffort({
modelEffort: null,
explicitReasoning: "high",
requestReasoningEffort: undefined,
fallbackReasoningEffort: "medium",
});
assert.equal(out, "high");
});
test("#2331 without suffix or client value, connection fallback applies", () => {
const out = resolveEffort({
modelEffort: null,
explicitReasoning: undefined,
requestReasoningEffort: undefined,
fallbackReasoningEffort: "medium",
});
assert.equal(out, "medium");
});
test("#2331 no input anywhere → undefined (caller will skip body.reasoning)", () => {
const out = resolveEffort({
modelEffort: null,
explicitReasoning: undefined,
requestReasoningEffort: undefined,
fallbackReasoningEffort: undefined,
});
assert.equal(out, undefined);
});
// ─── Regression check on the actual source ─────────────────────────────
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const CODEX_SRC = path.resolve(__dirname, "../../open-sse/executors/codex.ts");
test("#2331 codex.ts still prioritizes modelEffort first in rawEffort chain", () => {
const src = fs.readFileSync(CODEX_SRC, "utf8");
// The chain we expect: rawEffort = modelEffort || explicitReasoning || ...
// Anchor on the assignment so a future refactor that flips priority back
// (the bug we just fixed) trips this guard.
const ASSIGNMENT_RE = /const\s+rawEffort\s*=\s*([\s\S]{0,400}?);/;
const match = src.match(ASSIGNMENT_RE);
assert.ok(match, "rawEffort assignment not found in codex.ts");
const chain = match![1].replace(/\s+/g, " ").trim();
const firstToken = chain.split("||")[0].trim();
assert.equal(
firstToken,
"modelEffort",
`rawEffort priority chain must start with modelEffort, got: ${chain}`
);
});