Files
OmniRoute/tests/unit/gemini-models-parser.test.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
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.
2026-08-23 11:45:01 -03:00

83 lines
3.1 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import { parseGeminiModelsList } from "../../src/lib/providerModels/geminiModelsParser";
// A representative slice of the live generativelanguage v1beta/models response.
const SAMPLE = {
models: [
{
name: "models/gemini-2.5-flash",
displayName: "Gemini 2.5 Flash",
inputTokenLimit: 1048576,
outputTokenLimit: 65536,
supportedGenerationMethods: ["generateContent", "countTokens", "batchGenerateContent"],
thinking: true,
},
{
name: "models/gemini-3-pro-image-preview",
displayName: "Gemini 3 Pro Image Preview",
supportedGenerationMethods: ["generateContent", "countTokens"],
},
{
name: "models/text-embedding-004",
displayName: "Text Embedding 004",
supportedGenerationMethods: ["embedContent"],
},
{
name: "models/gemini-live-2.5-flash",
displayName: "Gemini Live",
supportedGenerationMethods: ["bidiGenerateContent"],
},
{
name: "models/veo-3.0-generate-001",
displayName: "Veo 3.0",
supportedGenerationMethods: ["predictLongRunning"],
},
],
};
test("parseGeminiModelsList strips the models/ prefix and maps display name", () => {
const models = parseGeminiModelsList(SAMPLE);
const flash = models.find((m) => m.id === "gemini-2.5-flash");
assert.ok(flash, "gemini-2.5-flash should be present");
assert.equal(flash!.name, "Gemini 2.5 Flash");
assert.equal(flash!.inputTokenLimit, 1048576);
assert.equal(flash!.outputTokenLimit, 65536);
assert.equal(flash!.supportsThinking, true);
assert.deepEqual(flash!.supportedEndpoints, ["chat"]);
});
test("parseGeminiModelsList maps generateContent image models to the chat endpoint", () => {
const models = parseGeminiModelsList(SAMPLE);
const proImage = models.find((m) => m.id === "gemini-3-pro-image-preview");
assert.ok(proImage, "gemini-3-pro-image-preview should be present");
// gemini-*-image models generate images via generateContent (chat-with-modalities path).
assert.deepEqual(proImage!.supportedEndpoints, ["chat"]);
});
test("parseGeminiModelsList maps embedContent and bidiGenerateContent", () => {
const models = parseGeminiModelsList(SAMPLE);
assert.deepEqual(models.find((m) => m.id === "text-embedding-004")!.supportedEndpoints, [
"embeddings",
]);
assert.deepEqual(models.find((m) => m.id === "gemini-live-2.5-flash")!.supportedEndpoints, [
"audio",
]);
});
test("parseGeminiModelsList maps Veo predictLongRunning models to the video endpoint", () => {
const models = parseGeminiModelsList(SAMPLE);
const veo = models.find((m) => m.id === "veo-3.0-generate-001");
assert.ok(veo, "veo-3.0-generate-001 should be present");
assert.deepEqual(veo!.supportedEndpoints, ["video"]);
});
test("parseGeminiModelsList defaults to chat and tolerates empty/missing input", () => {
assert.deepEqual(parseGeminiModelsList({}), []);
assert.deepEqual(parseGeminiModelsList(null), []);
const [m] = parseGeminiModelsList({ models: [{ name: "models/mystery" }] });
assert.equal(m.id, "mystery");
assert.deepEqual(m.supportedEndpoints, ["chat"]);
});