From 1776d144b83594fe5ee9cbf49fcdc06f01d5be95 Mon Sep 17 00:00:00 2001 From: Tao Lin Date: Mon, 3 Aug 2026 19:58:53 -0400 Subject: [PATCH] openenv/tbench2: drop the daytona bake CLI, which nothing can consume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-task sandbox refactor made the daytona leg declarative: every episode creates from an ``Image`` definition, and the definition hash IS the cache key. The bake CLI shipped alongside it registers *named snapshots* instead, and nothing on the create path can reference one — that needs ``CreateSandboxFromSnapshotParams(snapshot=...)``, while ``create_task_sandbox`` passes ``CreateSandboxFromImageParams(image=...)`` and always will, because avoiding the org-level snapshot quota is the reason the declarative path exists. So the "optional warm cache" the CLI advertises never warms anything the trainer touches; it only spends quota (the shared org has run within two of its 500-snapshot ceiling), and it needs a live API key to do it. No caller, no test, no doc, and no runbook references it: the README documents the daytona leg's env vars and never this entry point. Warming the daytona leg, if ever wanted, is one declarative create per task — the same code path a rollout uses — not a snapshot registration. Verified with the openenv example suite (21 passed, 1 skipped; ``pytest examples/experimental/openenv/tests/``), which is not in the repo-level testpaths. --- .../openenv/tb2_sandbox_daytona.py | 73 ++----------------- 1 file changed, 6 insertions(+), 67 deletions(-) diff --git a/examples/experimental/openenv/tb2_sandbox_daytona.py b/examples/experimental/openenv/tb2_sandbox_daytona.py index 5c62793f685..ccff9ed9b60 100644 --- a/examples/experimental/openenv/tb2_sandbox_daytona.py +++ b/examples/experimental/openenv/tb2_sandbox_daytona.py @@ -15,16 +15,16 @@ auto-stop+auto-delete TTL armed as a dead-man's switch: a keepalive thread beats the activity timer while the creating process lives, so a hard-killed caller's orphans are reclaimed instead of billing forever. - bake CLI (``python tb2_sandbox_daytona.py ...``) optionally pre-register - named snapshots ```` as a warm cache. + +There is deliberately no bake step here: on this provider the image definition +IS the cache key, so a create either hits the build cache or warms it, and +nothing a create passes can name a pre-registered snapshot — registering one +per task would only spend the org quota the declarative path exists to avoid. """ -import argparse import getpass import os -import re import shlex -import sys import threading import time from pathlib import Path @@ -38,10 +38,6 @@ ) -def snapshot_name(prefix: str, task_id: str) -> str: - return prefix + re.sub(r"[^a-z0-9-]", "-", task_id.lower()) - - def build_task_image(task_dir: Path, docker_image: str | None = None): """Daytona-declarative expression of the recipe (same layers as a Dockerfile expression would use, so the Daytona build cache is shared).""" @@ -205,7 +201,7 @@ def resolve_api_key() -> str: def make_daytona(): """Daytona client: key from resolve_api_key(), endpoint from optional DAYTONA_API_URL. Public: callers driving create_task_sandbox() need a - client configured the same way this module's own CLI is.""" + client configured this way.""" from daytona import Daytona, DaytonaConfig return Daytona( @@ -214,60 +210,3 @@ def make_daytona(): api_url=os.getenv("DAYTONA_API_URL", "https://app.daytona.io/api"), ) ) - - -def bake(daytona, tasks_dir: Path, task_id: str, prefix: str, force: bool) -> None: - """Register the named snapshot ```` (optional warm cache).""" - from daytona import CreateSnapshotParams - - task_dir = tasks_dir / task_id - name = snapshot_name(prefix, task_id) - try: - existing = daytona.snapshot.get(name) - except Exception: - existing = None - if existing is not None: - if not force: - print(f"[skip] {name} already exists (state={getattr(existing, 'state', '?')})") - return - print(f"[force] deleting existing {name}") - daytona.snapshot.delete(existing) - - resources = task_resources(task_dir) - print(f"[bake] {name} cpu={resources.cpu} mem={resources.memory}G disk={resources.disk}G") - daytona.snapshot.create( - CreateSnapshotParams( - name=name, - image=build_task_image(task_dir), - resources=resources, - entrypoint=["sleep", "infinity"], - ), - on_logs=lambda line: print(f" | {line}", flush=True), - timeout=1800, - ) - print(f"[done] {name}") - - -def main() -> None: - ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) - ap.add_argument("--tasks-dir", required=True, help="local terminal-bench-2 checkout") - group = ap.add_mutually_exclusive_group(required=True) - group.add_argument("--tasks", help="comma-separated task_ids") - group.add_argument("--all", action="store_true", help="every dir with a task.toml") - ap.add_argument("--prefix", default="tb2-", help="snapshot name prefix (default: tb2-)") - ap.add_argument("--force", action="store_true", help="recreate existing snapshots") - args = ap.parse_args() - - daytona = make_daytona() - tasks_dir = Path(args.tasks_dir).expanduser().resolve() - if args.all: - task_ids = sorted(p.name for p in tasks_dir.iterdir() if (p / "task.toml").is_file()) - else: - task_ids = [t.strip() for t in args.tasks.split(",") if t.strip()] - - for task_id in task_ids: - bake(daytona, tasks_dir, task_id, args.prefix, args.force) - - -if __name__ == "__main__": - sys.exit(main())