1414
1515from __future__ import annotations
1616
17- from dataclasses import asdict
18- from typing import Any , Union
17+ from typing import Any
1918
2019from opentelemetry ._logs import Logger
2120from opentelemetry .semconv ._incubating .attributes import (
2221 gen_ai_attributes as GenAI ,
2322)
2423from opentelemetry .semconv .attributes import server_attributes
2524from opentelemetry .trace import SpanKind , Tracer
25+ from opentelemetry .util .genai ._content import _get_content_attributes
2626from opentelemetry .util .genai ._invocation import Error , GenAIInvocation
2727from opentelemetry .util .genai .metrics import InvocationMetricsRecorder
2828from opentelemetry .util .genai .types import (
29- FunctionToolDefinition ,
30- GenericToolDefinition ,
3129 InputMessage ,
3230 MessagePart ,
3331 OutputMessage ,
32+ ToolDefinition ,
3433)
35- from opentelemetry .util .genai .utils import (
36- ContentCapturingMode ,
37- gen_ai_json_dumps ,
38- get_content_capturing_mode ,
39- is_experimental_mode ,
40- )
41-
42- ToolDefinition = Union [FunctionToolDefinition , GenericToolDefinition ]
4334
4435
4536class AgentInvocation (GenAIInvocation ):
4637 """Represents a single agent invocation (invoke_agent span).
4738
48- Use handler.start_agent() or the handler.invoke_agent() context manager
49- rather than constructing this directly.
39+ Use handler.start_invoke_local_agent() / handler.start_invoke_remote_agent()
40+ or the handler.invoke_local_agent() / handler.invoke_remote_agent() context
41+ managers rather than constructing this directly.
5042
51- Reference: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-agent-spans.md#invoke-agent-span
43+ Reference:
44+ Client span: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-agent-spans.md#invoke-agent-client-span
45+ Internal span: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-agent-spans.md#invoke-agent-internal-span
5246 """
5347
5448 def __init__ (
@@ -58,24 +52,22 @@ def __init__(
5852 logger : Logger ,
5953 provider : str ,
6054 * ,
55+ span_kind : SpanKind = SpanKind .INTERNAL ,
6156 request_model : str | None = None ,
6257 server_address : str | None = None ,
6358 server_port : int | None = None ,
64- agent_name : str | None = None ,
6559 attributes : dict [str , Any ] | None = None ,
6660 metric_attributes : dict [str , Any ] | None = None ,
6761 ) -> None :
68- """Use handler.start_agent () or handler.invoke_agent () instead of calling this directly."""
62+ """Use handler.start_invoke_local_agent () or handler.start_invoke_remote_agent () instead of calling this directly."""
6963 _operation_name = GenAI .GenAiOperationNameValues .INVOKE_AGENT .value
7064 super ().__init__ (
7165 tracer ,
7266 metrics_recorder ,
7367 logger ,
7468 operation_name = _operation_name ,
75- span_name = f"{ _operation_name } { agent_name } "
76- if agent_name
77- else _operation_name ,
78- span_kind = SpanKind .CLIENT ,
69+ span_name = _operation_name ,
70+ span_kind = span_kind ,
7971 attributes = attributes ,
8072 metric_attributes = metric_attributes ,
8173 )
@@ -84,7 +76,7 @@ def __init__(
8476 self .server_address = server_address
8577 self .server_port = server_port
8678
87- self .agent_name = agent_name
79+ self .agent_name : str | None = None
8880 self .agent_id : str | None = None
8981 self .agent_description : str | None = None
9082 self .agent_version : str | None = None
@@ -102,8 +94,6 @@ def __init__(
10294 self .seed : int | None = None
10395 self .choice_count : int | None = None
10496
105- self .finish_reasons : list [str ] | None = None
106- self .response_model_name : str | None = None
10797 self .input_tokens : int | None = None
10898 self .output_tokens : int | None = None
10999 self .cache_creation_input_tokens : int | None = None
@@ -116,18 +106,6 @@ def __init__(
116106
117107 self ._start ()
118108
119- def _get_finish_reasons (self ) -> list [str ] | None :
120- if self .finish_reasons is not None :
121- return self .finish_reasons or None
122- if self .output_messages :
123- reasons = [
124- msg .finish_reason
125- for msg in self .output_messages
126- if msg .finish_reason
127- ]
128- return reasons or None
129- return None
130-
131109 def _get_common_attributes (self ) -> dict [str , Any ]:
132110 optional_attrs = (
133111 (GenAI .GEN_AI_REQUEST_MODEL , self .request_model ),
@@ -160,10 +138,8 @@ def _get_request_attributes(self) -> dict[str, Any]:
160138 )
161139 return {k : v for k , v in optional_attrs if v is not None }
162140
163- def _get_response_attributes (self ) -> dict [str , Any ]:
141+ def _get_usage_attributes (self ) -> dict [str , Any ]:
164142 optional_attrs = (
165- (GenAI .GEN_AI_RESPONSE_FINISH_REASONS , self ._get_finish_reasons ()),
166- (GenAI .GEN_AI_RESPONSE_MODEL , self .response_model_name ),
167143 (GenAI .GEN_AI_USAGE_INPUT_TOKENS , self .input_tokens ),
168144 (GenAI .GEN_AI_USAGE_OUTPUT_TOKENS , self .output_tokens ),
169145 (
@@ -177,47 +153,19 @@ def _get_response_attributes(self) -> dict[str, Any]:
177153 )
178154 return {k : v for k , v in optional_attrs if v is not None }
179155
180- def _get_messages_for_span (self ) -> dict [str , Any ]:
181- if not is_experimental_mode () or get_content_capturing_mode () not in (
182- ContentCapturingMode .SPAN_ONLY ,
183- ContentCapturingMode .SPAN_AND_EVENT ,
184- ):
185- return {}
186- optional_attrs = (
187- (
188- GenAI .GEN_AI_INPUT_MESSAGES ,
189- gen_ai_json_dumps ([asdict (m ) for m in self .input_messages ])
190- if self .input_messages
191- else None ,
192- ),
193- (
194- GenAI .GEN_AI_OUTPUT_MESSAGES ,
195- gen_ai_json_dumps ([asdict (m ) for m in self .output_messages ])
196- if self .output_messages
197- else None ,
198- ),
199- (
200- GenAI .GEN_AI_SYSTEM_INSTRUCTIONS ,
201- gen_ai_json_dumps ([asdict (p ) for p in self .system_instruction ])
202- if self .system_instruction
203- else None ,
204- ),
205- (
206- GenAI .GEN_AI_TOOL_DEFINITIONS ,
207- gen_ai_json_dumps ([asdict (t ) for t in self .tool_definitions ])
208- if self .tool_definitions
209- else None ,
210- ),
156+ def _get_content_attributes_for_span (self ) -> dict [str , Any ]:
157+ return _get_content_attributes (
158+ input_messages = self .input_messages ,
159+ output_messages = self .output_messages ,
160+ system_instruction = self .system_instruction ,
161+ tool_definitions = self .tool_definitions ,
162+ for_span = True ,
211163 )
212- return {
213- key : value for key , value in optional_attrs if value is not None
214- }
215164
216165 def _get_metric_attributes (self ) -> dict [str , Any ]:
217166 optional_attrs = (
218167 (GenAI .GEN_AI_PROVIDER_NAME , self .provider ),
219168 (GenAI .GEN_AI_REQUEST_MODEL , self .request_model ),
220- (GenAI .GEN_AI_RESPONSE_MODEL , self .response_model_name ),
221169 (server_attributes .SERVER_ADDRESS , self .server_address ),
222170 (server_attributes .SERVER_PORT , self .server_port ),
223171 )
@@ -249,8 +197,8 @@ def _apply_finish(self, error: Error | None = None) -> None:
249197 attributes : dict [str , Any ] = {}
250198 attributes .update (self ._get_common_attributes ())
251199 attributes .update (self ._get_request_attributes ())
252- attributes .update (self ._get_response_attributes ())
253- attributes .update (self ._get_messages_for_span ())
200+ attributes .update (self ._get_usage_attributes ())
201+ attributes .update (self ._get_content_attributes_for_span ())
254202 attributes .update (self .attributes )
255203 self .span .set_attributes (attributes )
256204 self ._metrics_recorder .record (self )
0 commit comments