feat(ui): inline steer composer in the conversation viewer#121
Merged
Conversation
Press `i` in an agent's conversation viewer to open an input box, type a message, Enter to send (Esc cancels). The message is delivered via the existing session.steer / pendingSteers path — it appears as a user message and redirects the agent after its current tool, same as the steer_subagent tool. Works in both the FleetView overlay and /agents. Adds AgentManager.steer(id, message) to centralize the running-vs-pending routing, wires onSteer at both viewer call sites, and gates the affordance on the agent still being running/queued (mirrors the x/stop affordance). Tested at three layers: manager routing, composer interaction, and the fleet-list wiring seam (real ConversationViewer → manager.steer). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Shorter alternative if you prefer a one-liner subject + minimal body: feat(ui): steer agents from the conversation viewer `i` opens an input box to send a steering message to a running agent (Enter send, Esc cancel), delivered via session.steer. Adds AgentManager.steer() and tests across manager, viewer, and wiring.
Press Enter in an agent's conversation viewer to open an input box, type a message, Enter to send (Esc or an empty submit returns). The message is delivered via the existing session.steer / pendingSteers path — it appears as a user message and redirects the agent after its current tool, same as the steer_subagent tool. Works in the FleetView overlay and /agents. Adds AgentManager.steer(id, message) to centralize running-vs-pending routing, wires onSteer at both viewer call sites, and gates the affordance on the agent still being running/queued (mirrors the x/stop affordance). The idle footer keeps the full scroll-key hint by splitting into actions-left / nav-right.
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.
Steer agents from the conversation viewer
Adds an inline input box to the agent conversation viewer so you can steer a running subagent without leaving the view.
What
Enterin an agent's conversation viewer to open a composer, type a message,Enterto send.Escor an empty submit just returns.session.steer/pendingSteerspath — it appears as a user message and redirects the agent after its current tool, identical to thesteer_subagenttool./agentsviewer.running/queued(mirrors the existingx/stop affordance).Why
steer_subagentalready existed for the LLM, but a human watching an agent had no way to redirect it. This wires the same mechanism to the keyboard. Feedback is the steered message itself appearing in the live conversation you're already watching — no extra UI.Enteris the natural "interact" key, so the viewer stays modal and every existing shortcut (x/xstop, arrows/j/kscroll,qclose) is untouched.How
AgentManager.steer(id, message)centralizes routing: live session →session.steer; session not yet created → queued ontopendingSteers, flushed on creation.ConversationViewergains an optionalonSteercallback, a lazily-created single-lineInputcomposer, and acanSteer()gate symmetric withisStoppable(). While composing, the input owns all keys; chrome reserves one extra row.onSteeris wired tomanager.steer(record.id, …)at both viewer call sites (fleet-list.ts,index.ts).↑↓ scroll · PgUp/PgDn or Shift+↑↓ · Esc close) stays visible down to 80-col terminals. TheN lines · %position counter was dropped to make room.Testing
Covered at three layers:
steer()routing: unknown id, live session,pendingSteersqueuing, finished-agent rejection.ConversationViewerthrough the FleetList overlay (Enter → type → Enter) and assertsmanager.steeris called with the right agent id.Full suite green (675 passed / 4 skipped), typecheck + lint clean.
Notes
N lines · %scroll-position readout hides if the width is too small.Enterbinding is hardcoded, consistent with the existingx/qkeys in the same component (not routed through the keybindings manager).Render example
Idle — note Enter steer in the footer and the full scroll hint:
Composing — after pressing Enter and typing (█ is the live block cursor):