Changed message param from str to list[str] in chat() and route() commands. Words are joined with spaces, so 'timmy chat hello how are you' works without quoting. Single-word messages still work as before. - chat(): message: list[str], joined to full_message - route(): message: list[str], joined to full_message - 7 new tests in test_cli_multiword.py Closes #26
131 lines
4.7 KiB
Python
131 lines
4.7 KiB
Python
"""Tests for CLI multi-word message handling (issue #26).
|
|
|
|
This module tests that the chat and route commands properly handle
|
|
multi-word messages without requiring quotes.
|
|
"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
from timmy.cli import _CLI_SESSION_ID, app
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# chat command — multi-word message handling
|
|
# -----------------------------------------------------------------------------
|
|
|
|
|
|
def test_chat_joins_multiple_args():
|
|
"""chat command must join multiple arguments into a single message."""
|
|
mock_run_output = MagicMock()
|
|
mock_run_output.content = "Hello! I am doing well."
|
|
mock_run_output.status = "COMPLETED"
|
|
mock_run_output.active_requirements = []
|
|
|
|
mock_timmy = MagicMock()
|
|
mock_timmy.run.return_value = mock_run_output
|
|
|
|
with patch("timmy.cli.create_timmy", return_value=mock_timmy):
|
|
result = runner.invoke(app, ["chat", "hello", "how", "are", "you"])
|
|
|
|
# Verify the message was joined with spaces
|
|
mock_timmy.run.assert_called_once_with(
|
|
"hello how are you", stream=False, session_id=_CLI_SESSION_ID
|
|
)
|
|
assert result.exit_code == 0
|
|
assert "Hello! I am doing well." in result.output
|
|
|
|
|
|
def test_chat_single_word_still_works():
|
|
"""chat command must still work with a single word argument."""
|
|
mock_run_output = MagicMock()
|
|
mock_run_output.content = "Hello!"
|
|
mock_run_output.status = "COMPLETED"
|
|
mock_run_output.active_requirements = []
|
|
|
|
mock_timmy = MagicMock()
|
|
mock_timmy.run.return_value = mock_run_output
|
|
|
|
with patch("timmy.cli.create_timmy", return_value=mock_timmy):
|
|
result = runner.invoke(app, ["chat", "hello"])
|
|
|
|
mock_timmy.run.assert_called_once_with("hello", stream=False, session_id=_CLI_SESSION_ID)
|
|
assert result.exit_code == 0
|
|
assert "Hello!" in result.output
|
|
|
|
|
|
def test_chat_joins_complex_message():
|
|
"""chat command must handle complex multi-word messages with punctuation."""
|
|
mock_run_output = MagicMock()
|
|
mock_run_output.content = "The file is located at /path/to/file."
|
|
mock_run_output.status = "COMPLETED"
|
|
mock_run_output.active_requirements = []
|
|
|
|
mock_timmy = MagicMock()
|
|
mock_timmy.run.return_value = mock_run_output
|
|
|
|
with patch("timmy.cli.create_timmy", return_value=mock_timmy):
|
|
result = runner.invoke(
|
|
app,
|
|
["chat", "what", "is", "the", "path", "to", "the", "config", "file?"],
|
|
)
|
|
|
|
mock_timmy.run.assert_called_once_with(
|
|
"what is the path to the config file?", stream=False, session_id=_CLI_SESSION_ID
|
|
)
|
|
assert result.exit_code == 0
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# route command — multi-word message handling
|
|
# -----------------------------------------------------------------------------
|
|
|
|
|
|
def test_route_joins_multiple_args():
|
|
"""route command must join multiple arguments into a single message."""
|
|
with patch("timmy.agents.loader.route_request_with_match") as mock_route:
|
|
mock_route.return_value = ("orchestrator", None)
|
|
result = runner.invoke(app, ["route", "hello", "how", "are", "you"])
|
|
|
|
# Verify the message was joined with spaces
|
|
mock_route.assert_called_once_with("hello how are you")
|
|
assert result.exit_code == 0
|
|
assert "orchestrator" in result.output
|
|
|
|
|
|
def test_route_single_word_still_works():
|
|
"""route command must still work with a single word argument."""
|
|
with patch("timmy.agents.loader.route_request_with_match") as mock_route:
|
|
mock_route.return_value = ("spark", "test pattern")
|
|
result = runner.invoke(app, ["route", "test"])
|
|
|
|
mock_route.assert_called_once_with("test")
|
|
assert result.exit_code == 0
|
|
assert "spark" in result.output
|
|
|
|
|
|
def test_route_shows_match_info():
|
|
"""route command must display matched pattern when there is a match."""
|
|
with patch("timmy.agents.loader.route_request_with_match") as mock_route:
|
|
mock_route.return_value = ("agent_1", "pattern:hello")
|
|
result = runner.invoke(app, ["route", "hello", "world"])
|
|
|
|
mock_route.assert_called_once_with("hello world")
|
|
assert result.exit_code == 0
|
|
assert "agent_1" in result.output
|
|
assert "pattern:hello" in result.output
|
|
|
|
|
|
def test_route_no_match():
|
|
"""route command must show orchestrator when no pattern matches."""
|
|
with patch("timmy.agents.loader.route_request_with_match") as mock_route:
|
|
mock_route.return_value = (None, None)
|
|
result = runner.invoke(app, ["route", "unknown", "command", "here"])
|
|
|
|
mock_route.assert_called_once_with("unknown command here")
|
|
assert result.exit_code == 0
|
|
assert "orchestrator (no pattern match)" in result.output
|