feat: integra Planning system nel ReActAgent

- run() crea e traccia task nel planner
- run_plan() esegue sequenze di goal con progresso
- decompose_goal() scompone goal complessi via LLM
- Task tracciati con stato: pending->in_progress->completed/failed
This commit is contained in:
opencode committed 2026-03-24 09:45:21 +01:00
1 parent 1c7781a68f
commit f847b92b0a
1 file changed
+151 -17
+151 -17
View File
@@ -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(