fix(history): re-repair tool_use/tool_result pairing after truncation
limitHistoryTurns() can slice in the middle of a tool_use/tool_result pair, leaving orphaned tool_result blocks that the Anthropic API rejects with "unexpected tool_use_id found in tool_result blocks". Call sanitizeToolUseResultPairing() after truncation (only when truncation actually removed messages) to repair any broken pairs. Applied to both attempt.ts and compact.ts code paths. Fixes #4367
This commit is contained in:
parent
9025da2296
commit
adfd063b37
@ -58,6 +58,7 @@ import {
|
|||||||
sanitizeToolsForGoogle,
|
sanitizeToolsForGoogle,
|
||||||
} from "./google.js";
|
} from "./google.js";
|
||||||
import { getDmHistoryLimitFromSessionKey, limitHistoryTurns } from "./history.js";
|
import { getDmHistoryLimitFromSessionKey, limitHistoryTurns } from "./history.js";
|
||||||
|
import { sanitizeToolUseResultPairing } from "../session-transcript-repair.js";
|
||||||
import { resolveGlobalLane, resolveSessionLane } from "./lanes.js";
|
import { resolveGlobalLane, resolveSessionLane } from "./lanes.js";
|
||||||
import { log } from "./logger.js";
|
import { log } from "./logger.js";
|
||||||
import { buildModelAliasLines, resolveModel } from "./model.js";
|
import { buildModelAliasLines, resolveModel } from "./model.js";
|
||||||
@ -417,10 +418,14 @@ export async function compactEmbeddedPiSessionDirect(
|
|||||||
const validated = transcriptPolicy.validateAnthropicTurns
|
const validated = transcriptPolicy.validateAnthropicTurns
|
||||||
? validateAnthropicTurns(validatedGemini)
|
? validateAnthropicTurns(validatedGemini)
|
||||||
: validatedGemini;
|
: validatedGemini;
|
||||||
const limited = limitHistoryTurns(
|
const truncated = limitHistoryTurns(
|
||||||
validated,
|
validated,
|
||||||
getDmHistoryLimitFromSessionKey(params.sessionKey, params.config),
|
getDmHistoryLimitFromSessionKey(params.sessionKey, params.config),
|
||||||
);
|
);
|
||||||
|
// Re-repair tool_use/tool_result pairing after truncation, since
|
||||||
|
// limitHistoryTurns may slice in the middle of a paired exchange.
|
||||||
|
const limited =
|
||||||
|
truncated.length < validated.length ? sanitizeToolUseResultPairing(truncated) : truncated;
|
||||||
if (limited.length > 0) {
|
if (limited.length > 0) {
|
||||||
session.agent.replaceMessages(limited);
|
session.agent.replaceMessages(limited);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,7 @@ import {
|
|||||||
sanitizeSessionHistory,
|
sanitizeSessionHistory,
|
||||||
sanitizeToolsForGoogle,
|
sanitizeToolsForGoogle,
|
||||||
} from "../google.js";
|
} from "../google.js";
|
||||||
|
import { sanitizeToolUseResultPairing } from "../../session-transcript-repair.js";
|
||||||
import { getDmHistoryLimitFromSessionKey, limitHistoryTurns } from "../history.js";
|
import { getDmHistoryLimitFromSessionKey, limitHistoryTurns } from "../history.js";
|
||||||
import { log } from "../logger.js";
|
import { log } from "../logger.js";
|
||||||
import { buildModelAliasLines } from "../model.js";
|
import { buildModelAliasLines } from "../model.js";
|
||||||
@ -531,10 +532,14 @@ export async function runEmbeddedAttempt(
|
|||||||
const validated = transcriptPolicy.validateAnthropicTurns
|
const validated = transcriptPolicy.validateAnthropicTurns
|
||||||
? validateAnthropicTurns(validatedGemini)
|
? validateAnthropicTurns(validatedGemini)
|
||||||
: validatedGemini;
|
: validatedGemini;
|
||||||
const limited = limitHistoryTurns(
|
const truncated = limitHistoryTurns(
|
||||||
validated,
|
validated,
|
||||||
getDmHistoryLimitFromSessionKey(params.sessionKey, params.config),
|
getDmHistoryLimitFromSessionKey(params.sessionKey, params.config),
|
||||||
);
|
);
|
||||||
|
// Re-repair tool_use/tool_result pairing after truncation, since
|
||||||
|
// limitHistoryTurns may slice in the middle of a paired exchange.
|
||||||
|
const limited =
|
||||||
|
truncated.length < validated.length ? sanitizeToolUseResultPairing(truncated) : truncated;
|
||||||
cacheTrace?.recordStage("session:limited", { messages: limited });
|
cacheTrace?.recordStage("session:limited", { messages: limited });
|
||||||
if (limited.length > 0) {
|
if (limited.length > 0) {
|
||||||
activeSession.agent.replaceMessages(limited);
|
activeSession.agent.replaceMessages(limited);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user