Team Ai
Apppublic

openenv/coding_env

sourceHugging Faceupdated 3mo agoView on Hugging Face
21likes
auto_action.py277 linesDownload Raw Back to auto
1# Copyright (c) Meta Platforms, Inc. and affiliates.2# All rights reserved.3#4# This source code is licensed under the BSD-style license found in the5# LICENSE file in the root directory of this source tree.6 7"""8AutoAction - Automatic Action Class Selection9==============================================10 11AutoAction provides a HuggingFace-style API for automatically retrieving the12correct Action class from installed packages or HuggingFace Hub.13 14This module simplifies working with environment actions by automatically15detecting and returning the appropriate Action class without requiring16manual imports.17 18Example:19    >>> from openenv import AutoEnv, AutoAction20    >>>21    >>> # Get Action class from environment name22    >>> CodeAction = AutoAction.from_env("coding")23    >>> action = CodeAction(code="print('Hello!')")24    >>>25    >>> # From HuggingFace Hub26    >>> CodeAction = AutoAction.from_env("meta-pytorch/coding-env")27    >>>28    >>> # Use with AutoEnv29    >>> env = AutoEnv.from_env("coding-env")30    >>> result = env.step(action)31"""32 33from __future__ import annotations34 35import logging36from typing import Any, Dict, Type37 38from ._discovery import _is_hub_url, get_discovery39from .auto_env import AutoEnv40 41logger = logging.getLogger(__name__)42 43 44class AutoAction:45    """46    AutoAction automatically retrieves the correct Action class based on47    environment names or HuggingFace Hub repositories.48 49    This class follows the HuggingFace AutoModel pattern, making it easy to50    get the right Action class without needing to know which module to import.51 52    The class provides factory methods that look up the Action class and53    return the class (not an instance) for you to instantiate.54 55    Example:56        >>> # From installed package57        >>> CodeAction = AutoAction.from_env("coding")58        >>> action = CodeAction(code="print('test')")59        >>>60        >>> # From HuggingFace Hub61        >>> CodeAction = AutoAction.from_env("meta-pytorch/coding-env")62        >>> action = CodeAction(code="print('test')")63        >>>64        >>> # Use with AutoEnv for a complete workflow65        >>> env = AutoEnv.from_env("coding-env")66        >>> ActionClass = AutoAction.from_env("coding-env")67        >>> action = ActionClass(code="print('Hello, AutoAction!')")68        >>> result = env.step(action)69 70    Note:71        AutoAction is not meant to be instantiated directly. Use the class72        method from_env() instead.73    """74 75    def __init__(self):76        """AutoAction should not be instantiated directly. Use class methods instead."""77        raise TypeError(78            "AutoAction is a factory class and should not be instantiated directly. "79            "Use AutoAction.from_hub() or AutoAction.from_env() instead."80        )81 82    @classmethod83    def from_env(cls, name: str, skip_install: bool = False) -> Type:84        """85        Get the Action class from environment name or HuggingFace Hub repository.86 87        This method automatically:88        1. Checks if the name is a HuggingFace Hub URL/repo ID89        2. If Hub: downloads and installs the environment package90        3. If local: looks up the installed openenv-* package91        4. Imports and returns the Action class92 93        Args:94            name: Environment name or HuggingFace Hub repo ID95                  Examples:96                  - "coding" / "coding-env" / "coding_env"97                  - "meta-pytorch/coding-env" (Hub repo ID)98                  - "https://huggingface.co/meta-pytorch/coding-env" (Hub URL)99            skip_install: If True, skip package installation and return100                GenericAction class instead. Use this when working with101                GenericEnvClient to avoid installing remote packages.102 103        Returns:104            Action class (not an instance!). Returns GenericAction when105            skip_install=True.106 107        Raises:108            ValueError: If environment not found (only when skip_install=False)109            ImportError: If environment package is not installed (only when skip_install=False)110 111        Examples:112            >>> # From installed package113            >>> CodeAction = AutoAction.from_env("coding-env")114            >>> action = CodeAction(code="print('Hello!')")115            >>>116            >>> # From HuggingFace Hub117            >>> CodeAction = AutoAction.from_env("meta-pytorch/coding-env")118            >>> action = CodeAction(code="print('Hello!')")119            >>>120            >>> # Skip installation, use GenericAction (for GenericEnvClient)121            >>> ActionClass = AutoAction.from_env("user/repo", skip_install=True)122            >>> action = ActionClass(code="print('Hello!')")  # Returns GenericAction123            >>>124            >>> # Different name formats125            >>> EchoAction = AutoAction.from_env("echo")126            >>> EchoAction = AutoAction.from_env("echo-env")127            >>> EchoAction = AutoAction.from_env("echo_env")128        """129        # If skip_install is True, return GenericAction without any package lookup130        if skip_install:131            from openenv.core.generic_client import GenericAction132 133            logger.info(134                f"Returning GenericAction for '{name}' (skip_install=True). "135                f"Use keyword arguments to create actions: GenericAction(code='...')"136            )137            return GenericAction138 139        # Check if it's a HuggingFace Hub URL or repo ID140        if _is_hub_url(name):141            # Ensure package is installed (reuse AutoEnv logic, downloads only if needed)142            env_name = AutoEnv._ensure_package_from_hub(name)143        else:144            env_name = name145 146        # Get environment info from discovery147        discovery = get_discovery()148        env_info = discovery.get_environment_by_name(env_name)149 150        if not env_info:151            # Environment not found - provide helpful error message152            available_envs = discovery.discover()153 154            if not available_envs:155                raise ValueError(156                    "No OpenEnv environments found.\n"157                    "Install an environment with: pip install openenv-<env-name>\n"158                    "Or specify a HuggingFace Hub repository: AutoAction.from_env('openenv/echo_env')"159                )160 161            # Try to suggest similar environment names162            from difflib import get_close_matches163 164            env_keys = list(available_envs.keys())165            suggestions = get_close_matches(env_name, env_keys, n=3, cutoff=0.6)166 167            error_msg = f"Unknown environment '{env_name}'.\n"168            if suggestions:169                error_msg += f"Did you mean: {', '.join(suggestions)}?\n"170            error_msg += f"Available environments: {', '.join(sorted(env_keys))}"171 172            raise ValueError(error_msg)173 174        # Get the action class175        try:176            action_class = env_info.get_action_class()177            return action_class178        except ImportError as e:179            raise ImportError(180                f"Failed to import action class for '{env_name}'.\n"181                f"Package '{env_info.package_name}' appears to be installed but the module cannot be imported.\n"182                f"Try reinstalling: pip install --force-reinstall {env_info.package_name}\n"183                f"Original error: {e}"184            ) from e185 186    @classmethod187    def from_hub(cls, env_name: str, skip_install: bool = False) -> Type:188        """189        Get the Action class from environment name.190 191        This is an alias for from_env() for backward compatibility and clarity.192 193        Args:194            env_name: Environment name (e.g., "coding", "echo")195            skip_install: If True, skip package installation and return196                GenericAction class instead.197 198        Returns:199            Action class (not an instance!)200 201        Examples:202            >>> CodeAction = AutoAction.from_hub("coding")203            >>> action = CodeAction(code="print('Hello!')")204        """205        return cls.from_env(env_name, skip_install=skip_install)206 207    @classmethod208    def get_action_info(cls, name: str) -> Dict[str, Any]:209        """210        Get detailed information about an action class.211 212        Args:213            name: Environment name214 215        Returns:216            Dictionary with action class metadata217 218        Raises:219            ValueError: If environment not found220 221        Examples:222            >>> info = AutoAction.get_action_info("coding")223            >>> print(info['action_class'])224            'CodingAction'225            >>> print(info['module'])226            'coding_env.client'227        """228        discovery = get_discovery()229        env_info = discovery.get_environment_by_name(name)230 231        if not env_info:232            raise ValueError(f"Unknown environment: {name}")233 234        return {235            "env_key": env_info.env_key,236            "env_name": env_info.name,237            "package": env_info.package_name,238            "action_class": env_info.action_class_name,239            "observation_class": env_info.observation_class_name,240            "module": env_info.client_module_path,241        }242 243    @classmethod244    def list_actions(cls) -> None:245        """246        Print a formatted list of all available action classes.247 248        This discovers all installed openenv-* packages and displays249        their action class information in a user-friendly format.250 251        Examples:252            >>> AutoAction.list_actions()253            Available Action Classes:254            ----------------------------------------------------------------------255              echo           : EchoAction (from openenv-echo-env)256              coding         : CodingAction (from openenv-coding_env)257            ----------------------------------------------------------------------258            Total: 2 action classes259        """260        discovery = get_discovery()261        environments = discovery.discover()262 263        print("Available Action Classes:")264        print("-" * 70)265 266        if not environments:267            print("  No OpenEnv environments found.")268            print("  Install environments with: pip install openenv-<env-name>")269        else:270            for env_key in sorted(environments.keys()):271                env = environments[env_key]272                print(f"  {env_key:<15}: {env.action_class_name}")273                print(f"                   Package: {env.package_name}")274 275        print("-" * 70)276        print(f"Total: {len(environments)} action classes")277