Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
5f81dca
Enable A365 tracing in agentserver-core when hosted
singankit May 4, 2026
0392a27
Add agent_id, blueprint_id, and tenant_id resolution to tracing enric…
singankit May 4, 2026
8db62c6
Enable a365_enable_observability_exporter in A365 tracing config
singankit May 4, 2026
d8bb33e
Add a365_observability_scope_override to A365 tracing config
singankit May 5, 2026
a0c1637
Fix streaming context: capture full context (span + baggage) for iter…
singankit May 5, 2026
046cc7b
Fix baggage propagation: extract only W3C baggage from request headers
singankit May 6, 2026
aee8584
Fix W3C baggage propagation in invocations and add tests for both pac…
singankit May 6, 2026
167bd4a
Fix test: remove assertion for server-added baggage at span start time
singankit May 6, 2026
ce9ae4f
Fix test: use correct span name 'invoke_agent' instead of 'create_res…
singankit May 6, 2026
dab1c87
Fix invocations test: remove assertion for server-added baggage at sp…
singankit May 6, 2026
078502d
Add bkey/bval to local cspell ignore lists
singankit May 6, 2026
3cda909
Remove unused imports detach_context and set_current_span
singankit May 6, 2026
d9d5982
Add enable_sensitive_data param to configure_observability
singankit May 7, 2026
36b9d38
Fix test assertions to include enable_sensitive_data param
singankit May 7, 2026
0a1e5ec
Add microsoft.foundry.agent.type attribute scoped to invoke_agent spans
singankit May 8, 2026
0c0eea7
Remove invoke_agent SERVER span, keep W3C context propagation
singankit May 13, 2026
b9c187c
Add proper span parenting test for responses package
singankit May 13, 2026
7410482
Bump azure-ai-agentserver-core min dependency to >=2.0.0b4
singankit May 14, 2026
21e8641
Make request_context backward-compatible with core 2.0.0b3
singankit May 14, 2026
69b2660
Add e2e span parenting test with real caller span
singankit May 14, 2026
baf6478
Stamp invocation_id on spans via FoundryEnrichmentSpanProcessor and a…
singankit May 14, 2026
dff280f
Fix CI test failures: prevent OTel distro from contaminating global s…
singankit May 14, 2026
5857a8b
fix: use inject(headers) in traceparent test for CI reliability
singankit May 14, 2026
400d271
refactor: use OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT for …
singankit May 14, 2026
871e203
fix: use inject(headers) in invocations traceparent tests for CI reli…
singankit May 15, 2026
4290e21
Fix test_incoming_baggage_stamped_on_handler_spans for CI
singankit May 15, 2026
8047e3f
Merge origin/main into feature/enable-a365-tracing
singankit May 15, 2026
61e3a0e
Fix pylint errors: line-too-long and unused imports
singankit May 15, 2026
7ff6248
Simplify request_context() and add debug logging
singankit May 15, 2026
58806dc
Fix debug log: use get_current_span() instead of non-existent get_spa…
singankit May 15, 2026
6faa575
debug: log raw trace headers and full post-attach span context
singankit May 15, 2026
dd97f34
debug: create SERVER span in request_context for downstream instrumen…
singankit May 15, 2026
c19a4a7
debug: test span without explicit parent context
singankit May 15, 2026
422eb1d
debug: re-enable context=ctx on blah span to parent under remote trace
singankit May 15, 2026
dcbb745
feat: add Starlette OTel instrumentation for automatic HTTP SERVER spans
singankit May 15, 2026
9b7ee76
refactor: replace request_context with BaggageMiddleware + Starlette …
singankit May 16, 2026
7939515
Suppress noisy ASGI receive/send internal spans
singankit May 16, 2026
9db26d2
Test: remove BaggageMiddleware to isolate NonRecordingSpan crash
singankit May 16, 2026
55698eb
Replace Starlette instrumentor with TraceContextMiddleware
singankit May 16, 2026
c76059f
Fix TraceContextMiddleware: use opentelemetry.propagate.extract
singankit May 16, 2026
51b7c7b
Remove unused opentelemetry-instrumentation-starlette dependency
singankit May 16, 2026
7d73600
Fix pylint: trailing newline and unused contextlib import
singankit May 16, 2026
4d6e1e9
Fix E2E tracing test: skip distro mock when running with -m tracing_e2e
singankit May 17, 2026
c7dae15
Fix core E2E tests: remove request_context() calls
singankit May 17, 2026
7d116bf
Fix E2E test: use get_span_context() instead of .context
singankit May 17, 2026
c40da1b
Add E2E test: framework spans emitted without incoming trace context
singankit May 17, 2026
3fcfcbf
Use span_id and trace_id to validate span in App Insights
singankit May 17, 2026
b49f6f1
Remove flaky test_child_span_in_appinsights (redundant)
singankit May 17, 2026
9fe6460
Remove flaky test_handler_span_in_appinsights from invocations E2E
singankit May 17, 2026
b7852ca
Add App Insights warm-up fixture for E2E tracing tests
singankit May 17, 2026
26b4949
Fix pylint: remove trailing newline in _tracing.py
singankit May 17, 2026
b88a09f
Fix cspell: add markexpr and sess to ignore list
singankit May 18, 2026
5316153
Update CHANGELOGs for tracing middleware changes
singankit May 18, 2026
48d8f65
Update CHANGELOGs with comprehensive PR changes
singankit May 18, 2026
249fd79
Bump package versions to match unreleased changelog entries
singankit May 18, 2026
acd4f55
Consolidate changelog entries under current versions as Unreleased
singankit May 18, 2026
22ab1ae
Merge main and resolve CHANGELOG conflict
singankit May 18, 2026
d7b185f
Merge branch 'main' into feature/enable-a365-tracing
yulin-li May 19, 2026
b700342
Drop framework-level OpenTelemetry span for WebSocket connections (#4…
yulin-li May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion sdk/agentserver/azure-ai-agentserver-core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
# Release History

## 2.0.0b4 (2026-05-15)
## 2.0.0b4 (Unreleased)

### Features Added

- 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.
- 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.
Comment thread
singankit marked this conversation as resolved.
- 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.
- Added A365 tracing export support — when `FOUNDRY_HOSTING_ENVIRONMENT` and `FOUNDRY_AGENT365_TRACING_ENABLED` are set, telemetry is exported via the A365 observability pipeline.
- 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`).
- Added `gen_ai.agent.blueprint.id` and `microsoft.tenant.id` span attributes to the `FoundryEnrichmentSpanProcessor`.
- `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.

### Breaking Changes

- Removed `request_span()` method from `AgentServerHost`. Trace context propagation is now handled automatically by `TraceContextMiddleware`.

## 2.0.0b3 (2026-04-22)

### Features Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,14 @@ def __init__(

# Observability (logging + tracing) --------------------------------
_conn_str = applicationinsights_connection_string or self.config.appinsights_connection_string
_env_val = os.environ.get("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", "true")
_sensitive_data = _env_val.lower() not in ("false", "0")
if configure_observability is not None:
try:
configure_observability(
connection_string=_conn_str,
log_level=log_level,
enable_sensitive_data=_sensitive_data,
)
except ValueError:
raise # invalid log_level etc. — user should fix their config
Expand Down Expand Up @@ -285,6 +288,13 @@ async def _lifespan(_app: Starlette) -> AsyncGenerator[None, None]: # noqa: RUF
**kwargs,
)

