mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-24 04:01:10 -04:00
fix(fallback): add insufficient_quota error classification
- Classify OpenAI insufficient_quota errors as rate_limit to trigger fallback - Add quota pattern matching in JSON error body parsing - Add quota string pattern matching for error messages - Remove premature success recording - stream might still error during iteration Note: Stream-time errors (errors during iteration) are not yet caught by fallback retry logic. This is a known limitation when errors occur mid-stream rather than at call time. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -126,6 +126,9 @@ export namespace FallbackChain {
|
||||
if (errorMessage.includes("rate") && errorMessage.includes("limit")) {
|
||||
return "rate_limit"
|
||||
}
|
||||
if (errorMessage.includes("insufficient_quota") || errorMessage.includes("quota")) {
|
||||
return "rate_limit"
|
||||
}
|
||||
if (errorMessage.includes("overloaded") || errorMessage.includes("capacity")) {
|
||||
return "rate_limit"
|
||||
}
|
||||
@@ -142,6 +145,10 @@ export namespace FallbackChain {
|
||||
if (json.error?.type === "too_many_requests" || json.error?.code?.includes("rate_limit")) {
|
||||
return "rate_limit"
|
||||
}
|
||||
// OpenAI insufficient_quota errors should trigger fallback
|
||||
if (json.error?.type === "insufficient_quota" || json.error?.code === "insufficient_quota") {
|
||||
return "rate_limit"
|
||||
}
|
||||
if (json.error?.type === "server_error" || json.error?.type === "overloaded_error") {
|
||||
return "unavailable"
|
||||
}
|
||||
@@ -160,6 +167,9 @@ export namespace FallbackChain {
|
||||
if (lowerMessage.includes("too many requests") || lowerMessage.includes("429")) {
|
||||
return "rate_limit"
|
||||
}
|
||||
if (lowerMessage.includes("insufficient_quota") || lowerMessage.includes("exceeded") && lowerMessage.includes("quota")) {
|
||||
return "rate_limit"
|
||||
}
|
||||
if (lowerMessage.includes("overloaded") || lowerMessage.includes("capacity")) {
|
||||
return "rate_limit"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { CircuitBreaker } from "./circuit-breaker"
|
||||
import { FallbackChain } from "./fallback-chain"
|
||||
import { ModelEquivalence } from "./equivalence"
|
||||
import z from "zod"
|
||||
import type { StreamTextResult, ToolSet } from "ai"
|
||||
|
||||
/**
|
||||
* Fallback Orchestrator - Main entry point for LLM streaming with automatic fallback.
|
||||
@@ -139,9 +140,9 @@ export namespace Fallback {
|
||||
model: currentModel,
|
||||
})
|
||||
|
||||
// Success - record it and emit event if fallback was used
|
||||
CircuitBreaker.recordSuccess(currentModel.providerID)
|
||||
|
||||
// Don't record success immediately - the stream might still error during iteration
|
||||
// The circuit breaker will learn from failures; success is the default state
|
||||
// We only emit fallback notification here since we got a stream back
|
||||
if (attempt > 0 && fallbackConfig.notifyOnFallback) {
|
||||
Bus.publish(Event.FallbackUsed, {
|
||||
sessionID: input.sessionID,
|
||||
|
||||
Reference in New Issue
Block a user