From 250f9e15f5afb4f9e580f8331fc4760b772568ff Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 2 Mar 2026 01:05:54 +0000 Subject: [PATCH] fix(agents): land #31007 from @HOYALIM Co-authored-by: Ho Lim --- CHANGELOG.md | 1 + ...pi-embedded-helpers.isbillingerrormessage.test.ts | 5 +++++ src/agents/pi-embedded-helpers/errors.ts | 12 ++++++++---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abe61b334f5..5905e06dc16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Agents/Failover reason classification: avoid false rate-limit classification from incidental `tpm` substrings by matching TPM as a standalone token/phrase and keeping auth-context errors on the auth path. Landed from contributor PR #31007 by @HOYALIM. Thanks @HOYALIM. - Slack/Announce target account routing: enable session-backed announce-target lookup for Slack so multi-account announces resolve the correct `accountId` instead of defaulting to bot-token context. Landed from contributor PR #31028 by @taw0002. Thanks @taw0002. - Tools/Edit workspace boundary errors: preserve the real `Path escapes workspace root` failure path instead of surfacing a misleading access/file-not-found error when editing outside workspace roots. Landed from contributor PR #31015 by @haosenwang1018. Thanks @haosenwang1018. - Sandbox/mkdirp boundary checks: allow directory-safe boundary validation for existing in-boundary subdirectories, preventing false `cannot create directories` failures in sandbox write mode. (#30610) Thanks @glitch418x. diff --git a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts index a109af6d89f..21751d15dc5 100644 --- a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts +++ b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts @@ -461,6 +461,11 @@ describe("classifyFailoverReason", () => { expect(classifyFailoverReason("invalid api key")).toBe("auth"); expect(classifyFailoverReason("no credentials found")).toBe("auth"); expect(classifyFailoverReason("no api key found")).toBe("auth"); + expect( + classifyFailoverReason( + 'No API key found for provider "openai". Auth store: /tmp/openclaw-agent-abc/auth-profiles.json (agentDir: /tmp/openclaw-agent-abc).', + ), + ).toBe("auth"); expect(classifyFailoverReason("You have insufficient permissions for this operation.")).toBe( "auth", ); diff --git a/src/agents/pi-embedded-helpers/errors.ts b/src/agents/pi-embedded-helpers/errors.ts index 246f6c0ad24..5f8d70e3bbc 100644 --- a/src/agents/pi-embedded-helpers/errors.ts +++ b/src/agents/pi-embedded-helpers/errors.ts @@ -47,6 +47,11 @@ function isReasoningConstraintErrorMessage(raw: string): boolean { ); } +function hasRateLimitTpmHint(raw: string): boolean { + const lower = raw.toLowerCase(); + return /\btpm\b/i.test(lower) || lower.includes("tokens per minute"); +} + export function isContextOverflowError(errorMessage?: string): boolean { if (!errorMessage) { return false; @@ -54,7 +59,7 @@ export function isContextOverflowError(errorMessage?: string): boolean { const lower = errorMessage.toLowerCase(); // Groq uses 413 for TPM (tokens per minute) limits, which is a rate limit, not context overflow. - if (lower.includes("tpm") || lower.includes("tokens per minute")) { + if (hasRateLimitTpmHint(errorMessage)) { return false; } @@ -103,8 +108,7 @@ export function isLikelyContextOverflowError(errorMessage?: string): boolean { } // Groq uses 413 for TPM (tokens per minute) limits, which is a rate limit, not context overflow. - const lower = errorMessage.toLowerCase(); - if (lower.includes("tpm") || lower.includes("tokens per minute")) { + if (hasRateLimitTpmHint(errorMessage)) { return false; } @@ -622,7 +626,7 @@ const ERROR_PATTERNS = { "quota exceeded", "resource_exhausted", "usage limit", - "tpm", + /\btpm\b/i, "tokens per minute", ], overloaded: [