feat(api-rs,slackbotv2): keep working when a provider runs out of credits - #1307
Open
snario wants to merge 1 commit into
Open
feat(api-rs,slackbotv2): keep working when a provider runs out of credits#1307snario wants to merge 1 commit into
snario wants to merge 1 commit into
Conversation
When a provider runs out of credits, every execution on the affected harness fails terminally and the thread just shows a red error block. This adds an opt-in automatic fallback path: - api-rs classifies provider quota/credit exhaustion as a new "quota" terminal failure class (Codex CLI usage-limit prose, OpenAI insufficient_quota / usage_not_included codes as surfaced by codex and nanocodex, and the Anthropic credit-balance equivalent), and stamps failure_class on the session.execution_failed event payload so consumers get a machine-readable taxonomy instead of matching error prose. Plain rate limits stay in the transient catch-all. - slackbotv2 gains SLACKBOTV2_QUOTA_FALLBACK_HARNESS (slackbotv2.quotaFallbackHarness): when a rendered execution ends with the quota class on a different harness, the thread is pinned to the fallback harness exactly as an explicit --claude/--codex flag would be (sticky, model/provider tombstoned), the failed message is replayed once on it, and the existing harness-restart transcript preamble rebuilds context. A per-message state guard makes a fallback that itself fails terminal instead of looping, and explicit harness flags on the message still win over the fallback. Unset/empty config disables the behavior entirely; the failure-class event field is additive. Co-Authored-By: Claude Fable 5 <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.
The problem, in plain terms
If the provider behind your default harness runs out of credits — a ChatGPT/Codex usage cap, an exhausted OpenAI or Anthropic balance — the whole assistant goes down. Every message, in every thread, fails with:
…and it stays that way until a human notices, tops up credits, or manually switches threads to another harness. For deployments that run on subscription credits, this is the most common way the bot dies — and it always happens at the worst time, because credits run out precisely when the bot is being used heavily. This exact outage hit a live deployment this week: Codex credits ran out on a Friday afternoon with the reset three days away.
The frustrating part: most deployments already have a second, fully-credentialed harness sitting idle (Claude Code next to Codex, or vice versa). Today Centaur won't touch it unless a user knows to type
--claudein every affected thread.What this PR does
One new deployment value:
With that set, running out of credits stops being an outage:
--claude— re-feeds the thread transcript, and replays the failed message.The switch is sticky per thread (mid-conversation threads don't bounce back and forth during the outage), while new threads still start on the default harness — so when credits reset, the deployment drifts back to normal on its own, with zero operator action.
Sensible edges: a fallback that itself fails is terminal (a per-message guard prevents ping-pong loops), an explicit
--codex-style flag from the user always beats the automatic switch, and plain rate limits are deliberately not treated as quota exhaustion (they're transient; switching harnesses over them would cause churn).How it works
terminal_failure_class()gains a"quota"class covering the Codex CLI's usage-limit prose, the raw OpenAIinsufficient_quota/usage_not_includedcodes (as surfaced by both codex and nanocodex), and Anthropic's credit-balance message. The class is stamped onto thesession.execution_failedevent as a new additivefailure_classfield, so consumers react to a machine-readable taxonomy instead of regex-matching human error prose. Same values as the existing finished-execution metric label.slackbotv2_quota_harness_fallbacks_total{outcome}counter, chart plumbing for the new value/env, and a configuration-reference docs row.Testing
cargo test -p centaur-session-runtime terminal_failure_class— includes a new test pinning the quota classification (and that plain rate limits stay out of it)services/slackbotv2:bun run check:typesclean;bun test test— 233 tests, 0 fail, including new SSEfailure_classpropagation testsDeployment note
With
claudeCodeAuthMode: access_token, api-rs validates at startup that theanthropic-claudebroker credential exists in iron-control (the auth fragment references it) — seed that credential before pointingquotaFallbackHarnessatclaudecode, or api-rs crashloops on the 422. Verified on a live deployment.🤖 Generated with Claude Code