|
1 | 1 | """ |
2 | | -Sample tests for AgentEx ACP agent. |
| 2 | +Tests for ab000-hello-acp (agentic agent) |
3 | 3 |
|
4 | | -This test suite demonstrates how to test the main AgentEx API functions: |
5 | | -- Non-streaming event sending and polling |
6 | | -- Streaming event sending |
| 4 | +This test suite demonstrates testing an agentic agent using the AgentEx testing framework. |
7 | 5 |
|
8 | | -To run these tests: |
9 | | -1. Make sure the agent is running (via docker-compose or `agentex agents run`) |
10 | | -2. Set the AGENTEX_API_BASE_URL environment variable if not using default |
11 | | -3. Run: pytest test_agent.py -v |
| 6 | +Test coverage: |
| 7 | +- Event sending and polling for responses |
| 8 | +- Streaming event responses |
| 9 | +- Task creation and message polling |
12 | 10 |
|
13 | | -Configuration: |
14 | | -- AGENTEX_API_BASE_URL: Base URL for the AgentEx server (default: http://localhost:5003) |
15 | | -- AGENT_NAME: Name of the agent to test (default: ab000-hello-acp) |
16 | | -""" |
| 11 | +Prerequisites: |
| 12 | + - AgentEx services running (make dev) |
| 13 | + - Agent running: agentex agents run --manifest manifest.yaml |
17 | 14 |
|
18 | | -import os |
19 | | -import uuid |
20 | | -import asyncio |
| 15 | +Run tests: |
| 16 | + pytest tests/test_agent.py -v |
| 17 | +""" |
21 | 18 |
|
22 | 19 | import pytest |
23 | | -import pytest_asyncio |
24 | | -from test_utils.agentic import ( |
25 | | - poll_messages, |
26 | | - stream_agent_response, |
27 | | - send_event_and_poll_yielding, |
| 20 | + |
| 21 | +from agentex.lib.testing import ( |
| 22 | + test_agentic_agent, |
| 23 | + assert_valid_agent_response, |
| 24 | + assert_agent_response_contains, |
28 | 25 | ) |
29 | 26 |
|
30 | | -from agentex import AsyncAgentex |
31 | | -from agentex.types import TaskMessage |
32 | | -from agentex.types.agent_rpc_params import ParamsCreateTaskRequest |
33 | | -from agentex.types.text_content_param import TextContentParam |
34 | | - |
35 | | -# Configuration from environment variables |
36 | | -AGENTEX_API_BASE_URL = os.environ.get("AGENTEX_API_BASE_URL", "http://localhost:5003") |
37 | | -AGENT_NAME = os.environ.get("AGENT_NAME", "ab000-hello-acp") |
38 | | - |
39 | | - |
40 | | -@pytest_asyncio.fixture |
41 | | -async def client(): |
42 | | - """Create an AgentEx client instance for testing.""" |
43 | | - client = AsyncAgentex(base_url=AGENTEX_API_BASE_URL) |
44 | | - yield client |
45 | | - await client.close() |
46 | | - |
47 | | - |
48 | | -@pytest.fixture |
49 | | -def agent_name(): |
50 | | - """Return the agent name for testing.""" |
51 | | - return AGENT_NAME |
52 | | - |
53 | | - |
54 | | -@pytest_asyncio.fixture |
55 | | -async def agent_id(client: AsyncAgentex, agent_name): |
56 | | - """Retrieve the agent ID based on the agent name.""" |
57 | | - agents = await client.agents.list() |
58 | | - for agent in agents: |
59 | | - if agent.name == agent_name: |
60 | | - return agent.id |
61 | | - raise ValueError(f"Agent with name {agent_name} not found.") |
62 | | - |
63 | | - |
64 | | -class TestNonStreamingEvents: |
65 | | - """Test non-streaming event sending and polling.""" |
66 | | - |
67 | | - @pytest.mark.asyncio |
68 | | - async def test_send_event_and_poll(self, client: AsyncAgentex, agent_id: str): |
69 | | - """Test sending an event and polling for the response.""" |
70 | | - # Create a task for this conversation |
71 | | - task_response = await client.agents.create_task(agent_id, params=ParamsCreateTaskRequest(name=uuid.uuid1().hex)) |
72 | | - task = task_response.result |
73 | | - assert task is not None |
74 | | - |
75 | | - # Poll for the initial task creation message |
76 | | - async for message in poll_messages( |
77 | | - client=client, |
78 | | - task_id=task.id, |
79 | | - timeout=30, |
80 | | - sleep_interval=1.0, |
81 | | - ): |
82 | | - assert isinstance(message, TaskMessage) |
83 | | - if message.content and message.content.type == "text" and message.content.author == "agent": |
84 | | - assert "Hello! I've received your task" in message.content.content |
85 | | - break |
| 27 | +AGENT_NAME = "ab000-hello-acp" |
86 | 28 |
|
87 | | - # Send an event and poll for response |
88 | | - user_message = "Hello, this is a test message!" |
89 | | - async for message in send_event_and_poll_yielding( |
90 | | - client=client, |
91 | | - agent_id=agent_id, |
92 | | - task_id=task.id, |
93 | | - user_message=user_message, |
94 | | - timeout=30, |
95 | | - sleep_interval=1.0, |
96 | | - ): |
97 | | - assert isinstance(message, TaskMessage) |
98 | | - if message.content and message.content.type == "text" and message.content.author == "agent": |
99 | | - assert "Hello! I've received your message" in message.content.content |
100 | | - break |
101 | 29 |
|
| 30 | +@pytest.mark.asyncio |
| 31 | +async def test_send_event_and_poll(): |
| 32 | + """Test sending an event and polling for the response.""" |
| 33 | + async with test_agentic_agent(agent_name=AGENT_NAME) as test: |
| 34 | + # First event - should get initial task creation message |
| 35 | + initial_response = await test.send_event("Start task", timeout_seconds=30.0) |
| 36 | + assert_valid_agent_response(initial_response) |
| 37 | + assert_agent_response_contains(initial_response, "Hello! I've received your task") |
102 | 38 |
|
103 | | -class TestStreamingEvents: |
104 | | - """Test streaming event sending.""" |
| 39 | + # Second event - send user message |
| 40 | + user_message = "Hello, this is a test message!" |
| 41 | + response = await test.send_event(user_message, timeout_seconds=30.0) |
105 | 42 |
|
106 | | - @pytest.mark.asyncio |
107 | | - async def test_send_event_and_stream(self, client: AsyncAgentex, agent_id: str): |
108 | | - """Test sending an event and streaming the response.""" |
109 | | - task_response = await client.agents.create_task(agent_id, params=ParamsCreateTaskRequest(name=uuid.uuid1().hex)) |
110 | | - task = task_response.result |
111 | | - assert task is not None |
| 43 | + # Validate response |
| 44 | + assert_valid_agent_response(response) |
| 45 | + assert_agent_response_contains(response, "Hello! I've received your message") |
112 | 46 |
|
113 | | - user_message = "Hello, this is a test message!" |
114 | 47 |
|
115 | | - # Collect events from stream |
116 | | - all_events = [] |
| 48 | +@pytest.mark.asyncio |
| 49 | +async def test_send_event_and_stream(): |
| 50 | + """Test sending an event and streaming the response.""" |
| 51 | + async with test_agentic_agent(agent_name=AGENT_NAME) as test: |
| 52 | + user_message = "Hello, this is a test message!" |
117 | 53 |
|
118 | | - # Flags to track what we've received |
| 54 | + # Track what events we see |
119 | 55 | task_creation_found = False |
120 | 56 | user_echo_found = False |
121 | 57 | agent_response_found = False |
| 58 | + all_events = [] |
| 59 | + |
| 60 | + # Stream events |
| 61 | + async for event in test.send_event_and_stream(user_message, timeout_seconds=30.0): |
| 62 | + all_events.append(event) |
| 63 | + event_type = event.get("type") |
| 64 | + |
| 65 | + if event_type == "full": |
| 66 | + content = event.get("content", {}) |
| 67 | + if content.get("content") is None: |
| 68 | + continue # Skip empty content |
| 69 | + |
| 70 | + if content.get("type") == "text" and content.get("author") == "agent": |
| 71 | + # Check for initial task creation message |
| 72 | + if "Hello! I've received your task" in content.get("content", ""): |
| 73 | + task_creation_found = True |
| 74 | + # Check for agent response to user message |
| 75 | + elif "Hello! I've received your message" in content.get("content", ""): |
| 76 | + agent_response_found = True |
| 77 | + |
| 78 | + elif content.get("type") == "text" and content.get("author") == "user": |
| 79 | + # Check for user message echo (may or may not be present) |
| 80 | + if content.get("content") == user_message: |
| 81 | + user_echo_found = True |
| 82 | + |
| 83 | + # Exit early if we've found expected messages |
| 84 | + if task_creation_found and agent_response_found: |
| 85 | + break |
122 | 86 |
|
123 | | - async def collect_stream_events(): |
124 | | - nonlocal task_creation_found, user_echo_found, agent_response_found |
125 | | - |
126 | | - async for event in stream_agent_response( |
127 | | - client=client, |
128 | | - task_id=task.id, |
129 | | - timeout=30, |
130 | | - ): |
131 | | - all_events.append(event) |
132 | | - # Check events as they arrive |
133 | | - event_type = event.get("type") |
134 | | - if event_type == "full": |
135 | | - content = event.get("content", {}) |
136 | | - if content.get("content") is None: |
137 | | - continue # Skip empty content |
138 | | - if content.get("type") == "text" and content.get("author") == "agent": |
139 | | - # Check for initial task creation message |
140 | | - if "Hello! I've received your task" in content.get("content", ""): |
141 | | - task_creation_found = True |
142 | | - # Check for agent response to user message |
143 | | - elif "Hello! I've received your message" in content.get("content", ""): |
144 | | - # Agent response should come after user echo |
145 | | - assert user_echo_found, "Agent response arrived before user message echo (incorrect order)" |
146 | | - agent_response_found = True |
147 | | - elif content.get("type") == "text" and content.get("author") == "user": |
148 | | - # Check for user message echo |
149 | | - if content.get("content") == user_message: |
150 | | - user_echo_found = True |
151 | | - |
152 | | - # Exit early if we've found all expected messages |
153 | | - if task_creation_found and user_echo_found and agent_response_found: |
154 | | - break |
155 | | - |
156 | | - # Start streaming task |
157 | | - stream_task = asyncio.create_task(collect_stream_events()) |
158 | | - |
159 | | - # Send the event |
160 | | - event_content = TextContentParam(type="text", author="user", content=user_message) |
161 | | - await client.agents.send_event(agent_id=agent_id, params={"task_id": task.id, "content": event_content}) |
162 | | - |
163 | | - # Wait for streaming to complete |
164 | | - await stream_task |
| 87 | + # Validate we saw expected messages |
| 88 | + assert task_creation_found or agent_response_found, "Did not receive agent messages" |
| 89 | + assert len(all_events) > 0, "Should receive events" |
165 | 90 |
|
166 | 91 |
|
167 | 92 | if __name__ == "__main__": |
|
0 commit comments