Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,37 @@
unregister_span_enricher,
)
from .exporters.spectra_exporter_options import SpectraExporterOptions
from .inference_call_details import InferenceCallDetails, ServiceEndpoint
from .inference_call_details import InferenceCallDetails
from .models.service_endpoint import ServiceEndpoint
from .inference_operation_type import InferenceOperationType
from .inference_scope import InferenceScope
from .invoke_agent_details import InvokeAgentScopeDetails
from .invoke_agent_scope import InvokeAgentScope
from .middleware.baggage_builder import BaggageBuilder
from .models.caller_details import CallerDetails
from .models.messages import (
BlobPart,
ChatMessage,
FilePart,
FinishReason,
GenericPart,
InputMessages,
InputMessagesParam,
MessagePart,
MessageRole,
Modality,
OutputMessage,
OutputMessages,
OutputMessagesParam,
ReasoningPart,
ServerToolCallPart,
ServerToolCallResponsePart,
TextPart,
ToolCallRequestPart,
ToolCallResponsePart,
UriPart,
)
from .models.response import Response
from .models.user_details import UserDetails
from .opentelemetry_scope import OpenTelemetryScope
from .request import Request
Expand Down Expand Up @@ -70,12 +94,34 @@
"ToolCallDetails",
"Channel",
"Request",
"Response",
"SpanDetails",
"InferenceCallDetails",
"ServiceEndpoint",
# Enums
"InferenceOperationType",
"ToolType",
# OTEL gen-ai message format types
"MessageRole",
"FinishReason",
"Modality",
"TextPart",
"ToolCallRequestPart",
"ToolCallResponsePart",
"ReasoningPart",
"BlobPart",
"FilePart",
"UriPart",
"ServerToolCallPart",
"ServerToolCallResponsePart",
"GenericPart",
"MessagePart",
"ChatMessage",
"OutputMessage",
"InputMessages",
"OutputMessages",
"InputMessagesParam",
"OutputMessagesParam",
# Utility functions
"extract_context_from_headers",
"get_traceparent",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
GEN_AI_CONVERSATION_ID_KEY,
GEN_AI_TOOL_ARGS_KEY,
GEN_AI_TOOL_CALL_ID_KEY,
GEN_AI_TOOL_CALL_RESULT_KEY,
GEN_AI_TOOL_DESCRIPTION_KEY,
GEN_AI_TOOL_NAME_KEY,
GEN_AI_TOOL_TYPE_KEY,
Expand All @@ -21,12 +22,12 @@
USER_ID_KEY,
USER_NAME_KEY,
)
from .utils import safe_json_dumps, validate_and_normalize_ip
from .models.user_details import UserDetails
from .opentelemetry_scope import OpenTelemetryScope
from .request import Request
from .span_details import SpanDetails
from .tool_call_details import ToolCallDetails
from .utils import validate_and_normalize_ip


