Skip to content

feat(accounts): add per-account usage limits - #1528

Open
NikitaMGrimm wants to merge 27 commits into
Soju06:mainfrom
NikitaMGrimm:feat/per-account-usage-limits
Open

feat(accounts): add per-account usage limits#1528
NikitaMGrimm wants to merge 27 commits into
Soju06:mainfrom
NikitaMGrimm:feat/per-account-usage-limits

Conversation

@NikitaMGrimm

@NikitaMGrimm NikitaMGrimm commented Jul 29, 2026

Copy link
Copy Markdown

Summary

Adds an optional per-account usage cap so operators can reserve upstream quota for direct use. The cap applies across API keys and routing strategies.
The limit applies to both the 5-hour and weekly quota windows. Routing stops when either window reaches the configured percentage, making sure to preserve the remaining share.

Fixes #631

Type of change

  • feat: — new user-facing feature or capability

OpenSpec

  • This PR includes an OpenSpec change

Change directory: openspec/changes/add-account-usage-limits/

Changes

  • Store a reversible maximum-used percentage on each account.
  • Exclude capped accounts before sticky, policy, fallback, and additional-quota routing.
  • Add the account API, migration, dashboard controls, documentation, and tests.

Review notes

The selector uses standard usage rows already loaded into the cached selection snapshot; it adds no usage queries. Evaluation is linear in the candidate count.

Enabled limits fail closed when relevant telemetry is missing or older than max(2 × refresh interval, 180 seconds). The API and dashboard expose this as data_unavailable; fresh below-cap telemetry restores eligibility automatically.

Simplicity

  • The feature defaults to off.
  • No new setup step or setting is required.
  • No README, .env.example, or core navigation growth.

Test plan

uv run pytest -q tests/unit/test_account_usage_limits.py tests/unit/test_load_balancer.py tests/unit/test_load_balancer_concurrency.py tests/unit/test_proxy_utils.py tests/unit/test_accounts_service_transitions.py -k 'usage_limit or usage_limited'
# 32 passed

uv run pytest -q tests/integration/test_accounts_api_extended.py tests/integration/test_migrations.py -k 'usage_limit'
# 6 passed

npx -y @fission-ai/openspec@latest validate --specs
# 48 passed

Screenshots / output

limit not set:
image
limit set:
image
current set limit disabled:
<img width="1389" height="309" alt="image" src="https://github.com/user-attachments/assets/d057afad-abfb-489d-b1ef-0888ddca91f6" /

Checklist

  • Conventional Commit title
  • Linked issue
  • OpenSpec validation passes
  • Focused unit, API, and migration tests pass
  • Simplicity gates reviewed
  • CHANGELOG.md was not edited
  • Full CI matrix passes

Summary by CodeRabbit

  • New Features
    • Added configurable per-account usage limits with percentage thresholds.
    • Added controls to enable, disable, update, or remove limits.
    • Added usage-limit status, summaries, warnings, and dashboard badges.
    • Routing excludes accounts at or beyond limits and fails safely when usage data is unavailable.
    • Enforced limits across HTTP, WebSocket, sticky, fallback, and warmup flows.
  • Documentation
    • Documented usage-limit behavior and routing effects.
  • Localization
    • Added English, Korean, and Chinese translations for controls and messages.

@github-actions github-actions Bot added the db migration PR changes Alembic database migrations; maintainer must coordinate merge order label Jul 29, 2026
@NikitaMGrimm

NikitaMGrimm commented Jul 29, 2026

Copy link
Copy Markdown
Author

Regarding the UI design:

Alternatively, it could possibly work like this:
Enabled Toggle always shows, default is off.
Once someone enables the toggle, it gets set to 100% by default unless a prior value has been set.
New limits can then be set when toggled on.
Clear saved limit button would then be gone.

