Agents: classify Anthropic api_error internal server failures for fallback
This commit is contained in:
@@ -21,6 +21,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Cron/Gateway: keep `cron.list` and `cron.status` responsive during startup catch-up by avoiding a long-held cron lock while missed jobs execute. (#23106) Thanks @jayleekr.
|
||||
- Gateway/Config reload: compare array-valued config paths structurally during diffing so unchanged `memory.qmd.paths` and `memory.qmd.scope.rules` no longer trigger false restart-required reloads. (#23185) Thanks @rex05ai.
|
||||
- TUI/Input: enable multiline-paste burst coalescing on macOS Terminal.app and iTerm so pasted blocks no longer submit line-by-line as separate messages. (#18809) Thanks @fwends.
|
||||
- Agents/Fallbacks: treat JSON payloads with `type: "api_error"` + `"Internal server error"` as transient failover errors so Anthropic 500-style failures trigger model fallback. (#23193) Thanks @jarvis-lane.
|
||||
- Gateway/Pairing: treat operator.admin pairing tokens as satisfying operator.write requests so legacy devices stop looping through scope-upgrade prompts introduced in 2026.2.19. (#23125, #23006) Thanks @vignesh07.
|
||||
- Memory/QMD: add optional `memory.qmd.mcporter` search routing so QMD `query/search/vsearch` can run through mcporter keep-alive flows (including multi-collection paths) to reduce cold starts, while keeping searches on agent-scoped QMD state for consistent recall. (#19617) Thanks @nicole-luxe and @vignesh07.
|
||||
- Chat/UI: strip inline reply/audio directive tags (`[[reply_to_current]]`, `[[reply_to:<id>]]`, `[[audio_as_voice]]`) from displayed chat history, live chat event output, and session preview snippets so control tags no longer leak into user-visible surfaces.
|
||||
|
||||
@@ -377,4 +377,11 @@ describe("classifyFailoverReason", () => {
|
||||
),
|
||||
).toBe("rate_limit");
|
||||
});
|
||||
it("classifies JSON api_error internal server failures as timeout", () => {
|
||||
expect(
|
||||
classifyFailoverReason(
|
||||
'{"type":"error","error":{"type":"api_error","message":"Internal server error"}}',
|
||||
),
|
||||
).toBe("timeout");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -686,6 +686,16 @@ export function isOverloadedErrorMessage(raw: string): boolean {
|
||||
return matchesErrorPatterns(raw, ERROR_PATTERNS.overloaded);
|
||||
}
|
||||
|
||||
function isJsonApiInternalServerError(raw: string): boolean {
|
||||
if (!raw) {
|
||||
return false;
|
||||
}
|
||||
const value = raw.toLowerCase();
|
||||
// Anthropic often wraps transient 500s in JSON payloads like:
|
||||
// {"type":"error","error":{"type":"api_error","message":"Internal server error"}}
|
||||
return value.includes('"type":"api_error"') && value.includes("internal server error");
|
||||
}
|
||||
|
||||
export function parseImageDimensionError(raw: string): {
|
||||
maxDimensionPx?: number;
|
||||
messageIndex?: number;
|
||||
@@ -794,6 +804,9 @@ export function classifyFailoverReason(raw: string): FailoverReason | null {
|
||||
// Treat transient 5xx provider failures as retryable transport issues.
|
||||
return "timeout";
|
||||
}
|
||||
if (isJsonApiInternalServerError(raw)) {
|
||||
return "timeout";
|
||||
}
|
||||
if (isRateLimitErrorMessage(raw)) {
|
||||
return "rate_limit";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user