From 781874cb9f04cc0c608b1a3d636f17e9c6d28143 Mon Sep 17 00:00:00 2001 From: RadeenXALNW Date: Fri, 20 Jun 2025 16:26:04 +0000 Subject: [PATCH] added sdk support --- debug.py | 272 +++++++ new-test-2/__init__.py | 0 new-test-2/agent.py | 55 ++ new-test-2/main.py | 71 ++ new-test-2/requirements.txt | 4 + new-test-2/runagent.config.json | 17 + runagent/__init__.py | 22 +- runagent/cli/commands.py | 1008 +++++++++++++----------- runagent/cli/main.py | 6 +- runagent/client/__init__.py | 914 +-------------------- runagent/client/agents.py | 165 ++++ runagent/client/config.py | 193 +++++ runagent/client/deployment/__init__.py | 8 + runagent/client/deployment/local.py | 285 +++++++ runagent/client/deployment/remote.py | 160 ++++ runagent/client/exceptions.py | 37 +- runagent/client/sdk.py | 571 ++++++++++++++ runagent/client/template_manager.py | 167 ++++ runagent/constants.py | 2 +- runagent/test/debug_sdk.py | 81 ++ runagent/test/sdk_test.py | 38 + runagent/test/test_http.py | 62 ++ sdk-agent/__init__.py | 0 sdk-agent/agent.py | 55 ++ sdk-agent/main.py | 71 ++ sdk-agent/requirements.txt | 4 + sdk-agent/runagent.config.json | 17 + 27 files changed, 2900 insertions(+), 1385 deletions(-) create mode 100644 debug.py create mode 100644 new-test-2/__init__.py create mode 100644 new-test-2/agent.py create mode 100644 new-test-2/main.py create mode 100644 new-test-2/requirements.txt create mode 100644 new-test-2/runagent.config.json create mode 100644 runagent/client/agents.py create mode 100644 runagent/client/config.py create mode 100644 runagent/client/deployment/__init__.py create mode 100644 runagent/client/deployment/local.py create mode 100644 runagent/client/deployment/remote.py create mode 100644 runagent/client/sdk.py create mode 100644 runagent/client/template_manager.py create mode 100644 runagent/test/debug_sdk.py create mode 100644 runagent/test/sdk_test.py create mode 100644 runagent/test/test_http.py create mode 100644 sdk-agent/__init__.py create mode 100644 sdk-agent/agent.py create mode 100644 sdk-agent/main.py create mode 100644 sdk-agent/requirements.txt create mode 100644 sdk-agent/runagent.config.json diff --git a/debug.py b/debug.py new file mode 100644 index 0000000..fa20d9d --- /dev/null +++ b/debug.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python3 +""" +Debug script to identify why agent 732e45b2 is failing +""" + +import sys +import importlib.util +import traceback +import os +from pathlib import Path + +def debug_agent(agent_id="d6594457"): + """Debug the specific agent to find the exact error""" + + print(f"๐Ÿ” Debugging agent: {agent_id}") + print("=" * 50) + + # 1. Check agent directory + agent_dir = Path(f"deployments/{agent_id}") + print(f"๐Ÿ“ Agent directory: {agent_dir}") + print(f"๐Ÿ“ Directory exists: {agent_dir.exists()}") + + if not agent_dir.exists(): + print("โŒ Agent directory not found!") + return + + # 2. List files + print(f"๐Ÿ“„ Files in directory:") + for item in agent_dir.iterdir(): + size = item.stat().st_size if item.is_file() else "DIR" + print(f" - {item.name} ({size} bytes)") + + # 3. Check main.py exists + main_file = agent_dir / "main.py" + print(f"\n๐Ÿ“„ main.py exists: {main_file.exists()}") + + if not main_file.exists(): + print("โŒ main.py not found!") + return + + # 4. Check main.py content + print(f"\n๐Ÿ“„ main.py content (first 500 chars):") + try: + content = main_file.read_text() + print(content[:500] + ("..." if len(content) > 500 else "")) + print(f"\n๐Ÿ“„ File size: {len(content)} characters") + print(f"๐Ÿ“„ Has 'def run(': {'def run(' in content}") + except Exception as e: + print(f"โŒ Error reading main.py: {e}") + return + + # 5. Check requirements.txt + req_file = agent_dir / "requirements.txt" + print(f"\n๐Ÿ“‹ requirements.txt exists: {req_file.exists()}") + if req_file.exists(): + try: + reqs = req_file.read_text() + print(f"๐Ÿ“‹ Requirements:\n{reqs}") + except Exception as e: + print(f"โŒ Error reading requirements.txt: {e}") + + # 6. Check .env file + env_file = agent_dir / ".env" + print(f"\n๐Ÿ” .env file exists: {env_file.exists()}") + if env_file.exists(): + try: + env_content = env_file.read_text() + # Don't print actual keys, just show structure + lines = env_content.strip().split('\n') + print(f"๐Ÿ” .env has {len(lines)} lines") + for line in lines: + if '=' in line: + key = line.split('=')[0] + print(f" - {key}=***") + except Exception as e: + print(f"โŒ Error reading .env: {e}") + + # 7. Try to import main.py + print(f"\n๐Ÿ”„ Attempting to import main.py...") + + # Save original path + original_path = sys.path.copy() + + try: + # Add agent directory to Python path + sys.path.insert(0, str(agent_dir)) + + # Try to import + spec = importlib.util.spec_from_file_location("main", main_file) + if spec is None: + print("โŒ Could not create module spec") + return + + print("โœ… Module spec created successfully") + + main_module = importlib.util.module_from_spec(spec) + print("โœ… Module object created successfully") + + # Try to execute the module + print("๐Ÿ”„ Executing module...") + spec.loader.exec_module(main_module) + print("โœ… Module executed successfully") + + # Check for run function + if hasattr(main_module, 'run'): + print("โœ… 'run' function found") + print(f"โœ… 'run' is callable: {callable(main_module.run)}") + + # Try to call the run function + print("\n๐Ÿ”„ Testing run function with sample input...") + test_input = { + "messages": [{"role": "user", "content": "Hello test"}], + "config": {} + } + + try: + result = main_module.run(test_input) + print("โœ… Run function executed successfully!") + print(f"๐Ÿ“ค Result type: {type(result)}") + print(f"๐Ÿ“ค Result: {result}") + + # Check result format + if isinstance(result, dict): + print("โœ… Result is a dictionary") + if 'success' in result: + print(f"โœ… Has 'success' key: {result['success']}") + if 'result' in result: + print(f"โœ… Has 'result' key: {type(result['result'])}") + if 'errors' in result: + print(f"โš ๏ธ Has 'errors' key: {result['errors']}") + else: + print(f"โš ๏ธ Result is not a dictionary: {type(result)}") + + except Exception as e: + print(f"โŒ Error calling run function: {e}") + print(f"๐Ÿ“‹ Traceback:\n{traceback.format_exc()}") + else: + print("โŒ 'run' function not found!") + print(f"๐Ÿ“‹ Available attributes: {[attr for attr in dir(main_module) if not attr.startswith('_')]}") + + except Exception as e: + print(f"โŒ Error during import: {e}") + print(f"๐Ÿ“‹ Traceback:\n{traceback.format_exc()}") + + finally: + # Restore original Python path + sys.path = original_path + print(f"\n๐Ÿ”„ Python path restored") + + # 8. Check environment variables + print(f"\n๐Ÿ” Environment variables check:") + important_env_vars = ['OPENAI_API_KEY', 'PYTHONPATH'] + for var in important_env_vars: + value = os.environ.get(var) + if value: + print(f" - {var}: {'***' if 'KEY' in var else value}") + else: + print(f" - {var}: Not set") + + # 9. Check Python environment + print(f"\n๐Ÿ Python environment:") + print(f" - Python version: {sys.version}") + print(f" - Python executable: {sys.executable}") + print(f" - Current working directory: {os.getcwd()}") + + # 10. Check installed packages relevant to the agent + print(f"\n๐Ÿ“ฆ Checking installed packages:") + packages_to_check = ['langchain', 'langchain_openai', 'openai', 'python-dotenv'] + + for package in packages_to_check: + try: + __import__(package) + print(f" โœ… {package}: Installed") + except ImportError: + print(f" โŒ {package}: Not installed") + except Exception as e: + print(f" โš ๏ธ {package}: Error - {e}") + + print("\n" + "=" * 50) + print("๐Ÿ” Debug complete!") + + +def install_missing_dependencies(): + """Install missing dependencies for the agent""" + print("๐Ÿ“ฆ Installing missing dependencies...") + + import subprocess + + requirements = [ + "langchain==0.1.0", + "langchain-openai==0.0.5", + "openai==1.12.0", + "python-dotenv==1.0.0" + ] + + for req in requirements: + try: + print(f" Installing {req}...") + subprocess.check_call([ + sys.executable, "-m", "pip", "install", req, "--quiet" + ]) + print(f" โœ… {req} installed") + except subprocess.CalledProcessError as e: + print(f" โŒ Failed to install {req}: {e}") + + +def fix_env_file(agent_id="732e45b2"): + """Create or fix .env file for the agent""" + agent_dir = Path(f"deployments/{agent_id}") + env_file = agent_dir / ".env" + + print(f"๐Ÿ” Fixing .env file for agent {agent_id}") + + # Create a basic .env file with placeholder + env_content = """# RunAgent Environment Variables +OPENAI_API_KEY=your-openai-api-key-here + +# Note: Replace 'your-openai-api-key-here' with your actual OpenAI API key +# You can get one from: https://platform.openai.com/api-keys +""" + + try: + with open(env_file, 'w') as f: + f.write(env_content) + print(f"โœ… Created .env file at {env_file}") + print("โš ๏ธ Remember to add your actual OpenAI API key!") + except Exception as e: + print(f"โŒ Failed to create .env file: {e}") + + +def quick_fix_all(agent_id="732e45b2"): + """Apply all quick fixes""" + print("๐Ÿ”ง Applying quick fixes...") + print("=" * 50) + + # 1. Install dependencies + install_missing_dependencies() + + # 2. Fix .env file + fix_env_file(agent_id) + + # 3. Set temporary API key for testing + os.environ['OPENAI_API_KEY'] = 'test-key-for-debugging' + print("๐Ÿ” Set temporary OPENAI_API_KEY for testing") + + print("=" * 50) + print("โœ… Quick fixes applied!") + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description="Debug RunAgent local agent") + parser.add_argument("--agent-id", default="732e45b2", help="Agent ID to debug") + parser.add_argument("--fix", action="store_true", help="Apply quick fixes") + parser.add_argument("--install-deps", action="store_true", help="Install missing dependencies") + parser.add_argument("--fix-env", action="store_true", help="Fix .env file") + + args = parser.parse_args() + + if args.fix: + quick_fix_all(args.agent_id) + print("\n" + "=" * 50) + + if args.install_deps: + install_missing_dependencies() + + if args.fix_env: + fix_env_file(args.agent_id) + + # Always run debug + debug_agent(args.agent_id) \ No newline at end of file diff --git a/new-test-2/__init__.py b/new-test-2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/new-test-2/agent.py b/new-test-2/agent.py new file mode 100644 index 0000000..5094b47 --- /dev/null +++ b/new-test-2/agent.py @@ -0,0 +1,55 @@ +from typing import Dict, Any +from langchain_openai import ChatOpenAI +from langchain.chains import ConversationChain +from langchain.memory import ConversationBufferMemory +from langchain_core.messages import HumanMessage, AIMessage +import os +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +class LangChainBasicAgent: + """Basic LangChain agent with conversation memory""" + + def __init__(self, config: Dict[str, Any] = None): + self.config = config or {} + self.llm = ChatOpenAI( + temperature=self.config.get("temperature", 0.7), + model=self.config.get("model", "gpt-4o-mini"), + api_key=os.getenv("OPENAI_API_KEY") + ) + self.memory = ConversationBufferMemory() + self.conversation = ConversationChain( + llm=self.llm, + memory=self.memory, + verbose=self.config.get("verbose", False) + ) + + def process_message(self, message: str) -> str: + """Process a single message and return response""" + try: + response = self.conversation.predict(input=message) + return response + except Exception as e: + raise Exception(f"Error processing message: {str(e)}") + + def process_messages(self, messages: list) -> str: + """Process a list of messages and return the final response""" + if not messages: + return "No messages provided" + + # Add previous messages to memory (except the last one) + for msg in messages[:-1]: + if msg.get("role") == "user": + self.memory.chat_memory.add_user_message(msg["content"]) + elif msg.get("role") == "assistant": + self.memory.chat_memory.add_ai_message(msg["content"]) + + # Process the last message + last_message = messages[-1]["content"] + return self.process_message(last_message) + + def get_conversation_history(self) -> list: + """Get the conversation history""" + return self.memory.chat_memory.messages \ No newline at end of file diff --git a/new-test-2/main.py b/new-test-2/main.py new file mode 100644 index 0000000..678b515 --- /dev/null +++ b/new-test-2/main.py @@ -0,0 +1,71 @@ +from typing import Dict, Any +import time +from agent import LangChainBasicAgent + +def run(input_data: Dict[str, Any]) -> Dict[str, Any]: + """ + Main entry point for the LangChain Basic agent + + Args: + input_data: Dictionary containing: + - messages: List of message objects with 'role' and 'content' + - config: Optional configuration parameters + + Returns: + Dictionary with result, errors, and success status + """ + start_time = time.time() + + try: + # Extract configuration + config = input_data.get("config", {}) + messages = input_data.get("messages", []) + + if not messages: + return { + "result": { + "type": "string", + "content": "No messages provided", + "metadata": { + "execution_time": time.time() - start_time + } + }, + "errors": ["No messages provided"], + "success": False + } + + # Initialize agent + agent = LangChainBasicAgent(config) + + # Process messages + response = agent.process_messages(messages) + + # Calculate execution time + execution_time = time.time() - start_time + + return { + "result": { + "type": "string", + "content": response, + "metadata": { + "model_used": config.get("model", "gpt-4"), + "framework": "langchain", + "template": "basic", + "execution_time": execution_time, + "conversation_length": len(messages) + } + }, + "errors": [], + "success": True + } + + except Exception as e: + execution_time = time.time() - start_time + return { + "result": None, + "errors": [str(e)], + "success": False, + "metadata": { + "execution_time": execution_time + } + } \ No newline at end of file diff --git a/new-test-2/requirements.txt b/new-test-2/requirements.txt new file mode 100644 index 0000000..762acbe --- /dev/null +++ b/new-test-2/requirements.txt @@ -0,0 +1,4 @@ +langchain +langchain-openai +openai +python-dotenv diff --git a/new-test-2/runagent.config.json b/new-test-2/runagent.config.json new file mode 100644 index 0000000..b12c578 --- /dev/null +++ b/new-test-2/runagent.config.json @@ -0,0 +1,17 @@ +{ + "agent_name": "new-test-2", + "framework": "langchain", + "template": "basic", + "version": "0.1.0", + "created_at": "2025-06-17 13:42:03", + "template_source": { + "repo_url": "https://github.com/runagent-dev/runagent.git", + "branch": "radeen/cli-update", + "path": "templates/langchain/basic" + }, + "architecture": { + "main_file": "main.py", + "agent_file": "agent.py", + "entry_point": "run" + } +} \ No newline at end of file diff --git a/runagent/__init__.py b/runagent/__init__.py index a8e2a34..f0a95a8 100644 --- a/runagent/__init__.py +++ b/runagent/__init__.py @@ -1,15 +1,25 @@ -# runagent/__init__.py """ RunAgent - Deploy and manage AI agents easily. This package provides both a CLI and SDK for deploying and managing AI agents -built with frameworks like LangGraph. +built with frameworks like LangGraph, LangChain, and LlamaIndex. """ __version__ = "0.1.0" -# from .client import RunAgentClient -# from .client.exceptions import RunAgentClientError, AuthenticationError +# Import the main SDK components +from .client import RunAgentSDK, RunAgentError, AuthenticationError, ValidationError, ConnectionError, ServerError -# # Expose the client as the main interface -# __all__ = ["RunAgentClient", "RunAgentClientError", "AuthenticationError"] +# Main export - this is what was missing! +RunAgent = RunAgentSDK + +# Expose the main components for easy import +__all__ = [ + "RunAgent", + "RunAgentSDK", + "RunAgentError", + "AuthenticationError", + "ValidationError", + "ConnectionError", + "ServerError" +] diff --git a/runagent/cli/commands.py b/runagent/cli/commands.py index 321fb46..bfdf06f 100644 --- a/runagent/cli/commands.py +++ b/runagent/cli/commands.py @@ -1,6 +1,24 @@ +""" +CLI commands that use the restructured SDK internally. +""" + import click -import inquirer -from runagent.client import RunAgentClient +import json +import requests +from pathlib import Path +from rich.console import Console + +# Import the new SDK +from runagent import RunAgent +from runagent.client.exceptions import ( + RunAgentError, + AuthenticationError, + ValidationError, + TemplateError, + ConnectionError +) + +console = Console() @click.command() @@ -9,285 +27,343 @@ @click.option('--force', is_flag=True, help='Force reconfiguration') def setup(api_key, base_url, force): """Setup RunAgent authentication""" - client = RunAgentClient(cli_mode=True) # Enable interactive mode - client.setup(api_key=api_key, base_url=base_url, force=force) + try: + sdk = RunAgent() + + # Check if already configured + if sdk.is_configured() and not force: + config_status = sdk.get_config_status() + console.print("โš ๏ธ RunAgent is already configured:") + console.print(f" Base URL: [blue]{config_status.get('base_url')}[/blue]") + console.print(f" User: [green]{config_status.get('user_info', {}).get('email', 'Unknown')}[/green]") + + if not click.confirm("Do you want to reconfigure?"): + return + + # Configure SDK + sdk.configure(api_key=api_key, base_url=base_url, save=True) + + console.print("โœ… [green]Setup completed successfully![/green]") + + # Show user info + config_status = sdk.get_config_status() + user_info = config_status.get('user_info', {}) + if user_info: + console.print("\n๐Ÿ‘ค [bold]User Information:[/bold]") + for key, value in user_info.items(): + console.print(f" {key}: [cyan]{value}[/cyan]") + + except AuthenticationError as e: + console.print(f"โŒ [red]Authentication failed:[/red] {e}") + raise click.ClickException("Setup failed") + except Exception as e: + console.print(f"โŒ [red]Setup error:[/red] {e}") + raise click.ClickException("Setup failed") @click.command() @click.option('--yes', is_flag=True, help='Skip confirmation') def teardown(yes): """Remove RunAgent configuration""" - client = RunAgentClient(cli_mode=True) # Enable interactive mode - client.teardown(confirm=yes) + try: + sdk = RunAgent() + + if not yes: + config_status = sdk.get_config_status() + if config_status.get('configured'): + console.print("๐Ÿ“‹ [bold]Current configuration:[/bold]") + console.print(f" Base URL: [blue]{config_status.get('base_url')}[/blue]") + user_info = config_status.get('user_info', {}) + if user_info.get('email'): + console.print(f" User: [green]{user_info.get('email')}[/green]") + + if not click.confirm("โš ๏ธ This will remove all RunAgent configuration. Continue?"): + console.print("Teardown cancelled.") + return + + # Clear configuration + sdk.config.clear() + + console.print("โœ… [green]RunAgent teardown completed successfully![/green]") + console.print("๐Ÿ’ก Run [cyan]'runagent setup --api-key '[/cyan] to reconfigure") + + except Exception as e: + console.print(f"โŒ [red]Teardown error:[/red] {e}") + raise click.ClickException("Teardown failed") @click.command() @click.option('--folder', help='Project folder name') -@click.option('--framework', default=None, help='Framework to use (langchain, langgraph, llamaindex). Defaults to langchain if not specified') -@click.option('--template', default=None, help='Template variant (basic, advanced). Defaults to basic if not specified') -@click.option('--non-interactive', is_flag=True, help='Skip interactive prompts and use defaults (langchain/basic)') -def init(folder, framework, template, non_interactive): - """Initialize a new RunAgent project - - Examples: - runagent init # Interactive mode - runagent init --non-interactive # Use defaults (langchain/basic) - runagent init --framework langgraph # Specify framework, prompt for template - runagent init --framework langchain --template advanced # Specify both (no prompts) - """ - - # Determine if we should use CLI mode - # CLI mode is disabled if --non-interactive is used OR if both framework and template are provided - use_cli_mode = not non_interactive and not (framework and template) +@click.option('--framework', default=None, help='Framework to use (langchain, langgraph, llamaindex)') +@click.option('--template', default=None, help='Template variant (basic, advanced)') +@click.option('--non-interactive', is_flag=True, help='Skip interactive prompts') +@click.option('--overwrite', is_flag=True, help='Overwrite existing folder') +def init(folder, framework, template, non_interactive, overwrite): + """Initialize a new RunAgent project""" - client = RunAgentClient(cli_mode=use_cli_mode) - - # Call the init method - success = client.init( - framework=framework, - template=template, - folder=folder - ) - - if not success: + try: + sdk = RunAgent() + + # Get folder name + if not folder: + if non_interactive: + folder = "runagent-project" + else: + folder = click.prompt("๐Ÿ“ Project folder name", default="runagent-project") + + # Interactive framework selection + if not non_interactive and not framework: + templates = sdk.list_templates() + frameworks = list(templates.keys()) + + console.print("๐ŸŽฏ [bold]Available frameworks:[/bold]") + for i, fw in enumerate(frameworks, 1): + console.print(f" {i}. {fw}") + + choice = click.prompt( + "Select framework", + type=click.IntRange(1, len(frameworks)), + default=1 + ) + framework = frameworks[choice - 1] + + # Interactive template selection + if not non_interactive and not template: + templates = sdk.list_templates(framework) + template_list = templates.get(framework, ['basic']) + + console.print(f"\n๐Ÿงฑ [bold]Available templates for {framework}:[/bold]") + for i, tmpl in enumerate(template_list, 1): + console.print(f" {i}. {tmpl}") + + choice = click.prompt( + "Select template", + type=click.IntRange(1, len(template_list)), + default=1 + ) + template = template_list[choice - 1] + + # Use defaults if not specified + framework = framework or "langchain" + template = template or "basic" + + console.print(f"\n๐Ÿš€ [bold]Initializing project:[/bold]") + console.print(f" Folder: [cyan]{folder}[/cyan]") + console.print(f" Framework: [magenta]{framework}[/magenta]") + console.print(f" Template: [yellow]{template}[/yellow]") + + # Initialize project + success = sdk.init_project( + folder=folder, + framework=framework, + template=template, + overwrite=overwrite + ) + + if success: + console.print(f"\nโœ… [green]Project initialized successfully![/green]") + console.print(f"๐Ÿ“ Created: [cyan]{folder}[/cyan]") + + # Show next steps + console.print("\n๐Ÿ“ [bold]Next steps:[/bold]") + console.print(f" 1๏ธโƒฃ [cyan]cd {folder}[/cyan]") + console.print(f" 2๏ธโƒฃ Update your API keys in [yellow].env[/yellow] file") + console.print(f" 3๏ธโƒฃ Test locally: [cyan]python main.py[/cyan]") + console.print(f" 4๏ธโƒฃ Deploy: [cyan]runagent deploy-local --folder {folder}[/cyan]") + + except TemplateError as e: + console.print(f"โŒ [red]Template error:[/red] {e}") + raise click.ClickException("Project initialization failed") + except FileExistsError as e: + console.print(f"โŒ [red]Folder exists:[/red] {e}") + console.print("๐Ÿ’ก Use [cyan]--overwrite[/cyan] to force initialization") + raise click.ClickException("Project initialization failed") + except Exception as e: + console.print(f"โŒ [red]Initialization error:[/red] {e}") raise click.ClickException("Project initialization failed") @click.command() @click.option('--list', 'action_list', is_flag=True, help='List all available templates') -@click.option('--info', 'action_info', is_flag=True, help='Get detailed information about a specific template') +@click.option('--info', 'action_info', is_flag=True, help='Get detailed template information') @click.option('--framework', help='Framework name (required for --info)') @click.option('--template', help='Template name (required for --info)') -@click.option('--filter-framework', help='Filter templates by framework when listing') -@click.option('--format', type=click.Choice(['table', 'json', 'yaml']), default='table', help='Output format') +@click.option('--filter-framework', help='Filter templates by framework') +@click.option('--format', type=click.Choice(['table', 'json']), default='table', help='Output format') def template(action_list, action_info, framework, template, filter_framework, format): - """Manage project templates - list available templates or get detailed information""" + """Manage project templates""" if not action_list and not action_info: - click.echo("โŒ Please specify either --list or --info") - click.echo("Usage examples:") - click.echo(" runagent template --list") - click.echo(" runagent template --info --framework langchain --template basic") + console.print("โŒ Please specify either [cyan]--list[/cyan] or [cyan]--info[/cyan]") raise click.ClickException("No action specified") - if action_list and action_info: - click.echo("โŒ Please specify only one action: --list or --info") - raise click.ClickException("Multiple actions specified") - - client = RunAgentClient(cli_mode=True) - - if action_list: - _handle_list_templates(client, filter_framework, format) - elif action_info: - _handle_template_info(client, framework, template) - - -def _handle_list_templates(client, filter_framework, format): - """Handle the --list action""" try: - available_templates = client.list_templates() - - if not available_templates: - click.echo("โŒ No templates available") - return - - # Apply framework filter if specified - if filter_framework: - if filter_framework not in available_templates: - click.echo(f"โŒ Framework '{filter_framework}' not found") - click.echo(f"Available frameworks: {', '.join(available_templates.keys())}") - return - available_templates = {filter_framework: available_templates[filter_framework]} + sdk = RunAgent() - # Output in different formats - if format == 'json': - import json - click.echo(json.dumps(available_templates, indent=2)) - elif format == 'yaml': - try: - import yaml - click.echo(yaml.dump(available_templates, default_flow_style=False)) - except ImportError: - click.echo("โŒ PyYAML not installed. Using JSON format instead.") - import json - click.echo(json.dumps(available_templates, indent=2)) - else: # table format (default) - click.secho("๐Ÿ“‹ Available Templates:", fg='cyan', bold=True) - - for framework_name, templates in available_templates.items(): - click.secho(f"\n๐ŸŽฏ {framework_name}:", fg='blue', bold=True) - for tmpl in templates: - click.echo(f" - {tmpl}") - - click.echo(f"\n๐Ÿ’ก Use 'runagent template --info --framework --template