-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Python: Show FoundryAgent client spans in Foundry traces #7981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c133e29
2ac2114
c46ff52
7180c58
79db809
7695b7f
a3eeaee
807a12a
4f3b8b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,7 @@ | |
| from agent_framework.observability import AgentTelemetryLayer, ChatTelemetryLayer | ||
| from agent_framework_openai._chat_client import OpenAIChatOptions, RawOpenAIChatClient | ||
| from azure.ai.projects.aio import AIProjectClient | ||
| from azure.ai.projects.models import ConnectionType | ||
| from azure.core.credentials import TokenCredential | ||
| from azure.core.credentials_async import AsyncTokenCredential | ||
|
|
||
|
|
@@ -95,6 +96,7 @@ class FoundryAgentSettings(TypedDict, total=False): | |
|
|
||
|
|
||
| FOUNDRY_HOSTED_AGENT_SESSION_ID_KEY = "foundry_hosted_agent_session_id" | ||
| _FOUNDRY_PROJECT_ARM_ID_ATTRIBUTE = "microsoft.foundry.project.id" | ||
|
|
||
|
|
||
| class FoundryAgentOptions(OpenAIChatOptions, total=False): | ||
|
|
@@ -750,6 +752,7 @@ def __init__( | |
| client_kwargs["function_invocation_configuration"] = function_invocation_configuration | ||
|
|
||
| client = actual_client_type(**client_kwargs) | ||
| self._foundry_project_arm_id: str | None = None | ||
|
|
||
| super().__init__( | ||
| client=client, # type: ignore[arg-type] | ||
|
|
@@ -841,6 +844,22 @@ def _update_session_from_chat_response_update( | |
| if session is not None and isinstance(agent_session_id, str) and agent_session_id: | ||
| session.state[FOUNDRY_HOSTED_AGENT_SESSION_ID_KEY] = agent_session_id | ||
|
|
||
| async def _get_foundry_project_arm_id(self) -> str: | ||
| """Get the Foundry project ARM ID from its Application Insights connection.""" | ||
| client = cast(RawFoundryAgentChatClient, self.client) | ||
| # AIProjectClient does not expose the project ARM ID directly. Derive it from the | ||
| # project-scoped connection until https://github.com/Azure/azure-sdk-for-python/issues/48825 is addressed. | ||
| connections = client.project_client.connections.list(connection_type=ConnectionType.APPLICATION_INSIGHTS) | ||
| async for connection in connections: | ||
| connection_suffix = f"/connections/{connection.name}" | ||
| if not connection.id.lower().endswith(connection_suffix.lower()): | ||
| raise ValueError( | ||
| f"The Foundry Application Insights connection ID has an unexpected format: {connection.id!r}." | ||
| ) | ||
| return connection.id[: -len(connection_suffix)] | ||
|
|
||
| raise ValueError("The Foundry project does not have an Application Insights connection.") | ||
|
|
||
| async def configure_azure_monitor( | ||
| self, | ||
| enable_sensitive_data: bool = False, | ||
|
|
@@ -858,6 +877,8 @@ async def configure_azure_monitor( | |
|
|
||
| Raises: | ||
| ImportError: If azure-monitor-opentelemetry-exporter is not installed. | ||
| ValueError: If the Application Insights connection does not contain the expected | ||
| project-scoped ARM resource ID. | ||
| """ | ||
| from agent_framework.observability import ( | ||
| OBSERVABILITY_SETTINGS, | ||
|
|
@@ -897,6 +918,8 @@ async def configure_azure_monitor( | |
| "Install it with: pip install azure-monitor-opentelemetry" | ||
| ) from exc | ||
|
|
||
| self._foundry_project_arm_id = await self._get_foundry_project_arm_id() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so does calling this here, mean that only if you setup using this helper method this get's applied and things work? that's either something we need to document extra well, including the in the current samples, or something we need to rethink... (to be clear, I'm not opposed perse) |
||
|
|
||
| if "resource" not in kwargs: | ||
| kwargs["resource"] = create_resource() | ||
|
|
||
|
|
@@ -951,6 +974,18 @@ class FoundryAgent( # type: ignore[misc] | |
| ) | ||
| """ | ||
|
|
||
| @override | ||
| def _get_additional_otel_agent_attributes(self) -> Mapping[str, Any]: | ||
| """Return Foundry attributes required to discover the agent trace.""" | ||
| if self._foundry_project_arm_id: | ||
| return {_FOUNDRY_PROJECT_ARM_ID_ATTRIBUTE: self._foundry_project_arm_id} | ||
| return {} | ||
|
|
||
| @override | ||
| def _should_capture_agent_response_id(self) -> bool: | ||
| """Keep the response ID on the client agent span for Foundry trace discovery.""" | ||
| return True | ||
|
|
||
| def __init__( | ||
| self, | ||
| *, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this lookup degrade gracefully instead of aborting setup? The connection string has already been retrieved successfully, but the separate connections API can return no
APPLICATION_INSIGHTSentry, an unexpected ID shape, or its own service error. Any of those now preventsconfigure_azure_monitor()andenable_instrumentation()from running, so deployments that previously exported telemetry lose it entirely just because the optional Foundry project attribute cannot be derived. Please warn and continue configuring Azure Monitor without the project attribute when this lookup fails.