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.
Files changed (48) hide show
  1. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/PKG-INFO +1 -1
  2. {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
  3. microsoft_agents_a365_observability_core-0.2.1.dev44/microsoft_agents_a365/observability/core/channel.py +14 -0
  4. {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
  5. {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
  6. {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
  7. {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
  8. {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
  9. {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
  10. {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
  11. {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
  12. {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
  13. {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
  14. {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
  15. {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
  16. microsoft_agents_a365_observability_core-0.2.1.dev42/microsoft_agents_a365/observability/core/source_metadata.py +0 -16
  17. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/README.md +0 -0
  18. {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
  19. {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
  20. {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
  21. {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
  22. {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
  23. {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
  24. {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
  25. {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
  26. {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
  27. {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
  28. {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
  29. {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
  30. {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
  31. {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
  32. {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
  33. {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
  34. {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
  35. {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
  36. {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
  37. {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
  38. {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
  39. {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
  40. {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
  41. {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
  42. {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
  43. {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
  44. {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
  45. {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
  46. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/pyproject.toml +0 -0
  47. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/setup.cfg +0 -0
  48. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev44}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-a365-observability-core
3
- Version: 0.2.1.dev42
3
+ Version: 0.2.1.dev44
4
4
  Summary: Telemetry, tracing, and monitoring components for AI agents
5
5
  Author-email: Microsoft <support@microsoft.com>
6
6
  License: MIT
@@ -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 .source_metadata import SourceMetadata
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
- "SourceMetadata",
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
- # Agent user (user tied to agent instance during creation) or caller dimensions
64
- GEN_AI_CALLER_ID_KEY = "microsoft.caller.id"
65
- GEN_AI_CALLER_NAME_KEY = "microsoft.caller.name"
66
- GEN_AI_CALLER_UPN_KEY = "microsoft.caller.upn"
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
- GEN_AI_CALLER_AGENT_UPN_KEY = "microsoft.a365.caller.agent.user.upn"
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
- GEN_AI_AGENT_UPN_KEY = "microsoft.agent.user.upn"
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
- parent_id: str | None = None,
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
- parent_id: Optional parent Activity ID used to link this span to an upstream
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
- parent_id,
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
- parent_id: str | None = None,
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
- parent_id: Optional parent Activity ID used to link this span to an upstream
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
- parent_id=parent_id,
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.source_metadata:
132
- self.set_tag_maybe(CHANNEL_NAME_KEY, request.source_metadata.name)
133
- self.set_tag_maybe(CHANNEL_LINK_KEY, request.source_metadata.description)
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
- parent_id: str | None = None,
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
- parent_id: Optional parent Activity ID used to link this span to an upstream
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, parent_id, start_time, end_time
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
- parent_id: str | None = None,
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
- parent_id: Optional parent Activity ID used to link this span to an upstream
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
- parent_id=parent_id,
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.source_metadata:
124
- self.set_tag_maybe(CHANNEL_NAME_KEY, request.source_metadata.name)
125
- self.set_tag_maybe(CHANNEL_LINK_KEY, request.source_metadata.description)
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.source_metadata:
142
- self.set_tag_maybe(CHANNEL_NAME_KEY, request.source_metadata.name)
143
- self.set_tag_maybe(CHANNEL_LINK_KEY, request.source_metadata.description)
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(GEN_AI_CALLER_ID_KEY, caller_details.caller_id)
154
- self.set_tag_maybe(GEN_AI_CALLER_UPN_KEY, caller_details.caller_upn)
155
- self.set_tag_maybe(GEN_AI_CALLER_NAME_KEY, caller_details.caller_name)
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(GEN_AI_CALLER_AGENT_UPN_KEY, caller_agent_details.agent_upn)
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 deprecated, validate_and_normalize_ip
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(GEN_AI_AGENT_UPN_KEY, value)
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(GEN_AI_CALLER_ID_KEY, value)
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(GEN_AI_CALLER_NAME_KEY, value)
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(GEN_AI_CALLER_UPN_KEY, value)
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. (e.g., channel links or description)."""
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, parse_parent_id_to_context
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
- parent_id: str | None = None,
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
- parent_id: Optional parent Activity ID used to link this span to an upstream
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 parent_id is provided, parse it and use it as the parent context
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(GEN_AI_AGENT_UPN_KEY, agent_details.agent_upn)
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 .source_metadata import SourceMetadata
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
- source_metadata: SourceMetadata | None = None
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
- parent_id: str | None = None,
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
- parent_id: Optional parent Activity ID used to link this span to an upstream
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(agent_details, tenant_details, response, parent_id, start_time, end_time)
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
- parent_id: str | None = None,
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
- parent_id: Optional parent Activity ID used to link this span to an upstream
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
- parent_id=parent_id,
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.GEN_AI_AGENT_UPN_KEY, # microsoft.agent.user.upn
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.GEN_AI_CALLER_ID_KEY, # microsoft.caller.id
33
- consts.GEN_AI_CALLER_NAME_KEY, # microsoft.caller.name
34
- consts.GEN_AI_CALLER_UPN_KEY, # microsoft.caller.upn
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.GEN_AI_CALLER_AGENT_UPN_KEY, # microsoft.a365.caller.agent.user.upn
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 NonRecordingSpan, Span, SpanContext, TraceFlags, set_span_in_context
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
- # W3C Trace Context constants
33
- W3C_TRACE_CONTEXT_VERSION = "00"
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
- def validate_w3c_trace_context_version(version: str) -> bool:
39
- """Validate W3C Trace Context version.
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
- version: The version string to validate
41
+ headers: Dictionary of HTTP headers containing trace context.
42
+ Expected keys include ``traceparent`` and optionally ``tracestate``.
43
43
 
44
44
  Returns:
45
- True if valid, False otherwise
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
- def _is_valid_hex(hex_string: str) -> bool:
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
- Returns:
57
- True if all characters are valid hexadecimal (0-9, a-f, A-F), False otherwise
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 all(c in "0123456789abcdefABCDEF" for c in hex_string)
61
+ return extract(headers)
60
62
 
61
63
 
62
- def validate_trace_id(trace_id_hex: str) -> bool:
63
- """Validate W3C Trace Context trace_id format.
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
- trace_id_hex: The trace_id hex string to validate (should be 32 hex chars)
68
+ headers: Dictionary of HTTP headers, typically obtained from
69
+ :meth:`OpenTelemetryScope.inject_context_to_headers`.
67
70
 
68
71
  Returns:
69
- True if valid (32 hex chars), False otherwise
70
- """
71
- return len(trace_id_hex) == W3C_TRACE_ID_LENGTH and _is_valid_hex(trace_id_hex)
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
- def validate_span_id(span_id_hex: str) -> bool:
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
- Returns:
81
- True if valid (16 hex chars), False otherwise
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 len(span_id_hex) == W3C_SPAN_ID_LENGTH and _is_valid_hex(span_id_hex)
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-a365-observability-core
3
- Version: 0.2.1.dev42
3
+ Version: 0.2.1.dev44
4
4
  Summary: Telemetry, tracing, and monitoring components for AI agents
5
5
  Author-email: Microsoft <support@microsoft.com>
6
6
  License: MIT
@@ -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