From 3e705e4af081a22594b7346c52c55bbc2c8942c8 Mon Sep 17 00:00:00 2001 From: agentforce314 <273884145+agentforce314@users.noreply.github.com> Date: Sun, 16 Aug 2026 10:26:41 -0700 Subject: [PATCH 1/2] Revert "Merge pull request #898 from agentforce314/feat/nano-constraint-checklist" This reverts commit 9ea3fa8847e001414bfc2d240e602b49fbdd4910, reversing changes made to 6792ace4f4df6e74b0533fee9c5e212aaf1254fd. --- src/nano/prompt.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/nano/prompt.py b/src/nano/prompt.py index b3dbb961..eefeddc6 100644 --- a/src/nano/prompt.py +++ b/src/nano/prompt.py @@ -79,10 +79,9 @@ "- Run long builds, training runs, or downloads as ONE blocking bash " "command (tee output to a log) — never launch with nohup and poll in " "a loop", - "- Before finishing, re-read the task and list every explicit " - "requirement and constraint (exact formats, tolerances, numeric " - "bounds, required sources or methods), then test your artifact " - "against each one; plausible output is not verified output", + "- Before finishing, re-read the task and verify each explicit " + "requirement against what you actually produced; plausible output " + "is not verified output", "- Be concise in your responses", "- Show file paths clearly when working with files", ) From b21a6baa732c4a0b735c72724243a9abcd56cbf5 Mon Sep 17 00:00:00 2001 From: agentforce314 <273884145+agentforce314@users.noreply.github.com> Date: Sun, 16 Aug 2026 10:26:41 -0700 Subject: [PATCH 2/2] Revert "Merge pull request #897 from agentforce314/feat/nano-bash-no-timeout" This reverts commit 6792ace4f4df6e74b0533fee9c5e212aaf1254fd, reversing changes made to b60519dad0f19d009db8c4bb1aed83659842e4bf. --- eval/harbor/run_tb21_nano_max.sh | 1 - src/nano/prompt.py | 3 -- src/nano/tool_docs.py | 7 +--- src/tool_system/tools/bash/bash_tool.py | 24 ++--------- tests/nano/test_nano_bash.py | 56 ------------------------- 5 files changed, 5 insertions(+), 86 deletions(-) delete mode 100644 tests/nano/test_nano_bash.py diff --git a/eval/harbor/run_tb21_nano_max.sh b/eval/harbor/run_tb21_nano_max.sh index 91475904..41ca96cc 100755 --- a/eval/harbor/run_tb21_nano_max.sh +++ b/eval/harbor/run_tb21_nano_max.sh @@ -83,7 +83,6 @@ PYTHONPATH="$ROOT/eval/harbor" harbor run \ --ak "source=$WHEEL" \ --ak nano=1 \ --ak effort=max \ - --ak "max_turns=${NANO_MAX_TURNS:-600}" \ ${AK_EXTRA[@]+"${AK_EXTRA[@]}"} echo diff --git a/src/nano/prompt.py b/src/nano/prompt.py index eefeddc6..0576ee41 100644 --- a/src/nano/prompt.py +++ b/src/nano/prompt.py @@ -76,9 +76,6 @@ "files merely by opening them", "- Get a minimal working version of the requested deliverable in " "place early, then iterate to improve it", - "- Run long builds, training runs, or downloads as ONE blocking bash " - "command (tee output to a log) — never launch with nohup and poll in " - "a loop", "- Before finishing, re-read the task and verify each explicit " "requirement against what you actually produced; plausible output " "is not verified output", diff --git a/src/nano/tool_docs.py b/src/nano/tool_docs.py index 2043b6b1..05c36d38 100644 --- a/src/nano/tool_docs.py +++ b/src/nano/tool_docs.py @@ -22,11 +22,8 @@ ), "Bash": ( "Executes a bash command and returns stdout+stderr. The working " - "directory persists between commands; shell state does not. No " - "default timeout: a long build or training run can block in a " - "single call (tee output to a log file) — pass timeout (ms) only " - "when you want one. Long output is truncated. Quote paths " - "containing spaces." + "directory persists between commands; shell state does not. Long " + "output is truncated. Quote paths containing spaces." ), # Edit is intentionally absent: the nano registry swaps in # NanoEditTool (src/nano/edit_tool.py), which carries its own doc for diff --git a/src/tool_system/tools/bash/bash_tool.py b/src/tool_system/tools/bash/bash_tool.py index 84b6f6db..f6aecb44 100644 --- a/src/tool_system/tools/bash/bash_tool.py +++ b/src/tool_system/tools/bash/bash_tool.py @@ -659,37 +659,19 @@ def _bash_call(tool_input: dict[str, Any], context: ToolContext) -> ToolResult: ) # Resolve timeout: prefer explicit timeout (ms), fall back to timeout_s (legacy), then default - # - # Nano mode removes the ceiling entirely (pi's bash has no default - # timeout). Measured on TB 2.1 (tb21-nano-flash-max-2): the 2-minute - # default / 10-minute cap forced nohup-and-poll loops on every long - # build or training run — 225 poll-pattern commands across the 25 - # failed tasks, with compile-compcert alone burning 111 polls and - # dying at the 300-turn ceiling mid-build. One blocking call costs - # zero turns; the benchmark/task wall-clock and the abort signal - # (checked continuously by _run_supervised) remain the backstops. - from src.nano.state import is_nano_mode as _bash_is_nano - - _nano = _bash_is_nano() - _NANO_NO_TIMEOUT_S = 86_400 # 24h — effectively "until abort/wall-clock" timeout_ms = tool_input.get("timeout") if timeout_ms is not None: max_ms = get_max_timeout_ms() if not isinstance(timeout_ms, (int, float)) or timeout_ms < 1000: raise ToolInputError("timeout must be at least 1000 ms") - if timeout_ms > max_ms and not _nano: + if timeout_ms > max_ms: raise ToolInputError(f"timeout must not exceed {max_ms} ms") timeout_s = int(timeout_ms / 1000) else: timeout_s = tool_input.get("timeout_s") if timeout_s is None: - timeout_s = ( - _NANO_NO_TIMEOUT_S if _nano - else int(get_default_timeout_ms() / 1000) - ) - if not isinstance(timeout_s, int) or timeout_s < 1 or ( - timeout_s > 600 and not _nano - ): + timeout_s = int(get_default_timeout_ms() / 1000) + if not isinstance(timeout_s, int) or timeout_s < 1 or timeout_s > 600: raise ToolInputError("timeout_s must be an integer between 1 and 600") # Persist cwd across invocations (port of ``typescript/src/utils/Shell.ts``, diff --git a/tests/nano/test_nano_bash.py b/tests/nano/test_nano_bash.py deleted file mode 100644 index 3ec1ee7b..00000000 --- a/tests/nano/test_nano_bash.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Nano bash: no timeout ceiling (pi parity for long-running work). - -TB 2.1 evidence (tb21-nano-flash-max-2): the 2-minute default / 10-minute -cap forced nohup-and-poll loops — 225 poll-pattern commands across the 25 -failed tasks; compile-compcert burned 111 polls and hit the 300-turn -ceiling mid-build. Under nano a long build blocks in ONE call; the abort -signal and the task wall-clock remain the backstops. Stock behavior is -byte-identical. -""" - -from __future__ import annotations - -import pytest - -from src.nano.state import set_nano_mode -from src.tool_system.errors import ToolInputError -from src.tool_system.tools import BashTool - - -@pytest.fixture -def ctx(tmp_path): - from src.tool_system.context import ToolContext - - return ToolContext(cwd=tmp_path, workspace_root=tmp_path) - - -def _run(ctx, **extra): - return BashTool.call({"command": "echo long-ok", **extra}, ctx) - - -def test_nano_accepts_timeouts_beyond_the_stock_cap(ctx): - set_nano_mode(True) - result = _run(ctx, timeout=1_200_000) # 20 minutes - assert "long-ok" in str(result.output) - - -def test_stock_still_rejects_beyond_cap(ctx): - with pytest.raises(ToolInputError, match="must not exceed"): - _run(ctx, timeout=1_200_000) - - -def test_nano_default_runs_without_explicit_timeout(ctx): - set_nano_mode(True) - result = _run(ctx) - assert "long-ok" in str(result.output) - - -def test_stock_default_unchanged(ctx): - result = _run(ctx) - assert "long-ok" in str(result.output) - - -def test_minimum_floor_still_enforced_in_nano(ctx): - set_nano_mode(True) - with pytest.raises(ToolInputError, match="at least 1000 ms"): - _run(ctx, timeout=10)