Commit Graph

23 Commits

Author SHA1 Message Date
YeonGyu-Kim 222adeb606 fix(runtime-fallback): honor retryable signal 2026-05-25 00:03:29 +09:00
ZeyuFu a8ccffdd7c style(runtime-fallback): add explicit optional chain on .replace per review
Addresses cubic-dev-ai P1 finding on #4113 (#4113 review).

The original chain `extractErrorName(error)?.toLowerCase().replace(...)`
is semantically safe — JavaScript optional chaining short-circuits the
ENTIRE access chain when the head returns null/undefined, so when
`extractErrorName` returns undefined the whole expression evaluates to
undefined without ever reaching `.replace()`. Verified empirically via
`const x = undefined; x?.toLowerCase().replace(/_/g, "")` returns
undefined with no crash.

Applying the suggested defensive `?.` before `.replace` anyway, since
it is semantically a no-op and explicit chaining at each hop is easier
for static analyzers to reason about.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 11:05:01 -04:00
ZeyuFu f357ed033a fix(runtime-fallback): classify more provider quota error names
Closes #3937.

Adds three small classification gaps to `classifyErrorType` so that
quota-exhaustion errors from a wider range of providers trigger
configured fallback chains instead of looping retry attempts:

- Normalize error names by stripping `_` and `-` so snake_case /
  SCREAMING_SNAKE_CASE provider names (`insufficient_quota`,
  `RESOURCE_EXHAUSTED`, `rate_limit_exceeded`) match the existing
  alphanumeric `.includes()` checks.
- Add `resourceexhausted` to the quota error-name allow-list to cover
  Google Generative AI's gRPC code 8 / `ResourceExhausted` surface.
- Add `/resource.?exhausted/i` to the quota message-pattern list so the
  same error surface is caught when the provider only sets a generic
  error name but puts the signal in the message.

Three new regression tests in
`quota-error-classifier.regression.test.ts` cover:

- Google `RESOURCE_EXHAUSTED` (gRPC error name + quota-shaped message)
- Google `ResourceExhausted` message form without HTTP status
- OpenAI snake_case `insufficient_quota` error name

No existing tests were touched; the underscore normalization preserves
all existing `.includes()` matches by rewriting the one underscore-bearing
literal (`ai_loadapikeyerror` → `ailoadapikeyerror`) so previously
matched names still resolve.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 10:28:05 -04:00
wjiuxing 149a83d703 feat: add Chinese quota patterns to classifyErrorType 2026-05-15 22:22:21 +09:00
Qihao 583fa2420f fix(runtime-fallback): classify localized balance failures 2026-05-11 11:06:06 +08:00
wenghuayang863 f3f72fc96f fix(runtime-fallback): also classify Volcano Engine errors as quota_exceeded
- 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.
2026-05-11 01:03:02 +08:00
MoerAI a22416d270 fix(error-classifier): classify credit balance too low as quota_exceeded for fallback (fixes #3571) 2026-05-06 17:17:23 +09:00
MoerAI 59493002e4 fix(error-classifier): match insufficient balance/funds as quota_exceeded 2026-04-22 18:47:16 +09:00
MoerAI 7488c527df fix(runtime-fallback): trigger fallback on quota/credit exhaustion (fixes #3519) 2026-04-21 18:17:22 +09:00
YeonGyu-Kim 2c6a161441 test(runtime-fallback): fix OpenAI auto-retry test expectations
- Add timeout_seconds to mock config for auto-retry signal detection

- Add 'usage limit' pattern to quota_exceeded error classification

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-08 13:40:40 +09:00
YeonGyu-Kim 61083d499d fix(oauth+errors): OAuth silent refresh, quota STOP patterns, compaction loop cap
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.
2026-04-06 17:40:12 +09:00
YeonGyu-Kim e6d0484e57 Merge pull request #2710 from MoerAI/fix/rate-limit-hang
fix(runtime-fallback): detect bare 429 rate-limit signals (fixes #2677)
2026-03-26 08:53:41 +09:00
MoerAI f16d55ad95 fix: add errorName-based quota detection and strengthen test coverage 2026-03-23 15:19:09 +09:00
MoerAI 62d2704009 fix(runtime-fallback): detect prettified quota errors without HTTP status codes (fixes #2747) 2026-03-23 10:34:22 +09:00
MoerAI 3773e370ec fix(runtime-fallback): detect bare 429 rate-limit signals (fixes #2677) 2026-03-20 11:00:00 +09:00
YeonGyu-Kim c5c7ba4eed perf: pre-compile regex patterns and optimize hot-path string operations
- error-classifier: pre-compile default retry pattern regex
- think-mode/detector: combine multilingual patterns into single regex
- parser: skip redundant toLowerCase on pre-lowered keywords
- edit-operations: use fast arraysEqual instead of JSON comparison
- hash-computation: optimize streaming line extraction with index tracking
2026-03-18 14:19:23 +09:00
Ravi Tharuma de66f1f397 fix(runtime-fallback): prefer numeric status codes over non-numeric in extraction chain
The nullish-coalescing chain could stop at a non-numeric value (e.g.
status: "error"), preventing deeper nested numeric statusCode values
from being reached. Switch to Array.find() with a type guard to always
select the first numeric value.

Adds 11 tests for extractStatusCode covering: top-level, nested
(data/error/cause), non-numeric skip, fallback to regex, and
precedence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 13:51:23 +01:00
Ravi Tharuma 24a0f7b032 fix(runtime-fallback): extract status code from nested AI SDK errors
AI SDK wraps HTTP status codes inside error.error.statusCode (e.g., AI_APICallError). The current extractStatusCode only checks the top level, missing these nested codes.

This caused runtime-fallback to skip retryable errors like 400, 500, 504 because it couldn't find the status code.

Fixes #2617
2026-03-16 13:04:14 +01:00
YeonGyu-Kim ba86ef0eea fix: enable runtime fallback for delegated child sessions (#2357) 2026-03-12 13:39:04 +09:00
Ravi Tharuma c598afa521 Address PR review follow-ups for retry status handling 2026-03-09 12:43:30 +09:00
Ravi Tharuma eab5be666d Fix cooldown fallback switching across model/runtime fallback hooks 2026-03-09 12:43:01 +09:00
IYODA Atsushi fcaaa11a06 fix(runtime-fallback): detect type:error message parts for fallback progression 2026-02-21 02:42:20 +09:00
Youngbin Kim b6456faea8 refactor(runtime-fallback): decompose index.ts into focused modules
Split 1021-line index.ts into 10 focused modules per project conventions.

New structure:

- error-classifier.ts: error analysis with dynamic status code extraction

- agent-resolver.ts: agent detection utilities

- fallback-state.ts: state management and cooldown logic

- fallback-models.ts: model resolution from config

- auto-retry.ts: retry helpers with mutual recursion support

- event-handler.ts: session lifecycle events

- message-update-handler.ts: message.updated event handling

- chat-message-handler.ts: chat message interception

- hook.ts: main factory with proper cleanup

- types.ts: updated with HookDeps interface

- index.ts: 2-line barrel re-export

Embedded fixes:

- Fix setInterval leak with .unref()

- Replace require() with ESM import

- Add log warning on invalid model format

- Update sessionLastAccess on normal traffic

- Make extractStatusCode dynamic from config

- Remove unused SessionErrorInfo type

All 61 tests pass without modification.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-21 02:42:12 +09:00