mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 13:22:11 +03:00
* feat(dashboard): add search to Playground model picker dropdown (#4086) The shared ModelSelectModal (combo builder + CLI-code cards) already had search, but the Playground's raw model <select> in StudioConfigPane stayed a flat unsearchable list - unusable once a provider like OpenRouter contributed 50+ models. Adds a search input above the dropdown that filters options via filterModelsByQuery() (Turkish-safe accent/case-insensitive match, reusing matchesSearch()). The currently selected model always stays pinned in the list even when it doesn't match the query, so typing never silently swaps the active selection. Reuses the existing common.search i18n key already translated in all 42 locales - no new key needed. * chore(6811): re-sync onto release tip; CHANGELOG → changelog.d fragment (fragments-first)
75 lines
3.3 KiB
TypeScript
75 lines
3.3 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
pickDefaultModel,
|
|
resolveModelFilterKey,
|
|
filterModelsByQuery,
|
|
} from "../../src/app/(dashboard)/dashboard/playground/components/modelSelection.ts";
|
|
|
|
// Regression guards for #3731 (dup #3009): the Playground model selector was unusable
|
|
// for custom OpenAI-compatible providers.
|
|
|
|
test("resolveModelFilterKey: built-in provider filters by its id", () => {
|
|
assert.equal(resolveModelFilterKey("openai", undefined, false), "openai");
|
|
assert.equal(resolveModelFilterKey("anthropic", undefined, false), "anthropic");
|
|
});
|
|
|
|
test("resolveModelFilterKey: compatible provider WITH a resolved prefix filters by the prefix", () => {
|
|
assert.equal(resolveModelFilterKey("openai-compatible-abc123", "myco", true), "myco");
|
|
});
|
|
|
|
test("resolveModelFilterKey: compatible provider WITHOUT a prefix shows the full catalog (#3731)", () => {
|
|
// Defect A: the old logic returned the raw connection id, which matches nothing in the
|
|
// catalog and emptied the selector. It must return undefined (full catalog) instead.
|
|
const key = resolveModelFilterKey("openai-compatible-abc123", undefined, true);
|
|
assert.equal(key, undefined);
|
|
assert.notEqual(key, "openai-compatible-abc123");
|
|
});
|
|
|
|
test("resolveModelFilterKey: empty provider yields undefined", () => {
|
|
assert.equal(resolveModelFilterKey("", undefined, false), undefined);
|
|
});
|
|
|
|
test("pickDefaultModel: empty list selects nothing", () => {
|
|
assert.equal(pickDefaultModel("", []), null);
|
|
assert.equal(pickDefaultModel("gpt-4o", []), null);
|
|
});
|
|
|
|
test("pickDefaultModel: empty current model auto-selects the first model (#3731)", () => {
|
|
// Defect B: provider change reset the model to "" and nothing picked a default, so the
|
|
// chat failed with "Set a model". The first available model must be auto-selected.
|
|
assert.equal(pickDefaultModel("", ["myco/gpt-4o", "myco/gpt-4o-mini"]), "myco/gpt-4o");
|
|
assert.equal(pickDefaultModel(undefined, ["a", "b"]), "a");
|
|
});
|
|
|
|
test("pickDefaultModel: a current model not in the list is replaced by the first", () => {
|
|
assert.equal(pickDefaultModel("stale/model", ["a", "b"]), "a");
|
|
});
|
|
|
|
test("pickDefaultModel: a valid current model is kept (no redundant update)", () => {
|
|
assert.equal(pickDefaultModel("b", ["a", "b"]), null);
|
|
});
|
|
|
|
// Regression guards for #4086: search/filter on the raw Playground model <select>.
|
|
|
|
test("filterModelsByQuery: empty query returns the full list unchanged", () => {
|
|
const models = ["openai/gpt-4o", "anthropic/claude-3"];
|
|
assert.deepEqual(filterModelsByQuery(models, ""), models);
|
|
assert.deepEqual(filterModelsByQuery(models, " "), models);
|
|
});
|
|
|
|
test("filterModelsByQuery: matches case-insensitively on substring", () => {
|
|
const models = ["openai/gpt-4o", "anthropic/claude-3", "openrouter/mistral-large"];
|
|
assert.deepEqual(filterModelsByQuery(models, "GPT"), ["openai/gpt-4o"]);
|
|
assert.deepEqual(filterModelsByQuery(models, "claude"), ["anthropic/claude-3"]);
|
|
});
|
|
|
|
test("filterModelsByQuery: matches provider/namespace prefix", () => {
|
|
const models = ["openai/gpt-4o", "anthropic/claude-3", "openrouter/mistral-large"];
|
|
assert.deepEqual(filterModelsByQuery(models, "openrouter"), ["openrouter/mistral-large"]);
|
|
});
|
|
|
|
test("filterModelsByQuery: no matches returns an empty list", () => {
|
|
assert.deepEqual(filterModelsByQuery(["a", "b"], "zzz"), []);
|
|
});
|