Skip to content

Commit ef763d3

Browse files
committed
.
1 parent 5c9cdd6 commit ef763d3

File tree

14 files changed

+100
-1071
lines changed

14 files changed

+100
-1071
lines changed

examples/tutorials/10_async/10_temporal/060_open_ai_agents_sdk_hello_world/060_open_ai_agents_sdk_hello_world/project/run_worker.py

Lines changed: 0 additions & 39 deletions
This file was deleted.

examples/tutorials/10_async/10_temporal/060_open_ai_agents_sdk_hello_world/060_open_ai_agents_sdk_hello_world/tests/test_agent.py

Lines changed: 0 additions & 40 deletions
This file was deleted.

examples/tutorials/10_async/10_temporal/060_open_ai_agents_sdk_hello_world/project/run_worker.py

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import asyncio
22

3+
from project.workflow import ExampleTutorialWorkflow
34
from temporalio.contrib.openai_agents import OpenAIAgentsPlugin
45

5-
from project.workflow import At060OpenAiAgentsSdkHelloWorldWorkflow
66
from agentex.lib.utils.debug import setup_debug_if_enabled
77
from agentex.lib.utils.logging import make_logger
88
from agentex.lib.environment_variables import EnvironmentVariables
99
from agentex.lib.core.temporal.activities import get_all_activities
1010
from agentex.lib.core.temporal.workers.worker import AgentexWorker
11-
from agentex.lib.core.temporal.plugins.openai_agents.models.temporal_streaming_model import (
12-
TemporalStreamingModelProvider,
13-
)
14-
from agentex.lib.core.temporal.plugins.openai_agents.interceptors.context_interceptor import ContextInterceptor
1511

1612
environment_variables = EnvironmentVariables.refresh()
1713

@@ -29,40 +25,13 @@ async def main():
2925
# Add activities to the worker
3026
all_activities = get_all_activities() + [] # add your own activities here
3127

32-
# ============================================================================
33-
# STREAMING SETUP: Interceptor + Model Provider
34-
# ============================================================================
35-
# This is where the streaming magic is configured! Two key components:
36-
#
37-
# 1. ContextInterceptor
38-
# - Threads task_id through activity headers using Temporal's interceptor pattern
39-
# - Outbound: Reads _task_id from workflow instance, injects into activity headers
40-
# - Inbound: Extracts task_id from headers, sets streaming_task_id ContextVar
41-
# - This enables runtime context without forking the Temporal plugin!
42-
#
43-
# 2. TemporalStreamingModelProvider
44-
# - Returns TemporalStreamingModel instances that read task_id from ContextVar
45-
# - TemporalStreamingModel.get_response() streams tokens to Redis in real-time
46-
# - Still returns complete response to Temporal for determinism/replay safety
47-
# - Uses AgentEx ADK streaming infrastructure (Redis XADD to stream:{task_id})
48-
#
49-
# Together, these enable real-time LLM streaming while maintaining Temporal's
50-
# durability guarantees. No forked components - uses STANDARD OpenAIAgentsPlugin!
51-
context_interceptor = ContextInterceptor()
52-
temporal_streaming_model_provider = TemporalStreamingModelProvider()
53-
5428
# Create a worker with automatic tracing
55-
# IMPORTANT: We use the STANDARD temporalio.contrib.openai_agents.OpenAIAgentsPlugin
56-
# No forking needed! The interceptor + model provider handle all streaming logic.
57-
worker = AgentexWorker(
58-
task_queue=task_queue_name,
59-
plugins=[OpenAIAgentsPlugin(model_provider=temporal_streaming_model_provider)],
60-
interceptors=[context_interceptor],
61-
)
29+
# We are also adding the Open AI Agents SDK plugin to the worker.
30+
worker = AgentexWorker(task_queue=task_queue_name, plugins=[OpenAIAgentsPlugin()])
6231

6332
await worker.run(
6433
activities=all_activities,
65-
workflow=At060OpenAiAgentsSdkHelloWorldWorkflow,
34+
workflow=ExampleTutorialWorkflow,
6635
)
6736

6837

examples/tutorials/10_async/10_temporal/060_open_ai_agents_sdk_hello_world/tests/test_agent.py

Lines changed: 23 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,39 @@
11
"""
2-
Sample tests for AgentEx ACP agent.
2+
Tests for example-tutorial (OpenAI Agents SDK Hello World)
33
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+
Prerequisites:
5+
- AgentEx services running (make dev)
6+
- Temporal server running
7+
- Agent running: agentex agents run --manifest manifest.yaml
78
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
12-
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: example-tutorial)
9+
Run: pytest tests/test_agent.py -v
1610
"""
1711

18-
import os
19-
import uuid
20-
2112
import pytest
22-
import pytest_asyncio
23-
from test_utils.async_utils import (
24-
poll_messages,
25-
send_event_and_poll_yielding,
26-
)
27-
28-
from agentex import AsyncAgentex
29-
from agentex.types.task_message import TaskMessage
30-
from agentex.types.agent_rpc_params import ParamsCreateTaskRequest
31-
32-
# Configuration from environment variables
33-
AGENTEX_API_BASE_URL = os.environ.get("AGENTEX_API_BASE_URL", "http://localhost:5003")
34-
AGENT_NAME = os.environ.get("AGENT_NAME", "at060-open-ai-agents-sdk-hello-world")
35-
3613

