fix(agent-harness): route the no-progress nudge through InjectMessage so interactive turns don't crash (#4089)#4480
Merged
senamakel merged 1 commit intoJul 4, 2026
Conversation
Contributor
📝 WalkthroughWalkthroughUpdates repeated tool-failure handling to inject a system-message nudge instead of redirecting, and extends the config schema catalog test with two privacy mode methods. ChangesRepeated tool failure steering
Privacy mode schema catalog update
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
… so interactive turns don't crash (tinyhumansai#4089) The tinyagents 1.5 migration (tinyhumansai#4473) moved the no-progress escalation ladder into the crate (`no_progress::NoProgressTracker`), which feeds a structured "no progress since step X" corrective back into the loop as a `NoProgress::Nudge` — giving the model one chance to change strategy before the same-strategy retry cap. OpenHuman's `RepeatedToolFailureMiddleware` delivered that nudge via `SteeringCommand::Redirect`. But `Redirect` is Background (sub-agent) only: the interactive-turn steering policy deliberately permits just `InjectMessage`/`Pause` so the user's live turn can't be redirected out from under them by a rogue steer (`orchestration.rs`). The middleware runs on *every* turn, so every interactive turn that hit the nudge aborted with `steering command redirect is not permitted by the run policy` — a tinyhumansai#4473 regression that red-lines the raw-tool-loop / monitor E2E coverage suites. Deliver the nudge as a system message via the `InjectMessage` lane instead. The corrective is trusted, system-generated advisory text, so `InjectMessage` is both permitted (on interactive *and* background) and semantically correct — the change-strategy steering tinyhumansai#4089 asks for now actually reaches the model on interactive chat instead of crashing it. Tests: the nudge fires once (as an InjectMessage carrying the "no progress" signal + the failing call name) on the 2nd identical failure, before the halt; and a regression assertion that the interactive steering policy permits the `InjectMessage` lane the nudge now uses (and still refuses `Redirect`). Closes tinyhumansai#4089. Claude-Session: https://claude.ai/code/session_01KcmdqJVpjmnH31HqTHRLwG
a57ca24 to
e8172f5
Compare
This was referenced Jul 4, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
steering command redirect is not permitted by the run policy.InjectMessagesteering lane (permitted on interactive and background) instead ofRedirect(Background-only) — so the change-strategy steering [Harness] Change strategy after repeated unproductive results instead of retrying #4089 asks for actually reaches the model on interactive chat instead of crashing it.InjectMessagecarrying the "no progress" signal + failing call name) before the halt, and the interactive steering policy permits the lane the nudge now uses (while still refusingRedirect).config_*_privacy_modeto a stale schema-catalog golden — see## Related.Problem
Issue #4089: when a tool call keeps failing, the agent retries the same strategy instead of adapting; it should get a structured "no progress since step X" signal and change approach before the retry cap.
The tinyagents 1.5 migration (#4473) implemented the mechanism: the crate's
no_progress::NoProgressTrackerreturnsNoProgress::Nudge(instruction)— a[no progress since step N] … Do NOT repeat it. Change strategy …corrective — once before the same-strategy halt. OpenHuman'sRepeatedToolFailureMiddlewaredelivered it viaSteeringCommand::Redirect.But
Redirectis Background-only. The interactive-turn steering policy (orchestration.rs) deliberately permits justInjectMessage/Pauseso a rogue steer can't redirect the user's live turn out from under them.RepeatedToolFailureMiddlewareruns on every turn, so every interactive turn that hit the nudge aborted withsteering command redirect is not permitted by the run policy. This red-lines the raw-tool-loop / monitor E2E coverage suites (agent_*_raw_coverage_e2e,monitor_agent_e2e) — visible on #4473 itself and every PR off that base.Solution
Deliver the nudge as a system message via
SteeringCommand::InjectMessage(Message::system(instruction)). The corrective is trusted, system-generated advisory text, soInjectMessageis both permitted (interactive + background) and semantically correct — it lands the same corrective at the same safe loop boundary without weakening the interactive policy (Redirect stays refused for rogue-steer protection). The only otherRedirectsender (agent_orchestration/running_subagents.rssub-agent steering) is legitimately Background and untouched.Submission Checklist
InjectMessage; interactive-policy-permits-the-lane regression (the failure path: aRedirectnudge is refused by interactive).Nudgearm + the new assertions are exercised by the test.N/A: behaviour-fix to existing no-progress handling.## Related— N/A.N/A: internal steering lane.Closes #NNN.Impact
Related
test(ci):change adds the privacy_mode methods to theworker_a_controller_schemas_are_fully_exposedgolden (pre-existing feat(privacy): Privacy Mode + local-only inference enforcement (#4435) #4446 break; also fixed in feat(orchestration): nested contacts → sessions with create + session send #4475).AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
fix/GH-4089-change-strategy-on-repeatValidation Run
pnpm --filter openhuman-app format:check— N/A (no frontend changes)pnpm typecheck— N/A (no TS changes)openhuman::tinyagents::middleware::tests::repeated_tool_failure_nudges_change_of_strategy_before_the_halt— execution deferred to CI (shared build host); the raw-tool-loop E2E suites that were crashing exercise the fix end-to-endrustfmt --edition 2021 --checkclean;cargo check --bin openhuman-corepassed (Finished dev)Validation Blocked
command:cargo test --lib -- repeated_tool_failure_nudges_change_of_strategy_before_the_halterror:none — shared build host saturatedimpact:cargo checkcompiled clean; deterministic test validated by CIBehavior Changes
InjectMessage(permitted on all run classes) instead ofRedirect(Background-only), so interactive turns get the change-strategy corrective instead of crashing.Parity Contract
Redirectsteering is untouched. Interactive still refusesRedirect.InjectMessageand still refusesRedirect.Duplicate / Superseded PR Handling