Skip to content

feat(proxy): discover metadata and reload selected model offerings - #45023

Open
tudstudent wants to merge 41 commits into
BerriAI:mainfrom
tudstudent:gateway-model-metadata
Open

tudstudent wants to merge 41 commits into
BerriAI:mainfrom
tudstudent:gateway-model-metadata

Conversation

@tudstudent

@tudstudent tudstudent commented Oct 7, 2026 •

Copy link
Copy Markdown

The gateway publishes selected, authorized models with discovered limits and reasoning options, including supplier-pinned offerings. This update merges current upstream and reuses native implementations without adding a new test suite. Supplier metadata continues to refresh while intentional operator overrides remain available

Details

TLDR

Problem this solves:

  • Discovery omits independent limits and exact reasoning controls
  • Selected offerings disappear from wildcard-authorized client catalogs
  • Supplier availability and routing policy drift from operator intent

How it solves it:

  • Extend native ModelInfo, provider resolution and existing listing paths
  • Intersect consumer wildcard grants with selected public Router names
  • Compile private typed endpoint policies into native deployments
  • Preserve atomic offering reloads and reasoning-aware request budgets
  • Discover pinned endpoint bounds and compatible model reasoning controls

Intentional product change: external-offering mode makes the operator file authoritative. Runtime model-definition mutations, native batches, batch-purpose uploads and caller deployment selectors are rejected in this mode. Pinned policies disable response-cache reads and writes and reject caller tier selectors that would alter endpoint eligibility. Accepted OpenRouter effort values avoid the old unconditional provider rename. Unsupported/default/drop behavior follows native deployment policy. Existing key/team/customer permissions remain authoritative

User Flow

Before: a user with matching wildcard permissions can miss an enabled offering

  1. Configure the application with the gateway URL and scoped key
  2. Send GET https://gateway.example/v1/models after an offering is enabled
  3. Observe a missing alias, or missing effort choices on a pinned alias
  4. The application cannot select an effort absent from its catalog
  5. Another user with exact grants still cannot discover that offering

After: the same user discovers selected offerings within existing permissions

  1. Configure the application with the same gateway URL and scoped key
  2. Send GET https://gateway.example/v1/models after an offering is enabled
  3. Observe the permitted alias, endpoint-safe limits and known reasoning choices/default
  4. Select an advertised effort, or omit it to retain the supplier default
  5. Another user with exact grants still cannot discover that offering

Native Integration

Source-backed walkthrough, examples and implementation limits are documented in the architecture guide. The guide now distinguishes the latest native reasoning policy from offering metadata and budget defaulting

Canonical reasoning choices/defaults, tool and parallel-tool capabilities, modalities, endpoints, independent token limits and typed request budgets extend native model types and lookup. Unknown metadata is omitted. Caller budgets take precedence and never become physical model maxima

Supplier cards extend the native metadata facet and existing HTTP/cache machinery. Inventory uses native provider-base resolution, preserving explicit/environment/default precedence and avoiding ambient discovery credentials. The obsolete metadata module and fork-only compatibility wrappers are deleted

AUTO/MANUAL configuration supplies operator selection to native Router snapshots. Successful inventories control AUTO availability; MANUAL entries remain handwritten. Invalid edits preserve the last valid generation. Credential/account changes invalidate inventories, and in-flight requests retain their pinned generation

Private OpenRouter policies reside on native deployments rather than parallel snapshot maps. Exact only lists and allow_fallbacks: false compile into existing request shaping. Ingress/deployment guards reject connection, routing, parameter-dropping, fallback and policy overrides, and isolate caches. Chat, Responses, Responses-to-chat and Messages retain streaming/nonstreaming behavior. No provider ranking or pricing policy is added

Pinned AUTO offerings now fetch bounded, credential-scoped endpoint metadata only for selected models. They combine conservative eligible-endpoint bounds and capabilities with OpenRouter's model-level reasoning contract when those endpoints support effort selection. Unknown independent input remains omitted. Explicit fields win individually, MANUAL stays handwritten and unpinned discovery keeps its established model-level meaning. Last-known endpoint metadata survives refresh failure only for the same credential/base identity. The common metadata aggregation now lives with native types and is reused by public listing

Explicit null reasoning enums use the documented gateway effort set; omission, empty choices, mandatory reasoning and disabled defaults retain distinct semantics. Accepted declared OpenRouter max and xhigh survive request shaping rather than the old provider rename. Native deployment policy owns unsupported-value rounding/default/drop behavior. Provider-policy bodies remain unchanged, with no added fallback or require_parameters setting

Metadata Authority And Overrides

The external offering file is authoritative for model selection, connection and routing policy; it does not require model capabilities to be handwritten. Automatic supplier metadata is the normal path, not an opt-in exception.

  • AUTO, unpinned: downloaded supplier metadata overrides corresponding provider-appropriate bundled fallback fields. OpenRouter's unpinned catalog describes its model-level contract, not necessarily the endpoint serving a future request.
  • AUTO, pinned: routing policy selects the eligible endpoints, and their advertised limits/capabilities feed discovery automatically. Applicable model-level reasoning choices/defaults are combined with endpoint control support. Pinning does not turn an AUTO offering into a MANUAL definition, and unrestricted aggregate or bundled limits do not substitute for unknown pinned-endpoint bounds.
  • Explicit overrides: optional, per-field exceptions for an intentional operator policy or a verified missing value. Do not copy supplier-advertised values into configuration merely to enable a model; doing so unnecessarily freezes those fields against later discovery updates.
  • MANUAL: deliberately maintained metadata independent of inventory membership, for cases where automatic discovery is unavailable or unsuitable. A manual offering may still use an existing generic provider adapter; it does not inherently require custom provider code.
  • Request defaults: requested output budgets are separate from physical capability limits. An explicit caller budget takes precedence over the configured default-budget policy.

For example, if the sole eligible endpoint advertises a 300,000-token context and 30,000-token output ceiling, an AUTO offering without explicit overrides advertises those values and follows subsequent supplier changes on refresh. An unknown independent input limit remains omitted. Client applications consume the resolved gateway catalog rather than maintaining supplier-specific model exceptions.

Pre-Submission checklist

  • Meaningful mapped regression tests added
  • Affected mapped test files pass locally
  • Required remote CI and coverage pass on this tip
  • Scope remains selected-offering metadata, serving and authorization
  • Current-tip automated reviews complete and findings addressed

Local Validation

The source integration at 23ae9fbe177a21abc2b368f5e91df56516b42492 merges upstream dddbaa803d6e9fcc862ea7a5412f771cb1ae040e with history preserved

The native overlap audit reuses upstream deployment reasoning resolution and deployment-pricing/base-model lookup. The redundant fork key lookup is removed. Offering selection, pinned endpoint inventory/guarantees, request-budget policy and serving-generation guards remain because upstream has no equivalent implementation. New native secret-reference, timeout/admission and shared-capability registration behavior is retained. The registration boundary emits JSON-format arrays so existing native routing consumers accept the frozen metadata facet

The existing-test selection passes 2,811 cases across 30 mapped/native files. No new test case, matrix or test file is authored for this sync. Six private-helper cases are replaced by existing native functional coverage, and duplicate independent-limit lookup coverage is consolidated without its deleted upstream schema fixture, retaining the max_tokens assertion. The upstream merge's test additions are inherited, not a new fork test suite

Canonical BASE_REF=upstream/main make check passes source/test lint, formatting, unchanged rule/type/quality ceilings, imports, e2e typing, dashboard budgets and regenerated API-schema synchronization. Shard/slice/census checks pass for 617 children and 3,925 test files. No threshold, type cap, test selection or coverage guard is weakened

The architecture guide explains accepted versus unsupported effort behavior and the budget selector's limits. The sync adds no custom compactor, history store, client change or model-family workaround. These are offline/in-process results, not interactive client or real supplier inference proof. No live configuration, image or deployment is changed

CI Remediation

Current head is 3f78bfabd79073673c74c9b26cd1b89e26c1c9b4. Seven files change by +35/-17, with no runtime or documentation changes and no new test cases or files

Filelock is bounded below 3.20.4 in both distribution manifests and resolves to 3.20.3, before the vulnerable soft-lock and SQLite reader/writer features were introduced. This preserves Python 3.10 support. The extension overrides its packaging dependency to patched MSAL Node 7.1.1. Only the full-history DB shard gets eight minutes for checkout instead of three, retaining its history, credentials policy and 60-minute job budget

The unchanged OSV scanner and configuration report no unfiltered vulnerabilities locally. Python 3.10 runtime resolution, the extension's 53 tests, typechecking and packaging, five focused lock-user cases, 15 aggregate-gate cases, 17 telemetry preset cases and the core manifest case pass. Existing workflow startup and job-name checks pass. The canonical pre-commit entry passes test-tree Ruff and the unchanged test-quality gate against upstream/main

Two existing telemetry tests now scope their HTTP mock to the exporter session. The previous process-wide mock recorded unrelated background exports, causing a third request without AgentOps authorization in the assertion history. An in-process reproduction records that extra request before the change and exactly the two authenticated requests afterward. The JWT-fetch count, exact request count and authorization assertions remain unchanged

Remote Validation

Functional, dependency, lint and coverage checks completed on 3f78bfabd79073673c74c9b26cd1b89e26c1c9b4. Only the two policy/security checks described here remain red

