diff --git a/.env.example b/.env.example index 85ecf09d7..905bd4222 100644 --- a/.env.example +++ b/.env.example @@ -10,8 +10,8 @@ OPENROUTER_API_KEY= # Default model to use (OpenRouter format: provider/model) -# Examples: anthropic/claude-sonnet-4, openai/gpt-4o, google/gemini-2.0-flash, zhipuai/glm-4-plus -LLM_MODEL=anthropic/claude-sonnet-4 +# Examples: anthropic/claude-opus-4.6, openai/gpt-4o, google/gemini-2.0-flash, zhipuai/glm-4-plus +LLM_MODEL=anthropic/claude-opus-4.6 # ============================================================================= # TOOL API KEYS @@ -46,8 +46,11 @@ TERMINAL_DOCKER_IMAGE=python:3.11 TERMINAL_SINGULARITY_IMAGE=docker://python:3.11 TERMINAL_MODAL_IMAGE=python:3.11 -# Working directory inside the container -TERMINAL_CWD=/tmp +# Working directory for terminal commands +# For CLI: "." means current directory (resolved automatically from config.yaml) +# For containers (docker/singularity/modal): absolute path inside the container +# Usually managed by config.yaml (terminal.cwd) — uncomment to override +# TERMINAL_CWD=. # Default command timeout in seconds TERMINAL_TIMEOUT=60 diff --git a/cli.py b/cli.py index 66f0eafe4..73dffbee4 100755 --- a/cli.py +++ b/cli.py @@ -88,7 +88,7 @@ def load_cli_config() -> Dict[str, Any]: }, "terminal": { "env_type": "local", - "cwd": "/tmp", + "cwd": ".", # "." is resolved to os.getcwd() at runtime "timeout": 60, "lifetime_seconds": 300, "docker_image": "python:3.11", @@ -839,7 +839,7 @@ class HermesCLI: """Display current configuration with kawaii ASCII art.""" # Get terminal config from environment (which was set from cli-config.yaml) terminal_env = os.getenv("TERMINAL_ENV", "local") - terminal_cwd = os.getenv("TERMINAL_CWD", "/tmp") + terminal_cwd = os.getenv("TERMINAL_CWD", os.getcwd()) terminal_timeout = os.getenv("TERMINAL_TIMEOUT", "60") config_path = Path(__file__).parent / 'cli-config.yaml' diff --git a/hermes_cli/setup.py b/hermes_cli/setup.py index 75e019d9e..3b52dd904 100644 --- a/hermes_cli/setup.py +++ b/hermes_cli/setup.py @@ -501,11 +501,12 @@ def run_setup_wizard(args): # ========================================================================= print_header("Default Model") - current_model = config.get('model', 'anthropic/claude-sonnet-4') + current_model = config.get('model', 'anthropic/claude-opus-4.6') print_info(f"Current: {current_model}") model_choices = [ - "anthropic/claude-sonnet-4.5 (recommended)", + "anthropic/claude-opus-4.6 (recommended)", + "anthropic/claude-sonnet-4.5", "anthropic/claude-opus-4.5", "openai/gpt-5.2", "openai/gpt-5.2-codex", @@ -518,27 +519,31 @@ def run_setup_wizard(args): f"Keep current ({current_model})" ] - model_idx = prompt_choice("Select default model:", model_choices, 10) # Default: keep current + model_idx = prompt_choice("Select default model:", model_choices, 11) # Default: keep current model_map = { - 0: "anthropic/claude-sonnet-4.5", - 1: "anthropic/claude-opus-4.5", - 2: "openai/gpt-5.2", - 3: "openai/gpt-5.2-codex", - 4: "google/gemini-3-pro-preview", - 5: "google/gemini-3-flash-preview", - 6: "z-ai/glm-4.7", - 7: "moonshotai/kimi-k2.5", - 8: "minimax/minimax-m2.1", + 0: "anthropic/claude-opus-4.6", + 1: "anthropic/claude-sonnet-4.5", + 2: "anthropic/claude-opus-4.5", + 3: "openai/gpt-5.2", + 4: "openai/gpt-5.2-codex", + 5: "google/gemini-3-pro-preview", + 6: "google/gemini-3-flash-preview", + 7: "z-ai/glm-4.7", + 8: "moonshotai/kimi-k2.5", + 9: "minimax/minimax-m2.1", } if model_idx in model_map: config['model'] = model_map[model_idx] - elif model_idx == 9: # Custom - custom = prompt("Enter model name (e.g., anthropic/claude-sonnet-4.5)") + # Also update LLM_MODEL in .env so it stays in sync (cli.py reads .env first) + save_env_value("LLM_MODEL", model_map[model_idx]) + elif model_idx == 10: # Custom + custom = prompt("Enter model name (e.g., anthropic/claude-opus-4.6)") if custom: config['model'] = custom - # else: Keep current (model_idx == 10) + save_env_value("LLM_MODEL", custom) + # else: Keep current (model_idx == 11) # ========================================================================= # Step 4: Terminal Backend diff --git a/tools/file_operations.py b/tools/file_operations.py index 2509df3c5..7d399dc9b 100644 --- a/tools/file_operations.py +++ b/tools/file_operations.py @@ -254,12 +254,12 @@ class ShellFileOperations(FileOperations): Args: terminal_env: Any object with execute(command, cwd) method. Returns {"output": str, "returncode": int} - cwd: Working directory (defaults to env's cwd or /tmp) + cwd: Working directory (defaults to env's cwd or current directory) """ self.env = terminal_env # Determine cwd from various possible sources self.cwd = cwd or getattr(terminal_env, 'cwd', None) or \ - getattr(getattr(terminal_env, 'config', None), 'cwd', None) or '/tmp' + getattr(getattr(terminal_env, 'config', None), 'cwd', None) or os.getcwd() # Cache for command availability checks self._command_cache: Dict[str, bool] = {} diff --git a/tools/terminal_tool.py b/tools/terminal_tool.py index 9fe1162ac..93e250c86 100644 --- a/tools/terminal_tool.py +++ b/tools/terminal_tool.py @@ -961,7 +961,7 @@ class _ModalEnvironment: Note: stdin handling is not needed for Modal since it uses remote async execution. """ - def __init__(self, image: str, cwd: str = "/", timeout: int = 60): + def __init__(self, image: str, cwd: str = "/root", timeout: int = 60): from minisweagent.environments.extra.swerex_modal import SwerexModalEnvironment self._inner = SwerexModalEnvironment(image=image, cwd=cwd, timeout=timeout) self.cwd = cwd @@ -1034,12 +1034,25 @@ def _get_env_config() -> Dict[str, Any]: """Get terminal environment configuration from environment variables.""" # Default image with Python and Node.js for maximum compatibility default_image = "nikolaik/python-nodejs:python3.11-nodejs20" + env_type = os.getenv("TERMINAL_ENV", "local") + + # Default cwd depends on backend: + # - local/ssh: current working directory (CLI resolves "." before we get here) + # - docker/singularity: /tmp inside the container (singularity bind-mounts /scratch there) + # - modal: /root (ephemeral cloud container, full filesystem access) + if env_type == "modal": + default_cwd = "/root" + elif env_type in ("docker", "singularity"): + default_cwd = "/tmp" + else: + default_cwd = os.getcwd() + return { - "env_type": os.getenv("TERMINAL_ENV", "local"), # local, docker, singularity, modal, or ssh + "env_type": env_type, "docker_image": os.getenv("TERMINAL_DOCKER_IMAGE", default_image), "singularity_image": os.getenv("TERMINAL_SINGULARITY_IMAGE", f"docker://{default_image}"), "modal_image": os.getenv("TERMINAL_MODAL_IMAGE", default_image), - "cwd": os.getenv("TERMINAL_CWD", "/tmp"), + "cwd": os.getenv("TERMINAL_CWD", default_cwd), "timeout": int(os.getenv("TERMINAL_TIMEOUT", "60")), "lifetime_seconds": int(os.getenv("TERMINAL_LIFETIME_SECONDS", "300")), # SSH-specific config @@ -1574,6 +1587,6 @@ if __name__ == "__main__": print(f" TERMINAL_DOCKER_IMAGE: {os.getenv('TERMINAL_DOCKER_IMAGE', default_img)}") print(f" TERMINAL_SINGULARITY_IMAGE: {os.getenv('TERMINAL_SINGULARITY_IMAGE', f'docker://{default_img}')}") print(f" TERMINAL_MODAL_IMAGE: {os.getenv('TERMINAL_MODAL_IMAGE', default_img)}") - print(f" TERMINAL_CWD: {os.getenv('TERMINAL_CWD', '/tmp')}") + print(f" TERMINAL_CWD: {os.getenv('TERMINAL_CWD', os.getcwd())}") print(f" TERMINAL_TIMEOUT: {os.getenv('TERMINAL_TIMEOUT', '60')}") print(f" TERMINAL_LIFETIME_SECONDS: {os.getenv('TERMINAL_LIFETIME_SECONDS', '300')}")