One potential problem that exists right now if the above is implemented:
If a limit of 100% usage is set and enabled, it will still block routing after 100% is used up (after 0% of the limit is still available). There is no special case at 100% where blocking is effectively disabled at this point. This might cause requests after 100% to be "wasted" even though Codex might still allow them. (ongoing work and subagents before compactification triggers and input tokens aren't cached anymore)

Also delayed telemetry or in-flight requests can cause some unpreventable overshoot with the current implementation.
(Not too bad in my testing. Theoretically possible to try and predict the overshoot even with delayed telemetry but that might cause some bigger changes?)

@Soju06

Soju06 commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Triage note: this is a feature, so per the release train it queues behind the v1.23.0 stable cut (#1472) even once ready — no rush on your side. Meanwhile: (1) @Soju06, the author raised a concrete UI design question (always-visible enable toggle defaulting to 100% vs. the current clear-saved-limit control) that needs a maintainer call before the dashboard surface settles; (2) CI runs need maintainer workflow approval to start. Design looks aligned with the balancer-module ratchet (new app/core/balancer module, no selector hot-path DB I/O claimed) — we'll verify the app/core -> app/modules import boundary at review time.

@Komzpa Komzpa added the needs rebase Needs rebase or conflict repair against current main label Aug 6, 2026
@NikitaMGrimm
NikitaMGrimm force-pushed the feat/per-account-usage-limits branch 2 times, most recently from 9720787 to d3909d6 Compare August 9, 2026 15:18
@NikitaMGrimm

NikitaMGrimm commented Aug 9, 2026

Copy link
Copy Markdown
Author

Rebased. When you have time, could you approve the CI workflow and let me know if we should change the UI or keep the current design from the screenshots?
@Soju06

@Komzpa Komzpa removed the needs rebase Needs rebase or conflict repair against current main label Aug 9, 2026
@Komzpa

Komzpa commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3909d647c

ℹ️ 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".

Comment thread frontend/src/features/accounts/components/account-usage-limit-control.tsx Outdated
Comment thread app/core/balancer/logic.py
Comment thread app/modules/proxy/_load_balancer/sticky_selection.py
Comment thread app/modules/proxy/load_balancer.py
Comment thread app/core/usage/account_limits.py
@Komzpa Komzpa added the 🤖 codex: needs work [@codex review] raised an issue label Aug 9, 2026
@NikitaMGrimm

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 091aa1515f

ℹ️ 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".

Comment thread app/core/balancer/logic.py Outdated
Comment thread app/modules/proxy/load_balancer.py Outdated
@NikitaMGrimm

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f969778d35

ℹ️ 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".

Comment thread app/modules/quota_planner/warmup.py Outdated
@NikitaMGrimm

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6518cdc407

ℹ️ 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".

Comment thread app/modules/proxy/api.py Outdated
Comment thread app/modules/quota_planner/logic.py
@NikitaMGrimm

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe2833649c

ℹ️ 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".

Comment thread app/modules/proxy/_load_balancer/unbound_selection.py Outdated
@NikitaMGrimm

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b7ec8519ae

ℹ️ 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".

Comment thread app/core/usage/account_limits.py
Comment thread app/modules/proxy/_load_balancer/sticky_selection.py
@NikitaMGrimm

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@Komzpa Komzpa added 🤖 codex: needs work [@codex review] raised an issue needs rebase Needs rebase or conflict repair against current main and removed 🤖 codex: needs work [@codex review] raised an issue labels Aug 10, 2026
NikitaMGrimm and others added 26 commits August 18, 2026 15:16
@NikitaMGrimm
NikitaMGrimm force-pushed the feat/per-account-usage-limits branch from 8be2a95 to ab6c3bd Compare August 18, 2026 13:56
@Soju06

Soju06 commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Triage re-review after your 0818 push — this is now merge-ready on technical grounds except for one small fix: the migration reparent onto 20260806_030000_add_api_key_allowed_reasoning_efforts means that revision is no longer the alembic head, so tests/unit/test_db_migrate.py::test_api_key_reasoning_policy_migration_round_trips_from_current_parent fails at your head (the head-pin assertion needs 20260728_010000_add_account_usage_limits as the expected head). Verified it's the only PR-caused failure in the full unit suite. Once you push that, I'll approve the fork CI runs so the Postgres matrix exercises the migration path.

Answering the open 07-29 UI question explicitly since it was never closed out: the current set/clear control from your screenshots is accepted — no need for an always-visible toggle defaulting to 100%.

Everything else verified: WS-harness blocker fixed, quota interaction correctly isolated from ignore_standard_quota, fail-closed staleness behavior looks right, migration itself is well-formed, 20/20 review threads resolved. Note the 'db migration' label coordination: if another migration-bearing PR lands first you'll need one more reparent + the same head-pin update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

db migration PR changes Alembic database migrations; maintainer must coordinate merge order

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Account limit restriction

4 participants