Skip to content

feat: support OpenRouter models and multi-provider pricing entries#1089

Open
JoseArroyave wants to merge 5 commits intomnfst:mainfrom
JoseArroyave:feat/openrouter-models
Open

feat: support OpenRouter models and multi-provider pricing entries#1089
JoseArroyave wants to merge 5 commits intomnfst:mainfrom
JoseArroyave:feat/openrouter-models

Conversation

@JoseArroyave
Copy link
Copy Markdown

@JoseArroyave JoseArroyave commented Mar 12, 2026

Fix: Support OpenRouter models and multi-provider pricing entries

Fixes #1088

Support multi-provider models in the pricing sync and fix cache key collisions.

This change resolves an issue where models retrieved from the OpenRouter API were not correctly exposed in Local Mode because:

  • models were stored only under their vendor provider (e.g. OpenAI, Anthropic)
  • the pricing cache assumed model_name was unique and overwrote entries from different providers

This update enables proper multi-provider support so the same model can exist for both its vendor and OpenRouter without being overwritten in the cache.


Changes

1. Multi-provider support in model_pricing

The model_pricing table now uses a composite primary key:

(model_name, provider)

This allows the same model to exist for multiple providers.

Example:

## model_name | provider

gpt-4.1    | OpenAI
gpt-4.1    | OpenRouter

This is required because OpenRouter acts as an aggregator that exposes models from multiple vendors.


2. Store OpenRouter models explicitly

During the pricing sync (syncAllModels), models retrieved from OpenRouter are now stored for both providers:

  • the original vendor (e.g. OpenAI, Anthropic, etc.)
  • OpenRouter

This ensures that provider filtering works correctly when OpenRouter is configured as the active provider.


3. Fix cache key collision in pricingCache

The pricing cache previously used model_name as the cache key:

this.cache.set(row.model_name, row)

This caused entries from different providers to overwrite each other.

The cache now uses a composite key:

`${model_name}:${provider}`

This ensures each provider entry is cached independently.


4. Update quality score updates

Quality score updates now correctly target a specific provider entry:

update({ model_name, provider }, { quality_score })

instead of updating all rows with the same model name.


Result

After these changes:

  • OpenRouter models are properly stored and exposed.
  • Multiple providers per model are fully supported.
  • The pricing cache no longer overwrites entries.
  • Provider filtering works correctly in Local Mode.

Compatibility

These changes do not affect existing routing logic and remain backward-compatible with existing vendor providers.


Summary by cubic

Adds multi-provider model pricing with explicit OpenRouter entries so models show correctly in Local Mode. Improves cache keys and alias resolution to prevent provider collisions.

  • New Features

    • Composite key (model_name, provider) in model_pricing to support the same model across providers.
    • Pricing sync upserts both the vendor entry and an OpenRouter entry in one pass, without relying on openrouter/ ID prefixes.
  • Bug Fixes

    • Pricing cache keys include provider, with improved alias resolution to return the correct entry.
    • Quality score updates target (model_name, provider) rows only.

Written for commit a08ba6b. Summary will update on new commits.

@JoseArroyave JoseArroyave changed the title feat: support OpenRouter models and multi-provider pricing entries #1088 feat: support OpenRouter models and multi-provider pricing entries Mar 12, 2026
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/backend/src/database/pricing-sync.service.ts">

<violation number="1" location="packages/backend/src/database/pricing-sync.service.ts:163">
P2: Deduplicate provider targets before syncing. For `openrouter/*` models, `[provider, 'OpenRouter']` produces duplicate `OpenRouter` writes and duplicate history/update counts.</violation>
</file>

<file name="packages/backend/src/model-prices/model-pricing-cache.service.ts">

<violation number="1" location="packages/backend/src/model-prices/model-pricing-cache.service.ts:48">
P1: The cache now uses `${model_name}:${provider}` keys, but getByModel still looks up by raw model name/alias. This means existing callers like `getByModel('gpt-4o')` will always miss and return undefined unless they supply the composite key. Update getByModel (and its callers) to use the composite key or maintain a secondary index keyed by model name.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread packages/backend/src/model-prices/model-pricing-cache.service.ts
Comment thread packages/backend/src/database/pricing-sync.service.ts Outdated
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.01%. Comparing base (7fdd976) to head (a08ba6b).
⚠️ Report is 10 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1089      +/-   ##
==========================================
- Coverage   99.01%   99.01%   -0.01%     
==========================================
  Files         223      223              
  Lines       11584    11564      -20     
  Branches     3652     3640      -12     
==========================================
- Hits        11470    11450      -20     
- Misses         22       24       +2     
+ Partials       92       90       -2     
Flag Coverage Δ
backend 98.52% <100.00%> (-0.01%) ⬇️
frontend 99.84% <ø> (ø)
plugin 95.73% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

Missing OpenRouter models in Local Mode

1 participant