# Extract W3C trace context (traceparent/tracestate) and baggage
# from incoming HTTP requests so that any spans created downstream
# (e.g. by MAF / agent-framework) are children of the caller's trace.
# We do NOT create a SERVER span ourselves — we only propagate context.
from azure.ai.agentserver.core._tracing import TraceContextMiddleware # pylint: disable=import-outside-toplevel
self.add_middleware(TraceContextMiddleware)

# ------------------------------------------------------------------
# Server version (x-platform-server header)
# ------------------------------------------------------------------
Expand Down Expand Up @@ -327,56 +337,6 @@ def _build_server_version(self) -> str:
# Tracing (for protocol subclasses)
# ------------------------------------------------------------------

#: Default instrumentation scope for tracing spans.
#: Protocol subclasses should override this per the spec.
_INSTRUMENTATION_SCOPE = "Azure.AI.AgentServer"

@contextlib.contextmanager
def request_span(
self,
headers: Any,
request_id: str,
operation: str,
*,
operation_name: Optional[str] = None,
session_id: str = "",
end_on_exit: bool = True,
) -> Any:
"""Create a request-scoped span with this host's identity attributes.

Delegates to :func:`_tracing.request_span` with pre-populated
agent identity from environment variables.

:param headers: HTTP request headers.
:type headers: any
:param request_id: The request/invocation ID.
:type request_id: str
:param operation: Span operation (e.g. ``"invoke_agent"``).
:type operation: str
:keyword operation_name: Optional ``gen_ai.operation.name`` value.
:paramtype operation_name: str or None
:keyword session_id: Session ID.
:paramtype session_id: str
:keyword end_on_exit: Whether to end the span when the context exits.
:paramtype end_on_exit: bool
:return: Context manager yielding the OTel span.
:rtype: any
"""
with _tracing.request_span(
headers,
request_id,
operation,
agent_id=self.config.agent_id,
agent_name=self.config.agent_name,
agent_version=self.config.agent_version,
project_id=self.config.project_id,
operation_name=operation_name,
session_id=session_id,
end_on_exit=end_on_exit,
instrumentation_scope=self._INSTRUMENTATION_SCOPE,
) as span:
yield span

