feat: steer-only agent messages and a polished message box
Dean chose steer only: a message to a coding agent always steers the turn under way or opens one, and nothing is queued anywhere. This replaces O1's eve-side queueing (#1900) and reshapes O2's message box (#1907) into one consistent card. Base is coding-agents.
Server
POST /api/agents/{id}/messagestakes{ text, clientKey }.deliveryis gone; the coder channel'sturnPolicyissteer, and the eve client no longer names a per-message policy (both of Luke's channels steer).- Idempotent sends. The line's row stands under
sentLineId(clientKey)inmessages.client_id. The route reads it before GitHub is asked (sentLineStands) and the writer reads it again under the conversation lock, so a send repeated after a lost answer answers the agent as it stands and sends nothing; two sends racing under one key send once. This closes the gap O2 reported (a lost answer plus Retry repeating an instruction). takeAwaitingLinematches the oldest turnless user row by its words. That is safe with steer only: lines are received in the order sent, and two identical awaiting lines are interchangeable (same words, no turn, noturnIdon the wire), so whichever row a receipt takes, the end state is the same. The old delivery-id match existed only for a steer overtaking a queued message, which can no longer happen.tests/coder-host.test.tscovers two identical messages.- Goldens re-recorded under
LUKE_UPDATE_FIXTURES=1:coding-agent-wire-codingAgentMessageRequestSchemaandcoding-agent-view-codingAgentMessageParamsSchemalosedeliveryand gainclientKey.
Desktop
- The box is AI Elements'
PromptInputinAgentTab's composer slot: one 12px-radius card on the raised surface behind a hairline that brightens on focus-within, the textarea in the body font with no inner border, auto-growing from one to about eight lines, and a toolbar row inside the card's bottom edge. - Root cause of the monospace well:
base.cssresetsbuttonbut nottextarea, and Tailwind's preflight is deliberately left out, so the field was the browser's default (monospace, hard border).base.cssnow resetstextareatofont: inherit,border: 0, and the composer test holds that as a stylesheet contract. - Nothing changes with the agent's state: same placeholder ("Message the agent…"), same size, no hint line, no queue rows, no split menu, no ⌥Enter. The one exception is the round 28px button at the right: Send ↑ with text (disabled when empty and idle), Stop ■ when empty and a turn runs, both with tooltips.
- Enter sends, Shift+Enter is a new line. Every send mints a
clientKey; Retry reuses it. Errors are an inline line under the card in the host's words with Retry, the text staying in the box; a retired agent keeps the box, disabled, with the reason and no Retry. - O2's foundations stay: the optimistic send with reconcile, the
(agent, turnId)ledger withobserveMessaged, and Stop owned by the composer.
Removed
packages/hosted/src/coding-agent-wire.ts:CODING_AGENT_DELIVERY/CodingAgentDelivery, the request'sdeliveryfield,awaitedDeliverySchema/readAwaitedDelivery/awaitedDeliveryOf, and the queueing docs.packages/wire:MESSAGE_DELIVERY/MessageDelivery(nothing imports them any more) and thedeliveryfield of the stored typed-ask metadata.apps/web/server/coding-agents-app.ts: the delivery parameter and its comments.writeAwaitingLinestays, since it is the write every steer takes; it now takes the key and checks it under the lock.apps/web/server/hosted/brain-host/eve-sessions.ts: the per-messageturnPolicy(TURN_POLICY_OF_DELIVERY,EveMessage.delivery).apps/web/server/hosted/coder-host/channel.ts:TURN_POLICYQUEUE → STEER, comment rewritten;apps/web/coder/channels/eve.ts: the "queue policy" wording.apps/desktop/src/renderer/planning/agent-composer.tsx: the Queue rows, the delivery split menu, ⌥Enter, the hint line, the state-dependent placeholder.apps/desktop/src/renderer/ai-elements/queue.tsxand its CSS (.agent-composer-queue*,-hint,-chevron,-menu,-closed).- Desktop IPC and model (
coding-agent-acts,testing/acts.ts,coding-agent-model.ts,host-operator.ts): the delivery argument,agentLines's queued split. apps/web/server/README.md: the queue andmetadata.deliveryprose.docs/PLANNING.mdhad none.- Their tests, deleted because the feature is removed; the unrelated "queued" words (turn lifecycle, planning questions, the brain-host channel's own policy, preview deployment) are untouched.
- O2 added no shortcut, settings, or keycap entry for queueing, so there was nothing to remove there.
Screenshots
Rendered in headless Chrome over the real AgentTabView and the built renderer stylesheet (Linux fonts, so the face is DejaVu rather than SF Pro); committed on pr-assets.
| Idle, empty | Running, with text |
|---|---|
![]() | ![]() |
| Running, empty (Stop) | Error with Retry |
|---|---|
![]() | ![]() |
Verification
./scripts/check.sh exits 0 locally (lint, knip, discarded-effect, typecheck, every test file, the harness tests). CI could not verify the Mac: no macOS job runs on a pull request, and Dean waived ./scripts/verify.sh for this work, so the Mac rendering is unverified beyond the headless captures above.
🤖 Generated with Claude Code



