Skip to content

feat(llm-api-gateway): add input/output token rate limit dimensions - #1658

Draft
Max-NV wants to merge 4 commits into
NVIDIA:mainfrom
Max-NV:feat/1456-input-output-token-ratelimit
Draft

feat(llm-api-gateway): add input/output token rate limit dimensions#1658
Max-NV wants to merge 4 commits into
NVIDIA:mainfrom
Max-NV:feat/1456-input-output-token-ratelimit

Conversation

@Max-NV

@Max-NV Max-NV commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Why

Issue #1456 asks for input (prompt) and output (completion) token rate
limits, separate from the existing combined tokenRateLimit, using
the same format. The gateway already had partial plumbing for an
input/output split (per-minute-only dimensions, never populated from
config), but nothing let a model actually configure it, and nothing
enforced anything but a per-minute window.

What changed

  • ratelimit/resources.go: extends the input/output token dimensions
    from per-minute-only to the full second/minute/hour/day/week set,
    mirroring the existing combined TokensPer* dimensions.
  • api/ratelimit.go: CallerLimitResolver now parses
    ModelSpec.InputTokenRateLimit / OutputTokenRateLimit (same
    "<value>-<unit>" format as tokenRateLimit) and applies them
    independently of the combined limit; chooseTokenStats picks
    whichever configured input/output period is closest to being
    exhausted for the X-RateLimit-Tokens-* response headers, instead
    of always the finest configured period (which could hide a tighter,
    actually-binding coarser one).
  • nvcf/pb/llm_gateway.proto (+ regenerated stubs), nvcf/types.go,
    nvcf/client.go: add inputTokenRateLimit / outputTokenRateLimit
    to ModelSpec, read from the AuthLlmInvokeResponse.
  • MO (month) added as a rate-limit unit, approximated as a fixed
    30 days (the limiter only understands time.Duration, not calendar
    dates) - applies to the combined limit and both input/output limits,
    fanned out through the same dimension/struct/switch pattern as
    S/M/H/D/W. nvcf-cli gets the same unit.
  • src/clis/nvcf-cli: --llm-model / --llm-model-update now accept
    inputTokenRateLimit and outputTokenRateLimit, through parsing,
    validation, and the client DTOs sent to the NVCF API. Previously the
    CLI rejected these fields outright with "unknown llm model field".

The NVCF API (nvcf-core) side that lets a function actually set these
two fields is a separate companion change: #1661. Until that lands,
the new ModelSpec fields are simply always empty and this change is
a no-op in production.

How the three limits interact

tokenRateLimit, inputTokenRateLimit, and outputTokenRateLimit
are independent constraints, not alternatives. All three can be
configured at once, each is tracked as its own counter/key, and a
request must satisfy all of them (AND, not OR) to be admitted:
combined input+output <= tokenRateLimit, and separately
input <= inputTokenRateLimit, output <= outputTokenRateLimit.
Whichever is hit first throttles the request.

