diff --git a/src/agents/pi-embedded-runner/compact.ts b/src/agents/pi-embedded-runner/compact.ts index 2dc4c5325..c625b0413 100644 --- a/src/agents/pi-embedded-runner/compact.ts +++ b/src/agents/pi-embedded-runner/compact.ts @@ -35,6 +35,7 @@ import { validateAnthropicTurns, validateGeminiTurns, } from "../pi-embedded-helpers.js"; +import { sanitizeToolUseResultPairing } from "../session-transcript-repair.js"; import { ensurePiCompactionReserveTokens, resolveCompactionReserveTokensFloor, @@ -421,8 +422,19 @@ export async function compactEmbeddedPiSessionDirect( validated, getDmHistoryLimitFromSessionKey(params.sessionKey, params.config), ); - if (limited.length > 0) { - session.agent.replaceMessages(limited); + // Fix: Repair tool_use/tool_result pairings AFTER truncation (issue #4650) + const repaired = transcriptPolicy.repairToolUseResultPairing + ? sanitizeToolUseResultPairing(limited) + : limited; + // Re-run turn validation after limiting (issue #4650) to merge consecutive assistant/user messages + const revalidatedGemini = transcriptPolicy.validateGeminiTurns + ? validateGeminiTurns(repaired) + : repaired; + const revalidatedAnthropic = transcriptPolicy.validateAnthropicTurns + ? validateAnthropicTurns(revalidatedGemini) + : revalidatedGemini; + if (revalidatedAnthropic.length > 0) { + session.agent.replaceMessages(revalidatedAnthropic); } const result = await session.compact(params.customInstructions); // Estimate tokens after compaction by summing token estimates for remaining messages diff --git a/src/agents/pi-embedded-runner/run/attempt.ts b/src/agents/pi-embedded-runner/run/attempt.ts index 622bdb7f4..89cffecd2 100644 --- a/src/agents/pi-embedded-runner/run/attempt.ts +++ b/src/agents/pi-embedded-runner/run/attempt.ts @@ -536,11 +536,20 @@ export async function runEmbeddedAttempt( validated, getDmHistoryLimitFromSessionKey(params.sessionKey, params.config), ); - // Fix: Repair tool_use/tool_result pairings AFTER truncation (issue #4367) - const repaired = sanitizeToolUseResultPairing(limited); - cacheTrace?.recordStage("session:limited", { messages: repaired }); - if (repaired.length > 0) { - activeSession.agent.replaceMessages(repaired); + // Fix: Repair tool_use/tool_result pairings AFTER truncation (issue #4367, #4650) + const repaired = transcriptPolicy.repairToolUseResultPairing + ? sanitizeToolUseResultPairing(limited) + : limited; + // Re-run turn validation after limiting (issue #4650) to merge consecutive assistant/user messages + const revalidatedGemini = transcriptPolicy.validateGeminiTurns + ? validateGeminiTurns(repaired) + : repaired; + const revalidatedAnthropic = transcriptPolicy.validateAnthropicTurns + ? validateAnthropicTurns(revalidatedGemini) + : revalidatedGemini; + cacheTrace?.recordStage("session:limited", { messages: revalidatedAnthropic }); + if (revalidatedAnthropic.length > 0) { + activeSession.agent.replaceMessages(revalidatedAnthropic); } } catch (err) { sessionManager.flushPendingToolResults?.();