mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 15:52:52 +03:00
* fix(routing): only let Codex-native bare ids preempt a provider when codex is active #9275 widened CODEX_NATIVE_UNPREFIXED_MODELS from a single id to gpt-5.5 plus the gpt-5.6-sol/terra/luna tiers, so bare Codex CLI ids would reach the ChatGPT subscription instead of fanning out to whichever provider won the inference race. The early return it added never consulted the active-provider set, which made the codex-only guard 30 lines below unreachable for every id in the set: if (CODEX_NATIVE_UNPREFIXED_MODELS.has(modelId)) return { provider: "codex", ... } An OpenAI-only install therefore had bare gpt-5.5 routed to codex and failed with 'no active credentials for provider: codex' on a model OpenAI serves, and an install whose codex connection was merely inactive failed identically. This also silently reverted #5887's compatibility boundary. The preference now only PREEMPTS another provider when a codex connection is active. Ids that no other provider catalogs (codex-auto-review) still resolve to codex with no connection at all — there is nothing to preempt and 'no codex credentials' is the honest error. With codex active the preference still beats OpenAI, which is the point of #9275, and an explicit openai/ prefix overrides it either way. Tests: the three assertions that encode the intended #9275 change now expect codex (plus a new one pinning the explicit-prefix override); the rest were already correct and pass again untouched. Adds a regression test for the OpenAI-only case. * docs(changelog): correct fragment id to #9447 * test(routing): seed an active codex connection in the bare-precedence guards The two files #9275 added assert that bare gpt-5.5 / gpt-5.6-sol reach codex, but they ran against an empty database — so they also pinned 'codex wins with no codex connection at all', which is the regression #9447 removes. That put them in direct contradiction with plan3-p0 / chat-helpers / codex-gpt55-routing-5887, which assert openai for the very same input: no implementation could satisfy both, which is why the release could not go green. Seeding an active codex connection keeps the contract these files were written to guard (codex beats openai for a Codex-native bare id) while dropping the accidental 'even with no codex configured' half. Cases that need no connection are left as they were: the tier-only ids and codex-auto-review have no alternative provider to preempt, and the explicit-prefix overrides are unaffected. --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
108 lines
3.9 KiB
TypeScript
108 lines
3.9 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
|
|
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-bare-precedence-"));
|
|
process.env.DATA_DIR = TEST_DATA_DIR;
|
|
|
|
const core = await import("../../src/lib/db/core.ts");
|
|
const providersDb = await import("../../src/lib/db/providers.ts");
|
|
const { CODEX_NATIVE_UNPREFIXED_MODELS, getModelInfoCore } = await import(
|
|
"../../open-sse/services/model.ts"
|
|
);
|
|
|
|
// #FIX: bare Codex-default model ids must route to the `codex` provider
|
|
// (chatgpt.com OAuth) when no provider prefix is supplied, even when other
|
|
// providers that also catalog the id (e.g. `agentrouter`, `openai`) are
|
|
// active. The Codex cookie quota is the source of truth — auto-fanning to
|
|
// other providers silently breaks the "default" experience.
|
|
//
|
|
// #9447 bounded that precedence: it may only PREEMPT another provider when a
|
|
// codex connection is actually ACTIVE. These cases therefore seed one first.
|
|
// Without that bound, an OpenAI-only install had bare `gpt-5.5` sent to codex
|
|
// and failed with "no active credentials for provider: codex" on a model
|
|
// OpenAI serves. Ids that no other provider catalogs (the tier variants,
|
|
// `codex-auto-review`) still resolve to codex with no connection at all —
|
|
// there is no alternative to preempt — so those cases seed nothing.
|
|
async function seedActiveCodexConnection() {
|
|
await providersDb.createProviderConnection({
|
|
provider: "codex",
|
|
authType: "oauth",
|
|
email: "codex@example.com",
|
|
providerSpecificData: { workspaceId: "ws-precedence" },
|
|
});
|
|
}
|
|
|
|
test.after(() => {
|
|
core.resetDbInstance();
|
|
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
|
});
|
|
|
|
test("CODEX_NATIVE_UNPREFIXED_MODELS includes gpt-5.6-sol tier set", () => {
|
|
for (const id of [
|
|
"gpt-5.6-sol",
|
|
"gpt-5.6-sol-max",
|
|
"gpt-5.6-sol-xhigh",
|
|
"gpt-5.6-sol-high",
|
|
"gpt-5.6-sol-medium",
|
|
"gpt-5.6-sol-low",
|
|
"gpt-5.6-terra",
|
|
"gpt-5.6-terra-xhigh",
|
|
"gpt-5.6-luna",
|
|
"gpt-5.6-luna-xhigh",
|
|
"gpt-5.5",
|
|
"gpt-5.5-xhigh",
|
|
"gpt-5.5-medium",
|
|
"gpt-5.5-low",
|
|
"gpt-5.3-codex-spark",
|
|
"codex-auto-review",
|
|
]) {
|
|
assert.equal(
|
|
CODEX_NATIVE_UNPREFIXED_MODELS.has(id),
|
|
true,
|
|
`expected CODEX_NATIVE_UNPREFIXED_MODELS to include ${id}`
|
|
);
|
|
}
|
|
});
|
|
|
|
test("bare gpt-5.6-sol resolves to codex (provider native prefix wins)", async () => {
|
|
await seedActiveCodexConnection();
|
|
const info = await getModelInfoCore("gpt-5.6-sol", null);
|
|
assert.equal(info.provider, "codex", "bare gpt-5.6-sol must route to codex");
|
|
assert.equal(info.model, "gpt-5.6-sol");
|
|
});
|
|
|
|
test("bare gpt-5.5 resolves to codex", async () => {
|
|
const info = await getModelInfoCore("gpt-5.5", null);
|
|
assert.equal(info.provider, "codex");
|
|
assert.equal(info.model, "gpt-5.5");
|
|
});
|
|
|
|
test("bare gpt-5.6-sol-max resolves to codex", async () => {
|
|
const info = await getModelInfoCore("gpt-5.6-sol-max", null);
|
|
assert.equal(info.provider, "codex");
|
|
assert.equal(info.model, "gpt-5.6-sol-max");
|
|
});
|
|
|
|
test("agentrouter/gpt-5.6-sol (explicit prefix) routes to agentrouter", async () => {
|
|
const info = await getModelInfoCore("agentrouter/gpt-5.6-sol", null);
|
|
assert.equal(info.provider, "agentrouter");
|
|
assert.equal(info.model, "gpt-5.6-sol");
|
|
});
|
|
|
|
test("openai/gpt-5.6-sol (explicit prefix) routes to openai", async () => {
|
|
const info = await getModelInfoCore("openai/gpt-5.6-sol", null);
|
|
assert.equal(info.provider, "openai");
|
|
assert.equal(info.model, "gpt-5.6-sol");
|
|
});
|
|
|
|
test("codex-auto-review remains in the precedence set (regression guard)", async () => {
|
|
// Pre-fix regression: removing/replacing the set would silently break the
|
|
// `/review` codepath that ships with the Codex CLI.
|
|
assert.equal(CODEX_NATIVE_UNPREFIXED_MODELS.has("codex-auto-review"), true);
|
|
const info = await getModelInfoCore("codex-auto-review", null);
|
|
assert.equal(info.provider, "codex");
|
|
});
|