/ tests / unit / integrations / test_backend_semantics.py
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)