Skip to content
Draft
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
22 changes: 22 additions & 0 deletions examples/agent/openai-agents-sdk/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copy this file to .env and fill in your own values. Never commit .env.

# --- Splunk AO (Splunk Observability Cloud) ---------------------------------
# Use ONE deployment style. Do not mix the two sets of variables.
SPLUNK_AO_REALM=your-realm # for example: us1
SPLUNK_AO_O11Y_TOKEN=your-o11y-token # token that is allowed to send telemetry
SPLUNK_AO_PROJECT=your-splunk-ao-project-name
SPLUNK_AO_AGENT_STREAM=your-splunk-ao-agent-stream-name

# Standalone deployment instead of Splunk Observability Cloud:
# SPLUNK_AO_API_KEY=your-splunk-ao-api-key
# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url

# --- Model used by the agent (OpenAI or any OpenAI-compatible endpoint) -----
OPENAI_API_KEY=your-openai-api-key
# OPENAI_BASE_URL=https://your-openai-compatible-endpoint/v1 # optional, for example a LiteLLM proxy
# OPENAI_MODEL=gpt-4o-mini # default: gpt-4o-mini

# --- Instrumentation mode ---------------------------------------------------
# sdk = SplunkAOTracingProcessor (default)
# otel = community OpenTelemetry instrumentation for the Agents SDK
# INSTRUMENTATION=sdk
52 changes: 52 additions & 0 deletions examples/agent/openai-agents-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# OpenAI Agents SDK travel agent

A small travel agent built with the [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/) and
instrumented with Splunk AO. The agent has two mock tools (flight search and activity search), so each run
produces a tool-calling turn followed by a final answer.

The example shows two ways to send the same agent's telemetry to Splunk AO:

| `INSTRUMENTATION` | How it works |
|---|---|
| `sdk` (default) | `SplunkAOTracingProcessor`, registered with the Agents SDK's `set_trace_processors()` hook. |
| `otel` | The community OpenTelemetry instrumentation for the Agents SDK, with Splunk AO attached to a tracer provider through `add_splunk_ao_span_processor()`. |

## Prerequisites

- Python 3.11 or later
- A Splunk AO project and agent stream, plus a token that can send telemetry
- An OpenAI API key, or any OpenAI-compatible endpoint (set `OPENAI_BASE_URL`, for example to a LiteLLM proxy)

## Setup

```bash
pip install -r requirements.txt
cp .env.example .env # then fill in your own values; .env is git-ignored
```

For `INSTRUMENTATION=otel`, also install the extra package listed at the bottom of `requirements.txt`:

```bash
pip install opentelemetry-instrumentation-genai-openai-agents
```

Configure Splunk AO with **either** the Splunk Observability Cloud variables (`SPLUNK_AO_REALM` and
`SPLUNK_AO_O11Y_TOKEN`) **or** the standalone variables (`SPLUNK_AO_API_KEY` and `SPLUNK_AO_CONSOLE_URL`), not both.

## Run

```bash
INSTRUMENTATION=sdk python main.py
INSTRUMENTATION=otel python main.py
```

Each run picks a random route, asks the agent to plan a trip, and logs the final answer. Open the
agent stream you configured in Splunk AO to inspect the session: the agent, its turns, the LLM calls, and
the two tool calls.

## Notes

- The tools return deterministic mock data and call no external services.
- By default the Agents SDK also exports traces to OpenAI's tracing backend. `sdk` mode replaces that exporter, and
`otel` mode turns it off, so telemetry from this example goes only to Splunk AO.
- Environment variables you export in your shell take precedence over values in `.env`.
187 changes: 187 additions & 0 deletions examples/agent/openai-agents-sdk/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
"""
Travel agent demo using the OpenAI Agents SDK with Splunk AO instrumentation.

Two instrumentation modes, selected with the INSTRUMENTATION environment variable:

sdk (default) SplunkAOTracingProcessor, registered through the Agents SDK's
set_trace_processors() hook.
otel The community OpenTelemetry instrumentation for the Agents SDK,
with Splunk AO attached to a tracer provider through
add_splunk_ao_span_processor(). Needs the extra package listed
in requirements.txt.

The agent is a single TravelAgent with two mock tools (flight search and activity
search), so every run makes at least one tool-calling turn followed by a final answer.

Run:
INSTRUMENTATION=sdk python main.py
INSTRUMENTATION=otel python main.py
"""

from __future__ import annotations

import asyncio
import logging
import os
import random
from datetime import datetime, timedelta
from uuid import uuid4

from dotenv import load_dotenv

load_dotenv()

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("openai-agents-demo")

# ---------------------------------------------------------------------------
# LLM client
# ---------------------------------------------------------------------------

from agents import Agent, Runner, function_tool
from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
from openai import AsyncOpenAI

# The client reads OPENAI_API_KEY and, if set, OPENAI_BASE_URL from the environment, so it works with
# OpenAI or with any OpenAI-compatible endpoint (for example a LiteLLM proxy).
_client = AsyncOpenAI()
_model = OpenAIChatCompletionsModel(
model=os.environ.get("OPENAI_MODEL", "gpt-4o-mini"),
openai_client=_client,
)

# ---------------------------------------------------------------------------
# Mock tools (deterministic data, no external services)
# ---------------------------------------------------------------------------

