feat(agent): add Session.Steer to deliver mid-run user messages - #6306
Open
Jaisev-Sachdev wants to merge 1 commit into
Open
feat(agent): add Session.Steer to deliver mid-run user messages#6306Jaisev-Sachdev wants to merge 1 commit into
Jaisev-Sachdev wants to merge 1 commit into
Conversation
|
@Jaisev-Sachdev is attempting to deploy a commit to the IndexLabs Team on Vercel. A member of the Team first needs to authorize it. |
Multica tasks are fire-and-forget today: once an agent starts on an issue, there is no way to talk to it until the run ends. A comment posted mid-run is (correctly, and with care — multica-ai#5914) deferred and replayed as a follow-up task after completion. This adds the missing capability layer underneath a future live-delivery path: an optional, additive Steer hook on agent.Session that injects an additional user message into the RUNNING session. The claude backend can support this for free: it already runs --input-format stream-json and deliberately keeps stdin open for the whole run (for control_response frames). Steer writes one more user frame to that same pipe; the CLI queues it as the next user turn. Design points: - Steer is a nil-able func field on Session, not a new interface method, so the other 16 backends compile unchanged and callers must treat nil as "unsupported → use the existing follow-up-task path". - A steer frame can never overtake the initial prompt (gated on the prompt write completing), and a steer after the run finishes or is cancelled returns an error instead of silently dropping the message — the caller keeps the deferral fallback in both cases. - All stdin frame producers (initial prompt, control responses, Steer) now share one locked writer, making each frame write atomic. This also hardens a pre-existing latent interleaving between the prompt-writer goroutine and the scanner's control responses. Tested with a fake-CLI round trip: the steer text must arrive as a well-formed user frame on the same stdin, after the prompt, while the run is live (the fake blocks on the second frame, so non-delivery hangs the test rather than passing); plus steer-after-completion and steer-after-cancel error paths. Server-side wiring (routing a mid-run comment to a live session instead of the deferred replay, claim-based so completion reconcile never double-delivers) is deliberately NOT in this PR — proposed separately so the multica-ai#5914 invariants get their own review.
Jaisev-Sachdev
force-pushed
the
feat/agent-session-steer
branch
from
August 3, 2026 08:06
473ae26 to
f07b6da
Compare
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.
Problem
Multica execution is end-to-end today: once an agent starts a task there is no way to talk to it until the run finishes. A comment posted mid-run is (correctly, and carefully, #5914) recorded as a deferred obligation and replayed as a follow-up task after completion. That guarantees nothing is dropped, but the human is always a full task-cycle behind: you cannot say "stop, the fixture you're editing is generated, change the generator instead" while the agent still has 20 minutes of work ahead.
What this PR adds
The missing capability layer underneath live steering: an optional, additive
Steer func(text string) erroronagent.Session, implemented by the claude backend.The claude backend can support this essentially for free: it already runs
--input-format stream-jsonand deliberately keeps stdin open for the whole run (forcontrol_responseframes).Steerwrites one moreuserframe to that same pipe; the CLI queues it as the next user turn, so the in-flight turn is never corrupted.Design points
Steer == nilas "unsupported → use the existing follow-up-task path".Tests
CLAUDE_FAKE_MODEre-exec pattern as the deadlock tests): the steer text must arrive as a well-formed user frame on the same stdin, after the prompt, while the run is live — the fake blocks on the second frame, so non-delivery hangs the test rather than passing.go vetclean, full./pkg/agentsuite green, wholeservertree builds.What this PR deliberately does NOT do
No server-side wiring. Routing a mid-run comment to a live session instead of the deferred replay touches the #5914 invariants (completion reconcile, planned-comment registration, head-scoped merges), and that deserves its own design review rather than riding along here. Proposed direction, for context: live delivery as an optimization of the existing deferred outcome — the daemon claims a deferred comment for live delivery, the claim marks it covered so completion reconcile skips it, and anything unclaimed (unsupported backend, race with completion, delivery failure) flows through the existing replay path unchanged. Happy to write that up as an RFC issue if there's interest.
Why from us
We run self-hosted Multica driving Claude Code runtimes on GKE; "you can't chat with an agent while it works" is the top piece of feedback from our engineers. This is the smallest reviewable step toward fixing it.