Files
OmniRoute/open-sse/config/dynamicImageModelSources.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

50 lines
2.0 KiB
TypeScript

/**
* Registry indirection for image providers whose model list is discovered at runtime (#10692).
*
* `IMAGE_PROVIDERS` is reachable from `"use client"` dashboard pages — they read its KEYS to
* decide which providers support which media kind (see `mediaServiceKinds.ts`). A provider entry
* that imports its live-catalog service directly therefore drags that service, and everything it
* imports, into the browser graph. For AI Horde that meant
* `aihordeImageCatalog → safeOutboundFetch → proxyFetch → featureFlags → db/core → sqljsAdapter`,
* so the build tried to bundle `fs`/`net`/`tls` for the browser and failed.
*
* A dynamic `import()` does not help: the bundler still has to make the module browser-loadable.
* The dependency has to be inverted instead — the registry entry knows only this pure module, and
* the server-only service registers itself when it is imported (which every server path that needs
* live models already does).
*
* With no source registered the getter yields `[]`, which is exactly what the live catalog
* returned before it had polled — so the client keeps seeing the provider without its models,
* unchanged.
*/
export interface DynamicImageModelEntry {
id: string;
name: string;
inputModalities: string[];
}
type DynamicImageModelSource = () => DynamicImageModelEntry[];
const sources = new Map<string, DynamicImageModelSource>();
/** Called by a server-only catalog service at import time. Last registration wins. */
export function registerDynamicImageModelSource(
providerId: string,
source: DynamicImageModelSource
): void {
sources.set(providerId, source);
}
/** Models discovered for `providerId`, or `[]` when no server-side source is loaded. */
export function getDynamicImageModels(providerId: string): DynamicImageModelEntry[] {
const source = sources.get(providerId);
if (!source) return [];
return source();
}
/** Test seam — drops every registration. */
export function resetDynamicImageModelSources(): void {
sources.clear();
}