"""Tests for model adapters.""" from app.services.context.adapters import ( ClaudeAdapter, DefaultAdapter, OpenAIAdapter, get_adapter, ) from app.services.context.types import ( ContextType, ConversationContext, KnowledgeContext, MessageRole, SystemContext, TaskContext, ToolContext, ) class TestGetAdapter: """Tests for get_adapter function.""" def test_claude_models(self) -> None: """Test that Claude models get ClaudeAdapter.""" assert isinstance(get_adapter("claude-3-sonnet"), ClaudeAdapter) assert isinstance(get_adapter("claude-3-opus"), ClaudeAdapter) assert isinstance(get_adapter("claude-3-haiku"), ClaudeAdapter) assert isinstance(get_adapter("claude-2"), ClaudeAdapter) assert isinstance(get_adapter("anthropic/claude-3-sonnet"), ClaudeAdapter) def test_openai_models(self) -> None: """Test that OpenAI models get OpenAIAdapter.""" assert isinstance(get_adapter("gpt-4"), OpenAIAdapter) assert isinstance(get_adapter("gpt-4-turbo"), OpenAIAdapter) assert isinstance(get_adapter("gpt-3.5-turbo"), OpenAIAdapter) assert isinstance(get_adapter("openai/gpt-4"), OpenAIAdapter) assert isinstance(get_adapter("o1-mini"), OpenAIAdapter) assert isinstance(get_adapter("o3-mini"), OpenAIAdapter) def test_unknown_models(self) -> None: """Test that unknown models get DefaultAdapter.""" assert isinstance(get_adapter("llama-2"), DefaultAdapter) assert isinstance(get_adapter("mistral-7b"), DefaultAdapter) assert isinstance(get_adapter("custom-model"), DefaultAdapter) class TestModelAdapterBase: """Tests for ModelAdapter base class.""" def test_get_type_order(self) -> None: """Test default type ordering.""" adapter = DefaultAdapter() order = adapter.get_type_order() assert order == [ ContextType.SYSTEM, ContextType.TASK, ContextType.KNOWLEDGE, ContextType.CONVERSATION, ContextType.TOOL, ] def test_group_by_type(self) -> None: """Test grouping contexts by type.""" adapter = DefaultAdapter() contexts = [ SystemContext(content="System", source="system"), TaskContext(content="Task", source="task"), KnowledgeContext(content="Knowledge", source="docs"), SystemContext(content="System 2", source="system"), ] grouped = adapter.group_by_type(contexts) assert len(grouped[ContextType.SYSTEM]) == 2 assert len(grouped[ContextType.TASK]) == 1 assert len(grouped[ContextType.KNOWLEDGE]) == 1 assert ContextType.CONVERSATION not in grouped def test_matches_model_default(self) -> None: """Test that DefaultAdapter matches all models.""" assert DefaultAdapter.matches_model("anything") assert DefaultAdapter.matches_model("claude-3") assert DefaultAdapter.matches_model("gpt-4") class TestDefaultAdapter: """Tests for DefaultAdapter.""" def test_format_empty(self) -> None: """Test formatting empty context list.""" adapter = DefaultAdapter() result = adapter.format([]) assert result == "" def test_format_system(self) -> None: """Test formatting system context.""" adapter = DefaultAdapter() contexts = [ SystemContext(content="You are helpful.", source="system"), ] result = adapter.format(contexts) assert "You are helpful." in result def test_format_task(self) -> None: """Test formatting task context.""" adapter = DefaultAdapter() contexts = [ TaskContext(content="Write a function.", source="task"), ] result = adapter.format(contexts) assert "Task:" in result assert "Write a function." in result def test_format_knowledge(self) -> None: """Test formatting knowledge context.""" adapter = DefaultAdapter() contexts = [ KnowledgeContext(content="Documentation here.", source="docs"), ] result = adapter.format(contexts) assert "Reference Information:" in result assert "Documentation here." in result def test_format_conversation(self) -> None: """Test formatting conversation context.""" adapter = DefaultAdapter() contexts = [ ConversationContext( content="Hello!", source="chat", role=MessageRole.USER, ), ] result = adapter.format(contexts) assert "Previous Conversation:" in result assert "Hello!" in result def test_format_tool(self) -> None: """Test formatting tool context.""" adapter = DefaultAdapter() contexts = [ ToolContext( content="Result: success", source="tool", metadata={"tool_name": "search"}, ), ] result = adapter.format(contexts) assert "Tool Results:" in result assert "Result: success" in result class TestClaudeAdapter: """Tests for ClaudeAdapter.""" def test_matches_model(self) -> None: """Test model matching.""" assert ClaudeAdapter.matches_model("claude-3-sonnet") assert ClaudeAdapter.matches_model("claude-3-opus") assert ClaudeAdapter.matches_model("anthropic/claude-3-haiku") assert not ClaudeAdapter.matches_model("gpt-4") assert not ClaudeAdapter.matches_model("llama-2") def test_format_empty(self) -> None: """Test formatting empty context list.""" adapter = ClaudeAdapter() result = adapter.format([]) assert result == "" def test_format_system_uses_xml(self) -> None: """Test that system context uses XML tags.""" adapter = ClaudeAdapter() contexts = [ SystemContext(content="You are helpful.", source="system"), ] result = adapter.format(contexts) assert "" in result assert "" in result assert "You are helpful." in result def test_format_task_uses_xml(self) -> None: """Test that task context uses XML tags.""" adapter = ClaudeAdapter() contexts = [ TaskContext(content="Write a function.", source="task"), ] result = adapter.format(contexts) assert "" in result assert "" in result assert "Write a function." in result def test_format_knowledge_uses_document_tags(self) -> None: """Test that knowledge uses document XML tags.""" adapter = ClaudeAdapter() contexts = [ KnowledgeContext( content="Documentation here.", source="docs/api.md", relevance_score=0.9, ), ] result = adapter.format(contexts) assert "" in result assert "" in result assert '" in result assert "Documentation here." in result def test_format_knowledge_with_score(self) -> None: """Test that knowledge includes relevance score.""" adapter = ClaudeAdapter() contexts = [ KnowledgeContext( content="Doc content.", source="docs/api.md", metadata={"relevance_score": 0.95}, ), ] result = adapter.format(contexts) assert 'relevance="0.95"' in result def test_format_conversation_uses_message_tags(self) -> None: """Test that conversation uses message XML tags.""" adapter = ClaudeAdapter() contexts = [ ConversationContext( content="Hello!", source="chat", role=MessageRole.USER, metadata={"role": "user"}, ), ConversationContext( content="Hi there!", source="chat", role=MessageRole.ASSISTANT, metadata={"role": "assistant"}, ), ] result = adapter.format(contexts) assert "" in result assert "" in result assert '' in result assert '' in result assert "Hello!" in result assert "Hi there!" in result def test_format_tool_uses_tool_result_tags(self) -> None: """Test that tool results use tool_result XML tags.""" adapter = ClaudeAdapter() contexts = [ ToolContext( content='{"status": "ok"}', source="tool", metadata={"tool_name": "search", "status": "success"}, ), ] result = adapter.format(contexts) assert "" in result assert "" in result assert '" in result def test_format_multiple_types_in_order(self) -> None: """Test that multiple types are formatted in correct order.""" adapter = ClaudeAdapter() contexts = [ KnowledgeContext(content="Knowledge", source="docs"), SystemContext(content="System", source="system"), TaskContext(content="Task", source="task"), ] result = adapter.format(contexts) # Find positions system_pos = result.find("") task_pos = result.find("") knowledge_pos = result.find("") # Verify order assert system_pos < task_pos < knowledge_pos def test_escape_xml_in_source(self) -> None: """Test that XML special chars are escaped in source.""" adapter = ClaudeAdapter() contexts = [ KnowledgeContext( content="Doc content.", source='path/with"quotes&stuff.md', ), ] result = adapter.format(contexts) assert """ in result assert "&" in result class TestOpenAIAdapter: """Tests for OpenAIAdapter.""" def test_matches_model(self) -> None: """Test model matching.""" assert OpenAIAdapter.matches_model("gpt-4") assert OpenAIAdapter.matches_model("gpt-4-turbo") assert OpenAIAdapter.matches_model("gpt-3.5-turbo") assert OpenAIAdapter.matches_model("openai/gpt-4") assert OpenAIAdapter.matches_model("o1-preview") assert OpenAIAdapter.matches_model("o3-mini") assert not OpenAIAdapter.matches_model("claude-3") assert not OpenAIAdapter.matches_model("llama-2") def test_format_empty(self) -> None: """Test formatting empty context list.""" adapter = OpenAIAdapter() result = adapter.format([]) assert result == "" def test_format_system_plain(self) -> None: """Test that system content is plain.""" adapter = OpenAIAdapter() contexts = [ SystemContext(content="You are helpful.", source="system"), ] result = adapter.format(contexts) # System content should be plain without headers assert "You are helpful." in result assert "##" not in result # No markdown headers for system def test_format_task_uses_markdown(self) -> None: """Test that task uses markdown headers.""" adapter = OpenAIAdapter() contexts = [ TaskContext(content="Write a function.", source="task"), ] result = adapter.format(contexts) assert "## Current Task" in result assert "Write a function." in result def test_format_knowledge_uses_markdown(self) -> None: """Test that knowledge uses markdown with source headers.""" adapter = OpenAIAdapter() contexts = [ KnowledgeContext( content="Documentation here.", source="docs/api.md", relevance_score=0.9, ), ] result = adapter.format(contexts) assert "## Reference Documents" in result assert "### Source: docs/api.md" in result assert "Documentation here." in result def test_format_knowledge_with_score(self) -> None: """Test that knowledge includes relevance score.""" adapter = OpenAIAdapter() contexts = [ KnowledgeContext( content="Doc content.", source="docs/api.md", metadata={"relevance_score": 0.95}, ), ] result = adapter.format(contexts) assert "(relevance: 0.95)" in result def test_format_conversation_uses_bold_roles(self) -> None: """Test that conversation uses bold role labels.""" adapter = OpenAIAdapter() contexts = [ ConversationContext( content="Hello!", source="chat", role=MessageRole.USER, metadata={"role": "user"}, ), ConversationContext( content="Hi there!", source="chat", role=MessageRole.ASSISTANT, metadata={"role": "assistant"}, ), ] result = adapter.format(contexts) assert "**USER**:" in result assert "**ASSISTANT**:" in result assert "Hello!" in result assert "Hi there!" in result def test_format_tool_uses_code_blocks(self) -> None: """Test that tool results use code blocks.""" adapter = OpenAIAdapter() contexts = [ ToolContext( content='{"status": "ok"}', source="tool", metadata={"tool_name": "search", "status": "success"}, ), ] result = adapter.format(contexts) assert "## Recent Tool Results" in result assert "### Tool: search (success)" in result assert "```" in result # Code block assert '{"status": "ok"}' in result def test_format_multiple_types_in_order(self) -> None: """Test that multiple types are formatted in correct order.""" adapter = OpenAIAdapter() contexts = [ KnowledgeContext(content="Knowledge", source="docs"), SystemContext(content="System", source="system"), TaskContext(content="Task", source="task"), ] result = adapter.format(contexts) # System comes first (no header), then task, then knowledge system_pos = result.find("System") task_pos = result.find("## Current Task") knowledge_pos = result.find("## Reference Documents") assert system_pos < task_pos < knowledge_pos class TestAdapterIntegration: """Integration tests for adapters.""" def test_full_context_formatting_claude(self) -> None: """Test formatting a full set of contexts for Claude.""" adapter = ClaudeAdapter() contexts = [ SystemContext( content="You are an expert Python developer.", source="system", ), TaskContext( content="Implement user authentication.", source="task:AUTH-123", ), KnowledgeContext( content="JWT tokens provide stateless authentication...", source="docs/auth/jwt.md", relevance_score=0.9, ), ConversationContext( content="Can you help me implement JWT auth?", source="chat", role=MessageRole.USER, metadata={"role": "user"}, ), ToolContext( content='{"file": "auth.py", "status": "created"}', source="tool", metadata={"tool_name": "file_create"}, ), ] result = adapter.format(contexts) # Verify all sections present assert "" in result assert "" in result assert "" in result assert "" in result assert "" in result # Verify content assert "expert Python developer" in result assert "user authentication" in result assert "JWT tokens" in result assert "help me implement" in result assert "file_create" in result def test_full_context_formatting_openai(self) -> None: """Test formatting a full set of contexts for OpenAI.""" adapter = OpenAIAdapter() contexts = [ SystemContext( content="You are an expert Python developer.", source="system", ), TaskContext( content="Implement user authentication.", source="task:AUTH-123", ), KnowledgeContext( content="JWT tokens provide stateless authentication...", source="docs/auth/jwt.md", relevance_score=0.9, ), ConversationContext( content="Can you help me implement JWT auth?", source="chat", role=MessageRole.USER, metadata={"role": "user"}, ), ToolContext( content='{"file": "auth.py", "status": "created"}', source="tool", metadata={"tool_name": "file_create"}, ), ] result = adapter.format(contexts) # Verify all sections present assert "## Current Task" in result assert "## Reference Documents" in result assert "## Recent Tool Results" in result assert "**USER**:" in result # Verify content assert "expert Python developer" in result assert "user authentication" in result assert "JWT tokens" in result assert "help me implement" in result assert "file_create" in result