731 lines
25 KiB
Python
731 lines
25 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
LangCode Agent - A configurable agent harness using DeepAgents
|
|
Supports multiple LLM providers via LangChain's init_chat_model
|
|
Enhanced with unified provider tools and custom tools
|
|
"""
|
|
import os
|
|
import sys
|
|
from typing import Optional, List, Dict, Any
|
|
from deepagents import create_deep_agent
|
|
from langchain.chat_models import init_chat_model
|
|
from langchain_core.messages import HumanMessage, SystemMessage
|
|
from langchain_core.tools import Tool
|
|
|
|
# Import custom tools
|
|
try:
|
|
from tools import get_proxmox_tools
|
|
from tools.provider_tools import get_provider_tools, get_all_provider_tools
|
|
TOOLS_AVAILABLE = True
|
|
except ImportError:
|
|
TOOLS_AVAILABLE = False
|
|
print("Warning: Custom tools not available. Install required dependencies.")
|
|
|
|
# Import configuration manager
|
|
try:
|
|
from config_manager import config_manager
|
|
CONFIG_AVAILABLE = True
|
|
except ImportError:
|
|
CONFIG_AVAILABLE = False
|
|
print("Warning: Configuration manager not available.")
|
|
|
|
# Import skill manager
|
|
try:
|
|
from skill_manager import skill_manager
|
|
SKILL_MANAGER_AVAILABLE = True
|
|
except ImportError:
|
|
SKILL_MANAGER_AVAILABLE = False
|
|
print("Warning: Skill manager not available.")
|
|
|
|
|
|
def load_model_from_config():
|
|
"""
|
|
Load the LLM model based on configuration.
|
|
Configuration can come from environment variables or a config file.
|
|
For simplicity, we'll use environment variables.
|
|
|
|
Expected environment variables:
|
|
- OPENAI_API_KEY: For OpenAI models
|
|
- OLLAMA_BASE_URL: For Ollama (e.g., https://ollama.solarpi.net)
|
|
- MODEL_PROVIDER: One of "openai", "ollama", "openrouter", etc.
|
|
- MODEL_NAME: The specific model name (e.g., "gpt-4o", "gemma2:9b")
|
|
"""
|
|
provider = os.getenv("MODEL_PROVIDER", "openai").lower()
|
|
model_name = os.getenv("MODEL_NAME", "gpt-4o")
|
|
|
|
# Configure based on provider
|
|
if provider == "openai":
|
|
# Uses OPENAI_API_KEY from environment
|
|
return init_chat_model(f"openai:{model_name}")
|
|
elif provider == "ollama":
|
|
# For Ollama, we need to specify the base URL
|
|
base_url = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
|
|
return init_chat_model(f"ollama:{model_name}", base_url=base_url)
|
|
elif provider == "openrouter":
|
|
# For OpenRouter, we need OPENROUTER_API_KEY and optionally base URL
|
|
# Note: LangChain's init_chat_model for openrouter might require specific setup
|
|
# As of now, we assume it's supported via openai-compatible API
|
|
base_url = os.getenv("OPENROUTER_BASE_URL", "https://openrouter.ai/api/v1")
|
|
api_key = os.getenv("OPENROUTER_API_KEY")
|
|
if not api_key:
|
|
raise ValueError("OPENROUTER_API_KEY environment variable is required for OpenRouter")
|
|
# Using openai-compatible API
|
|
return init_chat_model(
|
|
f"openai:{model_name}",
|
|
base_url=base_url,
|
|
api_key=api_key
|
|
)
|
|
else:
|
|
# Fallback to openai for unknown providers (or add more as needed)
|
|
return init_chat_model(f"openai:{model_name}")
|
|
|
|
|
|
def get_mcp_tools() -> List[Tool]:
|
|
"""
|
|
Get MCP tools from configured MCP servers
|
|
|
|
Returns:
|
|
List of MCP-derived LangChain Tool objects
|
|
"""
|
|
from mcp_client import MCPClient, get_mcp_tools_from_client
|
|
|
|
mcp_tools = []
|
|
|
|
if not CONFIG_AVAILABLE:
|
|
return mcp_tools
|
|
|
|
try:
|
|
# Get all MCP server configurations
|
|
# We'll look for configurations with provider="mcp"
|
|
all_configs = config_manager.get_configurations()
|
|
mcp_configs = {
|
|
name: config for name, config in all_configs.items()
|
|
if config.get("provider") == "mcp"
|
|
}
|
|
|
|
for name, config in mcp_configs.items():
|
|
try:
|
|
server_url = config.get("server_url")
|
|
if not server_url:
|
|
print(f"⚠️ MCP configuration '{name}' missing server_url")
|
|
continue
|
|
|
|
headers = {}
|
|
api_key = config.get("api_key")
|
|
if api_key:
|
|
headers["Authorization"] = f"Bearer {api_key}"
|
|
|
|
mcp_client = MCPClient(
|
|
server_url=server_url,
|
|
headers=headers,
|
|
timeout=config.get("timeout", 30)
|
|
)
|
|
|
|
tools = get_mcp_tools_from_client(mcp_client)
|
|
mcp_tools.extend(tools)
|
|
print(f"✅ Added {len(tools)} tools from MCP server '{name}'")
|
|
except Exception as e:
|
|
print(f"⚠️ Could not load tools from MCP server '{name}': {e}")
|
|
|
|
except Exception as e:
|
|
print(f"⚠️ Error loading MCP tools: {e}")
|
|
|
|
return mcp_tools
|
|
|
|
|
|
def get_skill_tools() -> List[Tool]:
|
|
"""
|
|
Get skill management tools for the LangCode agent
|
|
|
|
Returns:
|
|
List of skill management LangChain Tool objects
|
|
"""
|
|
from skill_manager import skill_manager
|
|
|
|
skill_tools = []
|
|
|
|
# Search for skills
|
|
def search_skills_func(query: str, limit: int = 10) -> str:
|
|
try:
|
|
skills = skill_manager.search_skills(query, limit)
|
|
if not skills:
|
|
return f"No skills found for query: '{query}'"
|
|
|
|
result = f"Found {len(skills)} skills:\n"
|
|
for i, skill in enumerate(skills, 1):
|
|
result += f"{i}. {skill.get('name', 'Unknown')}: {skill.get('description', 'No description')}\n"
|
|
return result
|
|
except Exception as e:
|
|
return f"Error searching skills: {str(e)}"
|
|
|
|
# Install a skill
|
|
def install_skill_func(skill_name: str) -> str:
|
|
try:
|
|
success, message = skill_manager.install_skill(skill_name)
|
|
return message
|
|
except Exception as e:
|
|
return f"Error installing skill: {str(e)}"
|
|
|
|
# Uninstall a skill
|
|
def uninstall_skill_func(skill_name: str) -> str:
|
|
try:
|
|
success, message = skill_manager.uninstall_skill(skill_name)
|
|
return message
|
|
except Exception as e:
|
|
return f"Error uninstalling skill: {str(e)}"
|
|
|
|
# List installed skills
|
|
def list_installed_skills_func() -> str:
|
|
try:
|
|
skills = skill_manager.list_installed_skills()
|
|
if not skills:
|
|
return "No skills installed"
|
|
|
|
result = f"Installed skills ({len(skills)}):\n"
|
|
for i, skill in enumerate(skills, 1):
|
|
result += f"{i}. {skill.get('name', 'Unknown')}: {skill.get('description', 'No description')}\n"
|
|
return result
|
|
except Exception as e:
|
|
return f"Error listing installed skills: {str(e)}"
|
|
|
|
# Get skill details
|
|
def get_skill_details_func(skill_name: str) -> str:
|
|
try:
|
|
details = skill_manager.get_skill_details(skill_name)
|
|
if not details:
|
|
return f"Skill '{skill_name}' not found or no details available"
|
|
|
|
# Format the details nicely
|
|
result = f"Skill: {details.get('name', 'Unknown')}\n"
|
|
result += f"Description: {details.get('description', 'No description')}\n"
|
|
|
|
# Add other relevant details if available
|
|
if 'version' in details:
|
|
result += f"Version: {details['version']}\n"
|
|
if 'author' in details:
|
|
result += f"Author: {details['author']}\n"
|
|
if 'category' in details:
|
|
result += f"Category: {details['category']}\n"
|
|
|
|
return result
|
|
except Exception as e:
|
|
return f"Error getting skill details: {str(e)}"
|
|
|
|
# Create skill management tools
|
|
skill_tools.extend([
|
|
Tool(
|
|
name="search_skills",
|
|
description="Search for agent skills in the skills.sh registry. Use this to find skills by keyword or description.",
|
|
func=search_skills_func
|
|
),
|
|
Tool(
|
|
name="install_skill",
|
|
description="Install a skill from the skills.sh registry. Provide the skill name to install.",
|
|
func=install_skill_func
|
|
),
|
|
Tool(
|
|
name="uninstall_skill",
|
|
description="Uninstall an installed skill. Provide the skill name to remove.",
|
|
func=uninstall_skill_func
|
|
),
|
|
Tool(
|
|
name="list_installed_skills",
|
|
description="List all currently installed skills in the local skills directory.",
|
|
func=list_installed_skills_func
|
|
),
|
|
Tool(
|
|
name="get_skill_details",
|
|
description="Get detailed information about a specific skill. Provide the skill name to get details.",
|
|
func=get_skill_details_func
|
|
)
|
|
])
|
|
|
|
return skill_tools
|
|
|
|
|
|
def get_custom_tools() -> List[Tool]:
|
|
"""
|
|
Get custom tools for the LangCode agent
|
|
|
|
Returns:
|
|
List of custom tools
|
|
"""
|
|
custom_tools = []
|
|
|
|
if not TOOLS_AVAILABLE:
|
|
return custom_tools
|
|
|
|
# Add Proxmox tools if configured
|
|
proxmox_host = os.getenv("PROXMOX_HOST")
|
|
if proxmox_host:
|
|
proxmox_user = os.getenv("PROXMOX_USER", "root")
|
|
proxmox_password = os.getenv("PROXMOX_PASSWORD")
|
|
proxmox_token = os.getenv("PROXMOX_TOKEN")
|
|
|
|
try:
|
|
proxmox_tools = get_proxmox_tools(
|
|
host=proxmox_host,
|
|
user=proxmox_user,
|
|
password=proxmox_password,
|
|
api_token=proxmox_token
|
|
)
|
|
custom_tools.extend(proxmox_tools)
|
|
print(f"✅ Added {len(proxmox_tools)} Proxmox tools")
|
|
except Exception as e:
|
|
print(f"⚠️ Could not load Proxmox tools: {e}")
|
|
|
|
# Add unified provider tools for all configured providers
|
|
try:
|
|
provider_tools = get_all_provider_tools()
|
|
custom_tools.extend(provider_tools)
|
|
print(f"✅ Added {len(provider_tools)} provider tools")
|
|
except Exception as e:
|
|
print(f"⚠️ Could not load provider tools: {e}")
|
|
|
|
# Add MCP tools from configured servers
|
|
try:
|
|
mcp_tools = get_mcp_tools()
|
|
custom_tools.extend(mcp_tools)
|
|
print(f"✅ Added {len(mcp_tools)} MCP tools")
|
|
except Exception as e:
|
|
print(f"⚠️ Could not load MCP tools: {e}")
|
|
|
|
# Add skill management tools
|
|
try:
|
|
skill_tools = get_skill_tools()
|
|
custom_tools.extend(skill_tools)
|
|
print(f"✅ Added {len(skill_tools)} skill management tools")
|
|
except Exception as e:
|
|
print(f"⚠️ Could not load skill tools: {e}")
|
|
|
|
return custom_tools
|
|
|
|
|
|
def create_langcode_agent(system_prompt: Optional[str] = None):
|
|
"""
|
|
Create and return a DeepAgent instance with configurable model.
|
|
"""
|
|
if system_prompt is None:
|
|
system_prompt = """You are LangCode, a helpful AI agent that can plan, use tools,
|
|
manage context, and delegate to subagents. You are designed to be configurable
|
|
to work with various LLM providers.
|
|
|
|
You have access to:
|
|
1. Unified provider tools for managing LLM providers (list models, test connections, etc.)
|
|
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)
|
|
|
|
Use these tools when asked about:
|
|
- LLM provider management (listing models, testing connections, setting defaults)
|
|
- System administration and virtualization
|
|
- AI model management and configuration"""
|
|
|
|
model = load_model_from_config()
|
|
|
|
# Get custom tools
|
|
custom_tools = get_custom_tools()
|
|
|
|
# Create the agent with custom tools
|
|
agent = create_deep_agent(
|
|
model=model,
|
|
tools=custom_tools, # Add custom tools to the agent
|
|
system_prompt=system_prompt
|
|
)
|
|
|
|
return agent
|
|
|
|
|
|
def show_help():
|
|
"""Show available commands"""
|
|
print("""
|
|
📖 Comandi disponibili (prefissati con /):
|
|
|
|
/help, /? - Mostra questo messaggio di aiuto
|
|
/status - Mostra lo stato del sistema
|
|
/config list - Elenca tutte le configurazioni
|
|
/config active - Mostra la configurazione attiva
|
|
/config test - Testa la connessione alla configurazione attiva
|
|
/config use <name> - Cambia la configurazione attiva
|
|
/models - Elenca i modelli disponibili per il provider attivo
|
|
/clear - Pulisce lo schermo
|
|
/exit, /quit - Esci dall'agente
|
|
|
|
💡 Per chattare con l'agente, scrivi semplicemente il tuo messaggio senza "/".
|
|
Esempio: "Ciao, chi sei?" oppure "Elenca i file nella directory corrente"
|
|
""")
|
|
|
|
|
|
def show_status():
|
|
"""Show system status"""
|
|
print("\n📊 Stato del Sistema:")
|
|
print("=" * 40)
|
|
|
|
# Show provider info
|
|
provider = os.getenv("MODEL_PROVIDER", "non configurato")
|
|
model = os.getenv("MODEL_NAME", "non configurato")
|
|
print(f"Provider: {provider}")
|
|
print(f"Modello: {model}")
|
|
|
|
# Show Ollama URL if configured
|
|
if provider == "ollama":
|
|
ollama_url = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
|
|
print(f"Ollama URL: {ollama_url}")
|
|
|
|
# Show configuration status
|
|
if CONFIG_AVAILABLE:
|
|
active_config = config_manager.get_active_configuration()
|
|
if active_config:
|
|
print(f"Configurazione attiva: {active_config}")
|
|
else:
|
|
print("Configurazione attiva: Nessuna")
|
|
|
|
configs = config_manager.get_configurations()
|
|
print(f"Configurazioni totali: {len(configs)}")
|
|
|
|
# Show tools status
|
|
if TOOLS_AVAILABLE:
|
|
print("Strumenti personalizzati: Disponibili")
|
|
else:
|
|
print("Strumenti personalizzati: Non disponibili")
|
|
|
|
|
|
def list_configurations():
|
|
"""List all configurations"""
|
|
if not CONFIG_AVAILABLE:
|
|
print("❌ Gestore configurazioni non disponibile.")
|
|
return
|
|
|
|
configs = config_manager.get_configurations()
|
|
active = config_manager.get_active_configuration()
|
|
|
|
if not configs:
|
|
print("📭 Nessuna configurazione trovata.")
|
|
return
|
|
|
|
print("\n📋 Configurazioni disponibili:")
|
|
print("=" * 50)
|
|
|
|
for name, config in configs.items():
|
|
marker = "✅" if name == active else " "
|
|
provider = config.get("provider", "unknown")
|
|
model = config.get("model_name", "unknown")
|
|
print(f"{marker} {name}: {provider} - {model}")
|
|
|
|
|
|
def show_active_configuration():
|
|
"""Show active configuration"""
|
|
if not CONFIG_AVAILABLE:
|
|
print("❌ Gestore configurazioni non disponibile.")
|
|
return
|
|
|
|
active_name = config_manager.get_active_configuration()
|
|
if not active_name:
|
|
print("📭 Nessuna configurazione attiva.")
|
|
return
|
|
|
|
config = config_manager.get_configuration(active_name)
|
|
if not config:
|
|
print(f"❌ Configurazione '{active_name}' non trovata.")
|
|
return
|
|
|
|
print(f"\n✅ Configurazione attiva: {active_name}")
|
|
print(f" Provider: {config.get('provider', 'unknown')}")
|
|
print(f" Modello: {config.get('model_name', 'unknown')}")
|
|
|
|
if config.get('base_url'):
|
|
print(f" URL: {config.get('base_url')}")
|
|
|
|
|
|
def test_active_configuration():
|
|
"""Test connection to active configuration"""
|
|
if not CONFIG_AVAILABLE:
|
|
print("❌ Gestore configurazioni non disponibile.")
|
|
return
|
|
|
|
active_name = config_manager.get_active_configuration()
|
|
if not active_name:
|
|
print("📭 Nessuna configurazione attiva da testare.")
|
|
return
|
|
|
|
print(f"\n🔍 Test connessione a '{active_name}'...")
|
|
success, message = config_manager.test_configuration_connection(active_name)
|
|
|
|
if success:
|
|
print(f"✅ {message}")
|
|
else:
|
|
print(f"❌ {message}")
|
|
|
|
|
|
def use_configuration(name: str):
|
|
"""Set active configuration"""
|
|
if not CONFIG_AVAILABLE:
|
|
print("❌ Gestore configurazioni non disponibile.")
|
|
return
|
|
|
|
if not config_manager.configuration_exists(name):
|
|
print(f"❌ Configurazione '{name}' non trovata.")
|
|
print("Usa '/config list' per vedere le configurazioni disponibili.")
|
|
return
|
|
|
|
if config_manager.set_active_configuration(name):
|
|
print(f"✅ Configurazione '{name}' impostata come attiva.")
|
|
else:
|
|
print(f"❌ Errore nell'impostare la configurazione '{name}'.")
|
|
|
|
|
|
def list_models():
|
|
"""List available models for current provider"""
|
|
provider = os.getenv("MODEL_PROVIDER", "").lower()
|
|
|
|
if not provider:
|
|
print("❌ Nessun provider configurato.")
|
|
return
|
|
|
|
print(f"\n📋 Modelli disponibili per {provider}:")
|
|
print("=" * 40)
|
|
|
|
# This is a simplified version - in a real implementation,
|
|
# you would call the provider's API to list models
|
|
if provider == "ollama":
|
|
print("Per elencare i modelli Ollama, chiedi all'agente:")
|
|
print(" 'Elenca i modelli disponibili su Ollama'")
|
|
elif provider == "openai":
|
|
print("Modelli OpenAI comuni:")
|
|
print(" - gpt-4o")
|
|
print(" - gpt-4o-mini")
|
|
print(" - gpt-4-turbo")
|
|
print(" - gpt-3.5-turbo")
|
|
elif provider == "openrouter":
|
|
print("Per elencare i modelli OpenRouter, chiedi all'agente:")
|
|
print(" 'Elenca i modelli disponibili su OpenRouter'")
|
|
else:
|
|
print(f"Provider '{provider}' non riconosciuto.")
|
|
|
|
|
|
def clear_screen():
|
|
"""Clear the screen"""
|
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
|
|
|
|
def skills_search(query: str):
|
|
"""Search for skills"""
|
|
from skill_manager import skill_manager
|
|
|
|
try:
|
|
skills = skill_manager.search_skills(query)
|
|
if not skills:
|
|
print(f"No skills found for query: '{query}'")
|
|
return
|
|
|
|
print(f"\nFound {len(skills)} skills:")
|
|
print("=" * 50)
|
|
for i, skill in enumerate(skills, 1):
|
|
print(f"{i}. {skill.get('name', 'Unknown')}")
|
|
print(f" Description: {skill.get('description', 'No description')}")
|
|
if 'version' in skill:
|
|
print(f" Version: {skill['version']}")
|
|
if 'author' in skill:
|
|
print(f" Author: {skill['author']}")
|
|
print()
|
|
except Exception as e:
|
|
print(f"Error searching skills: {str(e)}")
|
|
|
|
|
|
def skills_install(skill_name: str):
|
|
"""Install a skill"""
|
|
from skill_manager import skill_manager
|
|
|
|
try:
|
|
success, message = skill_manager.install_skill(skill_name)
|
|
if success:
|
|
print(f"✅ {message}")
|
|
else:
|
|
print(f"❌ {message}")
|
|
except Exception as e:
|
|
print(f"Error installing skill: {str(e)}")
|
|
|
|
|
|
def skills_uninstall(skill_name: str):
|
|
"""Uninstall a skill"""
|
|
from skill_manager import skill_manager
|
|
|
|
try:
|
|
success, message = skill_manager.uninstall_skill(skill_name)
|
|
if success:
|
|
print(f"✅ {message}")
|
|
else:
|
|
print(f"❌ {message}")
|
|
except Exception as e:
|
|
print(f"Error uninstalling skill: {str(e)}")
|
|
|
|
|
|
def skills_list():
|
|
"""List installed skills"""
|
|
from skill_manager import skill_manager
|
|
|
|
try:
|
|
skills = skill_manager.list_installed_skills()
|
|
if not skills:
|
|
print("No skills installed")
|
|
return
|
|
|
|
print(f"\nInstalled skills ({len(skills)}):")
|
|
print("=" * 50)
|
|
for i, skill in enumerate(skills, 1):
|
|
print(f"{i}. {skill.get('name', 'Unknown')}")
|
|
print(f" Description: {skill.get('description', 'No description')}")
|
|
if 'version' in skill:
|
|
print(f" Version: {skill['version']}")
|
|
if 'author' in skill:
|
|
print(f" Author: {skill['author']}")
|
|
print(f" Path: {skill.get('path', 'Unknown')}")
|
|
print()
|
|
except Exception as e:
|
|
print(f"Error listing installed skills: {str(e)}")
|
|
|
|
|
|
def skills_details(skill_name: str):
|
|
"""Show skill details"""
|
|
from skill_manager import skill_manager
|
|
|
|
try:
|
|
details = skill_manager.get_skill_details(skill_name)
|
|
if not details:
|
|
print(f"Skill '{skill_name}' not found or no details available")
|
|
return
|
|
|
|
print(f"\nSkill Details: {details.get('name', 'Unknown')}")
|
|
print("=" * 50)
|
|
print(f"Description: {details.get('description', 'No description')}")
|
|
if 'version' in details:
|
|
print(f"Version: {details['version']}")
|
|
if 'author' in details:
|
|
print(f"Author: {details['author']}")
|
|
if 'category' in details:
|
|
print(f"Category: {details['category']}")
|
|
if 'repository' in details:
|
|
print(f"Repository: {details['repository']}")
|
|
if 'homepage' in details:
|
|
print(f"Homepage: {details['homepage']}")
|
|
print()
|
|
except Exception as e:
|
|
print(f"Error getting skill details: {str(e)}")
|
|
|
|
|
|
def process_command(user_input: str) -> bool:
|
|
"""
|
|
Process a command starting with "/"
|
|
|
|
Returns:
|
|
True if it was a command, False otherwise
|
|
"""
|
|
if not user_input.startswith('/'):
|
|
return False
|
|
|
|
# Remove the "/" and split into command and arguments
|
|
command_line = user_input[1:].strip()
|
|
parts = command_line.split()
|
|
command = parts[0].lower() if parts else ""
|
|
args = parts[1:] if len(parts) > 1 else []
|
|
|
|
# Process commands
|
|
if command in ['help', '?']:
|
|
show_help()
|
|
elif command == 'status':
|
|
show_status()
|
|
elif command == 'config':
|
|
if not args:
|
|
print("❌ Specifica un sottocomando: list, active, test, use <name>")
|
|
elif args[0] == 'list':
|
|
list_configurations()
|
|
elif args[0] == 'active':
|
|
show_active_configuration()
|
|
elif args[0] == 'test':
|
|
test_active_configuration()
|
|
elif args[0] == 'use' and len(args) > 1:
|
|
use_configuration(args[1])
|
|
else:
|
|
print(f"❌ Sottocomando sconosciuto: {args[0]}")
|
|
print("Sottocomandi disponibili: list, active, test, use <name>")
|
|
elif command == 'skills':
|
|
if not args:
|
|
print("❌ Specifica un sottocomando: search, install, uninstall, list, details")
|
|
elif args[0] == 'search' and len(args) > 1:
|
|
skills_search(' '.join(args[1:]))
|
|
elif args[0] == 'install' and len(args) > 1:
|
|
skills_install(args[1])
|
|
elif args[0] == 'uninstall' and len(args) > 1:
|
|
skills_uninstall(args[1])
|
|
elif args[0] == 'list':
|
|
skills_list()
|
|
elif args[0] == 'details' and len(args) > 1:
|
|
skills_details(args[1])
|
|
else:
|
|
print("❌ Sottocomando sconosciuto o argomenti mancanti")
|
|
print("Sottocomandi disponibili: search <query>, install <name>, uninstall <name>, list, details <name>")
|
|
elif command == 'models':
|
|
list_models()
|
|
elif command == 'clear':
|
|
clear_screen()
|
|
elif command in ['exit', 'quit']:
|
|
print("👋 Goodbye!")
|
|
sys.exit(0)
|
|
else:
|
|
print(f"❌ Comando sconosciuto: /{command}")
|
|
print("Digita /help per vedere i comandi disponibili.")
|
|
|
|
return True
|
|
|
|
|
|
def main():
|
|
"""
|
|
Main entry point for the LangCode agent.
|
|
"""
|
|
print("🚀 Initializing LangCode Agent...")
|
|
|
|
try:
|
|
agent = create_langcode_agent()
|
|
print("✅ Agent initialized successfully!")
|
|
|
|
# Show available tools
|
|
print("\n🔧 Available tools:")
|
|
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💬 You can now interact with the 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:
|
|
user_input = input("\n👤 You: ").strip()
|
|
|
|
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)]})
|
|
# Extract the AI's response
|
|
ai_message = result["messages"][-1]
|
|
print(f"\n🤖 LangCode: {ai_message.content}")
|
|
except Exception as e:
|
|
print(f"\n❌ Error: {str(e)}")
|
|
|
|
except Exception as e:
|
|
print(f"❌ Failed to initialize agent: {str(e)}")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |