fischer-agentkit/tests/unit/test_ask_human_tool.py

101 lines
3.2 KiB
Python

"""Tests for AskHumanTool."""
import asyncio
import pytest
from agentkit.tools.ask_human import AskHumanTool
class TestAskHumanToolBasic:
def test_tool_properties(self):
tool = AskHumanTool()
assert tool.name == "ask_human"
assert "question" in str(tool.parameters)
assert tool.parameters["required"] == ["question"]
@pytest.mark.asyncio
async def test_no_chat_mode_returns_default(self):
tool = AskHumanTool()
result = await tool.execute(question="What should I do?")
assert result == {"reply": "confirmed"}
@pytest.mark.asyncio
async def test_no_chat_mode_with_options(self):
tool = AskHumanTool()
result = await tool.execute(question="Choose:", options=["A", "B", "C"])
assert result == {"reply": "A"}
class TestAskHumanToolChatMode:
@pytest.mark.asyncio
async def test_ask_and_receive_reply(self):
tool = AskHumanTool(timeout=5.0)
pending: dict[str, asyncio.Future] = {}
ask_calls: list[tuple[str, str, list[str] | None]] = []
async def mock_ask_callback(request_id, question, options):
ask_calls.append((request_id, question, options))
tool.configure(pending_replies=pending, ask_callback=mock_ask_callback)
# Start the execute in a task
task = asyncio.create_task(
tool.execute(question="Continue?", options=["yes", "no"])
)
# Wait for the ask to be pushed
await asyncio.sleep(0.1)
assert len(ask_calls) == 1
request_id = ask_calls[0][0]
assert ask_calls[0][1] == "Continue?"
assert ask_calls[0][2] == ["yes", "no"]
# Simulate user reply
assert request_id in pending
pending[request_id].set_result("yes")
result = await task
assert result == {"reply": "yes"}
@pytest.mark.asyncio
async def test_timeout_returns_default(self):
tool = AskHumanTool(timeout=0.1)
pending: dict[str, asyncio.Future] = {}
async def mock_ask_callback(request_id, question, options):
pass # Never reply
tool.configure(pending_replies=pending, ask_callback=mock_ask_callback)
result = await tool.execute(question="Continue?", options=["yes", "no"])
assert result == {"reply": "yes"}
@pytest.mark.asyncio
async def test_timeout_no_options(self):
tool = AskHumanTool(timeout=0.1)
pending: dict[str, asyncio.Future] = {}
async def mock_ask_callback(request_id, question, options):
pass
tool.configure(pending_replies=pending, ask_callback=mock_ask_callback)
result = await tool.execute(question="Continue?")
assert "timeout" in result["reply"]
@pytest.mark.asyncio
async def test_cleanup_on_reply(self):
tool = AskHumanTool(timeout=5.0)
pending: dict[str, asyncio.Future] = {}
async def mock_ask_callback(request_id, question, options):
# Immediately reply
await asyncio.sleep(0.05)
pending[request_id].set_result("ok")
tool.configure(pending_replies=pending, ask_callback=mock_ask_callback)
await tool.execute(question="Test?")
# Pending should be cleaned up
assert len(pending) == 0