Merge upstream changes
This commit is contained in:
parent
b5d6fbe6ab
commit
42314b495a
3 changed files with 52 additions and 44 deletions
|
|
@ -33,7 +33,8 @@
|
||||||
"Bash(golangci-lint run:*)",
|
"Bash(golangci-lint run:*)",
|
||||||
"WebFetch(domain:core.telegram.org)",
|
"WebFetch(domain:core.telegram.org)",
|
||||||
"Bash(go doc:*)",
|
"Bash(go doc:*)",
|
||||||
"Bash(go install:*)"
|
"Bash(go install:*)",
|
||||||
|
"WebFetch(domain:raw.githubusercontent.com)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"remote": {
|
"remote": {
|
||||||
|
|
|
||||||
|
|
@ -633,26 +633,43 @@ func (m *Manager) handleTaskStatusSend(ctx context.Context, name string, w *chan
|
||||||
|
|
||||||
taskKey := taskStatusKey(name, msg.ChatID, msg.TaskID)
|
taskKey := taskStatusKey(name, msg.ChatID, msg.TaskID)
|
||||||
|
|
||||||
// Final message: send as permanent (non-draft) message so it persists.
|
// Final message: reuse the existing bubble when possible to avoid
|
||||||
// Drafts are ephemeral and disappear after a short time; the completion
|
// duplicate messages. If a permanent message (messageID) is tracked,
|
||||||
// message must survive. Clear the draft tracking and send via SendWithID
|
// edit it in-place. If a draft (draftID) is tracked, update it with
|
||||||
// or regular Send, which creates a permanent Telegram message.
|
// the completion content (the draft persists in Telegram and serves
|
||||||
|
// as the visible message; sending a separate permanent message would
|
||||||
|
// create a duplicate).
|
||||||
if msg.Final {
|
if msg.Final {
|
||||||
if v, loaded := m.taskMsgIDs.LoadAndDelete(taskKey); loaded {
|
v, loaded := m.taskMsgIDs.LoadAndDelete(taskKey)
|
||||||
if entry, ok := v.(statusMsgEntry); ok && entry.draftID != 0 {
|
m.statusEditTimes.Delete(taskKey)
|
||||||
if drafter, ok := w.ch.(DraftSender); ok {
|
|
||||||
if err := drafter.SendDraft(ctx, msg.ChatID, entry.draftID, ""); err != nil {
|
if loaded {
|
||||||
logger.WarnCF("channels", "Failed to dismiss task draft before final message", map[string]any{
|
if entry, ok := v.(statusMsgEntry); ok {
|
||||||
"task_id": taskKey,
|
// Path A: a permanent message exists — edit it in-place.
|
||||||
"chat_id": msg.ChatID,
|
if entry.messageID != "" {
|
||||||
"draft_id": entry.draftID,
|
if editor, ok := w.ch.(MessageEditor); ok {
|
||||||
"error": err.Error(),
|
if err := editor.EditMessage(ctx, msg.ChatID, entry.messageID, msg.Content); err == nil {
|
||||||
})
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Edit failed — fall through to send a new message.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path B: a draft exists — update it with the final
|
||||||
|
// content. Drafts persist visibly in Telegram, so do NOT
|
||||||
|
// send a separate permanent message (that causes duplicates).
|
||||||
|
if entry.draftID != 0 {
|
||||||
|
if drafter, ok := w.ch.(DraftSender); ok {
|
||||||
|
if err := drafter.SendDraft(ctx, msg.ChatID, entry.draftID, msg.Content); err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Draft update failed — fall through to send permanent.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.statusEditTimes.Delete(taskKey)
|
|
||||||
|
// No existing bubble to reuse — send a new permanent message.
|
||||||
if sender, ok := w.ch.(MessageSenderWithID); ok {
|
if sender, ok := w.ch.(MessageSenderWithID); ok {
|
||||||
if msgID, err := sender.SendWithID(ctx, msg.ChatID, msg.Content); err == nil && msgID != "" {
|
if msgID, err := sender.SendWithID(ctx, msg.ChatID, msg.Content); err == nil && msgID != "" {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -1439,39 +1439,32 @@ func TestHandleTaskStatusSend_UsesDraftSender(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleTaskStatusSend_Final_DismissesDraftBeforePermanentMessage(t *testing.T) {
|
func TestHandleTaskStatusSend_Final_UpdatesDraftInPlace(t *testing.T) {
|
||||||
m := newTestManager()
|
m := newTestManager()
|
||||||
var dismissCalled bool
|
var draftUpdateCalled bool
|
||||||
var dismissDraftID int
|
var draftUpdateDraftID int
|
||||||
var dismissContent string
|
var draftUpdateContent string
|
||||||
var finalSendWithIDCalled bool
|
|
||||||
|
|
||||||
ch := &mockDraftSender{
|
ch := &mockDraftSender{
|
||||||
mockChannel: mockChannel{
|
mockChannel: mockChannel{
|
||||||
sendFn: func(_ context.Context, _ bus.OutboundMessage) error {
|
sendFn: func(_ context.Context, _ bus.OutboundMessage) error {
|
||||||
t.Fatal("Send should not be called when SendWithID succeeds")
|
t.Fatal("Send should not be called when draft update succeeds")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
draftFn: func(_ context.Context, chatID string, draftID int, content string) error {
|
draftFn: func(_ context.Context, chatID string, draftID int, content string) error {
|
||||||
dismissCalled = true
|
draftUpdateCalled = true
|
||||||
dismissDraftID = draftID
|
draftUpdateDraftID = draftID
|
||||||
dismissContent = content
|
draftUpdateContent = content
|
||||||
if chatID != "123" {
|
if chatID != "123" {
|
||||||
t.Fatalf("expected dismiss chatID 123, got %s", chatID)
|
t.Fatalf("expected chatID 123, got %s", chatID)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
editFn: func(_ context.Context, _, _, _ string) error { return nil },
|
editFn: func(_ context.Context, _, _, _ string) error { return nil },
|
||||||
sendWithID: func(_ context.Context, chatID, content string) (string, error) {
|
sendWithID: func(_ context.Context, _, _ string) (string, error) {
|
||||||
finalSendWithIDCalled = true
|
t.Fatal("SendWithID should not be called when draft update succeeds")
|
||||||
if chatID != "123" {
|
return "", nil
|
||||||
t.Fatalf("expected final chatID 123, got %s", chatID)
|
|
||||||
}
|
|
||||||
if content != "task completed" {
|
|
||||||
t.Fatalf("expected final content 'task completed', got %s", content)
|
|
||||||
}
|
|
||||||
return "task-final-1", nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1490,17 +1483,14 @@ func TestHandleTaskStatusSend_Final_DismissesDraftBeforePermanentMessage(t *test
|
||||||
}
|
}
|
||||||
m.handleTaskStatusSend(context.Background(), "test", w, msg)
|
m.handleTaskStatusSend(context.Background(), "test", w, msg)
|
||||||
|
|
||||||
if !dismissCalled {
|
if !draftUpdateCalled {
|
||||||
t.Fatal("expected SendDraft dismiss call for final task status")
|
t.Fatal("expected SendDraft to update draft with final content")
|
||||||
}
|
}
|
||||||
if dismissDraftID != 42 {
|
if draftUpdateDraftID != 42 {
|
||||||
t.Fatalf("expected dismiss draftID 42, got %d", dismissDraftID)
|
t.Fatalf("expected draftID 42, got %d", draftUpdateDraftID)
|
||||||
}
|
}
|
||||||
if dismissContent != "" {
|
if draftUpdateContent != "task completed" {
|
||||||
t.Fatalf("expected empty dismiss content, got %q", dismissContent)
|
t.Fatalf("expected draft content 'task completed', got %q", draftUpdateContent)
|
||||||
}
|
|
||||||
if !finalSendWithIDCalled {
|
|
||||||
t.Fatal("expected final SendWithID to be called")
|
|
||||||
}
|
}
|
||||||
if _, loaded := m.taskMsgIDs.Load(taskStatusKey("test", "123", "task-final")); loaded {
|
if _, loaded := m.taskMsgIDs.Load(taskStatusKey("test", "123", "task-final")); loaded {
|
||||||
t.Fatal("expected taskMsgIDs entry to be deleted for final task status")
|
t.Fatal("expected taskMsgIDs entry to be deleted for final task status")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue