mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 02:42:24 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
133 lines
5.2 KiB
TypeScript
133 lines
5.2 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { sortCatalogModelsProviderGrouped } from "../../src/app/api/v1/models/catalogOrder.ts";
|
|
|
|
test("combo pinning: combos move to front regardless of input or registry order", () => {
|
|
// Combos are at input positions 1 and 3, and "combo" is not a registry key
|
|
// (would rank Infinity/unknown without pinning). Asserting they land first
|
|
// proves pinning overrides both input order and registry precedence.
|
|
const input = [
|
|
{ id: "openai/gpt-4", owned_by: "openai" },
|
|
{ id: "auto/smart", owned_by: "combo" },
|
|
{ id: "anthropic/claude", owned_by: "anthropic" },
|
|
{ id: "auto/cheap", owned_by: "combo" },
|
|
];
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
assert.deepEqual(
|
|
out.map((m) => m.id),
|
|
["auto/smart", "auto/cheap", "openai/gpt-4", "anthropic/claude"]
|
|
);
|
|
});
|
|
|
|
test("canonical owned_by grouping: oc prefix with opencode owned_by stays contiguous", () => {
|
|
const input = [
|
|
{ id: "oc/kimi-k2", owned_by: "opencode" },
|
|
{ id: "openai/gpt-4", owned_by: "openai" },
|
|
{ id: "oc/glm-5", owned_by: "opencode" },
|
|
{ id: "openai/gpt-5", owned_by: "openai" },
|
|
];
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
const keys = out.map((m) => m.owned_by);
|
|
assert.equal(keys.lastIndexOf("opencode") - keys.indexOf("opencode"), 1);
|
|
assert.equal(keys.lastIndexOf("openai") - keys.indexOf("openai"), 1);
|
|
});
|
|
|
|
test("registry precedence over code-unit: qoder before agy (both oauth)", () => {
|
|
// oauth.ts key order: qoder (idx 3) before agy (idx 4); code-unit: agy < qoder.
|
|
const input = [
|
|
{ id: "agy/gemini", owned_by: "agy" },
|
|
{ id: "qoder/model", owned_by: "qoder" },
|
|
];
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
assert.deepEqual(
|
|
out.map((m) => m.owned_by),
|
|
["qoder", "agy"]
|
|
);
|
|
});
|
|
|
|
test("registry precedence over code-unit: zed (oauth) before openai (apikey)", () => {
|
|
// oauth tier precedes apikey tier; code-unit: openai < zed.
|
|
const input = [
|
|
{ id: "openai/gpt-4", owned_by: "openai" },
|
|
{ id: "zed/model", owned_by: "zed" },
|
|
];
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
assert.deepEqual(
|
|
out.map((m) => m.owned_by),
|
|
["zed", "openai"]
|
|
);
|
|
});
|
|
|
|
test("unknown providers: deterministic code-unit order", () => {
|
|
const input = [
|
|
{ id: "zzz-unknown/m1", owned_by: "zzz-unknown" },
|
|
{ id: "Zed-unknown/m2", owned_by: "Zed-unknown" },
|
|
{ id: "aaa-unknown/m3", owned_by: "aaa-unknown" },
|
|
{ id: "9nine-unknown/m4", owned_by: "9nine-unknown" },
|
|
];
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
// Code-unit: '9'(0x39) < 'Z'(0x5A) < 'a'(0x61) < 'z'(0x7A).
|
|
assert.deepEqual(
|
|
out.map((m) => m.owned_by),
|
|
["9nine-unknown", "Zed-unknown", "aaa-unknown", "zzz-unknown"]
|
|
);
|
|
});
|
|
|
|
test("malformed rows: fallback to id-prefix, exact ordered sequence", () => {
|
|
// Empty id ("") is legal by the Record<string, unknown> type; group key ""
|
|
// sorts first among unknown fallbacks by code unit. Covers missing owned_by,
|
|
// empty owned_by, slashless id, and empty id, plus stability within a group.
|
|
const input = [
|
|
{ id: "openai/gpt-4", owned_by: "openai" }, // registry group
|
|
{ id: "weird/model", owned_by: "" }, // empty owned_by → prefix "weird"
|
|
{ id: "slashless", owned_by: "" }, // empty owned_by, no slash → "slashless"
|
|
{ id: "openai/gpt-5", owned_by: "openai" }, // registry group
|
|
{ id: "weird/model2" }, // missing owned_by → prefix "weird"
|
|
{ id: "", owned_by: "" }, // empty id → group key ""
|
|
];
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
// openai (finite registry rank) first in input order; then unknown fallbacks
|
|
// by code-unit of group key: "" < "slashless" < "weird"; stable within "weird".
|
|
assert.deepEqual(
|
|
out.map((m) => m.id),
|
|
["openai/gpt-4", "openai/gpt-5", "", "slashless", "weird/model", "weird/model2"]
|
|
);
|
|
});
|
|
|
|
test("stability: equal-ID twins preserve input order", () => {
|
|
const input = [
|
|
{ id: "openai/gpt-4", owned_by: "openai", subtype: "chat" },
|
|
{ id: "openai/gpt-4", owned_by: "openai", subtype: "speech" },
|
|
{ id: "openai/gpt-3.5", owned_by: "openai" },
|
|
];
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
assert.equal(out[0].subtype, "chat");
|
|
assert.equal(out[1].subtype, "speech");
|
|
assert.equal(out[2].id, "openai/gpt-3.5");
|
|
});
|
|
|
|
test("non-mutation: input array and elements untouched", () => {
|
|
const input = [
|
|
{ id: "openai/gpt-4", owned_by: "openai" },
|
|
{ id: "anthropic/claude", owned_by: "anthropic" },
|
|
];
|
|
const snapshot = JSON.parse(JSON.stringify(input));
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
assert.deepEqual(input, snapshot);
|
|
assert.notEqual(out, input);
|
|
assert.equal(out.length, input.length);
|
|
});
|
|
|
|
test("no drops or dupes: every row present exactly once", () => {
|
|
const input = [
|
|
{ id: "openai/gpt-4", owned_by: "openai" },
|
|
{ id: "auto/x", owned_by: "combo" },
|
|
{ id: "anthropic/claude", owned_by: "anthropic" },
|
|
{ id: "weird/m", owned_by: "" },
|
|
{ id: "openai/gpt-5", owned_by: "openai" },
|
|
];
|
|
const out = sortCatalogModelsProviderGrouped(input);
|
|
assert.equal(out.length, input.length);
|
|
assert.deepEqual(out.map((m) => m.id).sort(), input.map((m) => m.id).sort());
|
|
});
|