Skip to content

Commit 90f5416

Browse files
author
chaodu-agent
committed
fix: proper edit_message handling — finalize via send_message for draft path
- edit_message with reply_to='draft': route to sendRichMessageDraft (rich) or silently drop (non-rich). Never attempt editMessageText on dummy ref. - edit_message with real message_id: perform actual editMessageText for legacy streaming placeholder updates. - Stream finalization: when placeholder is dummy 'draft' ref, send final content as new message (send_message) so it gets persisted. This ensures rich path uses sendRichMessage for the final reply, not just a draft. Addresses 擺渡法師's 🔴 #2 — streaming finalization must persist.
1 parent 32dd083 commit 90f5416

2 files changed

Lines changed: 46 additions & 24 deletions

File tree

gateway/src/adapters/telegram.rs

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -417,27 +417,41 @@ pub async fn handle_reply(
417417
return;
418418
}
419419

420-
// Handle edit_message → stream via sendRichMessageDraft
420+
// Handle edit_message
421421
if reply.command.as_deref() == Some("edit_message") {
422-
if !rich_messages {
423-
// Without rich messages, "draft" placeholder has no real message_id to edit.
424-
// Silently drop — the final reply will be sent as a new message via send_message.
425-
return;
426-
}
427-
// Skip short updates — let thinking animation show until meaningful content arrives
428-
if reply.content.text.len() < 30 {
422+
if reply.reply_to == "draft" {
423+
// Dummy "draft" ref from streaming without placeholder.
424+
if rich_messages {
425+
// Skip short updates — let thinking animation show until meaningful content arrives
426+
if reply.content.text.len() < 30 {
427+
return;
428+
}
429+
let text = if reply.content.text.len() > 32768 {
430+
&reply.content.text[..reply.content.text.floor_char_boundary(32768)]
431+
} else {
432+
&reply.content.text
433+
};
434+
// Combine channel + thread to avoid draft_id collision in forum topics
435+
let chan: i64 = reply.channel.id.parse::<i64>().unwrap_or(1).abs();
436+
let tid: i64 = reply.channel.thread_id.as_deref().and_then(|t| t.parse::<i64>().ok()).unwrap_or(0).abs();
437+
let draft_id: i64 = (chan.wrapping_add(tid)) % 1_000_000 + 1;
438+
let _ = send_rich_message_draft(client, bot_token, &reply.channel.id, &reply.channel.thread_id, draft_id, text).await;
439+
}
440+
// else: rich_messages=false with dummy ref — silently drop (no real msg to edit)
429441
return;
430442
}
431-
let text = if reply.content.text.len() > 32768 {
432-
&reply.content.text[..reply.content.text.floor_char_boundary(32768)]
433-
} else {
434-
&reply.content.text
435-
};
436-
// Combine channel + thread to avoid draft_id collision in forum topics
437-
let chan: i64 = reply.channel.id.parse::<i64>().unwrap_or(1).abs();
438-
let tid: i64 = reply.channel.thread_id.as_deref().and_then(|t| t.parse::<i64>().ok()).unwrap_or(0).abs();
439-
let draft_id: i64 = (chan.wrapping_add(tid)) % 1_000_000 + 1;
440-
let _ = send_rich_message_draft(client, bot_token, &reply.channel.id, &reply.channel.thread_id, draft_id, text).await;
443+
// Real message_id — perform actual editMessageText (legacy streaming path)
444+
let url = format!("{TELEGRAM_API_BASE}/bot{bot_token}/editMessageText");
445+
let _ = client
446+
.post(&url)
447+
.json(&serde_json::json!({
448+
"chat_id": reply.channel.id,
449+
"message_id": reply.reply_to,
450+
"text": &reply.content.text,
451+
"parse_mode": "Markdown",
452+
}))
453+
.send()
454+
.await;
441455
return;
442456
}
443457

src/adapter.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -714,12 +714,20 @@ impl AdapterRouter {
714714
}
715715
}
716716
} else {
717-
// Normal streaming: edit first chunk into placeholder, send rest
718-
if let Some(first) = chunks.first() {
719-
let _ = adapter.edit_message(&msg, first).await;
720-
}
721-
for chunk in chunks.iter().skip(1) {
722-
let _ = adapter.send_message(&thread_channel, chunk).await;
717+
// Normal streaming: edit first chunk into placeholder, send rest.
718+
// If placeholder is a dummy "draft" ref (no real message), send as
719+
// new message instead — the gateway will persist via sendRichMessage.
720+
if msg.message_id == "draft" {
721+
for chunk in &chunks {
722+
let _ = adapter.send_message(&thread_channel, chunk).await;
723+
}
724+
} else {
725+
if let Some(first) = chunks.first() {
726+
let _ = adapter.edit_message(&msg, first).await;
727+
}
728+
for chunk in chunks.iter().skip(1) {
729+
let _ = adapter.send_message(&thread_channel, chunk).await;
730+
}
723731
}
724732
}
725733
} else {

0 commit comments

Comments
 (0)