mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 02:42:24 +03:00
Adds opt-in modelVisibilityAllowlist/modelVisibilityDenylist settings so an operator can curate exactly which models GET /v1/models advertises, mirrored into auto/* combo candidate pools (the same trap #6512 fixed for hidePaidModels). Default off, no behavior change for anyone who doesn't opt in. TDD: 4 new test files, 22/22 passing (16 node:test + 6 vitest) + regression sweep across virtual-auto-combo/hide-paid/hide-auto-no-think suites (21/21). Rebased onto the updated tip (a sibling #9133 landed first, same file) — kept both rebaseline annotations in file-size-baseline.json and set the value to the real measured line count after both merged.
67 lines
3.7 KiB
Markdown
67 lines
3.7 KiB
Markdown
---
|
|
title: "Model Exposure Allow/Deny List"
|
|
version: 3.8.51
|
|
lastUpdated: 2026-08-29
|
|
---
|
|
|
|
# Model Exposure Allow/Deny List
|
|
|
|
> Opt-in, off by default (`modelVisibilityAllowlist`/`modelVisibilityDenylist` both empty leaves
|
|
> the `/v1/models` catalog AND every `auto/*` candidate pool byte-identical). A sibling of
|
|
> `hidePaidModels`/`hideAutoCombos` (`src/lib/db/settings.ts`) for operators who want a curated
|
|
> model list for reasons that have nothing to do with cost.
|
|
|
|
## Why this exists
|
|
|
|
`hidePaidModels` answers "is this model free?" and `hideAutoCombos` answers "should `auto/*`
|
|
virtual ids be advertised at all?" — neither lets an operator curate an arbitrary subset of
|
|
models (e.g. presenting exactly the models a given Claude Code / OpenCode client should see,
|
|
independent of pricing). #11481 adds that as two independent, opt-in string-array settings.
|
|
|
|
## Settings
|
|
|
|
| Key | Type | Default | Meaning |
|
|
| ----------------------------- | ---------- | ------- | ----------------------------------------------------------------- |
|
|
| `modelVisibilityDenylist` | `string[]` | `[]` | Entries matching a candidate hide it from the catalog/candidate pool. |
|
|
| `modelVisibilityAllowlist` | `string[]` | `[]` | When non-empty, ONLY entries matching a candidate stay exposed. |
|
|
|
|
Both accept up to 500 entries of up to 200 characters each (Zod-validated in
|
|
`src/shared/validation/settingsSchemas.ts`). An entry is either:
|
|
|
|
- an exact catalog id — `"gpt-4o"` (bare model id) or `"openai/gpt-4o"` (provider-prefixed), or
|
|
- a glob pattern using `*`/`?` — e.g. `"openai/gpt-4*"` or `"anthropic/*"` — resolved via the
|
|
same shared `globToRegex()` matcher (`src/shared/utils/globPattern.ts`) already used by
|
|
`ModelRoutingSection`'s per-model combo mappings and `freeModels.ts::matchesOnlyPaidModels`.
|
|
|
|
Precedence: the denylist is checked first (a denied entry is always hidden, even if it also
|
|
matches the allowlist); when the allowlist is non-empty, only entries it matches survive.
|
|
|
|
## Two chokepoints, not one
|
|
|
|
The lesson from #6512 (a `hidePaidModels`-only catalog filter still let `auto/*` route to a
|
|
paid model, since the combo candidate pool was built independently) applies identically here.
|
|
The matching predicate `isModelExposureAllowed()` (`src/shared/utils/modelExposureList.ts`) is
|
|
called from BOTH:
|
|
|
|
- `src/app/api/v1/models/catalog.ts` — the `/v1/models` listing itself, at the same 5 per-source
|
|
chokepoints `shouldHidePaid()` already gates (static `PROVIDER_MODELS`, synced provider rows,
|
|
custom rows, alias-backed rows, managed-fallback rows).
|
|
- `open-sse/services/autoCombo/modelExposureFilter.ts::filterModelExposureCandidates()` — called
|
|
from `virtualFactory.ts::buildPreparedPool`, immediately after the equivalent
|
|
`filterPaidOnlyCandidates()` call, so a denied model can never be selected into an `auto/*`
|
|
candidate pool either.
|
|
|
|
## What is NOT filtered
|
|
|
|
Mirrors `hideAutoCombos`'s existing behaviour: a model id sent **explicitly** (not via `auto/*`,
|
|
and not discovered through the catalog listing) is never blocked at dispatch — only
|
|
advertisement/candidate-pool membership is filtered. This is independent of `hidePaidModels`;
|
|
an operator may want a curated set for reasons that have nothing to do with cost, so both
|
|
settings compose as independent AND-ed filters, same as the existing multi-flag composition in
|
|
`catalog.ts`.
|
|
|
|
Settings export (`GET /api/settings/export-json`) includes both arrays verbatim, like any other
|
|
settings field — unlike `hidePaidModels`'s combo-step export filter, there is no re-hydration
|
|
risk here: a denied id embedded in an exported combo step is the operator's own explicit routing
|
|
choice, not something the export boundary needs to strip.
|