#6268: fix: add timeout to compaction retry to prevent session lockout
agents
## Summary
Fixes #5784
When auto-compaction fails and triggers a retry (`willRetry=true`), the retry promise in `waitForCompactionRetry()` could hang forever if the SDK's internal retry never completes. This causes:
- Session permanently locked (`active=true`)
- Lock file never released
- Gateway restart is the only recovery
## Solution
This fix adds a configurable timeout (default 60 seconds) to `waitForCompactionRetry()`. When the timeout is reached:
1. Force-resolves the pending promise
2. Cleans up compaction state (`pendingCompactionRetry`, `compactionInFlight`)
3. Logs a warning
4. Returns `{ timedOut: true }` so callers can handle it
The session can then complete normally instead of hanging forever.
## Changes
- `src/agents/pi-embedded-subscribe.ts`: Add timeout parameter and timeout race logic to `waitForCompactionRetry()`
- `src/agents/pi-embedded-runner/run/attempt.ts`: Pass 60s timeout and log warning on timeout
- `src/agents/pi-embedded-subscribe.compaction-timeout.test.ts`: Add tests for timeout behavior
## Testing
Added unit tests that verify:
- Timeout fires after specified duration
- State is properly cleaned up on timeout
- Normal completion still works before timeout
- Default timeout is 60 seconds
## Backward Compatibility
The return type of `waitForCompactionRetry()` changed from `Promise<void>` to `Promise<{ timedOut?: boolean }>`. Existing `.then()` callbacks will still work, but callers may want to check `result.timedOut` to handle the timeout case.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
Adds a timeout path to `subscribeEmbeddedPiSession().waitForCompactionRetry()` (default 60s) so embedded runs don’t hang forever if the SDK’s internal compaction retry never completes, and wires the new result into the embedded attempt runner with an extra warning log. Includes new vitest coverage for timeout vs normal completion paths.
Overall this fits cleanly into the existing compaction retry bookkeeping in `pi-embedded-subscribe.ts` (the `pendingCompactionRetry` / `compactionInFlight` gate and shared promise resolver) and addresses the session lockout failure mode described in #5784.
<h3>Confidence Score: 3/5</h3>
- This PR is likely safe to merge, but the timeout may not apply in some call timing scenarios due to when waiting begins.
- Core change is localized and covered by tests, but `waitForCompactionRetry()` still resolves immediately if compaction starts after the next microtask, which can bypass both waiting and the new timeout in some real event-orderings.
- src/agents/pi-embedded-subscribe.ts
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#17445: fix(pi-embedded): add aggregate timeout to compaction retry + harde...
by joeykrug · 2026-02-15
84.1%
#5467: Fix: make embedded compaction wait abortable
by yoyooyooo · 2026-01-31
83.4%
#10505: feat(compaction): add timeout, model override, and diagnostic logging
by thebtf · 2026-02-06
79.1%
#16915: fix: await compaction hooks with timeout to prevent cross-session d...
by maximalmargin · 2026-02-15
78.6%
#10636: fix: setTimeout integer overflow causing server crash
by devmangel · 2026-02-06
77.4%
#10273: fix(agents): detect and auto-compact mid-run context overflow
by terryops · 2026-02-06
77.2%
#17721: fix: abort child run on subagent timeout + retry with backoff + sta...
by IrriVisionTechnologies · 2026-02-16
77.0%
#5593: fix(pi-embedded-runner): force-clear stuck embedded runs after timeout
by grassX1998 · 2026-01-31
76.7%
#4042: agents: add proactive compaction before request
by freedomzt · 2026-01-29
76.6%
#12477: fix(agents): prevent TimeoutOverflowWarning when timeout is disabled
by skylarkoo7 · 2026-02-09
76.5%