File size: 3,708 Bytes
5448d8b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | /**
* Regression tests for `isUsableCombo` (release/v3.8.2 code review, finding C1).
*
* The combo member refs returned by `/api/combos` do NOT carry a separate
* `providerId` field β OmniRoute's `normalizeComboRecord` folds the provider
* id INTO the full model string (e.g. "cc/claude-opus-4-7"). The previous
* implementation read `step.providerId` (always `undefined`), so the
* `usableOnly` combo filter silently never dropped anything. These tests pin
* the corrected behavior: the verdict is derived from the `step.model` prefix,
* mirroring `isUsableRawModelId`'s subtract-filter semantics.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { isUsableCombo, type OmniRouteRawCombo } from "../src/index.js";
/** Build a `usable` set bundle for the tests. */
function buildUsable(opts: { aliases?: string[]; canonicals?: string[]; known?: string[] }): {
aliases: Set<string>;
canonicals: Set<string>;
knownAliases: Set<string>;
} {
return {
aliases: new Set(opts.aliases ?? []),
canonicals: new Set(opts.canonicals ?? []),
// knownAliases is the union of every prefix the universe is aware of β
// usable or not. Default to including the usable aliases too.
knownAliases: new Set([...(opts.known ?? []), ...(opts.aliases ?? [])]),
};
}
function combo(models: OmniRouteRawCombo["models"]): OmniRouteRawCombo {
return { id: "c1", name: "Test Combo", models };
}
test("isUsableCombo: member with a usable alias prefix β keep", () => {
const usable = buildUsable({ aliases: ["cc"], known: ["cc", "dead"] });
const c = combo([{ kind: "model", model: "cc/claude-opus-4-7" }]);
assert.equal(isUsableCombo(c, usable), true);
});
test("isUsableCombo: all members known-but-NOT-usable β drop (the C1 regression)", () => {
// Before the fix this returned true unconditionally because step.providerId
// was always undefined. Now the known-but-unusable "dead" prefix is dropped.
const usable = buildUsable({ aliases: ["cc"], known: ["cc", "dead"] });
const c = combo([
{ kind: "model", model: "dead/legacy-model" },
{ kind: "model", model: "dead/another" },
]);
assert.equal(isUsableCombo(c, usable), false);
});
test("isUsableCombo: unknown prefix β keep (cannot prove unroutable)", () => {
const usable = buildUsable({ aliases: ["cc"], known: ["cc", "dead"] });
const c = combo([{ kind: "model", model: "agentrouter/mystery" }]);
assert.equal(isUsableCombo(c, usable), true);
});
test("isUsableCombo: mixed non-usable + usable member β keep", () => {
const usable = buildUsable({ aliases: ["cc"], known: ["cc", "dead"] });
const c = combo([
{ kind: "model", model: "dead/legacy" },
{ kind: "model", model: "cc/claude-opus-4-7" },
]);
assert.equal(isUsableCombo(c, usable), true);
});
test("isUsableCombo: zero members β keep", () => {
const usable = buildUsable({ aliases: ["cc"], known: ["cc"] });
assert.equal(isUsableCombo(combo([]), usable), true);
assert.equal(isUsableCombo(combo(undefined), usable), true);
});
test("isUsableCombo: only combo-ref steps (no resolvable model) β keep", () => {
const usable = buildUsable({ aliases: ["cc"], known: ["cc", "dead"] });
const c = combo([{ kind: "combo-ref", comboName: "nested" }]);
assert.equal(isUsableCombo(c, usable), true);
});
test("isUsableCombo: usable canonical prefix β keep", () => {
const usable = buildUsable({ canonicals: ["anthropic"], known: ["anthropic", "dead"] });
const c = combo([{ kind: "model", model: "anthropic/claude-opus-4-7" }]);
assert.equal(isUsableCombo(c, usable), true);
});
|