test_backend_semantics.py
1 """ 2 Test semantic correctness of the new HostedAgent/LocalAgent split. 3 4 Ensures that the provider= overload fix maintains all backward compatibility 5 while clearly distinguishing hosted runtime from local execution semantics. 6 """ 7 import pytest 8 import warnings 9 from unittest.mock import patch, MagicMock 10 11 def test_hosted_agent_imports(): 12 """Test that new HostedAgent classes can be imported.""" 13 from praisonai.integrations import HostedAgent, HostedAgentConfig 14 assert HostedAgent is not None 15 assert HostedAgentConfig is not None 16 17 # Also test top-level imports 18 from praisonai import HostedAgent as TopLevelHostedAgent 19 from praisonai import HostedAgentConfig as TopLevelHostedAgentConfig 20 assert TopLevelHostedAgent is not None 21 assert TopLevelHostedAgentConfig is not None 22 23 24 def test_local_agent_imports(): 25 """Test that new LocalAgent classes can be imported.""" 26 from praisonai.integrations import LocalAgent, LocalAgentConfig 27 assert LocalAgent is not None 28 assert LocalAgentConfig is not None 29 30 # Also test top-level imports 31 from praisonai import LocalAgent as TopLevelLocalAgent 32 from praisonai import LocalAgentConfig as TopLevelLocalAgentConfig 33 assert TopLevelLocalAgent is not None 34 assert TopLevelLocalAgentConfig is not None 35 36 37 def test_hosted_agent_only_accepts_anthropic(): 38 """Test that HostedAgent only accepts 'anthropic' as provider.""" 39 from praisonai.integrations import HostedAgent, HostedAgentConfig 40 41 # Should work 42 hosted = HostedAgent(provider="anthropic") 43 assert hosted.provider == "anthropic" 44 45 # Should raise ValueError for non-existent managed runtimes 46 with pytest.raises(ValueError) as exc_info: 47 HostedAgent(provider="modal") 48 assert "not yet available" in str(exc_info.value) 49 assert "LocalAgent" in str(exc_info.value) 50 51 with pytest.raises(ValueError) as exc_info: 52 HostedAgent(provider="e2b") 53 assert "not yet available" in str(exc_info.value) 54 55 with pytest.raises(ValueError) as exc_info: 56 HostedAgent(provider="openai") 57 assert "not yet available" in str(exc_info.value) 58 59 60 def test_local_agent_rejects_provider_overload(): 61 """Test that LocalAgent rejects the provider= overload pattern.""" 62 from praisonai.integrations import LocalAgent, LocalAgentConfig 63 64 # Should work without provider= 65 local = LocalAgent(config=LocalAgentConfig(model="gpt-4o-mini")) 66 67 # Should warn when provider= is used (deprecated pattern) 68 with warnings.catch_warnings(record=True) as w: 69 warnings.simplefilter("always") 70 LocalAgent(provider="openai", config=LocalAgentConfig(model="gpt-4o-mini")) 71 # Filter to only DeprecationWarning containing provider= to avoid false positives 72 dep_warnings = [ 73 rec for rec in w 74 if issubclass(rec.category, DeprecationWarning) 75 and "provider=" in str(rec.message) 76 and "config.model=" in str(rec.message) 77 ] 78 assert len(dep_warnings) == 1, f"Expected 1 provider= deprecation warning, got {len(dep_warnings)} from {len(w)} total warnings" 79 80 81 def test_managed_agent_deprecation_warnings(): 82 """Test that ManagedAgent emits proper deprecation warnings.""" 83 from praisonai.integrations.managed_agents import ManagedAgent 84 85 # LLM routing providers should emit deprecation warning 86 with warnings.catch_warnings(record=True) as w: 87 warnings.simplefilter("always") 88 89 with patch('praisonai.integrations.managed_local.LocalManagedAgent'): 90 ManagedAgent(provider="openai") 91 assert len(w) == 1 92 assert issubclass(w[0].category, DeprecationWarning) 93 assert "deprecated" in str(w[0].message).lower() 94 assert "LocalAgent" in str(w[0].message) 95 96 97 def test_managed_agent_compute_provider_errors(): 98 """Test that ManagedAgent raises proper errors for compute provider names.""" 99 from praisonai.integrations.managed_agents import ManagedAgent 100 101 # Compute providers should raise ValueError 102 with pytest.raises(ValueError) as exc_info: 103 ManagedAgent(provider="modal") 104 assert "compute" in str(exc_info.value).lower() 105 assert "LocalAgent" in str(exc_info.value) 106 107 with pytest.raises(ValueError) as exc_info: 108 ManagedAgent(provider="e2b") 109 assert "compute" in str(exc_info.value).lower() 110 assert "LocalAgent" in str(exc_info.value) 111 112 with pytest.raises(ValueError) as exc_info: 113 ManagedAgent(provider="docker") 114 assert "compute" in str(exc_info.value).lower() 115 assert "LocalAgent" in str(exc_info.value) 116 117 118 def test_managed_agent_anthropic_passthrough(): 119 """Test that ManagedAgent(provider='anthropic') still works.""" 120 from praisonai.integrations.managed_agents import ManagedAgent, AnthropicManagedAgent 121 122 with patch('praisonai.integrations.managed_agents.AnthropicManagedAgent') as mock_anthropic: 123 mock_instance = MagicMock() 124 mock_anthropic.return_value = mock_instance 125 126 result = ManagedAgent(provider="anthropic") 127 128 mock_anthropic.assert_called_once_with(provider="anthropic") 129 assert result == mock_instance 130 131 132 def test_backward_compatibility_all_old_names(): 133 """Test that all old import paths still work.""" 134 # All these should import without errors 135 from praisonai.integrations.managed_agents import ( 136 ManagedAgent, ManagedConfig, AnthropicManagedAgent, 137 ManagedAgentIntegration, ManagedBackendConfig 138 ) 139 from praisonai.integrations.managed_local import ( 140 LocalManagedAgent, LocalManagedConfig 141 ) 142 from praisonai.integrations.sandboxed_agent import ( 143 SandboxedAgent, SandboxedAgentConfig 144 ) 145 146 # Top-level imports 147 from praisonai import ( 148 ManagedAgent as TopManagedAgent, 149 ManagedConfig as TopManagedConfig, 150 AnthropicManagedAgent as TopAnthropicManagedAgent, 151 LocalManagedAgent as TopLocalManagedAgent, 152 LocalManagedConfig as TopLocalManagedConfig, 153 SandboxedAgent as TopSandboxedAgent, 154 SandboxedAgentConfig as TopSandboxedAgentConfig, 155 ) 156 157 # All should be defined 158 assert ManagedAgent is not None 159 assert ManagedConfig is not None 160 assert AnthropicManagedAgent is not None 161 assert ManagedAgentIntegration is not None 162 assert ManagedBackendConfig is not None 163 assert LocalManagedAgent is not None 164 assert LocalManagedConfig is not None 165 assert SandboxedAgent is not None 166 assert SandboxedAgentConfig is not None 167 168 169 def test_config_aliases(): 170 """Test that config class aliases work correctly.""" 171 from praisonai.integrations import ( 172 HostedAgent, HostedAgentConfig, LocalAgent, LocalAgentConfig 173 ) 174 from praisonai.integrations.managed_agents import ManagedConfig 175 from praisonai.integrations.managed_local import LocalManagedConfig 176 177 # HostedAgentConfig should alias ManagedConfig 178 assert HostedAgentConfig is ManagedConfig 179 180 # LocalAgentConfig should alias LocalManagedConfig 181 assert LocalAgentConfig is LocalManagedConfig 182 183 184 def test_unknown_provider_error(): 185 """Test that unknown providers raise helpful error messages.""" 186 from praisonai.integrations.managed_agents import ManagedAgent 187 188 with pytest.raises(ValueError) as exc_info: 189 ManagedAgent(provider="unknown-provider") 190 assert "Unknown provider" in str(exc_info.value) 191 assert "anthropic" in str(exc_info.value) 192 assert "LocalAgent" in str(exc_info.value)