class ExecuteToolScope(OpenTelemetryScope):
Expand Down Expand Up @@ -108,7 +109,9 @@ def __init__(
endpoint = details.endpoint

self.set_tag_maybe(GEN_AI_TOOL_NAME_KEY, tool_name)
self.set_tag_maybe(GEN_AI_TOOL_ARGS_KEY, arguments)
if arguments is not None:
serialized = safe_json_dumps(arguments) if isinstance(arguments, dict) else arguments
self.set_tag_maybe(GEN_AI_TOOL_ARGS_KEY, serialized)
self.set_tag_maybe(GEN_AI_TOOL_TYPE_KEY, tool_type)
self.set_tag_maybe(GEN_AI_TOOL_CALL_ID_KEY, tool_call_id)
self.set_tag_maybe(GEN_AI_TOOL_DESCRIPTION_KEY, description)
Expand All @@ -134,13 +137,15 @@ def __init__(
validate_and_normalize_ip(user_details.user_client_ip),
)

def record_response(self, response: str) -> None:
"""Records response information for telemetry tracking.
def record_response(self, result: dict[str, object] | str) -> None:
"""Record the tool call result for telemetry tracking.

Note: This method is intentionally a no-op as GEN_AI_EVENT_CONTENT was removed.
The method is kept for interface compatibility.
Per OTEL spec, the result is expected to be an object. If a string
is provided, it is recorded as-is (JSON string fallback). If a dict
is provided, it is serialized to JSON.

Args:
response: The response to record
result: Tool call result as a structured dict or JSON string
"""
pass
serialized = safe_json_dumps(result) if isinstance(result, dict) else result
self.set_tag_maybe(GEN_AI_TOOL_CALL_RESULT_KEY, serialized)

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,7 @@
from dataclasses import dataclass

from .inference_operation_type import InferenceOperationType


@dataclass
class ServiceEndpoint:
"""Represents a service endpoint with hostname and optional port."""

hostname: str
"""The hostname of the service endpoint."""

port: int | None = None
"""The port of the service endpoint."""
from .models.service_endpoint import ServiceEndpoint


@dataclass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
GEN_AI_CALLER_CLIENT_IP_KEY,
)
from .inference_call_details import InferenceCallDetails
from .message_utils import (
normalize_input_messages,
normalize_output_messages,
serialize_messages,
)
from .models.messages import InputMessagesParam, OutputMessagesParam
from .models.user_details import UserDetails
from .opentelemetry_scope import OpenTelemetryScope
from .request import Request
Expand Down Expand Up @@ -96,8 +102,8 @@ def __init__(
span_details=resolved_span_details,
)

if request.content:
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, request.content)
if request.content is not None:
self.record_input_messages(request.content)
self.set_tag_maybe(GEN_AI_CONVERSATION_ID_KEY, request.conversation_id)

self.set_tag_maybe(GEN_AI_OPERATION_NAME_KEY, details.operationName.value)
Expand Down Expand Up @@ -138,21 +144,29 @@ def __init__(
validate_and_normalize_ip(user_details.user_client_ip),
)

def record_input_messages(self, messages: List[str]) -> None:
def record_input_messages(self, messages: InputMessagesParam) -> None:
"""Records the input messages for telemetry tracking.

Accepts plain strings (auto-wrapped as OTEL ChatMessage with role ``user``)
or a versioned ``InputMessages`` wrapper.

Args:
messages: List of input messages
messages: List of input message strings or an InputMessages wrapper
"""
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, safe_json_dumps(messages))
wrapper = normalize_input_messages(messages)
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, serialize_messages(wrapper))

def record_output_messages(self, messages: List[str]) -> None:
def record_output_messages(self, messages: OutputMessagesParam) -> None:
"""Records the output messages for telemetry tracking.

Accepts plain strings (auto-wrapped as OTEL OutputMessage with role ``assistant``)
or a versioned ``OutputMessages`` wrapper.

Args:
messages: List of output messages
messages: List of output message strings or an OutputMessages wrapper
"""
self.set_tag_maybe(GEN_AI_OUTPUT_MESSAGES_KEY, safe_json_dumps(messages))
wrapper = normalize_output_messages(messages)
self.set_tag_maybe(GEN_AI_OUTPUT_MESSAGES_KEY, serialize_messages(wrapper))

def record_input_tokens(self, input_tokens: int) -> None:
"""Records the number of input tokens for telemetry tracking.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
# Data class for invoke agent scope details.

from dataclasses import dataclass
from urllib.parse import ParseResult

from .models.service_endpoint import ServiceEndpoint


@dataclass
class InvokeAgentScopeDetails:
"""Scope-level configuration for agent invocation tracing."""

endpoint: ParseResult | None = None
endpoint: ServiceEndpoint | None = None
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@
USER_NAME_KEY,
)
from .invoke_agent_details import InvokeAgentScopeDetails
from .message_utils import (
normalize_input_messages,
normalize_output_messages,
serialize_messages,
)
from .models.caller_details import CallerDetails
from .models.messages import InputMessagesParam, OutputMessagesParam
from .opentelemetry_scope import OpenTelemetryScope
from .request import Request
from .span_details import SpanDetails
from .utils import safe_json_dumps, validate_and_normalize_ip
from .utils import validate_and_normalize_ip

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -129,8 +135,8 @@ def __init__(
if request.channel:
self.set_tag_maybe(CHANNEL_NAME_KEY, request.channel.name)
self.set_tag_maybe(CHANNEL_LINK_KEY, request.channel.link)
if request.content:
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, safe_json_dumps([request.content]))
if request.content is not None:
self.record_input_messages(request.content)

# Set caller details tags
if caller_details:
Expand Down Expand Up @@ -176,18 +182,26 @@ def record_response(self, response: str) -> None:
"""
self.record_output_messages([response])

def record_input_messages(self, messages: list[str]) -> None:
def record_input_messages(self, messages: InputMessagesParam) -> None:
"""Record the input messages for telemetry tracking.

Accepts plain strings (auto-wrapped as OTEL ChatMessage with role ``user``)
or a versioned ``InputMessages`` wrapper.

Args:
messages: List of input messages to record
messages: List of input message strings or an InputMessages wrapper
"""
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, safe_json_dumps(messages))
wrapper = normalize_input_messages(messages)
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, serialize_messages(wrapper))

def record_output_messages(self, messages: list[str]) -> None:
def record_output_messages(self, messages: OutputMessagesParam) -> None:
"""Record the output messages for telemetry tracking.

Accepts plain strings (auto-wrapped as OTEL OutputMessage with role ``assistant``)
or a versioned ``OutputMessages`` wrapper.

Args:
messages: List of output messages to record
messages: List of output message strings or an OutputMessages wrapper
"""
self.set_tag_maybe(GEN_AI_OUTPUT_MESSAGES_KEY, safe_json_dumps(messages))
wrapper = normalize_output_messages(messages)
self.set_tag_maybe(GEN_AI_OUTPUT_MESSAGES_KEY, serialize_messages(wrapper))
Loading
Loading