Fleet event drawer — tool widget coverage + JSON-free log stream #1008

Closed
opened 2026-05-09 10:33:59 +00:00 by claude-desktop · 0 comments
Collaborator

User story

As an operator monitoring a fleet run, I want every event in the Log tab of the right drawer to render as a structured, readable widget — never as raw JSON — so that I can scan a run timeline without parsing nested objects.

Background

The dashboard's tool-call dispatcher (apps/web/src/components/tool-call-widgets/index.tsx:37) routes events from a server-normalised ToolKind (packages/shared/src/tool-kind.ts:183) to a per-kind widget. Anything outside the ANTHROPIC_TOOLS / CURSOR_TOOLS matrix or the mcp__ prefix collapses to kind: "unknown" and gets dumped as raw JSON by <UnknownToolCallView> (apps/web/src/components/tool-call-widgets/unknown-tool-call-view.tsx:11).

Operator review (2026-05-09) found multiple unmapped Claude Code built-ins surfacing as JSON in the live drawer (ToolSearch, AskUserQuestion, Skill, ExitPlanMode, ScheduleWakeup, Agent when invoked under non-Task aliases). Independently, assistant events render a redundant [+] toggle that, when expanded, dumps {text, model, thinking[]} even though <Reasoning> already renders the thinking blocks above (apps/web/src/components/event-log.tsx:626-672).

Acceptance criteria

Taxonomy (packages/shared/src/tool-kind.ts)

  • Add new ToolKind literals for the missing Claude Code built-ins: tool_search, ask_user_question, skill, exit_plan_mode, enter_plan_mode, schedule_wakeup. Update TOOL_KINDS array.
  • Extend ANTHROPIC_TOOLS map with the corresponding provider names (ToolSearch, AskUserQuestion, Skill, ExitPlanMode, EnterPlanMode, ScheduleWakeup).
  • Update tool-kind.test.ts to cover the new mappings + ensure unmapped names still return unknown.

Widgets (apps/web/src/components/tool-call-widgets/)

  • One widget per new kind, lazy-loaded from index.tsx REGISTRY:
    • tool-search-view.tsx — show query + max_results; on completion, render match count.
    • ask-user-question-view.tsx — render the question + options list (label + description per option), no JSON.
    • skill-view.tsx — show skill name + args summary (one-line key/value).
    • plan-mode-view.tsx — single component reused by both exit_plan_mode and enter_plan_mode; show plan text rendered as markdown when present.
    • schedule-wakeup-view.tsx — show delaySeconds (formatted as Nm Ns), reason, truncated prompt preview.
  • Each widget uses <WidgetFrame> + lifecycleState() from shared.tsx so state pills + frame styling stay consistent.

UnknownToolCallView replacement

  • Replace the raw safeStringify <pre> block with a structured key/value list: one row per top-level key in args, value rendered as a single-line monospace string with clip() truncation.
  • When result is present, render under a Result divider with the same key/value format.
  • Raw JSON only behind import.meta.env.DEV (gated by a small <DevRawJson> <details> block) so the production drawer never shows JSON.

Assistant detail toggle

  • In event-log.tsx EventRowBase (line 656-672), suppress the [+] detail toggle for ev.type === "assistant" whose detail is already covered by the <Reasoning> block (i.e. detail.thinking is the only non-trivial field).
  • Keep the toggle for non-assistant events whose detail is non-empty and not otherwise rendered.

Tests

  • Storybook (or fixture-driven render test) for each new widget showing input-streaming / input-available / output-available / output-error states.
  • Snapshot test asserting <UnknownToolCallView> renders no { / } characters in production mode for a representative payload.
  • Regression test for event-log.tsx confirming an assistant event with detail.thinking does not render the [+] toggle.

Out of scope

  • Diff review tab redesign — covered by the sibling story.
  • TurnsStrip / RunHeaderMeters polish.
  • Server-side tool-name normalisation for non-Anthropic providers (Cursor map already covers the SDK we ship).

References

  • Conversation 2026-05-09 — operator review of fleet drawer event log.
  • apps/web/src/components/tool-call-widgets/index.tsx:37 — REGISTRY.
  • apps/web/src/components/tool-call-widgets/unknown-tool-call-view.tsx:11 — JSON dump path.
  • apps/web/src/components/event-log.tsx:626-672 — assistant [+] detail toggle + generic detail fallback.
  • packages/shared/src/tool-kind.ts:135 — Anthropic tool name → kind map.
