From e67c4c3f2744f0ae4d69084a491141f254a2de29 Mon Sep 17 00:00:00 2001 From: dj-oyu <68707227+dj-oyu@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:33:06 +0900 Subject: [PATCH] feat(telegram): show tool progress on placeholder during agent loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Edit the Telegram placeholder message with tool names and iteration count (e.g. "🔧 web_search (2/20)") so users see live progress instead of a static "Thinking... 💭". Non-supporting channels silently skip. Co-Authored-By: Claude Opus 4.6 --- pkg/agent/loop.go | 10 ++++++++++ pkg/bus/types.go | 7 ++++--- pkg/channels/manager.go | 14 ++++++++++++++ pkg/channels/telegram.go | 17 +++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 20c788627..f1b1e9647 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -654,6 +654,16 @@ func (al *AgentLoop) runLLMIteration(ctx context.Context, agent *AgentInstance, "iteration": iteration, }) + // Publish status update for channels that support placeholder editing + if !constants.IsInternalChannel(opts.Channel) { + al.bus.PublishOutbound(bus.OutboundMessage{ + Channel: opts.Channel, + ChatID: opts.ChatID, + Content: fmt.Sprintf("🔧 %s (%d/%d)", strings.Join(toolNames, ", "), iteration, agent.MaxIterations), + IsStatus: true, + }) + } + // Build assistant message with tool calls assistantMsg := providers.Message{ Role: "assistant", diff --git a/pkg/bus/types.go b/pkg/bus/types.go index 44f9181a5..84f9458ed 100644 --- a/pkg/bus/types.go +++ b/pkg/bus/types.go @@ -11,9 +11,10 @@ type InboundMessage struct { } type OutboundMessage struct { - Channel string `json:"channel"` - ChatID string `json:"chat_id"` - Content string `json:"content"` + Channel string `json:"channel"` + ChatID string `json:"chat_id"` + Content string `json:"content"` + IsStatus bool `json:"is_status,omitempty"` } type MessageHandler func(InboundMessage) error diff --git a/pkg/channels/manager.go b/pkg/channels/manager.go index 7f6abc4cb..db28d1118 100644 --- a/pkg/channels/manager.go +++ b/pkg/channels/manager.go @@ -272,6 +272,20 @@ func (m *Manager) dispatchOutbound(ctx context.Context) { continue } + if msg.IsStatus { + if sc, ok := channel.(interface { + EditStatus(context.Context, bus.OutboundMessage) error + }); ok { + if err := sc.EditStatus(ctx, msg); err != nil { + logger.DebugCF("channels", "EditStatus failed", map[string]interface{}{ + "channel": msg.Channel, + "error": err.Error(), + }) + } + } + continue + } + if err := channel.Send(ctx, msg); err != nil { logger.ErrorCF("channels", "Error sending message to channel", map[string]interface{}{ "channel": msg.Channel, diff --git a/pkg/channels/telegram.go b/pkg/channels/telegram.go index d5863ec5a..75c77ebbf 100644 --- a/pkg/channels/telegram.go +++ b/pkg/channels/telegram.go @@ -146,6 +146,23 @@ func (c *TelegramChannel) Stop(ctx context.Context) error { return nil } +func (c *TelegramChannel) EditStatus(ctx context.Context, msg bus.OutboundMessage) error { + if !c.IsRunning() { + return nil + } + chatID, err := parseChatID(msg.ChatID) + if err != nil { + return nil + } + pID, ok := c.placeholders.Load(msg.ChatID) + if !ok { + return nil // no placeholder → nothing to edit + } + editMsg := tu.EditMessageText(tu.ID(chatID), pID.(int), msg.Content) + _, err = c.bot.EditMessageText(ctx, editMsg) + return err +} + func (c *TelegramChannel) Send(ctx context.Context, msg bus.OutboundMessage) error { if !c.IsRunning() { return fmt.Errorf("telegram bot not running")