"""Tests for Agent.kickoff() with A2A delegation using VCR cassettes.""" from __future__ import annotations import os import pytest from crewai import Agent from crewai.a2a.config import A2AClientConfig A2A_TEST_ENDPOINT = os.getenv( "A2A_TEST_ENDPOINT", "http://localhost:9999/.well-known/agent-card.json" ) class TestAgentA2AKickoff: """Tests for Agent.kickoff() with A2A delegation.""" @pytest.fixture def researcher_agent(self) -> Agent: """Create a research agent with A2A configuration.""" return Agent( role="Research Analyst", goal="Find and analyze information about AI developments", backstory="Expert researcher with access to remote specialized agents", verbose=True, a2a=[ A2AClientConfig( endpoint=A2A_TEST_ENDPOINT, fail_fast=False, max_turns=3, # Limit turns for testing ) ], ) @pytest.mark.skip(reason="VCR cassette matching issue with agent card caching") @pytest.mark.vcr() def test_agent_kickoff_delegates_to_a2a(self, researcher_agent: Agent) -> None: """Test that agent.kickoff() delegates to A2A server.""" result = researcher_agent.kickoff( "Use the remote A2A agent to find out what the current time is in New York." ) assert result is not None assert result.raw is not None assert isinstance(result.raw, str) assert len(result.raw) > 0 @pytest.mark.skip(reason="VCR cassette matching issue with agent card caching") @pytest.mark.vcr() def test_agent_kickoff_with_calculator_skill( self, researcher_agent: Agent ) -> None: """Test that agent can delegate calculation to A2A server.""" result = researcher_agent.kickoff( "Ask the remote A2A agent to calculate 25 times 17." ) assert result is not None assert result.raw is not None assert "425" in result.raw or "425.0" in result.raw @pytest.mark.skip(reason="VCR cassette matching issue with agent card caching") @pytest.mark.vcr() def test_agent_kickoff_with_conversation_skill( self, researcher_agent: Agent ) -> None: """Test that agent can have a conversation with A2A server.""" result = researcher_agent.kickoff( "Delegate to the remote A2A agent to explain quantum computing in simple terms." ) assert result is not None assert result.raw is not None assert isinstance(result.raw, str) assert len(result.raw) > 50 # Should have a meaningful response @pytest.mark.vcr() def test_agent_kickoff_returns_lite_agent_output( self, researcher_agent: Agent ) -> None: """Test that kickoff returns LiteAgentOutput with correct structure.""" from crewai.lite_agent_output import LiteAgentOutput result = researcher_agent.kickoff( "Use the A2A agent to tell me what time it is." ) assert isinstance(result, LiteAgentOutput) assert result.raw is not None assert result.agent_role == "Research Analyst" assert isinstance(result.messages, list) @pytest.mark.skip(reason="VCR cassette matching issue with agent card caching") @pytest.mark.vcr() def test_agent_kickoff_handles_multi_turn_conversation( self, researcher_agent: Agent ) -> None: """Test that agent handles multi-turn A2A conversations.""" # This should trigger multiple turns of conversation result = researcher_agent.kickoff( "Ask the remote A2A agent about recent developments in AI agent communication protocols." ) assert result is not None assert result.raw is not None # The response should contain information about A2A or agent protocols assert isinstance(result.raw, str) @pytest.mark.vcr() def test_agent_without_a2a_works_normally(self) -> None: """Test that agent without A2A config works normally.""" agent = Agent( role="Simple Assistant", goal="Help with basic tasks", backstory="A helpful assistant", verbose=False, ) # This should work without A2A delegation result = agent.kickoff("Say hello") assert result is not None assert result.raw is not None @pytest.mark.vcr() def test_agent_kickoff_with_failed_a2a_endpoint(self) -> None: """Test that agent handles failed A2A connection gracefully.""" agent = Agent( role="Research Analyst", goal="Find information", backstory="Expert researcher", verbose=False, a2a=[ A2AClientConfig( endpoint="http://nonexistent:9999/.well-known/agent-card.json", fail_fast=False, ) ], ) # Should fallback to local LLM when A2A fails result = agent.kickoff("What is 2 + 2?") assert result is not None assert result.raw is not None @pytest.mark.skip(reason="VCR cassette matching issue with agent card caching") @pytest.mark.vcr() def test_agent_kickoff_with_list_messages( self, researcher_agent: Agent ) -> None: """Test that agent.kickoff() works with list of messages.""" messages = [ { "role": "user", "content": "Delegate to the A2A agent to find the current time in Tokyo.", }, ] result = researcher_agent.kickoff(messages) assert result is not None assert result.raw is not None assert isinstance(result.raw, str) class TestAgentA2AKickoffAsync: """Tests for async Agent.kickoff_async() with A2A delegation.""" @pytest.fixture def researcher_agent(self) -> Agent: """Create a research agent with A2A configuration.""" return Agent( role="Research Analyst", goal="Find and analyze information", backstory="Expert researcher with access to remote agents", verbose=True, a2a=[ A2AClientConfig( endpoint=A2A_TEST_ENDPOINT, fail_fast=False, max_turns=3, ) ], ) @pytest.mark.vcr() @pytest.mark.asyncio async def test_agent_kickoff_async_delegates_to_a2a( self, researcher_agent: Agent ) -> None: """Test that agent.kickoff_async() delegates to A2A server.""" result = await researcher_agent.kickoff_async( "Use the remote A2A agent to calculate 10 plus 15." ) assert result is not None assert result.raw is not None assert isinstance(result.raw, str) @pytest.mark.skip(reason="Test assertion needs fixing - not capturing final answer") @pytest.mark.vcr() @pytest.mark.asyncio async def test_agent_kickoff_async_with_calculator( self, researcher_agent: Agent ) -> None: """Test async delegation with calculator skill.""" result = await researcher_agent.kickoff_async( "Ask the A2A agent to calculate 100 divided by 4." ) assert result is not None assert result.raw is not None assert "25" in result.raw or "25.0" in result.raw