37-
@pytest_asyncio.fixture
38-
async def client():
39-
"""Create an AsyncAgentex client instance for testing."""
40-
client = AsyncAgentex(base_url=AGENTEX_API_BASE_URL)
41-
yield client
42-
await client.close()
14+
from agentex.lib.testing import async_test_agent, assert_valid_agent_response
4315

16+
AGENT_NAME = "example-tutorial"
4417

45-
@pytest.fixture
46-
def agent_name():
47-
"""Return the agent name for testing."""
48-
return AGENT_NAME
4918

19+
@pytest.mark.asyncio
20+
async def test_agent_basic():
21+
"""Test basic agent functionality."""
22+
async with async_test_agent(agent_name=AGENT_NAME) as test:
23+
response = await test.send_event("Test message", timeout_seconds=60.0)
24+
assert_valid_agent_response(response)
5025

51-
@pytest_asyncio.fixture
52-
async def agent_id(client, agent_name):
53-
"""Retrieve the agent ID based on the agent name."""
54-
agents = await client.agents.list()
55-
for agent in agents:
56-
if agent.name == agent_name:
57-
return agent.id
58-
raise ValueError(f"Agent with name {agent_name} not found.")
5926

60-
61-
class TestNonStreamingEvents:
62-
"""Test non-streaming event sending and polling."""
63-
64-
@pytest.mark.asyncio
65-
async def test_send_event_and_poll(self, client: AsyncAgentex, agent_id: str):
66-
"""Test sending an event and polling for the response."""
67-
task_response = await client.agents.create_task(agent_id, params=ParamsCreateTaskRequest(name=uuid.uuid1().hex))
68-
task = task_response.result
69-
assert task is not None
70-
71-
# Poll for the initial task creation message
72-
async for message in poll_messages(
73-
client=client,
74-
task_id=task.id,
75-
timeout=30,
76-
sleep_interval=1.0,
77-
):
78-
assert isinstance(message, TaskMessage)
79-
if message.content and message.content.type == "text" and message.content.author == "agent":
80-
# Check for the Haiku Assistant welcome message
81-
assert "Haiku Assistant" in message.content.content
82-
assert "Temporal" in message.content.content
27+
@pytest.mark.asyncio
28+
async def test_agent_streaming():
29+
"""Test streaming responses."""
30+
async with async_test_agent(agent_name=AGENT_NAME) as test:
31+
events = []
32+
async for event in test.send_event_and_stream("Stream test", timeout_seconds=60.0):
33+
events.append(event)
34+
if event.get("type") == "done":
8335
break
84-
85-
# Send event and poll for response with streaming updates
86-
user_message = "Hello how is life?"
87-
print(f"[DEBUG 060 POLL] Sending message: '{user_message}'")
88-
89-
# Use yield_updates=True to get all streaming chunks as they're written
90-
final_message = None
91-
async for message in send_event_and_poll_yielding(
92-
client=client,
93-
agent_id=agent_id,
94-
task_id=task.id,
95-
user_message=user_message,
96-
timeout=30,
97-
sleep_interval=1.0,
98-
yield_updates=True, # Get updates as streaming writes chunks
99-
):
100-
if message.content and message.content.type == "text" and message.content.author == "agent":
101-
print(
102-
f"[DEBUG 060 POLL] Received update - Status: {message.streaming_status}, "
103-
f"Content length: {len(message.content.content)}"
104-
)
105-
final_message = message
106-
107-
# Stop polling once we get a DONE message
108-
if message.streaming_status == "DONE":
109-
print(f"[DEBUG 060 POLL] Streaming complete!")
110-
break
111-
112-
# Verify the final message has content (the haiku)
113-
assert final_message is not None, "Should have received an agent message"
114-
assert final_message.content is not None, "Final message should have content"
115-
assert len(final_message.content.content) > 0, "Final message should have haiku content"
116-
117-
print(f"[DEBUG 060 POLL] ✅ Successfully received haiku response!")
118-
print(f"[DEBUG 060 POLL] Final haiku:\n{final_message.content.content}")
119-
pass
120-
121-
122-
class TestStreamingEvents:
123-
"""Test streaming event sending (backend verification via polling)."""
124-
125-
@pytest.mark.asyncio
126-
async def test_send_event_and_stream(self, client: AsyncAgentex, agent_id: str):
127-
"""
128-
Streaming test placeholder.
129-
130-
NOTE: SSE streaming is tested via the UI (agentex-ui subscribeTaskState).
131-
Backend streaming functionality is verified in test_send_event_and_poll.
132-
"""
133-
pass
36+
assert len(events) > 0
13437

13538

13639
if __name__ == "__main__":

examples/tutorials/10_async/10_temporal/070_open_ai_agents_sdk_tools/070_open_ai_agents_sdk_tools/project/run_worker.py

Lines changed: 0 additions & 44 deletions
This file was deleted.

examples/tutorials/10_async/10_temporal/070_open_ai_agents_sdk_tools/070_open_ai_agents_sdk_tools/tests/test_agent.py

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)