Any of the three left unset is skipped entirely, not treated as a
limit of zero (doResourceLimit only checks a dimension when its
configured limit is non-zero). So a model can set only tokenRateLimit
(today's behavior, unchanged), only the input/output pair, or all
three together.

Testing

go test ./... in src/invocation-plane-services/llm-api-gateway and
in src/clis/nvcf-cli, both fully green, including new unit and
end-to-end coverage for every new dimension, the header-stats
tightest-period fix, and the CLI field parsing/validation/mapping.

A month-long window doesn't need a month to test: the limiter takes an
injectable clock, so TestDoResourceLimitMonthlyLimitResetsAfterPeriodElapses
just fast-forwards a fake clock by 31 days.

References

Relates to #1456

Adds independent input (prompt) and output (completion) token rate
limits alongside the existing combined tokenRateLimit, in the same
"<value>-<unit>" format across all S/M/H/D/W windows. Reads the new
ModelSpec.inputTokenRateLimit/outputTokenRateLimit fields returned by
the LlmGateway auth response and enforces them per-request; a
companion NVCF API (nvcf-core) change to set those fields is tracked
separately.

Relates to NVIDIA#1456
@Max-NV
Max-NV requested a review from a team as a code owner September 8, 2026 21:14
@Max-NV
Max-NV requested a review from sanjay-saxena September 8, 2026 21:14
@Max-NV
Max-NV marked this pull request as draft September 8, 2026 21:14
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 87e5ecca-5581-4b4b-a32d-18be3e92866a

📥 Commits

Reviewing files that changed from the base of the PR and between db43701 and ea7be32.

⛔ Files ignored due to path filters (2)
  • src/invocation-plane-services/llm-api-gateway/nvcf/pb/llm_gateway.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • src/invocation-plane-services/llm-api-gateway/nvcf/pb/llm_gateway_grpc.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
📒 Files selected for processing (8)
  • src/invocation-plane-services/llm-api-gateway/api/rate_limit_accounting_test.go
  • src/invocation-plane-services/llm-api-gateway/api/ratelimit.go
  • src/invocation-plane-services/llm-api-gateway/nvcf/client.go
  • src/invocation-plane-services/llm-api-gateway/nvcf/client_test.go
  • src/invocation-plane-services/llm-api-gateway/nvcf/pb/llm_gateway.proto
  • src/invocation-plane-services/llm-api-gateway/nvcf/types.go
  • src/invocation-plane-services/llm-api-gateway/ratelimit/resources.go
  • src/invocation-plane-services/llm-api-gateway/ratelimit/resources_test.go

Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review.


📝 Walkthrough

Walkthrough

The gateway adds separate input- and output-token rate limits across model specifications, resource enforcement, limit resolution, admission-key generation, and token-stat selection.

Changes

Token rate-limit support

Layer / File(s) Summary
Model rate-limit contract and conversion
src/invocation-plane-services/llm-api-gateway/nvcf/pb/llm_gateway.proto, src/invocation-plane-services/llm-api-gateway/nvcf/types.go, src/invocation-plane-services/llm-api-gateway/nvcf/client.go, src/invocation-plane-services/llm-api-gateway/nvcf/client_test.go
ModelSpec now carries separate input- and output-token rate limits. Protobuf conversion and authorization tests populate and verify both fields.
Input/output resource-limit enforcement
src/invocation-plane-services/llm-api-gateway/ratelimit/resources.go, src/invocation-plane-services/llm-api-gateway/ratelimit/resources_test.go
Resource limits support input- and output-token dimensions for second, minute, hour, day, and week periods. Enforcement, limit conversions, and rejection tests cover the new dimensions.
Resolver and token-stat selection
src/invocation-plane-services/llm-api-gateway/api/ratelimit.go, src/invocation-plane-services/llm-api-gateway/api/rate_limit_accounting_test.go
Limit resolution parses separate token categories and populates their period fields. Token-stat selection aggregates matching input/output results, prefers combined-token results, and selects the finer supported period. Admission-key and resolver tests cover these paths.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to ea7be

This adds independent input- and output-token quota support while preserving combined-token reporting precedence. Production behavior remains unchanged until upstream model specifications populate the new fields, and no merge-blocking risk is identified.

Sequence Diagram(s)

sequenceDiagram
  participant ModelSpec
  participant CallerLimitResolver
  participant doResourceLimit
  participant chooseTokenStats
  ModelSpec->>CallerLimitResolver: input/output token rate-limit values
  CallerLimitResolver->>doResourceLimit: populated ResourceLimit dimensions
  doResourceLimit->>doResourceLimit: evaluate input/output token quotas
  doResourceLimit->>chooseTokenStats: token-limit results
  chooseTokenStats->>chooseTokenStats: aggregate by period and select statistics
Loading

Suggested reviewers: along-2017

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 7 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows Conventional Commits format and accurately describes the primary feature: adding independent input and output token rate-limit dimensions to the LLM API gateway.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 7 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

… headers

chooseTokenStats returned on the first configured input/output period
(S/M/H/D/W) with any result, so a loose finer-period limit (e.g.
1000-S) could hide a tighter, actually-binding coarser one (e.g.
100-M) from the X-RateLimit-Tokens-* response headers, even though the
coarser one still enforces server-side. Pick whichever configured
period pair has the smallest remaining value instead, so the headers
always reflect the constraint closest to throttling the caller.

Found in adversarial review of NVIDIA#1658.

Relates to NVIDIA#1456
parseLLMModelString and parseLLMModelUpdateString rejected
inputTokenRateLimit/outputTokenRateLimit with "unknown llm model
field", so the CLI had no way to set the fields added for NVIDIA#1456 short
of hand-writing the REST JSON body. Adds the two fields through the
full path: CLI flag parsing, validation (reusing the existing
<value>-<unit> format check, now with the field name in error text),
and the client DTOs sent to the NVCF API.

Found in adversarial review of NVIDIA#1658.

Relates to NVIDIA#1456
Approximates a month as a fixed 30 days, same as the existing D/W
units, rather than a calendar-aligned window: the leaky-bucket limiter
only understands time.Duration, not calendar dates. Applies to the
combined tokenRateLimit and both input/output limits, so it fans out
through the same dimension/struct/switch pattern as the S/M/H/D/W
units: resources.go dimensions and struct fields, doResourceLimit
switch cases, the 3 ResourceLimitFrom* mappers, parseTokenRateLimit,
CallerLimitResolver, and chooseTokenStats.

nvcf-cli's --llm-model / --llm-model-update token rate limit
validation gets the same "MO" unit.

Testing a month-long window doesn't need to wait a month: the limiter
takes an injectable clock (see ratelimit_test.go's TestBucketsRefillOverTime
for the existing pattern), so TestDoResourceLimitMonthlyLimitResetsAfterPeriodElapses
just fast-forwards the fake clock by 31 days.

Relates to NVIDIA#1456
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.

1 participant