gateway/modules/workflow/agentManager.py
ValueOn AG f3860723af wip
2025-06-08 03:12:43 +02:00

212 lines
No EOL
7.4 KiB
Python

"""
Agent Manager Module for managing agent operations and execution.
"""
import os
import logging
import importlib
from typing import Dict, Any, List, Optional, Tuple
from datetime import datetime, UTC
import uuid
from modules.interfaces.serviceChatModel import (
ChatMessage, ChatDocument, UserInputRequest, ChatWorkflow, AgentResponse
)
logger = logging.getLogger(__name__)
class AgentManager:
"""Manager for agent operations and execution."""
_instance = None
@classmethod
def getInstance(cls):
"""Return a singleton instance of the agent manager."""
if cls._instance is None:
cls._instance = cls()
return cls._instance
# Internal Methods
def __init__(self):
"""Initialize the agent manager."""
if AgentManager._instance is not None:
raise RuntimeError("Singleton instance already exists - use getInstance()")
self.service = None
self.agents = {} # Dictionary to store agent instances
self._loadAgents() # Load agents on initialization
def _loadAgents(self):
"""Load all available agents from modules dynamically."""
logger.info("Loading agent modules...")
# Get the agents directory path
agentDir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "agents")
# Search for agent modules
agentModules = []
for filename in os.listdir(agentDir):
if filename.startswith("agent") and filename.endswith(".py"):
agentModules.append(filename[:-3]) # Remove .py extension
if not agentModules:
logger.warning("No agent modules found in directory: %s", agentDir)
return
logger.info(f"Found {len(agentModules)} agent modules: {', '.join(agentModules)}")
# Load each agent module
for moduleName in agentModules:
try:
# Import the module
module = importlib.import_module(f"modules.agents.{moduleName}")
# Extract agent name from module name
agentName = moduleName.split("agent")[-1]
className = f"Agent{agentName}"
getterName = f"getAgent{agentName}"
agent = None
# Try to get the agent via the getter function first
if hasattr(module, getterName):
getterFunc = getattr(module, getterName)
agent = getterFunc()
logger.info(f"Agent '{agent.name}' loaded via {getterName}()")
# If no getter, try to instantiate the agent class directly
elif hasattr(module, className):
agentClass = getattr(module, className)
agent = agentClass()
logger.info(f"Agent '{agent.name}' directly instantiated from {className}")
if agent:
# Register the agent
if self._registerAgent(agent):
logger.info(f"Successfully registered agent: {agent.name}")
else:
logger.error(f"Failed to register agent from module: {moduleName}")
else:
logger.warning(f"No agent class or getter function found in module: {moduleName}")
except ImportError as e:
logger.error(f"Failed to import module {moduleName}: {str(e)}")
except Exception as e:
logger.error(f"Error loading agent from module {moduleName}: {str(e)}")
def _registerAgent(self, agent: Any):
"""Register a new agent with the manager."""
if not hasattr(agent, 'name'):
logger.error("Agent must have a name attribute")
return False
self.agents[agent.name] = agent
if self.service and hasattr(agent, 'setService'):
agent.setService(self.service)
return True
# Public Methods
def initialize(self, service: Any):
"""Initialize the manager with service reference."""
# Store service reference
self.service = service
# Initialize agents with service
for agent in self.agents.values():
if hasattr(agent, 'setService'):
agent.setService(service)
return True
def getAgent(self, agentIdentifier: str) -> Optional[Any]:
"""
Get an agent instance by its identifier.
Args:
agentIdentifier: Name or identifier of the agent
Returns:
Agent instance if found, None otherwise
"""
agent = self.agents.get(agentIdentifier)
if not agent:
logger.warning(f"Agent '{agentIdentifier}' not found")
return agent
def getAllAgents(self) -> Dict[str, Any]:
"""
Get all registered agents.
Returns:
Dictionary mapping agent names to agent instances
"""
return self.agents.copy()
def getAgentInfos(self) -> List[Dict[str, Any]]:
"""Get information about all registered agents."""
return [
{
'name': agent.name,
'description': getattr(agent, 'description', ''),
'capabilities': getattr(agent, 'capabilities', []),
'inputTypes': getattr(agent, 'inputTypes', []),
'outputTypes': getattr(agent, 'outputTypes', [])
}
for agent in self.agents.values()
]
async def executeAgent(self, handover: Any) -> AgentResponse:
"""
Execute an agent with the given handover.
Args:
handover: Handover object containing agent execution context
Returns:
AgentResponse object with execution results
"""
try:
# Get agent instance
agent = self.agents.get(handover.currentAgent)
if not agent:
raise ValueError(f"Agent {handover.currentAgent} not found")
# Execute agent
response = await agent.execute(handover)
# Save output files if any
if response.message and response.message.documents:
self.service.document['agentOutputFilesSave'](handover, response.message.documents)
return response
except Exception as e:
logger.error(f"Error executing agent {handover.currentAgent}: {str(e)}")
# Create error message
errorMessage = ChatMessage(
id=str(uuid.uuid4()),
workflowId=handover.workflowId,
agentName=handover.currentAgent,
message=f"Error executing agent: {str(e)}",
role="system",
status="error",
sequenceNr=0,
startedAt=handover.startedAt,
finishedAt=datetime.now(UTC).isoformat(),
success=False
)
return AgentResponse(
success=False,
message=errorMessage,
error=str(e),
performance={},
progress=0.0
)
# Singleton factory for the agent manager
def getAgentManager():
return AgentManager.getInstance()