feat: Improve TelegramAdapter message handling with enhanced error management and draft message support

This commit is contained in:
fdc310
2026-06-02 01:14:25 +08:00
parent 2b533c4a00
commit d0f65b17ec

View File

@@ -1,5 +1,4 @@
from __future__ import annotations from __future__ import annotations
import time
import telegram import telegram
@@ -421,11 +420,15 @@ class TelegramAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
message_thread_id = getattr(effective_message, 'message_thread_id', None) if effective_message else None message_thread_id = getattr(effective_message, 'message_thread_id', None) if effective_message else None
if chat_type == 'private': if chat_type == 'private':
draft_id = int(time.time() * 1000) import time as _time
self.msg_stream_id[message_id] = ('private', draft_id)
draft_id = int(_time.time() * 1000)
self.msg_stream_id[message_id] = ('private', draft_id)
args = self._build_message_args(chat_id, 'Thinking...', message_thread_id, draft_id=draft_id) args = self._build_message_args(chat_id, 'Thinking...', message_thread_id, draft_id=draft_id)
try:
await self.bot.send_message_draft(**args) await self.bot.send_message_draft(**args)
except (telegram.error.RetryAfter, telegram.error.BadRequest):
pass
else: else:
args = self._build_message_args(chat_id, 'Thinking...', message_thread_id) args = self._build_message_args(chat_id, 'Thinking...', message_thread_id)
send_msg = await self.bot.send_message(**args) send_msg = await self.bot.send_message(**args)
@@ -452,7 +455,7 @@ class TelegramAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
if message_id not in self.msg_stream_id: if message_id not in self.msg_stream_id:
return return
chat_mode, draft_id = self.msg_stream_id[message_id] chat_mode, stream_id = self.msg_stream_id[message_id]
components = await TelegramMessageConverter.yiri2target(message, self.bot) components = await TelegramMessageConverter.yiri2target(message, self.bot)
if not components or components[0]['type'] != 'text': if not components or components[0]['type'] != 'text':
@@ -463,30 +466,40 @@ class TelegramAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
content = components[0]['text'] content = components[0]['text']
form_data = getattr(bot_message, '_form_data', None) form_data = getattr(bot_message, '_form_data', None)
if chat_mode == 'private':
if form_data and is_final: if form_data and is_final:
# Suppress the streaming-text materialisation: this chunk's
# content is just a placeholder (e.g. zero-width space, or
# the display_text used to keep ResponseWrapper from dropping
# the chunk). The button card below carries the real prompt.
self.msg_stream_id.pop(message_id, None) self.msg_stream_id.pop(message_id, None)
await self._send_form_action_buttons(message_source, form_data) await self._send_form_action_buttons(message_source, form_data)
return return
args = self._build_message_args(chat_id, content, message_thread_id, draft_id=draft_id)
if chat_mode == 'private':
# Streaming via draft (ephemeral preview in the chat input area)
if (msg_seq - 1) % 8 == 0 or is_final:
args = self._build_message_args(chat_id, content, message_thread_id, draft_id=stream_id)
try:
await self.bot.send_message_draft(**args) await self.bot.send_message_draft(**args)
except telegram.error.BadRequest as exc:
if 'Message_too_long' in str(exc):
args['text'] = content[:4000] + '\n\n… (truncated)'
try:
await self.bot.send_message_draft(**args)
except telegram.error.RetryAfter:
pass
else:
pass # Ignore other draft errors (cosmetic)
if is_final and bot_message.tool_calls is None: if is_final and bot_message.tool_calls is None:
del args['draft_id'] # Finalise: send the real message, discard the draft
args = self._build_message_args(chat_id, content, message_thread_id)
try:
await self.bot.send_message(**args) await self.bot.send_message(**args)
except telegram.error.BadRequest as exc:
if 'Message_too_long' in str(exc):
args['text'] = content[:4000] + '\n\n… (truncated)'
await self.bot.send_message(**args)
else:
raise
self.msg_stream_id.pop(message_id) self.msg_stream_id.pop(message_id)
else: else:
stream_id = draft_id # Streaming via edit_message_text (persistent message)
if form_data and is_final:
# Same suppression as the private branch — don't push the
# placeholder text into the streaming message; render the
# button card instead.
self.msg_stream_id.pop(message_id, None)
await self._send_form_action_buttons(message_source, form_data)
return
if (msg_seq - 1) % 8 == 0 or is_final: if (msg_seq - 1) % 8 == 0 or is_final:
args = { args = {
'message_id': stream_id, 'message_id': stream_id,
@@ -495,7 +508,14 @@ class TelegramAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
} }
if self.config.get('markdown_card', False): if self.config.get('markdown_card', False):
args['parse_mode'] = 'MarkdownV2' args['parse_mode'] = 'MarkdownV2'
try:
await self.bot.edit_message_text(**args) await self.bot.edit_message_text(**args)
except telegram.error.BadRequest as exc:
if 'Message_too_long' in str(exc):
args['text'] = self._process_markdown(content[:4000] + '\n\n… (truncated)')
await self.bot.edit_message_text(**args)
else:
raise
if is_final and bot_message.tool_calls is None: if is_final and bot_message.tool_calls is None:
self.msg_stream_id.pop(message_id) self.msg_stream_id.pop(message_id)