fix(agent-runner): deliver budget/billing error turns instead of dropping them#2759
Open
assapin wants to merge 2 commits into
Open
fix(agent-runner): deliver budget/billing error turns instead of dropping them#2759assapin wants to merge 2 commits into
assapin wants to merge 2 commits into
Conversation
…ping them A turn that ends in a non-retryable provider error (e.g. an Anthropic 403 billing_error) comes back from the streaming SDK as a result with is_error=true and no <message> envelope. dispatchResultText treated it as scratchpad and dropped it, then the poll-loop pushed a re-wrap nudge -> new turn -> same error, re-hammering the gateway until idle-kill. The user saw silence. - providers/claude.ts: surface is_error on the result event, and fall back to errors[] for the message text (error subtypes carry no result). - poll-loop.ts: when a result has no <message> blocks and is_error, deliver the notice verbatim to the originating channel and skip the nudge. Verified live (real agent image + SDK, 403 mock): the notice is delivered to the channel and the retry loop is gone. Refs nanocoai#2751
This was referenced Jun 15, 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.
Type of Change
Description
Closes #2751.
What — Budget/token-exhausted LLM turns (e.g. an Anthropic
403 billing_error, directly or via the OneCLI gateway) now reach the user instead of being silently dropped.Why — In streaming mode the Agent SDK doesn't throw for a budget/billing error; it yields a terminal
resultwithis_error: trueand no<message>envelope.translateEventsdiscardedis_error, anddispatchResultTexttreated the unwrapped notice as scratchpad and dropped it — then the poll-loop pushed the re-wrap nudge → new turn → same error, re-hammering the gateway until idle-kill. Net: the user got silence.How it works
providers/claude.ts— surfaceis_erroron theresultevent, and fall back to the error subtype'serrors[]for the message text (error subtypes carry noresult).poll-loop.ts— when a result has no<message>blocks andis_error, deliver the notice verbatim to the originating channel (deliverErrorResult, the same write the catch block already uses) and skip the re-wrap nudge. The happy path and the genuine wrap-mistake nudge are untouched.How it was tested
bun test): assert the error notice is delivered to the channel with no nudge, and that a normal unwrapped result still nudges (regression guard).111 pass, host472 pass, both typechecks + prettier.ANTHROPIC_BASE_URLpointed at a local403 billing_errormock: the notice is delivered to the channel and the retry loop is gone.Dependency
Requires the gateway to emit a standard Anthropic 403 so the SDK sets
is_error— e.g. OneCLI returning403 {"type":"error","error":{"type":"billing_error","message":"…"}}instead of a fabricated HTTP 200. Detailed in #2751. (Not429— that's retryable, the SDK auto-retries it, and the runner only logs rate-limit events → still silent.)