mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-16 20:02:45 +03:00
Merged as part of the 39-PR owner batch of 2026-09-11, validated as a unit. Boarded into one consolidated worktree cut from `release/v3.8.51` with the other 38 — zero conflicts between them. - ESLint over every changed file: no errors (the only finding was one suppression entry the batch emptied, pruned on #13243) - `typecheck:core` clean; `check:dashboard-typecheck` OK (206 pre-existing, within baseline); `check:changelog-integrity` OK - complexity 2821 / baseline 3218 and cognitive-complexity 1272 / baseline 1437 — both under baseline - 256 assertions green: 246 under node:test and 10 under vitest, which is where `tests/unit/**/*.test.tsx` actually runs - `check-file-size`: `chatCore.ts` rebaselined 6144 → 6146 for #13278 and #13276, annotated and landed on #13243 ⚠️ base-red inherited: #12732 — the provider count (356 in the docs vs the 358 the modules define) and `open-sse/utils/stream.ts` at 3115 > frozen 3098 both reproduce on the pure tip with zero contribution from this batch.
71 lines
3.4 KiB
TypeScript
71 lines
3.4 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { resolveComboTargets } from "../../open-sse/services/combo/comboStructure.ts";
|
|
import { resolveComboTargetModelStr } from "../../open-sse/services/combo/opencodeTargetAlias.ts";
|
|
import { parseModel } from "../../open-sse/services/model.ts";
|
|
|
|
// Issue #11912: a round-robin combo built from several "opencode" (free /
|
|
// dynamic no-auth) targets plus one "opencode-zen" (authenticated api-key)
|
|
// target routed 100% of upstream traffic to the opencode-zen connection.
|
|
//
|
|
// Root cause: open-sse/services/model.ts's manual ALIAS_TO_PROVIDER_ID
|
|
// override canonicalizes ANY "opencode/<model>" string to provider
|
|
// "opencode-zen" before dispatch, so every declared "opencode/<model>"
|
|
// combo target and the explicit "opencode-zen/<model>" target resolved to
|
|
// the identical provider identity — round-robin's "7 targets" were never 7
|
|
// distinct upstream accounts.
|
|
//
|
|
// Fix: combo target resolution (comboStructure.ts's normalizeRuntimeStep)
|
|
// now rewrites an ambiguous "opencode/<model>" combo target to the "oc/"
|
|
// no-auth alias, mirroring the combo builder's existing #2901 guard, before
|
|
// the model string reaches dispatch — so it resolves to the true no-auth
|
|
// "opencode" provider and stays distinct from an "opencode-zen/<model>"
|
|
// sibling target.
|
|
|
|
test("issue #11912: round-robin combo keeps opencode and opencode-zen targets on distinct providers", () => {
|
|
const targets = resolveComboTargets(
|
|
{
|
|
name: "opencode-round-robin",
|
|
strategy: "round-robin",
|
|
models: [
|
|
{ kind: "model", model: "opencode/mimo-v2.5-free" },
|
|
{ kind: "model", model: "opencode/mimo-v2.5-free" },
|
|
{ kind: "model", model: "opencode-zen/mimo-v2.5-free" },
|
|
],
|
|
},
|
|
null
|
|
);
|
|
|
|
assert.equal(targets.length, 3);
|
|
const [dynamicA, dynamicB, authenticated] = targets;
|
|
|
|
assert.notEqual(
|
|
dynamicA.provider,
|
|
authenticated.provider,
|
|
`combo target "opencode/<model>" resolved to provider "${dynamicA.provider}" — it collapsed ` +
|
|
`onto the same identity as the explicit "opencode-zen/<model>" target instead of routing ` +
|
|
`to the free/dynamic no-auth pool`
|
|
);
|
|
assert.equal(dynamicA.provider, dynamicB.provider);
|
|
assert.equal(authenticated.provider, "opencode-zen");
|
|
|
|
// The rewritten model string must still resolve to the genuine no-auth
|
|
// provider identity when it later reaches dispatch (parseModel is exactly
|
|
// what open-sse/services/combo/roundRobinCombo.ts and
|
|
// resolveModelOrError() call on the resolved target's modelStr).
|
|
assert.equal(parseModel(dynamicA.modelStr).provider, "opencode");
|
|
assert.equal(parseModel(authenticated.modelStr).provider, "opencode-zen");
|
|
});
|
|
|
|
test("resolveComboTargetModelStr rewrites the ambiguous opencode/ prefix to oc/", () => {
|
|
assert.equal(resolveComboTargetModelStr("opencode/mimo-v2.5-free"), "oc/mimo-v2.5-free");
|
|
// Siblings and the explicit api-key gateway must pass through untouched.
|
|
assert.equal(resolveComboTargetModelStr("opencode-zen/mimo-v2.5-free"), "opencode-zen/mimo-v2.5-free");
|
|
assert.equal(resolveComboTargetModelStr("opencode-go/mimo-v2.5-free"), "opencode-go/mimo-v2.5-free");
|
|
assert.equal(resolveComboTargetModelStr("oc/mimo-v2.5-free"), "oc/mimo-v2.5-free");
|
|
// Non-slashed / non-opencode strings are untouched.
|
|
assert.equal(resolveComboTargetModelStr("bare-model"), "bare-model");
|
|
assert.equal(resolveComboTargetModelStr("anthropic/claude"), "anthropic/claude");
|
|
});
|