Fix forwarded image payload parsing for agent channels

This commit is contained in:
jxxghp
2026-04-11 20:55:14 +08:00
parent 6c5fae56d9
commit edf3946558
4 changed files with 87 additions and 3 deletions

View File

@@ -193,10 +193,15 @@ class SlackModule(_ModuleBase, _MessageBase[Slack]):
if not client_config:
return None
try:
msg_json: dict = json.loads(body)
msg_json = json.loads(body)
while isinstance(msg_json, str):
msg_json = json.loads(msg_json)
except Exception as err:
logger.debug(f"解析Slack消息失败{str(err)}")
return None
if not isinstance(msg_json, dict):
logger.debug(f"Slack消息格式无效{type(msg_json)}")
return None
if msg_json:
images = None
if msg_json.get("type") == "message":

View File

@@ -131,11 +131,21 @@ class TelegramModule(_ModuleBase, _MessageBase[Telegram]):
return None
client: Telegram = self.get_instance(client_config.name)
try:
message: dict = json.loads(body)
message = json.loads(body)
while isinstance(message, str):
message = json.loads(message)
except Exception as err:
logger.debug(f"解析Telegram消息失败{str(err)}")
return None
if not isinstance(message, dict):
logger.debug(f"Telegram消息格式无效{type(message)}")
return None
# 兼容某些转发链路使用 Telegram Update 外壳
if "message" in message and isinstance(message.get("message"), dict):
message = message.get("message")
if message:
# 处理按钮回调
if "callback_query" in message:

View File

@@ -1,4 +1,5 @@
import asyncio
import json
import re
import threading
import time
@@ -113,7 +114,11 @@ class Telegram:
if self._should_process_message(message):
# 启动持续发送正在输入状态
self._start_typing_task(message.chat.id)
RequestUtils(timeout=15).post_res(self._ds_url, json=message.json)
payload = self._serialize_update_payload(message)
if not payload:
logger.warn("Telegram消息序列化失败跳过转发")
return
RequestUtils(timeout=15).post_res(self._ds_url, json=payload)
@_bot.callback_query_handler(func=lambda call: True)
def callback_query(call):
@@ -208,6 +213,23 @@ class Telegram:
logger.error(f"下载Telegram文件失败: {e}")
return None
@staticmethod
def _serialize_update_payload(message: Any) -> Optional[dict]:
"""
将 Telegram Message 对象稳定序列化为 dict避免 requests 的 json 参数再次包一层字符串。
"""
try:
if hasattr(message, "to_dict"):
payload = message.to_dict()
else:
payload = getattr(message, "json", None) or message
if isinstance(payload, str):
payload = json.loads(payload)
return payload if isinstance(payload, dict) else None
except Exception as e:
logger.error(f"序列化Telegram消息失败: {e}")
return None
def _update_user_chat_mapping(self, userid: int, chat_id: int) -> None:
"""
更新用户与聊天的映射关系

View File

@@ -1,4 +1,5 @@
import base64
import json
import unittest
from types import SimpleNamespace
from unittest.mock import Mock, patch
@@ -7,6 +8,7 @@ from app.agent.tools.impl.send_message import SendMessageInput
from app.chain.message import MessageChain
from app.core.config import settings
from app.modules.slack import SlackModule
from app.modules.telegram.telegram import Telegram
from app.modules.telegram import TelegramModule
from app.schemas import CommingMessage
from app.schemas.types import MessageChannel
@@ -26,6 +28,51 @@ class AgentImageSupportTest(unittest.TestCase):
["tg://file_id/large", "tg://file_id/doc-image"],
)
def test_telegram_message_parser_accepts_double_encoded_body(self):
module = TelegramModule()
body = json.dumps(
json.dumps(
{
"message": {
"from": {"id": 10001, "username": "tester"},
"chat": {"id": 10001, "type": "private"},
"photo": [{"file_id": "small"}, {"file_id": "large"}],
}
}
)
)
with patch.object(
module,
"get_config",
return_value=SimpleNamespace(name="telegram-test", config={}),
), patch.object(
module,
"get_instance",
return_value=SimpleNamespace(bot_username=None),
):
message = module.message_parser(
source="telegram-test", body=body, form={}, args={}
)
self.assertIsNotNone(message)
self.assertEqual(message.images, ["tg://file_id/large"])
def test_telegram_forward_payload_uses_dict_not_json_string(self):
payload = Telegram._serialize_update_payload(
SimpleNamespace(
to_dict=lambda: {
"text": "hi",
"photo": [{"file_id": "image-1"}],
}
)
)
self.assertEqual(
payload,
{"text": "hi", "photo": [{"file_id": "image-1"}]},
)
def test_process_allows_image_only_message(self):
chain = MessageChain()
message = CommingMessage(