OSV passes with no unfiltered vulnerabilities. DB/schema passes with 36 passed and 12 skipped. Root passes 7,054 cases, integrations passes 6,307, and the unchanged unit aggregate passes. Runtime resolution and core-distribution checks pass on every supported Python version from 3.10 through 3.14

The two remaining red checks are the unchanged fork dependency guard, which rejects every uv.lock edit from a fork, and CodeQL. Accepting the validated dependency fix through the canonical repository requires maintainer action. The fork guard is not bypassed

The current CodeQL check has exactly one annotation, at encrypt_decrypt_utils.py line 60. It classifies SHA256 as password hashing, while this call computes a server-keyed, domain-separated connection-identity HMAC rather than a password verifier. Python, JavaScript and Actions analyses pass. This single classification still requires upstream security disposition. No query suppression or algorithm workaround is introduced

The upstream Greptile bot reports automatic reviews disabled. Earlier manual requests, including the prior runtime-head request, did not yield a current review. They do not cover this new sync. No duplicate ping, fork-only scan or integration/permission workaround is requested

Type

New Feature, Bug Fix, Refactoring, Test

Caveats

Severe

  • External mode intentionally rejects model mutations and native batches
  • Policy/connection edits change the affected deployment identity
  • Unsupported efforts follow native rounding/default/drop rules

Medium

  • Endpoint bounds are supplier-reported, not independently benchmarked
  • Explicit limits keep overriding discovery until removed
  • Native account policy windows are not proven physical maxima
  • Policies currently support OpenRouter chat offerings
  • Paid supplier and interactive client proof remain unperformed
  • Fresh Greptile review remains outstanding
  • CodeQL flags the keyed identity MAC; security triage required
  • Fork dependency updates require acceptance through the canonical repository

Low

  • Pinned policies disable response caching

Final Attestation

  • Tests cover metadata, permissions, reloads, malformed inputs and bypasses
  • Required remote checks and automated reviews complete

@CLAassistant

CLAassistant commented Oct 7, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[High risk] Adds model discovery and external offering configuration to the proxy.

The follow-up appears safe to merge, with no outstanding code finding

What we checked:

  • Test reads personal credentials: The test sets both auth-path variables. get_account_id returns the account from that file without requesting a token
  • Smaller builds skip tests: The settings change debug information and incremental compilation, not assertions. All existing test commands and feature combinations remain in the job

Summary

The PR adds optional model metadata, selected AUTO/MANUAL offerings, atomic reloads and reasoning-aware request budgets

  • The follow-up replaces the account-lookup class patch with an isolated auth file. Real Authenticator.get_account_id reads the fixture account without network access or device login
  • The Rust test job disables debug information and incremental builds. Its test commands, feature combinations and assertions remain unchanged
  • The five supplied previous threads are addressed in current code. None has a supplied comment number
  • No new actionable issue or mounted-rule violation was found. Tests and the full local gate were not rerun during this review

Reviews (3) · Last reviewed commit: "ci(rust): bound feature-matrix build art..." · Reviewed by Greptile

Comment thread litellm/router.py Resolved
Comment thread litellm/router.py Resolved
Comment thread litellm/proxy/model_offerings.py Resolved
Comment thread litellm/proxy/model_offerings.py Fixed
Comment thread litellm/proxy/offering_router.py Fixed
Comment thread litellm/proxy/offering_router.py Fixed
Comment thread litellm/proxy/offering_router.py Resolved
@veria-ai

veria-ai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 5 · PR risk: 0/10

@codspeed

codspeed Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 35 untouched benchmarks


Comparing tudstudent:gateway-model-metadata (3f78bfa) with main (72f1ac4)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (dddbaa8) during the generation of this report, so 72f1ac4 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.42657% with 18 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/proxy/model_offerings.py 93.71% 12 Missing ⚠️
litellm/proxy/offering_router.py 97.41% 4 Missing ⚠️
litellm/router_utils/model_request_defaults.py 97.50% 1 Missing ⚠️
litellm/types/router.py 99.23% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

key: Final = (
configured_key.encode() if isinstance(configured_key, str) and configured_key else _MODEL_OFFERING_PROCESS_KEY
)
return hmac.new(key, b"litellm:model-offering-identity:v1\0" + value, hashlib.sha256).hexdigest()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This operation derives an opaque, purpose-separated connection identity using HMAC-SHA256 and the existing private server salt/master-key source. It is not password storage, a password verifier, or authentication. Public deployment IDs do not let an observer test credential guesses without the server key; the earlier unkeyed credential fingerprint was replaced for precisely that reason. test_model_offering_identity_uses_server_key_and_not_a_public_credential_hash and credential/account rotation regressions pass. Real HTTP checks also verify stable identities across separate processes with the same configured key. Unconfigured standalone mode uses a private process key and documents its restart-stability limitation. We believe the password-hashing classification does not match this use, but have not suppressed the alert. Leaving it open for maintainer/security assessment; please advise if a different identity design is preferred.