## User story As an operator monitoring a fleet run, I want every event in the Log tab of the right drawer to render as a structured, readable widget — never as raw JSON — so that I can scan a run timeline without parsing nested objects. ## Background The dashboard's tool-call dispatcher (`apps/web/src/components/tool-call-widgets/index.tsx:37`) routes events from a server-normalised `ToolKind` (packages/shared/src/tool-kind.ts:183) to a per-kind widget. Anything outside the `ANTHROPIC_TOOLS` / `CURSOR_TOOLS` matrix or the `mcp__` prefix collapses to `kind: "unknown"` and gets dumped as raw JSON by `<UnknownToolCallView>` (apps/web/src/components/tool-call-widgets/unknown-tool-call-view.tsx:11). Operator review (2026-05-09) found multiple unmapped Claude Code built-ins surfacing as JSON in the live drawer (`ToolSearch`, `AskUserQuestion`, `Skill`, `ExitPlanMode`, `ScheduleWakeup`, `Agent` when invoked under non-`Task` aliases). Independently, `assistant` events render a redundant `[+]` toggle that, when expanded, dumps `{text, model, thinking[]}` even though `<Reasoning>` already renders the thinking blocks above (apps/web/src/components/event-log.tsx:626-672). ## Acceptance criteria ### Taxonomy (`packages/shared/src/tool-kind.ts`) - [ ] Add new `ToolKind` literals for the missing Claude Code built-ins: `tool_search`, `ask_user_question`, `skill`, `exit_plan_mode`, `enter_plan_mode`, `schedule_wakeup`. Update `TOOL_KINDS` array. - [ ] Extend `ANTHROPIC_TOOLS` map with the corresponding provider names (`ToolSearch`, `AskUserQuestion`, `Skill`, `ExitPlanMode`, `EnterPlanMode`, `ScheduleWakeup`). - [ ] Update `tool-kind.test.ts` to cover the new mappings + ensure unmapped names still return `unknown`. ### Widgets (`apps/web/src/components/tool-call-widgets/`) - [ ] One widget per new kind, lazy-loaded from `index.tsx` REGISTRY: - `tool-search-view.tsx` — show `query` + `max_results`; on completion, render match count. - `ask-user-question-view.tsx` — render the question + options list (label + description per option), no JSON. - `skill-view.tsx` — show skill name + args summary (one-line key/value). - `plan-mode-view.tsx` — single component reused by both `exit_plan_mode` and `enter_plan_mode`; show plan text rendered as markdown when present. - `schedule-wakeup-view.tsx` — show `delaySeconds` (formatted as `Nm Ns`), `reason`, truncated `prompt` preview. - [ ] Each widget uses `<WidgetFrame>` + `lifecycleState()` from `shared.tsx` so state pills + frame styling stay consistent. ### UnknownToolCallView replacement - [ ] Replace the raw `safeStringify` `<pre>` block with a structured key/value list: one row per top-level key in `args`, value rendered as a single-line monospace string with `clip()` truncation. - [ ] When `result` is present, render under a `Result` divider with the same key/value format. - [ ] Raw JSON only behind `import.meta.env.DEV` (gated by a small `<DevRawJson>` `<details>` block) so the production drawer never shows JSON. ### Assistant detail toggle - [ ] In `event-log.tsx` `EventRowBase` (line 656-672), suppress the `[+]` detail toggle for `ev.type === "assistant"` whose `detail` is already covered by the `<Reasoning>` block (i.e. `detail.thinking` is the only non-trivial field). - [ ] Keep the toggle for non-assistant events whose `detail` is non-empty and not otherwise rendered. ### Tests - [ ] Storybook (or fixture-driven render test) for each new widget showing input-streaming / input-available / output-available / output-error states. - [ ] Snapshot test asserting `<UnknownToolCallView>` renders no `{` / `}` characters in production mode for a representative payload. - [ ] Regression test for `event-log.tsx` confirming an `assistant` event with `detail.thinking` does not render the `[+]` toggle. ## Out of scope - Diff review tab redesign — covered by the sibling story. - TurnsStrip / RunHeaderMeters polish. - Server-side tool-name normalisation for non-Anthropic providers (Cursor map already covers the SDK we ship). ## References - Conversation 2026-05-09 — operator review of fleet drawer event log. - `apps/web/src/components/tool-call-widgets/index.tsx:37` — REGISTRY. - `apps/web/src/components/tool-call-widgets/unknown-tool-call-view.tsx:11` — JSON dump path. - `apps/web/src/components/event-log.tsx:626-672` — assistant `[+]` detail toggle + generic detail fallback. - `packages/shared/src/tool-kind.ts:135` — Anthropic tool name → kind map.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks#1008
No description provided.