|
| 1 | +diff --git a/README.md b/README.md |
| 2 | +index 93296de..f1c8fea 100644 |
| 3 | +--- a/README.md |
| 4 | ++++ b/README.md |
| 5 | +@@ -333,6 +333,15 @@ with a `result` line carrying `errors[].code` of `budget` or `timeout` |
| 6 | + plus the token usage consumed — a host bills and reports it like any |
| 7 | + other outcome. |
| 8 | + |
| 9 | ++`timeout` is **cooperative** — checked between rounds, not by a |
| 10 | ++watchdog — so it bounds work at those checkpoints but does not |
| 11 | ++forcibly interrupt a blocking operation mid-round (a hung tool, a slow |
| 12 | ++network read, or a run parked on a mid-run question awaiting a human |
| 13 | ++answer). Use `--answer-timeout` to cap how long an ask waits, and rely |
| 14 | ++on the hosting process's own exec watchdog (which sends `cancel` then |
| 15 | ++kills) as the hard wall-clock stop for anything the cooperative budget |
| 16 | ++cannot reach. |
| 17 | ++ |
| 18 | + ### Slash commands |
| 19 | + |
| 20 | + | Command | Description | |
| 21 | +diff --git a/python_agent_harness/entry/cli.py b/python_agent_harness/entry/cli.py |
| 22 | +index 110ac2c..d627070 100644 |
| 23 | +--- a/python_agent_harness/entry/cli.py |
| 24 | ++++ b/python_agent_harness/entry/cli.py |
| 25 | +@@ -510,8 +510,10 @@ def build_parser() -> argparse.ArgumentParser: |
| 26 | + metavar="SECONDS", |
| 27 | + type=float, |
| 28 | + default=None, |
| 29 | +- help="wall-clock limit for EACH run in seconds (per-submit budget; " |
| 30 | +- "default: config serve.timeout, else unlimited)", |
| 31 | ++ help="wall-clock limit for EACH run in seconds (per-submit budget, " |
| 32 | ++ "cooperative — checked between rounds, does not interrupt a run " |
| 33 | ++ "blocked on a mid-run question; default: config serve.timeout, else " |
| 34 | ++ "unlimited)", |
| 35 | + ) |
| 36 | + return parser |
| 37 | + |
| 38 | +diff --git a/python_agent_harness/entry/server.py b/python_agent_harness/entry/server.py |
| 39 | +index 3154e9e..e4931c3 100644 |
| 40 | +--- a/python_agent_harness/entry/server.py |
| 41 | ++++ b/python_agent_harness/entry/server.py |
| 42 | +@@ -79,6 +79,15 @@ unwinds the agent loop through its normal path, so the run still ends |
| 43 | + with a ``result`` line carrying ``errors[].code`` of ``budget`` or |
| 44 | + ``timeout`` plus the usage consumed. |
| 45 | + |
| 46 | ++The ``timeout`` is COOPERATIVE: it is checked between rounds, not by a |
| 47 | ++watchdog, so it bounds work at those checkpoints but does not forcibly |
| 48 | ++interrupt a blocking operation mid-round — a hung tool, a slow HTTP |
| 49 | ++read, or a run parked on a mid-run ``ask`` awaiting a human answer. |
| 50 | ++Bound those separately: ``--answer-timeout`` caps how long an ask |
| 51 | ++waits, and the hosting process's own exec watchdog (it already sends |
| 52 | ++``cancel`` then kills) is the hard wall-clock stop for anything the |
| 53 | ++cooperative budget cannot reach. |
| 54 | ++ |
| 55 | + Concurrency: one run at a time (the web controller already enforces |
| 56 | + "one running run per conversation"); a submit while a run is active is |
| 57 | + rejected with an ``error`` line. The reader loop stays live while a |
| 58 | + |
0 commit comments