fix: redirect message tool to task status bubble for background tasks
Root cause: LLM calls the `message` tool during heartbeat execution, which publishes directly to the bus via sendCallback, bypassing the SendResponse=false guard. This creates a second bubble separate from the task status. Fix: For background tasks with SendResponse=false (e.g. heartbeat), replace the message tool's sendCallback to publish as IsTaskStatus with the same TaskID. This routes message tool output into the same bubble as streaming preview and task completion. Also removes the now-unnecessary PromoteStatusToTask call since streaming preview already uses IsTaskStatus directly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1804c85102
commit
0cea7ed32f
1 changed files with 23 additions and 11 deletions
|
|
@ -1127,6 +1127,28 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt
|
|||
// 1. Update tool contexts
|
||||
al.updateToolContexts(agent, opts.Channel, opts.ChatID)
|
||||
|
||||
// 1-bis. For background tasks that don't send a final response (e.g. heartbeat),
|
||||
// redirect the message tool to publish as IsTaskStatus so its output lands in
|
||||
// the same bubble as the task status instead of creating a separate message.
|
||||
if opts.Background && !opts.SendResponse && opts.TaskID != "" {
|
||||
if tool, ok := agent.Tools.Get("message"); ok {
|
||||
if mt, ok := tool.(*tools.MessageTool); ok {
|
||||
taskID := opts.TaskID
|
||||
mt.SetSendCallback(func(channel, chatID, content string) error {
|
||||
pubCtx, pubCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer pubCancel()
|
||||
return al.bus.PublishOutbound(pubCtx, bus.OutboundMessage{
|
||||
Channel: channel,
|
||||
ChatID: chatID,
|
||||
Content: content,
|
||||
IsTaskStatus: true,
|
||||
TaskID: taskID,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1a. Set session-specific working directory for bootstrap file lookup.
|
||||
// Prefer the tool-detected project directory (touch_dir) from the session tracker,
|
||||
// resolved as an absolute path under workspace. Fall back to worktree or workspace.
|
||||
|
|
@ -1391,17 +1413,7 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt
|
|||
task.Result = utils.Truncate(finalContent, 280)
|
||||
}
|
||||
|
||||
// 5e. Promote streaming status bubble to task message for background tasks.
|
||||
// When SendResponse is false (e.g. heartbeat), no final non-status message
|
||||
// triggers preSend's statusMsgIDs.LoadAndDelete cleanup, so the last
|
||||
// streaming chunk persists on Telegram. Move the tracked status message ID
|
||||
// into taskMsgIDs so the defer's IsTaskStatus completion notification edits
|
||||
// the existing bubble instead of creating a duplicate message.
|
||||
if opts.Background && !opts.SendResponse && !constants.IsInternalChannel(opts.Channel) && task != nil &&
|
||||
task.streamedChunks && opts.TaskID != "" {
|
||||
statusKey := opts.Channel + ":" + opts.ChatID
|
||||
al.channelManager.PromoteStatusToTask(statusKey, opts.TaskID)
|
||||
}
|
||||
|
||||
|
||||
// 6. Save final assistant message to session (deferred write-behind)
|
||||
agent.Sessions.AddMessage(opts.SessionKey, "assistant", finalContent)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue