feat: Aggiunge miglioramenti per memoria e pianificazione con integrazione MCP

- Aggiunto sistema SimplePersistentMemory per fatti, preferenze e cronologia conversazioni
- Aggiunto EnhancedPlanner con dipendenze task, priorità e tracciamento progresso
- Integrati strumenti di miglioramento nell'agente (remember, recall, preference, planning)
- Aggiunti comandi CLI /memory e /plan per accesso diretto da terminale
- Aggiunto client MCP per connessione a server Model Context Protocol
- Aggiornato README con documentazione completa per tutte le nuove funzionalità
- Corretto parsing comando creazione piano per gestire nomi multi-parola

Nuovi comandi:
- /memory remember <testo> - Ricorda un fatto
- /memory recall <query> - Cerca nella memoria
- /memory preference set/get - Gestisci preferenze
- /memory stats - Statistiche memoria
- /plan create <nome> <task1;task2;...> - Crea un piano
- /plan list - Elenca tutti i piani
- /plan progress <plan_id> - Mostra progresso piano
- /plan start <task_id> - Inizia un task
- /plan complete <task_id> - Completa un task
This commit is contained in:
opencode committed 2026-03-23 08:57:21 +01:00
1 parent 5a8fcda993
commit 56f2819a92
9 files changed
+1889 -1

No files matched your search

