diff --git a/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts b/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts index c5b9555a3..b3c517356 100644 --- a/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +++ b/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts @@ -100,16 +100,19 @@ export async function handleAgentEnd( // errorMessage looks uninformative. const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : ""; const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim()); - let errorMsg = rawErrorMsg; + // #3588: When errorMessage is uninformative, extract the real error from + // the assistant message text content for display purposes only. + // Classification still uses rawErrorMsg to avoid false positives from prose. + let displayMsg = rawErrorMsg; if (isUseless && "content" in lastMsg && Array.isArray(lastMsg.content)) { const textBlock = lastMsg.content.find((b: any) => b.type === "text" && b.text); - if (textBlock) errorMsg = (textBlock as any).text.slice(0, 300); + if (textBlock) displayMsg = (textBlock as any).text.slice(0, 300); } - const errorDetail = errorMsg ? `: ${errorMsg}` : ""; + const errorDetail = displayMsg ? `: ${displayMsg}` : ""; const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined; - // ── 1. Classify ────────────────────────────────────────────────────── - const cls = classifyError(errorMsg, explicitRetryAfterMs); + // ── 1. Classify using rawErrorMsg to avoid prose false-positives ──── + const cls = classifyError(rawErrorMsg, explicitRetryAfterMs); // Cap rate-limit backoff for CLI-style providers (openai-codex, google-gemini-cli) // which use per-user quotas with shorter windows (#2922).