From fdfcb6385d025fcb3e6cf6ded77a9936a7394be7 Mon Sep 17 00:00:00 2001 From: Rahul Devikar Date: Tue, 27 Jan 2026 12:01:23 -0800 Subject: [PATCH 1/2] Fix python SF sample --- .../sample-agent/ToolingManifest.json | 5 +--- python/agent-framework/sample-agent/agent.py | 12 +++++++- .../sample-agent/host_agent_server.py | 28 +++++++++++++++---- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/python/agent-framework/sample-agent/ToolingManifest.json b/python/agent-framework/sample-agent/ToolingManifest.json index e842561c..9d5cacf2 100644 --- a/python/agent-framework/sample-agent/ToolingManifest.json +++ b/python/agent-framework/sample-agent/ToolingManifest.json @@ -2,10 +2,7 @@ "mcpServers": [ { "mcpServerName": "mcp_MailTools", - "mcpServerUniqueName": "mcp_MailTools", - "url": "https://agent365.svc.cloud.microsoft/agents/servers/mcp_MailTools", - "scope": "McpServers.Mail.All", - "audience": "ea9ffc3e-8a23-4a7d-836d-234d7c7565c1" + "mcpServerUniqueName": "mcp_MailTools" } ] } \ No newline at end of file diff --git a/python/agent-framework/sample-agent/agent.py b/python/agent-framework/sample-agent/agent.py index 87715206..977ea1d8 100644 --- a/python/agent-framework/sample-agent/agent.py +++ b/python/agent-framework/sample-agent/agent.py @@ -120,6 +120,7 @@ def _create_chat_client(self): endpoint = os.getenv("AZURE_OPENAI_ENDPOINT") deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT") api_version = os.getenv("AZURE_OPENAI_API_VERSION") + api_key = os.getenv("AZURE_OPENAI_API_KEY") if not endpoint: raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required") @@ -130,9 +131,18 @@ def _create_chat_client(self): "AZURE_OPENAI_API_VERSION environment variable is required" ) + # Use API key if provided, otherwise fall back to Azure CLI credential + if api_key: + from azure.core.credentials import AzureKeyCredential + credential = AzureKeyCredential(api_key) + logger.info("Using API key authentication for Azure OpenAI") + else: + credential = AzureCliCredential() + logger.info("Using Azure CLI authentication for Azure OpenAI") + self.chat_client = AzureOpenAIChatClient( endpoint=endpoint, - credential=AzureCliCredential(), + credential=credential, deployment_name=deployment, api_version=api_version, ) diff --git a/python/agent-framework/sample-agent/host_agent_server.py b/python/agent-framework/sample-agent/host_agent_server.py index b6f4353c..f075270f 100644 --- a/python/agent-framework/sample-agent/host_agent_server.py +++ b/python/agent-framework/sample-agent/host_agent_server.py @@ -91,7 +91,13 @@ def __init__(self, agent_class: type[AgentInterface], *agent_args, **agent_kwarg f"Agent class {agent_class.__name__} must inherit from AgentInterface" ) - self.auth_handler_name = "AGENTIC" + # Auth handler name can be configured via environment + # Defaults to empty (no auth handler) - set AUTH_HANDLER_NAME=AGENTIC for production agentic auth + self.auth_handler_name = os.getenv("AUTH_HANDLER_NAME", "") or None + if self.auth_handler_name: + logger.info(f"🔐 Using auth handler: {self.auth_handler_name}") + else: + logger.info("🔓 No auth handler configured (AUTH_HANDLER_NAME not set)") self.agent_class = agent_class self.agent_args = agent_args @@ -118,19 +124,28 @@ def __init__(self, agent_class: type[AgentInterface], *agent_args, **agent_kwarg async def _setup_observability_token( self, context: TurnContext, tenant_id: str, agent_id: str ): + # Only attempt token exchange when auth handler is configured + if not self.auth_handler_name: + logger.debug("Skipping observability token exchange (no auth handler)") + return + try: + logger.info(f"🔐 Attempting token exchange for observability...") exaau_token = await self.agent_app.auth.exchange_token( context, scopes=get_observability_authentication_scope(), auth_handler_id=self.auth_handler_name, ) cache_agentic_token(tenant_id, agent_id, exaau_token.token) + logger.info(f"✅ Token exchange successful") except Exception as e: logger.warning(f"⚠️ Failed to cache observability token: {e}") async def _validate_agent_and_setup_context(self, context: TurnContext): + logger.info(f"🔍 Validating agent and setting up context...") tenant_id = context.activity.recipient.tenant_id agent_id = context.activity.recipient.agentic_app_id + logger.info(f"🔍 tenant_id={tenant_id}, agent_id={agent_id}") if not self.agent_instance: logger.error("Agent not available") @@ -143,7 +158,8 @@ async def _validate_agent_and_setup_context(self, context: TurnContext): # --- Handlers (Messages & Notifications) --- def _setup_handlers(self): """Setup message and notification handlers""" - handler = [self.auth_handler_name] + # Configure auth handlers - only required when auth_handler_name is set + handler_config = {"auth_handlers": [self.auth_handler_name]} if self.auth_handler_name else {} async def help_handler(context: TurnContext, _: TurnState): await context.send_activity( @@ -151,10 +167,10 @@ async def help_handler(context: TurnContext, _: TurnState): "How can I help you today?" ) - self.agent_app.conversation_update("membersAdded", auth_handlers=handler)(help_handler) - self.agent_app.message("/help", auth_handlers=handler)(help_handler) + self.agent_app.conversation_update("membersAdded", **handler_config)(help_handler) + self.agent_app.message("/help", **handler_config)(help_handler) - @self.agent_app.activity("message", auth_handlers=handler) + @self.agent_app.activity("message", **handler_config) async def on_message(context: TurnContext, _: TurnState): try: result = await self._validate_agent_and_setup_context(context) @@ -179,7 +195,7 @@ async def on_message(context: TurnContext, _: TurnState): @self.agent_notification.on_agent_notification( channel_id=ChannelId(channel="agents", sub_channel="*"), - auth_handlers=handler, + **handler_config, ) async def on_notification( context: TurnContext, From 9464cf1f13c86db20e29341dcd667e07ab202623 Mon Sep 17 00:00:00 2001 From: Rahul Devikar Date: Tue, 27 Jan 2026 16:09:06 -0800 Subject: [PATCH 2/2] fix: address PR review comments - Remove unnecessary f-prefix from log messages without interpolation - Add context (tenant_id, agent_id) to observability token log messages - Update type hints to use Optional[str] for auth_handler_name - Document AUTH_HANDLER_NAME in .env.template --- python/agent-framework/sample-agent/.env.template | 6 +++++- python/agent-framework/sample-agent/agent.py | 7 ++++--- .../agent-framework/sample-agent/agent_interface.py | 4 +++- .../sample-agent/host_agent_server.py | 12 +++++++++--- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/python/agent-framework/sample-agent/.env.template b/python/agent-framework/sample-agent/.env.template index 07f3d5c2..b7cd2aaf 100644 --- a/python/agent-framework/sample-agent/.env.template +++ b/python/agent-framework/sample-agent/.env.template @@ -3,8 +3,12 @@ OPENAI_API_KEY= MCP_SERVER_HOST= MCP_PLATFORM_ENDPOINT= -# Logging +# Authentication Handler Configuration +# Set to "AGENTIC" for production agentic auth, or leave empty for no auth handler +AUTH_HANDLER_NAME= + +# Logging LOG_LEVEL=INFO # Observability Configuration diff --git a/python/agent-framework/sample-agent/agent.py b/python/agent-framework/sample-agent/agent.py index 977ea1d8..f393cbac 100644 --- a/python/agent-framework/sample-agent/agent.py +++ b/python/agent-framework/sample-agent/agent.py @@ -20,6 +20,7 @@ import asyncio import logging import os +from typing import Optional from dotenv import load_dotenv @@ -203,7 +204,7 @@ def _initialize_services(self): logger.warning(f"⚠️ MCP tool service failed: {e}") self.tool_service = None - async def setup_mcp_servers(self, auth: Authorization, auth_handler_name: str, context: TurnContext): + async def setup_mcp_servers(self, auth: Authorization, auth_handler_name: Optional[str], context: TurnContext): """Set up MCP server connections""" if self.mcp_servers_initialized: return @@ -256,7 +257,7 @@ async def initialize(self): logger.info("Agent initialized") async def process_user_message( - self, message: str, auth: Authorization, auth_handler_name: str, context: TurnContext + self, message: str, auth: Authorization, auth_handler_name: Optional[str], context: TurnContext ) -> str: """Process user message using the AgentFramework SDK""" try: @@ -275,7 +276,7 @@ async def process_user_message( # async def handle_agent_notification_activity( - self, notification_activity, auth: Authorization, auth_handler_name: str, context: TurnContext + self, notification_activity, auth: Authorization, auth_handler_name: Optional[str], context: TurnContext ) -> str: """Handle agent notification activities (email, Word mentions, etc.)""" try: diff --git a/python/agent-framework/sample-agent/agent_interface.py b/python/agent-framework/sample-agent/agent_interface.py index 36b889c0..9fb61166 100644 --- a/python/agent-framework/sample-agent/agent_interface.py +++ b/python/agent-framework/sample-agent/agent_interface.py @@ -6,6 +6,8 @@ """ from abc import ABC, abstractmethod +from typing import Optional + from microsoft_agents.hosting.core import Authorization, TurnContext @@ -24,7 +26,7 @@ async def initialize(self) -> None: @abstractmethod async def process_user_message( - self, message: str, auth: Authorization, auth_handler_name: str, context: TurnContext + self, message: str, auth: Authorization, auth_handler_name: Optional[str], context: TurnContext ) -> str: """Process a user message and return a response.""" pass diff --git a/python/agent-framework/sample-agent/host_agent_server.py b/python/agent-framework/sample-agent/host_agent_server.py index f075270f..00a80375 100644 --- a/python/agent-framework/sample-agent/host_agent_server.py +++ b/python/agent-framework/sample-agent/host_agent_server.py @@ -130,19 +130,25 @@ async def _setup_observability_token( return try: - logger.info(f"🔐 Attempting token exchange for observability...") + logger.info( + f"🔐 Attempting token exchange for observability... " + f"(tenant_id={tenant_id}, agent_id={agent_id})" + ) exaau_token = await self.agent_app.auth.exchange_token( context, scopes=get_observability_authentication_scope(), auth_handler_id=self.auth_handler_name, ) cache_agentic_token(tenant_id, agent_id, exaau_token.token) - logger.info(f"✅ Token exchange successful") + logger.info( + f"✅ Token exchange successful " + f"(tenant_id={tenant_id}, agent_id={agent_id})" + ) except Exception as e: logger.warning(f"⚠️ Failed to cache observability token: {e}") async def _validate_agent_and_setup_context(self, context: TurnContext): - logger.info(f"🔍 Validating agent and setting up context...") + logger.info("🔍 Validating agent and setting up context...") tenant_id = context.activity.recipient.tenant_id agent_id = context.activity.recipient.agentic_app_id logger.info(f"🔍 tenant_id={tenant_id}, agent_id={agent_id}")