Skip to content

feat(agent): opt-in stall retry lane for local models (HERMES_STALL_RETRY_MODEL) - #37166

Closed
OmarB97 wants to merge 14 commits into
NousResearch:mainfrom
OmarB97:codex/pr35642-stall-retry-tail
Closed

feat(agent): opt-in stall retry lane for local models (HERMES_STALL_RETRY_MODEL)#37166
OmarB97 wants to merge 14 commits into
NousResearch:mainfrom
OmarB97:codex/pr35642-stall-retry-tail

Conversation

@OmarB97

@OmarB97 OmarB97 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Why

PR #35642 currently mixes the stall-retry policy stack with local TTFB failover, backend recovery scripts, canary tooling, and unrelated TUI test changes. Reviewers need the dflash stall-retry behavior isolated to the files that actually implement and test the retry policy.

What changed

How to review

Review agent/stall_retry.py first for the detection/config/promotion rules, then agent/conversation_loop.py for the integration order, then tests/agent/test_stall_retry.py for the captured dflash regressions and cap behavior. This draft is intentionally a replacement slice for #35642, not a merge-ready claim that #35620/#35638 have landed.

Evidence

  • Scope proof: git -c core.fsmonitor=false diff --name-only upstream/main..HEAD lists only agent/conversation_loop.py, agent/stall_retry.py, and tests/agent/test_stall_retry.py.
  • Focused behavior suite: scripts/run_tests.sh tests/agent/test_stall_retry.py -> 35 tests passed, 0 failed.
  • Compile check: python3 -m py_compile agent/stall_retry.py agent/conversation_loop.py tests/agent/test_stall_retry.py -> rc=0.
  • Diff hygiene: git -c core.fsmonitor=false diff --check upstream/main..HEAD -> rc=0.

Verification

  • scripts/run_tests.sh tests/agent/test_stall_retry.py -> 35 passed.
  • python3 -m py_compile agent/stall_retry.py agent/conversation_loop.py tests/agent/test_stall_retry.py -> passed.
  • git -c core.fsmonitor=false diff --check upstream/main..HEAD -> passed.

Risks / gaps

Medium risk because this changes agent retry behavior for configured dflash/local retry lanes. Remaining honest recovery-versus-regression evidence is explicitly tracked by MeshBoard parent task hermes-stall-retry-multiple-per-turn and split task hermes-pr35642-split-snowball-20260602; this PR only makes the code slice reviewable. Related non-policy slices are tracked separately: #37160 for canary tooling and #37163 for the TUI status assertion.

Collaborators

Participants:

  • @OmarB97 — operator on ko-mac.
  • Codex (GPT-5) — OpenAI frontier coding lane on ko-mac, task hermes-pr35642-split-snowball-20260602.

Process:

Context:

Timing:

  • Opened during the 2026-06-02 Codex pickup after MeshBoard onboarding and Syncthing doctor.

OmarB97 and others added 11 commits June 1, 2026 20:03
dflash (Qwen3.6-27B Q4_K_M, lucebox spec-decode) sometimes ends an agentic
decision turn with EOS right after a short action preamble ("Let me check
X:") and NO tool_call, stalling the loop. Higher-precision weights (the
stock qwen3.6-27b-256k lane on the same host) continue to a real tool call
on the identical prompt.

This adds agent/stall_retry.py: when a no-tool-call turn looks like that
stall (short, announces an action, not a genuine completion) and
HERMES_STALL_RETRY_MODEL is set, re-issue the SAME turn once on that lane;
if it yields tool calls, adopt it and continue. Same provider/endpoint so
only the model name is overridden (no client rebuild). Fires at most once
per conversation. No-op unless the env is set, so default behavior is
unchanged.

Validated: detector 17/17 on real captured stall contents, 0 false
positives on genuine completions; live retry recovered real stalls into
real tool calls (terminal/execute_code) against the live endpoint; runs
correctly under `hermes -z` (probe-confirmed, env propagated).
@OmarB97
OmarB97 marked this pull request as ready for review June 2, 2026 03:26
@alt-glitch alt-glitch added type/refactor Code restructuring, no behavior change comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have labels Jun 2, 2026
@OmarB97 OmarB97 changed the title [Hermes Agent][hermes-pr35642-split-snowball][3/n] Split stall retry policy stack feat(agent): opt-in stall retry lane for local models (HERMES_STALL_RETRY_MODEL) Jun 9, 2026
Omar B and others added 3 commits June 9, 2026 17:25
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lure returns

The stall-retry lane added three run_conversation failure returns
(stall_retry_limit_exhausted, stall_retry_failed_no_tool_call,
stall_retry_exception) with "final_response": None, tripping the
test_run_conversation_dict_returns_include_final_response guard that forbids
literal-None final_response on dict returns. Hoist each block's error text
into a local message var and set final_response to it, matching the sibling
convention where final_response == error (actionable text the caller/UI can
surface instead of an empty final response).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for isolating the retry work and supplying focused coverage. This automated hermes-sweeper review is closing it under the repository's configuration policy.

  • agent/stall_retry.py:18-40 makes the feature and its behavioral tuning user-facing through HERMES_STALL_RETRY_MODEL and additional non-secret HERMES_STALL_RETRY_* variables.
  • AGENTS.md:102-105 explicitly rejects new non-secret HERMES_* variables for behavioral configuration; those settings belong in config.yaml.
  • The underlying behavior is still meaningful on current main: agent/conversation_loop.py:4814-4815 treats a no-tool response as final. A focused re-scope using the supported config.yaml mechanism, while preserving cache and transcript invariants, would be the appropriate route.

The implementation effort and focused test coverage are appreciated.


Closed as not-planned per standing maintainer policy (env-var-for-config). This is a design-direction decision, not a code-quality judgment — see the Contribution Rubric in AGENTS.md for what the project is looking for. If you believe this policy was misapplied to your change, comment here and a maintainer will take a look.

@teknium1 teknium1 closed this Jul 13, 2026
@teknium1 teknium1 added the sweeper:not-planned Sweeper: closed per standing maintainer policy (design direction) label Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:not-planned Sweeper: closed per standing maintainer policy (design direction) type/refactor Code restructuring, no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants