Prefer recent aggregate tool-result truncation

This commit is contained in:
Tak Hoffman
2026-04-06 07:41:30 -05:00
committed by Peter Steinberger
parent 5e04b2d037
commit 4917009ac7
2 changed files with 47 additions and 1 deletions

View File

@@ -424,6 +424,46 @@ describe("truncateOversizedToolResultsInSession", () => {
).toBe(false);
});
it("prefers truncating newer aggregate tool-result entries before older larger ones", async () => {
const dir = await createTmpDir();
const sm = SessionManager.create(dir, dir);
sm.appendMessage(makeUserMessage("hello"));
sm.appendMessage(makeAssistantMessage("calling tools"));
const olderLarge = "older-large ".repeat(2_000);
const newerEnough = "newer-enough ".repeat(1_400);
sm.appendMessage(makeToolResult(olderLarge, "call_1"));
sm.appendMessage(makeToolResult(newerEnough, "call_2"));
const sessionFile = sm.getSessionFile()!;
const beforeBranch = SessionManager.open(sessionFile).getBranch();
const beforeToolResults = beforeBranch.filter(
(entry) => entry.type === "message" && entry.message.role === "toolResult",
);
const beforeTexts = beforeToolResults.map((entry) =>
entry.type === "message" ? getFirstToolResultText(entry.message) : "",
);
const result = await truncateOversizedToolResultsInSession({
sessionFile,
contextWindowTokens: 128_000,
});
expect(result.truncated).toBe(true);
expect(result.truncatedCount).toBe(1);
const afterBranch = SessionManager.open(sessionFile).getBranch();
const afterToolResults = afterBranch.filter(
(entry) => entry.type === "message" && entry.message.role === "toolResult",
);
const afterTexts = afterToolResults.map((entry) =>
entry.type === "message" ? getFirstToolResultText(entry.message) : "",
);
expect(afterTexts[0]).toBe(beforeTexts[0]);
expect(afterTexts[1]).not.toBe(beforeTexts[1]);
expect(afterTexts[1]).toContain("truncated");
});
it("allows persisted-session recovery truncation to shrink below the old 2k floor", async () => {
const dir = await createTmpDir();
const sm = SessionManager.create(dir, dir);

View File

@@ -288,6 +288,7 @@ function buildAggregateToolResultReplacements(params: {
(item.entry.message as { role?: string }).role === "toolResult",
)
.map((item) => ({
index: item.index,
entryId: item.entry.id,
message: item.entry.message,
textLength: getToolResultTextLength(item.entry.message),
@@ -306,7 +307,12 @@ function buildAggregateToolResultReplacements(params: {
let remainingReduction = totalChars - params.aggregateBudgetChars;
const replacements: Array<{ entryId: string; message: AgentMessage }> = [];
for (const candidate of candidates.toSorted((a, b) => b.textLength - a.textLength)) {
for (const candidate of candidates.toSorted((a, b) => {
if (a.index !== b.index) {
return b.index - a.index;
}
return b.textLength - a.textLength;
})) {
if (remainingReduction <= 0) {
break;
}