from abc import ABC, abstractmethod
from typing import Dict, List, Any, Optional
import asyncio
from dataclasses import dataclass
@dataclass
class AgentState:
"""Represents the current state of the agent"""
current_goal: Optional[str] = None
context: Dict[str, Any] = None
memory: Dict[str, Any] = None
active_tools: List[str] = None
class PerceptionModule(ABC):
"""Abstract base class for perception components"""
@abstractmethod
async def process_input(self, raw_input: Any) -> Dict[str, Any]:
"""Process raw input and extract structured information"""
pass
@abstractmethod
def extract_intent(self, processed_input: Dict[str, Any]) -> str:
"""Extract user intent from processed input"""
pass
class ReasoningEngine(ABC):
"""Abstract base class for reasoning components"""
@abstractmethod
async def analyze(self, state: AgentState, input_data: Dict[str, Any]) -> Dict[str, Any]:
"""Analyze current state and input to determine next actions"""
pass
@abstractmethod
async def plan(self, goal: str, context: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Create a plan to achieve the specified goal"""
pass
class MemorySystem(ABC):
"""Abstract base class for memory management"""
@abstractmethod
async def store(self, key: str, value: Any, metadata: Dict[str, Any] = None):
"""Store information in memory"""
pass
@abstractmethod
async def retrieve(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
"""Retrieve relevant information from memory"""
pass
@abstractmethod
async def update_context(self, context_updates: Dict[str, Any]):
"""Update the current context"""
pass
class ActionExecutor(ABC):
"""Abstract base class for action execution"""
@abstractmethod
async def execute_action(self, action: Dict[str, Any]) -> Dict[str, Any]:
"""Execute a specific action"""
pass
@abstractmethod
async def validate_result(self, action: Dict[str, Any], result: Dict[str, Any]) -> bool:
"""Validate the result of an action"""
pass
class CoreAgent:
"""Main agent orchestrator implementing the core architecture"""
def __init__(self,
perception: PerceptionModule,
reasoning: ReasoningEngine,
memory: MemorySystem,
executor: ActionExecutor):
self.perception = perception
self.reasoning = reasoning
self.memory = memory
self.executor = executor
self.state = AgentState()
self.running = False
async def initialize(self):
"""Initialize the agent and all components"""
await self.memory.store("agent_status", "initialized")
self.state.context = await self.memory.retrieve("initial_context")
self.running = True
async def process_input(self, user_input: Any) -> Dict[str, Any]:
"""Main processing loop for handling user input"""
try:
# Perception Phase
processed_input = await self.perception.process_input(user_input)
intent = self.perception.extract_intent(processed_input)
# Update state with new input
self.state.current_goal = intent
await self.memory.update_context({
"last_input": processed_input,
"current_intent": intent,
"timestamp": self._get_timestamp()
})
# Reasoning Phase
analysis = await self.reasoning.analyze(self.state, processed_input)
plan = await self.reasoning.plan(intent, self.state.context)
# Execution Phase
results = []
for action in plan:
result = await self.executor.execute_action(action)
# Validate and store result
if await self.executor.validate_result(action, result):
results.append(result)
await self.memory.store(f"action_result_{action['id']}", result)
else:
# Handle execution failure
error_result = await self._handle_execution_error(action, result)
results.append(error_result)
# Compile final response
response = await self._compile_response(results, intent)
# Update memory with interaction
await self.memory.store("last_interaction", {
"input": processed_input,
"intent": intent,
"plan": plan,
"results": results,
"response": response
})
return response
except Exception as e:
return await self._handle_error(e, user_input)
async def _handle_execution_error(self, action: Dict[str, Any], result: Dict[str, Any]) -> Dict[str, Any]:
"""Handle errors during action execution"""
error_context = {
"action": action,
"error": result.get("error"),
"timestamp": self._get_timestamp()
}
# Store error for learning
await self.memory.store(f"error_{action['id']}", error_context)
# Attempt recovery or alternative approach
recovery_plan = await self.reasoning.plan(
f"recover_from_error_{action['type']}",
error_context
)
if recovery_plan:
# Try recovery action
for recovery_action in recovery_plan:
recovery_result = await self.executor.execute_action(recovery_action)
if await self.executor.validate_result(recovery_action, recovery_result):
return recovery_result
# Return graceful error response
return {
"success": False,
"error": f"Failed to execute {action['type']} action",
"recovery_attempted": bool(recovery_plan)
}
async def _compile_response(self, results: List[Dict[str, Any]], intent: str) -> Dict[str, Any]:
"""Compile execution results into a coherent response"""
successful_results = [r for r in results if r.get("success", False)]
failed_results = [r for r in results if not r.get("success", False)]
response = {
"intent": intent,
"success": len(successful_results) > 0,
"results": successful_results,
"errors": failed_results,
"summary": await self._generate_summary(successful_results, intent)
}
return response
async def _generate_summary(self, results: List[Dict[str, Any]], intent: str) -> str:
"""Generate a human-readable summary of the results"""
if not results:
return f"Unable to complete the requested task: {intent}"
# Use reasoning engine to generate appropriate summary
summary_context = {
"intent": intent,
"results": results,
"result_count": len(results)
}
summary_plan = await self.reasoning.plan("generate_summary", summary_context)
if summary_plan:
summary_result = await self.executor.execute_action(summary_plan[0])
return summary_result.get("content", "Task completed successfully")
return f"Successfully completed {len(results)} actions for: {intent}"
async def _handle_error(self, error: Exception, user_input: Any) -> Dict[str, Any]:
"""Handle unexpected errors in the main processing loop"""
error_context = {
"error_type": type(error).__name__,
"error_message": str(error),
"user_input": str(user_input),
"timestamp": self._get_timestamp()
}
# Log error for debugging
await self.memory.store("system_error", error_context)
return {
"success": False,
"error": "An unexpected error occurred while processing your request",
"error_id": error_context["timestamp"],
"recovery_suggestions": [
"Please try rephrasing your request",
"Check if all required information is provided",
"Contact support if the issue persists"
]
}
def _get_timestamp(self) -> str:
"""Get current timestamp for logging"""
import datetime
return datetime.datetime.now().isoformat()
async def shutdown(self):
"""Gracefully shutdown the agent"""
self.running = False
await self.memory.store("agent_status", "shutdown")
# Example concrete implementations
class LLMPerceptionModule(PerceptionModule):
"""LLM-based perception implementation"""
def __init__(self, llm_client):
self.llm = llm_client
async def process_input(self, raw_input: Any) -> Dict[str, Any]:
# Implementation for LLM-based input processing
response = await self.llm.process(raw_input)
return {
"text": raw_input,
"entities": response.get("entities", []),
"sentiment": response.get("sentiment"),
"language": response.get("language", "en")
}
def extract_intent(self, processed_input: Dict[str, Any]) -> str:
# Extract intent from processed input
return processed_input.get("intent", "general_query")
class VectorMemorySystem(MemorySystem):
"""Vector database-based memory implementation"""
def __init__(self, vector_db):
self.vector_db = vector_db
self.context = {}
async def store(self, key: str, value: Any, metadata: Dict[str, Any] = None):
# Implementation for vector storage
await self.vector_db.insert(key, value, metadata or {})
async def retrieve(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
# Implementation for vector retrieval
return await self.vector_db.similarity_search(query, limit)
async def update_context(self, context_updates: Dict[str, Any]):
self.context.update(context_updates)
# Usage example
async def create_agent():
# Initialize components
perception = LLMPerceptionModule(llm_client)
reasoning = AdvancedReasoningEngine()
memory = VectorMemorySystem(vector_db)
executor = ToolBasedExecutor(tool_registry)
# Create and initialize agent
agent = CoreAgent(perception, reasoning, memory, executor)
await agent.initialize()
return agent