[openai-agents] Populate instructions and tool definitions from Response obj (#4196)

This commit is contained in:
Adam Malcontenti-Wilson
2026-03-12 05:33:50 +11:00
committed by GitHub
parent 196d088e13
commit b44ca58008
3 changed files with 74 additions and 0 deletions

View File

@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#4229](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4229))
- Document official package metadata and README for the OpenAI Agents instrumentation.
([#3859](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3859))
- Populate instructions and tool definitions from Response obj.
([#4196](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4196))
## Version 0.1.0 (2025-10-15)

View File

@@ -1056,10 +1056,20 @@ class GenAISemanticProcessor(TracingProcessor):
elif _is_instance_of(span_data, ResponseSpanData):
span_input = getattr(span_data, "input", None)
response_obj = getattr(span_data, "response", None)
if capture_messages and span_input:
payload.input_messages = (
self._normalize_messages_to_role_parts(span_input)
)
if (
capture_system
and response_obj
and hasattr(response_obj, "instructions")
):
payload.system_instructions = self._normalize_to_text_parts(
response_obj.instructions
)
if capture_system and span_input:
sys_instr = self._collect_system_instructions(span_input)
if sys_instr:
@@ -2016,6 +2026,22 @@ class GenAISemanticProcessor(TracingProcessor):
if output_tokens is not None:
yield GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens
# Tool definitions from response
if self._capture_tool_definitions and hasattr(
span_data.response, "tools"
):
yield (
GEN_AI_TOOL_DEFINITIONS,
safe_json_dumps(
list(
map(
lambda tool: tool.to_dict(),
span_data.response.tools,
)
)
),
)
# Input/output messages
if (
self.include_sensitive_data

View File

@@ -25,6 +25,7 @@ from agents.tracing import ( # noqa: E402
set_trace_processors,
trace,
)
from openai.types.responses import FunctionTool # noqa: E402
from opentelemetry.instrumentation.openai_agents import ( # noqa: E402
OpenAIAgentsInstrumentor,
@@ -62,6 +63,9 @@ GEN_AI_INPUT_MESSAGES = getattr(
GEN_AI_OUTPUT_MESSAGES = getattr(
GenAI, "GEN_AI_OUTPUT_MESSAGES", "gen_ai.output.messages"
)
GEN_AI_TOOL_DEFINITIONS = getattr(
GenAI, "GEN_AI_TOOL_DEFINITIONS", "gen_ai.tool.definitions"
)
def _instrument_with_provider(**instrument_kwargs):
@@ -478,8 +482,26 @@ def test_response_span_records_response_attributes():
class _Response:
def __init__(self) -> None:
self.id = "resp-123"
self.instructions = "You are a helpful assistant."
self.model = "gpt-4o-mini"
self.usage = _Usage(42, 9)
self.tools = [
FunctionTool(
name="get_current_weather",
type="function",
description="Get the current weather in a given location",
parameters={
"type": "object",
"properties": {
"location": {
"title": "Location",
"type": "string",
},
},
"required": ["location"],
},
)
]
self.output = [{"finish_reason": "stop"}]
try:
@@ -507,6 +529,30 @@ def test_response_span_records_response_attributes():
assert response.attributes[GenAI.GEN_AI_RESPONSE_FINISH_REASONS] == (
"stop",
)
system_instructions = json.loads(
response.attributes[GenAI.GEN_AI_SYSTEM_INSTRUCTIONS]
)
assert system_instructions == [
{"type": "text", "content": "You are a helpful assistant."}
]
tool_definitions = json.loads(
response.attributes[GEN_AI_TOOL_DEFINITIONS]
)
assert tool_definitions == [
{
"type": "function",
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {"title": "Location", "type": "string"},
},
"required": ["location"],
},
}
]
finally:
instrumentor.uninstrument()
exporter.clear()