feat(service-ai): optional per-turn daily chat quota (ADR-0040 §5) — default off#1760
Merged
Conversation
…t route (ADR-0040 §5) Mechanism only, default OFF — no behavior change unless a deployment sets AI_DAILY_USER_MESSAGES=<N>: - AgentChatQuota hook on buildAgentRoutes: checked before each user turn, consumed exactly once when admitted (per turn, not per tool call). - Refusal is honest at the moment of impact (perception rule): streaming clients receive the copy as a normal assistant message (no client change, no raw transport error); JSON clients get 429 + code 'ai_quota_exhausted' + resetAt. - DailyMessageQuota: N user turns / user / environment / UTC day, backed by the new ai_usage_daily platform object via IDataEngine. Counter semantics (lost update under-counts one turn) — entitlement gate, not billing. Fail-open on store errors: a broken counter never takes chat down. - Plan-tier policies (free vs pro) later implement AgentChatQuota and plug into the same gate; route and counter unchanged. 10 new tests (quota policy + route gate, both modes, env scoping, fail-open). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Why
ADR-0040 §5's perception rule: limits that can only manifest as refusal (quota exhausted) must be honest at the moment of impact — why, when it recovers, the way out — and must never degrade silently. This PR ships the mechanism for daily AI usage quotas; the policy (free/pro tier numbers) stays in deployment config and later plan entitlements. Companion to cloud#242 (blueprint scope cap) — together they are Phase 2a of the tiering plan.
What
AgentChatQuotahook onbuildAgentRoutes(…, {quota}):check()before each user turn,consume()exactly once when admitted (per turn — not per tool call, not per token). No quota wired → byte-identical behavior.encodeVercelDataStream(zero client changes, chat never shows a raw error); JSON mode returns 429 with stablecode: 'ai_quota_exhausted'+resetAt.DailyMessageQuota: N user turns / user / environment / UTC day, persisted in the newai_usage_dailyplatform object viaIDataEngine(survives restarts, shared across instances). Fail-open on counter errors — a broken counter must never take chat down. Explicitly documented as an entitlement gate, not billing-grade metering.AI_DAILY_USER_MESSAGES=<N>env var; unset/invalid → quota disabled (logged).Tests
embedder binding) fails on the unmodified baseline in the same worktree (env-only, verified via git stash) and passes in the main checkout; CI is the arbiter.Follow-ups
AgentChatQuotaimplementation (free/pro) once pricing tiers are decided — plugs into this gate unchanged.remainingsurfacing in the chat UI (progressive disclosure only near the limit).🤖 Generated with Claude Code