mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-27 01:11:40 +00:00
feat: implement edit_message() for Telegram/Discord/Slack and fix fallback regression
Building on PR #288's edit_message() abstraction: - Telegram: edit_message_text() with MarkdownV2 + plain text fallback - Discord: channel.fetch_message() + msg.edit() with length capping - Slack: chat_update() via slack_bolt client Also fixes the fallback regression in send_progress_messages() where platforms that don't support editing would receive duplicated accumulated tool lines. Now uses a can_edit flag — after the first failed edit, falls back to sending individual lines (matching pre-PR behavior).
This commit is contained in:
parent
5702eba93b
commit
1708dcd2b2
4 changed files with 91 additions and 15 deletions
|
|
@ -207,6 +207,28 @@ class DiscordAdapter(BasePlatformAdapter):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=str(e))
|
||||||
|
|
||||||
|
async def edit_message(
|
||||||
|
self,
|
||||||
|
chat_id: str,
|
||||||
|
message_id: str,
|
||||||
|
content: str,
|
||||||
|
) -> SendResult:
|
||||||
|
"""Edit a previously sent Discord message."""
|
||||||
|
if not self._client:
|
||||||
|
return SendResult(success=False, error="Not connected")
|
||||||
|
try:
|
||||||
|
channel = self._client.get_channel(int(chat_id))
|
||||||
|
if not channel:
|
||||||
|
channel = await self._client.fetch_channel(int(chat_id))
|
||||||
|
msg = await channel.fetch_message(int(message_id))
|
||||||
|
formatted = self.format_message(content)
|
||||||
|
if len(formatted) > self.MAX_MESSAGE_LENGTH:
|
||||||
|
formatted = formatted[:self.MAX_MESSAGE_LENGTH - 3] + "..."
|
||||||
|
await msg.edit(content=formatted)
|
||||||
|
return SendResult(success=True, message_id=message_id)
|
||||||
|
except Exception as e:
|
||||||
|
return SendResult(success=False, error=str(e))
|
||||||
|
|
||||||
async def send_voice(
|
async def send_voice(
|
||||||
self,
|
self,
|
||||||
chat_id: str,
|
chat_id: str,
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,25 @@ class SlackAdapter(BasePlatformAdapter):
|
||||||
print(f"[Slack] Send error: {e}")
|
print(f"[Slack] Send error: {e}")
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=str(e))
|
||||||
|
|
||||||
|
async def edit_message(
|
||||||
|
self,
|
||||||
|
chat_id: str,
|
||||||
|
message_id: str,
|
||||||
|
content: str,
|
||||||
|
) -> SendResult:
|
||||||
|
"""Edit a previously sent Slack message."""
|
||||||
|
if not self._app:
|
||||||
|
return SendResult(success=False, error="Not connected")
|
||||||
|
try:
|
||||||
|
await self._app.client.chat_update(
|
||||||
|
channel=chat_id,
|
||||||
|
ts=message_id,
|
||||||
|
text=content,
|
||||||
|
)
|
||||||
|
return SendResult(success=True, message_id=message_id)
|
||||||
|
except Exception as e:
|
||||||
|
return SendResult(success=False, error=str(e))
|
||||||
|
|
||||||
async def send_typing(self, chat_id: str) -> None:
|
async def send_typing(self, chat_id: str) -> None:
|
||||||
"""Slack doesn't have a direct typing indicator API for bots."""
|
"""Slack doesn't have a direct typing indicator API for bots."""
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,35 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=str(e))
|
||||||
|
|
||||||
|
async def edit_message(
|
||||||
|
self,
|
||||||
|
chat_id: str,
|
||||||
|
message_id: str,
|
||||||
|
content: str,
|
||||||
|
) -> SendResult:
|
||||||
|
"""Edit a previously sent Telegram message."""
|
||||||
|
if not self._bot:
|
||||||
|
return SendResult(success=False, error="Not connected")
|
||||||
|
try:
|
||||||
|
formatted = self.format_message(content)
|
||||||
|
try:
|
||||||
|
await self._bot.edit_message_text(
|
||||||
|
chat_id=int(chat_id),
|
||||||
|
message_id=int(message_id),
|
||||||
|
text=formatted,
|
||||||
|
parse_mode=ParseMode.MARKDOWN_V2,
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
# Fallback: retry without markdown formatting
|
||||||
|
await self._bot.edit_message_text(
|
||||||
|
chat_id=int(chat_id),
|
||||||
|
message_id=int(message_id),
|
||||||
|
text=content,
|
||||||
|
)
|
||||||
|
return SendResult(success=True, message_id=message_id)
|
||||||
|
except Exception as e:
|
||||||
|
return SendResult(success=False, error=str(e))
|
||||||
|
|
||||||
async def send_voice(
|
async def send_voice(
|
||||||
self,
|
self,
|
||||||
chat_id: str,
|
chat_id: str,
|
||||||
|
|
|
||||||
|
|
@ -1950,30 +1950,36 @@ class GatewayRunner:
|
||||||
|
|
||||||
progress_lines = [] # Accumulated tool lines
|
progress_lines = [] # Accumulated tool lines
|
||||||
progress_msg_id = None # ID of the progress message to edit
|
progress_msg_id = None # ID of the progress message to edit
|
||||||
|
can_edit = True # False once an edit fails (platform doesn't support it)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
msg = progress_queue.get_nowait()
|
msg = progress_queue.get_nowait()
|
||||||
progress_lines.append(msg)
|
progress_lines.append(msg)
|
||||||
full_text = "\n".join(progress_lines)
|
|
||||||
|
|
||||||
if progress_msg_id is None:
|
if can_edit and progress_msg_id is not None:
|
||||||
# First tool: send as new message
|
# Try to edit the existing progress message
|
||||||
result = await adapter.send(chat_id=source.chat_id, content=full_text)
|
full_text = "\n".join(progress_lines)
|
||||||
if result.success and result.message_id:
|
|
||||||
progress_msg_id = result.message_id
|
|
||||||
else:
|
|
||||||
# Subsequent tools: try to edit, fall back to new message
|
|
||||||
result = await adapter.edit_message(
|
result = await adapter.edit_message(
|
||||||
chat_id=source.chat_id,
|
chat_id=source.chat_id,
|
||||||
message_id=progress_msg_id,
|
message_id=progress_msg_id,
|
||||||
content=full_text,
|
content=full_text,
|
||||||
)
|
)
|
||||||
if not result.success:
|
if not result.success:
|
||||||
# Edit failed — send as new message and track it
|
# Platform doesn't support editing — stop trying,
|
||||||
|
# send just this new line as a separate message
|
||||||
|
can_edit = False
|
||||||
|
await adapter.send(chat_id=source.chat_id, content=msg)
|
||||||
|
else:
|
||||||
|
if can_edit:
|
||||||
|
# First tool: send all accumulated text as new message
|
||||||
|
full_text = "\n".join(progress_lines)
|
||||||
result = await adapter.send(chat_id=source.chat_id, content=full_text)
|
result = await adapter.send(chat_id=source.chat_id, content=full_text)
|
||||||
if result.success and result.message_id:
|
else:
|
||||||
progress_msg_id = result.message_id
|
# Editing unsupported: send just this line
|
||||||
|
result = await adapter.send(chat_id=source.chat_id, content=msg)
|
||||||
|
if result.success and result.message_id:
|
||||||
|
progress_msg_id = result.message_id
|
||||||
|
|
||||||
# Restore typing indicator
|
# Restore typing indicator
|
||||||
await asyncio.sleep(0.3)
|
await asyncio.sleep(0.3)
|
||||||
|
|
@ -1989,8 +1995,8 @@ class GatewayRunner:
|
||||||
progress_lines.append(msg)
|
progress_lines.append(msg)
|
||||||
except Exception:
|
except Exception:
|
||||||
break
|
break
|
||||||
# Final edit with all remaining tools
|
# Final edit with all remaining tools (only if editing works)
|
||||||
if progress_lines and progress_msg_id:
|
if can_edit and progress_lines and progress_msg_id:
|
||||||
full_text = "\n".join(progress_lines)
|
full_text = "\n".join(progress_lines)
|
||||||
try:
|
try:
|
||||||
await adapter.edit_message(
|
await adapter.edit_message(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue