This repository was archived by the owner on Sep 4, 2026. It is now read-only.
feat(chat): give MCP and tool rows their status, detail and a live toggle - #390
Merged
Merged
Conversation
ElbertePlinio
force-pushed
the
feat-parser-tool-detail
branch
from
July 26, 2026 02:04
53825a9 to
866360d
Compare
…ggle Frontend half of #362 and #365, behind the new default-off `mcpToolDetail` flag. Stacked on the parser slice, which is what makes these events exist. The wire event has always carried `status` and `detail` — `lib/agentChat.ts` declares both on `mcpToolCall` and `toolUse`. The timeline item type did not, so the reducer read them and threw them away, and `ChatTimeline` rendered `<McpCard server tool />` with no `detail` at all. With `detail` undefined `canExpand()` is false, which is exactly the reported symptom: a disabled chevron on a dead grey row. Both item types now carry `status` and `detail`, both optional so a row persisted before the parser learned to resolve non-Bash tools still renders. A completion that carries no result keeps the arg summary already on the row — resolving must never blank what the row was showing. Expansion moves into the hoisted `RowExpansion` map, the same contract `CommandCard` and `ThinkingBubble` use, so the toggle survives the virtualizer disposing the row on scroll-back. That was listed in #372 as a separate annoyance; it comes free here because these cards had to take `open`/`onToggle` anyway. Status renders through `StatusPill`, matching `CommandCard` rather than adding new chrome — bracket-cornered mono, never a filled chip. The two new render branches are extracted out of `renderItem` because adding them inline pushed it past the complexity cap. `flags.test.ts` enumerates the registry, so the new flag is asserted there rather than silently appearing. Refs #362, #365
ElbertePlinio
force-pushed
the
feat-tool-detail-ui
branch
from
July 26, 2026 02:06
26096f4 to
4cdf5c2
Compare
ElbertePlinio
added a commit
that referenced
this pull request
Jul 26, 2026
…ggle (#390) Frontend half of #362 and #365, behind the new default-off `mcpToolDetail` flag. Stacked on the parser slice, which is what makes these events exist. The wire event has always carried `status` and `detail` — `lib/agentChat.ts` declares both on `mcpToolCall` and `toolUse`. The timeline item type did not, so the reducer read them and threw them away, and `ChatTimeline` rendered `<McpCard server tool />` with no `detail` at all. With `detail` undefined `canExpand()` is false, which is exactly the reported symptom: a disabled chevron on a dead grey row. Both item types now carry `status` and `detail`, both optional so a row persisted before the parser learned to resolve non-Bash tools still renders. A completion that carries no result keeps the arg summary already on the row — resolving must never blank what the row was showing. Expansion moves into the hoisted `RowExpansion` map, the same contract `CommandCard` and `ThinkingBubble` use, so the toggle survives the virtualizer disposing the row on scroll-back. That was listed in #372 as a separate annoyance; it comes free here because these cards had to take `open`/`onToggle` anyway. Status renders through `StatusPill`, matching `CommandCard` rather than adding new chrome — bracket-cornered mono, never a filled chip. The two new render branches are extracted out of `renderItem` because adding them inline pushed it past the complexity cap. `flags.test.ts` enumerates the registry, so the new flag is asserted there rather than silently appearing. Refs #362, #365
ElbertePlinio
added a commit
that referenced
this pull request
Jul 26, 2026
…lag-gated) (#387) * fix(claude): let every tool row carry its args and reach a terminal status Shared parser slice for #362 and #365 — both issues named `claude_stream.rs`'s `RememberedTool` and the Bash-only guard in `map_tool_result` as one surface to serialize rather than duplicate, so this does that half once. **Nothing non-Bash ever completed.** `map_tool_result` returned `None` unless the tool was Bash, so every other tool was emitted `InProgress` and never updated — permanently "running" long after it finished. Lifting the guard alone would not have helped: `RememberedTool` collapsed everything non-Bash to a bare `Other`, discarding the name, so there was nothing left to route a completion to. It now retains the tool's identity — Bash, an MCP server/tool pair, or a named tool — and `map_tool_result` dispatches on it. **MCP rows were starved on purpose.** The MCP branch emitted `detail: None` while the non-MCP branch immediately below it attached `compact_input_summary(&input)`. That is why an MCP call rendered as one dead grey line: no args, no result, no completion, disabled chevron. **The generic row starved on a four-key allowlist.** `file_path`, `notebook_path`, `pattern`, `description` — `AskUserQuestion`, `Task`, `Skill`, `Glob`, `ToolSearch` and `Read`-with-offset carry none of them, so `detail` was `None` and the chevron was a dead button. Known keys still win (they are the human-meaningful ones); anything else falls back to a compact rendering of the whole input. Both payloads are capped in Rust, not the view, because these rows are persisted. Argument summaries take the FRONT of the string — the meaningful part of an argument list is at its head, unlike a command's output tail — and are capped far shorter, since they ride on a single collapsed row. Deliberately NOT in this slice, so the two follow-on PRs stay reviewable: `tool_progress` elapsed time and `system`/`status` compacting/requesting (#365 B1), which add a new event variant, and the frontend half of both issues — the timeline item's `status`/`detail` fields, the itemId update path, and the card wiring. Refs #362, #365 * fix(chat): resolve an MCP row in place instead of appending a duplicate The parser half of this change starts emitting completion events for MCP calls. `reduceMcpToolCall` appended unconditionally — it had no itemId match path, unlike its `reduceToolUse` sibling — so a resolving call would visibly double instead of updating. That makes the two halves inseparable: shipping the parser without this turns 'the row never finishes' into 'the row finishes twice'. Refs #362 * feat(chat): give MCP and tool rows their status, detail and a live toggle (#390) Frontend half of #362 and #365, behind the new default-off `mcpToolDetail` flag. Stacked on the parser slice, which is what makes these events exist. The wire event has always carried `status` and `detail` — `lib/agentChat.ts` declares both on `mcpToolCall` and `toolUse`. The timeline item type did not, so the reducer read them and threw them away, and `ChatTimeline` rendered `<McpCard server tool />` with no `detail` at all. With `detail` undefined `canExpand()` is false, which is exactly the reported symptom: a disabled chevron on a dead grey row. Both item types now carry `status` and `detail`, both optional so a row persisted before the parser learned to resolve non-Bash tools still renders. A completion that carries no result keeps the arg summary already on the row — resolving must never blank what the row was showing. Expansion moves into the hoisted `RowExpansion` map, the same contract `CommandCard` and `ThinkingBubble` use, so the toggle survives the virtualizer disposing the row on scroll-back. That was listed in #372 as a separate annoyance; it comes free here because these cards had to take `open`/`onToggle` anyway. Status renders through `StatusPill`, matching `CommandCard` rather than adding new chrome — bracket-cornered mono, never a filled chip. The two new render branches are extracted out of `renderItem` because adding them inline pushed it past the complexity cap. `flags.test.ts` enumerates the registry, so the new flag is asserted there rather than silently appearing. Refs #362, #365
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Frontend half of #362 and #365. Behind the new default-off
mcpToolDetailflag.The wire always carried this; the store threw it away
lib/agentChat.tsdeclaresstatusanddetailon bothmcpToolCallandtoolUse. The timeline item type did not, so the reducer read them and discarded them, andChatTimelinerendered:With
detailundefined,canExpand()is false → spacer instead of a chevron, disabled button, no body. That is exactly the reported symptom:MCP pickforge-lanes / lanes_waitas one dead grey line.What changed
statusanddetail, both optional — a row persisted before the parser learned to resolve non-Bash tools still renders rather than breaking on replay.RowExpansionmap, the same contractCommandCardandThinkingBubbleuse, so the toggle survives the virtualizer disposing the row on scroll-back. Chat transcript rows expand with no motion: only THINKING animates, CMD/TOOL/MCP/swarm/lanes snap open #372 listed that as a separate annoyance worth its own issue — it comes free here, because these cards had to takeopen/onToggleanyway.StatusPill, matchingCommandCardrather than adding new chrome: bracket-cornered mono, never a filled chip.Why the flag
A persisted row's shape changed and the parser only emits completions on newer builds, so
mainstays releasable while this is dark — same precedent aschangesReviewgating the receipt card.flags.test.tsenumerates the registry, so the new flag is asserted there rather than silently appearing.Tests
Three new store tests, all verified load-bearing (removing the carry fails two of them):
detail: nullkeeping the existing arg summaryfailedstatusValidation
bun run test:unit— 1604 passedbunx tsc --noEmitclean;bun run lintcleanThe two new render branches are extracted out of
renderItembecause adding them inline pushed it past the repo's complexity cap.Still not done for these two issues
Stated rather than implied:
tool_progresselapsed time andsystem/statuscompacting/requesting (A running turn is opaque: WORKING names nothing, no elapsed time, generic tool rows show no args and never complete #365 B1) — needs a new event variant inevent.rs. Without it,WorkingRowstill says nothing about what is running, which is A running turn is opaque: WORKING names nothing, no elapsed time, generic tool rows show no args and never complete #365's headline complaint.WorkingRownaming the active tool — depends on the above.COMPACT_LINE_PXstill holds. Worth re-measuring once elapsed time lands.Refs #362, #365