From d1b7e5ae9a92d53e97815305a1da8a99aeb29148 Mon Sep 17 00:00:00 2001 From: Joey Krug Date: Sat, 14 Mar 2026 18:07:18 -0400 Subject: [PATCH] fix: trigger timeout compaction for real timeouts --- .../run.timeout-triggered-compaction.test.ts | 16 +++++++++++++--- src/agents/pi-embedded-runner/run.ts | 9 +++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/agents/pi-embedded-runner/run.timeout-triggered-compaction.test.ts b/src/agents/pi-embedded-runner/run.timeout-triggered-compaction.test.ts index c5d4ea5d1ad..bccae68bfeb 100644 --- a/src/agents/pi-embedded-runner/run.timeout-triggered-compaction.test.ts +++ b/src/agents/pi-embedded-runner/run.timeout-triggered-compaction.test.ts @@ -198,7 +198,7 @@ describe("timeout-triggered compaction", () => { expect(result.payloads?.[0]?.text).toContain("timed out"); }); - it("does not attempt compaction when aborted", async () => { + it("still attempts compaction for timed-out attempts that set aborted", async () => { mockedRunEmbeddedAttempt.mockResolvedValueOnce( makeAttemptResult({ timedOut: true, @@ -208,10 +208,20 @@ describe("timeout-triggered compaction", () => { } as never, }), ); + mockedCompactDirect.mockResolvedValueOnce( + makeCompactionSuccess({ + summary: "timeout recovery compaction", + tokensBefore: 180000, + tokensAfter: 90000, + }), + ); + mockedRunEmbeddedAttempt.mockResolvedValueOnce(makeAttemptResult({ promptError: null })); - await runEmbeddedPiAgent(overflowBaseRunParams); + const result = await runEmbeddedPiAgent(overflowBaseRunParams); - expect(mockedCompactDirect).not.toHaveBeenCalled(); + expect(mockedCompactDirect).toHaveBeenCalledTimes(1); + expect(mockedRunEmbeddedAttempt).toHaveBeenCalledTimes(2); + expect(result.meta.error).toBeUndefined(); }); it("does not attempt compaction when timedOutDuringCompaction is true", async () => { diff --git a/src/agents/pi-embedded-runner/run.ts b/src/agents/pi-embedded-runner/run.ts index e723c513384..1a39f383ff8 100644 --- a/src/agents/pi-embedded-runner/run.ts +++ b/src/agents/pi-embedded-runner/run.ts @@ -1097,7 +1097,7 @@ export async function runEmbeddedPiAgent( // ── Timeout-triggered compaction ────────────────────────────────── // When the LLM times out with high context usage, compact before // retrying to break the death spiral of repeated timeouts. - if (timedOut && !aborted && !timedOutDuringCompaction) { + if (timedOut && !timedOutDuringCompaction) { // Only consider prompt-side tokens here. API totals include output // tokens, which can make a long generation look like high context // pressure even when the prompt itself was small. @@ -1112,12 +1112,14 @@ export async function runEmbeddedPiAgent( ); } else if (tokenUsedRatio > 0.65) { const timeoutDiagId = createCompactionDiagId(); + const nextTimeoutCompactionAttempt = timeoutCompactionAttempts + 1; log.warn( `[timeout-compaction] LLM timed out with high prompt token usage (${Math.round(tokenUsedRatio * 100)}%); ` + `attempting compaction before retry diagId=${timeoutDiagId}`, ); let timeoutCompactResult: Awaited>; await runOwnsCompactionBeforeHook("timeout recovery"); + timeoutCompactionAttempts = nextTimeoutCompactionAttempt; try { timeoutCompactResult = await contextEngine.compact({ sessionId: params.sessionId, @@ -1147,8 +1149,8 @@ export async function runEmbeddedPiAgent( ownerNumbers: params.ownerNumbers, trigger: "timeout_recovery", diagId: timeoutDiagId, - attempt: 1, - maxAttempts: 1, + attempt: nextTimeoutCompactionAttempt, + maxAttempts: MAX_TIMEOUT_COMPACTION_ATTEMPTS, }, }); } catch (compactErr) { @@ -1158,7 +1160,6 @@ export async function runEmbeddedPiAgent( timeoutCompactResult = { ok: false, compacted: false, reason: String(compactErr) }; } await runOwnsCompactionAfterHook("timeout recovery", timeoutCompactResult); - timeoutCompactionAttempts += 1; if (timeoutCompactResult.compacted) { autoCompactionCount += 1; log.info(