Spaces:
Running on Zero
Running on Zero
| from typing import Optional, List, Dict | |
| from agents.agent import Agent | |
| from agents.deals import Deal, Opportunity | |
| from agents.scanner_agent import ScannerAgent | |
| from agents.ensemble_agent import EnsembleAgent | |
| from agents.messaging_agent import MessagingAgent | |
| from openai import OpenAI | |
| import json | |
| class AutonomousPlanningAgent(Agent): | |
| name = "Autonomous Planning Agent" | |
| color = Agent.GREEN | |
| MODEL = "gpt-5.1" | |
| def __init__(self, collection): | |
| """ | |
| Create instances of the 3 Agents that this planner coordinates across | |
| """ | |
| self.log("Autonomous Planning Agent is initializing") | |
| self.scanner = ScannerAgent() | |
| self.ensemble = EnsembleAgent(collection) | |
| self.messenger = MessagingAgent() | |
| self.openai = OpenAI() | |
| self.memory = None | |
| self.opportunity = None | |
| self.log("Autonomous Planning Agent is ready") | |
| def scan_the_internet_for_bargains(self) -> str: | |
| """ | |
| Run the tool to scan | |
| """ | |
| self.log("Autonomous Planning agent is calling scanner") | |
| results = self.scanner.scan(memory=self.memory) | |
| return results.model_dump_json() if results else "No deals found" | |
| def estimate_true_value(self, description: str) -> str: | |
| """ | |
| Run the tool to estimate true value | |
| """ | |
| self.log("Autonomous Planning agent is estimating value via Ensemble Agent") | |
| estimate = self.ensemble.price(description) | |
| return f"The estimated true value of {description} is {estimate}" | |
| def notify_user_of_deal( | |
| self, description: str, deal_price: float, estimated_true_value: float, url: str | |
| ) -> Dict: | |
| """ | |
| Run the tool to notify the user | |
| """ | |
| if self.opportunity: | |
| self.log("Autonomous Planning agent is trying to notify the user a 2nd time; ignoring") | |
| else: | |
| self.log("Autonomous Planning agent is notifying user") | |
| self.messenger.notify(description, deal_price, estimated_true_value, url) | |
| deal = Deal(product_description=description, price=deal_price, url=url) | |
| discount = estimated_true_value - deal_price | |
| self.opportunity = Opportunity( | |
| deal=deal, estimate=estimated_true_value, discount=discount | |
| ) | |
| return "Notification sent ok" | |
| scan_function = { | |
| "name": "scan_the_internet_for_bargains", | |
| "description": "Returns top bargains scraped from the internet along with the price each item is being offered for", | |
| "parameters": { | |
| "type": "object", | |
| "properties": {}, | |
| "required": [], | |
| "additionalProperties": False, | |
| }, | |
| } | |
| estimate_function = { | |
| "name": "estimate_true_value", | |
| "description": "Given the description of an item, estimate how much it is actually worth", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "description": { | |
| "type": "string", | |
| "description": "The description of the item to be estimated", | |
| }, | |
| }, | |
| "required": ["description"], | |
| "additionalProperties": False, | |
| }, | |
| } | |
| notify_function = { | |
| "name": "notify_user_of_deal", | |
| "description": "Send the user a push notification about the single most compelling deal; only call this one time", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "description": { | |
| "type": "string", | |
| "description": "The description of the item itself scraped from the internet", | |
| }, | |
| "deal_price": { | |
| "type": "number", | |
| "description": "The price offered by this deal scraped from the internet", | |
| }, | |
| "estimated_true_value": { | |
| "type": "number", | |
| "description": "The estimated actual value that this is worth", | |
| }, | |
| "url": { | |
| "type": "string", | |
| "description": "The URL of this deal as scraped from the internet", | |
| }, | |
| }, | |
| "required": ["description", "deal_price", "estimated_true_value", "url"], | |
| "additionalProperties": False, | |
| }, | |
| } | |
| def get_tools(self): | |
| """ | |
| Return the json for the tools to be used | |
| """ | |
| return [ | |
| {"type": "function", "function": self.scan_function}, | |
| {"type": "function", "function": self.estimate_function}, | |
| {"type": "function", "function": self.notify_function}, | |
| ] | |
| def handle_tool_call(self, message): | |
| """ | |
| Actually call the tools associated with this message | |
| """ | |
| mapping = { | |
| "scan_the_internet_for_bargains": self.scan_the_internet_for_bargains, | |
| "estimate_true_value": self.estimate_true_value, | |
| "notify_user_of_deal": self.notify_user_of_deal, | |
| } | |
| results = [] | |
| for tool_call in message.tool_calls: | |
| tool_name = tool_call.function.name | |
| arguments = json.loads(tool_call.function.arguments) | |
| tool = mapping.get(tool_name) | |
| result = tool(**arguments) if tool else "" | |
| results.append({"role": "tool", "content": result, "tool_call_id": tool_call.id}) | |
| return results | |
| system_message = "You find great deals on bargain products using your tools, and notify the user of the best bargain." | |
| user_message = """ | |
| First, use your tool to scan the internet for bargain deals. Then for each deal, use your tool to estimate its true value. | |
| Then pick the single most compelling deal where the price is much lower than the estimated true value, and use your tool to notify the user. | |
| Then just reply OK to indicate success. | |
| """ | |
| messages = [ | |
| {"role": "system", "content": system_message}, | |
| {"role": "user", "content": user_message}, | |
| ] | |
| def plan(self, memory: List[str] = []) -> Optional[Opportunity]: | |
| """ | |
| Run the full workflow, providing the LLM with tools to surface scraped deals to the user | |
| :param memory: a list of URLs that have been surfaced in the past | |
| :return: an Opportunity if one was surfaced, otherwise None | |
| """ | |
| self.log("Autonomous Planning Agent is kicking off a run") | |
| self.memory = memory | |
| self.opportunity = None | |
| messages = self.messages[:] | |
| done = False | |
| while not done: | |
| response = self.openai.chat.completions.create( | |
| model=self.MODEL, messages=messages, tools=self.get_tools() | |
| ) | |
| if response.choices[0].finish_reason == "tool_calls": | |
| message = response.choices[0].message | |
| results = self.handle_tool_call(message) | |
| messages.append(message) | |
| messages.extend(results) | |
| else: | |
| done = True | |
| reply = response.choices[0].message.content | |
| self.log(f"Autonomous Planning Agent completed with: {reply}") | |
| return self.opportunity | |