Repository navigation
feat(usage): let chat callers see their own quota and conversation cost - #74
Merged
Merged
Conversation
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
added a commit
that referenced
this pull request
Oct 6, 2026
All three PRs changed the in-browser loop and the gateway, which this branch deletes, so this merge resolves conflicts mechanically and the behaviour is carried over onto the server loop in the commits that follow - one per behaviour, each with its tests: - #73/#75 wait handover: `wait_for_user_action` requires a `message`, repairs a small-model slip, refuses a wait with no message. Merged here (it lives in shared/host-events.ts); the server's rendering of the message in the transcript follows. - #73/#75 interrupted turns: an aborted turn's open calls keep a result saying why, and the next turn carries a reminder of what the wait was for. Follows. - #74 self-service consumption, redacted quota refusals, conversation cost. Follows. Resolved here: - Deleted on this branch, modified on main: kept deleted - api/src/gateway/router.ts, ui/src/composables/{use-agent-chat,agent-stream-parts}.ts and their two specs. - New on main and built on the deleted code, set aside to come back adapted: interrupted-turn.ts and its spec, gateway-cost.ts and its spec, the two self-usage specs, the "speaking during a wait" e2e (it reads the browser's /chat/completions request), and two moderation-cost api tests (gateway-shaped, and anonymous). - api/src/usage/enforce.ts: this branch's `checkAccountCreditCap` (re-checked between steps of a long run) and main's `accountViolation` (the cap plus the untrusted pool, also read by the self-usage view) compose - the cap check stays one definition. - shared/host-events.ts: main's `repairWaitInput` moves here from the deleted stream-part builder, beside the tool that uses it; verified byte-identical. - dev/resources/organizations.json: main's `user1` -> `user` role fix, plus this branch's NHI members. Takes effect when simple-directory reloads its fixtures. - The debug dialog shows its Consumption tab only when the chat can report usage, which the #74 port provides; until then its e2e keeps the two-tab expectation. - The wait-tool specs pass the now-required `message`. - ui/dts/auto-imports.d.ts: the running dev server wrote entries for main's set-aside files, and the committed copy already declared 11 modules this branch had deleted; pruned to what exists. host-events.md and quotas-usage.md merged main's text, which describes the browser mechanisms; each port commit rewrites its section for the server. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
albanm
added a commit
that referenced
this pull request
Oct 6, 2026
- GET /api/usage/:type/:id/self replaces the gateway's /usage route. - A refusal is stored as English text plus a data-refusal part (quota scope, period, reset; or moderation), redacted through quotaErrorBody like main's 429 body; the chat renders it in its own language. The quota text named the shared budgets' numbers to every caller until now. - The moderation call is spent onto the turn's run and recorded in its telemetry, so a blocked turn is no longer free in the conversation's total. - The session sends a `cost` frame (conversationCost, summed over runs) on attach and after every turn; the Consumption tab shows it. Exact, unlike main's total summed from response usage chunks. - Removes ui/src/utils/error.ts: both helpers read the gateway's errors and had no caller left. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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/usagereturns 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.usage.costin credits (OpenRouter's convention), including the moderation check when its verdict settles before the gate opens.periodandresets_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 …").recordUsagewithout a userId (owner of a user account) could increment an arbitrary usage document of that owner, e.g. an external user's record.test1-user1/dev1-user1had the non-existent org roleuser1; nowuser.Why: a user should be able to see their own quotas and consumption, including the current conversation's.
Heads-up:
account/untrustedscopes,usage/limitare now omitted unless the caller is an admin;periodis added.GET /api/limits/:type/:id(unchanged, intentional), so the redaction mainly protects shared budgets from external/anonymous callers.[DONE]).