From 52012dd43cc7e50256cd8f42b0bbd646edf860e4 Mon Sep 17 00:00:00 2001 From: dj-oyu <68707227+dj-oyu@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:12:19 +0900 Subject: [PATCH] fix: streaming preview shares task status bubble for background tasks Two issues fixed: 1. Streaming preview (IsStatus) created a separate bubble from task completion (IsTaskStatus) because they use different tracking maps (statusMsgIDs vs taskMsgIDs). For background tasks, streaming preview now uses IsTaskStatus with the same TaskID so all updates share a single bubble. 2. HEARTBEAT_OK was included in the task completion message because it didn't match defaultResponse. Added explicit exclusion so the completion shows just "Task completed (Xs)" without the sentinel. Co-Authored-By: Claude Opus 4.6 --- pkg/agent/loop.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 490456ed8..62012b461 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -1063,7 +1063,7 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt if opts.TaskID != "" { elapsed := time.Since(task.StartedAt) completionMsg := fmt.Sprintf("\u2705 Task completed (%.1fs)", elapsed.Seconds()) - if finalContent != "" && finalContent != defaultResponse { + if finalContent != "" && finalContent != defaultResponse && finalContent != "HEARTBEAT_OK" { // Keep completion + response in one bubble if short enough (4096 = Telegram limit). // If too long, edit the status bubble with the header, then send the // full response as a regular message — the channel worker's SplitMessage @@ -2245,12 +2245,21 @@ func (al *AgentLoop) runLLMIteration( defer close(streamDone) for up := range streamCh { display := buildStreamingDisplay(up.accumulated, up.reasoning) - _ = al.bus.PublishOutbound(ctx, bus.OutboundMessage{ - Channel: opts.Channel, - ChatID: opts.ChatID, - Content: display, - IsStatus: true, - }) + outMsg := bus.OutboundMessage{ + Channel: opts.Channel, + ChatID: opts.ChatID, + Content: display, + } + // For background tasks, publish streaming preview as + // IsTaskStatus so it shares the same bubble as task + // progress/completion (avoids a second bubble). + if opts.Background && opts.TaskID != "" { + outMsg.IsTaskStatus = true + outMsg.TaskID = opts.TaskID + } else { + outMsg.IsStatus = true + } + _ = al.bus.PublishOutbound(ctx, outMsg) } }() onChunk = func(accumulated, reasoning string) {