DESTINATIONS = {
"paris": ["Eiffel Tower at sunset", "Seine dinner cruise", "Day trip to Versailles"],
"tokyo": ["Tsukiji market food tour", "Ghibli Museum visit", "Day trip to Hakone"],
"rome": ["Colosseum underground tour", "Private pasta masterclass", "Trastevere walk"],
"sydney": ["Harbour Bridge climb", "Bondi to Coogee coastal walk", "Opera House tour"],
}

SCENARIOS = [
("Seattle", "Paris"),
("New York", "Tokyo"),
("San Francisco", "Rome"),
("Chicago", "Sydney"),
]


@function_tool
def mock_search_flights(origin: str, destination: str, departure: str) -> str:
"""Return mock flight options for a given route and date."""
random.seed(hash((origin, destination, departure)) % (2**32))
airline = random.choice(["SkyLine", "AeroJet", "CloudNine", "PacificAir"])
fare = random.randint(650, 1400)
return (
f"{airline} non-stop {origin}鈫抺destination}, depart {departure} 08:45, "
f"arrive same day 18:30. Return premium economy ${fare}."
)


@function_tool
def mock_search_activities(destination: str) -> str:
"""Return signature activities for the destination."""
highlights = DESTINATIONS.get(destination.lower(), DESTINATIONS["paris"])
return "Highlights:\n" + "\n".join(f"- {h}" for h in highlights)


# ---------------------------------------------------------------------------
# Agent definition
# ---------------------------------------------------------------------------

_agent = Agent(
name="TravelAgent",
instructions=(
"You are a travel specialist. Use mock_search_flights and mock_search_activities "
"to gather data, then summarise the trip plan briefly."
),
model=_model,
tools=[mock_search_flights, mock_search_activities],
)

# ---------------------------------------------------------------------------
# Instrumentation setup
# ---------------------------------------------------------------------------

INSTRUMENTATION = os.environ.get("INSTRUMENTATION", "sdk").lower()

if INSTRUMENTATION == "otel":
# OpenTelemetry path: community Agents SDK instrumentation + a Splunk AO span processor
from opentelemetry import trace as trace_api
from opentelemetry.sdk import trace as trace_sdk
from opentelemetry.sdk.resources import Resource
from splunk_ao.otel import SplunkAOSpanProcessor, add_splunk_ao_span_processor

_resource = Resource.create({"service.name": "openai-agents-demo"})
_provider = trace_sdk.TracerProvider(resource=_resource)
add_splunk_ao_span_processor(
_provider,
SplunkAOSpanProcessor(
project=os.environ.get("SPLUNK_AO_PROJECT"),
agentstream=os.environ.get("SPLUNK_AO_AGENT_STREAM"),
),
)
trace_api.set_tracer_provider(_provider)

try:
from opentelemetry.instrumentation.genai.openai_agents import OpenAIAgentsInstrumentor
# Keep the Agents SDK's default exporter from also sending traces to OpenAI's tracing backend.
OpenAIAgentsInstrumentor().instrument(disable_openai_trace_export=True)
log.info("OpenAIAgentsInstrumentor active")
except ImportError:
log.warning(
"opentelemetry-instrumentation-genai-openai-agents is not installed. "
"Run: pip install opentelemetry-instrumentation-genai-openai-agents"
)

else:
# SDK path: SplunkAOTracingProcessor registered through the Agents SDK's trace-processor hook
from agents import set_trace_processors
from splunk_ao.handlers.openai_agents import SplunkAOTracingProcessor

set_trace_processors([SplunkAOTracingProcessor(flush_on_trace_end=True)])
log.info("SplunkAOTracingProcessor active")

# ---------------------------------------------------------------------------
# Run
# ---------------------------------------------------------------------------


async def run_once() -> None:
session_id = str(uuid4())
origin, destination = random.choice(SCENARIOS)
departure = (datetime.now() + timedelta(days=30)).strftime("%Y-%m-%d")

prompt = (
f"Plan a 7-day trip from {origin} to {destination} departing {departure}. "
f"Use the available tools to find a flight and activities, then summarise briefly."
)

log.info(
"run started session=%s route=%s->%s instrumentation=%s",
session_id, origin, destination, INSTRUMENTATION,
)

if INSTRUMENTATION == "sdk":
from splunk_ao import splunk_ao_context
with splunk_ao_context(
project=os.environ.get("SPLUNK_AO_PROJECT"),
agent_stream=os.environ.get("SPLUNK_AO_AGENT_STREAM"),
session_id=session_id,
):
result = await Runner.run(_agent, input=prompt)
else:
result = await Runner.run(_agent, input=prompt)

log.info("run completed session=%s answer_chars=%d", session_id, len(result.final_output or ""))
log.info("answer=%s", (result.final_output or "")[:300])

if INSTRUMENTATION == "otel":
_provider.force_flush()


if __name__ == "__main__":
asyncio.run(run_once())
5 changes: 5 additions & 0 deletions examples/agent/openai-agents-sdk/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
splunk-ao[openai]>=0.5.0
python-dotenv

# Only needed for INSTRUMENTATION=otel:
# opentelemetry-instrumentation-genai-openai-agents
Loading