Skip to content

feat(providers): curated OpenRouter embeddings catalog + specialty merge in live discovery (#6976) - #6994

Merged
diegosouzapw merged 5 commits into
release/v3.8.49from
feat/6976-openrouter-embeddings-catalog
Jul 17, 2026
Merged

diegosouzapw merged 5 commits into
release/v3.8.49from
feat/6976-openrouter-embeddings-catalog

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Closes #6976

Root cause

OpenRouter serves embeddings via a dedicated OpenAI-compatible /api/v1/embeddings endpoint (omitted from /v1/models). open-sse/config/embeddingRegistry.ts already had an openrouter entry, but it was stale (3 legacy ids) and effectively dead code for discovery: providerModelsConfig.ts gives openrouter a live discovery config, so the live-discovery success path in buildApiDiscoveryResponse (src/app/api/providers/[id]/models/route.ts) returned the live /v1/models chat catalog verbatim — the specialty (embeddings/rerank) static catalog was only ever merged in on the no-config local_catalog fallback, which OpenRouter never hits.

Fix

  1. Refreshed the curated openrouter embeddingRegistry lineup — ids verified against the API reference (https://openrouter.ai/docs/api/reference/embeddings) and the models collections page, not display names: openai/text-embedding-3-small/-large, qwen/qwen3-embedding-8b/-4b, baai/bge-m3, mistralai/mistral-embed-2312, google/gemini-embedding-001. Dropped the legacy openai/text-embedding-ada-002 entry rather than guess at its current availability.
  2. Added mergeSpecialtyCatalogIntoLiveModels() (discovery/helpers.ts) that folds embeddings/rerank entries from getStaticModelsForProvider() into a successful live-discovery response, additively and deduped by id. Scoped via an explicit allowlist (LIVE_DISCOVERY_SPECIALTY_MERGE_PROVIDERS, currently just openrouter) rather than applied to every provider with an embeddingRegistry/rerankRegistry entry — some providers (Gemini) already return embedding models directly inside their live /v1/models response, so a blanket merge broke an existing pagination test (gemini-embedding-2/gemini-embedding-001 duplicating what Gemini's own live response already returns). Updated one pre-existing OpenRouter test (provider-models-route.test.ts) whose exact-equality assertion encoded the old (buggy) behavior.

TDD evidence

New tests/unit/openrouter-embeddings-catalog-6976.test.ts:

  • RED (Step 2/merge reverted): live discovery merges curated embeddings into the response even when /v1/models returns none failed — AssertionError: curated embedding baai/bge-m3 should be merged into live discovery; got: anthropic/claude-sonnet-5.
  • GREEN (fix applied): all 4 new tests pass (registry lineup + dimensions, getStaticModelsForProvider fold, live-discovery merge, live-vs-curated dedup-by-id).

Gates run

  • npm run typecheck:core — clean
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json <changed files> — 0 errors (pre-existing no-explicit-any warnings only, all suppressed)
  • node scripts/check/check-file-size.mjs — no new violations (3 pre-existing base-red files untouched)
  • node scripts/check/check-complexity.mjs / check-cognitive-complexity.mjs — both OK at baseline (2056 / 890, unchanged)
  • node scripts/check/check-changelog-integrity.mjs — OK
  • Full tests/unit/provider-models-route.test.ts (59 tests), provider-models-discovery-split.test.ts, provider-models-custom-merge-6247.test.ts, provider-models-route-codex.test.ts, provider-models-v1-route.test.ts, provider-scoped-models-route.test.ts, openrouter-registry.test.ts, rerank-openrouter-6574.test.ts — all green (regression sweep of the area)

Notes

  • Left nvidia/llama-nemotron-embed-vl-1b-v2 and perplexity/pplx-embed-v1-0.6b (both surfaced in the API reference/collections search) out of the curated list — less confident these fit the plain OpenAI-shaped embeddings request/response contract without further verification (multimodal / different input shape); flagging for a follow-up refresh rather than guessing.
  • google/gemini-embedding-2 (128–3072 flexible dims per the collections page) also left out — no single fixed dimension to record for the conflict guard, unlike gemini-embedding-001 (768, matching the existing gemini registry entry's convention in this file).

…rge in live discovery (#6976)

OpenRouter serves embeddings via a dedicated OpenAI-compatible
/api/v1/embeddings endpoint that is omitted from /v1/models, and the
embeddingRegistry entry for it was stale (3 legacy ids). Meanwhile
providerModelsConfig gives openrouter a live discovery config, so
buildApiDiscoveryResponse's success path returned only the live chat
catalog verbatim — the specialty (embeddings/rerank) static catalog was
only ever merged in on the no-config local_catalog fallback, so OpenRouter
embeddings never surfaced through model discovery.

Refreshed the curated openrouter embeddingRegistry lineup (ids verified
against https://openrouter.ai/docs/api/reference/embeddings and the
collections page) and added a scoped, additive merge
(mergeSpecialtyCatalogIntoLiveModels, allowlisted to openrouter) that folds
embeddings/rerank entries from getStaticModelsForProvider() into the live
discovery response, deduped by id. Scoped as an allowlist rather than a
blanket merge because some providers (e.g. Gemini) already return
embedding models directly from their live /v1/models endpoint, where a
blind merge would risk stale/duplicate entries.
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.47 to release/v3.8.48 July 13, 2026 05:04
@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.48 to release/v3.8.49 July 13, 2026 21:57
@diegosouzapw

Copy link
Copy Markdown
Owner Author

PR #6994 — aprovado. Probe TDD confirmou fail-without-fix no teste-chave do merge (revertendo route.ts/helpers.ts ele cai pra RED com a mensagem exata do bug original). Fui atrás dos IDs curados no OpenRouter (mistral-embed-2312, bge-m3, qwen3-embedding-4b/8b) — todos existem e batem com as dimensões documentadas. Único ponto de atenção (não bloqueante, não é regressão sua): google/gemini-embedding-001 fica registrado com dimensions: 768 mas o default real da API do Google pra esse modelo é 3072 — só que isso já é a convenção usada no entry nativo gemini no mesmo arquivo (linha 221), então você só espelhou um comportamento pré-existente. Vale um follow-up separado se quiser corrigir os dois de uma vez. Escopo do allowlist (só openrouter) bem justificado — evita duplicar embeddings no Gemini, que já retorna isso nativamente.

)

no-explicit-any is an error under tests/ (#6218), so the 4 `any`
usages in the new discovery assertions failed the max-warnings-0
lint gate. Replace them with an explicit ModelsResponseBody shape —
type-only change, all 13 assertions unchanged and still passing.
The new #6976 assertion added a 56th explicit `any` to this file,
one over the 55 frozen in config/quality/eslint-suppressions.json,
tripping the max-warnings-0 lint gate. Type the callback param
instead of raising the frozen count — the debt ratchet only decreases.
All 59 tests still pass.
@diegosouzapw

Copy link
Copy Markdown
Owner Author

Babysit summary

CI is green (13/13 SUCCESS, 2 NEUTRAL = Mergify skips). Not merged — handing off for human review & merge.

Fixes

# Commit Gate Rationale
1 6d0f8e23b Fast Quality Gates, Unit Tests (1–4/4), Vitest Merged release/v3.8.49 in. The branch was 57 commits behind; the stale base carried an orphan test (open-sse/translator/request/__tests__/openai-to-gemini.test.ts) already relocated on the release tip, which tripped check:test-discovery. The unit/Vitest reds were runner-infra SQLITE_FULL flakes, gone on re-run. Clean merge, no conflicts.
2 3ac194f76 No new ESLint warnings The new openrouter-embeddings-catalog-6976.test.ts used any 4×; no-explicit-any is an error under tests/ (#6218). Replaced with an explicit ModelsResponseBody type.
3 6b0379249 No new ESLint warnings The #6976 assertion added a 56th explicit any to provider-models-route.test.ts, one over the 55 frozen in config/quality/eslint-suppressions.json. Typed the callback param rather than raising the frozen count — the debt ratchet only decreases.

Guardrails honored

  • No assertion weakened or removed — assert counts unchanged (13 → 13 and 300 → 300); both suites still fully green (4/4 and 59/59).
  • No CI definition, ratchet baseline, or suppressions file edited. eslint-suppressions.json deliberately left at 55 — the violation was fixed at the cause.
  • Complexity/cognitive ratchets verified locally: complexity=2056 (baseline 2056), cognitiveComplexity=890 (baseline 890) — no regression.
  • Full local lint gate: 0 errors, 0 warnings.

Note on the base: release/v3.8.49's own CI is red on Quality Gates (Extended), Integration Tests (2/2), Package Artifact, Electron Package Smoke and Quality Ratchet. Those are pre-existing base-drift, unrelated to this PR, and are not in this PR's check set.

Ready for human review & merge.

@diegosouzapw
diegosouzapw merged commit b914eb1 into release/v3.8.49 Jul 17, 2026
15 checks passed
@diegosouzapw
diegosouzapw deleted the feat/6976-openrouter-embeddings-catalog branch July 19, 2026 21:00
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…rge in live discovery (diegosouzapw#6976) (diegosouzapw#6994)

* feat(providers): curated OpenRouter embeddings catalog + specialty merge in live discovery (diegosouzapw#6976)

OpenRouter serves embeddings via a dedicated OpenAI-compatible
/api/v1/embeddings endpoint that is omitted from /v1/models, and the
embeddingRegistry entry for it was stale (3 legacy ids). Meanwhile
providerModelsConfig gives openrouter a live discovery config, so
buildApiDiscoveryResponse's success path returned only the live chat
catalog verbatim — the specialty (embeddings/rerank) static catalog was
only ever merged in on the no-config local_catalog fallback, so OpenRouter
embeddings never surfaced through model discovery.

Refreshed the curated openrouter embeddingRegistry lineup (ids verified
against https://openrouter.ai/docs/api/reference/embeddings and the
collections page) and added a scoped, additive merge
(mergeSpecialtyCatalogIntoLiveModels, allowlisted to openrouter) that folds
embeddings/rerank entries from getStaticModelsForProvider() into the live
discovery response, deduped by id. Scoped as an allowlist rather than a
blanket merge because some providers (e.g. Gemini) already return
embedding models directly from their live /v1/models endpoint, where a
blind merge would risk stale/duplicate entries.

* test(providers): type the models discovery payload instead of any (diegosouzapw#6976)

no-explicit-any is an error under tests/ (diegosouzapw#6218), so the 4 `any`
usages in the new discovery assertions failed the max-warnings-0
lint gate. Replace them with an explicit ModelsResponseBody shape —
type-only change, all 13 assertions unchanged and still passing.

* test(providers): type the openrouter merge assertion callback (diegosouzapw#6976)

The new diegosouzapw#6976 assertion added a 56th explicit `any` to this file,
one over the 55 frozen in config/quality/eslint-suppressions.json,
tripping the max-warnings-0 lint gate. Type the callback param
instead of raising the frozen count — the debt ratchet only decreases.
All 59 tests still pass.
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…rge in live discovery (diegosouzapw#6976) (diegosouzapw#6994)

* feat(providers): curated OpenRouter embeddings catalog + specialty merge in live discovery (diegosouzapw#6976)

OpenRouter serves embeddings via a dedicated OpenAI-compatible
/api/v1/embeddings endpoint that is omitted from /v1/models, and the
embeddingRegistry entry for it was stale (3 legacy ids). Meanwhile
providerModelsConfig gives openrouter a live discovery config, so
buildApiDiscoveryResponse's success path returned only the live chat
catalog verbatim — the specialty (embeddings/rerank) static catalog was
only ever merged in on the no-config local_catalog fallback, so OpenRouter
embeddings never surfaced through model discovery.

Refreshed the curated openrouter embeddingRegistry lineup (ids verified
against https://openrouter.ai/docs/api/reference/embeddings and the
collections page) and added a scoped, additive merge
(mergeSpecialtyCatalogIntoLiveModels, allowlisted to openrouter) that folds
embeddings/rerank entries from getStaticModelsForProvider() into the live
discovery response, deduped by id. Scoped as an allowlist rather than a
blanket merge because some providers (e.g. Gemini) already return
embedding models directly from their live /v1/models endpoint, where a
blind merge would risk stale/duplicate entries.

* test(providers): type the models discovery payload instead of any (diegosouzapw#6976)

no-explicit-any is an error under tests/ (diegosouzapw#6218), so the 4 `any`
usages in the new discovery assertions failed the max-warnings-0
lint gate. Replace them with an explicit ModelsResponseBody shape —
type-only change, all 13 assertions unchanged and still passing.

* test(providers): type the openrouter merge assertion callback (diegosouzapw#6976)

The new diegosouzapw#6976 assertion added a 56th explicit `any` to this file,
one over the 55 frozen in config/quality/eslint-suppressions.json,
tripping the max-warnings-0 lint gate. Type the callback param
instead of raising the frozen count — the debt ratchet only decreases.
All 59 tests still pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(providers): OpenRouter embedding models not in list (curated catalog needed — upstream /v1/models has none)

1 participant