microsoft-agents-a365-observability-core 0.2.1.dev45__tar.gz → 0.2.1.dev46__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/PKG-INFO +1 -1
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/__init__.py +10 -8
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/agent_details.py +3 -6
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/constants.py +3 -1
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/execute_tool_scope.py +48 -50
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/inference_scope.py +41 -35
- microsoft_agents_a365_observability_core-0.2.1.dev46/microsoft_agents_a365/observability/core/invoke_agent_details.py +14 -0
- microsoft_agents_a365_observability_core-0.2.1.dev46/microsoft_agents_a365/observability/core/invoke_agent_scope.py +187 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/middleware/baggage_builder.py +15 -15
- microsoft_agents_a365_observability_core-0.2.1.dev46/microsoft_agents_a365/observability/core/models/caller_details.py +24 -0
- microsoft_agents_a365_observability_core-0.2.1.dev46/microsoft_agents_a365/observability/core/models/user_details.py +22 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/opentelemetry_scope.py +4 -12
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/request.py +2 -3
- microsoft_agents_a365_observability_core-0.2.1.dev46/microsoft_agents_a365/observability/core/span_details.py +25 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/spans_scopes/output_scope.py +49 -35
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/trace_processor/util.py +0 -1
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365_observability_core.egg-info/PKG-INFO +1 -1
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365_observability_core.egg-info/SOURCES.txt +2 -0
- microsoft_agents_a365_observability_core-0.2.1.dev45/microsoft_agents_a365/observability/core/invoke_agent_details.py +0 -18
- microsoft_agents_a365_observability_core-0.2.1.dev45/microsoft_agents_a365/observability/core/invoke_agent_scope.py +0 -208
- microsoft_agents_a365_observability_core-0.2.1.dev45/microsoft_agents_a365/observability/core/models/caller_details.py +0 -22
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/README.md +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/channel.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/config.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/execution_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/exporters/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/exporters/agent365_exporter.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/exporters/agent365_exporter_options.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/exporters/enriched_span.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/exporters/enriching_span_processor.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/exporters/spectra_exporter_options.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/exporters/utils.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/inference_call_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/inference_operation_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/middleware/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/models/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/models/agent_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/models/operation_source.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/models/response.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/spans_scopes/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/tenant_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/tool_call_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/tool_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/trace_processor/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/trace_processor/span_processor.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365/observability/core/utils.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365_observability_core.egg-info/dependency_links.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365_observability_core.egg-info/requires.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/microsoft_agents_a365_observability_core.egg-info/top_level.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/pyproject.toml +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/setup.cfg +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev45 → microsoft_agents_a365_observability_core-0.2.1.dev46}/setup.py +0 -0
|
@@ -11,7 +11,6 @@ from .config import (
|
|
|
11
11
|
is_configured,
|
|
12
12
|
)
|
|
13
13
|
from .execute_tool_scope import ExecuteToolScope
|
|
14
|
-
from .execution_type import ExecutionType
|
|
15
14
|
from .exporters.agent365_exporter_options import Agent365ExporterOptions
|
|
16
15
|
from .exporters.enriched_span import EnrichedReadableSpan
|
|
17
16
|
from .exporters.enriching_span_processor import (
|
|
@@ -23,13 +22,16 @@ from .exporters.spectra_exporter_options import SpectraExporterOptions
|
|
|
23
22
|
from .inference_call_details import InferenceCallDetails, ServiceEndpoint
|
|
24
23
|
from .inference_operation_type import InferenceOperationType
|
|
25
24
|
from .inference_scope import InferenceScope
|
|
26
|
-
from .invoke_agent_details import
|
|
25
|
+
from .invoke_agent_details import InvokeAgentScopeDetails
|
|
27
26
|
from .invoke_agent_scope import InvokeAgentScope
|
|
28
27
|
from .middleware.baggage_builder import BaggageBuilder
|
|
28
|
+
from .models.caller_details import CallerDetails
|
|
29
|
+
from .models.user_details import UserDetails
|
|
29
30
|
from .opentelemetry_scope import OpenTelemetryScope
|
|
30
31
|
from .request import Request
|
|
31
32
|
from .channel import Channel
|
|
32
|
-
from .
|
|
33
|
+
from .span_details import SpanDetails
|
|
34
|
+
from .spans_scopes.output_scope import OutputScope
|
|
33
35
|
from .tool_call_details import ToolCallDetails
|
|
34
36
|
from .tool_type import ToolType
|
|
35
37
|
from .trace_processor.span_processor import SpanProcessor
|
|
@@ -57,26 +59,26 @@ __all__ = [
|
|
|
57
59
|
"ExecuteToolScope",
|
|
58
60
|
"InvokeAgentScope",
|
|
59
61
|
"InferenceScope",
|
|
62
|
+
"OutputScope",
|
|
60
63
|
# Middleware
|
|
61
64
|
"BaggageBuilder",
|
|
62
65
|
# Data classes
|
|
63
|
-
"
|
|
66
|
+
"InvokeAgentScopeDetails",
|
|
64
67
|
"AgentDetails",
|
|
65
|
-
"
|
|
68
|
+
"CallerDetails",
|
|
69
|
+
"UserDetails",
|
|
66
70
|
"ToolCallDetails",
|
|
67
71
|
"Channel",
|
|
68
72
|
"Request",
|
|
73
|
+
"SpanDetails",
|
|
69
74
|
"InferenceCallDetails",
|
|
70
75
|
"ServiceEndpoint",
|
|
71
76
|
# Enums
|
|
72
|
-
"ExecutionType",
|
|
73
77
|
"InferenceOperationType",
|
|
74
78
|
"ToolType",
|
|
75
79
|
# Utility functions
|
|
76
80
|
"extract_context_from_headers",
|
|
77
81
|
"get_traceparent",
|
|
78
|
-
# Constants
|
|
79
|
-
# all constants from constants.py are exported via *
|
|
80
82
|
]
|
|
81
83
|
|
|
82
84
|
# This is a namespace package
|
|
@@ -18,11 +18,11 @@ class AgentDetails:
|
|
|
18
18
|
agent_description: Optional[str] = None
|
|
19
19
|
"""A description of the AI agent's purpose or capabilities."""
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
agentic_user_id: Optional[str] = None
|
|
22
22
|
"""Agentic User ID for the agent."""
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
"""
|
|
24
|
+
agentic_user_email: Optional[str] = None
|
|
25
|
+
"""Email address for the agentic user."""
|
|
26
26
|
|
|
27
27
|
agent_blueprint_id: Optional[str] = None
|
|
28
28
|
"""Blueprint/Application ID for the agent."""
|
|
@@ -33,9 +33,6 @@ class AgentDetails:
|
|
|
33
33
|
tenant_id: Optional[str] = None
|
|
34
34
|
"""Tenant ID for the agent."""
|
|
35
35
|
|
|
36
|
-
conversation_id: Optional[str] = None
|
|
37
|
-
"""Optional conversation ID for compatibility."""
|
|
38
|
-
|
|
39
36
|
icon_uri: Optional[str] = None
|
|
40
37
|
"""Optional icon URI for the agent."""
|
|
41
38
|
|
|
@@ -87,8 +87,10 @@ GEN_AI_AGENT_AUID_KEY = "microsoft.agent.user.id"
|
|
|
87
87
|
GEN_AI_AGENT_EMAIL_KEY = "microsoft.agent.user.email"
|
|
88
88
|
GEN_AI_AGENT_BLUEPRINT_ID_KEY = "microsoft.a365.agent.blueprint.id"
|
|
89
89
|
|
|
90
|
+
# Error type constants
|
|
91
|
+
ERROR_TYPE_CANCELLED = "TaskCanceledException"
|
|
92
|
+
|
|
90
93
|
# Execution context dimensions
|
|
91
|
-
GEN_AI_EXECUTION_TYPE_KEY = "gen_ai.execution.type"
|
|
92
94
|
GEN_AI_EXECUTION_PAYLOAD_KEY = "gen_ai.execution.payload"
|
|
93
95
|
|
|
94
96
|
# Channel dimensions
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# Copyright (c) Microsoft Corporation.
|
|
2
2
|
# Licensed under the MIT License.
|
|
3
3
|
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
|
|
6
|
-
from opentelemetry.context import Context
|
|
7
4
|
from opentelemetry.trace import SpanKind
|
|
8
5
|
|
|
9
6
|
from .agent_details import AgentDetails
|
|
@@ -11,6 +8,8 @@ from .constants import (
|
|
|
11
8
|
CHANNEL_LINK_KEY,
|
|
12
9
|
CHANNEL_NAME_KEY,
|
|
13
10
|
EXECUTE_TOOL_OPERATION_NAME,
|
|
11
|
+
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
12
|
+
GEN_AI_CONVERSATION_ID_KEY,
|
|
14
13
|
GEN_AI_TOOL_ARGS_KEY,
|
|
15
14
|
GEN_AI_TOOL_CALL_ID_KEY,
|
|
16
15
|
GEN_AI_TOOL_DESCRIPTION_KEY,
|
|
@@ -18,11 +17,16 @@ from .constants import (
|
|
|
18
17
|
GEN_AI_TOOL_TYPE_KEY,
|
|
19
18
|
SERVER_ADDRESS_KEY,
|
|
20
19
|
SERVER_PORT_KEY,
|
|
20
|
+
USER_EMAIL_KEY,
|
|
21
|
+
USER_ID_KEY,
|
|
22
|
+
USER_NAME_KEY,
|
|
21
23
|
)
|
|
24
|
+
from .models.user_details import UserDetails
|
|
22
25
|
from .opentelemetry_scope import OpenTelemetryScope
|
|
23
26
|
from .request import Request
|
|
24
|
-
from .
|
|
27
|
+
from .span_details import SpanDetails
|
|
25
28
|
from .tool_call_details import ToolCallDetails
|
|
29
|
+
from .utils import validate_and_normalize_ip
|
|
26
30
|
|
|
27
31
|
|
|
28
32
|
class ExecuteToolScope(OpenTelemetryScope):
|
|
@@ -30,88 +34,71 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
30
34
|
|
|
31
35
|
@staticmethod
|
|
32
36
|
def start(
|
|
37
|
+
request: Request,
|
|
33
38
|
details: ToolCallDetails,
|
|
34
39
|
agent_details: AgentDetails,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
parent_context: Context | None = None,
|
|
38
|
-
start_time: datetime | None = None,
|
|
39
|
-
end_time: datetime | None = None,
|
|
40
|
-
span_kind: SpanKind | None = None,
|
|
40
|
+
user_details: UserDetails | None = None,
|
|
41
|
+
span_details: SpanDetails | None = None,
|
|
41
42
|
) -> "ExecuteToolScope":
|
|
42
43
|
"""Creates and starts a new scope for tool execution tracing.
|
|
43
44
|
|
|
44
45
|
Args:
|
|
46
|
+
request: Request details for the tool execution
|
|
45
47
|
details: The details of the tool call
|
|
46
48
|
agent_details: The details of the agent making the call
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
50
|
-
upstream operation. Use ``extract_context_from_headers()`` to convert a
|
|
51
|
-
Context from HTTP headers containing W3C traceparent.
|
|
52
|
-
start_time: Optional explicit start time as a datetime object. Useful when
|
|
53
|
-
recording a tool call after execution has already completed.
|
|
54
|
-
end_time: Optional explicit end time as a datetime object. When provided,
|
|
55
|
-
the span will use this timestamp when disposed instead of the
|
|
56
|
-
current wall-clock time.
|
|
57
|
-
span_kind: Optional span kind override. Defaults to ``SpanKind.INTERNAL``.
|
|
58
|
-
Use ``SpanKind.CLIENT`` when the tool calls an external service.
|
|
49
|
+
user_details: Optional human user details
|
|
50
|
+
span_details: Optional span configuration (parent context, timing, kind)
|
|
59
51
|
|
|
60
52
|
Returns:
|
|
61
53
|
A new ExecuteToolScope instance
|
|
62
54
|
"""
|
|
63
55
|
return ExecuteToolScope(
|
|
56
|
+
request,
|
|
64
57
|
details,
|
|
65
58
|
agent_details,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
parent_context,
|
|
69
|
-
start_time,
|
|
70
|
-
end_time,
|
|
71
|
-
span_kind,
|
|
59
|
+
user_details,
|
|
60
|
+
span_details,
|
|
72
61
|
)
|
|
73
62
|
|
|
74
63
|
def __init__(
|
|
75
64
|
self,
|
|
65
|
+
request: Request,
|
|
76
66
|
details: ToolCallDetails,
|
|
77
67
|
agent_details: AgentDetails,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
parent_context: Context | None = None,
|
|
81
|
-
start_time: datetime | None = None,
|
|
82
|
-
end_time: datetime | None = None,
|
|
83
|
-
span_kind: SpanKind | None = None,
|
|
68
|
+
user_details: UserDetails | None = None,
|
|
69
|
+
span_details: SpanDetails | None = None,
|
|
84
70
|
):
|
|
85
71
|
"""Initialize the tool execution scope.
|
|
86
72
|
|
|
87
73
|
Args:
|
|
74
|
+
request: Request details for the tool execution
|
|
88
75
|
details: The details of the tool call
|
|
89
76
|
agent_details: The details of the agent making the call
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
93
|
-
upstream operation. Use ``extract_context_from_headers()`` to convert a
|
|
94
|
-
Context from HTTP headers containing W3C traceparent.
|
|
95
|
-
start_time: Optional explicit start time as a datetime object. Useful when
|
|
96
|
-
recording a tool call after execution has already completed.
|
|
97
|
-
end_time: Optional explicit end time as a datetime object. When provided,
|
|
98
|
-
the span will use this timestamp when disposed instead of the
|
|
99
|
-
current wall-clock time.
|
|
100
|
-
span_kind: Optional span kind override. Defaults to ``SpanKind.INTERNAL``.
|
|
101
|
-
Use ``SpanKind.CLIENT`` when the tool calls an external service.
|
|
77
|
+
user_details: Optional human user details
|
|
78
|
+
span_details: Optional span configuration (parent context, timing, kind)
|
|
102
79
|
"""
|
|
80
|
+
kind = SpanKind.INTERNAL
|
|
81
|
+
parent_context = None
|
|
82
|
+
start_time = None
|
|
83
|
+
end_time = None
|
|
84
|
+
if span_details is not None:
|
|
85
|
+
if span_details.span_kind is not None:
|
|
86
|
+
kind = span_details.span_kind
|
|
87
|
+
parent_context = span_details.parent_context
|
|
88
|
+
start_time = span_details.start_time
|
|
89
|
+
end_time = span_details.end_time
|
|
90
|
+
|
|
103
91
|
super().__init__(
|
|
104
|
-
kind=
|
|
92
|
+
kind=kind,
|
|
105
93
|
operation_name=EXECUTE_TOOL_OPERATION_NAME,
|
|
106
94
|
activity_name=f"{EXECUTE_TOOL_OPERATION_NAME} {details.tool_name}",
|
|
107
95
|
agent_details=agent_details,
|
|
108
|
-
tenant_details=tenant_details,
|
|
109
96
|
parent_context=parent_context,
|
|
110
97
|
start_time=start_time,
|
|
111
98
|
end_time=end_time,
|
|
112
99
|
)
|
|
113
100
|
|
|
114
|
-
# Extract details
|
|
101
|
+
# Extract details
|
|
115
102
|
tool_name = details.tool_name
|
|
116
103
|
arguments = details.arguments
|
|
117
104
|
tool_call_id = details.tool_call_id
|
|
@@ -124,6 +111,7 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
124
111
|
self.set_tag_maybe(GEN_AI_TOOL_TYPE_KEY, tool_type)
|
|
125
112
|
self.set_tag_maybe(GEN_AI_TOOL_CALL_ID_KEY, tool_call_id)
|
|
126
113
|
self.set_tag_maybe(GEN_AI_TOOL_DESCRIPTION_KEY, description)
|
|
114
|
+
self.set_tag_maybe(GEN_AI_CONVERSATION_ID_KEY, request.conversation_id)
|
|
127
115
|
|
|
128
116
|
if endpoint:
|
|
129
117
|
self.set_tag_maybe(SERVER_ADDRESS_KEY, endpoint.hostname)
|
|
@@ -131,10 +119,20 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
131
119
|
self.set_tag_maybe(SERVER_PORT_KEY, endpoint.port)
|
|
132
120
|
|
|
133
121
|
# Set request metadata if provided
|
|
134
|
-
if request
|
|
122
|
+
if request.channel:
|
|
135
123
|
self.set_tag_maybe(CHANNEL_NAME_KEY, request.channel.name)
|
|
136
124
|
self.set_tag_maybe(CHANNEL_LINK_KEY, request.channel.link)
|
|
137
125
|
|
|
126
|
+
# Set user details if provided
|
|
127
|
+
if user_details:
|
|
128
|
+
self.set_tag_maybe(USER_ID_KEY, user_details.user_id)
|
|
129
|
+
self.set_tag_maybe(USER_EMAIL_KEY, user_details.user_email)
|
|
130
|
+
self.set_tag_maybe(USER_NAME_KEY, user_details.user_name)
|
|
131
|
+
self.set_tag_maybe(
|
|
132
|
+
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
133
|
+
validate_and_normalize_ip(user_details.user_client_ip),
|
|
134
|
+
)
|
|
135
|
+
|
|
138
136
|
def record_response(self, response: str) -> None:
|
|
139
137
|
"""Records response information for telemetry tracking.
|
|
140
138
|
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
# Copyright (c) Microsoft Corporation.
|
|
2
2
|
# Licensed under the MIT License.
|
|
3
3
|
|
|
4
|
-
from datetime import datetime
|
|
5
4
|
from typing import List
|
|
6
5
|
|
|
7
|
-
from opentelemetry.context import Context
|
|
8
|
-
|
|
9
6
|
from .agent_details import AgentDetails
|
|
10
7
|
from .constants import (
|
|
11
8
|
CHANNEL_LINK_KEY,
|
|
12
9
|
CHANNEL_NAME_KEY,
|
|
13
10
|
GEN_AI_AGENT_THOUGHT_PROCESS_KEY,
|
|
11
|
+
GEN_AI_CONVERSATION_ID_KEY,
|
|
14
12
|
GEN_AI_INPUT_MESSAGES_KEY,
|
|
15
13
|
GEN_AI_OPERATION_NAME_KEY,
|
|
16
14
|
GEN_AI_OUTPUT_MESSAGES_KEY,
|
|
@@ -21,12 +19,17 @@ from .constants import (
|
|
|
21
19
|
GEN_AI_USAGE_OUTPUT_TOKENS_KEY,
|
|
22
20
|
SERVER_ADDRESS_KEY,
|
|
23
21
|
SERVER_PORT_KEY,
|
|
22
|
+
USER_EMAIL_KEY,
|
|
23
|
+
USER_ID_KEY,
|
|
24
|
+
USER_NAME_KEY,
|
|
25
|
+
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
24
26
|
)
|
|
25
27
|
from .inference_call_details import InferenceCallDetails
|
|
28
|
+
from .models.user_details import UserDetails
|
|
26
29
|
from .opentelemetry_scope import OpenTelemetryScope
|
|
27
30
|
from .request import Request
|
|
28
|
-
from .
|
|
29
|
-
from .utils import safe_json_dumps
|
|
31
|
+
from .span_details import SpanDetails
|
|
32
|
+
from .utils import safe_json_dumps, validate_and_normalize_ip
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
class InferenceScope(OpenTelemetryScope):
|
|
@@ -34,71 +37,64 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
34
37
|
|
|
35
38
|
@staticmethod
|
|
36
39
|
def start(
|
|
40
|
+
request: Request,
|
|
37
41
|
details: InferenceCallDetails,
|
|
38
42
|
agent_details: AgentDetails,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
parent_context: Context | None = None,
|
|
42
|
-
start_time: datetime | None = None,
|
|
43
|
-
end_time: datetime | None = None,
|
|
43
|
+
user_details: UserDetails | None = None,
|
|
44
|
+
span_details: SpanDetails | None = None,
|
|
44
45
|
) -> "InferenceScope":
|
|
45
46
|
"""Creates and starts a new scope for inference tracing.
|
|
46
47
|
|
|
47
48
|
Args:
|
|
49
|
+
request: Request details for the inference
|
|
48
50
|
details: The details of the inference call
|
|
49
51
|
agent_details: The details of the agent making the call
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
53
|
-
upstream operation. Use ``extract_context_from_headers()`` to convert a
|
|
54
|
-
Context from HTTP headers containing W3C traceparent.
|
|
55
|
-
start_time: Optional explicit start time as a datetime object.
|
|
56
|
-
end_time: Optional explicit end time as a datetime object.
|
|
52
|
+
user_details: Optional human user details
|
|
53
|
+
span_details: Optional span configuration (parent context, timing)
|
|
57
54
|
|
|
58
55
|
Returns:
|
|
59
56
|
A new InferenceScope instance
|
|
60
57
|
"""
|
|
61
|
-
return InferenceScope(
|
|
62
|
-
details, agent_details, tenant_details, request, parent_context, start_time, end_time
|
|
63
|
-
)
|
|
58
|
+
return InferenceScope(request, details, agent_details, user_details, span_details)
|
|
64
59
|
|
|
65
60
|
def __init__(
|
|
66
61
|
self,
|
|
62
|
+
request: Request,
|
|
67
63
|
details: InferenceCallDetails,
|
|
68
64
|
agent_details: AgentDetails,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
parent_context: Context | None = None,
|
|
72
|
-
start_time: datetime | None = None,
|
|
73
|
-
end_time: datetime | None = None,
|
|
65
|
+
user_details: UserDetails | None = None,
|
|
66
|
+
span_details: SpanDetails | None = None,
|
|
74
67
|
):
|
|
75
68
|
"""Initialize the inference scope.
|
|
76
69
|
|
|
77
70
|
Args:
|
|
71
|
+
request: Request details for the inference
|
|
78
72
|
details: The details of the inference call
|
|
79
73
|
agent_details: The details of the agent making the call
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
83
|
-
upstream operation. Use ``extract_context_from_headers()`` to convert a
|
|
84
|
-
Context from HTTP headers containing W3C traceparent.
|
|
85
|
-
start_time: Optional explicit start time as a datetime object.
|
|
86
|
-
end_time: Optional explicit end time as a datetime object.
|
|
74
|
+
user_details: Optional human user details
|
|
75
|
+
span_details: Optional span configuration (parent context, timing)
|
|
87
76
|
"""
|
|
77
|
+
parent_context = None
|
|
78
|
+
start_time = None
|
|
79
|
+
end_time = None
|
|
80
|
+
if span_details is not None:
|
|
81
|
+
parent_context = span_details.parent_context
|
|
82
|
+
start_time = span_details.start_time
|
|
83
|
+
end_time = span_details.end_time
|
|
88
84
|
|
|
89
85
|
super().__init__(
|
|
90
86
|
kind="Client",
|
|
91
87
|
operation_name=details.operationName.value,
|
|
92
88
|
activity_name=f"{details.operationName.value} {details.model}",
|
|
93
89
|
agent_details=agent_details,
|
|
94
|
-
tenant_details=tenant_details,
|
|
95
90
|
parent_context=parent_context,
|
|
96
91
|
start_time=start_time,
|
|
97
92
|
end_time=end_time,
|
|
98
93
|
)
|
|
99
94
|
|
|
100
|
-
if request:
|
|
95
|
+
if request.content:
|
|
101
96
|
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, request.content)
|
|
97
|
+
self.set_tag_maybe(GEN_AI_CONVERSATION_ID_KEY, request.conversation_id)
|
|
102
98
|
|
|
103
99
|
self.set_tag_maybe(GEN_AI_OPERATION_NAME_KEY, details.operationName.value)
|
|
104
100
|
self.set_tag_maybe(GEN_AI_REQUEST_MODEL_KEY, details.model)
|
|
@@ -124,10 +120,20 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
124
120
|
self.set_tag_maybe(SERVER_PORT_KEY, str(details.endpoint.port))
|
|
125
121
|
|
|
126
122
|
# Set request metadata if provided
|
|
127
|
-
if request
|
|
123
|
+
if request.channel:
|
|
128
124
|
self.set_tag_maybe(CHANNEL_NAME_KEY, request.channel.name)
|
|
129
125
|
self.set_tag_maybe(CHANNEL_LINK_KEY, request.channel.link)
|
|
130
126
|
|
|
127
|
+
# Set user details if provided
|
|
128
|
+
if user_details:
|
|
129
|
+
self.set_tag_maybe(USER_ID_KEY, user_details.user_id)
|
|
130
|
+
self.set_tag_maybe(USER_EMAIL_KEY, user_details.user_email)
|
|
131
|
+
self.set_tag_maybe(USER_NAME_KEY, user_details.user_name)
|
|
132
|
+
self.set_tag_maybe(
|
|
133
|
+
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
134
|
+
validate_and_normalize_ip(user_details.user_client_ip),
|
|
135
|
+
)
|
|
136
|
+
|
|
131
137
|
def record_input_messages(self, messages: List[str]) -> None:
|
|
132
138
|
"""Records the input messages for telemetry tracking.
|
|
133
139
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
# Data class for invoke agent scope details.
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from urllib.parse import ParseResult
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class InvokeAgentScopeDetails:
|
|
12
|
+
"""Scope-level configuration for agent invocation tracing."""
|
|
13
|
+
|
|
14
|
+
endpoint: ParseResult | None = None
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
# Invoke agent scope for tracing agent invocation.
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from opentelemetry.trace import SpanKind
|
|
9
|
+
|
|
10
|
+
from .agent_details import AgentDetails
|
|
11
|
+
from .constants import (
|
|
12
|
+
CHANNEL_LINK_KEY,
|
|
13
|
+
CHANNEL_NAME_KEY,
|
|
14
|
+
GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY,
|
|
15
|
+
GEN_AI_CALLER_AGENT_EMAIL_KEY,
|
|
16
|
+
GEN_AI_CALLER_AGENT_ID_KEY,
|
|
17
|
+
GEN_AI_CALLER_AGENT_NAME_KEY,
|
|
18
|
+
GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY,
|
|
19
|
+
GEN_AI_CALLER_AGENT_USER_ID_KEY,
|
|
20
|
+
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
21
|
+
GEN_AI_CONVERSATION_ID_KEY,
|
|
22
|
+
GEN_AI_INPUT_MESSAGES_KEY,
|
|
23
|
+
GEN_AI_OUTPUT_MESSAGES_KEY,
|
|
24
|
+
INVOKE_AGENT_OPERATION_NAME,
|
|
25
|
+
SERVER_ADDRESS_KEY,
|
|
26
|
+
SERVER_PORT_KEY,
|
|
27
|
+
SESSION_ID_KEY,
|
|
28
|
+
USER_EMAIL_KEY,
|
|
29
|
+
USER_ID_KEY,
|
|
30
|
+
USER_NAME_KEY,
|
|
31
|
+
)
|
|
32
|
+
from .invoke_agent_details import InvokeAgentScopeDetails
|
|
33
|
+
from .models.caller_details import CallerDetails
|
|
34
|
+
from .opentelemetry_scope import OpenTelemetryScope
|
|
35
|
+
from .request import Request
|
|
36
|
+
from .span_details import SpanDetails
|
|
37
|
+
from .utils import safe_json_dumps, validate_and_normalize_ip
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class InvokeAgentScope(OpenTelemetryScope):
|
|
43
|
+
"""Provides OpenTelemetry tracing scope for AI agent invocation operations."""
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def start(
|
|
47
|
+
request: Request,
|
|
48
|
+
scope_details: InvokeAgentScopeDetails,
|
|
49
|
+
agent_details: AgentDetails,
|
|
50
|
+
caller_details: CallerDetails | None = None,
|
|
51
|
+
span_details: SpanDetails | None = None,
|
|
52
|
+
) -> "InvokeAgentScope":
|
|
53
|
+
"""Create and start a new scope for agent invocation tracing.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
request: Request details for the invocation
|
|
57
|
+
scope_details: Scope-level configuration (endpoint)
|
|
58
|
+
agent_details: The details of the agent being invoked
|
|
59
|
+
caller_details: Optional composite caller details (human user and/or
|
|
60
|
+
calling agent for A2A scenarios)
|
|
61
|
+
span_details: Optional span configuration (parent context, timing, kind)
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
A new InvokeAgentScope instance
|
|
65
|
+
"""
|
|
66
|
+
return InvokeAgentScope(
|
|
67
|
+
request,
|
|
68
|
+
scope_details,
|
|
69
|
+
agent_details,
|
|
70
|
+
caller_details,
|
|
71
|
+
span_details,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
request: Request,
|
|
77
|
+
scope_details: InvokeAgentScopeDetails,
|
|
78
|
+
agent_details: AgentDetails,
|
|
79
|
+
caller_details: CallerDetails | None = None,
|
|
80
|
+
span_details: SpanDetails | None = None,
|
|
81
|
+
):
|
|
82
|
+
"""Initialize the agent invocation scope.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
request: Request details for the invocation
|
|
86
|
+
scope_details: Scope-level configuration (endpoint)
|
|
87
|
+
agent_details: The details of the agent being invoked
|
|
88
|
+
caller_details: Optional composite caller details (human user and/or
|
|
89
|
+
calling agent for A2A scenarios)
|
|
90
|
+
span_details: Optional span configuration (parent context, timing, kind)
|
|
91
|
+
"""
|
|
92
|
+
activity_name = INVOKE_AGENT_OPERATION_NAME
|
|
93
|
+
if agent_details.agent_name:
|
|
94
|
+
activity_name = f"{INVOKE_AGENT_OPERATION_NAME} {agent_details.agent_name}"
|
|
95
|
+
|
|
96
|
+
kind = SpanKind.CLIENT
|
|
97
|
+
parent_context = None
|
|
98
|
+
start_time = None
|
|
99
|
+
end_time = None
|
|
100
|
+
if span_details is not None:
|
|
101
|
+
if span_details.span_kind is not None:
|
|
102
|
+
kind = span_details.span_kind
|
|
103
|
+
parent_context = span_details.parent_context
|
|
104
|
+
start_time = span_details.start_time
|
|
105
|
+
end_time = span_details.end_time
|
|
106
|
+
|
|
107
|
+
super().__init__(
|
|
108
|
+
kind=kind,
|
|
109
|
+
operation_name=INVOKE_AGENT_OPERATION_NAME,
|
|
110
|
+
activity_name=activity_name,
|
|
111
|
+
agent_details=agent_details,
|
|
112
|
+
parent_context=parent_context,
|
|
113
|
+
start_time=start_time,
|
|
114
|
+
end_time=end_time,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
self.set_tag_maybe(SESSION_ID_KEY, request.session_id)
|
|
118
|
+
self.set_tag_maybe(GEN_AI_CONVERSATION_ID_KEY, request.conversation_id)
|
|
119
|
+
|
|
120
|
+
endpoint = scope_details.endpoint
|
|
121
|
+
if endpoint:
|
|
122
|
+
self.set_tag_maybe(SERVER_ADDRESS_KEY, endpoint.hostname)
|
|
123
|
+
if endpoint.port and endpoint.port != 443:
|
|
124
|
+
self.set_tag_maybe(SERVER_PORT_KEY, endpoint.port)
|
|
125
|
+
|
|
126
|
+
# Set request metadata
|
|
127
|
+
if request.channel:
|
|
128
|
+
self.set_tag_maybe(CHANNEL_NAME_KEY, request.channel.name)
|
|
129
|
+
self.set_tag_maybe(CHANNEL_LINK_KEY, request.channel.link)
|
|
130
|
+
if request.content:
|
|
131
|
+
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, safe_json_dumps([request.content]))
|
|
132
|
+
|
|
133
|
+
# Set caller details tags
|
|
134
|
+
if caller_details:
|
|
135
|
+
user_details = caller_details.user_details
|
|
136
|
+
if user_details:
|
|
137
|
+
self.set_tag_maybe(USER_ID_KEY, user_details.user_id)
|
|
138
|
+
self.set_tag_maybe(USER_EMAIL_KEY, user_details.user_email)
|
|
139
|
+
self.set_tag_maybe(USER_NAME_KEY, user_details.user_name)
|
|
140
|
+
self.set_tag_maybe(
|
|
141
|
+
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
142
|
+
validate_and_normalize_ip(user_details.user_client_ip),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Set caller agent details tags
|
|
146
|
+
caller_agent_details = caller_details.caller_agent_details
|
|
147
|
+
if caller_agent_details:
|
|
148
|
+
self.set_tag_maybe(GEN_AI_CALLER_AGENT_NAME_KEY, caller_agent_details.agent_name)
|
|
149
|
+
self.set_tag_maybe(GEN_AI_CALLER_AGENT_ID_KEY, caller_agent_details.agent_id)
|
|
150
|
+
self.set_tag_maybe(
|
|
151
|
+
GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY,
|
|
152
|
+
caller_agent_details.agent_blueprint_id,
|
|
153
|
+
)
|
|
154
|
+
self.set_tag_maybe(
|
|
155
|
+
GEN_AI_CALLER_AGENT_USER_ID_KEY, caller_agent_details.agentic_user_id
|
|
156
|
+
)
|
|
157
|
+
self.set_tag_maybe(
|
|
158
|
+
GEN_AI_CALLER_AGENT_EMAIL_KEY, caller_agent_details.agentic_user_email
|
|
159
|
+
)
|
|
160
|
+
self.set_tag_maybe(
|
|
161
|
+
GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY,
|
|
162
|
+
caller_agent_details.agent_platform_id,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def record_response(self, response: str) -> None:
|
|
166
|
+
"""Record response information for telemetry tracking.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
response: The response string to record
|
|
170
|
+
"""
|
|
171
|
+
self.record_output_messages([response])
|
|
172
|
+
|
|
173
|
+
def record_input_messages(self, messages: list[str]) -> None:
|
|
174
|
+
"""Record the input messages for telemetry tracking.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
messages: List of input messages to record
|
|
178
|
+
"""
|
|
179
|
+
self.set_tag_maybe(GEN_AI_INPUT_MESSAGES_KEY, safe_json_dumps(messages))
|
|
180
|
+
|
|
181
|
+
def record_output_messages(self, messages: list[str]) -> None:
|
|
182
|
+
"""Record the output messages for telemetry tracking.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
messages: List of output messages to record
|
|
186
|
+
"""
|
|
187
|
+
self.set_tag_maybe(GEN_AI_OUTPUT_MESSAGES_KEY, safe_json_dumps(messages))
|