Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions examples/zero-code-examples/openai-agents/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
openai-agents>=0.3.3
opentelemetry-instrumentation-openai-agents-v2>=0.1.0

opentelemetry-sdk>=1.36.0
opentelemetry-exporter-otlp-proto-http>=1.36.0
python-dotenv>=1.0.0
105 changes: 105 additions & 0 deletions examples/zero-code-examples/openai-agents/run.py
Comment thread
shahar-dagan marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""Run a dice-rolling OpenAI Agents SDK agent with OTLP export — no agentevals SDK.

Demonstrates zero-code integration: any OTel-instrumented agent streams
traces to agentevals by pointing the OTLP exporter at the receiver.

Unlike the LangChain and Strands examples, this one is fully self-contained:
the agent code lives inline with no cross-folder imports.

Prerequisites:
1. pip install -r requirements.txt
2. agentevals serve --dev
3. export OPENAI_API_KEY="your-key-here"

Usage:
python examples/zero-code-examples/openai-agents/run.py
"""

import os
import random

from agents import Agent, Runner, function_tool
from dotenv import load_dotenv
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.openai_agents import OpenAIAgentsInstrumentor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

load_dotenv(override=True)


@function_tool
def roll_die(sides: int) -> int:
"""Roll a die with the given number of sides and return the result."""
return random.randint(1, sides)


@function_tool
def check_prime(number: int) -> bool:
"""Return True if the number is prime, False otherwise."""
if number < 2:
return False
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
return False
return True


def main():
if not os.getenv("OPENAI_API_KEY"):
print("OPENAI_API_KEY not set.")
return

endpoint = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318")
print(f"OTLP endpoint: {endpoint}")

os.environ.setdefault("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", "span_and_event")

os.environ.setdefault(
"OTEL_RESOURCE_ATTRIBUTES",
"agentevals.eval_set_id=openai_agents_eval,agentevals.session_name=openai-agents-zero-code",
)

resource = Resource.create()

tracer_provider = TracerProvider(resource=resource)
tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(), schedule_delay_millis=1000))
trace.set_tracer_provider(tracer_provider)

OpenAIAgentsInstrumentor().instrument()

agent = Agent(
name="Dice Agent",
instructions="You are a helpful assistant. You can roll dice and check if numbers are prime.",
tools=[roll_die, check_prime],
)

test_queries = [
"Hi! Can you help me?",
"Roll a 20-sided die for me",
"Is the number you rolled prime?",
]

conversation_input: list = []

try:
for i, query in enumerate(test_queries, 1):
print(f"\n[{i}/{len(test_queries)}] User: {query}")

conversation_input.append({"role": "user", "content": query})
result = Runner.run_sync(agent, conversation_input)

agent_response = result.final_output or ""
print(f" Agent: {agent_response}")

conversation_input = result.to_input_list()
finally:
print()
tracer_provider.force_flush()
print("All traces flushed to OTLP receiver.")


if __name__ == "__main__":
main()
57 changes: 57 additions & 0 deletions tests/integration/test_live_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,63 @@ def test_session_visible_via_api(self, live_servers):
assert session_name in session_ids


@_skip_no_openai
class TestOpenAIAgentsZeroCode:
"""Run the OpenAI Agents SDK zero-code OTLP example and verify session grouping."""

def test_session_created_with_spans(self, live_servers):
main_port, otlp_port, mgr = live_servers
session_name = "e2e-openai-agents"

result = _run_agent(
"examples/zero-code-examples/openai-agents/run.py",
otlp_port,
session_name,
)
assert result.returncode == 0, f"Agent failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"

wait_for_session_complete_sync(mgr, session_name, timeout=30)
session = mgr.sessions[session_name]

assert session.is_complete
assert session.source == "otlp"
assert len(session.spans) > 0, "Expected spans from LLM calls"

def test_invocations_extracted(self, live_servers):
main_port, otlp_port, mgr = live_servers
session_name = "e2e-openai-agents-inv"

result = _run_agent(
"examples/zero-code-examples/openai-agents/run.py",
otlp_port,
session_name,
)
assert result.returncode == 0, f"Agent failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"

wait_for_session_complete_sync(mgr, session_name, timeout=30)
session = mgr.sessions[session_name]

assert len(session.invocations) > 0, "Expected extracted invocations"

def test_session_visible_via_api(self, live_servers):
main_port, otlp_port, mgr = live_servers
session_name = "e2e-openai-agents-api"

result = _run_agent(
"examples/zero-code-examples/openai-agents/run.py",
otlp_port,
session_name,
)
assert result.returncode == 0

wait_for_session_complete_sync(mgr, session_name, timeout=30)

resp = httpx.get(f"http://127.0.0.1:{main_port}/api/streaming/sessions")
assert resp.status_code == 200
session_ids = [s["sessionId"] for s in resp.json()["data"]]
assert session_name in session_ids


@_skip_no_openai
class TestAgentRerun:
"""Verify that re-running an agent with the same session_name creates
Expand Down
Loading