fix(telegram): scope tool feedback by session

This commit is contained in:
Anton Bogdanovich 2026-05-06 15:24:18 -07:00
parent 2608ddc6be
commit 5292ddf325
2 changed files with 68 additions and 3 deletions

View file

@ -203,7 +203,7 @@ func (c *TelegramChannel) Send(ctx context.Context, msg bus.OutboundMessage) ([]
if isToolFeedback {
toolFeedbackContent = fitToolFeedbackForTelegram(msg.Content, useMarkdownV2, 4096)
}
trackedChatID := telegramToolFeedbackChatKey(msg.ChatID, &msg.Context)
trackedChatID := telegramToolFeedbackTrackerKey(msg)
if isToolFeedback {
if msgID, handled, err := c.progress.Update(ctx, trackedChatID, toolFeedbackContent); handled {
if err != nil {
@ -411,6 +411,7 @@ func (c *TelegramChannel) StartTyping(ctx context.Context, chatID string) (func(
// EditMessage implements channels.MessageEditor.
func (c *TelegramChannel) EditMessage(ctx context.Context, chatID string, messageID string, content string) error {
useMarkdownV2 := c.tgCfg.UseMarkdownV2
chatID = telegramToolFeedbackDeliveryChatID(chatID)
cid, _, err := parseTelegramChatID(chatID)
if err != nil {
return err
@ -488,6 +489,23 @@ func outboundMessageIsToolFeedback(msg bus.OutboundMessage) bool {
return strings.EqualFold(strings.TrimSpace(msg.Context.Raw["message_kind"]), "tool_feedback")
}
func telegramToolFeedbackTrackerKey(msg bus.OutboundMessage) string {
key := telegramToolFeedbackChatKey(msg.ChatID, &msg.Context)
sessionKey := strings.TrimSpace(msg.SessionKey)
if key == "" || sessionKey == "" {
return key
}
return key + "#session:" + sessionKey
}
func telegramToolFeedbackDeliveryChatID(chatID string) string {
chatID = strings.TrimSpace(chatID)
if idx := strings.Index(chatID, "#session:"); idx >= 0 {
return strings.TrimSpace(chatID[:idx])
}
return chatID
}
func (c *TelegramChannel) currentToolFeedbackMessage(chatID string) (string, bool) {
if c.progress == nil {
return "", false
@ -529,7 +547,7 @@ func (c *TelegramChannel) dismissTrackedToolFeedbackMessage(ctx context.Context,
return
}
c.ClearToolFeedbackMessage(chatID)
_ = c.DeleteMessage(ctx, chatID, messageID)
_ = c.DeleteMessage(ctx, telegramToolFeedbackDeliveryChatID(chatID), messageID)
}
func (c *TelegramChannel) finalizeTrackedToolFeedbackMessage(
@ -542,7 +560,7 @@ func (c *TelegramChannel) finalizeTrackedToolFeedbackMessage(
if !ok || editFn == nil {
return nil, false
}
if err := editFn(ctx, chatID, msgID, content); err != nil {
if err := editFn(ctx, telegramToolFeedbackDeliveryChatID(chatID), msgID, content); err != nil {
c.RecordToolFeedbackMessage(chatID, msgID, baseContent)
return nil, false
}

View file

@ -374,6 +374,53 @@ func TestSend_TopicReplyDoesNotFinalizeDifferentTopicToolFeedback(t *testing.T)
assert.True(t, ok, "tool feedback in the original topic should remain tracked")
}
func TestSend_FinalReplyDoesNotFinalizeDifferentSessionToolFeedback(t *testing.T) {
nextMessageID := 0
caller := &stubCaller{
callFn: func(ctx context.Context, url string, data *ta.RequestData) (*ta.Response, error) {
nextMessageID++
return successResponseWithMessageID(t, nextMessageID), nil
},
}
ch := newTestChannel(t, caller)
baseCtx := bus.InboundContext{
Channel: "telegram",
ChatID: "-1001234567890",
TopicID: "42",
}
_, err := ch.Send(context.Background(), bus.OutboundMessage{
ChatID: "-1001234567890",
SessionKey: "subturn-1",
Content: "Working...\n• tool: `read_file`",
Context: bus.InboundContext{
Channel: "telegram",
ChatID: "-1001234567890",
TopicID: "42",
Raw: map[string]string{
"message_kind": "tool_feedback",
},
},
})
require.NoError(t, err)
ids, err := ch.Send(context.Background(), bus.OutboundMessage{
ChatID: "-1001234567890",
SessionKey: "main-session",
Content: "test",
Context: baseCtx,
})
require.NoError(t, err)
require.Len(t, caller.calls, 2)
assert.Equal(t, []string{"2"}, ids)
assert.Contains(t, caller.calls[1].URL, "sendMessage")
assert.NotContains(t, caller.calls[1].URL, "editMessageText")
msgID, ok := ch.currentToolFeedbackMessage("-1001234567890/42#session:subturn-1")
require.True(t, ok, "subturn tool feedback should remain tracked")
assert.Equal(t, "1", msgID)
}
func TestFinalizeTrackedToolFeedbackMessage_StopsTrackingBeforeEdit(t *testing.T) {
ch := newTestChannel(t, &stubCaller{
callFn: func(context.Context, string, *ta.RequestData) (*ta.Response, error) {