microsoft-agents-a365-observability-core 0.2.1.dev42__tar.gz → 0.2.1.dev44__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.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/PKG-INFO +1 -1
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/__init__.py +6 -2
- microsoft_agents_a365_observability_core-0.2.1.dev44/microsoft_agents_a365/observability/core/channel.py +14 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/constants.py +6 -6
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/execute_tool_scope.py +14 -11
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/inference_scope.py +15 -11
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/invoke_agent_scope.py +22 -11
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/middleware/baggage_builder.py +10 -20
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/opentelemetry_scope.py +53 -8
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/request.py +2 -2
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/spans_scopes/output_scope.py +14 -8
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/trace_processor/util.py +5 -5
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/utils.py +35 -102
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365_observability_core.egg-info/PKG-INFO +1 -1
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365_observability_core.egg-info/SOURCES.txt +1 -1
- microsoft_agents_a365_observability_core-0.2.1.dev42/microsoft_agents_a365/observability/core/source_metadata.py +0 -16
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/README.md +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/agent_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/config.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/execution_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/exporters/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/exporters/agent365_exporter.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/exporters/agent365_exporter_options.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/exporters/enriched_span.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/exporters/enriching_span_processor.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/exporters/spectra_exporter_options.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/exporters/utils.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/inference_call_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/inference_operation_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/invoke_agent_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/middleware/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/models/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/models/agent_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/models/caller_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/models/operation_source.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/models/response.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/spans_scopes/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/tenant_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/tool_call_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/tool_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/trace_processor/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365/observability/core/trace_processor/span_processor.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365_observability_core.egg-info/dependency_links.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365_observability_core.egg-info/requires.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/microsoft_agents_a365_observability_core.egg-info/top_level.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/pyproject.toml +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/setup.cfg +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/setup.py +0 -0
|
@@ -28,11 +28,12 @@ from .invoke_agent_scope import InvokeAgentScope
|
|
|
28
28
|
from .middleware.baggage_builder import BaggageBuilder
|
|
29
29
|
from .opentelemetry_scope import OpenTelemetryScope
|
|
30
30
|
from .request import Request
|
|
31
|
-
from .
|
|
31
|
+
from .channel import Channel
|
|
32
32
|
from .tenant_details import TenantDetails
|
|
33
33
|
from .tool_call_details import ToolCallDetails
|
|
34
34
|
from .tool_type import ToolType
|
|
35
35
|
from .trace_processor.span_processor import SpanProcessor
|
|
36
|
+
from .utils import extract_context_from_headers, get_traceparent
|
|
36
37
|
|
|
37
38
|
__all__ = [
|
|
38
39
|
# Main SDK functions
|
|
@@ -63,7 +64,7 @@ __all__ = [
|
|
|
63
64
|
"AgentDetails",
|
|
64
65
|
"TenantDetails",
|
|
65
66
|
"ToolCallDetails",
|
|
66
|
-
"
|
|
67
|
+
"Channel",
|
|
67
68
|
"Request",
|
|
68
69
|
"InferenceCallDetails",
|
|
69
70
|
"ServiceEndpoint",
|
|
@@ -71,6 +72,9 @@ __all__ = [
|
|
|
71
72
|
"ExecutionType",
|
|
72
73
|
"InferenceOperationType",
|
|
73
74
|
"ToolType",
|
|
75
|
+
# Utility functions
|
|
76
|
+
"extract_context_from_headers",
|
|
77
|
+
"get_traceparent",
|
|
74
78
|
# Constants
|
|
75
79
|
# all constants from constants.py are exported via *
|
|
76
80
|
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
# Channel class.
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Channel:
|
|
11
|
+
"""Channel information for agent execution context."""
|
|
12
|
+
|
|
13
|
+
name: str | None = None
|
|
14
|
+
link: str | None = None
|
|
@@ -60,15 +60,15 @@ GEN_AI_TOOL_ARGS_KEY = "gen_ai.tool.call.arguments"
|
|
|
60
60
|
GEN_AI_TOOL_CALL_RESULT_KEY = "gen_ai.tool.call.result"
|
|
61
61
|
GEN_AI_TOOL_TYPE_KEY = "gen_ai.tool.type"
|
|
62
62
|
|
|
63
|
-
#
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
# Human caller dimensions (OTel user.* namespace)
|
|
64
|
+
USER_ID_KEY = "user.id"
|
|
65
|
+
USER_NAME_KEY = "user.name"
|
|
66
|
+
USER_EMAIL_KEY = "user.email"
|
|
67
67
|
GEN_AI_CALLER_CLIENT_IP_KEY = "client.address"
|
|
68
68
|
|
|
69
69
|
# Agent to Agent caller agent dimensions
|
|
70
70
|
GEN_AI_CALLER_AGENT_USER_ID_KEY = "microsoft.a365.caller.agent.user.id"
|
|
71
|
-
|
|
71
|
+
GEN_AI_CALLER_AGENT_EMAIL_KEY = "microsoft.a365.caller.agent.user.email"
|
|
72
72
|
GEN_AI_CALLER_AGENT_NAME_KEY = "microsoft.a365.caller.agent.name"
|
|
73
73
|
GEN_AI_CALLER_AGENT_ID_KEY = "microsoft.a365.caller.agent.id"
|
|
74
74
|
GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY = "microsoft.a365.caller.agent.blueprint.id"
|
|
@@ -84,7 +84,7 @@ TENANT_ID_KEY = "microsoft.tenant.id"
|
|
|
84
84
|
|
|
85
85
|
# Baggage keys
|
|
86
86
|
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
90
|
# Execution context dimensions
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
|
|
6
|
+
from opentelemetry.context import Context
|
|
6
7
|
from opentelemetry.trace import SpanKind
|
|
7
8
|
|
|
8
9
|
from .agent_details import AgentDetails
|
|
@@ -33,7 +34,7 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
33
34
|
agent_details: AgentDetails,
|
|
34
35
|
tenant_details: TenantDetails,
|
|
35
36
|
request: Request | None = None,
|
|
36
|
-
|
|
37
|
+
parent_context: Context | None = None,
|
|
37
38
|
start_time: datetime | None = None,
|
|
38
39
|
end_time: datetime | None = None,
|
|
39
40
|
span_kind: SpanKind | None = None,
|
|
@@ -45,8 +46,9 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
45
46
|
agent_details: The details of the agent making the call
|
|
46
47
|
tenant_details: The details of the tenant
|
|
47
48
|
request: Optional request details for additional context
|
|
48
|
-
|
|
49
|
-
operation
|
|
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.
|
|
50
52
|
start_time: Optional explicit start time as a datetime object. Useful when
|
|
51
53
|
recording a tool call after execution has already completed.
|
|
52
54
|
end_time: Optional explicit end time as a datetime object. When provided,
|
|
@@ -63,7 +65,7 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
63
65
|
agent_details,
|
|
64
66
|
tenant_details,
|
|
65
67
|
request,
|
|
66
|
-
|
|
68
|
+
parent_context,
|
|
67
69
|
start_time,
|
|
68
70
|
end_time,
|
|
69
71
|
span_kind,
|
|
@@ -75,7 +77,7 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
75
77
|
agent_details: AgentDetails,
|
|
76
78
|
tenant_details: TenantDetails,
|
|
77
79
|
request: Request | None = None,
|
|
78
|
-
|
|
80
|
+
parent_context: Context | None = None,
|
|
79
81
|
start_time: datetime | None = None,
|
|
80
82
|
end_time: datetime | None = None,
|
|
81
83
|
span_kind: SpanKind | None = None,
|
|
@@ -87,8 +89,9 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
87
89
|
agent_details: The details of the agent making the call
|
|
88
90
|
tenant_details: The details of the tenant
|
|
89
91
|
request: Optional request details for additional context
|
|
90
|
-
|
|
91
|
-
operation
|
|
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.
|
|
92
95
|
start_time: Optional explicit start time as a datetime object. Useful when
|
|
93
96
|
recording a tool call after execution has already completed.
|
|
94
97
|
end_time: Optional explicit end time as a datetime object. When provided,
|
|
@@ -103,7 +106,7 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
103
106
|
activity_name=f"{EXECUTE_TOOL_OPERATION_NAME} {details.tool_name}",
|
|
104
107
|
agent_details=agent_details,
|
|
105
108
|
tenant_details=tenant_details,
|
|
106
|
-
|
|
109
|
+
parent_context=parent_context,
|
|
107
110
|
start_time=start_time,
|
|
108
111
|
end_time=end_time,
|
|
109
112
|
)
|
|
@@ -128,9 +131,9 @@ class ExecuteToolScope(OpenTelemetryScope):
|
|
|
128
131
|
self.set_tag_maybe(SERVER_PORT_KEY, endpoint.port)
|
|
129
132
|
|
|
130
133
|
# Set request metadata if provided
|
|
131
|
-
if request and request.
|
|
132
|
-
self.set_tag_maybe(CHANNEL_NAME_KEY, request.
|
|
133
|
-
self.set_tag_maybe(CHANNEL_LINK_KEY, request.
|
|
134
|
+
if request and request.channel:
|
|
135
|
+
self.set_tag_maybe(CHANNEL_NAME_KEY, request.channel.name)
|
|
136
|
+
self.set_tag_maybe(CHANNEL_LINK_KEY, request.channel.link)
|
|
134
137
|
|
|
135
138
|
def record_response(self, response: str) -> None:
|
|
136
139
|
"""Records response information for telemetry tracking.
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from typing import List
|
|
6
6
|
|
|
7
|
+
from opentelemetry.context import Context
|
|
8
|
+
|
|
7
9
|
from .agent_details import AgentDetails
|
|
8
10
|
from .constants import (
|
|
9
11
|
CHANNEL_LINK_KEY,
|
|
@@ -36,7 +38,7 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
36
38
|
agent_details: AgentDetails,
|
|
37
39
|
tenant_details: TenantDetails,
|
|
38
40
|
request: Request | None = None,
|
|
39
|
-
|
|
41
|
+
parent_context: Context | None = None,
|
|
40
42
|
start_time: datetime | None = None,
|
|
41
43
|
end_time: datetime | None = None,
|
|
42
44
|
) -> "InferenceScope":
|
|
@@ -47,8 +49,9 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
47
49
|
agent_details: The details of the agent making the call
|
|
48
50
|
tenant_details: The details of the tenant
|
|
49
51
|
request: Optional request details for additional context
|
|
50
|
-
|
|
51
|
-
operation
|
|
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.
|
|
52
55
|
start_time: Optional explicit start time as a datetime object.
|
|
53
56
|
end_time: Optional explicit end time as a datetime object.
|
|
54
57
|
|
|
@@ -56,7 +59,7 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
56
59
|
A new InferenceScope instance
|
|
57
60
|
"""
|
|
58
61
|
return InferenceScope(
|
|
59
|
-
details, agent_details, tenant_details, request,
|
|
62
|
+
details, agent_details, tenant_details, request, parent_context, start_time, end_time
|
|
60
63
|
)
|
|
61
64
|
|
|
62
65
|
def __init__(
|
|
@@ -65,7 +68,7 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
65
68
|
agent_details: AgentDetails,
|
|
66
69
|
tenant_details: TenantDetails,
|
|
67
70
|
request: Request | None = None,
|
|
68
|
-
|
|
71
|
+
parent_context: Context | None = None,
|
|
69
72
|
start_time: datetime | None = None,
|
|
70
73
|
end_time: datetime | None = None,
|
|
71
74
|
):
|
|
@@ -76,8 +79,9 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
76
79
|
agent_details: The details of the agent making the call
|
|
77
80
|
tenant_details: The details of the tenant
|
|
78
81
|
request: Optional request details for additional context
|
|
79
|
-
|
|
80
|
-
operation
|
|
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.
|
|
81
85
|
start_time: Optional explicit start time as a datetime object.
|
|
82
86
|
end_time: Optional explicit end time as a datetime object.
|
|
83
87
|
"""
|
|
@@ -88,7 +92,7 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
88
92
|
activity_name=f"{details.operationName.value} {details.model}",
|
|
89
93
|
agent_details=agent_details,
|
|
90
94
|
tenant_details=tenant_details,
|
|
91
|
-
|
|
95
|
+
parent_context=parent_context,
|
|
92
96
|
start_time=start_time,
|
|
93
97
|
end_time=end_time,
|
|
94
98
|
)
|
|
@@ -120,9 +124,9 @@ class InferenceScope(OpenTelemetryScope):
|
|
|
120
124
|
self.set_tag_maybe(SERVER_PORT_KEY, str(details.endpoint.port))
|
|
121
125
|
|
|
122
126
|
# Set request metadata if provided
|
|
123
|
-
if request and request.
|
|
124
|
-
self.set_tag_maybe(CHANNEL_NAME_KEY, request.
|
|
125
|
-
self.set_tag_maybe(CHANNEL_LINK_KEY, request.
|
|
127
|
+
if request and request.channel:
|
|
128
|
+
self.set_tag_maybe(CHANNEL_NAME_KEY, request.channel.name)
|
|
129
|
+
self.set_tag_maybe(CHANNEL_LINK_KEY, request.channel.link)
|
|
126
130
|
|
|
127
131
|
def record_input_messages(self, messages: List[str]) -> None:
|
|
128
132
|
"""Records the input messages for telemetry tracking.
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import logging
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
|
|
9
|
+
from opentelemetry.context import Context
|
|
9
10
|
from opentelemetry.trace import SpanKind
|
|
10
11
|
|
|
11
12
|
from .agent_details import AgentDetails
|
|
@@ -13,15 +14,12 @@ from .constants import (
|
|
|
13
14
|
CHANNEL_LINK_KEY,
|
|
14
15
|
CHANNEL_NAME_KEY,
|
|
15
16
|
GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY,
|
|
17
|
+
GEN_AI_CALLER_AGENT_EMAIL_KEY,
|
|
16
18
|
GEN_AI_CALLER_AGENT_ID_KEY,
|
|
17
19
|
GEN_AI_CALLER_AGENT_NAME_KEY,
|
|
18
20
|
GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY,
|
|
19
|
-
GEN_AI_CALLER_AGENT_UPN_KEY,
|
|
20
21
|
GEN_AI_CALLER_AGENT_USER_ID_KEY,
|
|
21
22
|
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
22
|
-
GEN_AI_CALLER_ID_KEY,
|
|
23
|
-
GEN_AI_CALLER_NAME_KEY,
|
|
24
|
-
GEN_AI_CALLER_UPN_KEY,
|
|
25
23
|
GEN_AI_EXECUTION_TYPE_KEY,
|
|
26
24
|
GEN_AI_INPUT_MESSAGES_KEY,
|
|
27
25
|
GEN_AI_OUTPUT_MESSAGES_KEY,
|
|
@@ -29,6 +27,9 @@ from .constants import (
|
|
|
29
27
|
SERVER_ADDRESS_KEY,
|
|
30
28
|
SERVER_PORT_KEY,
|
|
31
29
|
SESSION_ID_KEY,
|
|
30
|
+
USER_EMAIL_KEY,
|
|
31
|
+
USER_ID_KEY,
|
|
32
|
+
USER_NAME_KEY,
|
|
32
33
|
)
|
|
33
34
|
from .invoke_agent_details import InvokeAgentDetails
|
|
34
35
|
from .models.caller_details import CallerDetails
|
|
@@ -50,6 +51,7 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
50
51
|
request: Request | None = None,
|
|
51
52
|
caller_agent_details: AgentDetails | None = None,
|
|
52
53
|
caller_details: CallerDetails | None = None,
|
|
54
|
+
parent_context: Context | None = None,
|
|
53
55
|
start_time: datetime | None = None,
|
|
54
56
|
end_time: datetime | None = None,
|
|
55
57
|
span_kind: SpanKind | None = None,
|
|
@@ -63,6 +65,9 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
63
65
|
request: Optional request details for additional context
|
|
64
66
|
caller_agent_details: Optional details of the caller agent
|
|
65
67
|
caller_details: Optional details of the non-agentic caller
|
|
68
|
+
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
69
|
+
upstream operation. Use ``extract_context_from_headers()`` to convert a
|
|
70
|
+
Context from HTTP headers containing W3C traceparent.
|
|
66
71
|
start_time: Optional explicit start time as a datetime object.
|
|
67
72
|
end_time: Optional explicit end time as a datetime object.
|
|
68
73
|
span_kind: Optional span kind override. Defaults to ``SpanKind.CLIENT``.
|
|
@@ -77,6 +82,7 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
77
82
|
request,
|
|
78
83
|
caller_agent_details,
|
|
79
84
|
caller_details,
|
|
85
|
+
parent_context,
|
|
80
86
|
start_time,
|
|
81
87
|
end_time,
|
|
82
88
|
span_kind,
|
|
@@ -89,6 +95,7 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
89
95
|
request: Request | None = None,
|
|
90
96
|
caller_agent_details: AgentDetails | None = None,
|
|
91
97
|
caller_details: CallerDetails | None = None,
|
|
98
|
+
parent_context: Context | None = None,
|
|
92
99
|
start_time: datetime | None = None,
|
|
93
100
|
end_time: datetime | None = None,
|
|
94
101
|
span_kind: SpanKind | None = None,
|
|
@@ -101,6 +108,9 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
101
108
|
request: Optional request details for additional context
|
|
102
109
|
caller_agent_details: Optional details of the caller agent
|
|
103
110
|
caller_details: Optional details of the non-agentic caller
|
|
111
|
+
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
112
|
+
upstream operation. Use ``extract_context_from_headers()`` to convert a
|
|
113
|
+
Context from HTTP headers containing W3C traceparent.
|
|
104
114
|
start_time: Optional explicit start time as a datetime object.
|
|
105
115
|
end_time: Optional explicit end time as a datetime object.
|
|
106
116
|
span_kind: Optional span kind override. Defaults to ``SpanKind.CLIENT``.
|
|
@@ -118,6 +128,7 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
118
128
|
activity_name=activity_name,
|
|
119
129
|
agent_details=invoke_agent_details.details,
|
|
120
130
|
tenant_details=tenant_details,
|
|
131
|
+
parent_context=parent_context,
|
|
121
132
|
start_time=start_time,
|
|
122
133
|
end_time=end_time,
|
|
123
134
|
)
|
|
@@ -138,9 +149,9 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
138
149
|
|
|
139
150
|
# Set request metadata if provided
|
|
140
151
|
if request:
|
|
141
|
-
if request.
|
|
142
|
-
self.set_tag_maybe(CHANNEL_NAME_KEY, request.
|
|
143
|
-
self.set_tag_maybe(CHANNEL_LINK_KEY, request.
|
|
152
|
+
if request.channel:
|
|
153
|
+
self.set_tag_maybe(CHANNEL_NAME_KEY, request.channel.name)
|
|
154
|
+
self.set_tag_maybe(CHANNEL_LINK_KEY, request.channel.link)
|
|
144
155
|
|
|
145
156
|
self.set_tag_maybe(
|
|
146
157
|
GEN_AI_EXECUTION_TYPE_KEY,
|
|
@@ -150,9 +161,9 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
150
161
|
|
|
151
162
|
# Set caller details tags
|
|
152
163
|
if caller_details:
|
|
153
|
-
self.set_tag_maybe(
|
|
154
|
-
self.set_tag_maybe(
|
|
155
|
-
self.set_tag_maybe(
|
|
164
|
+
self.set_tag_maybe(USER_ID_KEY, caller_details.caller_id)
|
|
165
|
+
self.set_tag_maybe(USER_EMAIL_KEY, caller_details.caller_upn)
|
|
166
|
+
self.set_tag_maybe(USER_NAME_KEY, caller_details.caller_name)
|
|
156
167
|
# Validate and set caller client IP
|
|
157
168
|
self.set_tag_maybe(
|
|
158
169
|
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
@@ -167,7 +178,7 @@ class InvokeAgentScope(OpenTelemetryScope):
|
|
|
167
178
|
GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY, caller_agent_details.agent_blueprint_id
|
|
168
179
|
)
|
|
169
180
|
self.set_tag_maybe(GEN_AI_CALLER_AGENT_USER_ID_KEY, caller_agent_details.agent_auid)
|
|
170
|
-
self.set_tag_maybe(
|
|
181
|
+
self.set_tag_maybe(GEN_AI_CALLER_AGENT_EMAIL_KEY, caller_agent_details.agent_upn)
|
|
171
182
|
self.set_tag_maybe(
|
|
172
183
|
GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY, caller_agent_details.agent_platform_id
|
|
173
184
|
)
|
|
@@ -14,21 +14,21 @@ from ..constants import (
|
|
|
14
14
|
GEN_AI_AGENT_AUID_KEY,
|
|
15
15
|
GEN_AI_AGENT_BLUEPRINT_ID_KEY,
|
|
16
16
|
GEN_AI_AGENT_DESCRIPTION_KEY,
|
|
17
|
+
GEN_AI_AGENT_EMAIL_KEY,
|
|
17
18
|
GEN_AI_AGENT_ID_KEY,
|
|
18
19
|
GEN_AI_AGENT_NAME_KEY,
|
|
19
|
-
GEN_AI_AGENT_UPN_KEY,
|
|
20
20
|
GEN_AI_CALLER_CLIENT_IP_KEY,
|
|
21
|
-
GEN_AI_CALLER_ID_KEY,
|
|
22
|
-
GEN_AI_CALLER_NAME_KEY,
|
|
23
|
-
GEN_AI_CALLER_UPN_KEY,
|
|
24
21
|
GEN_AI_CONVERSATION_ID_KEY,
|
|
25
22
|
GEN_AI_CONVERSATION_ITEM_LINK_KEY,
|
|
26
23
|
SERVICE_NAME_KEY,
|
|
27
24
|
SESSION_DESCRIPTION_KEY,
|
|
28
25
|
SESSION_ID_KEY,
|
|
29
26
|
TENANT_ID_KEY,
|
|
27
|
+
USER_EMAIL_KEY,
|
|
28
|
+
USER_ID_KEY,
|
|
29
|
+
USER_NAME_KEY,
|
|
30
30
|
)
|
|
31
|
-
from ..utils import
|
|
31
|
+
from ..utils import validate_and_normalize_ip
|
|
32
32
|
|
|
33
33
|
logger = logging.getLogger(__name__)
|
|
34
34
|
|
|
@@ -115,7 +115,7 @@ class BaggageBuilder:
|
|
|
115
115
|
Returns:
|
|
116
116
|
Self for method chaining
|
|
117
117
|
"""
|
|
118
|
-
self._set(
|
|
118
|
+
self._set(GEN_AI_AGENT_EMAIL_KEY, value)
|
|
119
119
|
return self
|
|
120
120
|
|
|
121
121
|
def agent_blueprint_id(self, value: str | None) -> "BaggageBuilder":
|
|
@@ -139,7 +139,7 @@ class BaggageBuilder:
|
|
|
139
139
|
Returns:
|
|
140
140
|
Self for method chaining
|
|
141
141
|
"""
|
|
142
|
-
self._set(
|
|
142
|
+
self._set(USER_ID_KEY, value)
|
|
143
143
|
return self
|
|
144
144
|
|
|
145
145
|
def agent_name(self, value: str | None) -> "BaggageBuilder":
|
|
@@ -154,12 +154,12 @@ class BaggageBuilder:
|
|
|
154
154
|
|
|
155
155
|
def caller_name(self, value: str | None) -> "BaggageBuilder":
|
|
156
156
|
"""Set the caller name baggage value."""
|
|
157
|
-
self._set(
|
|
157
|
+
self._set(USER_NAME_KEY, value)
|
|
158
158
|
return self
|
|
159
159
|
|
|
160
160
|
def caller_upn(self, value: str | None) -> "BaggageBuilder":
|
|
161
161
|
"""Set the caller UPN baggage value."""
|
|
162
|
-
self._set(
|
|
162
|
+
self._set(USER_EMAIL_KEY, value)
|
|
163
163
|
return self
|
|
164
164
|
|
|
165
165
|
def caller_client_ip(self, value: str | None) -> "BaggageBuilder":
|
|
@@ -177,16 +177,6 @@ class BaggageBuilder:
|
|
|
177
177
|
self._set(GEN_AI_CONVERSATION_ITEM_LINK_KEY, value)
|
|
178
178
|
return self
|
|
179
179
|
|
|
180
|
-
@deprecated("Use channel_name() instead")
|
|
181
|
-
def source_metadata_name(self, value: str | None) -> "BaggageBuilder":
|
|
182
|
-
"""Set the execution source metadata name (e.g., channel name)."""
|
|
183
|
-
return self.channel_name(value)
|
|
184
|
-
|
|
185
|
-
@deprecated("Use channel_links() instead")
|
|
186
|
-
def source_metadata_description(self, value: str | None) -> "BaggageBuilder":
|
|
187
|
-
"""Set the execution source metadata description (e.g., channel description)."""
|
|
188
|
-
return self.channel_links(value)
|
|
189
|
-
|
|
190
180
|
def session_id(self, value: str | None) -> "BaggageBuilder":
|
|
191
181
|
"""Set the session ID baggage value."""
|
|
192
182
|
self._set(SESSION_ID_KEY, value)
|
|
@@ -203,7 +193,7 @@ class BaggageBuilder:
|
|
|
203
193
|
return self
|
|
204
194
|
|
|
205
195
|
def channel_links(self, value: str | None) -> "BaggageBuilder":
|
|
206
|
-
"""Sets the channel link baggage value.
|
|
196
|
+
"""Sets the channel link baggage value."""
|
|
207
197
|
self._set(CHANNEL_LINK_KEY, value)
|
|
208
198
|
return self
|
|
209
199
|
|
|
@@ -10,6 +10,8 @@ from threading import Lock
|
|
|
10
10
|
from typing import TYPE_CHECKING, Any
|
|
11
11
|
|
|
12
12
|
from opentelemetry import context, trace
|
|
13
|
+
from opentelemetry.context import Context
|
|
14
|
+
from opentelemetry.propagate import inject
|
|
13
15
|
from opentelemetry.trace import (
|
|
14
16
|
Span,
|
|
15
17
|
SpanKind,
|
|
@@ -26,10 +28,10 @@ from .constants import (
|
|
|
26
28
|
GEN_AI_AGENT_AUID_KEY,
|
|
27
29
|
GEN_AI_AGENT_BLUEPRINT_ID_KEY,
|
|
28
30
|
GEN_AI_AGENT_DESCRIPTION_KEY,
|
|
31
|
+
GEN_AI_AGENT_EMAIL_KEY,
|
|
29
32
|
GEN_AI_AGENT_ID_KEY,
|
|
30
33
|
GEN_AI_AGENT_NAME_KEY,
|
|
31
34
|
GEN_AI_AGENT_PLATFORM_ID_KEY,
|
|
32
|
-
GEN_AI_AGENT_UPN_KEY,
|
|
33
35
|
GEN_AI_CONVERSATION_ID_KEY,
|
|
34
36
|
GEN_AI_ICON_URI_KEY,
|
|
35
37
|
GEN_AI_OPERATION_NAME_KEY,
|
|
@@ -43,7 +45,7 @@ from .constants import (
|
|
|
43
45
|
TELEMETRY_SDK_VERSION_KEY,
|
|
44
46
|
TENANT_ID_KEY,
|
|
45
47
|
)
|
|
46
|
-
from .utils import get_sdk_version
|
|
48
|
+
from .utils import get_sdk_version
|
|
47
49
|
|
|
48
50
|
if TYPE_CHECKING:
|
|
49
51
|
from .agent_details import AgentDetails
|
|
@@ -97,7 +99,7 @@ class OpenTelemetryScope:
|
|
|
97
99
|
activity_name: str,
|
|
98
100
|
agent_details: "AgentDetails | None" = None,
|
|
99
101
|
tenant_details: "TenantDetails | None" = None,
|
|
100
|
-
|
|
102
|
+
parent_context: Context | None = None,
|
|
101
103
|
start_time: datetime | None = None,
|
|
102
104
|
end_time: datetime | None = None,
|
|
103
105
|
):
|
|
@@ -111,8 +113,9 @@ class OpenTelemetryScope:
|
|
|
111
113
|
activity_name: The name of the activity for display purposes
|
|
112
114
|
agent_details: Optional agent details
|
|
113
115
|
tenant_details: Optional tenant details
|
|
114
|
-
|
|
115
|
-
operation
|
|
116
|
+
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
117
|
+
upstream operation. Use ``extract_context_from_headers()`` to extract a
|
|
118
|
+
Context from HTTP headers containing W3C traceparent.
|
|
116
119
|
start_time: Optional explicit start time as a datetime object.
|
|
117
120
|
Useful when recording an operation after it has already completed.
|
|
118
121
|
end_time: Optional explicit end time as a datetime object.
|
|
@@ -146,9 +149,8 @@ class OpenTelemetryScope:
|
|
|
146
149
|
activity_kind = SpanKind.CONSUMER
|
|
147
150
|
|
|
148
151
|
# Get context for parent relationship
|
|
149
|
-
# If
|
|
152
|
+
# If parent_context is provided, use it directly
|
|
150
153
|
# Otherwise, use the current context
|
|
151
|
-
parent_context = parse_parent_id_to_context(parent_id)
|
|
152
154
|
span_context = parent_context if parent_context else context.get_current()
|
|
153
155
|
|
|
154
156
|
# Convert custom start time to OTel-compatible format (nanoseconds since epoch)
|
|
@@ -185,7 +187,7 @@ class OpenTelemetryScope:
|
|
|
185
187
|
GEN_AI_AGENT_DESCRIPTION_KEY, agent_details.agent_description
|
|
186
188
|
)
|
|
187
189
|
self.set_tag_maybe(GEN_AI_AGENT_AUID_KEY, agent_details.agent_auid)
|
|
188
|
-
self.set_tag_maybe(
|
|
190
|
+
self.set_tag_maybe(GEN_AI_AGENT_EMAIL_KEY, agent_details.agent_upn)
|
|
189
191
|
self.set_tag_maybe(
|
|
190
192
|
GEN_AI_AGENT_BLUEPRINT_ID_KEY, agent_details.agent_blueprint_id
|
|
191
193
|
)
|
|
@@ -286,6 +288,49 @@ class OpenTelemetryScope:
|
|
|
286
288
|
else:
|
|
287
289
|
self._span.end()
|
|
288
290
|
|
|
291
|
+
def get_context(self) -> Context | None:
|
|
292
|
+
"""Get the OpenTelemetry context for this scope's span.
|
|
293
|
+
|
|
294
|
+
This method returns a Context object containing this scope's span,
|
|
295
|
+
which can be used to propagate trace context to child operations
|
|
296
|
+
or downstream services.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
A Context containing this scope's span, or None if telemetry
|
|
300
|
+
is disabled or no span exists.
|
|
301
|
+
"""
|
|
302
|
+
if self._span and self._is_telemetry_enabled():
|
|
303
|
+
return set_span_in_context(self._span)
|
|
304
|
+
return None
|
|
305
|
+
|
|
306
|
+
def inject_context_to_headers(self) -> dict[str, str]:
|
|
307
|
+
"""Inject this span's trace context into W3C HTTP headers.
|
|
308
|
+
|
|
309
|
+
Returns a dictionary of headers containing ``traceparent`` and
|
|
310
|
+
optionally ``tracestate`` that can be forwarded to downstream services
|
|
311
|
+
or stored for later context propagation.
|
|
312
|
+
|
|
313
|
+
Example usage:
|
|
314
|
+
|
|
315
|
+
.. code-block:: python
|
|
316
|
+
|
|
317
|
+
scope = OpenTelemetryScope(...)
|
|
318
|
+
headers = scope.inject_context_to_headers()
|
|
319
|
+
# Add headers to outgoing HTTP request
|
|
320
|
+
requests.get("https://downstream-service/api", headers=headers)
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
A dictionary containing W3C trace context headers. Returns an
|
|
324
|
+
empty dictionary if telemetry is disabled or no span exists.
|
|
325
|
+
"""
|
|
326
|
+
headers: dict[str, str] = {}
|
|
327
|
+
if self._span and self._is_telemetry_enabled():
|
|
328
|
+
# Create a context with the current span
|
|
329
|
+
ctx = set_span_in_context(self._span)
|
|
330
|
+
# Use the global propagator to inject trace context into headers
|
|
331
|
+
inject(headers, context=ctx)
|
|
332
|
+
return headers
|
|
333
|
+
|
|
289
334
|
def __enter__(self):
|
|
290
335
|
"""Enter the context manager and make span active."""
|
|
291
336
|
if self._span and self._is_telemetry_enabled():
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
|
|
8
8
|
from .execution_type import ExecutionType
|
|
9
|
-
from .
|
|
9
|
+
from .channel import Channel
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@dataclass
|
|
@@ -16,4 +16,4 @@ class Request:
|
|
|
16
16
|
content: str
|
|
17
17
|
execution_type: ExecutionType
|
|
18
18
|
session_id: str | None = None
|
|
19
|
-
|
|
19
|
+
channel: Channel | None = None
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
|
|
6
|
+
from opentelemetry.context import Context
|
|
7
|
+
|
|
6
8
|
from ..agent_details import AgentDetails
|
|
7
9
|
from ..constants import GEN_AI_OUTPUT_MESSAGES_KEY
|
|
8
10
|
from ..models.response import Response
|
|
@@ -23,7 +25,7 @@ class OutputScope(OpenTelemetryScope):
|
|
|
23
25
|
agent_details: AgentDetails,
|
|
24
26
|
tenant_details: TenantDetails,
|
|
25
27
|
response: Response,
|
|
26
|
-
|
|
28
|
+
parent_context: Context | None = None,
|
|
27
29
|
start_time: datetime | None = None,
|
|
28
30
|
end_time: datetime | None = None,
|
|
29
31
|
) -> "OutputScope":
|
|
@@ -33,22 +35,25 @@ class OutputScope(OpenTelemetryScope):
|
|
|
33
35
|
agent_details: The details of the agent
|
|
34
36
|
tenant_details: The details of the tenant
|
|
35
37
|
response: The response details from the agent
|
|
36
|
-
|
|
37
|
-
operation
|
|
38
|
+
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
39
|
+
upstream operation. Use ``extract_context_from_headers()`` to convert a
|
|
40
|
+
Context from HTTP headers containing W3C traceparent.
|
|
38
41
|
start_time: Optional explicit start time as a datetime object.
|
|
39
42
|
end_time: Optional explicit end time as a datetime object.
|
|
40
43
|
|
|
41
44
|
Returns:
|
|
42
45
|
A new OutputScope instance
|
|
43
46
|
"""
|
|
44
|
-
return OutputScope(
|
|
47
|
+
return OutputScope(
|
|
48
|
+
agent_details, tenant_details, response, parent_context, start_time, end_time
|
|
49
|
+
)
|
|
45
50
|
|
|
46
51
|
def __init__(
|
|
47
52
|
self,
|
|
48
53
|
agent_details: AgentDetails,
|
|
49
54
|
tenant_details: TenantDetails,
|
|
50
55
|
response: Response,
|
|
51
|
-
|
|
56
|
+
parent_context: Context | None = None,
|
|
52
57
|
start_time: datetime | None = None,
|
|
53
58
|
end_time: datetime | None = None,
|
|
54
59
|
):
|
|
@@ -58,8 +63,9 @@ class OutputScope(OpenTelemetryScope):
|
|
|
58
63
|
agent_details: The details of the agent
|
|
59
64
|
tenant_details: The details of the tenant
|
|
60
65
|
response: The response details from the agent
|
|
61
|
-
|
|
62
|
-
operation
|
|
66
|
+
parent_context: Optional OpenTelemetry Context used to link this span to an
|
|
67
|
+
upstream operation. Use ``extract_context_from_headers()`` to convert a
|
|
68
|
+
Context from HTTP headers containing W3C traceparent.
|
|
63
69
|
start_time: Optional explicit start time as a datetime object.
|
|
64
70
|
end_time: Optional explicit end time as a datetime object.
|
|
65
71
|
"""
|
|
@@ -69,7 +75,7 @@ class OutputScope(OpenTelemetryScope):
|
|
|
69
75
|
activity_name=(f"{OUTPUT_OPERATION_NAME} {agent_details.agent_id}"),
|
|
70
76
|
agent_details=agent_details,
|
|
71
77
|
tenant_details=tenant_details,
|
|
72
|
-
|
|
78
|
+
parent_context=parent_context,
|
|
73
79
|
start_time=start_time,
|
|
74
80
|
end_time=end_time,
|
|
75
81
|
)
|
|
@@ -14,7 +14,7 @@ COMMON_ATTRIBUTES = [
|
|
|
14
14
|
consts.GEN_AI_AGENT_ID_KEY, # gen_ai.agent.id
|
|
15
15
|
consts.GEN_AI_AGENT_NAME_KEY, # gen_ai.agent.name
|
|
16
16
|
consts.GEN_AI_AGENT_DESCRIPTION_KEY, # gen_ai.agent.description
|
|
17
|
-
consts.
|
|
17
|
+
consts.GEN_AI_AGENT_EMAIL_KEY, # microsoft.agent.user.email
|
|
18
18
|
consts.GEN_AI_AGENT_BLUEPRINT_ID_KEY, # microsoft.a365.agent.blueprint.id
|
|
19
19
|
consts.GEN_AI_AGENT_AUID_KEY, # microsoft.agent.user.id
|
|
20
20
|
consts.GEN_AI_AGENT_PLATFORM_ID_KEY, # microsoft.a365.agent.platform.id
|
|
@@ -29,14 +29,14 @@ COMMON_ATTRIBUTES = [
|
|
|
29
29
|
# Invoke Agent–specific attributes
|
|
30
30
|
INVOKE_AGENT_ATTRIBUTES = [
|
|
31
31
|
# Caller / Invoker attributes
|
|
32
|
-
consts.
|
|
33
|
-
consts.
|
|
34
|
-
consts.
|
|
32
|
+
consts.USER_ID_KEY, # user.id
|
|
33
|
+
consts.USER_NAME_KEY, # user.name
|
|
34
|
+
consts.USER_EMAIL_KEY, # user.email
|
|
35
35
|
# Caller Agent (A2A) attributes
|
|
36
36
|
consts.GEN_AI_CALLER_AGENT_ID_KEY, # microsoft.a365.caller.agent.id
|
|
37
37
|
consts.GEN_AI_CALLER_AGENT_NAME_KEY, # microsoft.a365.caller.agent.name
|
|
38
38
|
consts.GEN_AI_CALLER_AGENT_USER_ID_KEY, # microsoft.a365.caller.agent.user.id
|
|
39
|
-
consts.
|
|
39
|
+
consts.GEN_AI_CALLER_AGENT_EMAIL_KEY, # microsoft.a365.caller.agent.user.email
|
|
40
40
|
consts.GEN_AI_CALLER_AGENT_APPLICATION_ID_KEY, # microsoft.a365.caller.agent.blueprint.id
|
|
41
41
|
consts.GEN_AI_CALLER_AGENT_PLATFORM_ID_KEY, # microsoft.a365.caller.agent.platform.id
|
|
42
42
|
consts.GEN_AI_EXECUTION_TYPE_KEY, # gen_ai.execution.type
|
|
@@ -15,11 +15,12 @@ from threading import RLock
|
|
|
15
15
|
from typing import Any, Generic, TypeVar, cast
|
|
16
16
|
|
|
17
17
|
from opentelemetry import context
|
|
18
|
+
from opentelemetry.propagate import extract
|
|
18
19
|
from opentelemetry.semconv.attributes.exception_attributes import (
|
|
19
20
|
EXCEPTION_MESSAGE,
|
|
20
21
|
EXCEPTION_STACKTRACE,
|
|
21
22
|
)
|
|
22
|
-
from opentelemetry.trace import
|
|
23
|
+
from opentelemetry.trace import Span
|
|
23
24
|
from opentelemetry.util.types import AttributeValue
|
|
24
25
|
from wrapt import ObjectProxy
|
|
25
26
|
|
|
@@ -29,126 +30,58 @@ logger = logging.getLogger(__name__)
|
|
|
29
30
|
logger.addHandler(logging.NullHandler())
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
W3C_TRACE_ID_LENGTH = 32 # 32 hex chars = 128 bits
|
|
35
|
-
W3C_SPAN_ID_LENGTH = 16 # 16 hex chars = 64 bits
|
|
33
|
+
def extract_context_from_headers(headers: dict[str, str]) -> context.Context:
|
|
34
|
+
"""Extract an OpenTelemetry Context from W3C trace HTTP headers.
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
Parses ``traceparent`` (and optionally ``tracestate``) headers and returns
|
|
37
|
+
an OpenTelemetry Context that can be passed as ``parent_context`` to any
|
|
38
|
+
scope's ``start()`` method.
|
|
40
39
|
|
|
41
40
|
Args:
|
|
42
|
-
|
|
41
|
+
headers: Dictionary of HTTP headers containing trace context.
|
|
42
|
+
Expected keys include ``traceparent`` and optionally ``tracestate``.
|
|
43
43
|
|
|
44
44
|
Returns:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return version == W3C_TRACE_CONTEXT_VERSION
|
|
45
|
+
An OpenTelemetry Context containing the extracted trace information.
|
|
46
|
+
If no valid trace context is found, returns an empty context.
|
|
48
47
|
|
|
48
|
+
Example::
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
"""Check if a string contains only valid hexadecimal characters.
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
hex_string: The string to validate
|
|
50
|
+
.. code-block:: python
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
headers = {
|
|
53
|
+
"traceparent": "00-1234567890abcdef1234567890abcdef-abcdefabcdef1234-01"
|
|
54
|
+
}
|
|
55
|
+
parent_context = extract_context_from_headers(headers)
|
|
56
|
+
with InferenceScope.start(
|
|
57
|
+
details, agent, tenant, parent_context=parent_context
|
|
58
|
+
):
|
|
59
|
+
pass
|
|
58
60
|
"""
|
|
59
|
-
return
|
|
61
|
+
return extract(headers)
|
|
60
62
|
|
|
61
63
|
|
|
62
|
-
def
|
|
63
|
-
"""
|
|
64
|
+
def get_traceparent(headers: dict[str, str]) -> str | None:
|
|
65
|
+
"""Return the W3C ``traceparent`` value from a headers dictionary.
|
|
64
66
|
|
|
65
67
|
Args:
|
|
66
|
-
|
|
68
|
+
headers: Dictionary of HTTP headers, typically obtained from
|
|
69
|
+
:meth:`OpenTelemetryScope.inject_context_to_headers`.
|
|
67
70
|
|
|
68
71
|
Returns:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
The traceparent string (e.g.
|
|
73
|
+
``"00-<trace-id>-<span-id>-<flags>"``), or ``None`` if the
|
|
74
|
+
key is not present.
|
|
72
75
|
|
|
76
|
+
Example::
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
"""Validate W3C Trace Context span_id format.
|
|
76
|
-
|
|
77
|
-
Args:
|
|
78
|
-
span_id_hex: The span_id hex string to validate (should be 16 hex chars)
|
|
78
|
+
.. code-block:: python
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
# Extract traceparent from incoming HTTP request headers
|
|
81
|
+
traceparent = get_traceparent(request.headers)
|
|
82
|
+
turn_context.turn_state[A365_PARENT_TRACEPARENT_KEY] = traceparent
|
|
82
83
|
"""
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def parse_parent_id_to_context(parent_id: str | None) -> context.Context | None:
|
|
87
|
-
"""Parse a W3C trace context parent ID and return a context with the parent span.
|
|
88
|
-
|
|
89
|
-
The parent_id format is expected to be W3C Trace Context format:
|
|
90
|
-
"00-{trace_id}-{span_id}-{trace_flags}"
|
|
91
|
-
Example: "00-1234567890abcdef1234567890abcdef-abcdefabcdef1234-01"
|
|
92
|
-
|
|
93
|
-
Args:
|
|
94
|
-
parent_id: The W3C Trace Context format parent ID string
|
|
95
|
-
|
|
96
|
-
Returns:
|
|
97
|
-
A context containing the parent span, or None if parent_id is invalid
|
|
98
|
-
"""
|
|
99
|
-
if not parent_id:
|
|
100
|
-
return None
|
|
101
|
-
|
|
102
|
-
try:
|
|
103
|
-
# W3C Trace Context format: "00-{trace_id}-{span_id}-{trace_flags}"
|
|
104
|
-
parts = parent_id.split("-")
|
|
105
|
-
if len(parts) != 4:
|
|
106
|
-
logger.warning(f"Invalid parent_id format (expected 4 parts): {parent_id}")
|
|
107
|
-
return None
|
|
108
|
-
|
|
109
|
-
version, trace_id_hex, span_id_hex, trace_flags_hex = parts
|
|
110
|
-
|
|
111
|
-
# Validate W3C Trace Context version
|
|
112
|
-
if not validate_w3c_trace_context_version(version):
|
|
113
|
-
logger.warning(f"Unsupported W3C Trace Context version: {version}")
|
|
114
|
-
return None
|
|
115
|
-
|
|
116
|
-
# Validate trace_id (must be 32 hex chars)
|
|
117
|
-
if not validate_trace_id(trace_id_hex):
|
|
118
|
-
logger.warning(
|
|
119
|
-
f"Invalid trace_id (expected {W3C_TRACE_ID_LENGTH} hex chars): '{trace_id_hex}'"
|
|
120
|
-
)
|
|
121
|
-
return None
|
|
122
|
-
|
|
123
|
-
# Validate span_id (must be 16 hex chars)
|
|
124
|
-
if not validate_span_id(span_id_hex):
|
|
125
|
-
logger.warning(
|
|
126
|
-
f"Invalid span_id (expected {W3C_SPAN_ID_LENGTH} hex chars): '{span_id_hex}'"
|
|
127
|
-
)
|
|
128
|
-
return None
|
|
129
|
-
|
|
130
|
-
# Parse the hex values
|
|
131
|
-
trace_id = int(trace_id_hex, 16)
|
|
132
|
-
span_id = int(span_id_hex, 16)
|
|
133
|
-
trace_flags = TraceFlags(int(trace_flags_hex, 16))
|
|
134
|
-
|
|
135
|
-
# Create a SpanContext from the parsed values
|
|
136
|
-
parent_span_context = SpanContext(
|
|
137
|
-
trace_id=trace_id,
|
|
138
|
-
span_id=span_id,
|
|
139
|
-
is_remote=True,
|
|
140
|
-
trace_flags=trace_flags,
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
# Create a NonRecordingSpan with the parent context
|
|
144
|
-
parent_span = NonRecordingSpan(parent_span_context)
|
|
145
|
-
|
|
146
|
-
# Create a context with the parent span
|
|
147
|
-
return set_span_in_context(parent_span)
|
|
148
|
-
|
|
149
|
-
except (ValueError, IndexError) as e:
|
|
150
|
-
logger.warning(f"Failed to parse parent_id '{parent_id}': {e}")
|
|
151
|
-
return None
|
|
84
|
+
return headers.get("traceparent")
|
|
152
85
|
|
|
153
86
|
|
|
154
87
|
def safe_json_dumps(obj: Any, **kwargs: Any) -> str:
|
|
@@ -3,6 +3,7 @@ pyproject.toml
|
|
|
3
3
|
setup.py
|
|
4
4
|
microsoft_agents_a365/observability/core/__init__.py
|
|
5
5
|
microsoft_agents_a365/observability/core/agent_details.py
|
|
6
|
+
microsoft_agents_a365/observability/core/channel.py
|
|
6
7
|
microsoft_agents_a365/observability/core/config.py
|
|
7
8
|
microsoft_agents_a365/observability/core/constants.py
|
|
8
9
|
microsoft_agents_a365/observability/core/execute_tool_scope.py
|
|
@@ -14,7 +15,6 @@ microsoft_agents_a365/observability/core/invoke_agent_details.py
|
|
|
14
15
|
microsoft_agents_a365/observability/core/invoke_agent_scope.py
|
|
15
16
|
microsoft_agents_a365/observability/core/opentelemetry_scope.py
|
|
16
17
|
microsoft_agents_a365/observability/core/request.py
|
|
17
|
-
microsoft_agents_a365/observability/core/source_metadata.py
|
|
18
18
|
microsoft_agents_a365/observability/core/tenant_details.py
|
|
19
19
|
microsoft_agents_a365/observability/core/tool_call_details.py
|
|
20
20
|
microsoft_agents_a365/observability/core/tool_type.py
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Copyright (c) Microsoft Corporation.
|
|
2
|
-
# Licensed under the MIT License.
|
|
3
|
-
|
|
4
|
-
# Source metadata class.
|
|
5
|
-
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@dataclass
|
|
10
|
-
class SourceMetadata:
|
|
11
|
-
"""Source metadata for agent execution context."""
|
|
12
|
-
|
|
13
|
-
id: str | None = None
|
|
14
|
-
name: str | None = None
|
|
15
|
-
icon_uri: str | None = None
|
|
16
|
-
description: str | None = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|