Harshil Patel
commited on
Commit
·
e0d574f
1
Parent(s):
7ec791b
Implement agent manager
Browse files- src/agent_manager.py +203 -0
src/agent_manager.py
ADDED
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from abc import ABC, abstractmethod
|
2 |
+
from typing import Dict, Type, Any, Optional
|
3 |
+
import os
|
4 |
+
import json
|
5 |
+
import ollama
|
6 |
+
from src.singleton import singleton
|
7 |
+
|
8 |
+
class Agent(ABC):
|
9 |
+
|
10 |
+
def __init__(self, agent_name: str, base_model: str, system_prompt: str):
|
11 |
+
self.agent_name = agent_name
|
12 |
+
self.base_model = base_model
|
13 |
+
self.system_prompt = system_prompt
|
14 |
+
self.create_model()
|
15 |
+
|
16 |
+
@abstractmethod
|
17 |
+
def create_model(self) -> None:
|
18 |
+
"""Create and Initialize agent"""
|
19 |
+
pass
|
20 |
+
|
21 |
+
@abstractmethod
|
22 |
+
def ask_agent(self, prompt: str) -> str:
|
23 |
+
"""ask agent a question"""
|
24 |
+
pass
|
25 |
+
|
26 |
+
@abstractmethod
|
27 |
+
def delete_agent(self) ->None:
|
28 |
+
"""delete agent"""
|
29 |
+
pass
|
30 |
+
|
31 |
+
class OllamaAgent(Agent):
|
32 |
+
|
33 |
+
def create_model(self):
|
34 |
+
ollama_response = ollama.create(
|
35 |
+
model = self.agent_name,
|
36 |
+
from_ = self.base_model,
|
37 |
+
system = self.system_prompt,
|
38 |
+
stream = False
|
39 |
+
)
|
40 |
+
|
41 |
+
def ask_agent(self, prompt):
|
42 |
+
print(f"Asked Agent {self.agent_name} a question")
|
43 |
+
agent_response = ollama.chat(
|
44 |
+
model=self.agent_name,
|
45 |
+
messages=[{"role": "user", "content": prompt}],
|
46 |
+
)
|
47 |
+
print(f"Agent {self.agent_name} answered with {agent_response.message.content}")
|
48 |
+
return agent_response.message.content
|
49 |
+
|
50 |
+
def delete_agent(self):
|
51 |
+
ollama.delete(self.agent_name)
|
52 |
+
|
53 |
+
@singleton
|
54 |
+
class AgentManager():
|
55 |
+
|
56 |
+
def __init__(self):
|
57 |
+
self._agents = {}
|
58 |
+
self._agent_types ={
|
59 |
+
ollama: OllamaAgent
|
60 |
+
}
|
61 |
+
|
62 |
+
self._load_agents()
|
63 |
+
|
64 |
+
def create_agent(self, agent_name: str, base_model: str, system_prompt: str, description: str = "", create_cost: float = 0, invoke_cost: float = 0,
|
65 |
+
**additional_params) -> Agent:
|
66 |
+
|
67 |
+
if agent_name in self._agents:
|
68 |
+
raise ValueError(f"Agent {agent_name} already exists")
|
69 |
+
|
70 |
+
agent_type = self._get_agent_type(base_model)
|
71 |
+
agent_class = self._agent_types.get(agent_type)
|
72 |
+
|
73 |
+
if not agent_class:
|
74 |
+
raise ValueError(f"Unsupported base model {base_model}")
|
75 |
+
|
76 |
+
# create agent
|
77 |
+
self._agents[agent_name] = agent_class(agent_name, base_model, system_prompt)
|
78 |
+
|
79 |
+
#save agent to file
|
80 |
+
self._save_agent(
|
81 |
+
agent_name,
|
82 |
+
base_model,
|
83 |
+
system_prompt,
|
84 |
+
description=description,
|
85 |
+
create_cost=create_cost,
|
86 |
+
invoke_cost=invoke_cost,
|
87 |
+
**additional_params # For any future parameters we might want to add
|
88 |
+
)
|
89 |
+
|
90 |
+
return self._agents[agent_name]
|
91 |
+
|
92 |
+
def get_agent(self, agent_name: str) -> Agent:
|
93 |
+
"""Get existing agent by name"""
|
94 |
+
if agent_name in self._agents:
|
95 |
+
raise ValueError(f"Agent {agent_name} already exists")
|
96 |
+
return self._agents[agent_name]
|
97 |
+
|
98 |
+
def list_agents(self) -> dict:
|
99 |
+
"""Return agent information (name, description, costs)"""
|
100 |
+
try:
|
101 |
+
if os.path.exists("./models/models.json"):
|
102 |
+
with open("./models/models.json", "r", encoding="utf8") as f:
|
103 |
+
full_models = json.loads(f.read())
|
104 |
+
|
105 |
+
# Create a simplified version with only the description and costs
|
106 |
+
simplified_agents = {}
|
107 |
+
for name, data in full_models.items():
|
108 |
+
simplified_agents[name] = {
|
109 |
+
"description": data.get("description", ""),
|
110 |
+
"create_cost": data.get("create_cost", 0),
|
111 |
+
"invoke_cost": data.get("invoke_cost", 0)
|
112 |
+
}
|
113 |
+
return simplified_agents
|
114 |
+
else:
|
115 |
+
return {}
|
116 |
+
except Exception as e:
|
117 |
+
print(f"Error listing agents: {e}")
|
118 |
+
return {}
|
119 |
+
|
120 |
+
def delete_agent(self, agent_name: str) -> None:
|
121 |
+
if agent_name not in self._agents:
|
122 |
+
raise ValueError(f"Agent {agent_name} does not exist")
|
123 |
+
self._agents[agent_name].delete_agent()
|
124 |
+
|
125 |
+
del self._agents[agent_name]
|
126 |
+
try:
|
127 |
+
if os.path.exists("./models/models.json"):
|
128 |
+
with open("./models/models.json", "r", encoding="utf8") as f:
|
129 |
+
models = json.loads(f.read())
|
130 |
+
|
131 |
+
del models[agent_name]
|
132 |
+
with open("./models/models.json", "w", encoding="utf8") as f:
|
133 |
+
f.write(json.dumps(models, indent=4))
|
134 |
+
except Exception as e:
|
135 |
+
print(f"Error deleting agent: {e}")
|
136 |
+
|
137 |
+
|
138 |
+
def _save_agent(self, agent_name: str, base_model: str, system_prompt: str,
|
139 |
+
description: str = "", create_cost: float = 0, invoke_cost: float = 0,
|
140 |
+
**additional_params) -> None:
|
141 |
+
"""Save a single agent to the models.json file"""
|
142 |
+
try:
|
143 |
+
# Ensure the directory exists
|
144 |
+
os.makedirs("./models", exist_ok=True)
|
145 |
+
|
146 |
+
# Read existing models file or create empty dict if it doesn't exist
|
147 |
+
try:
|
148 |
+
with open("./models/models.json", "r", encoding="utf8") as f:
|
149 |
+
models = json.loads(f.read())
|
150 |
+
except (FileNotFoundError, json.JSONDecodeError):
|
151 |
+
models = {}
|
152 |
+
|
153 |
+
# Update the models dict with the new agent
|
154 |
+
models[agent_name] = {
|
155 |
+
"base_model": base_model,
|
156 |
+
"description": description,
|
157 |
+
"system_prompt": system_prompt,
|
158 |
+
"create_cost": create_cost,
|
159 |
+
"invoke_cost": invoke_cost,
|
160 |
+
}
|
161 |
+
|
162 |
+
# Add any additional parameters that were passed
|
163 |
+
for key, value in additional_params.items():
|
164 |
+
models[agent_name][key] = value
|
165 |
+
|
166 |
+
# Write the updated models back to the file
|
167 |
+
with open("./models/models.json", "w", encoding="utf8") as f:
|
168 |
+
f.write(json.dumps(models, indent=4))
|
169 |
+
|
170 |
+
except Exception as e:
|
171 |
+
print(f"Error saving agent {agent_name}: {e}")
|
172 |
+
|
173 |
+
def _get_agent_type(self, base_model)->str:
|
174 |
+
if base_model.startswith("ollama"):
|
175 |
+
return "ollama"
|
176 |
+
else:
|
177 |
+
return "unknown"
|
178 |
+
|
179 |
+
def _load_agents(self) -> None:
|
180 |
+
"""Load agent configurations from disk"""
|
181 |
+
try:
|
182 |
+
if not os.path.exists("./models/models.json"):
|
183 |
+
return
|
184 |
+
|
185 |
+
with open("./models/models.json", "r", encoding="utf8") as f:
|
186 |
+
models = json.loads(f.read())
|
187 |
+
|
188 |
+
for name, data in models.items():
|
189 |
+
base_model = data["base_model"]
|
190 |
+
system_prompt = data["system_prompt"]
|
191 |
+
|
192 |
+
model_type = self._get_model_type(base_model)
|
193 |
+
manager_class = self._model_types.get(model_type)
|
194 |
+
|
195 |
+
if manager_class:
|
196 |
+
# Create the agent with the appropriate manager class
|
197 |
+
self._agents[name] = manager_class(
|
198 |
+
name,
|
199 |
+
base_model,
|
200 |
+
system_prompt
|
201 |
+
)
|
202 |
+
except Exception as e:
|
203 |
+
print(f"Error loading agents: {e}")
|