Skip to content

Commit 47f9d0b

Browse files
committed
openai-agents-v2: Populate instructions and tool definitions from Response obj
1 parent 93bea2d commit 47f9d0b

2 files changed

Lines changed: 60 additions & 0 deletions

File tree

instrumentation-genai/opentelemetry-instrumentation-openai-agents-v2/src/opentelemetry/instrumentation/openai_agents/span_processor.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,10 +1056,16 @@ def _build_content_payload(self, span: Span[Any]) -> ContentPayload:
10561056

10571057
elif _is_instance_of(span_data, ResponseSpanData):
10581058
span_input = getattr(span_data, "input", None)
1059+
response_obj = getattr(span_data, "response", None)
10591060
if capture_messages and span_input:
10601061
payload.input_messages = (
10611062
self._normalize_messages_to_role_parts(span_input)
10621063
)
1064+
1065+
if capture_system and response_obj and hasattr(response_obj, "instructions"):
1066+
payload.system_instructions = self._normalize_to_text_parts(
1067+
response_obj.instructions
1068+
)
10631069
if capture_system and span_input:
10641070
sys_instr = self._collect_system_instructions(span_input)
10651071
if sys_instr:
@@ -2029,6 +2035,25 @@ def _get_attributes_from_response_span_data(
20292035
if output_tokens is not None:
20302036
yield GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens
20312037

2038+
# Tool definitions from response
2039+
if self._capture_tool_definitions and hasattr(
2040+
span_data.response, "tools"
2041+
):
2042+
def _serialize_tool_value(value: Any) -> Optional[str]:
2043+
if value is None:
2044+
return None
2045+
return {
2046+
"name": getattr(value, "name", None),
2047+
"type": getattr(value, "type", None),
2048+
"description": getattr(value, "description", None),
2049+
"parameters": getattr(value, "parameters", None),
2050+
}
2051+
2052+
yield (
2053+
GEN_AI_TOOL_DEFINITIONS,
2054+
safe_json_dumps(list(map(_serialize_tool_value, span_data.response.tools))),
2055+
)
2056+
20322057
# Input/output messages
20332058
if (
20342059
self.include_sensitive_data

instrumentation-genai/opentelemetry-instrumentation-openai-agents-v2/tests/test_tracer.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,11 +484,25 @@ def __init__(self, input_tokens: int, output_tokens: int) -> None:
484484
self.input_tokens = input_tokens
485485
self.output_tokens = output_tokens
486486

487+
class _FunctionTool:
488+
def __init__(self) -> None:
489+
self.name = "get_current_weather"
490+
self.type = "function"
491+
self.description = "Get the current weather in a given location"
492+
self.parameters = {
493+
"type": "object",
494+
"properties": {
495+
"location": {"title": "Location", "type": "string"},
496+
},
497+
"required": ["location"],
498+
}
487499
class _Response:
488500
def __init__(self) -> None:
489501
self.id = "resp-123"
502+
self.instructions = "You are a helpful assistant."
490503
self.model = "gpt-4o-mini"
491504
self.usage = _Usage(42, 9)
505+
self.tools = [_FunctionTool()]
492506
self.output = [{"finish_reason": "stop"}]
493507

494508
try:
@@ -516,6 +530,27 @@ def __init__(self) -> None:
516530
assert response.attributes[GenAI.GEN_AI_RESPONSE_FINISH_REASONS] == (
517531
"stop",
518532
)
533+
534+
system_instructions = json.loads(response.attributes[GenAI.GEN_AI_SYSTEM_INSTRUCTIONS])
535+
assert system_instructions == [{
536+
"type": "text",
537+
"content": "You are a helpful assistant."
538+
}]
539+
tool_definitions = json.loads(response.attributes[GenAI.GEN_AI_TOOL_DEFINITIONS])
540+
assert tool_definitions == [
541+
{
542+
"type": "function",
543+
"name": "get_current_weather",
544+
"description": "Get the current weather in a given location",
545+
"parameters": {
546+
"type": "object",
547+
"properties": {
548+
"location": {"title": "Location", "type": "string"},
549+
},
550+
"required": ["location"],
551+
},
552+
}
553+
]
519554
finally:
520555
instrumentor.uninstrument()
521556
exporter.clear()

0 commit comments

Comments
 (0)