Files
OmniRoute/docs/reference
Sean Ford 010250cf08 fix(memory): list provider-node models in the Embedding and Rerank selectors (#13740)
* fix(api): type compatible-provider-node models in /v1/models by the node's apiType

Model rows discovered from an OpenAI-compatible provider node rarely carry
endpoint metadata — a TEI / Infinity / vLLM `/v1/models` listing is just ids —
and the catalog defaulted such rows to `["chat"]`. An `embeddings`-typed node
exposing `bge-m3` and a `rerank`-typed node exposing `bge-reranker-v2-m3`
therefore both surfaced in GET /v1/models as untyped chat models: clients
that build their picker from `type: "embedding"` / `type: "rerank"` never saw
them, and chat pickers listed models that 400 on chat.

- src/shared/constants/modelSupportedEndpoints.ts: add
  defaultEndpointsForProviderNodeApiType(apiType) — embeddings → ["embeddings"],
  rerank → ["rerank"], audio-* → themselves, images-generations → ["images"],
  chat/responses/unknown → ["chat"] (unchanged default).
- src/app/api/v1/models/catalog.ts: build a node-id → apiType map next to the
  existing node-id → type map; the synced-model and custom-model loops fall
  back to the node's modality instead of ["chat"] when a row has no
  supportedEndpoints; the custom-overlay merge path also classifies
  `type`/`subtype` from the overlay's explicit supportedEndpoints, so a manual
  `["rerank"]` row layered on a discovered chat-default row is re-typed.

Explicit supportedEndpoints on any row still take precedence, and chat /
responses nodes keep the historical behavior.

tests/unit/catalog-provider-node-apitype-endpoints.test.ts covers the helper
and the catalog end-to-end for embeddings, rerank, mixed, chat, and overlay
cases via getUnifiedModelsResponse().

* chore(changelog): name the #13734 fragment

* refactor(api): keep the provider-node modality helpers out of catalog.ts

catalog.ts is frozen by the file-size gate (must not grow past 2075
lines) and the apiType fallback pushed it to 2093. Move the node
apiType index, the endpoint fallback and the overlay type/subtype
fields into catalogNodeModality.ts so catalog.ts ends one line
shorter than the base; behaviour and tests are unchanged.

* fix(api): give nodeModelEndpoints a string[] return so the catalog classifier typechecks

The API-route typecheck gate flagged TS2345 at both classifyModelSupportedEndpoints()
call sites: the helper returned `ModelSupportedEndpoint[] | unknown[]`, and unknown[]
is not a readonly string[]. The base code only passed because the synced row's
supportedEndpoints was untyped. Same pass-through cast overlayEndpoints() already uses;
no behaviour change.

* fix(memory): list provider-node models in the embedding and rerank selectors

GET /api/memory/embedding-providers and GET /api/memory/rerank-providers
appended local provider nodes by apiType alone and always with models: [].
A node typed "embeddings" that also serves a rerank model — one TEI /
Infinity / vLLM box hosting both bge-m3 and bge-reranker-v2-m3 is the
common self-hosted layout — was filtered out of the Rerank selector
entirely (apiType not in chat/responses/rerank) and showed up in the
Embedding selector as a provider with nothing to pick. Typing prefix/model
by hand worked because the request path resolves it directly; only the
convenience layer was blind.

Add src/lib/memory/embedding/nodeModalityListings.ts, which builds the
listing from the node's synced + custom model rows, typing each row the way
/v1/models does (explicit supportedEndpoints wins, otherwise the node's
apiType via defaultEndpointsForProviderNodeApiType; a custom overlay
re-types a discovered row). A node is listed for a modality when its
apiType matches, when it is a generic chat/responses node (historical
behaviour, kept so catalog-less nodes still appear), or when any of its
rows is typed for the modality. Both endpoints use it; the curated
registries stay first and win on prefix collisions.

* chore(changelog): name the #13740 fragment
2026-09-18 11:32:26 -03:00
..
2026-07-13 09:12:40 -03:00