+258 -1
View File
@@ -6,6 +6,7 @@ Enhanced with unified provider tools and custom tools
"""
import os
import sys
import json
from typing import Optional, List, Dict, Any
from deepagents import create_deep_agent
from langchain.chat_models import init_chat_model
@@ -37,6 +38,18 @@ except ImportError:
SKILL_MANAGER_AVAILABLE = False
print("Warning: Skill manager not available.")
# Import enhancement modules
try:
from enhancements.simple_memory import simple_memory, create_simple_memory_tools
from enhancements.planning_enhancement import enhanced_planner
ENHANCEMENTS_AVAILABLE = True
except ImportError:
ENHANCEMENTS_AVAILABLE = False
print("Warning: Enhancement modules not available.")
# Import json for memory preference handling
import json
def load_model_from_config():
"""
@@ -298,6 +311,23 @@ def get_custom_tools() -> List[Tool]:
except Exception as e:
print(f"⚠️ Could not load skill tools: {e}")
# Add enhancement tools
try:
if ENHANCEMENTS_AVAILABLE:
# Add simple memory tools
memory_tools = create_simple_memory_tools(simple_memory)
custom_tools.extend(memory_tools)
print(f"✅ Added {len(memory_tools)} simple memory tools")
# Add planning tools
planning_tools = enhanced_planner.create_planning_tools()
custom_tools.extend(planning_tools)
print(f"✅ Added {len(planning_tools)} planning tools")
else:
print("⚠️ Enhancement modules not available, skipping enhancement tools")
except Exception as e:
print(f"⚠️ Could not load enhancement tools: {e}")
return custom_tools
@@ -315,7 +345,8 @@ def create_langcode_agent(system_prompt: Optional[str] = None):
2. Custom tools for managing Proxmox virtual machines
3. MCP tools for accessing external services and skills registries (like skills.sh)
4. Skill management tools for discovering, installing, and managing agent skills
5. Standard DeepAgents tools (planning, filesystem, shell, subagents)
5. Enhancement tools for persistent memory and advanced planning
6. Standard DeepAgents tools (planning, filesystem, shell, subagents)
Use these tools when asked about:
- LLM provider management (listing models, testing connections, setting defaults)
@@ -614,6 +645,173 @@ def skills_details(skill_name: str):
print(f"Error getting skill details: {str(e)}")
def memory_remember(text: str):
"""Remember a fact for future reference"""
from enhancements.simple_memory import simple_memory
try:
# Default category is "general"
simple_memory.add_fact(text, "general")
print(f"✅ Remembered: {text[:100]}{'...' if len(text) > 100 else ''}")
except Exception as e:
print(f"❌ Error remembering: {e}")
def memory_recall(query: str):
"""Recall facts by searching memory"""
from enhancements.simple_memory import simple_memory
try:
results = simple_memory.search_facts(query)
if not results:
print(f"No memories found for: {query}")
return
print(f"\nFound {len(results)} memories:")
print("=" * 50)
for i, fact in enumerate(results[:10], 1): # Limit to 10 results
print(f"{i}. {fact['fact']}")
print(f" Category: {fact['category']}")
print(f" Time: {fact['timestamp']}")
print()
except Exception as e:
print(f"Error recalling: {e}")
def memory_set_preference(key: str, value: str):
"""Set a user preference"""
from enhancements.simple_memory import simple_memory
try:
# Try to parse value as JSON for complex types
try:
parsed_val = json.loads(value)
except:
parsed_val = value
simple_memory.set_preference(key, parsed_val)
print(f"✅ Set preference '{key}' = {parsed_val}")
except Exception as e:
print(f"Error setting preference: {e}")
def memory_preference_get(key: str):
"""Get a user preference"""
from enhancements.simple_memory import simple_memory
try:
val = simple_memory.get_preference(key)
if val is not None:
print(f"Preference '{key}': {val}")
else:
print(f"Preference '{key}' not found")
except Exception as e:
print(f"Error getting preference: {e}")
def memory_stats():
"""Get memory statistics"""
from enhancements.simple_memory import simple_memory
try:
stats = simple_memory.get_memory_stats()
print("\nMemory Statistics:")
print("=" * 30)
print(f"Total Conversations: {stats['total_conversations']}")
print(f"Total Facts: {stats['total_facts']}")
print(f"Total Preferences: {stats['total_preferences']}")
print(f"Total Skills Used: {stats['total_skills_used']}")
print(f"Last Updated: {stats['last_updated'] or 'Never'}")
except Exception as e:
print(f"Error getting memory stats: {e}")
def _strip_quotes(s: str) -> str:
"""Strip surrounding quotes from a string"""
s = s.strip()
if len(s) >= 2:
if (s.startswith('"') and s.endswith('"')) or (s.startswith("'") and s.endswith("'")):
return s[1:-1]
return s
def plan_create(name: str, tasks_string: str):
"""Create a plan with multiple tasks"""
from enhancements.planning_enhancement import enhanced_planner
try:
# Strip quotes from name
name = _strip_quotes(name)
# Split tasks by semicolon and clean up
task_descriptions = [_strip_quotes(t.strip()) for t in tasks_string.split(';') if t.strip()]
if not task_descriptions:
print("❌ No tasks provided")
return
plan_id = enhanced_planner.create_plan(name, task_descriptions)
print(f"✅ Created plan '{name}' with ID: {plan_id}")
print(f" Tasks: {len(task_descriptions)}")
for i, desc in enumerate(task_descriptions, 1):
print(f" {i}. {desc}")
except Exception as e:
print(f"❌ Error creating plan: {e}")
def plan_list():
"""List all plans"""
from enhancements.planning_enhancement import enhanced_planner
try:
if not enhanced_planner.plans:
print("No plans created yet")
return
print(f"\nPlans ({len(enhanced_planner.plans)}):")
print("=" * 50)
for plan_id, task_ids in enhanced_planner.plans.items():
task_count = len(task_ids)
print(f"Plan ID: {plan_id}")
print(f" Tasks: {task_count}")
# Show first few tasks
for i, task_id in enumerate(task_ids[:3], 1):
if task_id in enhanced_planner.tasks:
task = enhanced_planner.tasks[task_id]
print(f" {i}. [{task.status.value}] {task.description}")
else:
print(f" {i}. [unknown] Task {task_id} not found")
if len(task_ids) > 3:
print(f" ... and {len(task_ids) - 3} more tasks")
print()
except Exception as e:
print(f"Error listing plans: {e}")
def plan_progress(plan_id: str):
"""Get progress information for a plan"""
from enhancements.planning_enhancement import enhanced_planner
try:
progress = enhanced_planner.get_plan_progress(plan_id)
if "error" in progress:
print(f"❌ {progress['error']}")
return
print(f"\nPlan {plan_id} Progress:")
print("=" * 40)
print(f"Total Tasks: {progress['total_tasks']}")
print(f"Completed: {progress['completed_tasks']}")
print(f"Failed: {progress['failed_tasks']}")
print(f"In Progress: {progress['in_progress_tasks']}")
print(f"Pending: {progress['pending_tasks']}")
print(f"Progress: {progress['progress_percentage']:.1f}%")
except Exception as e:
print(f"Error getting plan progress: {e}")
def plan_start(task_id: str):
"""Start working on a task"""
from enhancements.planning_enhancement import enhanced_planner
try:
if enhanced_planner.start_task(task_id):
print(f"✅ Started task {task_id}")
else:
print(f"❌ Failed to start task {task_id} - check dependencies or task ID")
except Exception as e:
print(f"Error starting task: {e}")
def plan_complete(task_id: str):
"""Mark a task as completed"""
from enhancements.planning_enhancement import enhanced_planner
try:
if enhanced_planner.complete_task(task_id):
print(f"✅ Completed task {task_id}")
else:
print(f"❌ Failed to complete task {task_id} - check task ID or status")
except Exception as e:
print(f"Error completing task: {e}")
def process_command(user_input: str) -> bool:
"""
Process a command starting with "/"
@@ -665,6 +863,65 @@ def process_command(user_input: str) -> bool:
else:
print("❌ Sottocomando sconosciuto o argomenti mancanti")
print("Sottocomandi disponibili: search <query>, install <name>, uninstall <name>, list, details <name>")
elif command == 'memory':
if not args:
print("❌ Specifica un sottocomando: remember, recall, preference, stats")
elif args[0] == 'remember' and len(args) > 1:
memory_remember(' '.join(args[1:]))
elif args[0] == 'recall' and len(args) > 1:
memory_recall(' '.join(args[1:]))
elif args[0] == 'preference':
if len(args) >= 4 and args[1] == 'set':
# Join everything after 'set' as the value (key is args[2], value is args[3:])
key = args[2]
value = ' '.join(args[3:])
memory_set_preference(key, value)
elif len(args) == 3 and args[1] == 'get':
key = args[2]
memory_preference_get(key)
else:
print("❌ Usage: preference set <key> <value> or preference get <key>")
elif args[0] == 'stats':
memory_stats()
else:
print("❌ Sottocomando sconosciuto o argomenti mancanti")
print("Sottocomandi disponibili: remember <text>, recall <query>, preference set <key> <value>, preference get <key>, stats")
elif command == 'plan':
if not args:
print("❌ Specifica un sottocomando: create, list, progress, start, complete")
elif args[0] == 'create':
# Handle plan creation with proper parsing
# Format: /plan create "Plan Name" "Task 1; Task 2; Task 3"
# Or: /plan create PlanName Task1;Task2;Task3
if len(args) < 3:
print("❌ Usage: /plan create <name> <task1;task2;...>")
else:
# Find the first semicolon to split name from tasks
remaining = ' '.join(args[1:])
# Check if there's a semicolon to determine name/tasks split
if ';' in remaining:
# Find the first semicolon
semi_idx = remaining.index(';')
name = remaining[:semi_idx].strip()
tasks = remaining[semi_idx+1:].strip()
plan_create(name, tasks)
else:
# No semicolon found - use second arg as first task name, rest as description
name = args[1]
tasks = ' '.join(args[2:])
plan_create(name, tasks)
elif args[0] == 'list':
plan_list()
elif args[0] == 'progress' and len(args) > 1:
plan_progress(args[1])
elif args[0] == 'start' and len(args) > 1:
plan_start(args[1])
elif args[0] == 'complete' and len(args) > 1:
plan_complete(args[1])
else:
print("❌ Sottocomando sconosciuto o argomenti mancanti")
print("Sottocomandi disponibili: create <name> <task1> <task2> ..., list, progress <plan_id>, start <task_id>, complete <task_id>")
elif command == 'models':
list_models()
elif command == 'clear':