Rename project: maxclaw → langcode
- Renamed all references from maxclaw to langcode across all files - Renamed maxclaw.py → langcode.py - Renamed completion scripts: maxclaw.bash/zsh → langcode.bash/zsh - Updated Dockerfile, README, all Python files, HTML, JSON, YAML - New Gitea repository: http://192.168.0.183:8085/truetype/langcode_agent.git
This commit is contained in:
1 parent
0612b290d5
commit
eda22811ce
39 files changed
+231
-231
No files matched your search
Executable
+551
@@ -0,0 +1,551 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
LangCode Agent - Unified CLI Entry Point
|
||||
Usage:
|
||||
langcode → avvia l'agent (chat interattiva)
|
||||
langcode chat → avvia l'agent
|
||||
langcode server [--port N] → avvia web server
|
||||
langcode tui → apre TUI configurazione
|
||||
langcode config list → lista configurazioni
|
||||
langcode config add → aggiungi configurazione
|
||||
langcode config remove NAME → rimuovi configurazione
|
||||
langcode config use NAME → attiva configurazione
|
||||
langcode config active → mostra configurazione attiva
|
||||
langcode config test [NAME] → testa connessione
|
||||
langcode config export → esporta configurazioni
|
||||
langcode config import FILE → importa configurazioni
|
||||
langcode config search Q → cerca configurazioni
|
||||
langcode analytics → mostra analytics
|
||||
langcode dashboard → mostra dashboard performance
|
||||
langcode version → mostra versione
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
|
||||
# Add current directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
VERSION = "1.0.0"
|
||||
|
||||
|
||||
def cmd_chat(args):
|
||||
"""Avvia l'agent in modalità chat interattiva"""
|
||||
from main import create_langcode_agent, process_command
|
||||
from langchain_core.messages import HumanMessage
|
||||
|
||||
print("🚀 Inizializzo LangCode Agent...")
|
||||
|
||||
try:
|
||||
agent = create_langcode_agent()
|
||||
print("✅ Agent inizializzato con successo!")
|
||||
|
||||
print("\n🔧 Strumenti disponibili:")
|
||||
print(" • Provider tools: list models, test connections, set defaults")
|
||||
print(" • Proxmox tools: manage VMs, snapshots, resources")
|
||||
print(" • Standard tools: planning, filesystem, shell, subagents")
|
||||
|
||||
print("\n💬 Puoi interagire con l'agent.")
|
||||
print("📌 Comandi speciali (prefissati con /):")
|
||||
print(" /help - Mostra i comandi disponibili")
|
||||
print(" /status - Mostra lo stato del sistema")
|
||||
print(" /config - Gestisci le configurazioni")
|
||||
print(" /exit - Esci dall'agente")
|
||||
print("\n💡 Per chattare, scrivi semplicemente il tuo messaggio.")
|
||||
|
||||
while True:
|
||||
try:
|
||||
user_input = input("\n👤 You: ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
print("\n👋 Arrivederci!")
|
||||
break
|
||||
|
||||
if not user_input:
|
||||
continue
|
||||
|
||||
# Check if it's a command (starts with /)
|
||||
if process_command(user_input):
|
||||
continue
|
||||
|
||||
# Otherwise, treat it as a chat message
|
||||
try:
|
||||
result = agent.invoke({"messages": [HumanMessage(content=user_input)]})
|
||||
ai_message = result["messages"][-1]
|
||||
print(f"\n🤖 LangCode: {ai_message.content}")
|
||||
except Exception as e:
|
||||
print(f"\n❌ Errore: {str(e)}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Inizializzazione fallita: {str(e)}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_server(args):
|
||||
"""Avvia il web server"""
|
||||
import uvicorn
|
||||
from api_server import app
|
||||
|
||||
host = args.host or "0.0.0.0"
|
||||
port = args.port or 8000
|
||||
|
||||
print(f"🌐 Avvio LangCode Web Server su http://{host}:{port}")
|
||||
print(f"📊 Dashboard: http://{host}:{port}/monitoring")
|
||||
print(f"🛒 Marketplace: http://{host}:{port}/marketplace")
|
||||
print(f"📡 API Docs: http://{host}:{port}/docs")
|
||||
print("Premi Ctrl+C per fermare il server\n")
|
||||
|
||||
uvicorn.run(app, host=host, port=port)
|
||||
|
||||
|
||||
def cmd_tui(args):
|
||||
"""Apre la TUI per gestione configurazioni"""
|
||||
from config_tui import main as tui_main
|
||||
tui_main()
|
||||
|
||||
|
||||
def cmd_config_list(args):
|
||||
"""Lista tutte le configurazioni"""
|
||||
from config_cli import print_configurations
|
||||
from config_manager import config_manager
|
||||
|
||||
configs = config_manager.get_configurations()
|
||||
if args.search:
|
||||
from config_cli import filter_configurations
|
||||
configs = filter_configurations(configs, args.search)
|
||||
print_configurations(configs, title=f"Configurazioni trovate per '{args.search}'")
|
||||
else:
|
||||
print_configurations(configs)
|
||||
|
||||
|
||||
def cmd_config_add(args):
|
||||
"""Aggiunge una nuova configurazione"""
|
||||
from config_manager import config_manager
|
||||
|
||||
if args.name and args.provider:
|
||||
# Modalità non-interattiva
|
||||
config_data = {"provider": args.provider}
|
||||
|
||||
if args.model:
|
||||
config_data["model_name"] = args.model
|
||||
else:
|
||||
# Default model per provider
|
||||
defaults = {
|
||||
"openai": "gpt-4o",
|
||||
"ollama": "gemma2:9b",
|
||||
"openrouter": "anthropic/claude-3.5-sonnet",
|
||||
"anthropic": "claude-3-5-sonnet-20241022",
|
||||
"google": "gemini-1.5-pro"
|
||||
}
|
||||
config_data["model_name"] = defaults.get(args.provider, "gpt-4o")
|
||||
|
||||
if args.api_key:
|
||||
config_data["api_key"] = args.api_key
|
||||
if args.base_url:
|
||||
config_data["base_url"] = args.base_url
|
||||
|
||||
try:
|
||||
config_manager.add_configuration(args.name, config_data)
|
||||
print(f"✅ Configurazione '{args.name}' aggiunta con successo!")
|
||||
if args.activate:
|
||||
config_manager.set_active_configuration(args.name)
|
||||
print(f"✅ Configurazione '{args.name}' attivata!")
|
||||
except Exception as e:
|
||||
print(f"❌ Errore: {e}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
# Modalità interattiva
|
||||
from config_cli import add_configuration
|
||||
add_configuration()
|
||||
|
||||
|
||||
def cmd_config_remove(args):
|
||||
"""Rimuove una configurazione"""
|
||||
from config_manager import config_manager
|
||||
|
||||
name = args.name
|
||||
if not name:
|
||||
name = input("Nome configurazione da rimuovere: ").strip()
|
||||
|
||||
if not name:
|
||||
print("❌ Nome richiesto.")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
config_manager.remove_configuration(name)
|
||||
print(f"✅ Configurazione '{name}' rimossa!")
|
||||
except Exception as e:
|
||||
print(f"❌ Errore: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_config_use(args):
|
||||
"""Attiva una configurazione"""
|
||||
from config_manager import config_manager
|
||||
|
||||
try:
|
||||
config_manager.set_active_configuration(args.name)
|
||||
print(f"✅ Configurazione '{args.name}' attivata!")
|
||||
except Exception as e:
|
||||
print(f"❌ Errore: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_config_active(args):
|
||||
"""Mostra la configurazione attiva"""
|
||||
from config_manager import config_manager
|
||||
|
||||
active = config_manager.get_active_configuration()
|
||||
if active:
|
||||
config = config_manager.get_configuration(active)
|
||||
print(f"\n📌 Configurazione attiva: {active}")
|
||||
print(f" Provider: {config.get('provider', 'unknown')}")
|
||||
print(f" Model: {config.get('model_name', 'unknown')}")
|
||||
if config.get('base_url'):
|
||||
print(f" Base URL: {config.get('base_url')}")
|
||||
else:
|
||||
print("⚠️ Nessuna configurazione attiva.")
|
||||
|
||||
|
||||
def cmd_config_test(args):
|
||||
"""Testa una configurazione"""
|
||||
from config_manager import config_manager
|
||||
|
||||
name = args.name or config_manager.get_active_configuration()
|
||||
if not name:
|
||||
print("❌ Nessuna configurazione specificata o attiva.")
|
||||
sys.exit(1)
|
||||
|
||||
config = config_manager.get_configuration(name)
|
||||
if not config:
|
||||
print(f"❌ Configurazione '{name}' non trovata.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"🔍 Test connessione per '{name}'...")
|
||||
provider = config.get("provider", "")
|
||||
|
||||
try:
|
||||
if provider == "ollama":
|
||||
import requests
|
||||
base_url = config.get("base_url", "http://localhost:11434")
|
||||
resp = requests.get(f"{base_url}/api/tags", timeout=10)
|
||||
if resp.status_code == 200:
|
||||
models = resp.json().get("models", [])
|
||||
print(f"✅ Ollama connesso! {len(models)} modelli disponibili.")
|
||||
for m in models[:5]:
|
||||
print(f" • {m['name']}")
|
||||
else:
|
||||
print(f"❌ Errore: HTTP {resp.status_code}")
|
||||
elif provider in ("openai", "openrouter", "anthropic"):
|
||||
api_key = config.get("api_key", "")
|
||||
if not api_key:
|
||||
print("❌ API key non configurata.")
|
||||
sys.exit(1)
|
||||
print("✅ API key presente (test completo richiede una chiamata API)")
|
||||
elif provider == "google":
|
||||
api_key = config.get("api_key", "")
|
||||
if not api_key:
|
||||
print("❌ API key non configurata.")
|
||||
sys.exit(1)
|
||||
print("✅ API key presente (test completo richiede una chiamata API)")
|
||||
else:
|
||||
print(f"⚠️ Test non supportato per provider '{provider}'")
|
||||
except Exception as e:
|
||||
print(f"❌ Errore connessione: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_config_export(args):
|
||||
"""Esporta configurazioni"""
|
||||
from config_cli import export_configurations
|
||||
if args.format and args.output:
|
||||
import json
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from config_manager import config_manager
|
||||
|
||||
configs = config_manager.get_configurations()
|
||||
if not configs:
|
||||
print("❌ Nessuna configurazione da esportare.")
|
||||
return
|
||||
|
||||
try:
|
||||
if args.format == 'json':
|
||||
export_file = Path(f"{args.output}.json")
|
||||
with open(export_file, 'w') as f:
|
||||
json.dump(configs, f, indent=2)
|
||||
else:
|
||||
export_file = Path(f"{args.output}.yaml")
|
||||
with open(export_file, 'w') as f:
|
||||
yaml.dump(configs, f, default_flow_style=False)
|
||||
print(f"✅ Configurazioni esportate in {export_file}")
|
||||
except Exception as e:
|
||||
print(f"❌ Errore: {e}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
export_configurations()
|
||||
|
||||
|
||||
def cmd_config_import(args):
|
||||
"""Importa configurazioni"""
|
||||
if args.file:
|
||||
import json
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from config_manager import config_manager
|
||||
|
||||
file_path = Path(args.file)
|
||||
if not file_path.exists():
|
||||
print(f"❌ File '{args.file}' non trovato.")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
if args.file.endswith('.json'):
|
||||
imported = json.load(f)
|
||||
elif args.file.endswith(('.yaml', '.yml')):
|
||||
imported = yaml.safe_load(f)
|
||||
else:
|
||||
print("❌ Formato non supportato. Usa .json o .yaml")
|
||||
sys.exit(1)
|
||||
|
||||
if not isinstance(imported, dict):
|
||||
print("❌ Formato configurazione non valido.")
|
||||
sys.exit(1)
|
||||
|
||||
count = 0
|
||||
for name, config in imported.items():
|
||||
try:
|
||||
config_manager.add_configuration(name, config)
|
||||
count += 1
|
||||
print(f"✅ Importata: {name}")
|
||||
except Exception as e:
|
||||
print(f"⚠️ '{name}': {e}")
|
||||
|
||||
print(f"\n✅ {count} configurazioni importate.")
|
||||
except Exception as e:
|
||||
print(f"❌ Errore: {e}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
from config_cli import import_configurations
|
||||
import_configurations()
|
||||
|
||||
|
||||
def cmd_config_search(args):
|
||||
"""Cerca configurazioni"""
|
||||
from config_cli import print_configurations, filter_configurations
|
||||
from config_manager import config_manager
|
||||
|
||||
configs = config_manager.get_configurations()
|
||||
filtered = filter_configurations(configs, args.query)
|
||||
print_configurations(filtered, title=f"Risultati per '{args.query}'")
|
||||
|
||||
|
||||
def cmd_analytics(args):
|
||||
"""Mostra analytics"""
|
||||
from analytics import AnalyticsEngine
|
||||
|
||||
engine = AnalyticsEngine()
|
||||
|
||||
if args.report:
|
||||
report = engine.get_detailed_report()
|
||||
print(report)
|
||||
elif args.clear:
|
||||
engine.clear_old_data()
|
||||
print("✅ Dati analytics cancellati.")
|
||||
else:
|
||||
# Mostra riepilogo rapido
|
||||
summary = engine.get_usage_summary()
|
||||
insights = engine.get_insights()
|
||||
|
||||
print("\n📊 LangCode Analytics")
|
||||
print("=" * 40)
|
||||
|
||||
if summary.get("total_conversations", 0) > 0:
|
||||
print(f"\n💬 Conversazioni totali: {summary['total_conversations']}")
|
||||
print(f"📝 Messaggi totali: {summary.get('total_messages', 0)}")
|
||||
print(f"⏱️ Tempo medio risposta: {summary.get('avg_response_time', 0):.2f}s")
|
||||
|
||||
if summary.get("provider_usage"):
|
||||
print("\n🔌 Utilizzo provider:")
|
||||
for provider, count in summary["provider_usage"].items():
|
||||
print(f" • {provider}: {count} volte")
|
||||
|
||||
if summary.get("tool_usage"):
|
||||
print("\n🔧 Utilizzo strumenti:")
|
||||
for tool, count in sorted(summary["tool_usage"].items(), key=lambda x: -x[1])[:5]:
|
||||
print(f" • {tool}: {count} volte")
|
||||
else:
|
||||
print("\n📭 Nessun dato analytics ancora.")
|
||||
print(" Usa l'agent per generare dati!")
|
||||
|
||||
if insights:
|
||||
print("\n💡 Insights:")
|
||||
for insight in insights[:3]:
|
||||
print(f" • {insight}")
|
||||
|
||||
print(f"\n📁 Dati salvati in: {engine.data_dir}")
|
||||
print(" Usa 'langcode analytics --report' per report completo")
|
||||
|
||||
|
||||
def cmd_dashboard(args):
|
||||
"""Mostra dashboard performance"""
|
||||
from dashboard import PerformanceDashboard
|
||||
|
||||
dashboard = PerformanceDashboard()
|
||||
|
||||
if args.clear:
|
||||
dashboard.clear_old_data()
|
||||
print("✅ Dati performance cancellati.")
|
||||
else:
|
||||
report = dashboard.get_summary()
|
||||
print("\n📈 LangCode Performance Dashboard")
|
||||
print("=" * 40)
|
||||
|
||||
if report.get("total_requests", 0) > 0:
|
||||
print(f"\n📊 Richieste totali: {report['total_requests']}")
|
||||
print(f"⏱️ Tempo medio risposta: {report.get('avg_response_time', 0):.2f}s")
|
||||
print(f"✅ Tasso successo: {report.get('success_rate', 0):.1f}%")
|
||||
|
||||
if report.get("slowest_operations"):
|
||||
print("\n🐌 Operazioni più lente:")
|
||||
for op in report["slowest_operations"][:3]:
|
||||
print(f" • {op['name']}: {op['time']:.2f}s")
|
||||
|
||||
if report.get("memory_usage"):
|
||||
mem = report["memory_usage"]
|
||||
print(f"\n💾 Memoria: {mem.get('current', 0):.1f}MB (picco: {mem.get('peak', 0):.1f}MB)")
|
||||
else:
|
||||
print("\n📭 Nessun dato performance ancora.")
|
||||
|
||||
print(f"\n📁 Dati salvati in: {dashboard.data_dir}")
|
||||
|
||||
|
||||
def cmd_version(args):
|
||||
"""Mostra versione"""
|
||||
print(f"LangCode Agent v{VERSION}")
|
||||
print("Agent harness basato su LangChain Deep Agents")
|
||||
print("https://github.com/truetype/langcode_agent")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="langcode",
|
||||
description="🚀 LangCode Agent - AI Agent harness configurabile",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Esempi:
|
||||
langcode Avvia l'agent (chat interattiva)
|
||||
langcode server --port 3000 Avvia web server su porta 3000
|
||||
langcode config list Lista tutte le configurazioni
|
||||
langcode config add -n ollama -p ollama -m gemma2:9b
|
||||
langcode config use ollama Attiva configurazione 'ollama'
|
||||
langcode config test Testa configurazione attiva
|
||||
langcode analytics Mostra riepilogo analytics
|
||||
langcode analytics --report Genera report completo
|
||||
"""
|
||||
)
|
||||
parser.add_argument("--version", "-v", action="version", version=f"langcode {VERSION}")
|
||||
|
||||
subparsers = parser.add_subparsers(dest="command", help="Comandi disponibili")
|
||||
|
||||
# === CHAT (default) ===
|
||||
chat_parser = subparsers.add_parser("chat", help="Avvia l'agent in modalità chat")
|
||||
chat_parser.set_defaults(func=cmd_chat)
|
||||
|
||||
# === SERVER ===
|
||||
server_parser = subparsers.add_parser("server", help="Avvia il web server")
|
||||
server_parser.add_argument("--port", "-p", type=int, default=8000, help="Porta del server (default: 8000)")
|
||||
server_parser.add_argument("--host", "-H", default="0.0.0.0", help="Host del server (default: 0.0.0.0)")
|
||||
server_parser.set_defaults(func=cmd_server)
|
||||
|
||||
# === TUI ===
|
||||
tui_parser = subparsers.add_parser("tui", help="Apre TUI per gestione configurazioni")
|
||||
tui_parser.set_defaults(func=cmd_tui)
|
||||
|
||||
# === CONFIG (nested subcommands) ===
|
||||
config_parser = subparsers.add_parser("config", help="Gestione configurazioni")
|
||||
config_subparsers = config_parser.add_subparsers(dest="config_command", help="Sottocomandi config")
|
||||
|
||||
# config list
|
||||
cl = config_subparsers.add_parser("list", help="Lista configurazioni")
|
||||
cl.add_argument("--search", "-s", help="Filtra per termine di ricerca")
|
||||
cl.set_defaults(func=cmd_config_list)
|
||||
|
||||
# config add
|
||||
ca = config_subparsers.add_parser("add", help="Aggiungi configurazione")
|
||||
ca.add_argument("--name", "-n", help="Nome configurazione")
|
||||
ca.add_argument("--provider", "-p", choices=["openai", "ollama", "openrouter", "anthropic", "google"], help="Provider")
|
||||
ca.add_argument("--model", "-m", help="Nome modello")
|
||||
ca.add_argument("--api-key", "-k", help="API key")
|
||||
ca.add_argument("--base-url", "-u", help="Base URL")
|
||||
ca.add_argument("--activate", "-a", action="store_true", help="Attiva dopo la creazione")
|
||||
ca.set_defaults(func=cmd_config_add)
|
||||
|
||||
# config remove
|
||||
cr = config_subparsers.add_parser("remove", help="Rimuovi configurazione")
|
||||
cr.add_argument("name", help="Nome configurazione da rimuovere")
|
||||
cr.set_defaults(func=cmd_config_remove)
|
||||
|
||||
# config use
|
||||
cu = config_subparsers.add_parser("use", help="Attiva configurazione")
|
||||
cu.add_argument("name", help="Nome configurazione da attivare")
|
||||
cu.set_defaults(func=cmd_config_use)
|
||||
|
||||
# config active
|
||||
cv = config_subparsers.add_parser("active", help="Mostra configurazione attiva")
|
||||
cv.set_defaults(func=cmd_config_active)
|
||||
|
||||
# config test
|
||||
ct = config_subparsers.add_parser("test", help="Testa connessione configurazione")
|
||||
ct.add_argument("name", nargs="?", help="Nome configurazione (default: attiva)")
|
||||
ct.set_defaults(func=cmd_config_test)
|
||||
|
||||
# config export
|
||||
ce = config_subparsers.add_parser("export", help="Esporta configurazioni")
|
||||
ce.add_argument("--format", "-f", choices=["json", "yaml"], help="Formato export")
|
||||
ce.add_argument("--output", "-o", help="Nome file output (senza estensione)")
|
||||
ce.set_defaults(func=cmd_config_export)
|
||||
|
||||
# config import
|
||||
ci = config_subparsers.add_parser("import", help="Importa configurazioni")
|
||||
ci.add_argument("file", nargs="?", help="File da importare (.json o .yaml)")
|
||||
ci.set_defaults(func=cmd_config_import)
|
||||
|
||||
# config search
|
||||
cs = config_subparsers.add_parser("search", help="Cerca configurazioni")
|
||||
cs.add_argument("query", help="Termine di ricerca")
|
||||
cs.set_defaults(func=cmd_config_search)
|
||||
|
||||
# === ANALYTICS ===
|
||||
analytics_parser = subparsers.add_parser("analytics", help="Mostra analytics")
|
||||
analytics_parser.add_argument("--report", "-r", action="store_true", help="Genera report completo")
|
||||
analytics_parser.add_argument("--clear", "-c", action="store_true", help="Cancella dati analytics")
|
||||
analytics_parser.set_defaults(func=cmd_analytics)
|
||||
|
||||
# === DASHBOARD ===
|
||||
dashboard_parser = subparsers.add_parser("dashboard", help="Mostra dashboard performance")
|
||||
dashboard_parser.add_argument("--clear", "-c", action="store_true", help="Cancella dati performance")
|
||||
dashboard_parser.set_defaults(func=cmd_dashboard)
|
||||
|
||||
# === VERSION ===
|
||||
version_parser = subparsers.add_parser("version", help="Mostra versione")
|
||||
version_parser.set_defaults(func=cmd_version)
|
||||
|
||||
# Parse arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
# Se nessun comando, avvia chat (default)
|
||||
if not args.command:
|
||||
args.func = cmd_chat
|
||||
args.func(args)
|
||||
return
|
||||
|
||||
# Esegui il comando
|
||||
if hasattr(args, 'func'):
|
||||
args.func(args)
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user