Skip to content

Commit fbbc825

Browse files
RaviPidaparthiVenkataAnilKumar
authored andcommitted
[agentserver] Spec compliance: error shapes, session headers, isolation, diagnostic logging, startup config logging, Foundry User-Agent (#46364)
* Spec compliance: error shapes, post-delete 404, storage logging Align error payloads with the container-spec behaviour contract: Error code compliance: - error.code uses 'invalid_request_error' for 400/404 (was 'invalid_request', 'not_found', 'invalid_mode') - error.code uses 'server_error' for 500 (was 'internal_error') - RequestValidationError default code updated to 'invalid_request_error' Post-delete behaviour (spec alignment with .NET PR #58252): - GET, input_items, and second DELETE on deleted responses now return 404 (was 400) - deleted_response() factory now delegates to not_found_response() Cancel/SSE message alignment: - Cancel incomplete: 'Cannot cancel a response in terminal state.' (was 'Cannot cancel an incomplete response.') - SSE replay non-bg: 'This response cannot be streamed because it was not created with background=true.' - SSE replay non-stream: '...stream=true.' Storage error propagation: - FoundryStorageError subclasses now explicitly caught in GET, cancel, and input_items handlers instead of being swallowed by broad except clauses - FoundryResourceNotFoundError -> 404, FoundryBadRequestError -> 400, FoundryApiError -> error_response (500) Storage call logging: - FoundryStorageLoggingPolicy: per-retry pipeline policy logging method, URI, status code, duration (ms), and correlation headers at the azure.ai.agentserver logger - Replaces built-in HttpLoggingPolicy to avoid double-logging Tests: - Added error.code assertions to all existing error tests across cancel, delete, get, create, and input_items endpoint tests - Updated post-delete tests from expecting 400 to 404 - Added new tests: SSE replay unknown ID, 404 message contains ID, 500 error body shape, SSE replay message variants - Added FoundryStorageLoggingPolicy unit tests (4 tests) - 791 tests passing Version bumped to 1.0.0b2. * Address PR review: add FoundryBadRequestError handlers, clean up imports, fix pyright/pylint, reclassify changelog * Set 1.0.0b2 release date to 2026-04-17 * feat: chat isolation enforcement & malformed ID validation Chat isolation key enforcement: - Store chat_isolation_key on ResponseExecution and _RuntimeState - Enforce key matching on GET, DELETE, Cancel, and InputItems endpoints - Mismatched/missing keys return indistinguishable 404 - Backward-compatible: no enforcement when created without a key Malformed ID validation: - All endpoints reject malformed response_id path params (wrong prefix, too short) with 400 before touching storage - previous_response_id in POST body also validated - Update existing tests using fake IDs to use well-formed IdGenerator IDs 14 chat isolation tests + 19 malformed ID tests (33 new, 824 total) * feat(agentserver-responses): eager eviction of terminal response records Port eager eviction from .NET PR #58252. After a response reaches a terminal state (completed, failed, cancelled, incomplete), the in-memory record is removed from RuntimeState so that subsequent GET, DELETE, Cancel, and SSE replay requests fall through to the durable storage provider. Key changes: - RuntimeState.try_evict(): removes terminal records while preserving chat isolation keys for provider-fallback enforcement - RuntimeState.mark_deleted(): supports DELETE provider fallback - Eviction wired into all 5 orchestrator terminal paths (bg non-stream, sync, bg+stream Path A, non-bg stream Path B, cancel) - Provider fallback paths added to handle_get, handle_delete, handle_cancel for evicted responses - B1 background check in cancel provider fallback (matches .NET) - Cancel idempotency: cancelled responses return 200 via provider - B2 stream/background checks in SSE replay provider fallback - background + stream mode flags stamped on all persisted responses - SSE events saved for replay after eviction (including fallback events) - store=false cancel returns 404 (matching .NET) - SSE datetime serialization fix in _build_sse_frame - 9 new eager eviction unit tests * fix(agentserver-responses): remove stream mode flag stamping on persisted responses The stream flag is not part of the ResponseObject contract and should not be persisted. After eager eviction, the server cannot distinguish bg+non-stream from bg+stream-with-expired-TTL, so the SSE replay fallback now uses a combined error message matching .NET's SseReplayResult: 'This response cannot be streamed because it was not created with stream=true or the stream TTL has expired.' Added TODO documenting the deliberate spec violation — the container spec prescribes distinct error messages but the provider doesn't carry enough context to distinguish the two cases. * feat(agentserver-responses): inbound request logging middleware and handler diagnostic logging - Add InboundRequestLoggingMiddleware (pure ASGI): logs method, path, status, duration, correlation headers (x-request-id, x-ms-client-request-id), and OTel trace ID. Status >= 400 → WARNING; exceptions → forced 500 WARNING. Query strings are excluded from logs. - Add INFO-level handler diagnostic logs to all 5 endpoints: create (params), get (entry + retrieval), delete (entry + success), cancel (entry + success), input_items (entry). - Add orchestrator handler invocation log with handler function name. - Wire middleware in ResponsesAgentServerHost via add_middleware(). - 13 new contract tests for middleware and handler logging. - Update CHANGELOG.md with logging features. Matches .NET PR #58274 (InboundRequestLoggingMiddleware + handler logging). * chore: remove .NET references from code comments and docstrings * fix: add type ignore for Starlette add_middleware typing * fix: update githubcopilot core dependency to >=2.0.0b1 The azure-ai-agentserver-core package was bumped to 2.0.0b1 but the githubcopilot package still had the old <1.0.0b18 upper bound, causing the Analyze dependencies CI gate to fail. * Revert "fix: update githubcopilot core dependency to >=2.0.0b1" This reverts commit 903e498. * Move InboundRequestLoggingMiddleware to core Moves the middleware from azure-ai-agentserver-responses to azure-ai-agentserver-core so all protocol hosts get consistent inbound request logging automatically. - Created _middleware.py in core with the middleware class - Wired into AgentServerHost.__init__ middleware list - Exported from core __init__.py - Removed explicit add_middleware() call from ResponsesAgentServerHost - Updated CHANGELOG to reflect the move Addresses review feedback from @ankitbko. * Bump core to 2.0.0b2, invocations to 1.0.0b2 for middleware move - core 2.0.0b2: Added InboundRequestLoggingMiddleware, CHANGELOG updated - invocations 1.0.0b2: Core dep bumped to >=2.0.0b2, CHANGELOG updated - responses: Core dep bumped to >=2.0.0b2 * feat(responses): add x-agent-session-id header + B40 error shape (§8, B40) - Add x-agent-session-id response header on all protocol endpoints per container spec §8. POST /responses uses the per-request resolved session ID; GET/DELETE/CANCEL/INPUT_ITEMS use the env var. - Update B40 malformed ID error shape: code 'invalid_parameters', param 'responseId{<value>}' matching spec contract. - Add _session_headers() helper for consistent header propagation across all handler code paths including error responses. - Add invalid_parameters_response() validation helper for B40. - Update previous_response_id validation to use 'invalid_parameters'. - Fix header inconsistency: all JSONResponse calls now include headers. - TDD: tests written first, verified red, then implementation, green. Tests: 851 responses + 76 core + 105 invocations passing. * Address PR review: fix CHANGELOG B40 wire shape, use public API in test * Log isolation key presence (not values) in endpoint handler diagnostics * Log isolation header presence in Foundry storage logging policy Add has_user_isolation_key/has_chat_isolation_key booleans to both success and failure log lines. Values are never logged. Includes 3 new unit tests covering presence, absence, and failure paths. * Fix pyright errors in agentserver source code - _tracing.py: Suppress OTel type stub gaps (start_as_current_span context manager, LoggerProvider API vs SDK mismatch, duck-typed BaggageLogRecordProcessor) with targeted type: ignore comments. - _base.py: Suppress Starlette Middleware factory protocol mismatch for pure-ASGI middleware classes (arg-type). All 13 production-source pyright errors resolved (0 remaining). Test-only errors from generated model unions are pre-existing. * Add startup configuration logging across all agentserver packages - Core: AgentServerHost lifespan emits 3 INFO log lines at startup: 1. Platform environment (is_hosted, agent_name, agent_version, port, session_id, sse_keepalive_interval) 2. Connectivity (project_endpoint masked, otlp_endpoint masked, appinsights_configured boolean — connection string never logged) 3. Host options (shutdown_timeout, registered protocols) - Core: _mask_uri() helper strips URI to scheme://host, returns '(not set)' for empty values, '(redacted)' for unparseable input - Responses: Logs storage_provider type, default_model, default_fetch_history_count, shutdown_grace_period at construction - Invocations: Logs openapi_spec_configured at construction - 13 new unit tests (8 for _mask_uri, 5 for startup log assertions) - Updated all 3 CHANGELOGs * Fix ruff lint issues across agentserver packages - Fix I001 import sorting in _base.py, _config.py, _tracing.py, _endpoint_handler.py, _sse.py (auto-fixed via ruff --fix) - Fix E501 line-too-long in _orchestrator.py (2 occurrences, wrapped long getattr expressions) * Address PR review comments: URL masking, SSE session headers, test hardening - _mask_uri docstring: Include '(redacted)' return case in :return: docs - FoundryStorageLoggingPolicy: Mask everything before /storage in URLs (host, scheme, /api/projects/{name} prefix all redacted); query params stripped. Only /storage/... resource path is logged for debugging. - SSE session headers: _parse_starting_after now accepts headers param; _build_live_stream_response and _try_replay_persisted_stream merge session headers into SSE headers so x-agent-session-id is present on all streaming responses and cursor-parse error responses. - test_valid_format_nonexistent_previous_response_id: Strengthened to explicitly assert code != 'invalid_parameters' and 'Malformed' not in message when status is 400, instead of weak OR-based assertion. - 6 new _mask_storage_url unit tests covering project path redaction, query stripping, /storage path preservation, edge cases. * Preserve api-version query param in Foundry storage URL masking _mask_storage_url now keeps the api-version query parameter in the masked output for debugging while still stripping all other params. Updated docstring example and tests accordingly. * Foundry storage User-Agent matches x-platform-server via lazy callback; cspell fixes * Fix post-eviction chat isolation: let Foundry storage enforce instead of local 404 * Remove redundant _chat_isolation_keys dict — use record directly The _chat_isolation_keys dict duplicated what ResponseExecution.chat_isolation_key already carries. For in-flight responses the record is available; for post-eviction responses Foundry storage enforces isolation server-side. - Remove _chat_isolation_keys dict and all add/delete/evict bookkeeping - Make check_chat_isolation a @staticmethod(stored_key, request_key) - Endpoint callers pass record.chat_isolation_key directly - Remove redundant INPUT_ITEMS KeyError fallback check (already checked above) - Update eviction test to verify static helper + record lifecycle * Address PR review: fix docstring and logging policy generics - FoundryStorageProvider: update get_server_version=None docstring to say 'uses Azure Core default User-Agent policy' (matches actual behavior) - FoundryStorageLoggingPolicy: remove misleading AsyncHTTPPolicy generic type args; use bare AsyncHTTPPolicy with type: ignore[type-arg] * Address PR review round 4: sdk_moniker, exc_info, test name - Restore sdk_moniker='ai-agentserver-responses/{VERSION}' in default UserAgentPolicy path (was dropped when adding _ServerVersionUserAgentPolicy) - Add exc_info=True to logging policy transport-failure warning - Rename test_malformed_previous_response_id_returns_400_with_details to _returns_400; assert error.type/code/param (no details array in wire shape) - Update module docstring to match actual contract * Fix pylint: extract helpers to reduce statement/branch counts Core: - _base.py: break long Middleware() line (127 > 120 chars) Responses (_endpoint_handler.py): - Extract _handle_get_fallback(): provider fallback for evicted/missing records - Extract _handle_get_stream(): stream=true path for in-flight records - Extract _handle_cancel_fallback(): provider fallback for cancel - Extract _check_cancel_terminal_status(): shared terminal-status logic used by both in-flight and provider-fallback cancel paths - handle_get: 61 -> ~30 statements - handle_cancel: 55 statements / 22 branches -> ~30 / ~12 * Suppress remaining pylint warnings in agentserver-responses - Add pylint disable for too-many-positional-arguments on constructors and get_input_items protocol methods (6 sites) - Add pylint disable for import-error/no-name-in-module on cross-package azure.ai.agentserver.core imports (4 sites) * fix: remove too-many-positional-arguments disable comments unsupported by pylint 3.2.7 CI uses pylint==3.2.7 which does not have the too-many-positional-arguments check (added in 3.3+). The inline pylint disable comments were triggering unknown-option-value warnings (W0012), causing exit code 4.
1 parent 427579e commit fbbc825

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3386
-223
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Release History
22

3+
## 2.0.0b2 (2026-04-17)
4+
5+
### Features Added
6+
7+
- Startup configuration logging — `AgentServerHost` lifespan now emits three INFO-level log lines at startup: platform environment (agent name, version, port, session ID, SSE keep-alive), connectivity (project endpoint and OTLP endpoint masked to scheme://host, Application Insights configured flag), and host options (shutdown timeout, registered protocols). Sensitive values (Application Insights connection string) are never logged.
8+
- `InboundRequestLoggingMiddleware` — pure-ASGI middleware wired automatically by `AgentServerHost` that logs every inbound HTTP request. Logs method, path (no query string), status code, duration in milliseconds, and correlation headers (`x-request-id`, `x-ms-client-request-id`). Status codes >= 400 are logged at WARNING; unhandled exceptions are logged as status 500 at WARNING. OpenTelemetry trace ID is included when an active trace exists.
9+
310
## 2.0.0b1 (2026-04-14)
411

512
This is a major architectural rewrite. The package has been redesigned as a lightweight hosting

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from ._base import AgentServerHost
2727
from ._config import AgentConfig
2828
from ._errors import create_error_response
29+
from ._middleware import InboundRequestLoggingMiddleware
2930
from ._server_version import build_server_version
3031
from ._tracing import (
3132
configure_observability,
@@ -41,6 +42,7 @@
4142
__all__ = [
4243
"AgentConfig",
4344
"AgentServerHost",
45+
"InboundRequestLoggingMiddleware",
4446
"build_server_version",
4547
"configure_observability",
4648
"create_error_response",

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

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66
import logging
77
import os
88
import signal
9-
from collections.abc import AsyncGenerator, AsyncIterable, AsyncIterator, Awaitable, Callable # pylint: disable=import-error
9+
import urllib.parse
10+
from collections.abc import ( # pylint: disable=import-error
11+
AsyncGenerator,
12+
AsyncIterable,
13+
AsyncIterator,
14+
Awaitable,
15+
Callable,
16+
)
1017
from typing import Any, MutableMapping, Optional, Union
1118

1219
from starlette.applications import Starlette
@@ -17,6 +24,7 @@
1724
from starlette.types import ASGIApp, Receive, Scope, Send
1825

1926
from . import _config, _tracing
27+
from ._middleware import InboundRequestLoggingMiddleware
2028
from ._server_version import build_server_version
2129
from ._version import VERSION as _CORE_VERSION
2230

@@ -25,6 +33,35 @@
2533
# Pre-built health-check response to avoid per-request allocation.
2634
_HEALTHY_BODY = b'{"status":"healthy"}'
2735

36+
_NOT_SET = "(not set)"
37+
38+
39+
def _mask_uri(uri: str) -> str:
40+
"""Return only the scheme and host of a URI, hiding path/query/credentials.
41+
42+
Returns ``"(not set)"`` for empty or whitespace-only values, or
43+
``"(redacted)"`` when the URI cannot be parsed into scheme + host.
44+
45+
:param uri: The URI to mask.
46+
:type uri: str
47+
:return: ``"scheme://host[:port]"``, ``"(not set)"``, or ``"(redacted)"``.
48+
:rtype: str
49+
"""
50+
stripped = uri.strip() if uri else ""
51+
if not stripped:
52+
return _NOT_SET
53+
try:
54+
parsed = urllib.parse.urlparse(stripped)
55+
scheme = parsed.scheme or ""
56+
host = parsed.hostname or ""
57+
if scheme and host:
58+
port_suffix = f":{parsed.port}" if parsed.port else ""
59+
return f"{scheme}://{host}{port_suffix}"
60+
# Best-effort: if parsing fails to extract components, redact entirely
61+
return "(redacted)"
62+
except Exception: # pylint: disable=broad-exception-caught
63+
return "(redacted)"
64+
2865

2966
class _PlatformHeaderMiddleware:
3067
"""Pure-ASGI middleware that adds ``x-platform-server`` header to responses.
@@ -176,6 +213,32 @@ def __init__(
176213
@contextlib.asynccontextmanager
177214
async def _lifespan(_app: Starlette) -> AsyncGenerator[None, None]: # noqa: RUF029
178215
logger.info("AgentServerHost started")
216+
217+
# --- Startup configuration logging ---
218+
cfg = self.config
219+
logger.info(
220+
"Platform environment: is_hosted=%s, agent_name=%s, agent_version=%s, "
221+
"port=%s, session_id=%s, sse_keepalive_interval=%s",
222+
cfg.is_hosted,
223+
cfg.agent_name or _NOT_SET,
224+
cfg.agent_version or _NOT_SET,
225+
cfg.port,
226+
cfg.session_id or _NOT_SET,
227+
cfg.sse_keepalive_interval if cfg.sse_keepalive_interval > 0 else "disabled",
228+
)
229+
logger.info(
230+
"Connectivity: project_endpoint=%s, otlp_endpoint=%s, appinsights_configured=%s",
231+
_mask_uri(cfg.project_endpoint),
232+
_mask_uri(cfg.otlp_endpoint),
233+
bool(cfg.appinsights_connection_string),
234+
)
235+
protocols = ", ".join(self._server_version_segments) if self._server_version_segments else _NOT_SET
236+
logger.info(
237+
"Host options: shutdown_timeout=%ss, protocols=%s",
238+
self._graceful_shutdown_timeout,
239+
protocols,
240+
)
241+
179242
yield
180243

181244
# --- SHUTDOWN: runs once when the server is stopping ---
@@ -210,7 +273,11 @@ async def _lifespan(_app: Starlette) -> AsyncGenerator[None, None]: # noqa: RUF
210273
routes=all_routes,
211274
lifespan=_lifespan,
212275
middleware=[
213-
Middleware(_PlatformHeaderMiddleware, get_server_version=self._build_server_version),
276+
Middleware(InboundRequestLoggingMiddleware), # type: ignore[arg-type]
277+
Middleware( # type: ignore[arg-type]
278+
_PlatformHeaderMiddleware,
279+
get_server_version=self._build_server_version,
280+
),
214281
],
215282
**kwargs,
216283
)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""
1616
import os
1717
from typing import Optional
18+
1819
from typing_extensions import Self
1920

2021
# ======================================================================
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# ---------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# ---------------------------------------------------------
4+
"""Inbound request logging middleware for Azure AI Agent Server hosts.
5+
6+
A pure-ASGI middleware that logs every inbound HTTP request at INFO level
7+
(start) and at INFO or WARNING level (completion, depending on status code).
8+
9+
Behaviour:
10+
- Logs method + path (no query string) on start.
11+
- Logs method + path + status code + duration on completion.
12+
- Correlation headers (``x-request-id``, ``x-ms-client-request-id``) are
13+
included when present.
14+
- OTel trace ID is included when an active trace exists.
15+
- Status >= 400 → WARNING; otherwise → INFO.
16+
- Unhandled exceptions → forced status 500, WARNING.
17+
"""
18+
19+
from __future__ import annotations
20+
21+
import logging
22+
import time
23+
from typing import Any, MutableMapping
24+
25+
from starlette.types import ASGIApp, Receive, Scope, Send
26+
27+
logger = logging.getLogger("azure.ai.agentserver")
28+
29+
30+
def _extract_header(headers: list[tuple[bytes, bytes]], name: bytes) -> str | None:
31+
"""Extract a header value from raw ASGI headers.
32+
33+
:param headers: Raw ASGI header tuples.
34+
:type headers: list[tuple[bytes, bytes]]
35+
:param name: Lower-case header name to look up.
36+
:type name: bytes
37+
:return: Decoded header value, or ``None`` if not found.
38+
:rtype: str | None
39+
"""
40+
for key, value in headers:
41+
if key == name:
42+
return value.decode("latin-1")
43+
return None
44+
45+
46+
def _get_trace_id() -> str | None:
47+
"""Return the current OTel trace ID hex string, or ``None``.
48+
49+
:return: Hex-encoded trace ID from the current OTel span, or ``None``.
50+
:rtype: str | None
51+
"""
52+
try:
53+
from opentelemetry import trace as _trace # pylint: disable=import-outside-toplevel
54+
55+
span = _trace.get_current_span()
56+
ctx = span.get_span_context()
57+
if ctx and ctx.trace_id:
58+
return format(ctx.trace_id, "032x")
59+
except Exception: # pylint: disable=broad-exception-caught
60+
pass
61+
return None
62+
63+
64+
class InboundRequestLoggingMiddleware:
65+
"""Pure-ASGI middleware that logs inbound HTTP requests.
66+
67+
Unlike ``BaseHTTPMiddleware``, this passes the ``receive`` callable
68+
through to the inner application untouched, preserving
69+
``request.is_disconnected()`` behaviour.
70+
71+
Wired automatically by :class:`AgentServerHost` so that all protocol
72+
hosts (responses, invocations, etc.) get consistent inbound logging.
73+
74+
:param app: The inner ASGI application.
75+
:type app: ASGIApp
76+
"""
77+
78+
def __init__(self, app: ASGIApp) -> None:
79+
self.app = app
80+
81+
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
82+
if scope["type"] != "http":
83+
await self.app(scope, receive, send)
84+
return
85+
86+
method: str = scope.get("method", "?")
87+
path: str = scope.get("path", "/")
88+
raw_headers: list[tuple[bytes, bytes]] = scope.get("headers", [])
89+
90+
request_id = _extract_header(raw_headers, b"x-request-id")
91+
client_request_id = _extract_header(raw_headers, b"x-ms-client-request-id")
92+
trace_id = _get_trace_id()
93+
94+
extra_parts: list[str] = []
95+
if request_id:
96+
extra_parts.append(f"x-request-id={request_id}")
97+
if client_request_id:
98+
extra_parts.append(f"x-ms-client-request-id={client_request_id}")
99+
if trace_id:
100+
extra_parts.append(f"trace_id={trace_id}")
101+
extra_str = f" [{', '.join(extra_parts)}]" if extra_parts else ""
102+
103+
logger.info("Inbound %s %s started%s", method, path, extra_str)
104+
105+
status_code: int | None = None
106+
start = time.monotonic()
107+
108+
async def _send_wrapper(message: MutableMapping[str, Any]) -> None:
109+
nonlocal status_code
110+
if message["type"] == "http.response.start":
111+
status_code = message.get("status", 0)
112+
await send(message)
113+
114+
try:
115+
await self.app(scope, receive, _send_wrapper)
116+
except Exception:
117+
elapsed_ms = (time.monotonic() - start) * 1000
118+
logger.warning(
119+
"Inbound %s %s failed with status 500 in %.1fms%s",
120+
method, path, elapsed_ms, extra_str,
121+
)
122+
raise
123+
124+
elapsed_ms = (time.monotonic() - start) * 1000
125+
126+
if status_code is not None and status_code >= 400:
127+
logger.warning(
128+
"Inbound %s %s completed with status %d in %.1fms%s",
129+
method, path, status_code, elapsed_ms, extra_str,
130+
)
131+
else:
132+
logger.info(
133+
"Inbound %s %s completed with status %s in %.1fms%s",
134+
method, path, status_code, elapsed_ms, extra_str,
135+
)

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def request_span(
245245
if x_request_id:
246246
ctx = _otel_baggage.set_baggage("x_request_id", x_request_id, context=ctx)
247247

248-
with tracer.start_as_current_span(
248+
with tracer.start_as_current_span( # type: ignore[reportGeneralTypeIssues]
249249
name=name,
250250
attributes=attrs,
251251
kind=trace.SpanKind.SERVER,
@@ -549,6 +549,7 @@ def _setup_trace_export(provider: Any, connection_string: str) -> None:
549549
return
550550
try:
551551
from opentelemetry.sdk.trace.export import BatchSpanProcessor
552+
552553
from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter # type: ignore[import-untyped]
553554
except ImportError:
554555
logger.warning("Trace export requires azure-monitor-opentelemetry-exporter.")
@@ -567,6 +568,7 @@ def _setup_log_export(resource: Any, connection_string: str) -> None:
567568
from opentelemetry._logs import set_logger_provider
568569
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
569570
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
571+
570572
from azure.monitor.opentelemetry.exporter import AzureMonitorLogExporter # type: ignore[import-untyped]
571573
except ImportError:
572574
logger.warning("Log export requires azure-monitor-opentelemetry-exporter.")
@@ -615,9 +617,12 @@ def _setup_otlp_log_export(resource: Any, endpoint: str) -> None:
615617
from opentelemetry._logs import set_logger_provider
616618
log_provider = LoggerProvider(resource=resource)
617619
set_logger_provider(log_provider)
618-
log_provider.add_log_record_processor(BatchLogRecordProcessor(
619-
OTLPLogExporter(endpoint=endpoint))) # type: ignore[union-attr]
620-
log_provider.add_log_record_processor(_BaggageLogRecordProcessor()) # type: ignore[arg-type]
620+
log_provider.add_log_record_processor( # type: ignore[union-attr]
621+
BatchLogRecordProcessor(OTLPLogExporter(endpoint=endpoint))
622+
)
623+
log_provider.add_log_record_processor( # type: ignore[union-attr]
624+
_BaggageLogRecordProcessor() # type: ignore[arg-type]
625+
)
621626
# Note: LoggingHandler is NOT added here to avoid duplicating the
622627
# handler already installed by _setup_log_export. The OTel LoggerProvider
623628
# receives log records via the handler added there (or from direct OTel

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# Copyright (c) Microsoft Corporation. All rights reserved.
33
# ---------------------------------------------------------
44

5-
VERSION = "2.0.0b1"
5+
VERSION = "2.0.0b2"

0 commit comments

Comments
 (0)