Implemented the next missing parity slice around agent configurations.

This commit is contained in:
Abdelrahman Abdallah
2026-04-17 05:03:19 +02:00
parent fabbda53a5
commit 02674ba594
14 changed files with 721 additions and 17 deletions
+75
View File
@@ -0,0 +1,75 @@
from __future__ import annotations
import os
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
from src.agent_registry import load_agent_registry, render_agent_detail, render_agents_report
def _write_agent(path: Path, *, name: str, description: str, body: str, extra: str = '') -> None:
payload = (
'---\n'
f'name: {name}\n'
f'description: "{description}"\n'
f'{extra}'
'---\n\n'
f'{body}\n'
)
path.write_text(payload, encoding='utf-8')
class AgentRegistryTests(unittest.TestCase):
def test_project_agent_overrides_built_in_agent(self) -> None:
with tempfile.TemporaryDirectory() as home_dir, tempfile.TemporaryDirectory() as tmp_dir:
workspace = Path(tmp_dir)
agents_dir = workspace / '.claude' / 'agents'
agents_dir.mkdir(parents=True)
_write_agent(
agents_dir / 'Explore.md',
name='Explore',
description='Project-specific explore agent.',
body='Search this repository carefully before answering.',
extra=(
'tools: read_file, grep_search\n'
'model: child-model\n'
'initialPrompt: Begin with rg-style discovery.\n'
),
)
with patch.dict(os.environ, {'HOME': home_dir}):
snapshot = load_agent_registry(workspace)
active = {agent.agent_type: agent for agent in snapshot.active_agents}
self.assertIn('Explore', active)
self.assertEqual(active['Explore'].source, 'projectSettings')
self.assertEqual(active['Explore'].model, 'child-model')
self.assertEqual(active['Explore'].tools, ('read_file', 'grep_search'))
self.assertEqual(active['Explore'].initial_prompt, 'Begin with rg-style discovery.')
report = render_agents_report(snapshot, cwd=workspace)
self.assertIn('Explore [projectSettings]', report)
self.assertIn('Shadowed Agents', report)
detail = render_agent_detail(snapshot, 'Explore')
self.assertIn('Project-specific explore agent.', detail)
self.assertIn('Begin with rg-style discovery.', detail)
self.assertIn('Search this repository carefully before answering.', detail)
def test_invalid_agent_file_is_reported(self) -> None:
with tempfile.TemporaryDirectory() as home_dir, tempfile.TemporaryDirectory() as tmp_dir:
workspace = Path(tmp_dir)
agents_dir = workspace / '.claude' / 'agents'
agents_dir.mkdir(parents=True)
(agents_dir / 'broken.md').write_text(
'---\nname: broken\n---\n',
encoding='utf-8',
)
with patch.dict(os.environ, {'HOME': home_dir}):
snapshot = load_agent_registry(workspace)
self.assertEqual(len(snapshot.failed_files), 1)
self.assertIn('missing a description', snapshot.failed_files[0].error)
+32
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
import json
import os
import tempfile
import unittest
from pathlib import Path
@@ -112,6 +113,37 @@ def make_recording_streaming_urlopen_side_effect(
class AgentRuntimeTests(unittest.TestCase):
def test_custom_project_agent_is_resolved_for_child_agent_configuration(self) -> None:
with tempfile.TemporaryDirectory() as home_dir, tempfile.TemporaryDirectory() as tmp_dir:
workspace = Path(tmp_dir)
agents_dir = workspace / '.claude' / 'agents'
agents_dir.mkdir(parents=True)
(agents_dir / 'Explore.md').write_text(
(
'---\n'
'name: Explore\n'
'description: "Project-specific explore agent."\n'
'tools: read_file, grep_search\n'
'model: child-model\n'
'initialPrompt: Start with a repository scan.\n'
'---\n\n'
'Search the repository and report findings.\n'
),
encoding='utf-8',
)
with patch.dict(os.environ, {'HOME': home_dir}):
agent = LocalCodingAgent(
model_config=ModelConfig(model='parent-model'),
runtime_config=AgentRuntimeConfig(cwd=workspace),
)
agent_def = agent._resolve_agent_definition({'subagent_type': 'Explore'})
child_model = agent._resolve_child_model_config({}, agent_def)
child_tools = agent._filter_tools_for_agent(agent_def)
self.assertEqual(agent_def.source, 'projectSettings')
self.assertEqual(agent_def.initial_prompt, 'Start with a repository scan.')
self.assertEqual(child_model.model, 'child-model')
self.assertEqual(sorted(child_tools), ['grep_search', 'read_file'])
def test_openai_client_parses_tool_calls(self) -> None:
responses = [
{
+30
View File
@@ -4,6 +4,7 @@ import tempfile
import unittest
import json
import sys
import os
from pathlib import Path
from unittest.mock import patch
@@ -119,6 +120,35 @@ class AgentSlashCommandTests(unittest.TestCase):
self.assertIn('Hard input limit', result.final_output)
self.assertIn('Auto-compact buffer', result.final_output)
def test_agents_command_lists_and_shows_custom_agents(self) -> None:
with tempfile.TemporaryDirectory() as home_dir, tempfile.TemporaryDirectory() as tmp_dir:
workspace = Path(tmp_dir)
agents_dir = workspace / '.claude' / 'agents'
agents_dir.mkdir(parents=True)
(agents_dir / 'reviewer.md').write_text(
(
'---\n'
'name: reviewer\n'
'description: "Review implementation changes carefully."\n'
'tools: read_file, grep_search\n'
'model: test-child-model\n'
'---\n\n'
'Inspect code changes and summarize risks.\n'
),
encoding='utf-8',
)
with patch.dict(os.environ, {'HOME': home_dir}):
agent = LocalCodingAgent(
model_config=ModelConfig(model='test-model'),
runtime_config=AgentRuntimeConfig(cwd=workspace),
)
list_result = agent.run('/agents')
detail_result = agent.run('/agents show reviewer')
self.assertIn('# Agents', list_result.final_output)
self.assertIn('reviewer [projectSettings]', list_result.final_output)
self.assertIn('# Agent: reviewer', detail_result.final_output)
self.assertIn('Inspect code changes and summarize risks.', detail_result.final_output)
def test_mcp_and_resource_commands_render_local_reports(self) -> None:
with tempfile.TemporaryDirectory() as tmp_dir:
workspace = Path(tmp_dir)
+8
View File
@@ -213,6 +213,14 @@ class MainCliTests(unittest.TestCase):
self.assertEqual(args.command, 'token-budget')
self.assertEqual(args.cwd, '.')
def test_parser_accepts_agents_command(self) -> None:
parser = build_parser()
args = parser.parse_args(['agents', 'reviewer', '--cwd', '.', '--all'])
self.assertEqual(args.command, 'agents')
self.assertEqual(args.agent_type, 'reviewer')
self.assertTrue(args.all)
self.assertEqual(args.cwd, '.')
def test_parser_accepts_team_runtime_commands(self) -> None:
parser = build_parser()
args = parser.parse_args(['team-create', 'reviewers', '--member', 'alice', '--cwd', '.'])