forked from microsoft/agent-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshared_state_middleware.py
More file actions
138 lines (109 loc) · 4.97 KB
/
shared_state_middleware.py
File metadata and controls
138 lines (109 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from collections.abc import Awaitable, Callable
from random import randint
from typing import Annotated
from agent_framework import (
FunctionInvocationContext,
tool,
)
from agent_framework.azure import AzureAIAgentClient
from azure.identity.aio import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
"""
Shared State Function-based MiddlewareTypes Example
This sample demonstrates how to implement function-based middleware within a class to share state.
The example includes:
- A MiddlewareContainer class with two simple function middleware methods
- First middleware: Counts function calls and stores the count in shared state
- Second middleware: Uses the shared count to add call numbers to function results
This approach shows how middleware can work together by sharing state within the same class instance.
"""
# 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 get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
@tool(approval_mode="never_require")
def get_time(
timezone: Annotated[str, Field(description="The timezone to get the time for.")] = "UTC",
) -> str:
"""Get the current time for a given timezone."""
import datetime
return f"The current time in {timezone} is {datetime.datetime.now().strftime('%H:%M:%S')}"
class MiddlewareContainer:
"""Container class that holds middleware functions with shared state."""
def __init__(self) -> None:
# Simple shared state: count function calls
self.call_count: int = 0
async def call_counter_middleware(
self,
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
"""First middleware: increments call count in shared state."""
# Increment the shared call count
self.call_count += 1
print(f"[CallCounter] This is function call #{self.call_count}")
# Call the next middleware/function
await call_next()
async def result_enhancer_middleware(
self,
context: FunctionInvocationContext,
call_next: Callable[[], Awaitable[None]],
) -> None:
"""Second middleware: uses shared call count to enhance function results."""
print(f"[ResultEnhancer] Current total calls so far: {self.call_count}")
# Call the next middleware/function
await call_next()
# After function execution, enhance the result using shared state
if context.result:
enhanced_result = f"[Call #{self.call_count}] {context.result}"
context.result = enhanced_result
print("[ResultEnhancer] Enhanced result with call number")
async def main() -> None:
"""Example demonstrating shared state function-based middleware."""
print("=== Shared State Function-based MiddlewareTypes Example ===")
# Create middleware container with shared state
middleware_container = MiddlewareContainer()
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
async with (
AzureCliCredential() as credential,
AzureAIAgentClient(credential=credential).as_agent(
name="UtilityAgent",
instructions="You are a helpful assistant that can provide weather information and current time.",
tools=[get_weather, get_time],
# Pass both middleware functions from the same container instance
# Order matters: counter runs first to increment count,
# then result enhancer uses the updated count
middleware=[
middleware_container.call_counter_middleware,
middleware_container.result_enhancer_middleware,
],
) as agent,
):
# Test multiple requests to see shared state in action
queries = [
"What's the weather like in New York?",
"What time is it in London?",
"What's the weather in Tokyo?",
]
for i, query in enumerate(queries, 1):
print(f"\n--- Query {i} ---")
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result.text if result.text else 'No response'}")
# Display final statistics
print("\n=== Final Statistics ===")
print(f"Total function calls made: {middleware_container.call_count}")
if __name__ == "__main__":
asyncio.run(main())