Skip to content

Add loop/thrash guard to the zarvis agent loop#324

Merged
edwin-zvs merged 1 commit into
mainfrom
zarvis-loop-guard
Jun 1, 2026
Merged

Add loop/thrash guard to the zarvis agent loop#324
edwin-zvs merged 1 commit into
mainfrom
zarvis-loop-guard

Conversation

@edwin-zvs

Copy link
Copy Markdown
Contributor

What

Adds a model/provider-agnostic guard to the zarvis per-turn step loop:

  • Non-progress nudge (always on). After 4 consecutive tool rounds with no successful result, inject a one-shot harness OBSERVATION telling the model to step back, verify state (run build/tests), change approach, or stop — rather than repeat a failing action.
  • Graceful caps (opt-in, 0 = unlimited, default off). AGENTD_ZARVIS_MAX_STEPS (model calls/turn) and AGENTD_ZARVIS_MAX_TURN_SECS (wall-clock/turn) let a session stop itself cleanly — partial work stays in the tree, session parks awaiting input — before an external timeout SIGKILLs it mid-edit.

Why

In DeepSWE benchmarking, one trial introduced a recursion/hang, then thrashed ~185 tool calls (12% failing, many exit_code 124), re-editing the same file 17× without recovering, until it hit the harness's 90-min AgentTimeoutError. This is a general failure mode (any model/repo): the loop had no notion of "not making progress" or "out of budget." The nudge gives the model a chance to self-correct; the caps bound the worst case.

Design notes / limitations

  • Default behavior is unchanged: caps default to off; the nudge only fires on repeated failing rounds (not on slow-but-progressing work).
  • The non-progress signal is "no tool result with ok=true in the round." It catches failing/timeout thrash (the observed case) but not "successful but pointless" looping — a deliberate, conservative scope.

Test plan

  • cargo build + cargo test -p agentd-adapter-zarvis → 138 passed, 0 failed.
  • Ran a 5-task pass@1 DeepSWE run with this build (AGENTD_ZARVIS_MAX_TURN_SECS=3600): all 5 trials completed with 0 exceptions / 0 timeouts (the prior run had a 90-min timeout). No regressions; guard was inert when not needed (0 nudges/caps fired this run).

🤖 Generated with Claude Code

A benchmark trial thrashed ~185 tool calls (re-editing the same file,
commands repeatedly timing out) into a 90-minute external timeout SIGKILL.
Add a model/provider-agnostic guard to the per-turn step loop:

- Non-progress nudge (always on): after NONPRODUCTIVE_STREAK_LIMIT (4)
  consecutive tool rounds with no successful result, inject a one-shot
  harness observation telling the model to step back, verify state (run
  the project's build/tests), change approach, or stop — instead of
  repeating a failing action.
- Graceful caps (opt-in, 0 = unlimited, default off → no behavior change):
  AGENTD_ZARVIS_MAX_STEPS caps model calls per turn; AGENTD_ZARVIS_MAX_TURN_SECS
  caps wall-clock per turn, so a session can stop itself cleanly (partial
  work preserved) before an external timeout kills it mid-edit.
@edwin-zvs
edwin-zvs merged commit 391d085 into main Jun 1, 2026
1 check passed
@edwin-zvs
edwin-zvs deleted the zarvis-loop-guard branch June 1, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant