import time
import uuid
from dataclasses import dataclass, field
from typing import Any, Callable, Dict, List, Optional
from ..memory.knowledge_store import KnowledgeStore
from .agent_communication import AgentCommunicationBus, AgentMessage, MessageType
from .agent_roles import AgentRole, get_agent_role
@dataclass
class AgentInstance:
agent_id: str
role: AgentRole
message_history: List[Dict[str, Any]] = field(default_factory=list)
context: Dict[str, Any] = field(default_factory=dict)
created_at: float = field(default_factory=time.time)
task_count: int = 0
def add_message(self, role: str, content: str):
self.message_history.append({"role": role, "content": content, "timestamp": time.time()})
def get_system_message(self) -> Dict[str, str]:
return {"role": "system", "content": self.role.system_prompt}
def get_messages_for_api(self) -> List[Dict[str, str]]:
return [self.get_system_message()] + [
{"role": msg["role"], "content": msg["content"]} for msg in self.message_history
]
class AgentManager:
def __init__(self, db_path: str, api_caller: Callable):
self.db_path = db_path
self.api_caller = api_caller
self.communication_bus = AgentCommunicationBus(db_path)
self.knowledge_store = KnowledgeStore(db_path)
self.active_agents: Dict[str, AgentInstance] = {}
self.session_id = str(uuid.uuid4())[:16]
def create_agent(self, role_name: str, agent_id: Optional[str] = None) -> str:
if agent_id is None:
agent_id = f"{role_name}_{str(uuid.uuid4())[:8]}"
role = get_agent_role(role_name)
agent = AgentInstance(agent_id=agent_id, role=role)
self.active_agents[agent_id] = agent
return agent_id
def get_agent(self, agent_id: str) -> Optional[AgentInstance]:
return self.active_agents.get(agent_id)
def remove_agent(self, agent_id: str) -> bool:
if agent_id in self.active_agents:
del self.active_agents[agent_id]
return True
return False
def execute_agent_task(
self, agent_id: str, task: str, context: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
agent = self.get_agent(agent_id)
if not agent:
return {"error": f"Agent {agent_id} not found"}
if context:
agent.context.update(context)
agent.add_message("user", task)
knowledge_matches = self.knowledge_store.search_entries(task, top_k=3)
agent.task_count += 1
messages = agent.get_messages_for_api()
if knowledge_matches:
knowledge_content = "Knowledge base matches based on your query:\\n"
for i, entry in enumerate(knowledge_matches, 1):
shortened_content = entry.content[:2000]
knowledge_content += f"{i}. {shortened_content}\\n\\n"
messages.insert(-1, {"role": "user", "content": knowledge_content})
try:
response = self.api_caller(
messages=messages,
temperature=agent.role.temperature,
max_tokens=agent.role.max_tokens,
)
if response and "choices" in response:
assistant_message = response["choices"][0]["message"]["content"]
agent.add_message("assistant", assistant_message)
return {
"success": True,
"agent_id": agent_id,
"response": assistant_message,
"role": agent.role.name,
"task_count": agent.task_count,
}
else:
return {"error": "Invalid API response", "agent_id": agent_id}
except Exception as e:
return {"error": str(e), "agent_id": agent_id}
def send_agent_message(
self,
from_agent_id: str,
to_agent_id: str,
content: str,
message_type: MessageType = MessageType.REQUEST,
metadata: Optional[Dict[str, Any]] = None,
):
message = AgentMessage(
from_agent=from_agent_id,
to_agent=to_agent_id,
message_type=message_type,
content=content,
metadata=metadata or {},
timestamp=time.time(),
message_id=str(uuid.uuid4())[:16],
)
self.communication_bus.send_message(message, self.session_id)
return message.message_id
def get_agent_messages(self, agent_id: str, unread_only: bool = True) -> List[AgentMessage]:
return self.communication_bus.get_messages(agent_id, unread_only)
def collaborate_agents(self, orchestrator_id: str, task: str, agent_roles: List[str]):
orchestrator = self.get_agent(orchestrator_id)
if not orchestrator:
orchestrator_id = self.create_agent("orchestrator")
orchestrator = self.get_agent(orchestrator_id)
worker_agents = []
for role in agent_roles:
agent_id = self.create_agent(role)
worker_agents.append({"agent_id": agent_id, "role": role})
orchestration_prompt = f"""Task: {task}
Available specialized agents:
{chr(10).join([f"- {a['agent_id']} ({a['role']})" for a in worker_agents])}
Break down the task and delegate subtasks to appropriate agents. Coordinate their work and integrate results."""
orchestrator_result = self.execute_agent_task(orchestrator_id, orchestration_prompt)
results = {"orchestrator": orchestrator_result, "agents": []}
for agent_info in worker_agents:
agent_id = agent_info["agent_id"]
messages = self.get_agent_messages(agent_id)
for msg in messages:
subtask = msg.content
result = self.execute_agent_task(agent_id, subtask)
results["agents"].append(result)
self.send_agent_message(
from_agent_id=agent_id,
to_agent_id=orchestrator_id,
content=result.get("response", ""),
message_type=MessageType.RESPONSE,
)
self.communication_bus.mark_as_read(msg.message_id)
return results
def get_session_summary(self) -> Dict[str, Any]:
summary = {
"session_id": self.session_id,
"active_agents": len(self.active_agents),
"agents": [
{
"agent_id": agent_id,
"role": agent.role.name,
"task_count": agent.task_count,
"message_count": len(agent.message_history),
}
for agent_id, agent in self.active_agents.items()
],
}
return summary
def clear_session(self):
self.active_agents.clear()
self.communication_bus.clear_messages(session_id=self.session_id)
self.session_id = str(uuid.uuid4())[:16]