feat: notify user when context compaction starts and completes

During auto-compaction the agent goes silent for several seconds while
the context is summarised.  Users on every channel (Discord, Feishu,
Telegram, webchat …) had no indication that something was happening —
leading to confusion and duplicate messages.

Changes:
- agent-runner-execution.ts: listen for compaction phase='start' event
  and immediately deliver a "🧹 Compacting context..." notice via the
  existing onBlockReply callback.  This fires for every channel because
  onBlockReply is the universal in-run delivery path.
- agent-runner.ts: make the completion notice unconditional (was
  previously guarded behind verboseEnabled).  Non-verbose users now see
  " Context compacted (count N)."; verbose users continue to see the
  legacy "🧹 Auto-compaction complete (count N)." wording.

Why onBlockReply for start?
onBlockReply is already wired to every channel adapter and fires during
the live run, so the notice arrives in-band with zero new plumbing.
Using verboseNotices (appended after the run) would be too late and
would miss the start signal entirely.

Fixes: users seeing silent pauses of 5-15 s with no feedback during
compaction on any channel.
This commit is contained in:
chenpitang 2026-03-07 19:21:26 +08:00 committed by Josh Lehman
parent 5e417b44e1
commit f422d3363d
No known key found for this signature in database
GPG Key ID: D141B425AC7F876B
2 changed files with 17 additions and 3 deletions

View File

@ -394,11 +394,17 @@ export async function runAgentTurnWithFallback(params: {
await params.opts?.onToolStart?.({ name, phase });
}
}
// Track auto-compaction completion and notify UI layer.
// Track auto-compaction and notify higher layers.
if (evt.stream === "compaction") {
const phase = typeof evt.data.phase === "string" ? evt.data.phase : "";
if (phase === "start") {
await params.opts?.onCompactionStart?.();
if (params.opts?.onCompactionStart) {
await params.opts.onCompactionStart();
} else {
// Use the universal in-run block reply path so every
// channel sees a notice while compaction is pausing the run.
await params.opts?.onBlockReply?.({ text: "🧹 Compacting context..." });
}
}
const completed = evt.data?.completed === true;
if (phase === "end" && completed) {

View File

@ -697,8 +697,16 @@ export async function runReplyAgent(params: {
});
}
// Always notify the user when compaction completes — not just in verbose
// mode. The "🧹 Compacting context..." notice was already sent at start,
// so the completion message closes the loop for every user regardless of
// their verbose setting.
const suffix = typeof count === "number" ? ` (count ${count})` : "";
verboseNotices.push({ text: `✅ Context compacted${suffix}.` });
if (verboseEnabled) {
const suffix = typeof count === "number" ? ` (count ${count})` : "";
// Verbose mode already gets the completion — keep the legacy notice
// text only for verbose so power users see the traditional wording.
verboseNotices.pop();
verboseNotices.push({ text: `🧹 Auto-compaction complete${suffix}.` });
}
}