Skip to content

improve(ui): flatten chat tool-call rows into a scannable list#99763

Merged
steipete merged 1 commit into
mainfrom
claude/flat-tool-call-rows
Jul 4, 2026
Merged

improve(ui): flatten chat tool-call rows into a scannable list#99763
steipete merged 1 commit into
mainfrom
claude/flat-tool-call-rows

Conversation

@steipete

@steipete steipete commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Closes #99760

What Problem This Solves

Tool calls in the Control UI chat render as heavily decorated nested cards: the Activity: N tools group draws a bordered card, every tool message inside it draws another bubble box, and the summary button on top adds an accent gradient, an inset highlight, and a 0 8px 22px drop shadow. Long tool summaries wrap across several lines. Dense agent sessions become hard to scan — a single 8-tool activity group fills an entire viewport.

Part of the box stacking is a CSS ordering bug: components.css begins with @import "./chat.css", so its legacy .chat-bubble and .chat-tool-card blocks load after chat/grouped.css/chat/tool-cards.css and override the intended .chat-bubble--tool-shell resets (padding: 0; border: 0; background: transparent). Each tool row therefore leaks a full bubble box underneath the summary pill.

Why This Change Was Made

Tool rows are now flat one-line rows (chevron + tool icon + label + mono detail, ellipsized), the activity group header is a flat clickable row, and its body is grouped by a thin left rule instead of a card. Expanded tool detail keeps soft tinted input/output blocks without card chrome; canvas/document previews keep their frame because they embed external content. Error states remain explicit (red icon/label plus Error badge, error groups still auto-expand). The duplicated legacy chat-bubble/tool-card CSS in components.css is deleted and the canonical .chat-bubble base in chat/grouped.css is reconciled to today's computed style, so normal user/assistant bubbles render unchanged. Dead render paths (renderToolCardSidebar, never-taken renderToolDataBlock branches) and their orphaned CSS are removed.

User Impact

Chat sessions with tool activity are dramatically denser and calmer: an 8-tool activity group shrinks from roughly a full screen of stacked cards to a few compact rows, in both light and dark themes. Collapsed rows clamp to one line; the full command and output remain one click away. No behavior changes: expand/collapse, error badges, sidebar open, and previews all work as before.

Evidence

Before/after with the same seeded conversation (mock gateway fixture, light and dark, collapsed/expanded/detail states):

Before After
Light, activity expanded before light after light
Dark, activity expanded before dark after dark
Light, tool detail expanded before detail after detail

Validation:

  • node scripts/run-vitest.mjs run ui/src/ui/chat/tool-cards.test.ts ui/src/ui/chat/tool-cards.node.test.ts ui/src/ui/chat/grouped-render.test.ts ui/src/ui/chat/build-chat-items.test.ts — 4 files, 153 tests passed
  • pnpm tsgo:core — clean
  • oxfmt --check on all touched files — clean
  • Structured autoreview (codex, gpt-5.5) on the diff — clean, no accepted findings
  • Screenshots produced against the Vite dev server with the control-ui e2e mock gateway (ui/src/test-helpers/control-ui-e2e.ts), viewport 1290×1180, deviceScaleFactor: 2

Net diff: −720 lines (340 insertions, 1060 deletions).

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui size: XL maintainer Maintainer-authored PR labels Jul 4, 2026
@clawsweeper

clawsweeper Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 4, 2026, 12:35 PM ET / 16:35 UTC.

Summary
Relative to current main, this PR flattens Control UI chat tool-call rows by changing the tool-card renderer, tool-card styles, grouped bubble shell styling, duplicated legacy component CSS, and focused tests.

Reproducibility: yes. Current main source and the linked issue describe the nested, decorated tool-call presentation, and the PR's screenshots show the before/after visual path; I did not run a live browser in this read-only review.

Review metrics: 1 noteworthy metric.

  • Current-main net surface: 5 UI files changed; 0 dependency, workflow, extension, or Codex files differ. The live PR file list is stale-base broad, so maintainers should judge the refreshed PR by the focused current-main delta.

Stored data model
Persistent data-model change detected: migration/backfill/repair: .agents/skills/openclaw-changelog-update/scripts/verify-release-notes.mjs, serialized state: test/scripts/crabbox-wrapper.test.ts, serialized state: test/scripts/docker-all-scheduler.test.ts, serialized state: test/scripts/openclaw-npm-publish.test.ts, serialized state: test/scripts/package-mac-app.test.ts, serialized state: test/scripts/package-mac-dist.test.ts, and 6 more. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #99760
Summary: This PR is the candidate fix for the exact Control UI tool-call visual heaviness issue; broader activity-collapse behavior remains a separate product question.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Resolve the GitHub CONFLICTING/DIRTY state so the live PR file list matches the focused current-main UI delta.
  • [P2] Rerun the focused chat UI tests or equivalent required checks on the refreshed head.

