| """ |
| Autonomous Agent for problem solving and self-improvement. |
| |
| This module implements an autonomous agent that can understand problems, |
| decompose them into sub-tasks, generate and test solutions, and learn from results. |
| """ |
| import json |
| import logging |
| from typing import Dict, List, Optional, Any, Tuple |
| from datetime import datetime |
| from pathlib import Path |
| import hashlib |
|
|
| |
| logging.basicConfig( |
| level=logging.INFO, |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
| ) |
| logger = logging.getLogger(__name__) |
|
|
| class AutonomousAgent: |
| """ |
| An autonomous agent that can solve problems through decomposition, |
| solution generation, and learning. |
| """ |
| |
| def __init__(self, expert_system, code_agent, knowledge_base_path: str = "knowledge_base"): |
| """ |
| Initialize the autonomous agent. |
| |
| Args: |
| expert_system: Instance of ExpertSystem for problem solving |
| code_agent: Instance of CodeAgent for code execution |
| knowledge_base_path: Path to store learned knowledge |
| """ |
| self.expert_system = expert_system |
| self.code_agent = code_agent |
| self.knowledge_base_path = Path(knowledge_base_path) |
| self.knowledge_base_path.mkdir(exist_ok=True) |
| self.memory = self._load_knowledge() |
| |
| def _load_knowledge(self) -> Dict[str, Any]: |
| """Load existing knowledge from the knowledge base.""" |
| knowledge = { |
| 'solutions': {}, |
| 'patterns': {}, |
| 'lessons_learned': [] |
| } |
| |
| |
| solutions_file = self.knowledge_base_path / 'solutions.json' |
| if solutions_file.exists(): |
| with open(solutions_file, 'r', encoding='utf-8') as f: |
| knowledge['solutions'] = json.load(f) |
| |
| |
| patterns_file = self.knowledge_base_path / 'patterns.json' |
| if patterns_file.exists(): |
| with open(patterns_file, 'r', encoding='utf-8') as f: |
| knowledge['patterns'] = json.load(f) |
| |
| |
| lessons_file = self.knowledge_base_path / 'lessons.json' |
| if lessons_file.exists(): |
| with open(lessons_file, 'r', encoding='utf-8') as f: |
| knowledge['lessons_learned'] = json.load(f) |
| |
| return knowledge |
| |
| def _save_knowledge(self) -> None: |
| """Save current knowledge to the knowledge base.""" |
| |
| with open(self.knowledge_base_path / 'solutions.json', 'w', encoding='utf-8') as f: |
| json.dump(self.memory['solutions'], f, indent=2) |
| |
| |
| with open(self.knowledge_base_path / 'patterns.json', 'w', encoding='utf-8') as f: |
| json.dump(self.memory['patterns'], f, indent=2) |
| |
| |
| with open(self.knowledge_base_path / 'lessons.json', 'w', encoding='utf-8') as f: |
| json.dump(self.memory['lessons_learned'], f, indent=2) |
| |
| def _generate_solution_id(self, problem: str) -> str: |
| """Generate a unique ID for a problem/solution.""" |
| return hashlib.md5(problem.encode('utf-8')).hexdigest() |
| |
| def solve_problem(self, problem: str) -> Dict[str, Any]: |
| """ |
| Solve a problem autonomously. |
| |
| Args: |
| problem: The problem to solve |
| |
| Returns: |
| Dict containing the solution and metadata |
| """ |
| logger.info(f"Solving problem: {problem[:100]}...") |
| |
| |
| problem_id = self._generate_solution_id(problem) |
| if problem_id in self.memory['solutions']: |
| logger.info("Found existing solution in knowledge base") |
| return self.memory['solutions'][problem_id] |
| |
| |
| sub_tasks = self._decompose_problem(problem) |
| |
| |
| solutions = [] |
| for i, task in enumerate(sub_tasks, 1): |
| logger.info(f"Solving sub-task {i}/{len(sub_tasks)}: {task}") |
| solution = self._solve_sub_task(task) |
| solutions.append({ |
| 'task': task, |
| 'solution': solution |
| }) |
| |
| |
| final_solution = self._combine_solutions(problem, solutions) |
| |
| |
| self.memory['solutions'][problem_id] = { |
| 'problem': problem, |
| 'solution': final_solution, |
| 'timestamp': datetime.now().isoformat(), |
| 'sub_tasks': solutions |
| } |
| |
| |
| self._save_knowledge() |
| |
| return self.memory['solutions'][problem_id] |
| |
| def _decompose_problem(self, problem: str) -> List[str]: |
| """Break down a problem into sub-tasks.""" |
| try: |
| |
| prompt = f""" |
| Break down the following problem into clear, independent sub-tasks. |
| Return the sub-tasks as a JSON array of strings. |
| |
| Problem: {problem} |
| |
| Sub-tasks: |
| """ |
| |
| |
| response = self.expert_system.solve_problem( |
| problem=prompt, |
| subject='general', |
| temperature=0.3, |
| max_tokens=1000 |
| ) |
| |
| |
| content = response.get('solution', '').strip() |
| |
| |
| if content.startswith('```'): |
| content = '\n'.join(content.split('\n')[1:-1]) |
| |
| |
| sub_tasks = json.loads(content) |
| return [str(task) for task in sub_tasks] |
| |
| except Exception as e: |
| logger.error(f"Error decomposing problem: {e}") |
| |
| return [problem] |
| |
| def _solve_sub_task(self, task: str) -> Dict[str, Any]: |
| """Solve a single sub-task.""" |
| |
| for pattern, solution in self.memory['patterns'].items(): |
| if self._pattern_matches(pattern, task): |
| logger.info(f"Matched pattern: {pattern}") |
| return { |
| 'type': 'pattern_match', |
| 'pattern': pattern, |
| 'solution': solution, |
| 'source': 'memory' |
| } |
| |
| |
| return self._generate_solution(task) |
| |
| def _pattern_matches(self, pattern: str, task: str) -> bool: |
| """Check if a task matches a known pattern.""" |
| |
| pattern_terms = set(pattern.lower().split()) |
| task_terms = set(task.lower().split()) |
| return len(pattern_terms.intersection(task_terms)) / len(pattern_terms) > 0.6 |
| |
| def _generate_solution(self, task: str) -> Dict[str, Any]: |
| """Generate a solution for a task.""" |
| try: |
| |
| is_code_task = any(term in task.lower() for term in ['code', 'function', 'script', 'program']) |
| |
| |
| prompt = f""" |
| Provide a solution to the following task. |
| """ |
| |
| if is_code_task: |
| prompt += """ |
| This appears to be a coding task. Please provide a complete, working Python function or script. |
| Include all necessary imports and example usage if applicable. |
| """ |
| |
| prompt += f""" |
| |
| Task: {task} |
| |
| Solution: |
| """ |
| |
| |
| response = self.expert_system.solve_problem( |
| problem=prompt, |
| subject='coding' if is_code_task else 'general', |
| temperature=0.2, |
| max_tokens=2000 |
| ) |
| |
| solution = response.get('solution', '').strip() |
| |
| |
| if is_code_task: |
| try: |
| result, output = self.code_agent.execute_code(solution) |
| return { |
| 'type': 'code', |
| 'solution': solution, |
| 'result': str(result) if result is not None else None, |
| 'output': output, |
| 'success': result is not None, |
| 'source': 'generated' |
| } |
| except Exception as e: |
| logger.error(f"Error executing generated code: {e}") |
| return { |
| 'type': 'code_error', |
| 'solution': solution, |
| 'error': str(e), |
| 'source': 'generated' |
| } |
| except Exception as e: |
| logger.error(f"Error generating solution: {e}") |
| return { |
| 'type': 'error', |
| 'error': str(e), |
| 'source': 'generated' |
| } |
| |
| def _combine_solutions(self, problem: str, solutions: List[Dict[str, Any]]) -> str: |
| """Combine solutions to sub-tasks into a final solution.""" |
| |
| combined = f"# Solution to: {problem}\n\n" |
| |
| for i, sol in enumerate(solutions, 1): |
| combined += f"## Sub-task {i}: {sol['task']}\n\n" |
| if sol['solution'].get('type') == 'code_solution': |
| combined += f"```python\n{sol['solution']['solution']}\n```\n\n" |
| if 'execution_result' in sol['solution']: |
| exec_result = sol['solution']['execution_result'] |
| if exec_result['output']: |
| combined += f"### Output\n```\n{exec_result['output']}\n```\n\n" |
| if exec_result['result']: |
| combined += f"### Result\n```\n{exec_result['result']}\n```\n\n" |
| else: |
| combined += f"{sol['solution'].get('solution', 'No solution generated')}\n\n" |
| |
| return combined |
| |
| def learn_from_experience(self) -> None: |
| """Analyze past solutions to learn patterns and improve future performance.""" |
| logger.info("Analyzing past solutions to learn patterns...") |
| |
| |
| for problem_id, solution_data in self.memory['solutions'].items(): |
| problem = solution_data['problem'] |
| solution = solution_data['solution'] |
| |
| |
| terms = set(problem.lower().split()) |
| |
| |
| for term in terms: |
| if len(term) > 3: |
| if term not in self.memory['patterns']: |
| self.memory['patterns'][term] = [] |
| self.memory['patterns'][term].append({ |
| 'problem': problem, |
| 'solution': solution, |
| 'timestamp': solution_data.get('timestamp', datetime.now().isoformat()) |
| }) |
| |
| |
| self._save_knowledge() |
| logger.info(f"Learned {len(self.memory['patterns'])} patterns from past solutions") |
|
|