From 47e49da77cfb6d44f1ae840e2c7b370bdbca8306 Mon Sep 17 00:00:00 2001 From: teknium1 Date: Thu, 12 Mar 2026 09:11:44 -0700 Subject: [PATCH] feat: make tinker-atropos RL training fully optional The tinker-atropos submodule and its heavy dependencies (atroposlib, tinker, wandb, fastapi, uvicorn) were being installed for all users by default, adding significant install time and disk usage for most users who don't need RL training capabilities. Changes: - install.sh: Only init mini-swe-agent submodule by default; skip tinker-atropos clone and install entirely - install.sh: Remove --recurse-submodules from git clone (only fetches what's needed) - pyproject.toml: Add [rl] optional dependency group for explicit opt-in - rl_training_tool.py: Move LOGS_DIR.mkdir() from module-level to lazy init (_ensure_logs_dir) to avoid side effects on import - README.md: Update contributor quick start to not auto-fetch tinker-atropos; add RL opt-in instructions Users who want RL training can opt in with: git submodule update --init tinker-atropos uv pip install -e ./tinker-atropos --- README.md | 9 ++++++++- pyproject.toml | 7 +++++++ scripts/install.sh | 24 ++++++++++++------------ tools/rl_training_tool.py | 10 ++++++++-- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 9f08b4bba..ca042613d 100644 --- a/README.md +++ b/README.md @@ -124,8 +124,9 @@ We welcome contributions! See the [Contributing Guide](https://hermes-agent.nous Quick start for contributors: ```bash -git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git +git clone https://github.com/NousResearch/hermes-agent.git cd hermes-agent +git submodule update --init mini-swe-agent # required terminal backend curl -LsSf https://astral.sh/uv/install.sh | sh uv venv .venv --python 3.11 source .venv/bin/activate @@ -134,6 +135,12 @@ uv pip install -e "./mini-swe-agent" python -m pytest tests/ -q ``` +> **RL Training (optional):** To work on the RL/Tinker-Atropos integration, also run: +> ```bash +> git submodule update --init tinker-atropos +> uv pip install -e "./tinker-atropos" +> ``` + --- ## Community diff --git a/pyproject.toml b/pyproject.toml index 876c47f73..75f76e785 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,13 @@ pty = [ honcho = ["honcho-ai>=2.0.1"] mcp = ["mcp>=1.2.0"] homeassistant = ["aiohttp>=3.9.0"] +rl = [ + "atroposlib @ git+https://github.com/NousResearch/atropos.git", + "tinker @ git+https://github.com/thinking-machines-lab/tinker.git", + "fastapi>=0.104.0", + "uvicorn[standard]>=0.24.0", + "wandb>=0.15.0", +] yc-bench = ["yc-bench @ git+https://github.com/collinear-ai/yc-bench.git"] all = [ "hermes-agent[modal]", diff --git a/scripts/install.sh b/scripts/install.sh index 7b87237b7..7862bd9bb 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -572,17 +572,16 @@ clone_repo() { fi else # Try SSH first (for private repo access), fall back to HTTPS - # Use --recurse-submodules to also clone mini-swe-agent and tinker-atropos # GIT_SSH_COMMAND disables interactive prompts and sets a short timeout # so SSH fails fast instead of hanging when no key is configured. log_info "Trying SSH clone..." if GIT_SSH_COMMAND="ssh -o BatchMode=yes -o ConnectTimeout=5" \ - git clone --branch "$BRANCH" --recurse-submodules "$REPO_URL_SSH" "$INSTALL_DIR" 2>/dev/null; then + git clone --branch "$BRANCH" "$REPO_URL_SSH" "$INSTALL_DIR" 2>/dev/null; then log_success "Cloned via SSH" else rm -rf "$INSTALL_DIR" 2>/dev/null # Clean up partial SSH clone log_info "SSH failed, trying HTTPS..." - if git clone --branch "$BRANCH" --recurse-submodules "$REPO_URL_HTTPS" "$INSTALL_DIR"; then + if git clone --branch "$BRANCH" "$REPO_URL_HTTPS" "$INSTALL_DIR"; then log_success "Cloned via HTTPS" else log_error "Failed to clone repository" @@ -593,10 +592,12 @@ clone_repo() { cd "$INSTALL_DIR" - # Ensure submodules are initialized and updated (for existing installs or if --recurse failed) - log_info "Initializing submodules (mini-swe-agent, tinker-atropos)..." - git submodule update --init --recursive - log_success "Submodules ready" + # Only init mini-swe-agent (terminal tool backend — required). + # tinker-atropos (RL training) is optional and heavy — users can opt in later + # with: git submodule update --init tinker-atropos && uv pip install -e ./tinker-atropos + log_info "Initializing mini-swe-agent submodule (terminal backend)..." + git submodule update --init mini-swe-agent + log_success "Submodule ready" log_success "Repository ready" } @@ -679,12 +680,11 @@ install_deps() { log_warn "mini-swe-agent not found (run: git submodule update --init)" fi - log_info "Installing tinker-atropos (RL training backend)..." + # tinker-atropos (RL training) is optional — skip by default. + # To enable RL tools: git submodule update --init tinker-atropos && uv pip install -e "./tinker-atropos" if [ -d "tinker-atropos" ] && [ -f "tinker-atropos/pyproject.toml" ]; then - $UV_CMD pip install -e "./tinker-atropos" || log_warn "tinker-atropos install failed (RL tools may not work)" - log_success "tinker-atropos installed" - else - log_warn "tinker-atropos not found (run: git submodule update --init)" + log_info "tinker-atropos submodule found — skipping install (optional, for RL training)" + log_info " To install: $UV_CMD pip install -e \"./tinker-atropos\"" fi log_success "All dependencies installed" diff --git a/tools/rl_training_tool.py b/tools/rl_training_tool.py index 61b8a7088..aa658bfe6 100644 --- a/tools/rl_training_tool.py +++ b/tools/rl_training_tool.py @@ -54,8 +54,11 @@ ENVIRONMENTS_DIR = TINKER_ATROPOS_ROOT / "tinker_atropos" / "environments" CONFIGS_DIR = TINKER_ATROPOS_ROOT / "configs" LOGS_DIR = TINKER_ATROPOS_ROOT / "logs" -# Ensure logs directory exists -LOGS_DIR.mkdir(exist_ok=True) + +def _ensure_logs_dir(): + """Lazily create logs directory on first use (avoid side effects at import time).""" + if TINKER_ATROPOS_ROOT.exists(): + LOGS_DIR.mkdir(exist_ok=True) # ============================================================================ @@ -314,6 +317,8 @@ async def _spawn_training_run(run_state: RunState, config_path: Path): """ run_id = run_state.run_id + _ensure_logs_dir() + # Log file paths api_log = LOGS_DIR / f"api_{run_id}.log" trainer_log = LOGS_DIR / f"trainer_{run_id}.log" @@ -1092,6 +1097,7 @@ async def rl_test_inference( } # Create output directory for test results + _ensure_logs_dir() test_output_dir = LOGS_DIR / "inference_tests" test_output_dir.mkdir(exist_ok=True)