Skip to content

Add manual ACP session rotation command#932

Merged
tlongwell-block merged 4 commits into
mainfrom
max/manual-session-rotation
Jun 12, 2026
Merged

Add manual ACP session rotation command#932
tlongwell-block merged 4 commits into
mainfrom
max/manual-session-rotation

Conversation

@tlongwell-block

Copy link
Copy Markdown
Collaborator

Summary

  • add an owner/mention-gated !rotate control command to the sprout-acp harness
  • generalize in-flight task control from cancel-only to typed control signals so rotation can reuse the shutdown/cancel path
  • invalidate idle channel sessions immediately, or cancel the in-flight turn and invalidate once it returns
  • document the new command in the sprout-acp README

Verification

  • cargo test -p sprout-acp
  • git show --stat --check HEAD

Notes

  • Initial plain git push ran repo pre-push hooks and hit an existing/unrelated desktop Rust compatibility error in desktop/src-tauri/src/commands/agent_discovery.rs for unstable str::floor_char_boundary. This change only touches crates/sprout-acp and the focused sprout-acp tests pass.

@tlongwell-block tlongwell-block requested a review from a team as a code owner June 9, 2026 20:27
@tlongwell-block tlongwell-block force-pushed the max/manual-session-rotation branch from e16ab22 to 63978f4 Compare June 9, 2026 20:27
Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
@tlongwell-block tlongwell-block force-pushed the max/manual-session-rotation branch from 63978f4 to 3b38579 Compare June 9, 2026 20:27
Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
@tlongwell-block tlongwell-block force-pushed the max/manual-session-rotation branch from 52dfc4d to 3281f19 Compare June 12, 2026 14:55
Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>

@tlongwell-block tlongwell-block left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at merge head f4ea8fc. Verified locally: cargo fmt --check, clippy -p buzz-acp --all-targets -D warnings, cargo test -p buzz-acp (288 pass) — all green in a clean worktree.

The design is right: generalizing CancelModeControlSignal and reusing the cancel path for rotation is the minimal way to do this. The is_owner_control_command extraction de-triplicates the shutdown/cancel/rotate checks nicely. README distinction between !cancel and !rotate is accurate.

One correctness gap — rotate intent can be silently dropped in the Race 1 window (pool.rs ~L1122):

When !rotate arrives while a turn is in-flight but the turn completes naturally just before the signal lands (has_in_flight_prompt() is false), the else-branch sends PromptOutcome::Ok without invalidating the session. The main loop's fired=true path also skips invalidate_channel_sessions. Net: the owner explicitly asked for a fresh session, the harness logged "rotating", and the next turn reuses the old session anyway.

For !cancel this race resolution is correct — nothing left to cancel. For !rotate the intent isn't "stop the turn", it's "next turn gets a fresh session", and that intent survives the turn finishing. Suggested ~3-line fix in the else branch:

if control_signal == ControlSignal::Rotate {
    agent.state.invalidate(&source);
}

This is also the one place ControlSignal::Rotate must differ from Cancel — right now every match arm treats them identically (Cancel | Rotate => None), so the variant is purely informational. The fix makes it load-bearing.

Same-shaped (rarer) edge: if control_tx was already consumed by a prior signal, fired=false → the idle-invalidation fallback runs while the agent is checked out, so invalidate_channel_sessions misses it. Could be handled by tracking a pending-rotate per channel, but that's heavier machinery; probably fine to note and skip.

Narrow windows, non-corrupting (worst case: one stale-context turn after rotate), so not blocking — but the 3-line fix is cheap and closes the main one.

Nit: is_owner_control_command doesn't actually check ownership — that stays at the call site (consistent with prior code, but the name overpromises slightly).

Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
@tlongwell-block tlongwell-block merged commit 00dc491 into main Jun 12, 2026
24 checks passed
@tlongwell-block tlongwell-block deleted the max/manual-session-rotation branch June 12, 2026 15:50
wpfleger96 pushed a commit that referenced this pull request Jun 12, 2026
…session-new

* origin/main:
  fix(huddle): Pocket TTS quality overhaul — reference parity + cross-message pipelining (#997)
  Add manual ACP session rotation command (#932)
  fix(desktop): heal stale persona_team_dir paths in release builds (#1003)
  ci(docker): publish public ghcr.io/block/buzz image (native multi-arch) (#986)
  fix(buzz-agent): cap tool-result text at 50 KiB with middle elision (#952)
  feat(huddle): sentence-at-a-time voice-mode guidelines for lower TTS latency (#996)
  Shard desktop Playwright CI jobs (#992)
  chore(release): release version 0.3.18 (#995)
  Video Player Improvements  (#993)
  Improve first-run welcome setup (#970)
  fix(release): use legacy updater key secret (#991)

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	crates/buzz-acp/src/lib.rs
#	crates/buzz-agent/src/config.rs
tellaho added a commit that referenced this pull request Jun 12, 2026
…tate

* origin/main:
  Add relay disconnect UX: friendly errors, reconnect, cached identity (#1004)
  feat(agents): add active turn indicators to Agents Menu (#1005)
  ci: add fork guards to docker, release, and auto-tag workflows (#1007)
  docs(nip-rs): add optional thread read context scheme (#1006)
  fix(huddle): Pocket TTS quality overhaul — reference parity + cross-message pipelining (#997)
  Add manual ACP session rotation command (#932)
  fix(desktop): heal stale persona_team_dir paths in release builds (#1003)
  ci(docker): publish public ghcr.io/block/buzz image (native multi-arch) (#986)
  fix(buzz-agent): cap tool-result text at 50 KiB with middle elision (#952)
  feat(huddle): sentence-at-a-time voice-mode guidelines for lower TTS latency (#996)
  Shard desktop Playwright CI jobs (#992)
  chore(release): release version 0.3.18 (#995)
  Video Player Improvements  (#993)
  Improve first-run welcome setup (#970)
  fix(release): use legacy updater key secret (#991)
  Replace built-in personas with Fizz (#987)
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