|
1 | | -"""OpenAI Agents Instrumentation for AgentOps |
2 | | -
|
3 | | -This module provides instrumentation for OpenAI Agents, adding telemetry to track agent |
4 | | -interactions, conversation flows, and tool usage. |
| 1 | +"""OpenAI Agents SDK Instrumentation for AgentOps |
| 2 | +
|
| 3 | +This module provides instrumentation for the OpenAI Agents SDK, leveraging its built-in |
| 4 | +tracing API for observability. It captures detailed information about agent execution, |
| 5 | +tool usage, LLM requests, and token metrics. |
| 6 | +
|
| 7 | +The implementation uses a clean separation between exporters and processors. The exporter |
| 8 | +translates Agent spans into OpenTelemetry spans with appropriate semantic conventions. |
| 9 | +The processor implements the tracing interface, collects metrics, and manages timing data. |
| 10 | +
|
| 11 | +We use the built-in add_trace_processor hook for all functionality. Streaming support |
| 12 | +would require monkey-patching the run method of `Runner`, but doesn't really get us |
| 13 | +more data than we already have, since the `Response` object is always passed to us |
| 14 | +from the `agents.tracing` module. |
| 15 | +
|
| 16 | +TODO Calls to the OpenAI API are not available in this tracing context, so we may |
| 17 | +need to monkey-patch the `openai` from here to get that data. While we do have |
| 18 | +separate instrumentation for the OpenAI API, in order to get it to nest with the |
| 19 | +spans we create here, it's probably easier (or even required) that we incorporate |
| 20 | +that here as well. |
5 | 21 | """ |
6 | | - |
7 | | -from typing import List |
8 | | - |
| 22 | +from typing import Collection |
| 23 | +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor # type: ignore |
9 | 24 | from agentops.logging import logger |
10 | | -from opentelemetry.instrumentation.instrumentor import BaseInstrumentor |
11 | | -from agentops.instrumentation.openai_agents import ( |
12 | | - LIBRARY_VERSION, |
13 | | -) |
| 25 | +from agentops.instrumentation.openai_agents.processor import OpenAIAgentsProcessor |
| 26 | +from agentops.instrumentation.openai_agents.exporter import OpenAIAgentsExporter |
14 | 27 |
|
15 | 28 |
|
16 | 29 | class OpenAIAgentsInstrumentor(BaseInstrumentor): |
17 | | - """OpenAI Agents instrumentation class. |
| 30 | + """An instrumentor for OpenAI Agents SDK that primarily uses the built-in tracing API.""" |
18 | 31 |
|
19 | | - This class provides instrumentation for OpenAI Agents, adding telemetry to track agent |
20 | | - interactions, conversation flows, and tool usage. |
21 | | - """ |
| 32 | + _processor = None |
| 33 | + _exporter = None |
| 34 | + _default_processor = None |
22 | 35 |
|
23 | | - def __init__(self): |
24 | | - super().__init__() |
| 36 | + def instrumentation_dependencies(self) -> Collection[str]: |
| 37 | + """Return packages required for instrumentation.""" |
| 38 | + return ["openai-agents >= 0.0.1"] |
25 | 39 |
|
26 | | - self._is_instrumented_by_openai_agents = False |
27 | | - self._original = None |
28 | | - |
29 | | - def instrumentation_dependencies(self) -> List[str]: |
30 | | - """Packages required for OpenAI Agents instrumentation. |
| 40 | + def _instrument(self, **kwargs): |
| 41 | + """Instrument the OpenAI Agents SDK.""" |
| 42 | + tracer_provider = kwargs.get("tracer_provider") |
31 | 43 |
|
32 | | - Returns: |
33 | | - List of required package names. |
34 | | - """ |
35 | | - return [] |
| 44 | + try: |
| 45 | + self._exporter = OpenAIAgentsExporter(tracer_provider=tracer_provider) |
| 46 | + self._processor = OpenAIAgentsProcessor( |
| 47 | + exporter=self._exporter, |
| 48 | + ) |
36 | 49 |
|
37 | | - def _instrument(self, **kwargs): |
38 | | - """Instrument OpenAI Agents. |
| 50 | + # Replace the default processor with our processor |
| 51 | + from agents import set_trace_processors # type: ignore |
| 52 | + from agents.tracing.processors import default_processor # type: ignore |
39 | 53 |
|
40 | | - This method instruments OpenAI Agents by patching the Response class to add |
41 | | - telemetry for tracking agent interactions, conversation flows, and tool usage. |
42 | | - """ |
43 | | - # Check if already instrumented |
44 | | - if self._is_instrumented_by_openai_agents: |
45 | | - logger.debug("OpenAI Agents is already instrumented") |
46 | | - return |
| 54 | + # Store reference to default processor for later restoration |
| 55 | + self._default_processor = default_processor() |
| 56 | + set_trace_processors([self._processor]) |
| 57 | + logger.debug("Replaced default processor with OpenAIAgentsProcessor in OpenAI Agents SDK") |
47 | 58 |
|
48 | | - try: |
49 | | - # Check if Agents SDK is available |
50 | | - logger.debug(f"OpenAI Agents SDK detected with version: {LIBRARY_VERSION}") |
51 | | - self._is_instrumented_by_openai_agents = True |
52 | 59 | except Exception as e: |
53 | | - logger.debug(f"OpenAI Agents SDK not available: {e}") |
54 | | - return |
55 | | - |
56 | | - return self |
| 60 | + logger.warning(f"Failed to instrument OpenAI Agents SDK: {e}") |
57 | 61 |
|
58 | 62 | def _uninstrument(self, **kwargs): |
59 | 63 | """Remove instrumentation from OpenAI Agents SDK.""" |
|
0 commit comments