Risk before merge

  • [P1] GitHub still reports the live PR as CONFLICTING/DIRTY, so maintainers need a rebase or mergeability refresh before merge even though the current-main tree diff is focused.
  • [P1] The PR carries protected maintainer and security labels, so visual acceptance and any stale security-sensitive file-list cleanup need explicit maintainer handling.
  • [P1] The live GitHub file list still shows stale dependency/workflow/Codex surfaces; if those remain after rebase, they need normal security and ownership review before merge.

Maintainer options:

  1. Decide the mitigation before merge
    Refresh the PR so GitHub sees the focused 5-file UI-only delta, preserve the flat tool-row behavior, then merge only after maintainer visual acceptance and required checks pass.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P2] Protected labels and the dirty GitHub merge state require human rebase and visual acceptance; there is no narrow automated repair to queue from this review.

Security
Cleared: No concrete security or supply-chain concern was found in the current-main net diff, which is UI-only; stale dependency/workflow files should disappear after rebase.

Review details

Best possible solution:

Refresh the PR so GitHub sees the focused 5-file UI-only delta, preserve the flat tool-row behavior, then merge only after maintainer visual acceptance and required checks pass.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main source and the linked issue describe the nested, decorated tool-call presentation, and the PR's screenshots show the before/after visual path; I did not run a live browser in this read-only review.

Is this the best way to solve the issue?

Yes, after rebase. Removing duplicated legacy CSS and flattening the existing tool-card presentation is narrower than adding a config mode; the remaining decision is maintainer visual acceptance, not a different code layer.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 280e8d487627.

Label changes

Label justifications:

  • P3: This is low-risk Control UI ergonomics and visual-density cleanup, with merge blocked by maintainer/rebase handling rather than an urgent runtime regression.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (screenshot): The PR body includes before/after Control UI screenshots, and the downloaded after-light image directly shows the flatter tool-call rows and error styling.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes before/after Control UI screenshots, and the downloaded after-light image directly shows the flatter tool-call rows and error styling.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The PR body includes before/after Control UI screenshots, and the downloaded after-light image directly shows the flatter tool-call rows and error styling.
Evidence reviewed

What I checked:

  • Repository policy read: Root AGENTS.md and relevant scoped guides were read fully; protected-label handling, UI review guidance, and PR review-depth guidance affected this review. (AGENTS.md:1, 280e8d487627)
  • Live PR state: GitHub reports the PR open at head 2d84255 with protected maintainer/security labels and mergeable=CONFLICTING, mergeStateStatus=DIRTY. (2d8425560997)
  • Current-main net surface: The local tree comparison from current main to the PR head is focused to 5 UI files with 413 insertions and 1043 deletions; package, lockfile, workflow, Codex, and extension files do not differ against current main. (2d8425560997)
  • Flat row implementation: The PR head makes collapsed tool summaries borderless, transparent, single-line, and ellipsized, matching the requested scannable list behavior. (ui/src/styles/chat/tool-cards.css:17, 2d8425560997)
  • Tool shell reset: The PR head resets the tool bubble shell padding, border, background, and shadow so tool rows no longer inherit full chat-bubble chrome. (ui/src/styles/chat/grouped.css:228, 2d8425560997)
  • Screenshot proof inspected: The PR body's before/after light-mode screenshots were downloaded from the linked gist; the after image visibly shows compact flat activity rows and explicit error rows. (2d8425560997)

