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:
1 parent
5a8fcda993
commit
56f2819a92
9 files changed
+1889
-1
No files matched your search
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"conversations": [],
|
||||
"facts": [
|
||||
{
|
||||
"timestamp": "2026-03-22T20:18:14.550293",
|
||||
"fact": "LangCode Agent supports MCP integration",
|
||||
"category": "features"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-22T20:27:22.386697",
|
||||
"fact": "LangCode Agent supports MCP integration",
|
||||
"category": "features"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-22T21:16:16.644866",
|
||||
"fact": "\"LangCode Agent supports MCP integration\"",
|
||||
"category": "general"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-22T21:19:31.649087",
|
||||
"fact": "\"LangCode Agent supports MCP integration\"",
|
||||
"category": "general"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-22T21:25:33.013155",
|
||||
"fact": "\"LangCode Agent supports MCP integration\"",
|
||||
"category": "general"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-22T21:30:17.895357",
|
||||
"fact": "\"LangCode Agent supports MCP integration\"",
|
||||
"category": "general"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-22T22:34:46.997791",
|
||||
"fact": "\"LangCode Agent supports MCP integration\"",
|
||||
"category": "general"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-03-23T07:14:33.532609",
|
||||
"fact": "\"LangCode Agent supports MCP integration\"",
|
||||
"category": "general"
|
||||
}
|
||||
],
|
||||
"preferences": {
|
||||
"model_provider": "ollama"
|
||||
},
|
||||
"skills_used": [],
|
||||
"last_updated": "2026-03-23T07:14:33.532819"
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
# LangCode Agent Enhancement Implementation Plan
|
||||
Based on LangChain Deep Agents Architecture Analysis
|
||||
|
||||
## Overview
|
||||
|
||||
This plan outlines the integration of enhancements inspired by LangChain's Deep Agents architecture into the LangCode Agent. The enhancements focus on:
|
||||
|
||||
1. **Advanced Memory Systems** - Persistent, semantic, and summary-based memory
|
||||
2. **Enhanced Planning & Reasoning** - Sophisticated task planning and execution tracking
|
||||
3. **Production Observability** - Monitoring, tracing, and debugging capabilities
|
||||
4. **Agent Hierarchies** - Specialist agents and routing capabilities
|
||||
|
||||
## Phase 1: Foundation Enhancements (Immediate Integration)
|
||||
|
||||
### 1.1 Simple Persistent Memory System
|
||||
**File:** `enhancements/simple_memory.py`
|
||||
**Status:** Implemented and tested
|
||||
**Integration Points:**
|
||||
- Import in `main.py`: `from enhancements.simple_memory import simple_memory, create_simple_memory_tools`
|
||||
- Add to `get_custom_tools()`: Extend with memory tools
|
||||
- Update system prompt to mention memory capabilities
|
||||
- Add CLI commands: `/memory remember`, `/memory recall`, `/memory preference`, `/memory stats`
|
||||
|
||||
### 1.2 Enhanced Planning System
|
||||
**File:** `enhancements/planning_enhancement.py`
|
||||
**Status:** Implemented and tested
|
||||
**Integration Points:**
|
||||
- Import in `main.py`: `from enhancements.planning_enhancement import enhanced_planner`
|
||||
- Add to `get_custom_tools()`: Extend with planning tools
|
||||
- Update system prompt to mention planning capabilities
|
||||
- Enhance existing `/todo` commands or add `/plan` subcommands
|
||||
|
||||
## Phase 2: Advanced Features (Next Iteration)
|
||||
|
||||
### 2.1 Advanced Memory with Vector Storage
|
||||
**File:** `enhancements/memory_enhancement.py`
|
||||
**Dependencies:**
|
||||
- `langchain-community` for OllamaEmbeddings and FAISS
|
||||
- `sentence-transformers` for embeddings
|
||||
**Integration Points:**
|
||||
- Similar to simple memory but with semantic search capabilities
|
||||
- Add background processing for conversation summarization
|
||||
- Implement memory consolidation during idle periods
|
||||
|
||||
### 2.2 Agent Hierarchies and Routing
|
||||
**New File:** `enhancements/agent_hierarchy.py`
|
||||
**Features:**
|
||||
- Specialist agents for different domains (coding, research, system admin)
|
||||
- Intelligent routing based on task analysis
|
||||
- Agent-to-agent communication patterns
|
||||
- Load balancing and specialization
|
||||
|
||||
### 2.3 Production Observability
|
||||
**New File:** `enhancements/observability.py`
|
||||
**Features:**
|
||||
- LangChain-style callbacks for tracing
|
||||
- Tool usage monitoring and metrics
|
||||
- Performance profiling
|
||||
- Error tracking and alerting
|
||||
- Integration with LangSmith or custom monitoring
|
||||
|
||||
## Phase 3: Deep Agents Alignment (Future Work)
|
||||
|
||||
### 3.1 Context Management Enhancements
|
||||
- Implement automatic summarization at 85% context usage
|
||||
- Add file-based storage for large tool outputs
|
||||
- Implement pointer-based context management
|
||||
- Add context compression techniques
|
||||
|
||||
### 3.2 Subagent Spawning Improvements
|
||||
- Enhance the `task` tool with better isolation
|
||||
- Add per-subagent model configuration
|
||||
- Implement subagent pooling for efficiency
|
||||
- Add inter-subagent communication mechanisms
|
||||
|
||||
### 3.3 Advanced Planning Features
|
||||
- Implement plan-and-execute agent pattern
|
||||
- Add self-reflection and critique mechanisms
|
||||
- Enable dynamic replanning based on execution results
|
||||
- Add contingency planning and error recovery
|
||||
|
||||
## Integration Strategy
|
||||
|
||||
### Step-by-Step Integration:
|
||||
|
||||
1. **Start with Simple Enhancements** (Phase 1)
|
||||
- Integrate `simple_memory.py` and `planning_enhancement.py`
|
||||
- Test thoroughly with existing functionality
|
||||
- Gather user feedback
|
||||
|
||||
2. **Update Documentation**
|
||||
- Update `docs/plans/` with enhancement designs
|
||||
- Add usage examples to README
|
||||
- Create tutorial examples
|
||||
|
||||
3. **Gradual Rollout of Advanced Features** (Phase 2)
|
||||
- Add one enhancement at a time
|
||||
- Maintain backward compatibility
|
||||
- Provide migration paths
|
||||
|
||||
4. **Performance Optimization**
|
||||
- Profile and optimize memory usage
|
||||
- Implement caching where appropriate
|
||||
- Add configuration options to enable/disable features
|
||||
|
||||
## CLI Integration Examples
|
||||
|
||||
### Memory Commands:
|
||||
```
|
||||
/memory remember "LangCode uses Ollama for local models" --category architecture
|
||||
/memory recall "Ollama"
|
||||
/memory preference set model_provider ollama
|
||||
/memory preference get model_provider
|
||||
/memory stats
|
||||
```
|
||||
|
||||
### Planning Commands:
|
||||
```
|
||||
/plan create "Implement user authentication" --tasks "Design DB schema" "Create API endpoints" "Write frontend" "Add tests"
|
||||
/plan start auth-plan
|
||||
/plan list
|
||||
/plan progress auth-plan
|
||||
/task list
|
||||
/task start task_0000
|
||||
/task complete task_0000 "Authentication system implemented"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
Add to configuration system:
|
||||
```json
|
||||
{
|
||||
"enhancements": {
|
||||
"memory": {
|
||||
"type": "simple|advanced",
|
||||
"persist_directory": "./.langcode/memory",
|
||||
"max_conversations": 100,
|
||||
"max_facts": 50
|
||||
},
|
||||
"planning": {
|
||||
"enabled": true,
|
||||
"auto_create_todos": true,
|
||||
"dependency_tracking": true
|
||||
},
|
||||
"observability": {
|
||||
"enabled": false,
|
||||
"trace_level": "info",
|
||||
"metrics_endpoint": "http://localhost:9090/metrics"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Backward Compatibility Strategy
|
||||
|
||||
All enhancements are designed to be:
|
||||
- **Optional**: Can be enabled/disabled via configuration
|
||||
- **Additive**: Don't modify existing core functionality
|
||||
- **Testable**: Include comprehensive test suites
|
||||
- **Documented**: Clear usage instructions and examples
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
1. **Dependency Management**:
|
||||
- Enhancements with heavy dependencies are isolated
|
||||
- Fallback to simpler implementations when deps missing
|
||||
- Clear error messages when features unavailable
|
||||
|
||||
2. **Performance Impact**:
|
||||
- Lazy initialization of heavy components
|
||||
- Configurable feature flags
|
||||
- Performance monitoring built-in
|
||||
|
||||
3. **Data Safety**:
|
||||
- Memory data stored locally by default
|
||||
- No automatic data transmission
|
||||
- User control over what gets remembered
|
||||
|
||||
## Success Metrics
|
||||
|
||||
After implementation, measure:
|
||||
- User adoption of new features
|
||||
- Reduction in repeated context requests
|
||||
- Improvement in complex task completion rates
|
||||
- User satisfaction scores
|
||||
- System performance impact
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Review and approve this implementation plan
|
||||
2. Begin Phase 1 integration (simple memory and planning)
|
||||
3. Conduct internal testing
|
||||
4. Gather feedback from pilot users
|
||||
5. Iterate based on feedback
|
||||
6. Proceed to Phase 2 enhancements
|
||||
|
||||
---
|
||||
|
||||
*This plan brings LangCode Agent closer to the production-grade architecture patterns revealed in LangChain's Deep Agents while maintaining the project's core strengths in configurability and modularity.*
|
||||
@@ -20,6 +20,10 @@ Un agente configurabile basato su DeepAgents che supporta più provider LLM.
|
||||
- **Marketplace plugin**: Scopri e installa plugin dal marketplace
|
||||
- **Analytics avanzate**: Analisi dettagliate dell'uso e raccomandazioni
|
||||
- **Comandi integrati**: Comandi speciali con prefisso "/" per gestione rapida
|
||||
- **MCP Integration**: Connect to MCP servers for external services and tools
|
||||
- **Skill Management**: Discover, install, and manage agent skills from skills.sh registry
|
||||
- **Memory Enhancement**: Sistema di memoria persistente per fatti, preferenze e cronologia conversazioni
|
||||
- **Planning Enhancement**: Pianificazione avanzata dei task con dipendenze, tracciamento progresso e monitoraggio stato
|
||||
- **Monitoraggio**: Sistema di logging e monitoraggio delle performance
|
||||
- **Dashboard performance**: Monitoraggio dettagliato delle performance
|
||||
- **Ottimizzazioni performance**: Caching, connection pooling, lazy loading
|
||||
@@ -235,6 +239,23 @@ langcode analytics # Riepilogo rapido
|
||||
langcode analytics --report # Report completo
|
||||
langcode dashboard # Dashboard performance
|
||||
|
||||
# Skills management
|
||||
langcode skills list # Lista skills installate
|
||||
langcode skills search "coding" # Cerca skills
|
||||
langcode skills install "skill-name" # Installa skill
|
||||
langcode skills details "skill-name" # Dettagli skill
|
||||
|
||||
# Memory
|
||||
langcode memory remember "fact" # Ricorda un fatto
|
||||
langcode memory recall "query" # Cerca fatti
|
||||
langcode memory preference set k v # Imposta preferenza
|
||||
langcode memory stats # Statistiche
|
||||
|
||||
# Planning
|
||||
langcode plan create "name" "t1;t2" # Crea piano
|
||||
langcode plan list # Lista piani
|
||||
langcode plan progress plan_id # Progresso piano
|
||||
|
||||
# Info
|
||||
langcode version
|
||||
langcode --help
|
||||
@@ -266,6 +287,19 @@ Quando interagisci con l'agente, puoi usare comandi speciali preceduti da "/" pe
|
||||
/language - Cambia la lingua dell'interfaccia
|
||||
/performance - Mostra il report delle performance
|
||||
/monitoring - Apre la dashboard di monitoraggio
|
||||
/skills list - Elenca skills installate
|
||||
/skills search <q> - Cerca skills nel registry
|
||||
/skills install <n> - Installa una skill
|
||||
/skills details <n> - Mostra dettagli di una skill
|
||||
/memory remember - Ricorda un fatto
|
||||
/memory recall - Cerca fatti nella memoria
|
||||
/memory preference - Gestisci preferenze
|
||||
/memory stats - Statistiche memoria
|
||||
/plan create <n> - Crea un piano
|
||||
/plan list - Lista tutti i piani
|
||||
/plan progress <id> - Mostra progresso piano
|
||||
/plan start <id> - Inizia un task
|
||||
/plan complete <id> - Completa un task
|
||||
/exit, /quit - Esci dall'agente
|
||||
```
|
||||
|
||||
@@ -989,6 +1023,174 @@ I dati di performance vengono salvati in `~/.langcode/performance/` e includono:
|
||||
- Utilizzo provider
|
||||
- Statistiche di sistema
|
||||
|
||||
## MCP Integration
|
||||
|
||||
LangCode Agent supports the Model Context Protocol (MCP) for connecting to external services and tools.
|
||||
|
||||
### Configurazione MCP
|
||||
|
||||
Per configurare un server MCP:
|
||||
|
||||
```bash
|
||||
langcode config add -n my-mcp -p mcp -u http://localhost:8080 --api-key your-key
|
||||
```
|
||||
|
||||
### Utilizzo MCP
|
||||
|
||||
Una volta configurato, gli strumenti MCP sono automaticamente disponibili nell'agente.
|
||||
|
||||
### Strumenti MCP Disponibili
|
||||
|
||||
- Gli strumenti variano in base al server MCP configurato
|
||||
- Consulta la documentazione del server MCP per gli strumenti specifici
|
||||
|
||||
## Skill Management
|
||||
|
||||
LangCode Agent può scoprire, installare e gestire skills dal registry skills.sh.
|
||||
|
||||
### Cercare Skills
|
||||
|
||||
```bash
|
||||
# Cerca skills per parola chiave
|
||||
langcode skills search "coding"
|
||||
/skills search "coding"
|
||||
```
|
||||
|
||||
### Installare Skills
|
||||
|
||||
```bash
|
||||
# Installa una skill
|
||||
langcode skills install "code-review-expert"
|
||||
/skills install "code-review-expert"
|
||||
```
|
||||
|
||||
### Elencare Skills Installate
|
||||
|
||||
```bash
|
||||
# Lista tutte le skills installate
|
||||
langcode skills list
|
||||
/skills list
|
||||
```
|
||||
|
||||
### Dettagli Skill
|
||||
|
||||
```bash
|
||||
# Mostra dettagli di una skill
|
||||
langcode skills details "code-review-expert"
|
||||
/skills details "code-review-expert"
|
||||
```
|
||||
|
||||
### Disinstallare Skills
|
||||
|
||||
```bash
|
||||
# Disinstalla una skill
|
||||
langcode skills uninstall "code-review-expert"
|
||||
/skills uninstall "code-review-expert"
|
||||
```
|
||||
|
||||
### Strumenti Skills nell'Agente
|
||||
|
||||
L'agente ha accesso a strumenti per:
|
||||
- `search_skills`: Cerca skills nel registry
|
||||
- `install_skill`: Installa una skill
|
||||
- `uninstall_skill`: Disinstalla una skill
|
||||
- `list_installed_skills`: Lista skills installate
|
||||
- `get_skill_details`: Ottieni dettagli di una skill
|
||||
|
||||
## Memory Enhancement
|
||||
|
||||
LangCode Agent include un sistema di memoria persistente per ricordare fatti, preferenze e cronologia delle conversazioni.
|
||||
|
||||
### Comandi Memory
|
||||
|
||||
```bash
|
||||
# Ricorda un fatto
|
||||
/memory remember Il mio colore preferito è il blu
|
||||
|
||||
# Cerca fatti nella memoria
|
||||
/memory recall colore
|
||||
|
||||
# Imposta una preferenza
|
||||
/memory preference set tema "dark mode"
|
||||
|
||||
/memory preference set lingua "italiano"
|
||||
|
||||
# Ottieni una preferenza
|
||||
/memory preference get tema
|
||||
|
||||
# Statistiche memoria
|
||||
/memory stats
|
||||
```
|
||||
|
||||
### Strumenti Memory nell'Agente
|
||||
|
||||
L'agente ha accesso a strumenti per:
|
||||
- `remember`: Ricorda un fatto
|
||||
- `recall`: Cerca fatti nella memoria
|
||||
- `preference`: Gestisci preferenze utente
|
||||
- `memory_stats`: Ottieni statistiche della memoria
|
||||
|
||||
### Come Funziona
|
||||
|
||||
La memoria persistente:
|
||||
- Salva automaticamente le conversazioni
|
||||
- Permette di aggiungere fatti categorizzati
|
||||
- Mantiene le preferenze dell'utente
|
||||
- Traccia le skills utilizzate
|
||||
- Persiste tra le sessioni
|
||||
|
||||
## Planning Enhancement
|
||||
|
||||
LangCode Agent include un sistema avanzato di pianificazione con dipendenze, tracciamento del progresso e monitoraggio dello stato.
|
||||
|
||||
### Creare un Piano
|
||||
|
||||
```bash
|
||||
# Crea un piano con più task
|
||||
/plan create "My Project" "Task 1; Task 2; Task 3"
|
||||
```
|
||||
|
||||
### Elencare Piani
|
||||
|
||||
```bash
|
||||
# Lista tutti i piani
|
||||
/plan list
|
||||
```
|
||||
|
||||
### Progresso del Piano
|
||||
|
||||
```bash
|
||||
# Mostra progresso di un piano
|
||||
/plan progress plan_0000
|
||||
```
|
||||
|
||||
### Gestire Task
|
||||
|
||||
```bash
|
||||
# Inizia un task
|
||||
/plan start task_0000
|
||||
|
||||
# Completa un task
|
||||
/plan complete task_0000
|
||||
```
|
||||
|
||||
### Strumenti Planning nell'Agente
|
||||
|
||||
L'agente ha accesso a strumenti per:
|
||||
- `create_task`: Crea un nuovo task
|
||||
- `start_task`: Inizia a lavorare su un task
|
||||
- `complete_task`: Marca un task come completato
|
||||
- `list_tasks`: Lista tutti i task
|
||||
- `get_ready_tasks`: Ottieni task pronti per essere iniziati
|
||||
- `get_plan_progress`: Ottieni progresso di un piano
|
||||
|
||||
### Caratteristiche Avanzate
|
||||
|
||||
- **Priorità**: low, medium, high, urgent
|
||||
- **Dipendenze**: I task possono dipendere da altri task
|
||||
- **Stati**: pending, in_progress, completed, failed, cancelled
|
||||
- **Progresso**: Calcolo automatico della percentuale di completamento
|
||||
|
||||
## Test
|
||||
|
||||
Esegui la suite di test:
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Enhancements for LangCode Agent based on LangChain Deep Agents analysis
|
||||
|
||||
This directory contains planned enhancements to bring LangCode Agent closer to the architecture patterns revealed in LangChain's Deep Agents framework.
|
||||
|
||||
## Planned Enhancements
|
||||
|
||||
1. **Enhanced Memory Systems**
|
||||
- Add VectorStoreRetrieverMemory for semantic recall
|
||||
- Implement SummaryBufferMemory for conversation summarization
|
||||
- Add persistent memory storage for cross-session learning
|
||||
|
||||
2. **Advanced Planning & Reasoning**
|
||||
- Implement plan-and-execute agent pattern
|
||||
- Add self-reflection capabilities
|
||||
- Improve task decomposition and tracking
|
||||
|
||||
3. **Production Observability**
|
||||
- Add LangChain-style callbacks for tracing
|
||||
- Implement tool usage monitoring
|
||||
- Add performance metrics collection
|
||||
|
||||
4. **Advanced Tool Composition**
|
||||
- Implement tool chaining capabilities
|
||||
- Add async tool execution for parallelism
|
||||
- Enhance input validation and error handling
|
||||
|
||||
5. **Agent Hierarchies**
|
||||
- Develop specialist subagents for specific domains
|
||||
- Implement agent routing based on task analysis
|
||||
- Add agent-to-agent communication patterns
|
||||
|
||||
## Implementation Approach
|
||||
|
||||
Each enhancement will be implemented as a separate module that can be optionally integrated into the main agent, maintaining backward compatibility while extending capabilities.
|
||||
|
||||
The enhancements will follow the same patterns already established in the codebase:
|
||||
- Modular design
|
||||
- Configuration-driven behavior
|
||||
- Clear separation of concerns
|
||||
- Comprehensive error handling
|
||||
@@ -0,0 +1,317 @@
|
||||
"""
|
||||
Enhanced memory systems for LangCode Agent
|
||||
Implements advanced memory patterns from LangChain Deep Agents
|
||||
"""
|
||||
import os
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
# Try to import from langchain_core, fallback to community if needed
|
||||
try:
|
||||
from langchain_core.memory import BaseMemory
|
||||
from langchain_core.vectorstores import VectorStore
|
||||
from langchain_core.embeddings import Embeddings
|
||||
from langchain_core.documents import Document
|
||||
from langchain_core.storage import BaseStore
|
||||
from langchain_core.retrievers import BaseRetriever
|
||||
LANGCHAIN_CORE_AVAILABLE = True
|
||||
except ImportError:
|
||||
LANGCHAIN_CORE_AVAILABLE = False
|
||||
# We'll handle this gracefully in the implementation
|
||||
|
||||
# Try to import OllamaEmbeddings
|
||||
try:
|
||||
from langchain_community.embeddings import OllamaEmbeddings
|
||||
OLLAMA_AVAILABLE = True
|
||||
except ImportError:
|
||||
OLLAMA_AVAILABLE = False
|
||||
OllamaEmbeddings = None # type: ignore
|
||||
|
||||
# Try to import FAISS for vector store
|
||||
try:
|
||||
from langchain_community.vectorstores import FAISS
|
||||
FAISS_AVAILABLE = True
|
||||
except ImportError:
|
||||
FAISS_AVAILABLE = False
|
||||
FAISS = None # type: ignore
|
||||
|
||||
# Try to import memory components
|
||||
try:
|
||||
from langchain_core.memory import VectorStoreRetrieverMemory, SummaryBufferMemory
|
||||
MEMORY_COMPONENTS_AVAILABLE = True
|
||||
except ImportError:
|
||||
MEMORY_COMPONENTS_AVAILABLE = False
|
||||
VectorStoreRetrieverMemory = None # type: ignore
|
||||
SummaryBufferMemory = None # type: ignore
|
||||
|
||||
from langchain_core.tools import Tool
|
||||
|
||||
class EnhancedMemoryManager:
|
||||
"""Manages enhanced memory systems for the LangCode Agent"""
|
||||
|
||||
def __init__(self,
|
||||
embedding_model: str = "nomic-embed-text",
|
||||
ollama_base_url: str = "http://localhost:11434",
|
||||
persist_directory: str = "./.langcode/memory"):
|
||||
"""
|
||||
Initialize the enhanced memory manager
|
||||
|
||||
Args:
|
||||
embedding_model: Name of the embedding model to use
|
||||
ollama_base_url: URL for Ollama service
|
||||
persist_directory: Directory to persist memory data
|
||||
"""
|
||||
self.embedding_model = embedding_model
|
||||
self.ollama_base_url = ollama_base_url
|
||||
self.persist_directory = persist_directory
|
||||
|
||||
# Ensure persist directory exists
|
||||
os.makedirs(persist_directory, exist_ok=True)
|
||||
|
||||
# Initialize components if available
|
||||
self.embeddings = None
|
||||
self.vectorstore = None
|
||||
self.summary_memory = None
|
||||
self.vector_memory = None
|
||||
self.docstore = None
|
||||
|
||||
self._initialize_memory_systems()
|
||||
|
||||
def _initialize_memory_systems(self):
|
||||
"""Initialize all memory systems if dependencies are available"""
|
||||
if not (OLLAMA_AVAILABLE and FAISS_AVAILABLE and MEMORY_COMPONENTS_AVAILABLE):
|
||||
missing = []
|
||||
if not OLLAMA_AVAILABLE:
|
||||
missing.append("Ollama embeddings")
|
||||
if not FAISS_AVAILABLE:
|
||||
missing.append("FAISS vector store")
|
||||
if not MEMORY_COMPONENTS_AVAILABLE:
|
||||
missing.append("Memory components")
|
||||
print(f"Warning: Enhanced memory features limited due to missing: {', '.join(missing)}")
|
||||
return
|
||||
|
||||
try:
|
||||
# Initialize embeddings
|
||||
self.embeddings = OllamaEmbeddings(
|
||||
model=self.embedding_model,
|
||||
base_url=self.ollama_base_url
|
||||
)
|
||||
|
||||
# Initialize docstore for storing documents
|
||||
from langchain.storage import InMemoryStore
|
||||
self.docstore = InMemoryStore()
|
||||
|
||||
# Initialize vector store for semantic memory
|
||||
self.vectorstore = FAISS(
|
||||
embedding_function=self.embeddings,
|
||||
index=None,
|
||||
docstore=self.docstore,
|
||||
index_to_docstore_id={}
|
||||
)
|
||||
|
||||
# Initialize vector store memory
|
||||
self.vector_memory = VectorStoreRetrieverMemory(
|
||||
retriever=self.vectorstore.as_retriever(search_kwargs={"k": 3})
|
||||
)
|
||||
|
||||
# Initialize summary memory for conversation compression
|
||||
self.summary_memory = SummaryBufferMemory(
|
||||
max_token_limit=1000
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to initialize enhanced memory systems: {e}")
|
||||
# Reset to None if initialization failed
|
||||
self.embeddings = None
|
||||
self.vectorstore = None
|
||||
self.summary_memory = None
|
||||
self.vector_memory = None
|
||||
self.docstore = None
|
||||
|
||||
def set_llm_for_summary_memory(self, llm):
|
||||
"""Set the LLM for summary memory"""
|
||||
if self.summary_memory and hasattr(self.summary_memory, 'llm'):
|
||||
self.summary_memory.llm = llm
|
||||
|
||||
def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Save context to all memory systems
|
||||
|
||||
Args:
|
||||
inputs: Input values from the conversation
|
||||
outputs: Output values from the conversation
|
||||
"""
|
||||
try:
|
||||
# Save to vector memory
|
||||
if self.vector_memory:
|
||||
self.vector_memory.save_context(inputs, outputs)
|
||||
|
||||
# Save to summary memory
|
||||
if self.summary_memory:
|
||||
self.summary_memory.save_context(inputs, outputs)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to save context to memory: {e}")
|
||||
|
||||
def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Load memory variables from all memory systems
|
||||
|
||||
Args:
|
||||
inputs: Input values for context retrieval
|
||||
|
||||
Returns:
|
||||
Dictionary containing memory variables
|
||||
"""
|
||||
result = {}
|
||||
|
||||
try:
|
||||
# Load from vector memory
|
||||
if self.vector_memory:
|
||||
vector_result = self.vector_memory.load_memory_variables(inputs)
|
||||
result.update(vector_result)
|
||||
|
||||
# Load from summary memory
|
||||
if self.summary_memory:
|
||||
summary_result = self.summary_memory.load_memory_variables(inputs)
|
||||
result.update(summary_result)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to load memory variables: {e}")
|
||||
|
||||
return result
|
||||
|
||||
def add_document(self, content: str, metadata: Optional[Dict[str, Any]] = None) -> None:
|
||||
"""
|
||||
Add a document to the vector store for long-term memory
|
||||
|
||||
Args:
|
||||
content: Document content to store
|
||||
metadata: Optional metadata for the document
|
||||
"""
|
||||
if not self.vectorstore:
|
||||
return
|
||||
|
||||
try:
|
||||
doc = Document(page_content=content, metadata=metadata or {})
|
||||
self.vectorstore.add_documents([doc])
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to add document to vector store: {e}")
|
||||
|
||||
def search_similar(self, query: str, k: int = 3) -> List[Document]:
|
||||
"""
|
||||
Search for similar documents in vector store
|
||||
|
||||
Args:
|
||||
query: Search query
|
||||
k: Number of results to return
|
||||
|
||||
Returns:
|
||||
List of similar documents
|
||||
"""
|
||||
if not self.vectorstore:
|
||||
return []
|
||||
|
||||
try:
|
||||
return self.vectorstore.similarity_search(query, k=k)
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to search vector store: {e}")
|
||||
return []
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Clear all memory systems"""
|
||||
try:
|
||||
if self.vector_memory:
|
||||
self.vector_memory.clear()
|
||||
if self.summary_memory:
|
||||
self.summary_memory.clear()
|
||||
# Reinitialize vector store
|
||||
self._initialize_memory_systems()
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to clear memory systems: {e}")
|
||||
|
||||
def create_memory_tools(memory_manager: EnhancedMemoryManager) -> List[Tool]:
|
||||
"""
|
||||
Create LangChain tools for the enhanced memory system
|
||||
|
||||
Args:
|
||||
memory_manager: Instance of EnhancedMemoryManager
|
||||
|
||||
Returns:
|
||||
List of memory tools
|
||||
"""
|
||||
|
||||
def add_memory_func(content: str, metadata: str = "{}") -> str:
|
||||
try:
|
||||
metadata_dict = json.loads(metadata) if metadata.strip() else {}
|
||||
memory_manager.add_document(content, metadata_dict)
|
||||
return f"Added content to memory: {content[:50]}{'...' if len(content) > 50 else ''}"
|
||||
except Exception as e:
|
||||
return f"Error adding to memory: {str(e)}"
|
||||
|
||||
def search_memory_func(query: str, k: str = "3") -> str:
|
||||
try:
|
||||
k_int = int(k)
|
||||
results = memory_manager.search_similar(query, k_int)
|
||||
if not results:
|
||||
return "No similar memories found."
|
||||
|
||||
result = f"Found {len(results)} similar memories:\n"
|
||||
for i, doc in enumerate(results, 1):
|
||||
result += f"{i}. {doc.page_content[:100]}{'...' if len(doc.page_content) > 100 else ''}\n"
|
||||
if doc.metadata:
|
||||
result += f" Metadata: {doc.metadata}\n"
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error searching memory: {str(e)}"
|
||||
|
||||
def clear_memory_func() -> str:
|
||||
try:
|
||||
memory_manager.clear()
|
||||
return "Memory cleared successfully."
|
||||
except Exception as e:
|
||||
return f"Error clearing memory: {str(e)}"
|
||||
|
||||
def get_memory_stats_func() -> str:
|
||||
try:
|
||||
stats = []
|
||||
if memory_manager.vectorstore:
|
||||
# Try to get vector count
|
||||
try:
|
||||
count = memory_manager.vectorstore.index.ntotal if hasattr(memory_manager.vectorstore.index, 'ntotal') else 'unknown'
|
||||
stats.append(f"Vector store: {count} vectors")
|
||||
except:
|
||||
stats.append("Vector store: active")
|
||||
if memory_manager.summary_memory:
|
||||
stats.append("Summary memory: active")
|
||||
if memory_manager.vector_memory:
|
||||
stats.append("Vector memory: active")
|
||||
return "Memory Systems:\n" + "\n".join(f" - {s}" for s in stats)
|
||||
except Exception as e:
|
||||
return f"Error getting memory stats: {str(e)}"
|
||||
|
||||
return [
|
||||
Tool(
|
||||
name="add_to_memory",
|
||||
description="Add content to long-term memory. Provide content and optional metadata as JSON string.",
|
||||
func=add_memory_func
|
||||
),
|
||||
Tool(
|
||||
name="search_memory",
|
||||
description="Search long-term memory for similar content. Provide query and optional k (number of results, default 3).",
|
||||
func=search_memory_func
|
||||
),
|
||||
Tool(
|
||||
name="clear_memory",
|
||||
description="Clear all long-term memory.",
|
||||
func=clear_memory_func
|
||||
),
|
||||
Tool(
|
||||
name="memory_stats",
|
||||
description="Get statistics about the memory systems.",
|
||||
func=get_memory_stats_func
|
||||
)
|
||||
]
|
||||
|
||||
# Global instance for easy access
|
||||
enhanced_memory_manager = EnhancedMemoryManager()
|
||||
@@ -0,0 +1,364 @@
|
||||
"""
|
||||
Enhanced planning systems for LangCode Agent
|
||||
Implements advanced planning patterns from LangChain Deep Agents
|
||||
"""
|
||||
import json
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional, Tuple
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass, asdict, field
|
||||
from langchain_core.tools import Tool
|
||||
|
||||
class TaskStatus(Enum):
|
||||
PENDING = "pending"
|
||||
IN_PROGRESS = "in_progress"
|
||||
COMPLETED = "completed"
|
||||
CANCELLED = "cancelled"
|
||||
FAILED = "failed"
|
||||
|
||||
class TaskPriority(Enum):
|
||||
LOW = "low"
|
||||
MEDIUM = "medium"
|
||||
HIGH = "high"
|
||||
URGENT = "urgent"
|
||||
|
||||
@dataclass
|
||||
class Task:
|
||||
"""Represents a task in the planning system"""
|
||||
id: str
|
||||
description: str
|
||||
status: TaskStatus
|
||||
priority: TaskPriority
|
||||
created_at: datetime
|
||||
dependencies: List[str] = field(default_factory=list) # List of task IDs that must be completed first
|
||||
started_at: Optional[datetime] = None
|
||||
completed_at: Optional[datetime] = None
|
||||
result: Optional[Any] = None
|
||||
error: Optional[str] = None
|
||||
subtasks: List[str] = field(default_factory=list) # List of subtask IDs
|
||||
|
||||
class EnhancedPlanner:
|
||||
"""Enhanced planning system for LangCode Agent"""
|
||||
|
||||
def __init__(self):
|
||||
self.tasks: Dict[str, Task] = {}
|
||||
self.task_counter = 0
|
||||
self.plans: Dict[str, List[str]] = {} # plan_id -> list of task IDs
|
||||
|
||||
def create_task(self,
|
||||
description: str,
|
||||
priority: TaskPriority = TaskPriority.MEDIUM,
|
||||
dependencies: Optional[List[str]] = None) -> str:
|
||||
"""
|
||||
Create a new task
|
||||
|
||||
Args:
|
||||
description: Task description
|
||||
priority: Task priority level
|
||||
dependencies: List of task IDs that must be completed first
|
||||
|
||||
Returns:
|
||||
Task ID
|
||||
"""
|
||||
if dependencies is None:
|
||||
dependencies = []
|
||||
|
||||
task_id = f"task_{self.task_counter:04d}"
|
||||
self.task_counter += 1
|
||||
|
||||
task = Task(
|
||||
id=task_id,
|
||||
description=description,
|
||||
status=TaskStatus.PENDING,
|
||||
priority=priority,
|
||||
dependencies=dependencies,
|
||||
created_at=datetime.now()
|
||||
)
|
||||
|
||||
self.tasks[task_id] = task
|
||||
return task_id
|
||||
|
||||
def create_plan(self, name: str, task_descriptions: List[str]) -> str:
|
||||
"""
|
||||
Create a plan with multiple tasks
|
||||
|
||||
Args:
|
||||
name: Plan name
|
||||
task_descriptions: List of task descriptions
|
||||
|
||||
Returns:
|
||||
Plan ID
|
||||
"""
|
||||
plan_id = f"plan_{len(self.plans):04d}"
|
||||
task_ids = []
|
||||
|
||||
for desc in task_descriptions:
|
||||
task_id = self.create_task(desc)
|
||||
task_ids.append(task_id)
|
||||
|
||||
self.plans[plan_id] = task_ids
|
||||
return plan_id
|
||||
|
||||
def start_task(self, task_id: str) -> bool:
|
||||
"""
|
||||
Start working on a task
|
||||
|
||||
Args:
|
||||
task_id: ID of the task to start
|
||||
|
||||
Returns:
|
||||
True if task started successfully, False otherwise
|
||||
"""
|
||||
if task_id not in self.tasks:
|
||||
return False
|
||||
|
||||
task = self.tasks[task_id]
|
||||
|
||||
# Check if dependencies are completed
|
||||
for dep_id in task.dependencies:
|
||||
if dep_id not in self.tasks or self.tasks[dep_id].status != TaskStatus.COMPLETED:
|
||||
return False # Dependencies not met
|
||||
|
||||
task.status = TaskStatus.IN_PROGRESS
|
||||
task.started_at = datetime.now()
|
||||
return True
|
||||
|
||||
def complete_task(self, task_id: str, result: Any = None) -> bool:
|
||||
"""
|
||||
Mark a task as completed
|
||||
|
||||
Args:
|
||||
task_id: ID of the task to complete
|
||||
result: Result of the task execution
|
||||
|
||||
Returns:
|
||||
True if task completed successfully, False otherwise
|
||||
"""
|
||||
if task_id not in self.tasks:
|
||||
return False
|
||||
|
||||
task = self.tasks[task_id]
|
||||
if task.status != TaskStatus.IN_PROGRESS:
|
||||
return False
|
||||
|
||||
task.status = TaskStatus.COMPLETED
|
||||
task.completed_at = datetime.now()
|
||||
task.result = result
|
||||
return True
|
||||
|
||||
def fail_task(self, task_id: str, error: str) -> bool:
|
||||
"""
|
||||
Mark a task as failed
|
||||
|
||||
Args:
|
||||
task_id: ID of the task to fail
|
||||
error: Error message
|
||||
|
||||
Returns:
|
||||
True if task marked as failed, False otherwise
|
||||
"""
|
||||
if task_id not in self.tasks:
|
||||
return False
|
||||
|
||||
task = self.tasks[task_id]
|
||||
if task.status != TaskStatus.IN_PROGRESS:
|
||||
return False
|
||||
|
||||
task.status = TaskStatus.FAILED
|
||||
task.completed_at = datetime.now()
|
||||
task.error = error
|
||||
return True
|
||||
|
||||
def get_ready_tasks(self) -> List[Task]:
|
||||
"""
|
||||
Get tasks that are ready to be started (dependencies met)
|
||||
|
||||
Returns:
|
||||
List of ready tasks
|
||||
"""
|
||||
ready_tasks = []
|
||||
for task in self.tasks.values():
|
||||
if task.status == TaskStatus.PENDING:
|
||||
# Check if all dependencies are completed
|
||||
deps_met = True
|
||||
for dep_id in task.dependencies:
|
||||
if dep_id not in self.tasks or self.tasks[dep_id].status != TaskStatus.COMPLETED:
|
||||
deps_met = False
|
||||
break
|
||||
if deps_met:
|
||||
ready_tasks.append(task)
|
||||
return ready_tasks
|
||||
|
||||
def get_task_status(self, task_id: str) -> Optional[TaskStatus]:
|
||||
"""
|
||||
Get the status of a task
|
||||
|
||||
Args:
|
||||
task_id: ID of the task
|
||||
|
||||
Returns:
|
||||
Task status or None if task not found
|
||||
"""
|
||||
if task_id in self.tasks:
|
||||
return self.tasks[task_id].status
|
||||
return None
|
||||
|
||||
def get_plan_progress(self, plan_id: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get progress information for a plan
|
||||
|
||||
Args:
|
||||
plan_id: ID of the plan
|
||||
|
||||
Returns:
|
||||
Dictionary with progress information
|
||||
"""
|
||||
if plan_id not in self.plans:
|
||||
return {"error": "Plan not found"}
|
||||
|
||||
task_ids = self.plans[plan_id]
|
||||
total_tasks = len(task_ids)
|
||||
completed_tasks = 0
|
||||
failed_tasks = 0
|
||||
in_progress_tasks = 0
|
||||
|
||||
for task_id in task_ids:
|
||||
if task_id in self.tasks:
|
||||
task = self.tasks[task_id]
|
||||
if task.status == TaskStatus.COMPLETED:
|
||||
completed_tasks += 1
|
||||
elif task.status == TaskStatus.FAILED:
|
||||
failed_tasks += 1
|
||||
elif task.status == TaskStatus.IN_PROGRESS:
|
||||
in_progress_tasks += 1
|
||||
|
||||
return {
|
||||
"plan_id": plan_id,
|
||||
"total_tasks": total_tasks,
|
||||
"completed_tasks": completed_tasks,
|
||||
"failed_tasks": failed_tasks,
|
||||
"in_progress_tasks": in_progress_tasks,
|
||||
"pending_tasks": total_tasks - completed_tasks - failed_tasks - in_progress_tasks,
|
||||
"progress_percentage": (completed_tasks / total_tasks * 100) if total_tasks > 0 else 0
|
||||
}
|
||||
|
||||
def create_planning_tools(self) -> List[Tool]:
|
||||
"""
|
||||
Create LangChain tools for the planning system
|
||||
|
||||
Returns:
|
||||
List of planning tools
|
||||
"""
|
||||
def create_task_func(description: str, priority: str = "medium", dependencies: str = "") -> str:
|
||||
try:
|
||||
priority_enum = TaskPriority(priority.lower())
|
||||
dep_list = [d.strip() for d in dependencies.split(",") if d.strip()] if dependencies else []
|
||||
task_id = self.create_task(description, priority_enum, dep_list)
|
||||
return f"Created task '{description}' with ID: {task_id}"
|
||||
except Exception as e:
|
||||
return f"Error creating task: {str(e)}"
|
||||
|
||||
def start_task_func(task_id: str) -> str:
|
||||
try:
|
||||
if self.start_task(task_id):
|
||||
return f"Started task {task_id}"
|
||||
else:
|
||||
return f"Failed to start task {task_id} - check dependencies or task ID"
|
||||
except Exception as e:
|
||||
return f"Error starting task: {str(e)}"
|
||||
|
||||
def complete_task_func(task_id: str, result: str = "") -> str:
|
||||
try:
|
||||
if self.complete_task(task_id, result if result else None):
|
||||
return f"Completed task {task_id}"
|
||||
else:
|
||||
return f"Failed to complete task {task_id} - check task ID or status"
|
||||
except Exception as e:
|
||||
return f"Error completing task: {str(e)}"
|
||||
|
||||
def list_tasks_func(status: str = "") -> str:
|
||||
try:
|
||||
if status:
|
||||
status_enum = TaskStatus(status.lower())
|
||||
filtered_tasks = [t for t in self.tasks.values() if t.status == status_enum]
|
||||
else:
|
||||
filtered_tasks = list(self.tasks.values())
|
||||
|
||||
if not filtered_tasks:
|
||||
return "No tasks found"
|
||||
|
||||
result = f"Tasks ({len(filtered_tasks)}):\n"
|
||||
for task in sorted(filtered_tasks, key=lambda t: t.created_at):
|
||||
result += f"- [{task.status.value}] {task.id}: {task.description}\n"
|
||||
if task.dependencies:
|
||||
result += f" Dependencies: {', '.join(task.dependencies)}\n"
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error listing tasks: {str(e)}"
|
||||
|
||||
def get_ready_tasks_func() -> str:
|
||||
try:
|
||||
ready_tasks = self.get_ready_tasks()
|
||||
if not ready_tasks:
|
||||
return "No tasks ready to start"
|
||||
|
||||
result = f"Ready tasks ({len(ready_tasks)}):\n"
|
||||
for task in ready_tasks:
|
||||
result += f"- {task.id}: {task.description}\n"
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error getting ready tasks: {str(e)}"
|
||||
|
||||
def get_plan_progress_func(plan_id: str) -> str:
|
||||
try:
|
||||
progress = self.get_plan_progress(plan_id)
|
||||
if "error" in progress:
|
||||
return progress["error"]
|
||||
|
||||
result = f"Plan {plan_id} Progress:\n"
|
||||
result += f" Total: {progress['total_tasks']}\n"
|
||||
result += f" Completed: {progress['completed_tasks']}\n"
|
||||
result += f" Failed: {progress['failed_tasks']}\n"
|
||||
result += f" In Progress: {progress['in_progress_tasks']}\n"
|
||||
result += f" Pending: {progress['pending_tasks']}\n"
|
||||
result += f" Progress: {progress['progress_percentage']:.1f}%\n"
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error getting plan progress: {str(e)}"
|
||||
|
||||
return [
|
||||
Tool(
|
||||
name="create_task",
|
||||
description="Create a new task. Provide description, priority (low/medium/high/urgent), and optional dependencies (comma-separated task IDs)",
|
||||
func=create_task_func
|
||||
),
|
||||
Tool(
|
||||
name="start_task",
|
||||
description="Start working on a task. Provide task ID",
|
||||
func=start_task_func
|
||||
),
|
||||
Tool(
|
||||
name="complete_task",
|
||||
description="Mark a task as completed. Provide task ID and optional result",
|
||||
func=complete_task_func
|
||||
),
|
||||
Tool(
|
||||
name="list_tasks",
|
||||
description="List all tasks. Optionally filter by status (pending, in_progress, completed, failed)",
|
||||
func=list_tasks_func
|
||||
),
|
||||
Tool(
|
||||
name="get_ready_tasks",
|
||||
description="Get tasks that are ready to be started (dependencies met)",
|
||||
func=get_ready_tasks_func
|
||||
),
|
||||
Tool(
|
||||
name="get_plan_progress",
|
||||
description="Get progress information for a plan. Provide plan ID",
|
||||
func=get_plan_progress_func
|
||||
)
|
||||
]
|
||||
|
||||
# Global planner instance
|
||||
enhanced_planner = EnhancedPlanner()
|
||||
@@ -0,0 +1,266 @@
|
||||
"""
|
||||
Simple memory enhancement for LangCode Agent
|
||||
Implements basic persistent memory without complex dependencies
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, Any, List, Optional
|
||||
from datetime import datetime
|
||||
|
||||
class SimplePersistentMemory:
|
||||
"""Simple persistent memory system for LangCode Agent"""
|
||||
|
||||
def __init__(self, memory_file: str = "./.langcode/simple_memory.json"):
|
||||
"""
|
||||
Initialize the simple persistent memory
|
||||
|
||||
Args:
|
||||
memory_file: Path to the memory file
|
||||
"""
|
||||
self.memory_file = memory_file
|
||||
self.memory_data = {
|
||||
"conversations": [],
|
||||
"facts": [],
|
||||
"preferences": {},
|
||||
"skills_used": [],
|
||||
"last_updated": None
|
||||
}
|
||||
|
||||
# Ensure directory exists
|
||||
os.makedirs(os.path.dirname(memory_file), exist_ok=True)
|
||||
|
||||
# Load existing memory
|
||||
self.load()
|
||||
|
||||
def load(self) -> None:
|
||||
"""Load memory from file"""
|
||||
try:
|
||||
if os.path.exists(self.memory_file):
|
||||
with open(self.memory_file, 'r') as f:
|
||||
self.memory_data = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to load memory: {e}")
|
||||
# Reset to default if load fails
|
||||
self.memory_data = {
|
||||
"conversations": [],
|
||||
"facts": [],
|
||||
"preferences": {},
|
||||
"skills_used": [],
|
||||
"last_updated": None
|
||||
}
|
||||
|
||||
def save(self) -> None:
|
||||
"""Save memory to file"""
|
||||
try:
|
||||
self.memory_data["last_updated"] = datetime.now().isoformat()
|
||||
with open(self.memory_file, 'w') as f:
|
||||
json.dump(self.memory_data, f, indent=2)
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to save memory: {e}")
|
||||
|
||||
def add_conversation(self, user_input: str, agent_response: str) -> None:
|
||||
"""
|
||||
Add a conversation exchange to memory
|
||||
|
||||
Args:
|
||||
user_input: User's input
|
||||
agent_response: Agent's response
|
||||
"""
|
||||
self.memory_data["conversations"].append({
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"user": user_input,
|
||||
"agent": agent_response
|
||||
})
|
||||
|
||||
# Keep only last 100 conversations to prevent file from growing too large
|
||||
if len(self.memory_data["conversations"]) > 100:
|
||||
self.memory_data["conversations"] = self.memory_data["conversations"][-100:]
|
||||
|
||||
self.save()
|
||||
|
||||
def add_fact(self, fact: str, category: str = "general") -> None:
|
||||
"""
|
||||
Add a fact to memory
|
||||
|
||||
Args:
|
||||
fact: The fact to remember
|
||||
category: Category for the fact
|
||||
"""
|
||||
self.memory_data["facts"].append({
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"fact": fact,
|
||||
"category": category
|
||||
})
|
||||
|
||||
# Keep only last 50 facts
|
||||
if len(self.memory_data["facts"]) > 50:
|
||||
self.memory_data["facts"] = self.memory_data["facts"][-50:]
|
||||
|
||||
self.save()
|
||||
|
||||
def set_preference(self, key: str, value: Any) -> None:
|
||||
"""
|
||||
Set a user preference
|
||||
|
||||
Args:
|
||||
key: Preference key
|
||||
value: Preference value
|
||||
"""
|
||||
self.memory_data["preferences"][key] = value
|
||||
self.save()
|
||||
|
||||
def get_preference(self, key: str, default: Any = None) -> Any:
|
||||
"""
|
||||
Get a user preference
|
||||
|
||||
Args:
|
||||
key: Preference key
|
||||
default: Default value if key not found
|
||||
|
||||
Returns:
|
||||
Preference value or default
|
||||
"""
|
||||
return self.memory_data["preferences"].get(key, default)
|
||||
|
||||
def add_skill_used(self, skill_name: str) -> None:
|
||||
"""
|
||||
Record that a skill was used
|
||||
|
||||
Args:
|
||||
skill_name: Name of the skill used
|
||||
"""
|
||||
if skill_name not in self.memory_data["skills_used"]:
|
||||
self.memory_data["skills_used"].append(skill_name)
|
||||
self.save()
|
||||
|
||||
def get_recent_conversations(self, limit: int = 5) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Get recent conversations
|
||||
|
||||
Args:
|
||||
limit: Maximum number of conversations to return
|
||||
|
||||
Returns:
|
||||
List of recent conversations
|
||||
"""
|
||||
return self.memory_data["conversations"][-limit:] if self.memory_data["conversations"] else []
|
||||
|
||||
def search_facts(self, query: str) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Search facts by query
|
||||
|
||||
Args:
|
||||
query: Search query
|
||||
|
||||
Returns:
|
||||
List of matching facts
|
||||
"""
|
||||
query_lower = query.lower()
|
||||
return [
|
||||
fact for fact in self.memory_data["facts"]
|
||||
if query_lower in fact["fact"].lower()
|
||||
]
|
||||
|
||||
def get_memory_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get memory statistics
|
||||
|
||||
Returns:
|
||||
Dictionary with memory statistics
|
||||
"""
|
||||
return {
|
||||
"total_conversations": len(self.memory_data["conversations"]),
|
||||
"total_facts": len(self.memory_data["facts"]),
|
||||
"total_preferences": len(self.memory_data["preferences"]),
|
||||
"total_skills_used": len(self.memory_data["skills_used"]),
|
||||
"last_updated": self.memory_data["last_updated"]
|
||||
}
|
||||
|
||||
def create_simple_memory_tools(memory: SimplePersistentMemory) -> List:
|
||||
"""
|
||||
Create simple tools for the persistent memory system
|
||||
|
||||
Args:
|
||||
memory: Instance of SimplePersistentMemory
|
||||
|
||||
Returns:
|
||||
List of memory tools
|
||||
"""
|
||||
from langchain_core.tools import Tool
|
||||
|
||||
def remember_func(fact: str, category: str = "general") -> str:
|
||||
try:
|
||||
memory.add_fact(fact, category)
|
||||
return f"Remembered: {fact}"
|
||||
except Exception as e:
|
||||
return f"Error remembering: {str(e)}"
|
||||
|
||||
def recall_func(query: str) -> str:
|
||||
try:
|
||||
results = memory.search_facts(query)
|
||||
if not results:
|
||||
return f"No memories found for: {query}"
|
||||
|
||||
result = f"Found {len(results)} memories:\n"
|
||||
for i, fact in enumerate(results[:5], 1): # Limit to 5 results
|
||||
result += f"{i}. {fact['fact']} ({fact['category']})\n"
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error recalling: {str(e)}"
|
||||
|
||||
def preference_func(action: str, key: str = "", value: str = "") -> str:
|
||||
try:
|
||||
if action.lower() == "set" and key and value:
|
||||
# Try to parse value as JSON for complex types
|
||||
try:
|
||||
parsed_value = json.loads(value)
|
||||
except:
|
||||
parsed_value = value
|
||||
memory.set_preference(key, parsed_value)
|
||||
return f"Set preference '{key}' = {parsed_value}"
|
||||
elif action.lower() == "get" and key:
|
||||
val = memory.get_preference(key)
|
||||
return f"Preference '{key}': {val}"
|
||||
else:
|
||||
return "Usage: preference set <key> <value> or preference get <key>"
|
||||
except Exception as e:
|
||||
return f"Error with preference: {str(e)}"
|
||||
|
||||
def stats_func() -> str:
|
||||
try:
|
||||
stats = memory.get_memory_stats()
|
||||
result = "Memory Statistics:\n"
|
||||
result += f" Conversations: {stats['total_conversations']}\n"
|
||||
result += f" Facts: {stats['total_facts']}\n"
|
||||
result += f" Preferences: {stats['total_preferences']}\n"
|
||||
result += f" Skills Used: {stats['total_skills_used']}\n"
|
||||
result += f" Last Updated: {stats['last_updated'] or 'Never'}\n"
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error getting memory stats: {str(e)}"
|
||||
|
||||
return [
|
||||
Tool(
|
||||
name="remember",
|
||||
description="Remember a fact for future reference. Provide fact and optional category.",
|
||||
func=remember_func
|
||||
),
|
||||
Tool(
|
||||
name="recall",
|
||||
description="Recall facts by searching memory. Provide search query.",
|
||||
func=recall_func
|
||||
),
|
||||
Tool(
|
||||
name="preference",
|
||||
description="Get or set user preferences. Usage: preference set <key> <value> or preference get <key>",
|
||||
func=preference_func
|
||||
),
|
||||
Tool(
|
||||
name="memory_stats",
|
||||
description="Get statistics about the memory system.",
|
||||
func=stats_func
|
||||
)
|
||||
]
|
||||
|
||||
# Global instance
|
||||
simple_memory = SimplePersistentMemory()
|
||||
@@ -0,0 +1,193 @@
|
||||
"""
|
||||
Test integration of enhancements with LangCode Agent
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, '.')
|
||||
|
||||
def test_enhancements_import():
|
||||
"""Test that our enhancements can be imported"""
|
||||
print("Testing enhancement imports...")
|
||||
|
||||
try:
|
||||
from enhancements.simple_memory import simple_memory, create_simple_memory_tools
|
||||
print("✓ Simple memory enhancement imported successfully")
|
||||
except Exception as e:
|
||||
print(f"✗ Failed to import simple memory enhancement: {e}")
|
||||
return False
|
||||
|
||||
try:
|
||||
from enhancements.planning_enhancement import enhanced_planner
|
||||
print("✓ Planning enhancement imported successfully")
|
||||
except Exception as e:
|
||||
print(f"✗ Failed to import planning enhancement: {e}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def test_simple_memory():
|
||||
"""Test simple memory functionality"""
|
||||
print("\nTesting simple memory...")
|
||||
|
||||
try:
|
||||
from enhancements.simple_memory import simple_memory
|
||||
|
||||
# Test adding a fact
|
||||
simple_memory.add_fact("LangCode Agent supports MCP integration", "features")
|
||||
print("✓ Added fact to memory")
|
||||
|
||||
# Test recalling
|
||||
results = simple_memory.search_facts("MCP")
|
||||
if results:
|
||||
print(f"✓ Recalled {len(results)} facts about MCP")
|
||||
else:
|
||||
print("✗ Failed to recall facts about MCP")
|
||||
return False
|
||||
|
||||
# Test preference
|
||||
simple_memory.set_preference("model_provider", "ollama")
|
||||
provider = simple_memory.get_preference("model_provider")
|
||||
if provider == "ollama":
|
||||
print("✓ Preference system works")
|
||||
else:
|
||||
print(f"✗ Preference system failed: got {provider}")
|
||||
return False
|
||||
|
||||
# Test stats
|
||||
stats = simple_memory.get_memory_stats()
|
||||
if isinstance(stats, dict) and "total_facts" in stats:
|
||||
print(f"✓ Memory stats work: {stats['total_facts']} facts")
|
||||
else:
|
||||
print("✗ Memory stats failed")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Simple memory test failed: {e}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def test_planning():
|
||||
"""Test planning functionality"""
|
||||
print("\nTesting planning...")
|
||||
|
||||
try:
|
||||
from enhancements.planning_enhancement import enhanced_planner, TaskPriority
|
||||
|
||||
# Test creating a task
|
||||
task_id = enhanced_planner.create_task("Test task", TaskPriority.HIGH)
|
||||
if task_id:
|
||||
print(f"✓ Created task: {task_id}")
|
||||
else:
|
||||
print("✗ Failed to create task")
|
||||
return False
|
||||
|
||||
# Test starting task
|
||||
if enhanced_planner.start_task(task_id):
|
||||
print("✓ Started task successfully")
|
||||
else:
|
||||
print("✗ Failed to start task")
|
||||
return False
|
||||
|
||||
# Test completing task
|
||||
if enhanced_planner.complete_task(task_id, "Task completed successfully"):
|
||||
print("✓ Completed task successfully")
|
||||
else:
|
||||
print("✗ Failed to complete task")
|
||||
return False
|
||||
|
||||
# Test listing tasks by getting the tool and calling it
|
||||
planning_tools = enhanced_planner.create_planning_tools()
|
||||
list_tasks_tool = None
|
||||
for tool in planning_tools:
|
||||
if tool.name == "list_tasks":
|
||||
list_tasks_tool = tool
|
||||
break
|
||||
|
||||
if list_tasks_tool and list_tasks_tool.func:
|
||||
tasks_output = list_tasks_tool.func("")
|
||||
if "Test task" in tasks_output and "completed" in tasks_output:
|
||||
print("✓ Task listing works")
|
||||
else:
|
||||
print("✗ Task listing failed")
|
||||
print(f" Output: {tasks_output}")
|
||||
return False
|
||||
else:
|
||||
print("✗ Could not find or call list_tasks tool")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Planning test failed: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def test_tool_creation():
|
||||
"""Test that our enhancements create valid LangChain tools"""
|
||||
print("\nTesting tool creation...")
|
||||
|
||||
try:
|
||||
from enhancements.simple_memory import create_simple_memory_tools, simple_memory
|
||||
from enhancements.planning_enhancement import enhanced_planner
|
||||
|
||||
# Test simple memory tools
|
||||
memory_tools = create_simple_memory_tools(simple_memory)
|
||||
if len(memory_tools) == 4:
|
||||
print(f"✓ Simple memory tools created: {len(memory_tools)} tools")
|
||||
tool_names = [tool.name for tool in memory_tools]
|
||||
expected = ["remember", "recall", "preference", "memory_stats"]
|
||||
if all(name in tool_names for name in expected):
|
||||
print("✓ All expected memory tools present")
|
||||
else:
|
||||
print(f"✗ Missing some memory tools. Got: {tool_names}")
|
||||
return False
|
||||
else:
|
||||
print(f"✗ Expected 4 memory tools, got {len(memory_tools)}")
|
||||
return False
|
||||
|
||||
# Test planning tools
|
||||
planning_tools = enhanced_planner.create_planning_tools()
|
||||
if len(planning_tools) == 6:
|
||||
print(f"✓ Planning tools created: {len(planning_tools)} tools")
|
||||
tool_names = [tool.name for tool in planning_tools]
|
||||
expected = ["create_task", "start_task", "complete_task", "list_tasks", "get_ready_tasks", "get_plan_progress"]
|
||||
if all(name in tool_names for name in expected):
|
||||
print("✓ All expected planning tools present")
|
||||
else:
|
||||
print(f"✗ Missing some planning tools. Got: {tool_names}")
|
||||
return False
|
||||
else:
|
||||
print(f"✗ Expected 6 planning tools, got {len(planning_tools)}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Tool creation test failed: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""Run all tests"""
|
||||
print("=== LangCode Agent Enhancements Integration Test ===\n")
|
||||
|
||||
all_passed = True
|
||||
|
||||
all_passed &= test_enhancements_import()
|
||||
all_passed &= test_simple_memory()
|
||||
all_passed &= test_planning()
|
||||
all_passed &= test_tool_creation()
|
||||
|
||||
print("\n=== Test Results ===")
|
||||
if all_passed:
|
||||
print("✓ All tests passed! Enhancements are ready for integration.")
|
||||
return 0
|
||||
else:
|
||||
print("✗ Some tests failed. Please review the implementation.")
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -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':
|
||||
|
||||
Reference in new issue
Block a user