Skip to content

Commit 74fb2fe

Browse files
singankitCopilotyulin-liYulin Li
authored
Enable A365 tracing and fix W3C baggage propagation in agentserver (#46754)
* Enable A365 tracing in agentserver-core when hosted Conditionally enable A365 observability export via microsoft-opentelemetry distro when both FOUNDRY_HOSTING_ENVIRONMENT and FOUNDRY_AGENT365_TRACING_ENABLED env vars are set. Uses S2S endpoint for token resolution in hosted environments. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add agent_id, blueprint_id, and tenant_id resolution to tracing enrichment - Add resolve_agent_id() with FOUNDRY_AGENT_INSTANCE_CLIENT_ID env var (falls back to name:version or name) - Add resolve_agent_blueprint_id() with FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID - Add resolve_agent_tenant_id() with FOUNDRY_AGENT_TENANT_ID - Wire all three through _FoundryEnrichmentSpanProcessor - Make processor __init__ keyword-only Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Enable a365_enable_observability_exporter in A365 tracing config Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add a365_observability_scope_override to A365 tracing config Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix streaming context: capture full context (span + baggage) for iterator The streaming async generator runs after the request handler's finally block detaches baggage. Fix by capturing the full OTel context (including baggage) at wrap time and re-attaching it during iteration, so child spans created during streaming can see baggage entries like conversation_id. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix baggage propagation: extract only W3C baggage from request headers Extract incoming baggage (e.g. user.id) using W3CBaggagePropagator without re-extracting traceparent, preserving parent-child span relationships while making caller's baggage entries visible to downstream span processors. Also removes stale flask/sqlalchemy imports from prior attempts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix W3C baggage propagation in invocations and add tests for both packages - Apply same baggage extraction fix to invocations/_invocation.py - Add 3 baggage propagation tests for invocations package - Add 3 baggage propagation tests for responses package - Tests verify: baggage merging, span parenting preserved, empty header safety Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix test: remove assertion for server-added baggage at span start time Server-added entries (response_id) are set after span starts, so on_start processor won't see them. Test should only verify incoming baggage merging. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix test: use correct span name 'invoke_agent' instead of 'create_response' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix invocations test: remove assertion for server-added baggage at span start Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add bkey/bval to local cspell ignore lists Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove unused imports detach_context and set_current_span Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add enable_sensitive_data param to configure_observability Thread enable_sensitive_data kwarg from AgentServerHost through configure_observability -> _configure_tracing -> _setup_distro_export -> use_microsoft_opentelemetry so Agent Framework SDK records prompts, tool arguments, and results. Defaults to True; set FOUNDRY_ENABLE_SENSITIVE_DATA=false to opt out. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix test assertions to include enable_sensitive_data param Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add microsoft.foundry.agent.type attribute scoped to invoke_agent spans - Add _ATTR_FOUNDRY_AGENT_TYPE constant - Set agent_type='hosted' when FOUNDRY_HOSTING_ENVIRONMENT is set - Only write attribute on spans with gen_ai.operation.name == invoke_agent - Add 3 tests for agent_type scoping behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove invoke_agent SERVER span, keep W3C context propagation Replace request_span() with request_context() that extracts and attaches incoming W3C trace context (traceparent/tracestate/baggage) without creating a span. Framework spans created inside handlers are now parented directly under the caller's span. Changes: - core/_tracing.py: Add request_context(), remove request_span() - core/_base.py: Simplify AgentServerHost.request_context() wrapper - invocations/_invocation.py: Remove span creation/attrs/end logic - responses/_endpoint_handler.py: Same simplification - Remove agent_type from enrichment processor (no invoke_agent span) - Update all tests to validate context propagation without server span Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add proper span parenting test for responses package Replaces the weak status-code-only assertion with a test that creates a span inside the handler and verifies trace ID and parent span ID match the incoming traceparent header. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Bump azure-ai-agentserver-core min dependency to >=2.0.0b4 The request_context method was added in 2.0.0b4 (as part of the invoke_agent span removal). Update invocations and responses packages to require the correct minimum version. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make request_context backward-compatible with core 2.0.0b3 Revert min dependency back to >=2.0.0b3 and add hasattr guards so that invocations/responses gracefully degrade when running against core 2.0.0b3 (which lacks request_context). This fixes the mindependency CI check. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add e2e span parenting test with real caller span Creates a real OTel caller span, injects its trace context into the request headers, creates a child span in the invocation handler, and validates the handler span is correctly parented under the caller. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Stamp invocation_id on spans via FoundryEnrichmentSpanProcessor and add baggage tests - Add invocation_id baggage-to-span-attribute mapping in _FoundryEnrichmentSpanProcessor.on_start - Add core tests for invocation_id enrichment (from baggage, no baggage, child propagation) - Add invocations test verifying SDK-set baggage (invocation_id, session_id) available in handler - Add responses test verifying SDK-set baggage (response_id, conversation_id, streaming) available in handler - Add invocations integration test verifying baggage entries stamped as span attributes via enricher Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix CI test failures: prevent OTel distro from contaminating global state In CI environments where microsoft-opentelemetry distro is installed and APPLICATIONINSIGHTS_CONNECTION_STRING is set, non-tracing tests would trigger use_microsoft_opentelemetry() on the first server construction, installing a global TracerProvider that breaks traceparent-propagation tests. Fix: - Add session-scoped _prevent_distro_setup fixture in both invocations and responses conftest.py that mocks _setup_distro_export for all tests - Pass configure_observability=None in conftest factory functions - Pass configure_observability=None in test_tracing_disabled_by_default and test_no_tracing_when_no_endpoints Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use inject(headers) in traceparent test for CI reliability Replace synthetic traceparent string with real OTel span + inject() pattern. This ensures correct trace context propagation regardless of which TracerProvider or auto-instrumentation (e.g. microsoft-opentelemetry) is active in the CI environment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: use OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT for sensitive data Replace FOUNDRY_ENABLE_SENSITIVE_DATA with the standard OpenTelemetry GenAI semantic convention env var for controlling sensitive data capture. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use inject(headers) in invocations traceparent tests for CI reliability Replace synthetic traceparent strings with real OTel span + inject() pattern in both streaming and non-streaming span parenting tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix test_incoming_baggage_stamped_on_handler_spans for CI Rewrite the enrichment processor test to run in isolation without TestClient/ASGI, avoiding CI-specific context propagation differences. The full baggage flow through the invocations server is already covered by test_sdk_set_baggage_available_in_handler. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix pylint errors: line-too-long and unused imports - core/_base.py: break long line for env var read - invocations/_invocation.py: remove unused StreamingResponse import - responses/_endpoint_handler.py: remove unused RequestValidationError and build_create_otel_attrs imports, break long context manager line Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify request_context() and add debug logging - Pass headers directly to propagator instead of using _extract_w3c_carrier - Remove _extract_w3c_carrier helper and _W3C_HEADERS constant - Add debug log for attached span context (type, trace_id, trace_flags) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix debug log: use get_current_span() instead of non-existent get_span_from_context() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * debug: log raw trace headers and full post-attach span context Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * debug: create SERVER span in request_context for downstream instrumentors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * debug: test span without explicit parent context Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * debug: re-enable context=ctx on blah span to parent under remote trace Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: add Starlette OTel instrumentation for automatic HTTP SERVER spans Replaces the manual span with proper Starlette instrumentation that creates a SERVER span per request with trace context propagation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: replace request_context with BaggageMiddleware + Starlette instrumentor Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Suppress noisy ASGI receive/send internal spans Patch OpenTelemetryMiddleware.__init__ to set exclude_receive_span and exclude_send_span to True, suppressing the per-event INTERNAL spans (http receive / http send) that the Starlette OTel instrumentor creates. The upstream ASGI middleware already supports these attributes via its exclude_spans constructor parameter, but the Starlette instrumentor does not expose them yet (tracked in opentelemetry-python-contrib#3725). The monkeypatch can be removed once upstream adds constructor support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Test: remove BaggageMiddleware to isolate NonRecordingSpan crash Temporarily remove BaggageMiddleware from the middleware stack to test whether its context.attach() call is causing the NonRecordingSpan crash in azure-ai-projects _responses_instrumentor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Replace Starlette instrumentor with TraceContextMiddleware Remove the Starlette OTel instrumentor (which created noisy SERVER and ASGI internal spans) and replace with a lightweight TraceContextMiddleware that only extracts W3C traceparent/tracestate/baggage from incoming requests. This ensures downstream spans (from MAF/agent-framework) are children of the caller's trace without creating extra spans. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix TraceContextMiddleware: use opentelemetry.propagate.extract TraceContextTextMapPropagator was not importable from opentelemetry.trace.propagation. Use the global propagate.extract() instead which handles both TraceContext and Baggage propagation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove unused opentelemetry-instrumentation-starlette dependency No longer needed since we replaced StarletteInstrumentor with our own lightweight TraceContextMiddleware. Fixes CI 'Analyze dependencies' failure (dependency not in shared_requirements.txt). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix pylint: trailing newline and unused contextlib import Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix E2E tracing test: skip distro mock when running with -m tracing_e2e The _prevent_distro_setup fixture was blocking the Azure Monitor exporter for ALL tests including E2E ones. Now checks the marker expression and yields without patching when tracing_e2e tests are selected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix core E2E tests: remove request_context() calls TraceContextMiddleware now propagates W3C trace context automatically at the middleware layer, so handlers no longer need to call request_context(). The method was removed from AgentServerHost in this branch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix E2E test: use get_span_context() instead of .context NonRecordingSpan does not expose a public .context attribute in all OpenTelemetry versions. Use get_span_context() which is the stable API that works for all span types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add E2E test: framework spans emitted without incoming trace context Verifies that when an incoming request has NO traceparent/tracestate/baggage headers (e.g. health checks, direct calls), spans created by downstream frameworks like MAF are still properly exported to App Insights as new traces. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use span_id and trace_id to validate span in App Insights Instead of matching by span name, capture the exact span_id and trace_id from the created span and query App Insights by those IDs for precise correlation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove flaky test_child_span_in_appinsights (redundant) This test is a duplicate of test_span_parenting_in_appinsights and test_span_emitted_without_incoming_trace_context. It fails intermittently because it runs first and App Insights ingestion delay is longer for the initial telemetry session. The same validation is covered by the later tests which pass reliably. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove flaky test_handler_span_in_appinsights from invocations E2E Same App Insights ingestion timing issue as core — first test to run suffers from cold-start delay > 300s. The span parenting test already validates span export AND parent-child relationships (superset). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add App Insights warm-up fixture for E2E tracing tests App Insights has a cold-start ingestion delay for the first telemetry session sent to a resource — data can take 5+ minutes to become queryable via KQL. This caused the first E2E test to always fail in CI. Fix: Add a session-scoped autouse fixture that sends a dummy span and polls until App Insights confirms ingestion (up to 360s). Real tests then run against a 'warm' pipeline with fast ingestion. Also restores test_handler_span_in_appinsights which is no longer flaky. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix pylint: remove trailing newline in _tracing.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix cspell: add markexpr and sess to ignore list Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update CHANGELOGs for tracing middleware changes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update CHANGELOGs with comprehensive PR changes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Bump package versions to match unreleased changelog entries - azure-ai-agentserver-core: 2.0.0b4 -> 2.0.0b5 - azure-ai-agentserver-invocations: 1.0.0b4 -> 1.0.0b5 - azure-ai-agentserver-responses: 1.0.0b6 -> 1.0.0b7 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Consolidate changelog entries under current versions as Unreleased Merged new release notes into existing version entries (b4/b4/b6) instead of creating separate b5/b5/b7 entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Drop framework-level OpenTelemetry span for WebSocket connections (#46973) Aligns the invocations_ws transport with the new tracing model on feature/enable-a365-tracing: trace context propagation is handled by the core TraceContextMiddleware, and user-created spans inside handlers are correctly parented without a framework-generated root span. - _invocation_ws.py: remove the per-connection 'websocket_session' span (request_span call, otel_span, _safe_set_attrs helper, end_span import, span_ctx finalize block). Drop the dead 'handler_exc' kwarg on _finalize_session and the 'error_message' kwarg on _emit_close_event (handler exception text never reaches the close-event log line, by design). - _constants.py: drop unused ATTR_SPAN_ERROR_MESSAGE; relabel the section comment from 'Span attribute keys' to 'Structured-log extra keys'. - CHANGELOG.md: trim the WS telemetry feature bullet to describe the log-only path; no breaking-change entry (the WS span was added and removed within the same unreleased 1.0.0b4). - tests/test_ws_tracing.py: removed (17 span-assertion tests obsolete; close-event log line still covered by tests/test_ws_close_event.py). 186 tests pass, 2 skipped. Co-authored-by: Yulin Li <yulili@microsoft.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Yulin Li <liyulin@pku.edu.cn> Co-authored-by: Yulin Li <yulili@microsoft.com>
1 parent 85e5342 commit 74fb2fe

23 files changed

Lines changed: 1355 additions & 1522 deletions

File tree

sdk/agentserver/azure-ai-agentserver-core/CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
# Release History
22

3-
## 2.0.0b4 (2026-05-15)
3+
## 2.0.0b4 (Unreleased)
44

55
### Features Added
66

77
- Added `_platform_headers` module with cross-cutting protocol header name constants (`x-request-id`, `x-platform-server`, `x-agent-session-id`, `x-platform-error-source`, `x-platform-error-detail`, and others). Protocol packages now import shared header name strings from core instead of maintaining their own copies.
8+
- Added `TraceContextMiddleware` — a lightweight pure-ASGI middleware that propagates W3C trace context (`traceparent`, `tracestate`) and baggage from incoming HTTP requests. Any spans created by downstream frameworks (e.g. MAF / agent-framework) are automatically children of the caller's trace without additional framework spans.
9+
- Added `enable_sensitive_data` parameter to `configure_observability()` to control whether prompts, tool arguments, and results are recorded in telemetry. Respects `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` environment variable.
10+
- Added A365 tracing export support — when `FOUNDRY_HOSTING_ENVIRONMENT` and `FOUNDRY_AGENT365_TRACING_ENABLED` are set, telemetry is exported via the A365 observability pipeline.
11+
- Added `resolve_agent_id()`, `resolve_agent_blueprint_id()`, and `resolve_agent_tenant_id()` config helpers for new Foundry environment variables (`FOUNDRY_AGENT_INSTANCE_CLIENT_ID`, `FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID`, `FOUNDRY_AGENT_TENANT_ID`).
12+
- Added `gen_ai.agent.blueprint.id` and `microsoft.tenant.id` span attributes to the `FoundryEnrichmentSpanProcessor`.
813
- `AgentConfig.ws_ping_interval` — new field resolved from the `WS_KEEPALIVE_INTERVAL` environment variable (auto-injected by AgentService into hosted-agent containers). `0` disables; negative/non-finite values raise `ValueError` at startup. `AgentServerHost._build_hypercorn_config` wires this into Hypercorn's `websocket_ping_interval` so any protocol package serving WebSocket routes inherits keep-alive without per-package wiring.
914

15+
### Breaking Changes
16+
17+
- Removed `request_span()` method from `AgentServerHost`. Trace context propagation is now handled automatically by `TraceContextMiddleware`.
18+
1019
## 2.0.0b3 (2026-04-22)
1120

1221
### Features Added

sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/_base.py

Lines changed: 10 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,14 @@ def __init__(
188188

189189
# Observability (logging + tracing) --------------------------------
190190
_conn_str = applicationinsights_connection_string or self.config.appinsights_connection_string
191+
_env_val = os.environ.get("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", "true")
192+
_sensitive_data = _env_val.lower() not in ("false", "0")
191193
if configure_observability is not None:
192194
try:
193195
configure_observability(
194196
connection_string=_conn_str,
195197
log_level=log_level,
198+
enable_sensitive_data=_sensitive_data,
196199
)
197200
except ValueError:
198201
raise # invalid log_level etc. — user should fix their config
@@ -285,6 +288,13 @@ async def _lifespan(_app: Starlette) -> AsyncGenerator[None, None]: # noqa: RUF
285288
**kwargs,
286289
)
287290

291+
# Extract W3C trace context (traceparent/tracestate) and baggage
292+
# from incoming HTTP requests so that any spans created downstream
293+
# (e.g. by MAF / agent-framework) are children of the caller's trace.
294+
# We do NOT create a SERVER span ourselves — we only propagate context.
295+
from azure.ai.agentserver.core._tracing import TraceContextMiddleware # pylint: disable=import-outside-toplevel
296+
self.add_middleware(TraceContextMiddleware)
297+
288298
# ------------------------------------------------------------------
289299
# Server version (x-platform-server header)
290300
# ------------------------------------------------------------------
@@ -327,56 +337,6 @@ def _build_server_version(self) -> str:
327337
# Tracing (for protocol subclasses)
328338
# ------------------------------------------------------------------
329339

330-
#: Default instrumentation scope for tracing spans.
331-
#: Protocol subclasses should override this per the spec.
332-
_INSTRUMENTATION_SCOPE = "Azure.AI.AgentServer"
333-
334-
@contextlib.contextmanager
335-
def request_span(
336-
self,
337-
headers: Any,
338-
request_id: str,
339-
operation: str,
340-
*,
341-
operation_name: Optional[str] = None,
342-
session_id: str = "",
343-
end_on_exit: bool = True,
344-
) -> Any:
345-
"""Create a request-scoped span with this host's identity attributes.
346-
347-
Delegates to :func:`_tracing.request_span` with pre-populated
348-
agent identity from environment variables.
349-
350-
:param headers: HTTP request headers.
351-
:type headers: any
352-
:param request_id: The request/invocation ID.
353-
:type request_id: str
354-
:param operation: Span operation (e.g. ``"invoke_agent"``).
355-
:type operation: str
356-
:keyword operation_name: Optional ``gen_ai.operation.name`` value.
357-
:paramtype operation_name: str or None
358-
:keyword session_id: Session ID.
359-
:paramtype session_id: str
360-
:keyword end_on_exit: Whether to end the span when the context exits.
361-
:paramtype end_on_exit: bool
362-
:return: Context manager yielding the OTel span.
363-
:rtype: any
364-
"""
365-
with _tracing.request_span(
366-
headers,
367-
request_id,
368-
operation,
369-
agent_id=self.config.agent_id,
370-
agent_name=self.config.agent_name,
371-
agent_version=self.config.agent_version,
372-
project_id=self.config.project_id,
373-
operation_name=operation_name,
374-
session_id=session_id,
375-
end_on_exit=end_on_exit,
376-
instrumentation_scope=self._INSTRUMENTATION_SCOPE,
377-
) as span:
378-
yield span
379-
380340
# ------------------------------------------------------------------
381341
# Shutdown handler (server-level lifecycle)
382342
# ------------------------------------------------------------------

sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/_config.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
_ENV_FOUNDRY_AGENT_NAME = "FOUNDRY_AGENT_NAME"
2626
_ENV_FOUNDRY_AGENT_VERSION = "FOUNDRY_AGENT_VERSION"
27+
_ENV_FOUNDRY_AGENT_INSTANCE_CLIENT_ID = "FOUNDRY_AGENT_INSTANCE_CLIENT_ID"
28+
_ENV_FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID = "FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID"
29+
_ENV_FOUNDRY_AGENT_TENANT_ID = "FOUNDRY_AGENT_TENANT_ID"
2730
_ENV_FOUNDRY_HOSTING_ENVIRONMENT = "FOUNDRY_HOSTING_ENVIRONMENT"
2831
_ENV_FOUNDRY_PROJECT_ENDPOINT = "FOUNDRY_PROJECT_ENDPOINT"
2932
_ENV_FOUNDRY_PROJECT_ARM_ID = "FOUNDRY_PROJECT_ARM_ID"
@@ -290,6 +293,46 @@ def resolve_agent_version() -> str:
290293
return os.environ.get(_ENV_FOUNDRY_AGENT_VERSION, "")
291294

292295

296+
def resolve_agent_id() -> str:
297+
"""Resolve the agent ID.
298+
299+
Resolution order:
300+
1. ``FOUNDRY_AGENT_INSTANCE_CLIENT_ID`` environment variable.
301+
2. ``<agent_name>:<agent_version>`` if both are set.
302+
3. ``<agent_name>`` if only name is set.
303+
4. Empty string if nothing is available.
304+
305+
:return: The resolved agent ID, or an empty string if not determinable.
306+
:rtype: str
307+
"""
308+
agent_id = os.environ.get(_ENV_FOUNDRY_AGENT_INSTANCE_CLIENT_ID, "")
309+
if agent_id:
310+
return agent_id
311+
agent_name = os.environ.get(_ENV_FOUNDRY_AGENT_NAME, "")
312+
agent_version = os.environ.get(_ENV_FOUNDRY_AGENT_VERSION, "")
313+
if agent_name and agent_version:
314+
return f"{agent_name}:{agent_version}"
315+
return agent_name
316+
317+
318+
def resolve_agent_blueprint_id() -> str:
319+
"""Resolve the agent blueprint client ID from the ``FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID`` environment variable.
320+
321+
:return: The agent blueprint client ID, or an empty string if not set.
322+
:rtype: str
323+
"""
324+
return os.environ.get(_ENV_FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID, "")
325+
326+
327+
def resolve_agent_tenant_id() -> str:
328+
"""Resolve the agent tenant ID from the ``FOUNDRY_AGENT_TENANT_ID`` environment variable.
329+
330+
:return: The agent tenant ID, or an empty string if not set.
331+
:rtype: str
332+
"""
333+
return os.environ.get(_ENV_FOUNDRY_AGENT_TENANT_ID, "")
334+
335+
293336
def resolve_project_id() -> str:
294337
"""Resolve the Foundry project ARM resource ID from the ``FOUNDRY_PROJECT_ARM_ID`` environment variable.
295338

sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/_constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class Constants:
1919
# Tracing
2020
APPLICATIONINSIGHTS_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING"
2121
OTEL_EXPORTER_OTLP_ENDPOINT = "OTEL_EXPORTER_OTLP_ENDPOINT"
22+
FOUNDRY_AGENT365_TRACING_ENABLED = "FOUNDRY_AGENT365_TRACING_ENABLED"
23+
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"
2224

2325
# SSE keep-alive
2426
SSE_KEEPALIVE_INTERVAL = "SSE_KEEPALIVE_INTERVAL"

0 commit comments

Comments
 (0)