# Copyright (c) Microsoft. All rights reserved. import asyncio from collections.abc import Awaitable, Callable from typing import Annotated from agent_framework import Agent, FunctionInvocationContext, tool from agent_framework.foundry import FoundryChatClient from azure.identity.aio import AzureCliCredential from dotenv import load_dotenv from pydantic import Field # Load environment variables from .env file load_dotenv() """ Exception Handling with MiddlewareTypes This sample demonstrates how to use middleware for centralized exception handling in function calls. The example shows: - How to catch exceptions thrown by functions and provide graceful error responses - Overriding function results when errors occur to provide user-friendly messages - Using middleware to implement retry logic, fallback mechanisms, or error reporting The middleware catches TimeoutError from an unstable data service and replaces it with a helpful message for the user, preventing raw exceptions from reaching the end user. """ # NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; # see samples/02-agents/tools/function_tool_with_approval.py # and samples/02-agents/tools/function_tool_with_approval_and_sessions.py. @tool(approval_mode="never_require") def unstable_data_service( query: Annotated[str, Field(description="The data query to execute.")], ) -> str: """A simulated data service that sometimes throws exceptions.""" # Simulate failure raise TimeoutError("Data service request timed out") async def exception_handling_middleware( context: FunctionInvocationContext, call_next: Callable[[], Awaitable[None]] ) -> None: function_name = context.function.name try: print(f"[ExceptionHandlingMiddleware] Executing function: {function_name}") await call_next() print(f"[ExceptionHandlingMiddleware] Function {function_name} completed successfully.") except TimeoutError as e: print(f"[ExceptionHandlingMiddleware] Caught TimeoutError: {e}") # Override function result to provide custom message in response. context.result = ( "Request Timeout: The data service is taking longer than expected to respond." "Respond with message - 'Sorry for the inconvenience, please try again later.'" ) async def main() -> None: """Example demonstrating exception handling with middleware.""" print("=== Exception Handling MiddlewareTypes Example ===") # For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred # authentication option. async with ( AzureCliCredential() as credential, Agent( client=FoundryChatClient(credential=credential), name="DataAgent", instructions="You are a helpful data assistant. Use the data service tool to fetch information for users.", tools=unstable_data_service, middleware=[exception_handling_middleware], ) as agent, ): query = "Get user statistics" print(f"User: {query}") result = await agent.run(query) print(f"Agent: {result}") if __name__ == "__main__": asyncio.run(main())