From d68417bbc8ee0111a7b6f5ff238b0aae23a8e6d8 Mon Sep 17 00:00:00 2001 From: opencode Date: Sat, 21 Mar 2026 22:39:51 +0100 Subject: [PATCH] cleanup: remove pycache files and update main.py --- __pycache__/config_manager.cpython-314.pyc | Bin 23578 -> 0 bytes __pycache__/config_tui.cpython-314.pyc | Bin 22098 -> 0 bytes __pycache__/main.cpython-314.pyc | Bin 4443 -> 33323 bytes main.py | 251 ++++++++++++++++++++- 4 files changed, 250 insertions(+), 1 deletion(-) delete mode 100644 __pycache__/config_manager.cpython-314.pyc delete mode 100644 __pycache__/config_tui.cpython-314.pyc diff --git a/__pycache__/config_manager.cpython-314.pyc b/__pycache__/config_manager.cpython-314.pyc deleted file mode 100644 index d9a92678e2cc1e68ee045d635bb4517bb661c59f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23578 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 diff --git a/__pycache__/config_tui.cpython-314.pyc b/__pycache__/config_tui.cpython-314.pyc deleted file mode 100644 index e721037527a845870bb16fa97705ce7494a2aae3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22098 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 F`oDv90muLV diff --git a/__pycache__/main.cpython-314.pyc b/__pycache__/main.cpython-314.pyc index 4d64d5cdb0cee2e91e3c0c397f655acf1a167b66..2e26d7fffb8b6589d271615cc863ccefb00514a3 100644 GIT binary patch literal 33323 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 L2K_a?4&na;sZDQy delta 1709 zcmY*ZOKcNo5dQb+_4=8o>paND3B*fD48#y1At{7MQp#(E(jtXe#$Lj<_OAJN4YrH0 z4^&FRjG$wI25%#QK=U$kgDo2G*Jmlq8=(0aSIQLp4!g8aiVsl9nH+nKmW}9 z-^{lk(2ryB*Mk8O0sXc2u68Yi&>uwEAf_(7_z2yM$Esau1}V%WH^E!HE3=cH3BeLv znVa-Zh?Y3vvwU4h;UmcMD?Y^&L5dJTxp0oM0*V)`!3!Zp-1iPbS-7_YT?lrgWc?aA zNArKVC? z0@FVD%m}a=dWC{i!!yFZ6Mks=KH!SD4gO_Fhz;UEfTpuA-TXZdM(nbh&^bE>Z_ldbz67hn0=+x9^$77 z9$cED6p#H?DJt_jNdN1k1pccP7`NT-KSi)tOItmk0*KIb*xohMWOtNB#yj0)pPlLP zi3N6yJ@F$#ifF%GPB1>#F4?!si3#@~$x3l0jndFC(}^@n4pwBqx28*gHe8kph6WG^ zOi9+|&G(bsHyIF%F}u6c;@NoB(aLUW%s%;k|BQ65Tu`MxwWL{nl4VF&ikdZ0^g-6* z+SfO4Nq~m~Qjru6>c`S?!^mDNtKE)}S4|Uwn*d}_#?UQDq6o83j@|lV6FzsZ?Nq%fFWNO3J#~~g`(wfFc(?@H$xPM*YvB#dnzVRh{JBa5 zLUhI~n>Y@V%;6ql5R0aYQ|qC4teVA~<%nsmnyRPjP^wA7kvXozlg&f_@E$Nu!e?>- zk{Sa1apHnFu*4?T*fy?tCEU9h-Zsar2!Vy*;F6Gh$s=!YA$Vpu>Ut3BS`2kBG;Q6p6xy>AZu!hu3U7N9Zh6wwX%F5QYK(u= z_D~*vAP+CZM;2NS{uUm!uirRdJq?+Ba;R;52f8PF2;W5$o;<`K9zpjH5as@eZ(L^P zJ(2NVW_}9~mib8X@Vosz?jCzZ+?8Q3t5 za2MVQ%;BwaLDOe3T_u{BRn@}!IJ%ImvA7=ft8^Eq`CkAf>1SaTfM8beXkGnS#)7XqTh z$4Fd7?W-uhigx{u#-8(i)X=MQ6s*PPF^OtkJ4PYaKUY~|qK{bN!(-1F#J0J&{0kRO BuzUaj 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':