Skip to content

Commit 7a22b3f

Browse files
SidSid-Qinjalehman
authored
feat(agents): flush reply pipeline before compaction wait (#35489)
Merged via squash. Prepared head SHA: 7dbbcc5 Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman
1 parent 6084c26 commit 7a22b3f

4 files changed

Lines changed: 16 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ Docs: https://docs.openclaw.ai
160160
- Discord/inbound timeout isolation: separate inbound worker timeout tracking from listener timeout budgets so queued Discord replies are no longer dropped when listener watchdog windows expire mid-run. (#36602) Thanks @dutifulbob.
161161
- Memory/doctor SecretRef handling: treat SecretRef-backed memory-search API keys as configured, and fail embedding setup with explicit unresolved-secret errors instead of crashing. (#36835) Thanks @joshavant.
162162
- Memory/flush default prompt: ban timestamped variant filenames during default memory flush runs so durable notes stay in the canonical daily `memory/YYYY-MM-DD.md` file. (#34951) thanks @zerone0x.
163+
- Agents/reply delivery timing: flush embedded Pi block replies before waiting on compaction retries so already-generated assistant replies reach channels before compaction wait completes. (#35489) thanks @Sid-Qin.
163164

164165
## 2026.3.2
165166

extensions/llm-task/src/llm-task-tool.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ async function loadRunEmbeddedPiAgent(): Promise<RunEmbeddedPiAgentFn> {
2626

2727
// Bundled install (built)
2828
// NOTE: there is no src/ tree in a packaged install. Prefer a stable internal entrypoint.
29-
const distModulePath = "../../../dist/extensionAPI.js";
30-
const mod = await import(distModulePath);
29+
const distExtensionApi = "../../../dist/extensionAPI.js";
30+
const mod = (await import(distExtensionApi)) as { runEmbeddedPiAgent?: unknown };
3131
// oxlint-disable-next-line typescript/no-explicit-any
3232
const fn = (mod as any).runEmbeddedPiAgent;
3333
if (typeof fn !== "function") {

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,14 @@ export async function runEmbeddedAttempt(
16881688
const preCompactionSessionId = activeSession.sessionId;
16891689

16901690
try {
1691+
// Flush buffered block replies before waiting for compaction so the
1692+
// user receives the assistant response immediately. Without this,
1693+
// coalesced/buffered blocks stay in the pipeline until compaction
1694+
// finishes — which can take minutes on large contexts (#35074).
1695+
if (params.onBlockReplyFlush) {
1696+
await params.onBlockReplyFlush();
1697+
}
1698+
16911699
await abortable(waitForCompactionRetry());
16921700
} catch (err) {
16931701
if (isRunnerAbortError(err)) {

src/agents/pi-embedded-subscribe.handlers.lifecycle.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ export function handleAgentEnd(ctx: EmbeddedPiSubscribeContext) {
7373
}
7474

7575
ctx.flushBlockReplyBuffer();
76+
// Flush the reply pipeline so the response reaches the channel before
77+
// compaction wait blocks the run. This mirrors the pattern used by
78+
// handleToolExecutionStart and ensures delivery is not held hostage to
79+
// long-running compaction (#35074).
80+
void ctx.params.onBlockReplyFlush?.();
7681

7782
ctx.state.blockState.thinking = false;
7883
ctx.state.blockState.final = false;

0 commit comments

Comments
 (0)