diff --git a/enhancements/react_agent.py b/enhancements/react_agent.py index 85d0819..fb72616 100644 --- a/enhancements/react_agent.py +++ b/enhancements/react_agent.py @@ -147,12 +147,13 @@ Goal: Qual è il contenuto del file? RISPOSTA:""" - def run(self, goal: str) -> Dict[str, Any]: + def run(self, goal: str, track_in_planner: bool = True) -> Dict[str, Any]: """ Esegue un goal attraverso il loop ReAct. Args: goal: Goal da raggiungere + track_in_planner: Se True, traccia il task nel planner Returns: Dict con success, result, steps, iterations @@ -161,12 +162,25 @@ RISPOSTA:""" self.context = f"GOAL: {goal}\n" self.steps = [] + # Traccia nel planner se richiesto + task_id = None + if track_in_planner and self.planner: + task_id = self.planner.create_task( + description=goal, + priority=TaskPriority.MEDIUM + ) + self.planner.start_task(task_id) + if self.verbose: + print(f"📋 Task creato: {task_id}") + if self.verbose: print(f"\n🎯 GOAL: {goal}") print("="*60) # Esegui prima azione current_input = goal + success = False + final_result = "" for iteration in range(1, self.max_iterations + 1): # 1. THINK - analizza input corrente @@ -180,11 +194,16 @@ RISPOSTA:""" if thought.strip().upper().startswith("SUCCESS"): result = thought[len("SUCCESS"):].strip() self._add_step(AgentState.DONE, thought) - return self._build_result(True, result, f"Goal raggiunto in {iteration} step") + success = True + final_result = result + break if thought.strip().upper().startswith("FAIL"): reason = thought[len("FAIL:"):].strip() self._add_step(AgentState.FAILED, thought) + final_result = self.context + if task_id: + self.planner.fail_task(task_id, reason) return self._build_result(False, self.context, reason) # 2. ACT - parse e esegui tool @@ -200,26 +219,37 @@ RISPOSTA:""" self.context += f"\n{observation}" self._add_step(AgentState.OBSERVING, thought, action_result, observation) - # Se l'azione era un tool, verifica se il goal è raggiunto + # Se l'azione era un tool, goal semplice raggiunto if action_result.action_name != "respond": - # Goal semplice raggiunto - tool ha dato la risposta - # Restituisci SUCCESS con il risultato - self._add_step(AgentState.DONE, thought, action_result) - return self._build_result( - True, - action_result.result, - f"Goal raggiunto in {iteration} step con tool {action_result.action_name}" - ) + success = True + final_result = action_result.result + break # 4. EVALUATE - solo per risposte dirette self._add_step(AgentState.EVALUATING, thought, action_result, observation) + current_input = f"Risultato: {action_result.result}\n\nGoal: {goal}\nGoal raggiunto?" - # Max iterations reached - return self._build_result( - False, - self.context, - f"Raggiunto massimo numero di iterazioni ({self.max_iterations})" - ) + # Aggiorna planner + if task_id: + if success: + self.planner.complete_task(task_id, final_result) + if self.verbose: + print(f"✅ Task {task_id} completato") + else: + self.planner.fail_task(task_id, "Max iterations reached") + + if success: + return self._build_result( + True, + final_result, + f"Goal raggiunto in {iteration} step" + ) + else: + return self._build_result( + False, + self.context, + f"Raggiunto massimo numero di iterazioni ({self.max_iterations})" + ) def _think(self, goal: str) -> str: """LLM decide la prossima azione basata su contesto e goal""" @@ -359,6 +389,110 @@ RISPOSTA:""" "total_tasks": len(self.planner.tasks), "plans": len(self.planner.plans) } + + def run_plan(self, goals: List[str], plan_name: str = "multi_step_plan") -> Dict[str, Any]: + """ + Esegue un piano con più goal in sequenza. + + Args: + goals: Lista di goal da eseguire in ordine + plan_name: Nome del piano + + Returns: + Dict con risultati per ogni goal e progresso complessivo + """ + # Crea piano nel planner + plan_id = self.planner.create_plan(plan_name, goals) + + if self.verbose: + print(f"\n📋 PIANO: {plan_name}") + print(f" Goal: {len(goals)}") + print("="*60) + + results = [] + completed = 0 + failed = 0 + + for i, goal in enumerate(goals): + if self.verbose: + print(f"\n--- Goal {i+1}/{len(goals)} ---") + + result = self.run(goal, track_in_planner=True) + results.append({ + "goal": goal, + "success": result["success"], + "result": result["result"][:200] if result["result"] else None, + "error": result.get("error") + }) + + if result["success"]: + completed += 1 + else: + failed += 1 + + # Risultato complessivo + overall_success = failed == 0 + + if self.verbose: + print(f"\n{'='*60}") + print(f"📊 PIANO COMPLETATO") + print(f" Totale: {len(goals)}") + print(f" Completati: {completed}") + print(f" Falliti: {failed}") + + return { + "success": overall_success, + "plan_id": plan_id, + "total_goals": len(goals), + "completed": completed, + "failed": failed, + "results": results, + "plan_progress": self.planner.get_plan_progress(plan_id) + } + + def decompose_goal(self, complex_goal: str) -> List[str]: + """ + Decompone un goal complesso in sotto-goal usando LLM. + + Args: + complex_goal: Goal complesso da decomporre + + Returns: + Lista di sotto-goal + """ + prompt = f"""Scomponi questo goal in passi sequenziali semplici. + +Goal complesso: {complex_goal} + +Elenca i passi necessari, uno per riga. Ogni passo deve essere un'azione concreta. +Non usare numeri o bullet, solo testo puro. + +ESEMPIO: +Goal: Prepara report vendite mensile +Output: +Leggi i dati di vendita dal database +Analizza i dati e calcola totali +Genera il report in formato markdown +Salva il report come report_mese.md""" + + try: + response = self.llm.invoke([HumanMessage(content=prompt)]) + content = response.content if hasattr(response, 'content') else str(response) + + # Parse output - una linea per passo + lines = [l.strip() for l in content.split('\n') if l.strip()] + # Filtra linee vuote e possibili header + steps = [l for l in lines if len(l) > 10 and not l.startswith('#')] + + if self.verbose: + print(f"\n🔬 Goal decomposed into {len(steps)} steps") + + return steps + except Exception as e: + if self.verbose: + print(f"⚠️ Decomposition failed: {e}") + # Fallback: ritorna goal originale + return [complex_goal] def create_react_agent(