mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-20 08:32:25 +00:00
fix(feishu): send all messages to topic when in thread
This commit is contained in:
parent
908f1246d8
commit
843e96f09d
@ -1539,10 +1539,11 @@ class FeishuChannel(BaseChannel):
|
|||||||
# same topic automatically when the target message is inside a topic.
|
# same topic automatically when the target message is inside a topic.
|
||||||
reply_message_id: str | None = None
|
reply_message_id: str | None = None
|
||||||
_msg_id = msg.metadata.get("message_id")
|
_msg_id = msg.metadata.get("message_id")
|
||||||
|
has_thread_id = msg.metadata.get("thread_id")
|
||||||
if self.config.reply_to_message and not msg.metadata.get("_progress", False):
|
if self.config.reply_to_message and not msg.metadata.get("_progress", False):
|
||||||
reply_message_id = _msg_id
|
reply_message_id = _msg_id
|
||||||
# For topic group messages, always reply to keep context in thread
|
# For topic group messages, always reply to keep context in thread
|
||||||
elif msg.metadata.get("thread_id"):
|
elif has_thread_id:
|
||||||
reply_message_id = _msg_id
|
reply_message_id = _msg_id
|
||||||
|
|
||||||
first_send = True # tracks whether the reply has already been used
|
first_send = True # tracks whether the reply has already been used
|
||||||
@ -1555,7 +1556,17 @@ class FeishuChannel(BaseChannel):
|
|||||||
existing topic must not create a new topic.
|
existing topic must not create a new topic.
|
||||||
"""
|
"""
|
||||||
nonlocal first_send
|
nonlocal first_send
|
||||||
if reply_message_id and first_send:
|
if reply_message_id:
|
||||||
|
# If we're in a topic, always use reply to stay in the topic
|
||||||
|
if has_thread_id:
|
||||||
|
ok = self._reply_message_sync(
|
||||||
|
reply_message_id, m_type, content,
|
||||||
|
reply_in_thread=self._should_use_reply_in_thread(msg.metadata),
|
||||||
|
)
|
||||||
|
if ok:
|
||||||
|
return
|
||||||
|
elif first_send:
|
||||||
|
# If we're not in a topic but replying to message, only first uses reply
|
||||||
first_send = False
|
first_send = False
|
||||||
ok = self._reply_message_sync(
|
ok = self._reply_message_sync(
|
||||||
reply_message_id, m_type, content,
|
reply_message_id, m_type, content,
|
||||||
|
|||||||
@ -346,6 +346,89 @@ async def test_send_fallback_to_create_when_reply_fails() -> None:
|
|||||||
channel._client.im.v1.message.create.assert_called_once()
|
channel._client.im.v1.message.create.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_multiple_messages_all_use_reply_when_in_topic(tmp_path: Path) -> None:
|
||||||
|
"""When in a topic (has thread_id), all messages use reply API to stay in topic."""
|
||||||
|
channel = _make_feishu_channel(reply_to_message=False)
|
||||||
|
|
||||||
|
file1 = tmp_path / "file1.png"
|
||||||
|
file2 = tmp_path / "file2.png"
|
||||||
|
file1.write_bytes(b"demo1")
|
||||||
|
file2.write_bytes(b"demo2")
|
||||||
|
|
||||||
|
reply_calls = []
|
||||||
|
create_calls = []
|
||||||
|
|
||||||
|
def _mock_reply(*args, **kwargs) -> bool:
|
||||||
|
reply_calls.append((args, kwargs))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _mock_create(*args, **kwargs) -> str:
|
||||||
|
create_calls.append((args, kwargs))
|
||||||
|
return "msg_id"
|
||||||
|
|
||||||
|
with patch.object(channel, "_upload_file_sync", return_value="file-key"), \
|
||||||
|
patch.object(channel, "_upload_image_sync", return_value="image-key"), \
|
||||||
|
patch.object(channel, "_reply_message_sync", side_effect=_mock_reply), \
|
||||||
|
patch.object(channel, "_send_message_sync", side_effect=_mock_create):
|
||||||
|
await channel.send(OutboundMessage(
|
||||||
|
channel="feishu",
|
||||||
|
chat_id="oc_abc",
|
||||||
|
content="hello",
|
||||||
|
media=[str(file1), str(file2)],
|
||||||
|
metadata={
|
||||||
|
"message_id": "om_001",
|
||||||
|
"thread_id": "om_thread",
|
||||||
|
"chat_type": "group",
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
# All 3 sends (text + 2 images) should use reply
|
||||||
|
assert len(reply_calls) == 3
|
||||||
|
assert len(create_calls) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_multiple_messages_only_first_uses_reply_when_reply_to_message(tmp_path: Path) -> None:
|
||||||
|
"""When reply_to_message is enabled but not in topic, only first message uses reply."""
|
||||||
|
channel = _make_feishu_channel(reply_to_message=True)
|
||||||
|
|
||||||
|
file1 = tmp_path / "file1.png"
|
||||||
|
file2 = tmp_path / "file2.png"
|
||||||
|
file1.write_bytes(b"demo1")
|
||||||
|
file2.write_bytes(b"demo2")
|
||||||
|
|
||||||
|
reply_calls = []
|
||||||
|
create_calls = []
|
||||||
|
|
||||||
|
def _mock_reply(*args, **kwargs) -> bool:
|
||||||
|
reply_calls.append((args, kwargs))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _mock_create(*args, **kwargs) -> str:
|
||||||
|
create_calls.append((args, kwargs))
|
||||||
|
return "msg_id"
|
||||||
|
|
||||||
|
with patch.object(channel, "_upload_file_sync", return_value="file-key"), \
|
||||||
|
patch.object(channel, "_upload_image_sync", return_value="image-key"), \
|
||||||
|
patch.object(channel, "_reply_message_sync", side_effect=_mock_reply), \
|
||||||
|
patch.object(channel, "_send_message_sync", side_effect=_mock_create):
|
||||||
|
await channel.send(OutboundMessage(
|
||||||
|
channel="feishu",
|
||||||
|
chat_id="oc_abc",
|
||||||
|
content="hello",
|
||||||
|
media=[str(file1), str(file2)],
|
||||||
|
metadata={
|
||||||
|
"message_id": "om_001",
|
||||||
|
"chat_type": "group",
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
# Only first send uses reply, rest use create
|
||||||
|
assert len(reply_calls) == 1
|
||||||
|
assert len(create_calls) == 2
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# _on_message — parent_id / root_id metadata tests
|
# _on_message — parent_id / root_id metadata tests
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user