forked from microsoft/agent-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
131 lines (102 loc) · 4.41 KB
/
main.py
File metadata and controls
131 lines (102 loc) · 4.41 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
# Copyright (c) Microsoft. All rights reserved.
"""
Demonstrate a workflow that responds to user input using an agent with
function tools assigned. Exits the loop when the user enters "exit".
"""
import asyncio
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Annotated, Any
from agent_framework import FileCheckpointStorage, tool
from agent_framework.azure import AzureOpenAIResponsesClient
from agent_framework_declarative import ExternalInputRequest, ExternalInputResponse, WorkflowFactory
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from pydantic import Field
# Load environment variables from .env file
load_dotenv()
TEMP_DIR = Path(__file__).with_suffix("").parent / "tmp" / "checkpoints"
TEMP_DIR.mkdir(parents=True, exist_ok=True)
@dataclass
class MenuItem:
category: str
name: str
price: float
is_special: bool = False
MENU_ITEMS = [
MenuItem(category="Soup", name="Clam Chowder", price=4.95, is_special=True),
MenuItem(category="Soup", name="Tomato Soup", price=4.95, is_special=False),
MenuItem(category="Salad", name="Cobb Salad", price=9.99, is_special=False),
MenuItem(category="Salad", name="House Salad", price=4.95, is_special=False),
MenuItem(category="Drink", name="Chai Tea", price=2.95, is_special=True),
MenuItem(category="Drink", name="Soda", price=1.95, is_special=False),
]
# 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_menu() -> list[dict[str, Any]]:
"""Get all menu items."""
return [{"category": i.category, "name": i.name, "price": i.price} for i in MENU_ITEMS]
@tool(approval_mode="never_require")
def get_specials() -> list[dict[str, Any]]:
"""Get today's specials."""
return [{"category": i.category, "name": i.name, "price": i.price} for i in MENU_ITEMS if i.is_special]
@tool(approval_mode="never_require")
def get_item_price(name: Annotated[str, Field(description="Menu item name")]) -> str:
"""Get price of a menu item."""
for item in MENU_ITEMS:
if item.name.lower() == name.lower():
return f"${item.price:.2f}"
return f"Item '{name}' not found."
async def main():
# Create agent with tools
client = AzureOpenAIResponsesClient(
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
credential=AzureCliCredential(),
)
menu_agent = client.as_agent(
name="MenuAgent",
instructions="Answer questions about menu items, specials, and prices.",
tools=[get_menu, get_specials, get_item_price],
)
# Clean up any existing checkpoints
for file in TEMP_DIR.glob("*"):
file.unlink()
factory = WorkflowFactory(checkpoint_storage=FileCheckpointStorage(TEMP_DIR))
factory.register_agent("MenuAgent", menu_agent)
workflow = factory.create_workflow_from_yaml_path(Path(__file__).parent / "workflow.yaml")
# Get initial input
print("Restaurant Menu Assistant (type 'exit' to quit)\n")
user_input = input("You: ").strip() # noqa: ASYNC250
if not user_input:
return
# Run workflow with external loop handling
pending_request_id: str | None = None
first_response = True
while True:
if pending_request_id:
response = ExternalInputResponse(user_input=user_input)
stream = workflow.run(stream=True, responses={pending_request_id: response})
else:
stream = workflow.run({"userInput": user_input}, stream=True)
pending_request_id = None
first_response = True
async for event in stream:
if event.type == "output" and isinstance(event.data, str):
if first_response:
print("MenuAgent: ", end="")
first_response = False
print(event.data, end="", flush=True)
elif event.type == "request_info" and isinstance(event.data, ExternalInputRequest):
pending_request_id = event.request_id
print()
if not pending_request_id:
break
user_input = input("\nYou: ").strip()
if not user_input:
continue
if __name__ == "__main__":
asyncio.run(main())