mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2026-03-13 08:10:39 +08:00
[openai-agents] Populate instructions and tool definitions from Response obj (#4196)
This commit is contained in:
committed by
GitHub
parent
196d088e13
commit
b44ca58008
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user