Comment thread litellm/proxy/offering_router.py Fixed
@tudstudent

Copy link
Copy Markdown
Author

Current head: a7e747c946. All runs have finished: 110 checks pass, eight are skipped, and CodeQL is the only failing check. Veria confirms both reported security issues are addressed.

The follow-up revisions address the review findings and the CI quality failures. The current revision uses the native cached HTTP-client factory and reacquires the inventory client for each refresh, so cache eviction cannot leave polling attached to a closed handler. Tests cover startup, invalid configuration, shutdown and actual cache eviction/reacquisition.

Local validation passed the full make check, all 37 primary code-quality workflow commands and 88 affected lifecycle/inventory tests. The preceding security/snapshot revision passed 659 regressions; these counts overlap and are not summed. Fake-credential loopback HTTP checks confirm that extra_body.model is rejected with HTTP 400 before forwarding, while ordinary requests and harmless extra parameters succeed. No production supplier calls were needed for these checks.

Two CodeQL classifications need maintainer assessment:

  1. HMAC classification: the HMAC uses the existing private server salt/master-key source to derive a purpose-separated connection identity. It is not password storage or password verification. Unlike the earlier unkeyed fingerprint, a public deployment ID cannot be used to test credential guesses without the server key. Configured-key identities are stable across restarts and change when the credential/account changes.
  2. Router-delegation classification: OfferingRouterView deliberately delegates native router members to an already initialized Router, including request-pinned snapshots. Calling the base constructor again would allocate unused resources and register duplicate callbacks. The regression tests exercise routing, authorization, reload isolation and the actual encrypted-content affinity callback.

We have not suppressed either alert or added an artificial constructor call. Please assess whether these are acceptable intentional uses or whether you prefer a different design. The PR description documents the exact validation scope and limitations. CodeQL is still red; passing functional and quality checks do not constitute CodeQL approval.

Greptile's visible 3/5 summary still refers to e13aa93e01, before the corrective revisions. The fixes for structured reasoning objects, encrypted-history lookup, shared deployment names and supplier layering are included and covered by regressions. Please reassess the current head rather than treating that older summary as a review of this revision.

@tudstudent
tudstudent force-pushed the gateway-model-metadata branch from a7e747c to f7178be Compare October 7, 2026 11:32
Comment thread litellm/proxy/model_offerings.py Resolved
Comment thread litellm/proxy/offering_router.py Resolved
Comment thread tests/unit/llms/test_model_inventory.py Resolved
@tudstudent
tudstudent requested a review from a team October 8, 2026 12:29
Comment thread litellm/proxy/offering_router.py Resolved
@greptile-apps

greptile-apps Bot commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Automatic reviews are disabled for this repository.

haydster7 and others added 8 commits October 15, 2026 13:21
…ing metadata (BerriAI#41041)

* fix(proxy): resolve model aliases to their target deployment for listing metadata

A model alias (a key's `aliases`, a team's `model_aliases`, or the router's
`model_group_alias`) is rewritten at request time and owns no deployment row,
so `get_model_listing_info` returns None for it and the alias name is not a
cost-map key either. Both metadata candidate sources come up empty and the
listing entry carries no `mode`, `max_input_tokens`, or `max_output_tokens`,
while the deployment it routes to reports them on the same response.

Resolve a listed alias to the deployment it routes to for the metadata lookup,
keeping the alias as the response id. Maps are applied in order, each against
the result of the last, mirroring how `litellm_pre_call_utils` applies the team
map and then the key map, so a chained alias reports the deployment the caller
actually reaches rather than an intermediate one. An alias shadowing a
same-named deployment follows the alias, because the request rewrite does too.

Fixes the model_aliases half of BerriAI#40553.

* fix(proxy): look listed aliases up through the shared alias chain

Drop the separate alias resolver and retarget a listed alias in
alias_listing_entries and alias_target instead, so /v1/models and
/v1/models/{id} report the model /chat/completions rewrites it to, and
only when the caller can list that model

* fix(proxy): keep deployed listed models' own rows and resolve team alias targets at list and retrieval

* fix(proxy): resolve router_settings aliases, keep alias labels, and skip paused targets in model listing

* fix(proxy): leave an alias to an undiscoverable model bare in model listing

A team alias whose target has discoverable: false showed the hidden model's mode and limits on GET /v1/models and retrieved it by alias. Undiscoverable groups now count as hidden for alias resolution, as on main, while admins still see them.

* fix(proxy): leave an alias to a model a listing callback hides bare in model listing

* fix(proxy): keep aliases bare for models a listing callback never judged or another team owns

---------

Co-authored-by: haydster7 <[email protected]>
Co-authored-by: mateo-berri <[email protected]>

This branch has not been deployed

No deployments
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.

4 participants