Skip to content

Commit 90749d7

Browse files
committed
fix(agents): truncate tool results before overflow compaction
1 parent 65c5c3f commit 90749d7

2 files changed

Lines changed: 73 additions & 15 deletions

File tree

src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -239,15 +239,10 @@ describe("overflow compaction in run loop", () => {
239239
expectLogIncludes(mockedLog.warn, "auto-compaction failed");
240240
});
241241

242-
it("falls back to tool-result truncation and retries when oversized results are detected", async () => {
242+
it("tries tool-result truncation before compaction and retries when oversized results are detected", async () => {
243243
queueOverflowAttemptWithOversizedToolOutput(mockedRunEmbeddedAttempt, makeOverflowError());
244244
mockedRunEmbeddedAttempt.mockResolvedValueOnce(makeAttemptResult({ promptError: null }));
245245

246-
mockedCompactDirect.mockResolvedValueOnce({
247-
ok: false,
248-
compacted: false,
249-
reason: "nothing to compact",
250-
});
251246
mockedSessionLikelyHasOversizedToolResults.mockReturnValue(true);
252247
mockedTruncateOversizedToolResultsInSession.mockResolvedValueOnce({
253248
truncated: true,
@@ -256,7 +251,7 @@ describe("overflow compaction in run loop", () => {
256251

257252
const result = await runEmbeddedPiAgent(baseParams);
258253

259-
expect(mockedCompactDirect).toHaveBeenCalledTimes(1);
254+
expect(mockedCompactDirect).not.toHaveBeenCalled();
260255
expect(
261256
requireMockCallArg(mockedSessionLikelyHasOversizedToolResults, 0).contextWindowTokens,
262257
).toBe(200000);
@@ -268,7 +263,7 @@ describe("overflow compaction in run loop", () => {
268263
expect(result.meta.error).toBeUndefined();
269264
});
270265

271-
it("retries after fallback truncation for a mixed oversized-plus-aggregate tool tail", async () => {
266+
it("retries after pre-compaction truncation for a mixed oversized-plus-aggregate tool tail", async () => {
272267
mockedRunEmbeddedAttempt
273268
.mockResolvedValueOnce(
274269
makeAttemptResult({
@@ -291,11 +286,6 @@ describe("overflow compaction in run loop", () => {
291286
)
292287
.mockResolvedValueOnce(makeAttemptResult({ promptError: null }));
293288

294-
mockedCompactDirect.mockResolvedValueOnce({
295-
ok: false,
296-
compacted: false,
297-
reason: "nothing to compact",
298-
});
299289
mockedSessionLikelyHasOversizedToolResults.mockReturnValue(true);
300290
mockedTruncateOversizedToolResultsInSession.mockResolvedValueOnce({
301291
truncated: true,
@@ -304,15 +294,42 @@ describe("overflow compaction in run loop", () => {
304294

305295
const result = await runEmbeddedPiAgent(baseParams);
306296

307-
expect(mockedCompactDirect).toHaveBeenCalledTimes(1);
297+
expect(mockedCompactDirect).not.toHaveBeenCalled();
308298
const oversizedArgs = requireMockCallArg(mockedSessionLikelyHasOversizedToolResults, 0);
309299
const messages = oversizedArgs.messages as Array<{ role?: string }>;
310300
expect(messages.filter((message) => message.role === "toolResult")).toHaveLength(3);
311301
expect(requireMockCallArg(mockedTruncateOversizedToolResultsInSession, 0).sessionFile).toBe(
312302
"/tmp/session.json",
313303
);
314304
expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(2);
315-
expectLogIncludes(mockedLog.info, "Truncated 2 tool result(s)");
305+
expect(result.meta.error).toBeUndefined();
306+
});
307+
308+
it("retries compaction when pre-compaction tool-result truncation does not help", async () => {
309+
queueOverflowAttemptWithOversizedToolOutput(mockedRunEmbeddedAttempt, makeOverflowError());
310+
mockedRunEmbeddedAttempt.mockResolvedValueOnce(makeAttemptResult({ promptError: null }));
311+
312+
mockedSessionLikelyHasOversizedToolResults.mockReturnValue(true);
313+
mockedTruncateOversizedToolResultsInSession.mockResolvedValueOnce({
314+
truncated: false,
315+
truncatedCount: 0,
316+
reason: "no reducible tool results",
317+
});
318+
mockedCompactDirect.mockResolvedValueOnce(
319+
makeCompactionSuccess({
320+
summary: "Compacted after truncation miss",
321+
firstKeptEntryId: "entry-9",
322+
tokensBefore: 150000,
323+
}),
324+
);
325+
326+
const result = await runEmbeddedPiAgent(baseParams);
327+
328+
expect(mockedTruncateOversizedToolResultsInSession).toHaveBeenCalledTimes(1);
329+
expect(mockedCompactDirect).toHaveBeenCalledTimes(1);
330+
expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(2);
331+
expectLogIncludes(mockedLog.warn, "Tool result truncation did not help before compaction");
332+
expectLogIncludes(mockedLog.info, "auto-compaction succeeded");
316333
expect(result.meta.error).toBeUndefined();
317334
});
318335

src/agents/pi-embedded-runner/run.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,47 @@ export async function runEmbeddedPiAgent(
17361736
}
17371737
continue;
17381738
}
1739+
if (!toolResultTruncationAttempted && !preflightRecovery) {
1740+
const contextWindowTokens = ctxInfo.tokens;
1741+
const toolResultMaxChars = resolveLiveToolResultMaxChars({
1742+
contextWindowTokens,
1743+
cfg: params.config,
1744+
agentId: sessionAgentId,
1745+
});
1746+
const hasOversized = attempt.messagesSnapshot
1747+
? sessionLikelyHasOversizedToolResults({
1748+
messages: attempt.messagesSnapshot,
1749+
contextWindowTokens,
1750+
maxCharsOverride: toolResultMaxChars,
1751+
})
1752+
: false;
1753+
1754+
if (hasOversized) {
1755+
toolResultTruncationAttempted = true;
1756+
log.warn(
1757+
`[context-overflow-recovery] Attempting tool result truncation before compaction for ${provider}/${modelId} ` +
1758+
`(contextWindow=${contextWindowTokens} tokens)`,
1759+
);
1760+
const truncResult = await truncateOversizedToolResultsInSession({
1761+
sessionFile: activeSessionFile,
1762+
contextWindowTokens,
1763+
maxCharsOverride: toolResultMaxChars,
1764+
sessionId: activeSessionId,
1765+
sessionKey: params.sessionKey,
1766+
config: params.config,
1767+
});
1768+
if (truncResult.truncated) {
1769+
log.info(
1770+
`[context-overflow-recovery] Truncated ${truncResult.truncatedCount} tool result(s); retrying prompt`,
1771+
);
1772+
continue;
1773+
}
1774+
log.warn(
1775+
`[context-overflow-recovery] Tool result truncation did not help before compaction: ${truncResult.reason ?? "unknown"}`,
1776+
);
1777+
}
1778+
}
1779+
17391780
// Attempt explicit overflow compaction only when this attempt did not
17401781
// already auto-compact.
17411782
if (

0 commit comments

Comments
 (0)