|
| 1 | +from agno.agent.agent import Agent |
| 2 | +from agno.models.openai.chat import OpenAIChat |
| 3 | +from agno.team import Team |
| 4 | + |
| 5 | + |
| 6 | +# Define tools to manage our shopping list |
| 7 | +def add_item(agent: Agent, item: str) -> str: |
| 8 | + """Add an item to the shopping list and return confirmation. |
| 9 | +
|
| 10 | + Args: |
| 11 | + item (str): The item to add to the shopping list. |
| 12 | + """ |
| 13 | + # Add the item if it's not already in the list |
| 14 | + if item.lower() not in [ |
| 15 | + i.lower() for i in agent.team_session_state["shopping_list"] |
| 16 | + ]: |
| 17 | + agent.team_session_state["shopping_list"].append(item) |
| 18 | + return f"Added '{item}' to the shopping list" |
| 19 | + else: |
| 20 | + return f"'{item}' is already in the shopping list" |
| 21 | + |
| 22 | + |
| 23 | +def remove_item(agent: Agent, item: str) -> str: |
| 24 | + """Remove an item from the shopping list by name. |
| 25 | +
|
| 26 | + Args: |
| 27 | + item (str): The item to remove from the shopping list. |
| 28 | + """ |
| 29 | + # Case-insensitive search |
| 30 | + for i, list_item in enumerate(agent.team_session_state["shopping_list"]): |
| 31 | + if list_item.lower() == item.lower(): |
| 32 | + agent.team_session_state["shopping_list"].pop(i) |
| 33 | + return f"Removed '{list_item}' from the shopping list" |
| 34 | + |
| 35 | + return f"'{item}' was not found in the shopping list. Current shopping list: {agent.team_session_state['shopping_list']}" |
| 36 | + |
| 37 | + |
| 38 | +def remove_all_items(agent: Agent) -> str: |
| 39 | + """Remove all items from the shopping list.""" |
| 40 | + agent.team_session_state["shopping_list"] = [] |
| 41 | + return "All items removed from the shopping list" |
| 42 | + |
| 43 | + |
| 44 | +shopping_list_agent = Agent( |
| 45 | + name="Shopping List Agent", |
| 46 | + role="Manage the shopping list", |
| 47 | + agent_id="shopping_list_manager", |
| 48 | + model=OpenAIChat(id="gpt-4o-mini"), |
| 49 | + tools=[add_item, remove_item, remove_all_items], |
| 50 | + instructions=[ |
| 51 | + "Manage the shopping list by adding and removing items", |
| 52 | + "Always confirm when items are added or removed", |
| 53 | + "If the task is done, update the session state to log the changes & chores you've performed", |
| 54 | + ], |
| 55 | +) |
| 56 | + |
| 57 | + |
| 58 | +# Shopping management team - new layer for handling all shopping list modifications |
| 59 | +shopping_mgmt_team = Team( |
| 60 | + name="Shopping Management Team", |
| 61 | + team_id="shopping_management", |
| 62 | + mode="coordinate", |
| 63 | + model=OpenAIChat(id="gpt-4o-mini"), |
| 64 | + show_tool_calls=True, |
| 65 | + members=[shopping_list_agent], |
| 66 | + instructions=[ |
| 67 | + "Manage adding and removing items from the shopping list using the Shopping List Agent", |
| 68 | + "Forward requests to add or remove items to the Shopping List Agent", |
| 69 | + ], |
| 70 | +) |
| 71 | + |
| 72 | + |
| 73 | +def get_ingredients(agent: Agent) -> str: |
| 74 | + """Retrieve ingredients from the shopping list to use for recipe suggestions. |
| 75 | +
|
| 76 | + Args: |
| 77 | + meal_type (str): Type of meal to suggest (breakfast, lunch, dinner, snack, or any) |
| 78 | + """ |
| 79 | + shopping_list = agent.team_session_state["shopping_list"] |
| 80 | + |
| 81 | + if not shopping_list: |
| 82 | + return "The shopping list is empty. Add some ingredients first to get recipe suggestions." |
| 83 | + |
| 84 | + # Just return the ingredients - the agent will create recipes |
| 85 | + return f"Available ingredients from shopping list: {', '.join(shopping_list)}" |
| 86 | + |
| 87 | + |
| 88 | +recipe_agent = Agent( |
| 89 | + name="Recipe Suggester", |
| 90 | + agent_id="recipe_suggester", |
| 91 | + role="Suggest recipes based on available ingredients", |
| 92 | + model=OpenAIChat(id="gpt-4o-mini"), |
| 93 | + tools=[get_ingredients], |
| 94 | + instructions=[ |
| 95 | + "First, use the get_ingredients tool to get the current ingredients from the shopping list", |
| 96 | + "After getting the ingredients, create detailed recipe suggestions based on those ingredients", |
| 97 | + "Create at least 3 different recipe ideas using the available ingredients", |
| 98 | + "For each recipe, include: name, ingredients needed (highlighting which ones are from the shopping list), and brief preparation steps", |
| 99 | + "Be creative but practical with recipe suggestions", |
| 100 | + "Consider common pantry items that people usually have available in addition to shopping list items", |
| 101 | + "Consider dietary preferences if mentioned by the user", |
| 102 | + "If no meal type is specified, suggest a variety of options (breakfast, lunch, dinner, snacks)", |
| 103 | + ], |
| 104 | +) |
| 105 | + |
| 106 | + |
| 107 | +def list_items(team: Team) -> str: |
| 108 | + """List all items in the shopping list.""" |
| 109 | + shopping_list = team.team_session_state["shopping_list"] |
| 110 | + |
| 111 | + if not shopping_list: |
| 112 | + return "The shopping list is empty." |
| 113 | + |
| 114 | + items_text = "\n".join([f"- {item}" for item in shopping_list]) |
| 115 | + return f"Current shopping list:\n{items_text}" |
| 116 | + |
| 117 | + |
| 118 | +# Create meal planning subteam |
| 119 | +meal_planning_team = Team( |
| 120 | + name="Meal Planning Team", |
| 121 | + team_id="meal_planning", |
| 122 | + mode="coordinate", |
| 123 | + model=OpenAIChat(id="gpt-4o-mini"), |
| 124 | + members=[recipe_agent], |
| 125 | + instructions=[ |
| 126 | + "You are a meal planning team that suggests recipes based on shopping list items.", |
| 127 | + "IMPORTANT: When users ask 'What can I make with these ingredients?' or any recipe-related questions, IMMEDIATELY forward the EXACT SAME request to the recipe_agent WITHOUT asking for further information.", |
| 128 | + "DO NOT ask the user for ingredients - the recipe_agent will work with what's already in the shopping list.", |
| 129 | + "Your primary job is to forward recipe requests directly to the recipe_agent without modification.", |
| 130 | + ], |
| 131 | +) |
| 132 | + |
| 133 | + |
| 134 | +def add_chore(team: Team, chore: str, priority: str = "medium") -> str: |
| 135 | + """Add a chore to the list with priority level. |
| 136 | +
|
| 137 | + Args: |
| 138 | + chore (str): The chore to add to the list |
| 139 | + priority (str): Priority level of the chore (low, medium, high) |
| 140 | +
|
| 141 | + Returns: |
| 142 | + str: Confirmation message |
| 143 | + """ |
| 144 | + # Initialize chores list if it doesn't exist |
| 145 | + if "chores" not in team.session_state: |
| 146 | + team.session_state["chores"] = [] |
| 147 | + |
| 148 | + # Validate priority |
| 149 | + valid_priorities = ["low", "medium", "high"] |
| 150 | + if priority.lower() not in valid_priorities: |
| 151 | + priority = "medium" # Default to medium if invalid |
| 152 | + |
| 153 | + # Add the chore with timestamp and priority |
| 154 | + from datetime import datetime |
| 155 | + |
| 156 | + chore_entry = { |
| 157 | + "description": chore, |
| 158 | + "priority": priority.lower(), |
| 159 | + "added_at": datetime.now().strftime("%Y-%m-%d %H:%M"), |
| 160 | + } |
| 161 | + |
| 162 | + team.session_state["chores"].append(chore_entry) |
| 163 | + |
| 164 | + return f"Added chore: '{chore}' with {priority} priority" |
| 165 | + |
| 166 | + |
| 167 | +shopping_team = Team( |
| 168 | + name="Shopping List Team", |
| 169 | + mode="coordinate", |
| 170 | + model=OpenAIChat(id="gpt-4o-mini"), |
| 171 | + team_session_state={"shopping_list": []}, |
| 172 | + tools=[list_items, add_chore], |
| 173 | + session_state={"chores": []}, |
| 174 | + team_id="shopping_list_team", |
| 175 | + members=[ |
| 176 | + shopping_mgmt_team, |
| 177 | + meal_planning_team, |
| 178 | + ], |
| 179 | + show_tool_calls=True, |
| 180 | + markdown=True, |
| 181 | + instructions=[ |
| 182 | + "You are a team that manages a shopping list & helps plan meals using that list.", |
| 183 | + "If you need to add or remove items from the shopping list, forward the full request to the Shopping Management Team.", |
| 184 | + "IMPORTANT: If the user asks about recipes or what they can make with ingredients, IMMEDIATELY forward the EXACT request to the meal_planning_team with NO additional questions.", |
| 185 | + "Example: When user asks 'What can I make with these ingredients?', you should simply forward this exact request to meal_planning_team without asking for more information.", |
| 186 | + "If you need to list the items in the shopping list, use the list_items tool.", |
| 187 | + "If the user got something from the shopping list, it means it can be removed from the shopping list.", |
| 188 | + "After each completed task, use the add_chore tool to log exactly what was done with high priority.", |
| 189 | + ], |
| 190 | + show_members_responses=True, |
| 191 | +) |
| 192 | + |
| 193 | +# Example usage |
| 194 | +shopping_team.print_response( |
| 195 | + "Add milk, eggs, and bread to the shopping list", stream=True |
| 196 | +) |
| 197 | +print(f"Session state: {shopping_team.team_session_state}") |
| 198 | + |
| 199 | +shopping_team.print_response("I got bread", stream=True) |
| 200 | +print(f"Session state: {shopping_team.team_session_state}") |
| 201 | + |
| 202 | +shopping_team.print_response("I need apples and oranges", stream=True) |
| 203 | +print(f"Session state: {shopping_team.team_session_state}") |
| 204 | + |
| 205 | +shopping_team.print_response("whats on my list?", stream=True) |
| 206 | +print(f"Session state: {shopping_team.team_session_state}") |
| 207 | + |
| 208 | +# Try the meal planning feature |
| 209 | +shopping_team.print_response("What can I make with these ingredients?", stream=True) |
| 210 | +print(f"Session state: {shopping_team.team_session_state}") |
| 211 | + |
| 212 | +shopping_team.print_response( |
| 213 | + "Clear everything from my list and start over with just bananas and yogurt", |
| 214 | + stream=True, |
| 215 | +) |
| 216 | +print(f"Shared Session state: {shopping_team.team_session_state}") |
| 217 | + |
| 218 | + |
| 219 | +print(f"Team session state: {shopping_team.session_state}") |
0 commit comments