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
This commit is contained in:
teknium1 2026-03-12 09:11:44 -07:00
parent e004c094ea
commit 47e49da77c
4 changed files with 35 additions and 15 deletions

View file

@ -124,8 +124,9 @@ We welcome contributions! See the [Contributing Guide](https://hermes-agent.nous
Quick start for contributors: Quick start for contributors:
```bash ```bash
git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent cd hermes-agent
git submodule update --init mini-swe-agent # required terminal backend
curl -LsSf https://astral.sh/uv/install.sh | sh curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv .venv --python 3.11 uv venv .venv --python 3.11
source .venv/bin/activate source .venv/bin/activate
@ -134,6 +135,12 @@ uv pip install -e "./mini-swe-agent"
python -m pytest tests/ -q 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 ## Community

View file

@ -53,6 +53,13 @@ pty = [
honcho = ["honcho-ai>=2.0.1"] honcho = ["honcho-ai>=2.0.1"]
mcp = ["mcp>=1.2.0"] mcp = ["mcp>=1.2.0"]
homeassistant = ["aiohttp>=3.9.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"] yc-bench = ["yc-bench @ git+https://github.com/collinear-ai/yc-bench.git"]
all = [ all = [
"hermes-agent[modal]", "hermes-agent[modal]",

View file

@ -572,17 +572,16 @@ clone_repo() {
fi fi
else else
# Try SSH first (for private repo access), fall back to HTTPS # 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 # GIT_SSH_COMMAND disables interactive prompts and sets a short timeout
# so SSH fails fast instead of hanging when no key is configured. # so SSH fails fast instead of hanging when no key is configured.
log_info "Trying SSH clone..." log_info "Trying SSH clone..."
if GIT_SSH_COMMAND="ssh -o BatchMode=yes -o ConnectTimeout=5" \ 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" log_success "Cloned via SSH"
else else
rm -rf "$INSTALL_DIR" 2>/dev/null # Clean up partial SSH clone rm -rf "$INSTALL_DIR" 2>/dev/null # Clean up partial SSH clone
log_info "SSH failed, trying HTTPS..." 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" log_success "Cloned via HTTPS"
else else
log_error "Failed to clone repository" log_error "Failed to clone repository"
@ -593,10 +592,12 @@ clone_repo() {
cd "$INSTALL_DIR" cd "$INSTALL_DIR"
# Ensure submodules are initialized and updated (for existing installs or if --recurse failed) # Only init mini-swe-agent (terminal tool backend — required).
log_info "Initializing submodules (mini-swe-agent, tinker-atropos)..." # tinker-atropos (RL training) is optional and heavy — users can opt in later
git submodule update --init --recursive # with: git submodule update --init tinker-atropos && uv pip install -e ./tinker-atropos
log_success "Submodules ready" log_info "Initializing mini-swe-agent submodule (terminal backend)..."
git submodule update --init mini-swe-agent
log_success "Submodule ready"
log_success "Repository ready" log_success "Repository ready"
} }
@ -679,12 +680,11 @@ install_deps() {
log_warn "mini-swe-agent not found (run: git submodule update --init)" log_warn "mini-swe-agent not found (run: git submodule update --init)"
fi 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 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_info "tinker-atropos submodule found — skipping install (optional, for RL training)"
log_success "tinker-atropos installed" log_info " To install: $UV_CMD pip install -e \"./tinker-atropos\""
else
log_warn "tinker-atropos not found (run: git submodule update --init)"
fi fi
log_success "All dependencies installed" log_success "All dependencies installed"

View file

@ -54,8 +54,11 @@ ENVIRONMENTS_DIR = TINKER_ATROPOS_ROOT / "tinker_atropos" / "environments"
CONFIGS_DIR = TINKER_ATROPOS_ROOT / "configs" CONFIGS_DIR = TINKER_ATROPOS_ROOT / "configs"
LOGS_DIR = TINKER_ATROPOS_ROOT / "logs" 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 run_id = run_state.run_id
_ensure_logs_dir()
# Log file paths # Log file paths
api_log = LOGS_DIR / f"api_{run_id}.log" api_log = LOGS_DIR / f"api_{run_id}.log"
trainer_log = LOGS_DIR / f"trainer_{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 # Create output directory for test results
_ensure_logs_dir()
test_output_dir = LOGS_DIR / "inference_tests" test_output_dir = LOGS_DIR / "inference_tests"
test_output_dir.mkdir(exist_ok=True) test_output_dir.mkdir(exist_ok=True)