- Add /exceeded.*quota/i and /usage\s*quota/i to classifyErrorType quota block
- Align /usage.?quota/i -> /usage\s*quota/i in RETRYABLE_ERROR_PATTERNS for consistency
- Strengthen auto-retry-signal test assertion
- Add classifyErrorType assertion to Volcano Engine regression test
Ensures Volcano Engine errors are both retryable AND logged as
errorType: quota_exceeded.
Volcano Engine sends quota exceeded errors with the words in reverse
order: 'You have exceeded the 5-hour usage quota'. The existing
patterns required 'quota' to precede 'exceeded', so they never matched.
- Add /exceeded.*quota/i and /usage.?quota/i to RETRYABLE_ERROR_PATTERNS
- Add exceeded.*quota and usage\s*quota to AUTO_RETRY_PATTERNS
- Add regression tests for both detection paths
Fixes: runtime-fallback not triggering on Volcano Engine quota errors
Remove quota exhaustion patterns from RETRYABLE_ERROR_PATTERNS:
- 'usage limit reached' patterns (lines 30, 32)
- 'insufficient credits' pattern (line 37)
- 'credit balance too low' pattern (line 38)
These errors indicate permanent quota exhaustion, not temporary
rate limits. They are already handled by classifyErrorType() which returns
'quota_exceeded', and isRetryableError() properly stops on these
unless there's an explicit auto-retry signal.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Bug fixes:
1. OAuth token refresh (#3149): buildHttpRequestInit() now attempts silent refresh
via refresh_token before triggering full browser re-auth. Added refresh() method
to McpOAuthProvider. Includes test isolation fix for discovery mock.
2. Quota error STOP (#3126): Added STOP_MESSAGE_PATTERNS in model-error-classifier
that take precedence over RETRYABLE_MESSAGE_PATTERNS. Message-only quota errors
now non-retryable. Runtime-fallback: quota_exceeded with 'retrying in' signal
still triggers fallback (provider-managed auto-retry). Restored removed patterns.
3. Compaction loop (#3127): MAX_RECOVERY_ATTEMPTS=3 cap + additional suppression
guard from opencode session in degradation monitor.
Also: refactored extractAutoRetrySignal to auto-retry-signal.ts, new regression
tests for quota classifier and compaction degradation monitor.
- background_output: snapshot read cursor before consuming, restore on
/undo message removal so re-reads return data (fixes#2915)
- MCP loader: preserve oauth field in transformMcpServer, add scope/
projectPath filtering so local-scoped MCPs only load in matching
directories (fixes#2917)
- runtime-fallback: add 'reached your usage limit' to retryable error
patterns so quota exhaustion triggers model fallback (fixes#2918)
Verified: bun test (4606 pass / 0 fail), tsc --noEmit clean
model_not_supported errors from providers (e.g. OpenAI returning
{"error": {"code": "model_not_supported"}}) were not recognized as
retryable. Subagents would silently fail with no response, hanging the
parent session.
Fix:
- Add "model_not_supported", "model not supported", "model is not
supported" to RETRYABLE_MESSAGE_PATTERNS in model-error-classifier.ts
- Add regex patterns to RETRYABLE_ERROR_PATTERNS in
runtime-fallback/constants.ts to match "model ... is ... not ...
supported" with flexible spacing
- Add regression test covering all three variations
Now model_not_supported errors trigger the normal fallback chain instead
of silent failure.
Refactor retry signal detection to be provider-agnostic:
- Replace hardcoded Copilot/OpenAI checks with generic pattern matching
- Detect any provider message containing limit/quota keywords + [retrying in X]
- Add OpenAI pattern: 'usage limit has been reached [retrying in X]'
- Update logging to use generic 'provider' instead of specific names
- Add 'usage limit has been reached' to RETRYABLE_ERROR_PATTERNS
This enables fallback escalation for any provider that signals automatic
retries due to quota/rate limits, not just Copilot and OpenAI.
Closes PR discussion: generalize retry pattern detection
Bug fixes:
1. extractStatusCode: handle nested data.statusCode (Anthropic error structure)
2. Error regex: relax credit.*balance.*too.*low pattern for multi-char gaps
3. Zod schema: bump max_fallback_attempts from 10 to 20 (config rejected silently)
4. getFallbackModelsForSession: fallback to sisyphus/any agent when session.error lacks agent
5. Model detection: derive model from agent config when session.error lacks model info
6. Auto-retry: resend last user message with fallback model via promptAsync
7. Persistent fallback: override model on every chat.message (not just pendingFallbackModel)
8. Manual model change: detect UI model changes and reset fallback state
9. Agent preservation: include agent in promptAsync body to prevent defaulting to sisyphus
Additional:
- Add sessionRetryInFlight guard to prevent double-retries
- Add resolveAgentForSession with 3-tier resolution (event → session memory → session ID)
- Add normalizeAgentName for display names like "Prometheus (Planner)" → "prometheus"
- Add resolveAgentForSessionFromContext to fetch agent from session messages
- Move AGENT_NAMES and agentPattern to module scope for reuse
- Register runtime-fallback hooks in event.ts and chat-message.ts
- Remove diagnostic debug logging from isRetryableError
- Add 400 to default retry_on_errors and credit/balance patterns to RETRYABLE_ERROR_PATTERNS
Replace word-boundary regex with stricter patterns that match
status codes only at start/end of string or surrounded by whitespace.
Prevents false matches like '1429' or '4290'.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add configuration schemas for runtime model fallback feature:
- RuntimeFallbackConfigSchema with enabled, retry_on_errors,
max_fallback_attempts, cooldown_seconds, notify_on_fallback
- FallbackModelsSchema for init-time fallback model selection
- Add fallback_models to AgentOverrideConfigSchema and CategoryConfigSchema
- Export types and schemas from config/index.ts
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>