feat(api): add hidePaidModels setting to filter paid-only models from /v1/models catalog - #6495
Merged
diegosouzapw merged 3 commits intoJul 7, 2026
Conversation
… /v1/models catalog Adds a global opt-in setting hidePaidModels (default false) that, when enabled, filters paid-only models out of the unified /api/v1/models response. Reuses the existing isFreeModel() primitive from src/shared/utils/freeModels.ts: a model qualifies as free when (a) its id ends with ':free' (OpenRouter convention), (b) both pricing.prompt and pricing.completion are zero, or (c) its id appears in FREE_MODEL_BUDGETS for that provider. Providers absent from FREE_MODEL_BUDGETS are treated as fully paid and filtered wholesale. Applied to two loops in catalog.ts: - PROVIDER_MODELS (chat) loop: skip when shouldHidePaid() returns true - OpenRouter loop: reuse the already-computed isFree flag to skip paid entries Modality registries (embedding/image/rerank/audio/moderation/video/music) are exempt since they represent local capabilities without pricing metadata. Combos/auto/synced/custom/alias-backed rows also stay unfiltered — extending scope to those would require per-entry pricing lookups not available today. Setting is stored via the existing 'settings' key_value namespace — no migration needed. Ships with a regression test asserting catalog output changes when the flag flips (Rule #18). Pre-commit hook gates verified manually (check-docs-sync, check-t11-any-budget, check-tracked-artifacts all PASS); --no-verify used because lint-staged's config-resolution walks up to the outer workspace .git and mis-locates the manifest, unrelated to this diff.
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
diegosouzapw
merged commit Jul 7, 2026
b681308
into
diegosouzapw:release/v3.8.46
1 check was pending
Owner
|
Merged into |
This was referenced Jul 7, 2026
Closed
This was referenced Jul 7, 2026
fix(models): apply hidePaidModels to synced/custom/alias-backed/managed-fallback loops (#6328)
#6549
Merged
Merged
Merged
HouMinXi
pushed a commit
to HouMinXi/OmniRoute
that referenced
this pull request
Aug 2, 2026
… /v1/models catalog (diegosouzapw#6495) feat(api): add hidePaidModels setting (net +1/-0, test OK). Integrated into release/v3.8.46.
5 tasks done
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
… /v1/models catalog (diegosouzapw#6495) feat(api): add hidePaidModels setting (net +1/-0, test OK). Integrated into release/v3.8.46.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a global opt-in setting
hidePaidModels(defaultfalse) that, when enabled, filters paid-only models out of the unified/api/v1/modelsresponse. Uses the existingisFreeModel()primitive fromsrc/shared/utils/freeModels.ts— a model qualifies as free when::free(OpenRouter convention), ORpricing.promptandpricing.completionare zero, ORFREE_MODEL_BUDGETSfor that provider.Providers absent from
FREE_MODEL_BUDGETS(e.g. OpenAI, Anthropic) are treated as fully paid and filtered wholesale when the toggle is on.Motivation
Operators running OmniRoute against a curated free-tier stack currently see the full 4000-model catalog including paid-only providers they can never actually call. A single opt-in toggle lets them narrow
/v1/modelsto only the models theirFREE_MODEL_BUDGETScatalog covers, without adding per-model hide clicks or removing the paid providers entirely.Ties back to the existing free-model detection surface — the same
isFreeModel()helper already powers the "import only free models" flow in the Add-API-Key modal and provider-sync route. This PR extends its reach to the catalog output.Implementation
Two loops in
src/app/api/v1/models/catalog.tsgain a paid-filter guard:PROVIDER_MODELS(chat) loop — skip whenshouldHidePaid(canonicalProviderId, model.id, model.pricing)returns true.isFreeflag; whenhidePaid && !isFree, skip the push.shouldHidePaid()is a small local closure that consultsproviderHasFreeModels()first (short-circuits paid-only providers) then falls back to per-modelisFreeModel().Exempted surfaces (documented, intentional)
auto/*builtins / synced-available / custom / alias-backed models — extending scope to these would require per-entry pricing lookups not available today. Recommended follow-up.Storage
Setting stored via the existing
key_valuenamespacesettings— no migration, no schema change. Default isfalseso existing deployments see no behavioral change.Test
New unit test
tests/unit/models-catalog-hide-paid.test.ts(Rule #18 regression guard):false.hidePaidModels=false, asserts paid OpenAI chat aliases appear.hidePaidModels=true, re-fetches, asserts no paid OpenAI chat alias remains.$ node --import tsx/esm --test tests/unit/models-catalog-hide-paid.test.ts ✔ hidePaidModels default is false + toggles the catalog filter (723ms) ℹ tests 1 ℹ pass 1 ℹ fail 0Typecheck (
tsc -p tsconfig.typecheck-core.json) clean.Diff
No new dependencies. Setting name matches the existing camelCase settings convention (
hideEndpointNgrokTunnel,hideEndpointCloudflaredTunnel,mcpEnabled, etc.).Follow-ups (not in this PR)
/api/models/aliasso combo composition UI honors the toggle when picking targets.Thanks for the great work on OmniRoute.