helloparthshah Kunal Pai harshil-21 commited on
Commit
6900003
·
1 Parent(s): cab9413

QOL updates and refactoring. Also fixed the tool/agent budgeting

Browse files

Co-authored-by: Kunal Pai <kunpai@users.noreply.github.com>
Co-authored-by: Harshil Patel <hpppatel@ucdavis.edu>

bench/benchmarking_connections.py CHANGED
@@ -72,7 +72,7 @@ def benchmark_nyt_connections(num_samples=20, categories=None):
72
  if categories and sample["category"] not in categories:
73
  continue
74
  print(f"Sample {i}: {sample['contest']}")
75
- prompt = f"Given the following words, group them into 4 categories of 4 words each:\n{' '.join(sample['words'])}\n\n"
76
  start_time = time.time()
77
  response = client.predict(messages=[{"role": "user", "content": prompt}], api_name="/run")
78
  end_time = time.time()
 
72
  if categories and sample["category"] not in categories:
73
  continue
74
  print(f"Sample {i}: {sample['contest']}")
75
+ prompt = f"Given the following words, group them into 4 categories of 4 words each:\n{' '.join(sample['words'])}\n\n Once you've solved it, final output should be in the following format Group 1: word1, word2, word3, word4\nGroup 2: ..."
76
  start_time = time.time()
77
  response = client.predict(messages=[{"role": "user", "content": prompt}], api_name="/run")
78
  end_time = time.time()
default_tools/fire_agent.py CHANGED
@@ -1,4 +1,3 @@
1
- from src.budget_manager import BudgetManager
2
  from src.agent_manager import AgentManager
3
 
4
  __all__ = ['FireAgent']
 
 
1
  from src.agent_manager import AgentManager
2
 
3
  __all__ = ['FireAgent']
default_tools/get_budget.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ __all__ = ['GetBudget']
3
+
4
+ from src.budget_manager import BudgetManager
5
+
6
+
7
+ class GetBudget():
8
+ dependencies = []
9
+
10
+ inputSchema = {
11
+ "name": "GetBudget",
12
+ "description": "Retrieves the current budget available.",
13
+ "parameters": {
14
+ "type": "object",
15
+ "properties":{},
16
+ "required": [],
17
+ },
18
+ }
19
+
20
+
21
+ def run(self, **kwargs):
22
+ budget_manager = BudgetManager()
23
+ total_budget = budget_manager.get_total_budget()
24
+ current_expense = budget_manager.get_current_expense()
25
+ current_remaining_budget = budget_manager.get_current_remaining_budget()
26
+ return {
27
+ "status": "success",
28
+ "message": "Budget retrieved successfully",
29
+ "output": {
30
+ "total_budget": total_budget,
31
+ "current_expense": current_expense,
32
+ "current_remaining_budget": current_remaining_budget
33
+ }
34
+ }
35
+
main.py CHANGED
@@ -1,6 +1,6 @@
1
  from google.genai import types
2
  from src.manager import GeminiManager
3
- from src.tool_loader import ToolLoader
4
  import gradio as gr
5
  import time
6
  import base64
@@ -22,11 +22,7 @@ _header_html = f"""
22
  """
23
 
24
  if __name__ == "__main__":
25
- # Define the tool metadata for orchestration.
26
- # Load the tools using the ToolLoader class.
27
- tool_loader = ToolLoader()
28
-
29
- model_manager = GeminiManager(toolsLoader=tool_loader, gemini_model="gemini-2.0-flash")
30
 
31
  def user_message(msg: str, history: list) -> tuple[str, list]:
32
  """Adds user message to chat history"""
@@ -54,7 +50,7 @@ if __name__ == "__main__":
54
  css = """
55
  #title-row { background: #2c2c2c; border-radius: 8px; padding: 8px; }
56
  """
57
- with gr.Blocks(css=css) as demo:
58
  with gr.Row():
59
  gr.HTML(_header_html)
60
  model_dropdown = gr.Dropdown(
@@ -67,7 +63,7 @@ if __name__ == "__main__":
67
  ],
68
  value="HASHIRU",
69
  # label="HASHIRU",
70
- scale=4,
71
  interactive=True,
72
  )
73
 
 
1
  from google.genai import types
