import pytest from nanobot.agent.tools.message import MessageTool from nanobot.bus.events import OutboundMessage @pytest.mark.asyncio async def test_message_tool_returns_error_when_no_target_context() -> None: tool = MessageTool() result = await tool.execute(content="test") assert result == "Error: No target channel/chat specified" @pytest.mark.asyncio @pytest.mark.parametrize( "bad", [ "not a list", [["ok"], "row-not-a-list"], [["ok", 42]], [[None]], ], ) async def test_message_tool_rejects_malformed_buttons(bad) -> None: """``buttons`` must be ``list[list[str]]``; the tool validates the shape up front so a malformed LLM payload errors visibly instead of slipping into the channel layer where Telegram would silently reject the frame.""" tool = MessageTool() result = await tool.execute( content="hi", channel="telegram", chat_id="1", buttons=bad, ) assert result == "Error: buttons must be a list of list of strings" @pytest.mark.asyncio async def test_message_tool_marks_channel_delivery_only_when_enabled() -> None: sent: list[OutboundMessage] = [] async def _send(msg: OutboundMessage) -> None: sent.append(msg) tool = MessageTool(send_callback=_send) await tool.execute(content="normal", channel="telegram", chat_id="1") token = tool.set_record_channel_delivery(True) try: await tool.execute(content="cron", channel="telegram", chat_id="1") finally: tool.reset_record_channel_delivery(token) assert sent[0].metadata == {} assert sent[1].metadata == {"_record_channel_delivery": True}