mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(channels): dismiss tool feedback animation when turn ends via ResponseHandled (#2713)
* fix(channels): dismiss tool feedback animation when turn ends via ResponseHandled When a tool sets ResponseHandled=true (e.g., send_file), the turn ends without producing a final assistant response. This meant no outbound message triggered FinalizeToolFeedbackMessage, leaving the animation goroutine running indefinitely — editing the Feishu card every 3 seconds with "." / ".." suffixes long after the tool had finished. Fix: call DismissToolFeedback at "Tool output satisfied delivery" so the tracker is cleared and the animation goroutine is stopped immediately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(adapters): add DismissToolFeedback to channelManagerAdapter The adapter must implement the new interface method added in the previous commit, otherwise the package fails to compile. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(channels): pass InboundContext to DismissToolFeedback for topic-aware keys Telegram forum topics use scoped tracker keys like "chatID/topicID", resolved via ToolFeedbackMessageChatID with the InboundContext. The previous nil context caused the lookup to fall back to the raw chatID, missing the topic-scoped entry and leaving the animation goroutine orphaned in forum-topic conversations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * style: wrap long function signatures for golines Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,3 +43,9 @@ func (a *channelManagerAdapter) SendMedia(ctx context.Context, msg bus.OutboundM
|
||||
func (a *channelManagerAdapter) SendPlaceholder(ctx context.Context, channel, chatID string) bool {
|
||||
return a.inner.SendPlaceholder(ctx, channel, chatID)
|
||||
}
|
||||
|
||||
func (a *channelManagerAdapter) DismissToolFeedback(
|
||||
ctx context.Context, channel, chatID string, outboundCtx *bus.InboundContext,
|
||||
) {
|
||||
a.inner.DismissToolFeedback(ctx, channel, chatID, outboundCtx)
|
||||
}
|
||||
|
||||
@@ -44,4 +44,11 @@ type ChannelManager interface {
|
||||
|
||||
// SendPlaceholder sends a placeholder message (e.g., for audio transcription).
|
||||
SendPlaceholder(ctx context.Context, channel, chatID string) bool
|
||||
|
||||
// DismissToolFeedback clears any tracked tool feedback animation for the
|
||||
// given channel/chat. Call this when a turn ends without a final response
|
||||
// (e.g., ResponseHandled tools) to avoid orphaned animation goroutines.
|
||||
// outboundCtx carries topic/thread info needed for channels that use
|
||||
// scoped tracker keys (e.g., Telegram forum topics); may be nil.
|
||||
DismissToolFeedback(ctx context.Context, channel, chatID string, outboundCtx *bus.InboundContext)
|
||||
}
|
||||
|
||||
@@ -704,6 +704,9 @@ toolLoop:
|
||||
}
|
||||
ts.setPhase(TurnPhaseCompleted)
|
||||
ts.setFinalContent("")
|
||||
if al.channelManager != nil && ts.channel != "" {
|
||||
al.channelManager.DismissToolFeedback(ctx, ts.channel, ts.chatID, ts.opts.InboundContext)
|
||||
}
|
||||
logger.InfoCF("agent", "Tool output satisfied delivery; ending turn without follow-up LLM",
|
||||
map[string]any{
|
||||
"agent_id": ts.agent.ID,
|
||||
|
||||
@@ -192,6 +192,21 @@ func clearTrackedToolFeedbackMessage(
|
||||
}
|
||||
}
|
||||
|
||||
// DismissToolFeedback clears any tracked tool feedback animation for the
|
||||
// given channel/chat. This is called when a turn ends without a final
|
||||
// response (e.g., ResponseHandled tools) to stop orphaned animation goroutines.
|
||||
// outboundCtx carries topic/thread info for channels that use scoped tracker
|
||||
// keys (e.g., Telegram forum topics); may be nil for non-topic channels.
|
||||
func (m *Manager) DismissToolFeedback(
|
||||
ctx context.Context, channelName, chatID string, outboundCtx *bus.InboundContext,
|
||||
) {
|
||||
ch, ok := m.GetChannel(channelName)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
dismissTrackedToolFeedbackMessage(ctx, ch, chatID, outboundCtx)
|
||||
}
|
||||
|
||||
func prepareToolFeedbackMessageContent(ch Channel, content string) string {
|
||||
prepared := strings.TrimSpace(content)
|
||||
if prepared == "" {
|
||||
|
||||
Reference in New Issue
Block a user