feat(ui): replace composer run-status pill with a transcript working spark#104768
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 11, 2026, 8:52 PM ET / July 12, 2026, 00:52 UTC. Summary PR surface: Source -44, Tests +80. Total +36 across 13 files. Reproducibility: yes. Current source deterministically suppresses Done, while current main, the PR body, the linked issue, and the submitted after image all establish the expected visible completion confirmation. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Keep the transcript spark as the active-work signal, restore the existing timed borderless Done toast alongside Interrupted, and attach fresh desktop/mobile proof from the final head. Do we have a high-confidence way to reproduce the issue? Yes. Current source deterministically suppresses Done, while current main, the PR body, the linked issue, and the submitted after image all establish the expected visible completion confirmation. Is this the best way to solve the issue? No in its current form. Moving active feedback into the transcript is the cleaner shared visual language, but deleting the promised Done confirmation is unnecessary and the final design lacks matching real-behavior proof. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against e7c3f7be6c83. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source -44, Tests +80. Total +36 across 13 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (1 earlier review cycle)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13a7975bec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ${composerRunStatus?.phase === "interrupted" | ||
| ? html` | ||
| <div class="agent-chat__composer-run-status"> | ||
| ${renderChatRunStatusIndicator(composerRunStatus, inProgressLabel)} | ||
| ${renderChatRunStatusIndicator(composerRunStatus)} | ||
| </div> |
There was a problem hiding this comment.
Keep interrupted status visible on mobile
When a run is interrupted, this branch now renders the only visible status into .agent-chat__composer-run-status; the old mobile .agent-chat__composer-progress strip was removed, and ui/src/styles/chat/layout.css:2749-2752 still hides .agent-chat__composer-run-status at mobile widths. On phones/tablets, stopping a run therefore leaves only the sr-only live region and no visible confirmation, even though interrupted runs do not add a transcript marker. Please keep a visible mobile status slot or avoid hiding this element for the interrupted state.
Useful? React with 👍 / 👎.
… show mobile interrupted toast
|
Merged via squash.
|
- void the now-async submitToolResult calls in the anvil-voice test - oxfmt scripts/sync-fakoli-fork-main.mjs - sync control-ui i18n raw-copy baseline + locale meta (upstream openclaw#104768 left Interrupted strings out of the baseline; path-filtered upstream CI never ran the check) - drop unused WatchInboxStore.shouldShowExecApprovalReviewStatus (upstream openclaw#104913, flagged by the iOS periphery scan)
…spark (openclaw#104768) * feat(ui): redesign composer run-status indicator as chrome-free status text * feat(ui): replace run-status text with transcript working spark * fix(ui): keep working spark through reloads, dodge running tool rows, show mobile interrupted toast * fix(ui): satisfy lint on tool-stream marker access
Closes #104765
What Problem This Solves
While the agent works, the composer footer narrates the run as a bordered pill: rounded-full chip, 1px info-blue border, tinted spinner, blue text cycling through "Sending message...", "Preparing model...", " is responding...". It reads like an alert, competes with the composer controls beside it, and duplicates signals the UI already has (the Stop button, streaming text, running tool rows). On mobile the same status renders as an even heavier full-width bordered box above the input. Meanwhile the transcript's pre-reply feedback was a generic three-dot typing bubble that only covered two narrow states.
Why This Change Was Made
The working indicator moves to where the work appears, Claude-style: the transcript's reading indicator becomes a small pulsing brand spark (
icons.spark,--accent) rendered where the reply will materialize, and its trigger broadens to the whole "working with nothing visibly streaming" window — pre-first-token, queued sends, reconnects to running sessions (isChatRunWorkinginchat-composer.ts, threaded throughbuildChatItemsasrunWorking). One indicator concept, one code path: the three-dot bubble is deleted, not kept alongside.The spark yields whenever something better signals activity: streamed text replaces it, a visible running tool row suppresses it (no stacked indicators), and the initial-load skeleton keeps priority on an empty thread — while background reloads with visible content keep the spark alive. The composer stops narrating: the visible pill and the mobile progress strip are removed. Two things survive on purpose:
role="status"pill for screen readers — and unlike the old pill it also announces on mobile.User Impact
While the agent works you see a small pulsing OpenClaw spark in the transcript where the reply will appear, instead of a blue-bordered spinner pill in the composer. The composer footer stays quiet; Stop/Send behavior is unchanged. Aborted runs still show a brief "Interrupted" note, now on mobile too. Reduced-motion users get a static spark.
Working (before → after, light):
Working (after, dark) + pulse animation:
Streaming — content replaces the spark (light):
Interrupted toast (desktop + mobile, light):
Mobile working (before → after, light):
Evidence
startControlUiE2eServer+installMockGateway) driving a real send → ack → delta → aborted event sequence; light/dark viaprefers-color-scheme.pnpm test ui/src/pages/chat/chat-composer.test.ts ui/src/pages/chat/chat-view.test.ts ui/src/pages/chat/components/chat-message.test.ts ui/src/pages/chat/chat-thread.test.ts ui/src/pages/chat/chat-responsive.browser.test.ts— green (Testbox). Run-status contracts rewritten (spark presence, sr-only announcements, interrupted-only toast) and new builder tests pin the spark rules (background reload keeps it, initial-load skeleton wins, running tool rows suppress it, hidden tool calls keep it).ui/src/e2e/chat-composer-redesign.e2e.test.ts— 6 passed locally (Playwright), asserting spark pre-token, spark yielding to streamed text, and no visible composer run status.chat-flow.e2e.test.tsreading-indicator flows pass; its two failures ("workspace files panel", "worktree chat") reproduce identically with all changes reverted to the branch base — pre-existing local-environment failures, unrelated (ui e2e runs in the live/e2e workflow, not PR CI).pnpm check:changed(Testbox) — format/lint/typecheck lanes green for the committed tree.fix(ui): keep working spark through reloads...; fresh run after the fixes is clean ("patch is correct", no accepted findings).