Repository navigation
feat: expose max_output in /v1/models - #3379
Conversation
Surface per-model output-token limits in the public catalogue: each provider entry carries its mapping's exact maxOutput, and the model level reports the minimum across mappings that declare one - the largest max_tokens guaranteed to be accepted regardless of which provider serves the request (requests are validated against the routed mapping's limit, so anything above it fails with HTTP 400). Consumers previously had no way to discover the cap; the Pi coding-agent integration reads this field to set per-model output limits. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WalkthroughThe models API exposes optional ChangesModel output limit metadata
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/gateway/src/models/models.spec.ts (1)
104-134: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winCover the omitted provider-level field.
This test verifies a mapping with
max_output: 64000, but it does not verify the optional provider contract. Select a mapping whose sourcemaxOutputisundefinedand assert that the response object omitsmax_output. Otherwise, a provider-level serialization regression can pass this test.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/gateway/src/models/models.spec.ts` around lines 104 - 134, Extend the GET /v1/models test to select a provider mapping from the response whose source ProviderModelMapping.maxOutput is undefined, then assert that its serialized provider object does not contain max_output. Keep the existing positive max_output assertion and model-level minimum checks unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/gateway/src/models/models.spec.ts`:
- Around line 104-134: Extend the GET /v1/models test to select a provider
mapping from the response whose source ProviderModelMapping.maxOutput is
undefined, then assert that its serialized provider object does not contain
max_output. Keep the existing positive max_output assertion and model-level
minimum checks unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3fcf76f3-0025-4af1-9e72-ae75b6cf78fb
📒 Files selected for processing (2)
apps/gateway/src/models/models.spec.tsapps/gateway/src/models/models.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54f40d1db2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const limits = mappings | ||
| .map((p) => p.maxOutput) | ||
| .filter((limit): limit is number => limit !== undefined); |
There was a problem hiding this comment.
Exclude deactivated mappings from the model-level limit
When a model retains both active and deactivated mappings, this minimum includes mappings that can no longer serve requests. For example, after 2026-06-22 the default GET /v1/models still includes deepseek-v3.2, but its deactivated Nebius mapping contributes 32768, so consumers such as the Pi integration cap output there even though every active mapping with a declared limit accepts at least 65536. Filter mappings whose deactivatedAt has passed before calculating the advertised serving bound, as pickPricingProvider already does for model-level pricing.
AGENTS.md reference: AGENTS.md:L229-L230
Useful? React with 👍 / 👎.
Deactivated mappings can no longer serve requests, so their declared limits must not constrain the advertised model-level bound (e.g. deepseek-v3.2's retired Nebius mapping capped it at 32768 while every servable mapping accepts at least 65536). Deprecated mappings remain routable and keep enforcing their limit, so they stay in. Addresses the Codex review finding on theopenco#3379. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
What
Surfaces per-model output-token limits in the public
GET /v1/modelscatalogue:providers[]entry carries its mapping's exactmaxOutputasmax_outputmax_tokensvalue guaranteed to be accepted regardless of which provider serves the request (the gateway validatesmax_tokensagainst the routed mapping's limit and rejects anything above it with HTTP 400). Deactivated mappings can no longer serve, so their limits are excluded; deprecated mappings remain routable and stay inmax_tokens, so they don't constrain the model-level bound; models where no mapping declares one omit the fieldWhy
Consumers currently have no way to discover the cap — they either guess low and truncate output or guess high and get 400s. The Pi coding-agent integration (earendil-works/pi#7480) reads this field to set per-model output limits (falling back to a conservative 4096 until this ships).
Testing
Extended
models.spec.tswith a spot check (claude-haiku-4-5 → 64000 per-provider and model-level) plus an exhaustive assertion that every model'smax_outputequals the minimum across its still-servable declaring mappings (or is omitted), and a deepseek-v3.2 case pinning the bound to 65536 rather than its retired Nebius mapping's 32768. All 23 models endpoint tests pass;tscand prettier clean.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests