101 lines
3.2 KiB
Python
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
|