Likely related people:

  • Peter Steinberger: Recent merged history includes the chat style dedupe work in the affected files and older chat renderer/style splits; he also has prior history in this surface beyond authoring this PR. (role: recent Control UI style/refactor contributor; confidence: high; commits: 33022da15508, 1acbd6aea048, aa092045c05c; files: ui/src/styles/chat/tool-cards.css, ui/src/styles/components.css, ui/src/ui/chat/tool-cards.ts)
  • Tak Hoffman: Recent history shows interleaved tool-card pairing and assistant directive rendering work in the same renderer/style surface. (role: recent tool-card/chat contributor; confidence: medium; commits: d9812b85c41d, cc5c691f0069; files: ui/src/ui/chat/tool-cards.ts, ui/src/styles/chat/tool-cards.css)
  • Val Alexander: Dashboard-v2 and appearance-polish history shaped the Control UI style foundation that this PR changes. (role: dashboard UI foundation contributor; confidence: medium; commits: f76a3c5225bb, df72ca1ecec7; files: ui/src/styles/chat/tool-cards.css, ui/src/styles/components.css)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (5 earlier review cycles)
  • reviewed 2026-07-04T05:07:46.660Z sha 392de88 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T08:05:16.718Z sha d76f012 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T08:13:07.029Z sha d76f012 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T08:24:53.791Z sha 8e06193 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T08:37:43.344Z sha 8e06193 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. labels Jul 4, 2026
@steipete
steipete force-pushed the claude/flat-tool-call-rows branch 2 times, most recently from e93318d to 392de88 Compare July 4, 2026 04:58
@steipete
steipete requested a review from a team as a code owner July 4, 2026 08:00
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: line Channel integration: line channel: telegram Channel integration: telegram app: ios App: ios app: macos App: macos gateway Gateway runtime cli CLI command changes scripts Repository scripts commands Command implementations agents Agent runtime and tooling labels Jul 4, 2026
@github-actions github-actions Bot added the dependencies-changed PR changes dependency-related files label Jul 4, 2026
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Dependency graph guard cleared

This PR no longer has blocked dependency graph changes. A future dependency graph change requires a fresh /allow-dependencies-change comment after the guard blocks that new head SHA.

  • Current SHA: 8909ebf6b1d7c43ce13d43a8a3d7e96786ab3035

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d76f012b4d

ℹ️ 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".

`telegram sendRichMessage rejected invalid entity; falling back to plain text: ${errText}`,
);
return await sendPlainFallback(richFallbackText);
return await sendPlainFallback(fallbackPlan.plainText);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Split rich fallback text before sendMessage

When rich Telegram replies are chunked for the 32,768-char rich limit, the plain fallback can still exceed the normal 4,000-char sendMessage limit. This path computes fallbackPlan.chunks but discards it and sends fallbackPlan.plainText as one message, unlike the durable rich-send path in send.ts; any long rich reply that hits the new rich/entity parse fallback fails again as message-too-long instead of degrading to plain chunks.

Useful? React with 👍 / 👎.

@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord channel: matrix Channel integration: matrix channel: msteams Channel integration: msteams channel: signal Channel integration: signal channel: slack Channel integration: slack labels Jul 4, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 4, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2d84255609

ℹ️ 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".

Comment on lines +1907 to +1908
? api.editMessageText(chatId, messageId, fallbackPlan.plainText, plainTextParams)
: api.editMessageText(chatId, messageId, fallbackPlan.plainText),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Split rich edit fallback before calling editMessageText

For the newly handled rich HTML parse fallback, this passes the entire fallbackPlan.plainText into the normal editMessageText API. Telegram limits editMessageText.text to 1–4096 characters after entity parsing (https://core.telegram.org/bots/api#editmessagetext), while rich messages here can be up to 32,768 chars, so a long rich edit that should degrade to plain text will fail again as message-too-long instead of updating; the send path above uses fallbackPlan.chunks, so this edit path needs an equivalent bounded fallback or replacement strategy.

Useful? React with 👍 / 👎.

Tool calls in Control UI chat rendered as triple-nested cards: activity
group card + tool-shell bubble chrome + gradient summary pill with a
0 8px 22px drop shadow. Collapsed rows now render as flat single-line
rows with ellipsis, the activity group uses a flat header plus a left
rule, and expanded detail keeps soft tinted blocks without card chrome.
Also deletes the dead legacy .chat-tool-card__details/__output CSS and
the unused renderToolCardSidebar path with its never-taken
renderToolDataBlock branches.

Closes #99760
@steipete
steipete force-pushed the claude/flat-tool-call-rows branch from 2d84255 to 8909ebf Compare July 4, 2026 23:31
@openclaw-barnacle openclaw-barnacle Bot removed docs Improvements or additions to documentation channel: discord Channel integration: discord channel: imessage Channel integration: imessage channel: line Channel integration: line channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: nostr Channel integration: nostr channel: signal Channel integration: signal channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser labels Jul 4, 2026
@steipete

steipete commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

Merged via squash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui maintainer Maintainer-authored PR P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Control UI: tool-call rendering is visually heavy (triple-nested boxes, gradients, drop shadows)

1 participant