From 21e5f43a8596b2c93637fe4c7accfb0d48de3dfe Mon Sep 17 00:00:00 2001 From: Krish Mehta <66878328+DjKesu@users.noreply.github.com> Date: Sun, 16 Feb 2025 17:08:51 -0500 Subject: [PATCH] feat: Add agent listing functionality (#444) * Create agent listing functionality * feat: add agent listing functionality with proper documentation and style * removed pyopenagi and focusing only on cerebrum --- .gitignore | 5 +- aios/config/config.yaml | 2 +- install/install.sh | 90 ++++++++++++++++------- scripts/README.md | 3 + scripts/list_agents.py | 155 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 228 insertions(+), 27 deletions(-) create mode 100644 scripts/list_agents.py diff --git a/.gitignore b/.gitignore index 9e1fd11..0596bd8 100644 --- a/.gitignore +++ b/.gitignore @@ -206,4 +206,7 @@ workspace cache # Ignore configuration files -aios/config/config.yaml \ No newline at end of file +aios/config/config.yaml + +# ignore cerebrum +Cerebrum/* diff --git a/aios/config/config.yaml b/aios/config/config.yaml index 32685c7..dd4115e 100644 --- a/aios/config/config.yaml +++ b/aios/config/config.yaml @@ -21,4 +21,4 @@ llm: server: host: "localhost" - port: 8000 \ No newline at end of file + port: 8000 diff --git a/install/install.sh b/install/install.sh index 87fabaf..f7967ac 100644 --- a/install/install.sh +++ b/install/install.sh @@ -60,8 +60,14 @@ python -m pip install --upgrade pip pip install -r "$INSTALL_DIR/src/requirements.txt" -# Remove non-kernel files +# Remove non-kernel files but preserve necessary scripts +mkdir -p "$INSTALL_DIR/src/scripts_temp" +cp "$INSTALL_DIR/src/scripts/list_agents.py" "$INSTALL_DIR/src/scripts_temp/" rm -rf "$INSTALL_DIR/src/scripts" +mkdir -p "$INSTALL_DIR/src/scripts" +mv "$INSTALL_DIR/src/scripts_temp/list_agents.py" "$INSTALL_DIR/src/scripts/" +rm -rf "$INSTALL_DIR/src/scripts_temp" + rm -rf "$INSTALL_DIR/src/tests" rm -rf "$INSTALL_DIR/src/docs" @@ -99,14 +105,14 @@ start() { return fi source "$INSTALL_DIR/venv/bin/activate" - + # Check Python version before starting PYTHON_VERSION=$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') if [[ ! "$PYTHON_VERSION" =~ ^3\.(10|11)$ ]]; then echo "Error: Unsupported Python version $PYTHON_VERSION. Only Python 3.10 or 3.11 are supported." return 1 fi - + load_env cd "$INSTALL_DIR/src" nohup uvicorn runtime.kernel:app --reload > "$INSTALL_DIR/server.log" 2>&1 & @@ -133,13 +139,13 @@ restart() { update() { echo "Checking for updates..." - + # Stop server if running if [ -f "$PID_FILE" ]; then echo "Stopping server for update..." stop fi - + # Check Python version before updating source "$INSTALL_DIR/venv/bin/activate" PYTHON_VERSION=$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') @@ -147,43 +153,43 @@ update() { echo "Error: Unsupported Python version $PYTHON_VERSION. Only Python 3.10 or 3.11 are supported." return 1 fi - + # Store current commit hash cd "$INSTALL_DIR/src" current_hash=$(git rev-parse HEAD) - + # Fetch and pull latest changes git fetch origin remote_hash=$(git rev-parse origin/$(git rev-parse --abbrev-ref HEAD)) - + if [ "$current_hash" = "$remote_hash" ]; then echo "Already up to date!" start return fi - + echo "Updates found, installing..." - + # Pull latest changes git pull - + # Activate venv and update dependencies pip install -r requirements.txt - + # Remove any new non-kernel files that might have been added rm -rf "$INSTALL_DIR/src/scripts" rm -rf "$INSTALL_DIR/src/tests" rm -rf "$INSTALL_DIR/src/docs" - + rm -f "$INSTALL_DIR/src/requirements-cuda.txt" rm -f "$INSTALL_DIR/src/.dockerignore" rm -f "$INSTALL_DIR/src/.env.example" rm -f "$INSTALL_DIR/src/.precommit-config.yaml" rm -f "$INSTALL_DIR/src/README.md" rm -f "$INSTALL_DIR/src/Dockerfile" - + echo "Update complete!" - + # Restart server start } @@ -191,18 +197,18 @@ update() { clean() { # First stop everything stop - + # Deactivate virtual environment if active if [ -n "$VIRTUAL_ENV" ]; then deactivate fi - + # Remove the installation directory rm -rf "$INSTALL_DIR" - + # Remove the executable rm -f "$HOME/.local/bin/aios" - + echo "AIOS installation cleaned up successfully" } @@ -210,17 +216,17 @@ env_add() { echo "Adding new environment variable" echo "Enter variable name (e.g., API_KEY):" read varname - + # Validate variable name if [[ ! $varname =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then echo "Invalid variable name. Use only letters, numbers, and underscores, and start with a letter or underscore." return 1 fi - + echo "Enter variable value:" read -s varvalue # -s flag hides the input (good for sensitive values) echo # Add newline after hidden input - + # Check if variable already exists if grep -q "^$varname=" "$ENV_FILE" 2>/dev/null; then echo "Variable $varname already exists. Do you want to update it? (y/n)" @@ -232,7 +238,7 @@ env_add() { # Remove old value sed -i.bak "/^$varname=/d" "$ENV_FILE" && rm "$ENV_FILE.bak" fi - + # Add new value echo "$varname=$varvalue" >> "$ENV_FILE" echo "Environment variable added successfully" @@ -255,7 +261,7 @@ env_remove() { echo "" echo "Enter the number of the variable to remove:" read varnum - + if [[ "$varnum" =~ ^[0-9]+$ ]]; then varname=$(sed -n "${varnum}p" "$ENV_FILE" | cut -d= -f1) if [ -n "$varname" ]; then @@ -331,6 +337,31 @@ Subcommands: - Immediate removal from configuration Note: Server restart required for environment changes to take effect +HELP + ;; + esac + ;; + "agents") + case "$2" in + "list") + # Activate virtual environment and run Python script + source "$INSTALL_DIR/venv/bin/activate" + python "$INSTALL_DIR/src/scripts/list_agents.py" + ;; + *) + cat << 'HELP' +Agent Management + +Usage: aios agents + +Subcommands: + list List all available agents + - Shows Cerebrum built-in agents + - Shows cached agents from previous installations + - Shows available agents to install from AIOS foundation + - Displays versions and sources for each agent + +Note: Requires active internet connection for online agent listing HELP ;; esac @@ -373,6 +404,14 @@ Commands: remove - Remove a variable (interactive) Environment changes require server restart to take effect + agents Manage AIOS agents + Subcommands: + list - List all available agents + • Shows Cerebrum built-in agents + • Shows cached agents from previous installations + • Shows available agents to install from AIOS foundation + • Displays versions and sources for each agent + clean Uninstall AIOS completely - Stops any running server - Removes all AIOS files and configurations @@ -383,6 +422,7 @@ Commands: Examples: aios start # Start the server aios env add # Add a new API key or configuration value + aios agents list # View all available agents aios update # Update to the latest version Notes: @@ -428,4 +468,4 @@ Note: AIOS requires Python 3.10 or 3.11 For more information, visit: https://github.com/agiresearch/AIOS -COMPLETE \ No newline at end of file +COMPLETE diff --git a/scripts/README.md b/scripts/README.md index a63a306..7276c6b 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,2 +1,5 @@ # scripts +## list_agents.py + +List all agents available to use and install. diff --git a/scripts/list_agents.py b/scripts/list_agents.py new file mode 100644 index 0000000..912f68c --- /dev/null +++ b/scripts/list_agents.py @@ -0,0 +1,155 @@ +# This file provides functionality to list both offline and online AIOS agents. +# It can display locally installed agents as well as agents available for installation +# from the AIOS foundation. + +import os +import importlib +from pathlib import Path +from typing import Dict, List +from cerebrum.manager.agent import AgentManager +import platformdirs + +def parse_version_from_filename(filename: str) -> str: + """Extract version from a filename like 'agent_1.2.3.agent' + + Args: + filename (str): The filename to parse version from + + Returns: + str: The extracted version string + """ + return filename.replace('agent_', '').replace('.agent', '') + +def get_offline_agents() -> Dict[str, List[str]]: + """Get all locally downloaded/installed agents with their versions + + This function checks multiple locations for installed agents: + - Cerebrum built-in agents + - User's cache directory + + Returns: + Dict[str, List[str]]: A dictionary mapping agent IDs to their available versions + """ + offline_agents = {} + + # Check in Cerebrum built-in agents + try: + cerebrum_path = importlib.util.find_spec('cerebrum').submodule_search_locations[0] + example_paths = [ + os.path.join(cerebrum_path, "example", "agents"), + os.path.join(cerebrum_path, "cerebrum", "example", "agents") + ] + + for example_path in example_paths: + if os.path.exists(example_path): + for agent in os.listdir(example_path): + agent_path = os.path.join(example_path, agent) + if os.path.isdir(agent_path) and os.path.exists(os.path.join(agent_path, 'agent.py')): + agent_id = f"example/{agent}" + if agent_id not in offline_agents: + offline_agents[agent_id] = ["built-in"] + except (ImportError, AttributeError): + print("Error getting offline agents: cerebrum package not found") + + # Check in cache directory + try: + cache_dir = Path(platformdirs.user_cache_dir("cerebrum")) + if cache_dir.exists(): + for author in cache_dir.iterdir(): + if author.is_dir(): + for agent in author.iterdir(): + if agent.is_dir(): + agent_id = f"{author.name}/{agent.name}" + versions = [] + for version_file in agent.glob("*.agent"): + version = parse_version_from_filename(version_file.stem) + versions.append(version) + if versions: + offline_agents[agent_id] = sorted(versions, key=lambda v: [int(x) for x in v.split('.')]) + except Exception as e: + print(f"Error getting offline agents: Could not access cache directory: {str(e)}") + + return offline_agents + +def get_online_agents() -> Dict[str, List[str]]: + """Get all available online agents from AIOS foundation with their versions + + This function connects to the AIOS foundation server to retrieve a list of + all available agents and their versions. + + Returns: + Dict[str, List[str]]: A dictionary mapping agent IDs to their available versions + """ + online_agents = {} + try: + manager = AgentManager("https://app.aios.foundation/") + agent_list = manager.list_available_agents() + for agent_info in agent_list: + # Parse the full agent path which includes version + full_path = agent_info["agent"] + agent_path, version = full_path.rsplit("/", 1) + if agent_path in online_agents: + online_agents[agent_path].append(version) + else: + online_agents[agent_path] = [version] + + # Sort versions for each agent + for agent_id in online_agents: + online_agents[agent_id] = sorted(online_agents[agent_id], key=lambda v: [int(x) for x in v.split('.')]) + + except Exception as e: + print(f"Error getting online agents: {str(e)}") + + return online_agents + +def main(): + """Main function to list all offline and online AIOS agents + + This function retrieves and displays: + - Offline agents that are ready to use (locally installed) + - Online agents that are available to install + Each agent entry shows its latest version and any other available versions. + """ + # Get offline and online agents + offline_agents = get_offline_agents() + online_agents = get_online_agents() + + # Print results + print("\n=== List of Agents ===") + + print("Offline Agents (Ready to Use):") + print("-" * 50) + if offline_agents: + for agent_id in sorted(offline_agents.keys()): + versions = offline_agents[agent_id] + if len(versions) == 1 and versions[0] in ["local", "built-in"]: + print(f" • {agent_id} [{versions[0]}]") + else: + latest_version = versions[-1] if versions else "unknown" + other_versions = versions[:-1] if len(versions) > 1 else [] + version_str = f"v{latest_version}" + if other_versions: + version_str += f" (also: {', '.join(f'v{v}' for v in other_versions)})" + print(f" • {agent_id} [{version_str}]") + else: + print(" No agents installed locally") + print("-" * 50) + + print("\nOnline Agents (Available to Install):") + print("-" * 50) + installable_agents = set(online_agents.keys()) - set(offline_agents.keys()) + if installable_agents: + for agent_id in sorted(installable_agents): + versions = online_agents[agent_id] + latest_version = versions[-1] if versions else "unknown" + other_versions = versions[:-1] if len(versions) > 1 else [] + version_str = f"v{latest_version}" + if other_versions: + version_str += f" (also: {', '.join(f'v{v}' for v in other_versions)})" + print(f" • {agent_id} [{version_str}]") + else: + print(" No additional agents available to install") + print("-" * 50) + +if __name__ == "__main__": + main()