Skip to content

fix(agent): don't acknowledge a steer that the ending turn drops - #4992

Open
shani-singh1 wants to merge 1 commit into
block:mainfrom
shani-singh1:fix/agent-steer-dropped-at-turn-end
Open

fix(agent): don't acknowledge a steer that the ending turn drops#4992
shani-singh1 wants to merge 1 commit into
block:mainfrom
shani-singh1:fix/agent-steer-dropped-at-turn-end

Conversation

@shani-singh1

Copy link
Copy Markdown
Contributor

Fixes #4942.

Problem

RunCtx::run (crates/buzz-agent/src/agent.rs) drains the steer queue only at each round boundary — the top of the loop. When the provider returns end_turn, the run returns without a final drain, and the outer prompt task clears active_run_id/steer_tx only afterwards.

A steer that arrives in that window — after the last drain_steers(), before the turn tears down — is accepted by the handler (steer_tx.send succeeds → it returns {runId, messageId}) and then silently dropped: the run has already left its loop and never drains it again. steer_folds_into_active_turn_without_cancelling exposes this intermittently as "steered text never reached the provider." The window is small, so it only fails under full-suite timing (it passes in isolation), which is exactly the flakiness reported.

Fix

When end_turn is accepted, before ending:

  1. self.steer.close() — closing the receiver makes the handler's steer_tx.send fail for any steer that races this decision, so it is rejected (the client falls back to a new turn) instead of acknowledged-and-dropped.
  2. A final self.drain_steers() folds in anything accepted before the close. drain_steers now returns whether it folded a non-empty steer; if it did, continue runs one more round to actually deliver it rather than losing it.

So a successful steer response now guarantees the run consumes the steer — the invariant #4942 asks for. This only affects the end-of-turn path; mid-turn steering across rounds is unchanged (the channel stays open until end_turn).

The test gains a third canned response, consumed only in the rare timing where the steer lands after the final round's request was already dispatched and the fix runs one extra round to deliver it. In the common timing the steer folds into the existing round and the third response is unused.

Validation — please read

I could not run the fake_llm integration harness locally: on this Windows box every fake_llm test (including a trivial text_only_end_turn) panics in init_session at the agent-binary spawn/handshake, and it fails identically on clean main with my branch stashed — so it's a pre-existing local-environment issue, not this change. What I did verify:

  • cargo test -p buzz-agent --no-run — the code fix and the test change compile clean (0 errors/warnings).
  • cargo test -p buzz-agent --lib389 pass. The only 2 failures are auth::tests::cache_path_includes_namespace_and_hash and hints::tests::discover_skills_dedup_by_name — OS-path-sensitive tests in modules this change doesn't touch, failing on clean main too.
  • cargo fmt -p buzz-agent -- --check — clean.

So the change is compile-verified and unit-test-clean; the end-to-end steer behavior is validated by CI, which runs the fake_llm suite on Linux. Flagging the gap plainly rather than implying a green integration run. The logic is deliberately minimal (a bool return + four lines on the accept path; the give-up early-return is untouched) to keep it low-risk.

`RunCtx::run` drains the steer queue only at each round boundary (top of the
loop). When the provider returns `end_turn`, the run returns without a final
drain, and the outer prompt task clears `active_run_id`/`steer_tx` afterwards.
A steer that arrives in that window — after the last drain, before the turn
tears down — is accepted by the handler (`steer_tx.send` succeeds, it returns
`{runId, messageId}`) and then silently dropped: the run never drains it again.
The `steer_folds_into_active_turn_without_cancelling` test exposes this
intermittently as "steered text never reached the provider" (issue block#4942).

When `end_turn` is accepted, close the steer channel before ending. Closing
makes the handler reject any steer that races the decision (its `send` now
fails) instead of acknowledging one it can't deliver, so the client falls back
to a new turn. Then do a final drain of anything accepted *before* the close;
if a steer was folded in, run one more round to act on it rather than losing
it. A successful steer response therefore guarantees the run consumes the
steer.

The test gains a third canned response, consumed only in the rare timing where
the steer lands after the final round's request was dispatched and the fix runs
one extra round to deliver it; the common timing folds the steer into the
existing round and leaves it unused.

Fixes block#4942

Signed-off-by: Shani Singh <teamdeveloperworld@gmail.com>
@shani-singh1
shani-singh1 requested a review from a team as a code owner August 6, 2026 01:29
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.

buzz-agent can acknowledge a steer that is dropped during turn completion

1 participant