refactor(ui): centralize tool call detail presentation - #5412
colaforniaw wants to merge 1 commit into
Conversation
hqhq1025
left a comment
There was a problem hiding this comment.
No P0-P3 findings at a8827f2d133221603f921f8c1bf2b53aa422e13b.
This change centralizes the mutually exclusive tool-detail selection in describeToolCall() and leaves ToolCallDetailBody as the renderer for that decision. The connector-owned panel, live stream, shared/owned settled result, quiet JSON, args-only, permission-denied, bypass, sandbox-denial, cancellation, and PTY-control paths retain their previous precedence and presentation.
I compared the exact parent and this head with an independent server-render matrix covering 32,256 combinations of locale, result kind, args shape, tool name, status, observed activity, and live chunks. After normalizing React-generated aria-describedby IDs, there were zero markup differences and no render exceptions. The new presentation suite also passes unchanged on the exact parent (28/28), which is consistent with this refactor's stated zero-behavior-change contract.
Validation completed with build:test, full workspace typecheck, UI 507/507, the focused presentation suite 28/28, lint, format, ASF headers, changed-file Biome, UI/Desktop Knip, and git diff --check. A conflict-free synthetic merge onto current main (c980b93a37ad38fb78f255b6fffcf844e125f64c) also passed build, typecheck, and the focused suite; hosted test and label are green. I did not independently exercise packaged macOS/Windows Electron or a native screen-reader session.
Automated review notice: This comment was posted by an automated review agent operated by hqhq1025. It is not an independent human review and does not replace one.
a8827f2 to
dc13246
Compare
hqhq1025
left a comment
There was a problem hiding this comment.
No P0-P3 findings at dc1324677391256d3106c8188215d9dc928c991f.
The rebased four-file change still centralizes mutually exclusive tool-detail selection in describeToolCall() and leaves ToolCallDetailBody to render that decision. The connector-owned panel, live stream, shared/owned settled result, quiet JSON, args-only, permission-denied, bypass, sandbox-denial, cancellation, and PTY-control paths retain their prior precedence and presentation.
For this exact head, I compared the current base and PR using an independent server-render matrix covering 32,256 combinations of locale, result kind, args shape, tool name, status, observed activity, and live chunks. After normalizing React-generated IDs, there were zero markup differences and no render exceptions. The four PR files are also byte-identical to the previously reviewed patch after rebasing, and the current focused presentation suite passes 28/28.
Local validation passed with a clean install, build:test, full workspace typecheck, UI 498/498, focused presentation 28/28, lint, format, ASF headers, changed-file Biome, UI/Desktop Knip, git diff --check, Storybook production build, and three consecutive transcript geometry runs. The hosted test check is currently red because one geometry run observed three cold-reader slips where the gate allows one; the same exact-head scenario passed all three local repetitions, and the exact base's hosted test is green, so the available evidence does not attribute that isolated failure to this refactor. The gate remains red and should be rerun before merge.
I did not independently exercise packaged macOS/Windows Electron or a native screen-reader session.
Automated review notice: This comment was posted by an automated review agent operated by hqhq1025. It is not an independent human review and does not replace one.
Route expanded tool details through one internal presentation decision, consolidate quiet JSON composition, and remove the duplicate owned-panel rule. Preserve the rendered behavior with coverage across owned, shared, live, and failure presentations. Generated-by: OpenAI Codex
dc13246 to
bc706c3
Compare
hqhq1025
left a comment
There was a problem hiding this comment.
Reviewed exact head bc706c3a62af708061fc8d9068283a8f63d50c84.
I found no P0-P3 issue. This force-updated commit has the same complete tree object (57f858e6b2c7ab17da0722a48a35adf8ae0422d2) as the previously reviewed head dc1324677391256d3106c8188215d9dc928c991f; git range-diff reports the refactor patch unchanged, and all four affected UI file blobs are identical. The production behavior therefore remains the reviewed zero-behavior-change refactor: describeToolCall() centrally selects connector-owned, live, shared/owned settled, quiet JSON, args-only, permission, sandbox, cancellation, and PTY-control presentations, while the detail body renders that decision.
The identical tree previously passed a clean install, build:test, full workspace typecheck, UI 498/498, focused presentation 28/28, lint, format, ASF headers, changed-file Biome, UI/Desktop Knip, git diff --check, Storybook production build, three consecutive transcript-geometry runs, and an independent 32,256-case SSR differential with zero normalized markup differences or render exceptions. The new exact head's hosted test check is now green, resolving the prior head's unclosed geometry gate.
This head is directly based on current main 672d82731a638e45e3ec87022eabdcf70a5a90be, and GitHub reports MERGEABLE. I did not independently exercise packaged macOS/Windows Electron or a native screen-reader session; final acceptance remains a human decision.
Automated review notice: This comment was posted by an automated review agent operated by hqhq1025. It is not an independent human review and does not replace one.
Astro-Han
left a comment
There was a problem hiding this comment.
Thanks for splitting this out — the single-decision shape is much easier to reason about than three places that had to agree. I checked behavior parity first, since the claim is "no rendered change"; I could not construct a reachable input where the output differs. Nits below.
Parity checks I ran
Owned-panel routing is equivalent. The ownedPanel IIFE (packages/ui/src/tool-activity.tsx:217-233) is the deleted resultOwnsOwnPanel (packages/ui/src/tool-activity/result-projection.ts:71-88 on main) verbatim: connector + json first, then the same six-kind switch. ownsPanel = ownedPanel !== undefined || requiresBypass (:234) matches the old resultOwnsOwnPanel(item) || requiresBypass, and showResult / displayResult / invocationLine / showLiveStream (:235-248) keep their old guards, so invocation suppression and the live-to-settled switch are unchanged.
The new if-chain reproduces the old IIFE's priority. Walking the reachable combinations against main's shared-well block (packages/ui/src/tool-activity.tsx:286-320): json result → :295 (same title, because describeQuietJsonPresentation keeps the headline !== invocationLine rule); settled non-owned result → :305; raw args dump → :319; invocation-line fallback → :329. :319 is unreachable when showResult is true (:305 catches it first), which is exactly the old !showResult guard on argsBody (main:289-292). The item.args && truthiness test also matches the old hasSharedPanelContent disjunct (main:243), so falsy-but-defined args still render nothing rather than a (空) block. One nice side effect: the old code could emit an empty <div data-slot="tool-output" class="maka-tool-output-stack"> when the IIFE returned null; that's gone.
Per-tool special-casing survives. WriteStdin + shell_run still reaches PtyControlPreview, because the owned branch passes toolName/args (:269-280) and ToolResultPreview keys off them (packages/ui/src/tool-activity/tool-result-preview.tsx:219); ptyControlResult still suppresses only the sandbox banner (:251-255); the load-tool renderer is still selected only for connector tools, and passing item.result instead of displayResult is safe because withLiveStreamFallback is the identity for json.
The props widening is inert. The shared branch now passes toolName/args/shellRunSource (:305-317) where main's shared call site passed none (main:309-315). Those three are read only in the shell_run branch of ToolResultPreview, and shell_run is always owned, so the shared branch can never observe them. No API break either: ToolResultPreview's props are untouched, and result-projection.ts isn't re-exported from index.ts/components.tsx, so dropping resultOwnsOwnPanel breaks no consumer.
No accessibility delta. actionIdentity is computed once (:426-431) from the same two parts as outputActionIdentity, so every copy button's aria-label (Copy: <tool>) is unchanged, and data-slot/data-kind are still emitted by the same components in the same places.
Nits
-
The
argsOnlybranch has no test, and the test named for it doesn't reach it.tool-activity.tsx:319-327requires!invocationLine, but the new case usesargs: { alpha: 1, beta: true }(packages/ui/src/__tests__/tool-activity-presentation.test.ts:692-702).formatToolInvocationLinefalls through to its last resort and returnsalpha: 1 / beta: true(packages/core/src/tool-quiet-preview.ts:326), so!invocationLineis false and the render lands on the invocation-line branch (:329)./alpha/,/beta/and the panel count all match either way — the test would still pass with:319-327deleted. That branch is reachable in production:projectToolActivityArgsprojectstodo_writeargs to{}(packages/core/src/tool-activity-args.ts:185), which produces no key/value lines → undefined invocation line → thelanguage="json"(空)dump. Usingargs: {}(or an array) there would cover it. -
Three of the six owned kinds are absent from the family test.
:222-228still routesweb_search,web_search_errorandrive_workflowto bespoke cards that emit nodata-slot="tool-output"(tool-result-preview.tsx:759,:768,:821,:718). The parametrized list (tool-activity-presentation.test.ts:496-599) coversfile_diff/terminal/shell_runpipes+pty only, so the "never nest these in the shared well" invariant is unasserted for exactly the kinds that would silently gain a.maka-tool-output-stackwrapper (which carriesmargin-top: 4px) if someone dropped them from the switch. Adding them with an expected count of0plusdoesNotMatch(/maka-tool-output-stack/)would close that gap. -
describeQuietJsonPresentationstops one step short of unifying.tool-result-preview.tsx:239-240runs body and title throughformatUserVisibleToolText, while thequietTextarm ofToolCallDetailBody(tool-activity.tsx:362-369) passes them through raw. That matchesmain(main:295-305skipped it for the shared quiet panel too), so it isn't a regression — but the helper's contract is now "returns text that some callers localize and others don't", which is the kind of drift this refactor is meant to remove. A one-line comment saying the asymmetry is deliberate would be enough. -
nit:
outputPanelCount(tool-activity-presentation.test.ts:44-46) duplicates the inlinemarkup.match(/data-slot="tool-output"/g)idiom already used at:408and:440; reusing the helper there keeps one spelling. -
nit: both checklist boxes at the bottom of the description are unchecked even though the Verification section reports lint/format/typecheck/tests green — worth ticking or calling out what's outstanding, since the before/after screenshots follow-up is still open too.
Summary
Tool call details currently select presentation ownership in several places.
ToolCallDetail,ToolResultPreview, andresultOwnsOwnPanelmust agree on panel routing, quiet JSON composition, and live-to-settled behavior.Route each expanded detail through one internal
describeToolCalldecision. The decision now owns body selection, invocation/title/args composition, permission-denied hiding, connector load cards, and the live-to-settled switch. Reuse one quiet JSON presentation and remove the duplicate owned-panel rule.Rendered behavior remains unchanged across owned and shared panels, connector tools, streaming output, cancellation, bypass, and sandbox failures.
Fixes #5403
Verification
npm run lintpassed.npm run format:checkpassed.npm --workspace @maka/ui run buildpassed.npm --workspace @maka/ui run typecheckpassed.tool-activity-presentation.test.tspassed: 30/30.npx knip --workspace apps/desktoppassed.npx knip --workspace packages/uipassed.git diff --checkpassed.npm run buildandnpm run typecheckwere attempted but do not complete on the currentorigin/main. Unrelated baseline errors include implicitanyfailures in runtime tests and existing CLI/Desktop protocol type drift around transcript overlay and bootstrap fields.Draft follow-up
AI use
Select exactly one:
Tool(s) and scope: OpenAI Codex implemented the refactor, added the presentation coverage, performed adversarial review and design ablation, ran local verification, and prepared this PR. The commit includes a
Generated-by: OpenAI Codextrailer.Checklist
Does this PR entail a change in behavior?