scripts-test-persona-provider-integration
""" Tests for PersonaLoader and ProviderDetector Integration (ADR-073).
Tests the integration between PersonaLoader and ProviderDetector for provider-aware model selection and diversity verification. """
import os import unittest from pathlib import Path from unittest.mock import patch, MagicMock
from core.persona_loader import ( PersonaLoader, verify_panel_diversity, adjust_confidence_for_provider_mode, get_provider_mode, get_provider_diversity_report, ) from core.provider_detector import ( ProviderMode, Provider, reset_default_detector, )
class TestPersonaLoaderProviderIntegration(unittest.TestCase): """Test PersonaLoader integration with ProviderDetector."""
def setUp(self):
"""Reset detectors before each test."""
reset_default_detector()
def tearDown(self):
"""Clean up after each test."""
reset_default_detector()
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
}, clear=True)
def test_get_model_single_provider_anthropic(self):
"""Test model selection in single-provider mode with Anthropic."""
loader = PersonaLoader()
# In single-provider mode with Anthropic, should return appropriate tier models
model = loader.get_model_for_persona("technical_architect", provider_aware=True)
# Should be a Claude model (Anthropic is the only available provider)
self.assertIn("claude", model.lower())
@patch.dict(os.environ, {
"OPENAI_API_KEY": "sk-openai-test",
}, clear=True)
def test_get_model_single_provider_openai(self):
"""Test model selection in single-provider mode with OpenAI."""
loader = PersonaLoader()
model = loader.get_model_for_persona("technical_architect", provider_aware=True)
# Should be an OpenAI model (O3, GPT-4.1, etc.)
self.assertTrue(
"gpt" in model.lower() or "o3" in model.lower(),
f"Expected OpenAI model, got {model}"
)
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"OPENAI_API_KEY": "sk-openai-test",
}, clear=True)
def test_get_model_dual_provider(self):
"""Test model selection in dual-provider mode."""
loader = PersonaLoader()
model = loader.get_model_for_persona("technical_architect", provider_aware=True)
# In dual mode, should return a model from available providers
self.assertTrue(
"claude" in model.lower() or "gpt" in model.lower() or "o3" in model.lower(),
f"Expected Anthropic or OpenAI model, got {model}"
)
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"OPENAI_API_KEY": "sk-openai-test",
"DEEPSEEK_API_KEY": "sk-deepseek-test",
}, clear=True)
def test_get_model_multi_provider(self):
"""Test model selection in multi-provider mode."""
loader = PersonaLoader()
# In multi-provider mode, should use full routing config
model = loader.get_model_for_persona("technical_architect", provider_aware=True)
# Model should be returned (could be any configured model)
self.assertIsNotNone(model)
self.assertIsInstance(model, str)
def test_get_model_provider_aware_disabled(self):
"""Test that provider_aware=False bypasses provider detection."""
loader = PersonaLoader()
# With provider_aware=False, should use standard config priority
model = loader.get_model_for_persona(
"technical_architect",
provider_aware=False
)
# Should return a model from standard config
self.assertIsNotNone(model)
class TestPanelDiversityProviderAware(unittest.TestCase): """Test verify_panel_diversity with provider awareness."""
def setUp(self):
reset_default_detector()
def tearDown(self):
reset_default_detector()
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
}, clear=True)
def test_diversity_single_provider_relaxed(self):
"""Test that single-provider mode relaxes diversity requirements."""
loader = PersonaLoader()
is_valid, details = loader.verify_panel_diversity(provider_aware=True)
# In single-provider mode, should have relaxed requirements
self.assertEqual(details["provider_mode"], "single")
self.assertEqual(details["diversity_strategy"], "model_tier_diversity")
self.assertEqual(details["min_required"], 1) # Only 1 family required
self.assertEqual(details["max_allowed_weight"], 1.0) # 100% from one family OK
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"OPENAI_API_KEY": "sk-openai-test",
}, clear=True)
def test_diversity_dual_provider(self):
"""Test that dual-provider mode has moderate diversity requirements."""
loader = PersonaLoader()
is_valid, details = loader.verify_panel_diversity(provider_aware=True)
self.assertEqual(details["provider_mode"], "dual")
self.assertEqual(details["diversity_strategy"], "provider_alternation")
self.assertEqual(details["min_required"], 2)
self.assertEqual(details["max_allowed_weight"], 0.60)
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"OPENAI_API_KEY": "sk-openai-test",
"DEEPSEEK_API_KEY": "sk-deepseek-test",
}, clear=True)
def test_diversity_multi_provider_full(self):
"""Test that multi-provider mode has full diversity requirements."""
loader = PersonaLoader()
is_valid, details = loader.verify_panel_diversity(provider_aware=True)
self.assertEqual(details["provider_mode"], "multi")
self.assertEqual(details["diversity_strategy"], "full_diversity")
def test_diversity_provider_aware_disabled(self):
"""Test that provider_aware=False uses standard requirements."""
loader = PersonaLoader()
is_valid, details = loader.verify_panel_diversity(provider_aware=False)
# Should use config-based requirements, not provider detection
self.assertIn("num_families", details)
# Default min_required from config should be used
self.assertGreaterEqual(details["min_required"], 3)
class TestConfidenceAdjustment(unittest.TestCase): """Test confidence adjustment based on provider mode."""
def setUp(self):
reset_default_detector()
def tearDown(self):
reset_default_detector()
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
}, clear=True)
def test_confidence_adjustment_single_provider(self):
"""Test -10% adjustment in single-provider mode."""
loader = PersonaLoader()
adjusted = loader.adjust_confidence_for_provider_mode(0.90)
# Single provider: 0.90 - 0.10 = 0.80
self.assertAlmostEqual(adjusted, 0.80, places=2)
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"OPENAI_API_KEY": "sk-openai-test",
}, clear=True)
def test_confidence_adjustment_dual_provider(self):
"""Test -5% adjustment in dual-provider mode."""
loader = PersonaLoader()
adjusted = loader.adjust_confidence_for_provider_mode(0.90)
# Dual provider: 0.90 - 0.05 = 0.85
self.assertAlmostEqual(adjusted, 0.85, places=2)
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"OPENAI_API_KEY": "sk-openai-test",
"DEEPSEEK_API_KEY": "sk-deepseek-test",
}, clear=True)
def test_confidence_adjustment_multi_provider(self):
"""Test no adjustment in multi-provider mode."""
loader = PersonaLoader()
adjusted = loader.adjust_confidence_for_provider_mode(0.90)
# Multi provider: no adjustment
self.assertAlmostEqual(adjusted, 0.90, places=2)
class TestConvenienceFunctions(unittest.TestCase): """Test module-level convenience functions."""
def setUp(self):
reset_default_detector()
def tearDown(self):
reset_default_detector()
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"OPENAI_API_KEY": "sk-openai-test",
}, clear=True)
def test_verify_panel_diversity_function(self):
"""Test convenience function for panel diversity."""
is_valid, details = verify_panel_diversity(provider_aware=True)
self.assertIn("provider_mode", details)
self.assertEqual(details["provider_mode"], "dual")
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
}, clear=True)
def test_adjust_confidence_function(self):
"""Test convenience function for confidence adjustment."""
adjusted = adjust_confidence_for_provider_mode(0.90)
self.assertAlmostEqual(adjusted, 0.80, places=2)
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"OPENAI_API_KEY": "sk-openai-test",
}, clear=True)
def test_get_provider_mode_function(self):
"""Test convenience function for provider mode."""
mode = get_provider_mode()
self.assertEqual(mode, ProviderMode.DUAL)
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
}, clear=True)
def test_get_diversity_report_function(self):
"""Test convenience function for diversity report."""
report = get_provider_diversity_report()
self.assertIn("mode", report)
self.assertIn("provider_count", report)
self.assertEqual(report["mode"], "single")
class TestEdgeCases(unittest.TestCase): """Test edge cases and error handling."""
def setUp(self):
reset_default_detector()
def tearDown(self):
reset_default_detector()
@patch.dict(os.environ, {}, clear=True)
def test_no_providers_available(self):
"""Test behavior when no providers are configured."""
loader = PersonaLoader()
# Should fall back to config-based selection
model = loader.get_model_for_persona("technical_architect", provider_aware=True)
# Should still return a model from config
self.assertIsNotNone(model)
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
"CODITECT_JUDGE_MODEL_TECHNICAL_ARCHITECT": "custom-model-override",
}, clear=True)
def test_env_override_takes_priority(self):
"""Test that environment variable overrides provider detection."""
loader = PersonaLoader()
model = loader.get_model_for_persona("technical_architect", provider_aware=True)
# Environment variable should take priority over provider detection
self.assertEqual(model, "custom-model-override")
@patch.dict(os.environ, {
"ANTHROPIC_API_KEY": "sk-ant-test",
}, clear=True)
def test_runtime_override_takes_priority(self):
"""Test that runtime override takes priority over everything."""
loader = PersonaLoader()
model = loader.get_model_for_persona(
"technical_architect",
override_model="explicit-override",
provider_aware=True
)
self.assertEqual(model, "explicit-override")
if name == "main": unittest.main()