From 9e67e1125ba3bfdbe2fa68bec505ed1d96b66b1c Mon Sep 17 00:00:00 2001 From: chenxingzhen Date: Fri, 20 Mar 2026 17:35:39 +0800 Subject: [PATCH] fix: add profile cooldown bookkeeping and mutating-tool side-effect warning 1. run.ts: call maybeMarkAuthProfileFailure before early return in incomplete turn detection, so the exhausted credential enters cooldown and multi-profile setups rotate to a healthy profile on the next turn 2. run.ts: check attempt.toolMetas for mutating tools and warn users about potential side-effects when tools already executed before the turn was interrupted, preventing blind retries of mutating actions Addresses third round of review feedback on PR #50930. Co-Authored-By: Claude Opus 4.6 --- src/agents/pi-embedded-runner/run.ts | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/agents/pi-embedded-runner/run.ts b/src/agents/pi-embedded-runner/run.ts index 962f6c87b95..a8cd1799b75 100644 --- a/src/agents/pi-embedded-runner/run.ts +++ b/src/agents/pi-embedded-runner/run.ts @@ -64,6 +64,7 @@ import { type FailoverReason, } from "../pi-embedded-helpers.js"; import { ensureRuntimePluginsLoaded } from "../runtime-plugins.js"; +import { isLikelyMutatingToolName } from "../tool-mutation.js"; import { derivePromptTokens, normalizeUsage, type UsageLike } from "../usage.js"; import { redactRunIdentifier, resolveRunWorkspaceDir } from "../workspace-run.js"; import { buildEmbeddedCompactionRuntimeContext } from "./compaction-runtime-context.js"; @@ -1630,10 +1631,32 @@ export async function runEmbeddedPiAgent( `incomplete turn detected: runId=${params.runId} sessionId=${params.sessionId} ` + `stopReason=${incompleteStopReason} payloads=0 — surfacing error to user`, ); + + // Mark the failing profile for cooldown so multi-profile setups + // rotate away from the exhausted credential on the next turn. + if (lastProfileId) { + const failoverReason = classifyFailoverReason( + lastAssistant?.errorMessage ?? "", + ); + await maybeMarkAuthProfileFailure({ + profileId: lastProfileId, + reason: resolveAuthProfileFailureReason(failoverReason), + }); + } + + // Warn about potential side-effects when mutating tools executed + // before the turn was interrupted, so users don't blindly retry. + const hadMutatingTools = attempt.toolMetas.some((t) => + isLikelyMutatingToolName(t.toolName), + ); + const errorText = hadMutatingTools + ? "⚠️ Agent couldn't generate a response. Note: some tool actions may have already been executed — please verify before retrying." + : "⚠️ Agent couldn't generate a response. Please try again."; + return { payloads: [ { - text: "⚠️ Agent couldn't generate a response. Please try again.", + text: errorText, isError: true, }, ],