"""Tests for timmy.tools_delegation — delegate_task and list_swarm_agents. Agent IDs are now defined in config/agents.yaml, not hardcoded Python. Tests reference the YAML-defined IDs: orchestrator, researcher, coder, writer, memory, experimenter. """ from timmy.tools_delegation import delegate_task, list_swarm_agents class TestDelegateTask: def test_unknown_agent_returns_error(self): result = delegate_task("nonexistent", "do something") assert result["success"] is False assert "Unknown agent" in result["error"] assert result["task_id"] is None def test_valid_agent_names_normalised(self): # Agent IDs are lowercased; whitespace should be stripped result = delegate_task(" Researcher ", "think about it") assert "Unknown agent" not in result.get("error", "") def test_invalid_priority_defaults_to_normal(self): # Even with bad priority, delegate_task should not crash result = delegate_task("coder", "build", priority="ultra") assert isinstance(result, dict) def test_all_valid_agents_accepted(self): # These IDs match config/agents.yaml valid_agents = ["orchestrator", "researcher", "coder", "writer", "memory", "experimenter"] for agent in valid_agents: result = delegate_task(agent, "test task") assert "Unknown agent" not in result.get("error", ""), f"{agent} rejected" def test_old_agent_names_no_longer_valid(self): # Old hardcoded names should not work anymore for old_name in ["seer", "forge", "echo", "helm", "quill", "mace"]: result = delegate_task(old_name, "test") assert result["success"] is False assert "Unknown agent" in result["error"] class TestListSwarmAgents: def test_returns_agents_from_yaml(self): result = list_swarm_agents() assert result["success"] is True assert len(result["agents"]) > 0 agent_names = [a["name"] for a in result["agents"]] # These names come from config/agents.yaml assert "Seer" in agent_names assert "Forge" in agent_names assert "Timmy" in agent_names class TestDelegateToKimi: """Tests for delegate_to_kimi() — Timmy's Kimi delegation tool.""" def test_returns_dict(self, monkeypatch): """delegate_to_kimi should always return a dict.""" import shutil monkeypatch.setattr(shutil, "which", lambda x: None) from timmy.tools_delegation import delegate_to_kimi result = delegate_to_kimi("test task") assert isinstance(result, dict) assert "success" in result def test_kimi_not_found_returns_error(self, monkeypatch): """Should handle missing kimi CLI gracefully.""" import shutil monkeypatch.setattr(shutil, "which", lambda x: None) from timmy.tools_delegation import delegate_to_kimi result = delegate_to_kimi("test task") assert result["success"] is False assert "not found" in result["error"] def test_invalid_workdir_returns_error(self, monkeypatch): """Should reject non-existent working directories.""" import shutil monkeypatch.setattr(shutil, "which", lambda x: "/usr/bin/kimi") from timmy.tools_delegation import delegate_to_kimi result = delegate_to_kimi("test", working_directory="/nonexistent/path") assert result["success"] is False assert "does not exist" in result["error"] def test_timeout_returns_error(self, monkeypatch): """Should handle subprocess timeout gracefully.""" import shutil import subprocess monkeypatch.setattr(shutil, "which", lambda x: "/usr/bin/kimi") def timeout_run(*args, **kwargs): raise subprocess.TimeoutExpired(cmd="kimi", timeout=300) monkeypatch.setattr(subprocess, "run", timeout_run) from timmy.tools_delegation import delegate_to_kimi result = delegate_to_kimi("complex task") assert result["success"] is False assert "timed out" in result["error"].lower() def test_successful_delegation(self, monkeypatch): """Should capture Kimi's output on success.""" import shutil import subprocess monkeypatch.setattr(shutil, "which", lambda x: "/usr/bin/kimi") def mock_run(*args, **kwargs): return subprocess.CompletedProcess( args=args[0] if args else [], returncode=0, stdout="Fixed the bug in session.py\n\nChanges:\n- Added null check", stderr="", ) monkeypatch.setattr(subprocess, "run", mock_run) from config import settings from timmy.tools_delegation import delegate_to_kimi result = delegate_to_kimi("fix session bug", working_directory=settings.repo_root) assert result["success"] is True assert "Fixed the bug" in result["output"] assert result["return_code"] == 0 def test_default_workdir_uses_repo_root(self, monkeypatch): """Empty working_directory should default to settings.repo_root.""" import shutil import subprocess calls = [] monkeypatch.setattr(shutil, "which", lambda x: "/usr/bin/kimi") def capture_run(*args, **kwargs): calls.append(kwargs.get("cwd", "")) return subprocess.CompletedProcess( args=args[0] if args else [], returncode=0, stdout="done", stderr="" ) monkeypatch.setattr(subprocess, "run", capture_run) from config import settings from timmy.tools_delegation import delegate_to_kimi delegate_to_kimi("test task") assert len(calls) == 1 assert calls[0] == settings.repo_root