Repository navigation
fix(app): show a steer as pending from its first frame - #55251
Conversation
A steer sent while the agent works rendered as delivered until the agent and model switch returned, then faded to pending. Admit the prompt before the selection commits, as the TUI does, and stop the fade into the pending state.
There was a problem hiding this comment.
The approach looks right. Passing the selection commit as the data layer's prepare matches what /compact and the TUI already do. The steer's row now appears in the same step as the handoff, and the agent/model switch still runs inside the per-session admission queue, before the POST. Retries reuse a finished switch, a failed switch still isn't retried, and a staged revert still settles before admission. The CSS change only removes the fade while a message is pending.
Checked by reading the code against packages/client/src/solid/data.ts and running bun test src/composer/submit.test.ts (15/15 pass). I couldn't run the Playwright spec or watch the colour change myself because there's no browser in this environment, so I'm relying on your before/after captures.
Public API: unchanged (prepare already existed on the data layer's prompt).
Blocking: bun run typecheck in packages/app now fails in submit.test.ts. It passes on dev. See the inline comment.
| const request = await admitted.promise | ||
|
|
||
| expect(calls).toEqual([...row.calls, "prompt"]) | ||
| expect(calls).toEqual(row.calls) |
There was a problem hiding this comment.
This breaks bun run typecheck in packages/app (passes on dev): test.each makes row.calls a readonly array, so toEqual rejects it with TS2769 (readonly [...] is not assignable to string[]). expect(calls).toEqual([...row.calls]) fixes it.
A steer sent while the agent works showed as delivered (blue) for a few frames, then faded to pending (gray).
Causes (both needed for the flash)
sendPromptawaited the agent and model switch beforedata.session.promptadmitted the optimistic row. Until then the timeline had only the handoff message. It has no pending status, so it rendered as delivered, and as the active turn withWorkingunder it.user-message-texttransitionsbackground-colorandcolorover 200 ms. The row computes its style as delivered once before admission marks it pending, so it faded from blue even when admission landed in the same task.Fix
composer/submit.ts: pass the selection commit as the data layer'sprepare, like the TUI and/compact. The prompt admits locally in the same task as the handoff. The switch still lands before the POST.message-part.css:transition: nonein the pending state. Only delivery (gray → blue) animates.sequenceDiagram participant C as Composer participant T as Timeline participant D as Data layer participant S as Server Note over C,S: Before C->>T: handoff (no pending status: blue) C->>S: switch agent / model S-->>C: ok C->>D: prompt() admits the optimistic row (pending: fades to gray) D->>S: POST prompt Note over C,S: After C->>T: handoff C->>D: prompt({ prepare }) admits in the same task (pending: gray) D->>S: switch agent / model (prepare) D->>S: POST promptModel switch held in flight
Bubble background on each painted frame after Enter (Chromium, local mock server)
Model switch slowed to 900 ms
Before
before-slowed.mp4
After
after-slowed.mp4