docs(error-handling): QUOTA_EXCEEDED has one producer, the ObjectOS agent chat route - #20220
Merged
objectstack-fleet[bot] merged 1 commit intoSep 27, 2026
Merged
Conversation
…gent chat route The section said no producer emits QUOTA_EXCEEDED and told readers not to branch on it. The ObjectOS agent chat route (POST /api/v1/ai/agents/:agentName/chat) answers it with a nested 429 when a deployment's per-user daily chat-turn cap is spent, but only to a JSON-mode request (stream: false); a streaming request gets the refusal as in-band assistant text on HTTP 200. Document that route, the measured body (error.details.resetAt, category rate_limit, no Retry-After), and keep the SMS TOO_MANY_REQUESTS sentence. Claude-Session: https://claude.ai/code/session_01Rjy9MeetSfq34PKn81CRiN Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Sep 27, 2026
objectstack-fleet
Bot
deleted the
claude/issue-19958-quota-exceeded-doc
branch
September 27, 2026 11:24
This was referenced Sep 27, 2026
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.
Fixes #19958
Clause-②: no
Docs only. One section of
content/docs/protocol/kernel/error-handling.mdxis rewritten: theQUOTA_EXCEEDEDentry. No runtime, spec or error-code-ledger change.QUOTA_EXCEEDEDstays registered, as the narrowed ruling on #17707 (5807013768) keeps it.What the page said, and what it says now
Removed (it was false):
Added (each sentence rests on a measurement below):
Kept as it was: the SMS sentence (
the SMS daily quota answers TOO_MANY_REQUESTS) and the pointer toRATE_LIMIT_EXCEEDEDfor request pacing. The SMS sentence still holds onmain:packages/services/service-sms/src/sms-daily-quota.ts:85isSMS_QUOTA_EXCEEDED_CODE = 'TOO_MANY_REQUESTS'. The only change there is its first word, "Quota enforcement that does exist" → "Other quota enforcement".The producer, measured (cloud
main48d70663)The producer and reader are cited here, not in the doc, following the dispatch's route.
packages/service-ai/src/routes/agent-routes.ts:572-575:return sendError(429, 'QUOTA_EXCEEDED', message, { details: { resetAt: decision.resetAt }, category: 'rate_limit' }).agent-routes.ts:527:const wantStreamMode = body.stream !== false;. At:552-565a streaming request getsstatus: 200with the copy as onetext-deltapart, so there is no code on that path.packages/service-ai/src/routes/envelope.ts:188-198:sendErrorwrites{ success: false, error: { code, message, httpStatus: status, ...extra } }.packages/service-ai/src/plugin.ts:1154-1159: the gate exists only when the deployment sets its daily-turn knob to a positive number, and the only implementation wired isDailyMessageQuota. Its refusal always setsresetAt(quota/agent-chat-quota.ts:92-96).Retry-Afteron this path.sendErrorreturns status and body only, and no cloud writer adds that header to this route.packages/service-ai/src/__tests__/agent-error-envelope.conformance.test.ts:300-315(status 429, code,detailsequal to{ resetAt }).mainhas no producer of this code.git grep QUOTA_EXCEEDEDate7f69dbbgives 40 lines: docs, generated references, the registration inpackages/spec/src/api/errors.zod.ts:106, a ledger test, a status baseline, and the SMSSMS_QUOTA_EXCEEDED_*constants whose value isTOO_MANY_REQUESTS.The readers, measured
objectui, pin
f8a9d0fb(current.objectui-sha) andmain25c7d584.tool-display.ts,tool-display.test.tsanduseObjectChat.tsare byte-identical between the two.packages/plugin-chatbot/src/tool-display.ts:314-326and:336:parseAiQuotaErrordeliberately does NOT recognizeQUOTA_EXCEEDED.isUnsentSendError(:404) andisRateLimitError(:423). They key on the HTTP status tagged bysendAwareFetch, or on a raw-text regex.code, notdetails.resetAt, notcategory. The card's "objectui branches on it (error.details.resetAt,category)" comes from a comment at:317that describes the producer. No read in objectui matches it.streamingEnabled = true(useObjectChat.ts:768, sent asstreamat:931). Its default path therefore receives the in-band text on HTTP 200. The 429 branch is reached only when a chatbot schema setsstreamingEnabled: false, and it is pinned by fixture (tool-display.test.ts:365-390).@objectstack/client, this repo ate7f69dbb:client.ai.agents.chat()sendsstream: false(packages/client/src/index.ts:6648-6653). It throws an error carryingcode,category,detailsandhttpStatus(fromres.status) (:7376-7405).chatStream()sendsstream: true(:6662-6667).Field mismatches (dispatch Zone 2 item 2):
code,details.resetAt,categoryandhttpStatus, and readsmessageonly through the regex probe.error.retryable, which isundefinedhere.Choices this PR settled
content/docs/ai/index.mdx: the in-product chat runtime "ships in ObjectOS". The section links there.httpStatus: 429. Triage ruled 「⛔ 不要自行补充字段」.httpStatusis not an added field: the producer'ssendErrorwrites it on every body (envelope.ts:198), and leaving it out would misdescribe the wire. The field list under the example names only what a client acts on:code,details.resetAt,categoryandmessage.retryAfterSecondsandRetry-Afterare named only as absent.messageis illustrative. It is the English half ofDailyMessageQuota's copy with an example limit of 50. The real copy is bilingual, Chinese first. The doc says to displaymessage, never to parse it.Acceptance notes
content/docs/api/error-catalog.mdxdisagrees with the rewritten section. It is not edited here (claim file surface).:507-510: the entry sends readers to "checkretryAfterSeconds", which this producer never sends;details.resetAtis the field. Its cause line says "API usage quota for the current period", while the only producer is a per-user daily chat-turn cap.:913(rate_limit) agrees.httpStatus, and it does not listcategory. That is true of the writer it names,packages/types/src/response-envelope.ts. The ObjectOS route writes through its ownsendError, which carries both. Not edited.fetchWithRetryexample underRATE_LIMIT_EXCEEDEDretries any 429 byRetry-After. Against this 429 it would wait zero seconds and retry. The new section warns against that. The loop under "Implement Retry Logic" keys on the code and letsQUOTA_EXCEEDEDthrow, which is right. Its comment "it is present on every 429" is inaccurate for this code's 429, but the comment sits inside theRATE_LIMIT_EXCEEDEDbranch, so behaviour is unaffected. Carrier: none.62597c5880;.objectui-shais nowf8a9d0fb. The cited lines are unchanged at both.Verification (head
6e0bb38e)node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackgives 41 commands on the actual changed paths, identical to the dispatch lead.check:doc-formula-expressions,check:doc-security-posture,check:skill-examplesandcheck:docs-transcript-drift.check:docswas held back until spec was built. None of those refusals counted as a reading. The lines were re-run after builds underscripts/pm/os-verify-lock.sh:turbo run buildover@objectstack/lint...,@objectstack/formulaand@objectstack/spec: VERDICT command-exit 0.@objectstack/client-react...and@objectstack/client...: VERDICT command-exit 0.check:skill-examplesneeded this second build because it refused again, on missing client declarations.check:skill-examplesthen read "259 prose examples type-check across 3 surface(s)".dispatch-gates.mjs --ran ran.listprints: "✓ dispatch-gates --ran: 41 derived famil(ies) accounted for — 41 run, 0 NOT-MEASURED (a DERIVED zero — all 41 recorded an exit code and none of them is 3)."pnpm check:nul-bytesexits 0, and the control-byte self-scan of the edited file has no hits.skip-changeset: 0 of 69 non-private workspace packages list afiles[]entry reachingcontent/docs.main.origin/mainmoved to7e7fab73, and no commit since BASEe7f69dbbtouches either doc.Generated by Claude Code