-
Notifications
You must be signed in to change notification settings - Fork 924
Workflow root span for openai agents #3825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
4830f59
Implement OpenAI Agents span processing
nagkumar91 e279865
Merge branch 'main' into tracers-and-spans
nagkumar91 44b91e8
Update OpenAI Agents changelog with PR references
nagkumar91 1d78868
Add OpenAI Agents manual and zero-code examples
nagkumar91 f0154ea
Load dotenv in OpenAI Agents examples
nagkumar91 ed61f0d
Update the tracer and finalize tests
nagkumar91 9633585
Capture spans from zero code sample
nagkumar91 eefc31b
Merge branch 'main' into tracers-and-spans
nagkumar91 ba45d16
Default OpenAI agent trace start to now
nagkumar91 20e80a3
Annotate OpenAI trace provider helper
nagkumar91 5165bad
Remove OpenAI Agents system env override
nagkumar91 fd707d3
Use gen_ai.provider.name for OpenAI Agents spans
nagkumar91 523e7e2
Support new SDK InMemorySpanExporter import in tests
nagkumar91 3c5fd9a
Ensure OpenAI agent span names include model when available
nagkumar91 c032131
Handle agent creation spans in OpenAI Agents instrumentation
nagkumar91 b3cc03a
Allow overriding OpenAI agent name via environment variable
nagkumar91 c813d08
Define span type constants for OpenAI Agents instrumentation
nagkumar91 0ec1c82
Add OpenAI Agents response and completion span tests
nagkumar91 407fdfb
Match response finish reasons tuple in tests
nagkumar91 0125626
Add workflow root span support and handoff example
nagkumar91 1c34387
Merge branch 'main' into workflow-root-span
nagkumar91 1981410
Merge branch 'main' into workflow-root-span
nagkumar91 147b9d1
Merge branch 'main' into workflow-root-span
nagkumar91 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
instrumentation-genai/opentelemetry-instrumentation-openai-agents/.gitignore
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| examples/.env | ||
| examples/openai_agents_multi_agent_travel/.env | ||
| examples/**/.env |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
...entation-genai/opentelemetry-instrumentation-openai-agents/examples/handoffs/.env.example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Update this with your real OpenAI API key | ||
| OPENAI_API_KEY=sk-YOUR_API_KEY | ||
|
|
||
| # Uncomment and adjust if you use a non-default OTLP collector endpoint | ||
| # OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 | ||
| # OTEL_EXPORTER_OTLP_PROTOCOL=grpc | ||
|
|
||
| OTEL_SERVICE_NAME=opentelemetry-python-openai-agents-handoffs | ||
|
|
||
| # Optionally override the agent name reported on spans | ||
| # OTEL_GENAI_AGENT_NAME=Travel Concierge |
39 changes: 39 additions & 0 deletions
39
...-genai/opentelemetry-instrumentation-openai-agents/examples/handoffs/README.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| OpenTelemetry OpenAI Agents Handoff Example | ||
| ========================================== | ||
|
|
||
| This example shows how the OpenTelemetry OpenAI Agents instrumentation captures | ||
| spans in a small multi-agent workflow. Three agents collaborate: a primary | ||
| concierge, a concise assistant with a random-number tool, and a Spanish | ||
| specialist reached through a handoff. Running the sample produces | ||
| ``invoke_agent`` spans for each agent as well as an ``execute_tool`` span for | ||
| the random-number function. | ||
|
|
||
| Setup | ||
| ----- | ||
|
|
||
| 1. Copy `.env.example <.env.example>`_ to `.env` and populate it with your real | ||
| ``OPENAI_API_KEY``. Adjust the OTLP exporter settings if your collector does | ||
| not listen on ``http://localhost:4317``. | ||
| 2. Create a virtual environment and install the dependencies: | ||
|
|
||
| :: | ||
|
|
||
| python3 -m venv .venv | ||
| source .venv/bin/activate | ||
| pip install "python-dotenv[cli]" | ||
| pip install -r requirements.txt | ||
|
|
||
| Run | ||
| --- | ||
|
|
||
| Execute the workflow with ``dotenv`` so the environment variables from ``.env`` | ||
| are loaded automatically: | ||
|
|
||
| :: | ||
|
|
||
| dotenv run -- python main.py | ||
|
|
||
| The script emits a short transcript to stdout while spans stream to the OTLP | ||
| endpoint defined in your environment. You should see multiple | ||
| ``invoke_agent`` spans (one per agent) and an ``execute_tool`` span for the | ||
| random-number helper triggered during the run. |
162 changes: 162 additions & 0 deletions
162
instrumentation-genai/opentelemetry-instrumentation-openai-agents/examples/handoffs/main.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| # pylint: skip-file | ||
| """Multi-agent handoff example instrumented with OpenTelemetry.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import asyncio | ||
| import json | ||
| import random | ||
|
|
||
| from agents import Agent, HandoffInputData, Runner, function_tool, handoff | ||
| from agents import trace as agent_trace | ||
| from agents.extensions import handoff_filters | ||
| from agents.models import is_gpt_5_default | ||
| from dotenv import load_dotenv | ||
|
|
||
| from opentelemetry import trace as otel_trace | ||
| from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( | ||
| OTLPSpanExporter, | ||
| ) | ||
| from opentelemetry.instrumentation.openai_agents import ( | ||
| OpenAIAgentsInstrumentor, | ||
| ) | ||
| from opentelemetry.sdk.trace import TracerProvider | ||
| from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
|
|
||
|
|
||
| def configure_otel() -> None: | ||
| """Configure the OpenTelemetry SDK and enable the Agents instrumentation.""" | ||
|
|
||
| provider = TracerProvider() | ||
| provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter())) | ||
| otel_trace.set_tracer_provider(provider) | ||
|
|
||
| OpenAIAgentsInstrumentor().instrument(tracer_provider=provider) | ||
|
|
||
|
|
||
| @function_tool | ||
| def random_number_tool(maximum: int) -> int: | ||
| """Return a random integer between 0 and ``maximum``.""" | ||
|
|
||
| return random.randint(0, maximum) | ||
|
|
||
|
|
||
| def spanish_handoff_message_filter( | ||
| handoff_message_data: HandoffInputData, | ||
| ) -> HandoffInputData: | ||
| """Trim the message history forwarded to the Spanish-speaking agent.""" | ||
|
|
||
| if is_gpt_5_default(): | ||
| # When GPT-5 is enabled we skip additional filtering. | ||
| return HandoffInputData( | ||
| input_history=handoff_message_data.input_history, | ||
| pre_handoff_items=tuple(handoff_message_data.pre_handoff_items), | ||
| new_items=tuple(handoff_message_data.new_items), | ||
| ) | ||
|
|
||
| filtered = handoff_filters.remove_all_tools(handoff_message_data) | ||
| history = ( | ||
| tuple(filtered.input_history[2:]) | ||
| if isinstance(filtered.input_history, tuple) | ||
| else filtered.input_history[2:] | ||
| ) | ||
|
|
||
| return HandoffInputData( | ||
| input_history=history, | ||
| pre_handoff_items=tuple(filtered.pre_handoff_items), | ||
| new_items=tuple(filtered.new_items), | ||
| ) | ||
|
|
||
|
|
||
| assistant = Agent( | ||
| name="Assistant", | ||
| instructions="Be extremely concise.", | ||
| tools=[random_number_tool], | ||
| ) | ||
|
|
||
| spanish_assistant = Agent( | ||
| name="Spanish Assistant", | ||
| instructions="You only speak Spanish and are extremely concise.", | ||
| handoff_description="A Spanish-speaking assistant.", | ||
| ) | ||
|
|
||
| concierge = Agent( | ||
| name="Concierge", | ||
| instructions=( | ||
| "Be a helpful assistant. If the traveler switches to Spanish, handoff to" | ||
| " the Spanish specialist. Use the random number tool when asked for" | ||
| " numbers." | ||
| ), | ||
| handoffs=[ | ||
| handoff(spanish_assistant, input_filter=spanish_handoff_message_filter) | ||
| ], | ||
| ) | ||
|
|
||
|
|
||
| async def run_workflow() -> None: | ||
| """Execute a conversation that triggers tool calls and handoffs.""" | ||
|
|
||
| with agent_trace(workflow_name="Travel concierge handoff"): | ||
| # Step 1: Basic conversation with the initial assistant. | ||
| result = await Runner.run( | ||
| assistant, | ||
| input="I'm planning a trip to Madrid. Can you help?", | ||
| ) | ||
|
|
||
| print("Step 1 complete") | ||
|
|
||
| # Step 2: Ask for a random number to exercise the tool span. | ||
| result = await Runner.run( | ||
| assistant, | ||
| input=result.to_input_list() | ||
| + [ | ||
| { | ||
| "content": "Pick a lucky number between 0 and 20", | ||
| "role": "user", | ||
| } | ||
| ], | ||
| ) | ||
|
|
||
| print("Step 2 complete") | ||
|
|
||
| # Step 3: Continue the conversation with the concierge agent. | ||
| result = await Runner.run( | ||
| concierge, | ||
| input=result.to_input_list() | ||
| + [ | ||
| { | ||
| "content": "Recommend some sights in Madrid for a weekend trip.", | ||
| "role": "user", | ||
| } | ||
| ], | ||
| ) | ||
|
|
||
| print("Step 3 complete") | ||
|
|
||
| # Step 4: Switch to Spanish to cause a handoff to the specialist. | ||
| result = await Runner.run( | ||
| concierge, | ||
| input=result.to_input_list() | ||
| + [ | ||
| { | ||
| "content": "Por favor habla en español. ¿Puedes resumir el plan?", | ||
| "role": "user", | ||
| } | ||
| ], | ||
| ) | ||
|
|
||
| print("Step 4 complete") | ||
|
|
||
| print("\n=== Conversation Transcript ===\n") | ||
| for message in result.to_input_list(): | ||
| print(json.dumps(message, indent=2, ensure_ascii=False)) | ||
|
|
||
|
|
||
| def main() -> None: | ||
| load_dotenv() | ||
| configure_otel() | ||
| asyncio.run(run_workflow()) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
6 changes: 6 additions & 0 deletions
6
...tion-genai/opentelemetry-instrumentation-openai-agents/examples/handoffs/requirements.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| openai-agents~=0.3.3 | ||
| python-dotenv~=1.0 | ||
|
|
||
| opentelemetry-sdk~=1.36.0 | ||
| opentelemetry-exporter-otlp-proto-grpc~=1.36.0 | ||
| opentelemetry-instrumentation-openai-agents~=0.1.0.dev |
11 changes: 11 additions & 0 deletions
11
...umentation-genai/opentelemetry-instrumentation-openai-agents/examples/manual/.env.example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Update this with your real OpenAI API key | ||
| OPENAI_API_KEY=sk-YOUR_API_KEY | ||
|
|
||
| # Uncomment and adjust if you use a non-default OTLP collector endpoint | ||
| # OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 | ||
| # OTEL_EXPORTER_OTLP_PROTOCOL=grpc | ||
|
|
||
| OTEL_SERVICE_NAME=opentelemetry-python-openai-agents-manual | ||
|
|
||
| # Optionally override the agent name reported on spans | ||
| # OTEL_GENAI_AGENT_NAME=Travel Concierge |
42 changes: 42 additions & 0 deletions
42
...on-genai/opentelemetry-instrumentation-openai-agents/examples/manual/README.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| OpenTelemetry OpenAI Agents Instrumentation Example | ||
| =================================================== | ||
|
|
||
| This example demonstrates how to manually configure the OpenTelemetry SDK | ||
| alongside the OpenAI Agents instrumentation. | ||
|
|
||
| Running `main.py <main.py>`_ produces spans for the end-to-end agent run, | ||
| including tool invocations and model generations. Spans are exported through | ||
| OTLP/gRPC to the endpoint configured in the environment. | ||
|
|
||
| Setup | ||
| ----- | ||
|
|
||
| 1. Copy `.env.example <.env.example>`_ to `.env` and update it with your real | ||
| ``OPENAI_API_KEY``. If your | ||
| OTLP collector is not reachable via ``http://localhost:4317``, adjust the | ||
| endpoint variables as needed. | ||
| 2. Create a virtual environment and install the dependencies: | ||
|
|
||
| :: | ||
|
|
||
| python3 -m venv .venv | ||
| source .venv/bin/activate | ||
| pip install "python-dotenv[cli]" | ||
| pip install -r requirements.txt | ||
|
|
||
| Run | ||
| --- | ||
|
|
||
| Execute the sample with ``dotenv`` so the environment variables from ``.env`` | ||
| are applied: | ||
|
|
||
| :: | ||
|
|
||
| dotenv run -- python main.py | ||
|
|
||
| The script automatically loads environment variables from ``.env`` so running | ||
| ``python main.py`` directly also works if the shell already has the required | ||
| values exported. | ||
|
|
||
| You should see the agent response printed to the console while spans export to | ||
| your configured observability backend. |
65 changes: 65 additions & 0 deletions
65
instrumentation-genai/opentelemetry-instrumentation-openai-agents/examples/manual/main.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # pylint: skip-file | ||
| """Manual OpenAI Agents instrumentation example.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from agents import Agent, Runner, function_tool | ||
| from dotenv import load_dotenv | ||
|
|
||
| from opentelemetry import trace | ||
| from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( | ||
| OTLPSpanExporter, | ||
| ) | ||
| from opentelemetry.instrumentation.openai_agents import ( | ||
| OpenAIAgentsInstrumentor, | ||
| ) | ||
| from opentelemetry.sdk.trace import TracerProvider | ||
| from opentelemetry.sdk.trace.export import BatchSpanProcessor | ||
|
|
||
|
|
||
| def configure_otel() -> None: | ||
| """Configure the OpenTelemetry SDK for exporting spans.""" | ||
|
|
||
| provider = TracerProvider() | ||
| provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter())) | ||
| trace.set_tracer_provider(provider) | ||
|
|
||
| OpenAIAgentsInstrumentor().instrument(tracer_provider=provider) | ||
|
|
||
|
|
||
| @function_tool | ||
| def get_weather(city: str) -> str: | ||
| """Return a canned weather response for the requested city.""" | ||
|
|
||
| return f"The forecast for {city} is sunny with pleasant temperatures." | ||
|
|
||
|
|
||
| def run_agent() -> None: | ||
| """Create a simple agent and execute a single run.""" | ||
|
|
||
| assistant = Agent( | ||
| name="Travel Concierge", | ||
| instructions=( | ||
| "You are a concise travel concierge. Use the weather tool when the" | ||
| " traveler asks about local conditions." | ||
| ), | ||
| tools=[get_weather], | ||
| ) | ||
|
|
||
| result = Runner.run_sync( | ||
| assistant, | ||
| "I'm visiting Barcelona this weekend. How should I pack?", | ||
| ) | ||
|
|
||
| print("Agent response:") | ||
| print(result.final_output) | ||
|
|
||
|
|
||
| def main() -> None: | ||
| load_dotenv() | ||
| configure_otel() | ||
| run_agent() | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
6 changes: 6 additions & 0 deletions
6
...tation-genai/opentelemetry-instrumentation-openai-agents/examples/manual/requirements.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| openai-agents~=0.3.3 | ||
| python-dotenv~=1.0 | ||
|
|
||
| opentelemetry-sdk~=1.36.0 | ||
| opentelemetry-exporter-otlp-proto-grpc~=1.36.0 | ||
| opentelemetry-instrumentation-openai-agents~=0.1.0.dev |
14 changes: 14 additions & 0 deletions
14
...ntation-genai/opentelemetry-instrumentation-openai-agents/examples/zero-code/.env.example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| # Update this with your real OpenAI API key | ||
| OPENAI_API_KEY=sk-YOUR_API_KEY | ||
|
|
||
| # Uncomment and adjust if you use a non-default OTLP collector endpoint | ||
| # OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 | ||
| # OTEL_EXPORTER_OTLP_PROTOCOL=grpc | ||
|
|
||
| OTEL_SERVICE_NAME=opentelemetry-python-openai-agents-zero-code | ||
|
|
||
| # Enable auto-instrumentation for logs if desired | ||
| OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true | ||
|
|
||
| # Optionally override the agent name reported on spans | ||
| # OTEL_GENAI_AGENT_NAME=Travel Concierge |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should it be opentelemetry-instrumentation-openai-agents-v2?