diff --git a/__pycache__/config_manager.cpython-314.pyc b/__pycache__/config_manager.cpython-314.pyc deleted file mode 100644 index d9a9267..0000000 Binary files a/__pycache__/config_manager.cpython-314.pyc and /dev/null differ diff --git a/__pycache__/config_tui.cpython-314.pyc b/__pycache__/config_tui.cpython-314.pyc deleted file mode 100644 index e721037..0000000 Binary files a/__pycache__/config_tui.cpython-314.pyc and /dev/null differ diff --git a/__pycache__/main.cpython-314.pyc b/__pycache__/main.cpython-314.pyc index 4d64d5c..2e26d7f 100644 Binary files a/__pycache__/main.cpython-314.pyc and b/__pycache__/main.cpython-314.pyc differ diff --git a/main.py b/main.py index 4f4f357..8cbcd4f 100644 --- a/main.py +++ b/main.py @@ -29,6 +29,14 @@ 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(): """ @@ -125,6 +133,116 @@ def get_mcp_tools() -> List[Tool]: 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 @@ -172,6 +290,14 @@ def get_custom_tools() -> List[Tool]: 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 @@ -187,7 +313,9 @@ def create_langcode_agent(system_prompt: Optional[str] = None): 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. Standard DeepAgents tools (planning, filesystem, shell, subagents) + 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) @@ -381,6 +509,111 @@ def clear_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 "/" @@ -416,6 +649,22 @@ def process_command(user_input: str) -> bool: else: print(f"❌ Sottocomando sconosciuto: {args[0]}") print("Sottocomandi disponibili: list, active, test, use ") + 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 , install , uninstall , list, details ") elif command == 'models': list_models() elif command == 'clear':