# ------------------------------------------------------------------
# Shutdown handler (server-level lifecycle)
# ------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@

_ENV_FOUNDRY_AGENT_NAME = "FOUNDRY_AGENT_NAME"
_ENV_FOUNDRY_AGENT_VERSION = "FOUNDRY_AGENT_VERSION"
_ENV_FOUNDRY_AGENT_INSTANCE_CLIENT_ID = "FOUNDRY_AGENT_INSTANCE_CLIENT_ID"
Comment thread
ankitbko marked this conversation as resolved.
_ENV_FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID = "FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID"
_ENV_FOUNDRY_AGENT_TENANT_ID = "FOUNDRY_AGENT_TENANT_ID"
_ENV_FOUNDRY_HOSTING_ENVIRONMENT = "FOUNDRY_HOSTING_ENVIRONMENT"
_ENV_FOUNDRY_PROJECT_ENDPOINT = "FOUNDRY_PROJECT_ENDPOINT"
_ENV_FOUNDRY_PROJECT_ARM_ID = "FOUNDRY_PROJECT_ARM_ID"
Expand Down Expand Up @@ -290,6 +293,46 @@ def resolve_agent_version() -> str:
return os.environ.get(_ENV_FOUNDRY_AGENT_VERSION, "")


def resolve_agent_id() -> str:
"""Resolve the agent ID.

Resolution order:
1. ``FOUNDRY_AGENT_INSTANCE_CLIENT_ID`` environment variable.
2. ``<agent_name>:<agent_version>`` if both are set.
3. ``<agent_name>`` if only name is set.
4. Empty string if nothing is available.

:return: The resolved agent ID, or an empty string if not determinable.
:rtype: str
"""
agent_id = os.environ.get(_ENV_FOUNDRY_AGENT_INSTANCE_CLIENT_ID, "")
if agent_id:
return agent_id
agent_name = os.environ.get(_ENV_FOUNDRY_AGENT_NAME, "")
agent_version = os.environ.get(_ENV_FOUNDRY_AGENT_VERSION, "")
if agent_name and agent_version:
return f"{agent_name}:{agent_version}"
return agent_name


def resolve_agent_blueprint_id() -> str:
"""Resolve the agent blueprint client ID from the ``FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID`` environment variable.

:return: The agent blueprint client ID, or an empty string if not set.
:rtype: str
"""
return os.environ.get(_ENV_FOUNDRY_AGENT_BLUEPRINT_CLIENT_ID, "")


def resolve_agent_tenant_id() -> str:
"""Resolve the agent tenant ID from the ``FOUNDRY_AGENT_TENANT_ID`` environment variable.

:return: The agent tenant ID, or an empty string if not set.
:rtype: str
"""
return os.environ.get(_ENV_FOUNDRY_AGENT_TENANT_ID, "")


def resolve_project_id() -> str:
"""Resolve the Foundry project ARM resource ID from the ``FOUNDRY_PROJECT_ARM_ID`` environment variable.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class Constants:
# Tracing
APPLICATIONINSIGHTS_CONNECTION_STRING = "APPLICATIONINSIGHTS_CONNECTION_STRING"
OTEL_EXPORTER_OTLP_ENDPOINT = "OTEL_EXPORTER_OTLP_ENDPOINT"
FOUNDRY_AGENT365_TRACING_ENABLED = "FOUNDRY_AGENT365_TRACING_ENABLED"
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"

# SSE keep-alive
SSE_KEEPALIVE_INTERVAL = "SSE_KEEPALIVE_INTERVAL"
Expand Down
Loading