-
-
Notifications
You must be signed in to change notification settings - Fork 69.2k
Reply generated but not delivered when compaction triggers session rollover #47335
Description
Bug Description
When a session approaches context limits (~85% usage) and auto-compaction triggers with willRetry=true (overflow recovery), the LLM generates a reply that is visible in the session transcript (stopReason: "stop"), but the reply is never delivered to the messaging channel (Discord, Telegram, etc.).
Root Cause
The existing fix in 7a22b3fa0 (#35489) added an onBlockReplyFlush() call before waitForCompactionRetryWithAggregateTimeout() in attempt.ts. This correctly flushes the first reply's block streaming pipeline before the compaction wait begins.
However, when compaction retries (willRetry=true), the SDK internally runs a new agent loop via setTimeout(() => this.agent.continue()). This retry generates a new reply with its own block replies streamed through the same subscriber pipeline. The event flow is:
- Retry's
agent_endfires →handleAgentEndcallsflushBlockReplyBuffer()(sync) +void onBlockReplyFlush()(fire-and-forget) handleAgentEndthen callsresolveCompactionRetry()which synchronously resolves the compaction wait promisewaitForCompactionRetryWithAggregateTimeoutinattempt.tsunblocks- The attempt continues and returns — but
onBlockReplyFlush()from step 1 hasn't completed yet!
Since didStream() is true (from the first reply's block streaming), shouldDropFinalPayloads suppresses the final payload assembly. The retry's block replies are still in-flight in the async pipeline flush. Result: the reply is recorded in the transcript but never delivered to the user.
Proposed Fix
Add an idempotent onBlockReplyFlush() call after waitForCompactionRetryWithAggregateTimeout resolves, before the attempt continues. This ensures both the original and retry reply pipelines are fully drained. The call is harmless when compaction doesn't retry (flushing an already-flushed pipeline is a no-op).
Related
- feat(agents): flush reply pipeline before compaction wait #35489 /
7a22b3fa0— original fix for in-run compaction flush (covers non-retry case) handleAgentEndusesvoid onBlockReplyFlush()(fire-and-forget) — correct for the event handler context, but means the compaction retry resolution races with the flush