2
  from src.manager import GeminiManager
3
+ from src.tool_manager import ToolManager
4
  import gradio as gr
5
  import time
6
  import base64
 
22
  """
23
 
24
  if __name__ == "__main__":
25
+ model_manager = GeminiManager(gemini_model="gemini-2.0-flash")
 
 
 
 
26
 
27
  def user_message(msg: str, history: list) -> tuple[str, list]:
28
  """Adds user message to chat history"""
 
50
  css = """
51
  #title-row { background: #2c2c2c; border-radius: 8px; padding: 8px; }
52
  """
53
+ with gr.Blocks(css=css, fill_width=True, fill_height=True) as demo:
54
  with gr.Row():
55
  gr.HTML(_header_html)
56
  model_dropdown = gr.Dropdown(
 
63
  ],
64
  value="HASHIRU",
65
  # label="HASHIRU",
66
+ scale=2,
67
  interactive=True,
68
  )
69
 
src/agent_manager.py CHANGED
@@ -95,9 +95,9 @@ class GeminiAgent(Agent):
95
  self.messages = []
96
  @singleton
97
  class AgentManager():
98
- budget_manager = BudgetManager()
99
  def __init__(self):
100
- self._agents = {}
101
  self._agent_types ={
102
  "ollama": OllamaAgent,
103
  "gemini": GeminiAgent
@@ -111,19 +111,15 @@ class AgentManager():
111
  if agent_name in self._agents:
112
  raise ValueError(f"Agent {agent_name} already exists")
113
 
114
- agent_type = self._get_agent_type(base_model)
115
- agent_class = self._agent_types.get(agent_type)
116
-
117
- if not agent_class:
118
- raise ValueError(f"Unsupported base model {base_model}")
119
-
120
- if not self.budget_manager.can_spend(create_cost):
121
- raise ValueError(f"Do not have enough budget to create the tool. "
122
- +f"Creating the tool costs {create_cost} but only {self.budget_manager.get_current_remaining_budget()} is remaining")
123
-
124
- self.budget_manager.add_to_expense(create_cost)
125
- # create agent
126
- self._agents[agent_name] = agent_class(agent_name, base_model, system_prompt, create_cost,invoke_cost )
127
 
128
  #save agent to file
129
  self._save_agent(
@@ -135,9 +131,28 @@ class AgentManager():
135
  invoke_cost=invoke_cost,
136
  **additional_params # For any future parameters we might want to add
137
  )
138
-
139
  return (self._agents[agent_name], self.budget_manager.get_current_remaining_budget())
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  def get_agent(self, agent_name: str) -> Agent:
142
  """Get existing agent by name"""
143
  if agent_name not in self._agents:
@@ -167,12 +182,10 @@ class AgentManager():
167
  return {}
168
 
169
  def delete_agent(self, agent_name: str) -> int:
170
- if agent_name not in self._agents:
171
- raise ValueError(f"Agent {agent_name} does not exist")
172
-
173
- self.budget_manager.add_to_expense(-1 * self._agents[agent_name].creation_cost)
174
- self._agents[agent_name].delete_agent()
175
 
 
 
176
 
177
  del self._agents[agent_name]
178
  try:
@@ -188,12 +201,10 @@ class AgentManager():
188
  return self.budget_manager.get_current_remaining_budget()
189
 
190
  def ask_agent(self, agent_name: str, prompt: str) -> Tuple[str,int]:
191
- agent = self._agents[agent_name]
192
-
193
- if not self.budget_manager.can_spend(agent.invoke_cost):
194
- raise ValueError(f"Do not have enough budget to ask Agent {agent_name} a question. "
195
- +f"Asking Agent {agent_name} costs {agent.invoke_cost} but only {self.budget_manager.get_current_remaining_budget()} is remaining")
196
 
 
 
197
  response = agent.ask_agent(prompt)
198
  return (response, self.budget_manager.get_current_remaining_budget())
199
 
@@ -264,6 +275,15 @@ class AgentManager():
264
 
265
  if manager_class:
266
  # Create the agent with the appropriate manager class
 
 
 
 
 
 
 
 
 
267
  self._agents[name] = manager_class(
268
  name,
269
  base_model,
 
95
  self.messages = []
96
  @singleton
97
  class AgentManager():
98
+ budget_manager: BudgetManager = BudgetManager()
99
  def __init__(self):
100
+ self._agents: Dict[str, Agent] = {}
101
  self._agent_types ={
102
  "ollama": OllamaAgent,
103
  "gemini": GeminiAgent
 
111
  if agent_name in self._agents:
112
  raise ValueError(f"Agent {agent_name} already exists")
113
 
114
+ self._agents[agent_name] = self.create_agent_class(
115
+ agent_name,
116
+ base_model,
117
+ system_prompt,
118
+ description=description,
119
+ create_cost=create_cost,
120
+ invoke_cost=invoke_cost,
121
+ **additional_params # For any future parameters we might want to add
122
+ )
 
 
 
 
123
 
124
  #save agent to file
125
  self._save_agent(
 
131
  invoke_cost=invoke_cost,
132
  **additional_params # For any future parameters we might want to add
133
  )
 
134
  return (self._agents[agent_name], self.budget_manager.get_current_remaining_budget())
135
 
136
+ def validate_budget(self, amount: float) -> None:
137
+ if not self.budget_manager.can_spend(amount):
138
+ raise ValueError(f"Do not have enough budget to create the tool. "
139
+ +f"Creating the tool costs {amount} but only {self.budget_manager.get_current_remaining_budget()} is remaining")
140
+
141
+ def create_agent_class(self, agent_name: str, base_model: str, system_prompt: str, description: str = "", create_cost: float = 0, invoke_cost: float = 0,
142
+ **additional_params) -> Agent:
143
+ agent_type = self._get_agent_type(base_model)
144
+ agent_class = self._agent_types.get(agent_type)
145
+
146
+ if not agent_class:
147
+ raise ValueError(f"Unsupported base model {base_model}")
148
+
149
+ self.validate_budget(create_cost)
150
+
151
+ self.budget_manager.add_to_expense(create_cost)
152
+ # create agent
153
+ return agent_class(agent_name, base_model, system_prompt, create_cost,invoke_cost)
154
+
155
+
156
  def get_agent(self, agent_name: str) -> Agent:
157
  """Get existing agent by name"""
158
  if agent_name not in self._agents:
 
182
  return {}
183
 
184
  def delete_agent(self, agent_name: str) -> int:
185
+ agent = self.get_agent(agent_name)
 
 
 
 
186
 
187
+ self.budget_manager.remove_from_expense(agent.creation_cost)
188
+ agent.delete_agent()
189
 
190
  del self._agents[agent_name]
191
  try:
 
201
  return self.budget_manager.get_current_remaining_budget()
202
 
203
  def ask_agent(self, agent_name: str, prompt: str) -> Tuple[str,int]:
204
+ agent = self.get_agent(agent_name)
 
 
 
 
205
 
206
+ self.validate_budget(agent.invoke_cost)
207
+
208
  response = agent.ask_agent(prompt)
209
  return (response, self.budget_manager.get_current_remaining_budget())
210
 
 
275
 
276
  if manager_class:
277
  # Create the agent with the appropriate manager class
278
+ self._agents[name] = self.create_agent_class(
279
+ name,
280
+ base_model,
281
+ system_prompt,
282
+ description=data.get("description", ""),
283
+ create_cost=creation_cost,
284
+ invoke_cost=invoke_cost,
285
+ **data.get("additional_params", {})
286
+ )
287
  self._agents[name] = manager_class(
288
  name,
289
  base_model,
src/budget_manager.py CHANGED
@@ -20,4 +20,9 @@ class BudgetManager():
20
  def add_to_expense(self, cost):
21
  if not self.can_spend(cost):
22
  raise Exception("No budget remaining")
23
- self.current_expense += cost
 
 
 
 
 
 
20
  def add_to_expense(self, cost):
21
  if not self.can_spend(cost):
22
  raise Exception("No budget remaining")
23
+ self.current_expense += cost
24
+
25
+ def remove_from_expense(self, cost):
26
+ if self.current_expense - cost < 0:
27
+ raise Exception("Cannot remove more than current expense")
28
+ self.current_expense -= cost
src/manager.py CHANGED
@@ -4,7 +4,7 @@ from google.genai.types import *
4
  import os
5
  from dotenv import load_dotenv
6
  import sys
7
- from src.tool_loader import ToolLoader
8
  from src.utils.suppress_outputs import suppress_output
9
  import logging
10
  import gradio as gr
@@ -16,17 +16,29 @@ logger.addHandler(handler)
16
 
17
 
18
  class GeminiManager:
19
- def __init__(self, toolsLoader: ToolLoader, system_prompt_file="./models/system3.prompt", gemini_model="gemini-2.5-pro-exp-03-25"):
 
 
 
 
20
  load_dotenv()
 
 
 
 
 
 
 
 
 
21
  self.API_KEY = os.getenv("GEMINI_KEY")
22
  self.client = genai.Client(api_key=self.API_KEY)
23
- self.toolsLoader: ToolLoader = toolsLoader
24
  self.toolsLoader.load_tools()
25
  self.model_name = gemini_model
26
  with open(system_prompt_file, 'r', encoding="utf8") as f:
27
  self.system_prompt = f.read()
28
  self.messages = []
29
-
30
  def generate_response(self, messages):
31
  return self.client.models.generate_content(
32
  model=self.model_name,
 
4
  import os
5
  from dotenv import load_dotenv
6
  import sys
7
+ from src.tool_manager import ToolManager
8
  from src.utils.suppress_outputs import suppress_output
9
  import logging
10
  import gradio as gr
 
16
 
17
 
18
  class GeminiManager:
19
+ def __init__(self, toolsLoader: ToolManager = None,
20
+ system_prompt_file="./models/system3.prompt",
21
+ gemini_model="gemini-2.5-pro-exp-03-25",
22
+ local_only=False, allow_tool_creation=True,
23
+ cloud_only=False, use_economy=True):
24
  load_dotenv()
25
+ self.toolsLoader: ToolManager = toolsLoader
26
+ if not toolsLoader:
27
+ self.toolsLoader: ToolManager = ToolManager()
28
+
29
+ self.local_only = local_only
30
+ self.allow_tool_creation = allow_tool_creation
31
+ self.cloud_only = cloud_only
32
+ self.use_economy = use_economy
33
+
34
  self.API_KEY = os.getenv("GEMINI_KEY")
35
  self.client = genai.Client(api_key=self.API_KEY)
 
36
  self.toolsLoader.load_tools()
37
  self.model_name = gemini_model
38
  with open(system_prompt_file, 'r', encoding="utf8") as f:
39
  self.system_prompt = f.read()
40
  self.messages = []
41
+
42
  def generate_response(self, messages):
43
  return self.client.models.generate_content(
44
  model=self.model_name,
src/{tool_loader.py → tool_manager.py} RENAMED
@@ -2,6 +2,7 @@ import importlib
2
  import importlib.util
3
  import os
4
  import types
 
5
  import pip
6
  from google.genai import types
7
  import sys
@@ -27,7 +28,17 @@ class Tool:
27
  self.name = self.inputSchema["name"]
28
  self.description = self.inputSchema["description"]
29
  self.dependencies = self.tool.dependencies
30
- for package in self.tool.dependencies:
 
 
 
 
 
 
 
 
 
 
31
  try:
32
  __import__(package.split('==')[0])
33
  except ImportError:
@@ -40,25 +51,12 @@ class Tool:
40
  return self.tool.run(**query)
41
 
42
  @singleton
43
- class ToolLoader:
44
- toolsImported = []
45
- budget_manager = BudgetManager()
46
 
47
  def __init__(self):
48
  self.load_tools()
49
- self.load_costs()
50
-
51
- def load_costs(self):
52
- get_agents = GetAgents()
53
- agents = get_agents.run()["agents"]
54
- for agent in agents:
55
- agentConfig = agents[agent]
56
- if agentConfig["create_cost"] is not None:
57
- self.budget_manager.add_to_expense(agentConfig["create_cost"])
58
- for tool in self.toolsImported:
59
- if "create_cost" in tool.inputSchema:
60
- if tool.inputSchema["create_cost"] is not None:
61
- self.budget_manager.add_to_expense(tool.inputSchema["create_cost"])
62
 
63
  output_assistant_response(f"Budget Remaining: {self.budget_manager.get_current_remaining_budget()}")
64
 
@@ -75,12 +73,16 @@ class ToolLoader:
75
  toolClass = getattr(foo, class_name)
76
  toolObj = Tool(toolClass)
77
  newToolsImported.append(toolObj)
 
 
78
  self.toolsImported = newToolsImported
79
 
80
  def runTool(self, toolName, query):
81
  output_assistant_response(f"Budget Remaining: {self.budget_manager.get_current_remaining_budget()}")
82
  for tool in self.toolsImported:
83
  if tool.name == toolName:
 
 
84
  return tool.run(query)
85
  output_assistant_response(f"Budget Remaining: {self.budget_manager.get_current_remaining_budget()}")
86
  return {
@@ -118,6 +120,9 @@ class ToolLoader:
118
  tool_deletor.run(name=toolName, file_path=toolFile)
119
  for tool in self.toolsImported:
120
  if tool.name == toolName:
 
 
 
121
  self.toolsImported.remove(tool)
122
  return {
123
  "status": "success",
@@ -129,10 +134,4 @@ class ToolLoader:
129
  "status": "error",
130
  "message": f"Tool {toolName} not found",
131
  "output": None
132
- }
133
-
134
- # toolLoader = ToolLoader()
135
-
136
- # Example usage
137
- # print(toolLoader.getTools())
138
- # print(toolLoader.runTool("AgentCreator", {"agent_name": "Kunla","base_model":"llama3.2","system_prompt": "You love making the indian dish called Kulcha. You declare that in every conversation you have in a witty way." }))
 
2
  import importlib.util
3
  import os
4
  import types
5
+ from typing import List
6
  import pip
7
  from google.genai import types
8
  import sys
 
28
  self.name = self.inputSchema["name"]
29
  self.description = self.inputSchema["description"]
30
  self.dependencies = self.tool.dependencies
31
+ self.create_cost = None
32
+ self.invoke_cost = None
33
+ if "create_cost" in self.tool.inputSchema:
34
+ self.create_cost = self.tool.inputSchema["create_cost"]
35
+ if "invoke_cost" in self.tool.inputSchema:
36
+ self.invoke_cost = self.tool.inputSchema["invoke_cost"]
37
+ if self.dependencies:
38
+ self.install_dependencies()
39
+
40
+ def install_dependencies(self):
41
+ for package in self.dependencies:
42
  try:
43
  __import__(package.split('==')[0])
44
  except ImportError:
 
51
  return self.tool.run(**query)
52
 
53
  @singleton
54
+ class ToolManager:
55
+ toolsImported: List[Tool] = []
56
+ budget_manager: BudgetManager = BudgetManager()
57
 
58
  def __init__(self):
59
  self.load_tools()
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
  output_assistant_response(f"Budget Remaining: {self.budget_manager.get_current_remaining_budget()}")
62
 
 
73
  toolClass = getattr(foo, class_name)
74
  toolObj = Tool(toolClass)
75
  newToolsImported.append(toolObj)
76
+ if toolObj.create_cost is not None:
77
+ self.budget_manager.add_to_expense(toolObj.create_cost)
78
  self.toolsImported = newToolsImported
79
 
80
  def runTool(self, toolName, query):
81
  output_assistant_response(f"Budget Remaining: {self.budget_manager.get_current_remaining_budget()}")
82
  for tool in self.toolsImported:
83
  if tool.name == toolName:
84
+ if tool.invoke_cost is not None:
85
+ self.budget_manager.add_to_expense(tool.invoke_cost)
86
  return tool.run(query)
87
  output_assistant_response(f"Budget Remaining: {self.budget_manager.get_current_remaining_budget()}")
88
  return {
 
120
  tool_deletor.run(name=toolName, file_path=toolFile)
121
  for tool in self.toolsImported:
122
  if tool.name == toolName:
123
+ # remove budget for the tool
124
+ if tool.create_cost is not None:
125
+ self.budget_manager.remove_from_expense(tool.create_cost)
126
  self.toolsImported.remove(tool)
127
  return {
128
  "status": "success",
 
134
  "status": "error",
135
  "message": f"Tool {toolName} not found",
136
  "output": None
137
+ }