Skip to content

feat(usage): let chat callers see their own quota and conversation cost - #74

Merged
albanm merged 12 commits into
mainfrom
feat-self-limits-consumption
Oct 1, 2026
Merged

albanm merged 12 commits into
mainfrom
feat-self-limits-consumption

Conversation

@albanm

@albanm albanm commented Oct 1, 2026

Copy link
Copy Markdown
Member

Any chat caller (org member, external user, anonymous visitor, account owner) can now see their own AI quota and what the current conversation has cost.

  • GET /api/gateway/:type/:id/usage returns the caller's daily/weekly/monthly windows (used, limit, reset date), resolved with the same identity as a completion. The org credit cap and the anonymous+external pool are reported as a status (ok/exhausted + reset date); their numbers are only shown to admins of the account.
  • Gateway completions report usage.cost in credits (OpenRouter's convention), including the moderation check when its verdict settles before the gate opens.
  • The chat sums those costs into a conversation total, shown with the quota windows in a new Consumption tab of the chat settings dialog.
  • Quota 429s carry period and resets_at, drop the shared budgets' numbers for non-admins, are no longer retried client-side, and render as a localized message ("Your daily AI quota is used up. It resets on …").
  • Fix: recordUsage without a userId (owner of a user account) could increment an arbitrary usage document of that owner, e.g. an external user's record.
  • Dev fixtures: test1-user1/dev1-user1 had the non-existent org role user1; now user.

Why: a user should be able to see their own quotas and consumption, including the current conversation's.

Heads-up:

  • 429 body change: for account/untrusted scopes, usage/limit are now omitted unless the caller is an admin; period is added.
  • Org members can still read the credit cap through GET /api/limits/:type/:id (unchanged, intentional), so the redaction mainly protects shared budgets from external/anonymous callers.
  • The streamed gateway path now awaits the moderation gate before writing the finish/usage chunk (it already did before [DONE]).
  • The conversation total is informational: a moderation verdict landing after the gate failed open, or a blocked request, is recorded server-side but not reported to the client.

albanm and others added 12 commits September 30, 2026 11:05
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…dmins

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… usage

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rrors

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… the raw message

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Without a userId the upsert filter matched an arbitrary usage document
of the owner (an external user's record or the untrusted pool).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The gate is awaited before the finish chunk, so it is never pending there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
'user1' is not a role: it mapped to no quota, so these members could
not exercise the simple-user profile.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@albanm
albanm merged commit 39cc1e0 into main Oct 1, 2026
4 checks passed
@albanm
albanm deleted the feat-self-limits-consumption branch October 1, 2026 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant