openai-agents-python/src/agents/tracing/span_data.py
Kazuhiro Sera 25f97f979b
Fix typos and misspellings (#486)
Detected typos using typos-cli (https://crates.io/crates/typos-cli). It
detected "occured" in a string constant "handoff_occured" too, but I
didn't change the part this time because it could be a minor breaking
change.


Full outputs:
```
% typos .
error: `Supresses` should be `Suppresses`
  --> ./src/agents/function_schema.py:134:7
    |
134 |     # Supresses warnings about missing annotations for params
    |       ^^^^^^^^^
    |
error: `typ` should be `typo`, `type`
  --> ./src/agents/strict_schema.py:51:5
   |
51 |     typ = json_schema.get("type")
   |     ^^^
   |
error: `typ` should be `typo`, `type`
  --> ./src/agents/strict_schema.py:52:8
   |
52 |     if typ == "object" and "additionalProperties" not in json_schema:
   |        ^^^
   |
error: `typ` should be `typo`, `type`
  --> ./src/agents/strict_schema.py:55:9
   |
55 |         typ == "object"
   |         ^^^
   |
error: `occured` should be `occurred`
  --> ./src/agents/stream_events.py:34:18
   |
34 |         "handoff_occured",
   |                  ^^^^^^^
   |
error: `occured` should be `occurred`
  --> ./src/agents/_run_impl.py:723:69
    |
723 |                 event = RunItemStreamEvent(item=item, name="handoff_occured")
    |                                                                     ^^^^^^^
    |
error: `desitnation` should be `destination`
  --> ./src/agents/tracing/span_data.py:171:25
    |
171 |     Includes source and desitnation agents.
    |                         ^^^^^^^^^^^
    |
error: `exmaples` should be `examples`
  --> ./docs/scripts/translate_docs.py:71:145
   |
71 |         "* The term 'examples' must be code examples when the page mentions the code examples in the repo, it can be translated as either 'code exmaples' or 'sample code'.",
   |                                                                                                                                                 ^^^^^^^^
   |
error: `structed` should be `structured`
  --> ./tests/test_agent_hooks.py:227:16
    |
227 | async def test_structed_output_non_streamed_agent_hooks():
    |                ^^^^^^^^
    |
error: `structed` should be `structured`
  --> ./tests/test_agent_hooks.py:298:16
    |
298 | async def test_structed_output_streamed_agent_hooks():
    |                ^^^^^^^^
    |
```
2025-04-14 10:37:13 -04:00

374 lines
8.8 KiB
Python

from __future__ import annotations
import abc
from collections.abc import Mapping, Sequence
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from openai.types.responses import Response, ResponseInputItemParam
class SpanData(abc.ABC):
"""
Represents span data in the trace.
"""
@abc.abstractmethod
def export(self) -> dict[str, Any]:
"""Export the span data as a dictionary."""
pass
@property
@abc.abstractmethod
def type(self) -> str:
"""Return the type of the span."""
pass
class AgentSpanData(SpanData):
"""
Represents an Agent Span in the trace.
Includes name, handoffs, tools, and output type.
"""
__slots__ = ("name", "handoffs", "tools", "output_type")
def __init__(
self,
name: str,
handoffs: list[str] | None = None,
tools: list[str] | None = None,
output_type: str | None = None,
):
self.name = name
self.handoffs: list[str] | None = handoffs
self.tools: list[str] | None = tools
self.output_type: str | None = output_type
@property
def type(self) -> str:
return "agent"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"name": self.name,
"handoffs": self.handoffs,
"tools": self.tools,
"output_type": self.output_type,
}
class FunctionSpanData(SpanData):
"""
Represents a Function Span in the trace.
Includes input, output and MCP data (if applicable).
"""
__slots__ = ("name", "input", "output", "mcp_data")
def __init__(
self,
name: str,
input: str | None,
output: Any | None,
mcp_data: dict[str, Any] | None = None,
):
self.name = name
self.input = input
self.output = output
self.mcp_data = mcp_data
@property
def type(self) -> str:
return "function"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"name": self.name,
"input": self.input,
"output": str(self.output) if self.output else None,
"mcp_data": self.mcp_data,
}
class GenerationSpanData(SpanData):
"""
Represents a Generation Span in the trace.
Includes input, output, model, model configuration, and usage.
"""
__slots__ = (
"input",
"output",
"model",
"model_config",
"usage",
)
def __init__(
self,
input: Sequence[Mapping[str, Any]] | None = None,
output: Sequence[Mapping[str, Any]] | None = None,
model: str | None = None,
model_config: Mapping[str, Any] | None = None,
usage: dict[str, Any] | None = None,
):
self.input = input
self.output = output
self.model = model
self.model_config = model_config
self.usage = usage
@property
def type(self) -> str:
return "generation"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"input": self.input,
"output": self.output,
"model": self.model,
"model_config": self.model_config,
"usage": self.usage,
}
class ResponseSpanData(SpanData):
"""
Represents a Response Span in the trace.
Includes response and input.
"""
__slots__ = ("response", "input")
def __init__(
self,
response: Response | None = None,
input: str | list[ResponseInputItemParam] | None = None,
) -> None:
self.response = response
# This is not used by the OpenAI trace processors, but is useful for other tracing
# processor implementations
self.input = input
@property
def type(self) -> str:
return "response"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"response_id": self.response.id if self.response else None,
}
class HandoffSpanData(SpanData):
"""
Represents a Handoff Span in the trace.
Includes source and destination agents.
"""
__slots__ = ("from_agent", "to_agent")
def __init__(self, from_agent: str | None, to_agent: str | None):
self.from_agent = from_agent
self.to_agent = to_agent
@property
def type(self) -> str:
return "handoff"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"from_agent": self.from_agent,
"to_agent": self.to_agent,
}
class CustomSpanData(SpanData):
"""
Represents a Custom Span in the trace.
Includes name and data property bag.
"""
__slots__ = ("name", "data")
def __init__(self, name: str, data: dict[str, Any]):
self.name = name
self.data = data
@property
def type(self) -> str:
return "custom"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"name": self.name,
"data": self.data,
}
class GuardrailSpanData(SpanData):
"""
Represents a Guardrail Span in the trace.
Includes name and triggered status.
"""
__slots__ = ("name", "triggered")
def __init__(self, name: str, triggered: bool = False):
self.name = name
self.triggered = triggered
@property
def type(self) -> str:
return "guardrail"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"name": self.name,
"triggered": self.triggered,
}
class TranscriptionSpanData(SpanData):
"""
Represents a Transcription Span in the trace.
Includes input, output, model, and model configuration.
"""
__slots__ = (
"input",
"output",
"model",
"model_config",
)
def __init__(
self,
input: str | None = None,
input_format: str | None = "pcm",
output: str | None = None,
model: str | None = None,
model_config: Mapping[str, Any] | None = None,
):
self.input = input
self.input_format = input_format
self.output = output
self.model = model
self.model_config = model_config
@property
def type(self) -> str:
return "transcription"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"input": {
"data": self.input or "",
"format": self.input_format,
},
"output": self.output,
"model": self.model,
"model_config": self.model_config,
}
class SpeechSpanData(SpanData):
"""
Represents a Speech Span in the trace.
Includes input, output, model, model configuration, and first content timestamp.
"""
__slots__ = ("input", "output", "model", "model_config", "first_content_at")
def __init__(
self,
input: str | None = None,
output: str | None = None,
output_format: str | None = "pcm",
model: str | None = None,
model_config: Mapping[str, Any] | None = None,
first_content_at: str | None = None,
):
self.input = input
self.output = output
self.output_format = output_format
self.model = model
self.model_config = model_config
self.first_content_at = first_content_at
@property
def type(self) -> str:
return "speech"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"input": self.input,
"output": {
"data": self.output or "",
"format": self.output_format,
},
"model": self.model,
"model_config": self.model_config,
"first_content_at": self.first_content_at,
}
class SpeechGroupSpanData(SpanData):
"""
Represents a Speech Group Span in the trace.
"""
__slots__ = "input"
def __init__(
self,
input: str | None = None,
):
self.input = input
@property
def type(self) -> str:
return "speech-group"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"input": self.input,
}
class MCPListToolsSpanData(SpanData):
"""
Represents an MCP List Tools Span in the trace.
Includes server and result.
"""
__slots__ = (
"server",
"result",
)
def __init__(self, server: str | None = None, result: list[str] | None = None):
self.server = server
self.result = result
@property
def type(self) -> str:
return "mcp_tools"
def export(self) -> dict[str, Any]:
return {
"type": self.type,
"server": self.server,
"result": self.result,
}