Skip to content

fix(ui): normalize pending tool-call previews + pending renderer states (split 1 of #27) - #32

Merged
MarlBurroW merged 2 commits into
MarlBurroW:mainfrom
kdegeek:pr/tool-preview-pending-states
Jul 6, 2026
Merged

fix(ui): normalize pending tool-call previews + pending renderer states (split 1 of #27)#32
MarlBurroW merged 2 commits into
MarlBurroW:mainfrom
kdegeek:pr/tool-preview-pending-states

Conversation

@kdegeek

@kdegeek kdegeek commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

First split out of #27 (the runtime/UI hardening branch), per @MarlBurroW's suggested breakdown — the self-contained, easily-mergeable UI slice, rebased on current main.

  • Normalize pending tool-call preview args. chat:tool-call-start renders a preview before streamed tool args arrive, so a preview renderer reading args.path / args.command / args.title could crash on a still-pending call. Args are now normalized to {} centrally in registerPreviewRenderer (and normalizeToolCallArgs), with safe getStringArg / getPathArg accessors in the preview renderers.
  • Pending renderer states for file-op result renderers. FileEdit and FileWrite render an explicit spinner + "pending" state while their args stream, instead of flashing their result/failure UI.
  • Add the previously-missing i18n keys these states use — tools.status.pending, tools.renderers.editingFile, tools.renderers.writingFile — to en.json and all nine other locales, so the English defaultValue no longer leaks into every language.

Two additions beyond the original branch (both in-theme)

  • MultiEdit and ListDirectory get the same pending handling. Both previously rendered the red failed UI for an unresolved call (success is false while result is undefined). They now distinguish pending from failed exactly like FileEdit/FileWrite (failed = status === 'error' || error !== null || (result !== undefined && !success)). One caught by a CodeRabbit pass (MultiEdit), the other found alongside it (ListDirectory).
  • A 4th locale key, tools.renderers.listingDirectory, for the ListDirectory pending message (multi_edit reuses editingFile).

Validation

  • bun run typecheck — PASS
  • bun run test — PASS (3985 tests)
  • bun run build — PASS (pre-existing Vite chunk-size warnings only)
  • bun scripts/check-locales.ts — PASS (all 10 locales, matching key paths, no em-dashes)
  • git diff --check — PASS
  • CodeRabbit review — 0 findings

The remaining pieces of #27 (crash-safe pre-insert/checkpoint, the multi-candidate auth/cache path resolution + getRealHome boot-crash fix, and the restart-gating / toolbox-grant design questions) will follow as separate PRs / discussion.

🤖 Generated with Claude Code

kdegeek and others added 2 commits July 6, 2026 14:14
…e keys

Split out of PR #27 as the independently-mergeable UI slice, rebased on main.

- Normalize tool-call args to {} before rendering previews so a
  chat:tool-call-start event (which fires before streamed args arrive) can't
  crash a preview renderer reading args.title / args.path / args.command etc.
  Centralized in registerPreviewRenderer + normalizeToolCallArgs, with safe
  getStringArg/getPathArg accessors in the preview renderers.
- FileEdit/FileWrite renderers show explicit pending states while args stream.
- Add the three previously-missing i18n keys these states use
  (tools.status.pending, tools.renderers.editingFile, tools.renderers.writingFile)
  to en.json and all nine other locales so the English defaultValue no longer
  leaks into every language. `bun scripts/check-locales.ts` passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… not failed

CodeRabbit flagged MultiEditRenderer showing the red "failed" UI for an
unresolved call (success is false while result is undefined). ListDirectoryRenderer
had the identical latent bug. Both now distinguish pending from failed the same way
FileEditRenderer/FileWriteRenderer do (failed = real error or completed-unsuccessful),
and render a spinner + pending state while the call streams.

Adds the `tools.renderers.listingDirectory` key across all 10 locales for the
list_directory pending message; multi_edit reuses `editingFile`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kdegeek
kdegeek requested a review from MarlBurroW as a code owner July 6, 2026 19:29
Copilot AI review requested due to automatic review settings July 6, 2026 19:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the chat UI’s tool-call rendering to behave safely during the “pending/streaming args” window, preventing crashes in tool preview renderers and avoiding incorrect “failed” flashes for file-operation renderers. It also completes the corresponding i18n additions across all supported locales.

Changes:

  • Normalize tool preview renderer args to {} during chat:tool-call-start / pending states, and add safer arg access in preview renderers.
  • Add explicit pending UI states (spinner + pending text) for file-operation result renderers (including MultiEdit and ListDirectory) so pending calls don’t appear failed.
  • Add new i18n keys for pending/tool renderer messaging across all 10 locales, plus targeted tests for normalization and pending rendering behavior.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/server/tools/shell-tools.test.ts Makes /tmp expectations robust by resolving symlinks via realpathSync.
src/client/locales/en.json Adds new tool pending/renderer strings for English.
src/client/locales/de.json Adds new tool pending/renderer strings for German.
src/client/locales/es.json Adds new tool pending/renderer strings for Spanish.
src/client/locales/fr.json Adds new tool pending/renderer strings for French.
src/client/locales/it.json Adds new tool pending/renderer strings for Italian.
src/client/locales/ja.json Adds new tool pending/renderer strings for Japanese.
src/client/locales/pl.json Adds new tool pending/renderer strings for Polish.
src/client/locales/pt-BR.json Adds new tool pending/renderer strings for Brazilian Portuguese.
src/client/locales/ru.json Adds new tool pending/renderer strings for Russian.
src/client/locales/zh-CN.json Adds new tool pending/renderer strings for Simplified Chinese.
src/client/lib/tool-registry.ts Normalizes preview-renderer args to {} to avoid pending-state crashes.
src/client/lib/tool-preview-renderers.ts Uses safer arg accessors for common preview renderers (path/command/sql/etc.).
src/client/lib/tool-preview-renderers.test.ts Adds regression tests ensuring previews/renderers don’t throw or flash failed while pending.
src/client/components/chat/ToolCallItem.tsx Normalizes args to {} before passing into preview/renderers/JSON viewer.
src/client/components/chat/renderers/FileEditRenderer.tsx Adds explicit pending state UI and safer args access.
src/client/components/chat/renderers/FileReadRenderer.tsx Makes args.path access null-safe for pending tool calls.
src/client/components/chat/renderers/FileWriteRenderer.tsx Adds explicit pending state UI and safer args access.
src/client/components/chat/renderers/MultiEditRenderer.tsx Distinguishes pending vs failed and renders pending spinner/message.
src/client/components/chat/renderers/ListDirectoryRenderer.tsx Distinguishes pending vs failed and renders pending spinner/message.
src/client/components/chat/InlineToolCall.tsx Introduces normalizeToolCallArgs and applies it for inline tool call rendering.
src/client/components/chat/InlineToolCall.test.ts Adds tests for normalizeToolCallArgs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@MarlBurroW MarlBurroW left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Reviewed and verified, this is exactly the split we hoped for. Thank you @kdegeek!

What we checked before merging:

  • Full diff read: the central normalization in registerPreviewRenderer plus the getStringArg/getPathArg accessors are clean, and the failed = status === 'error' || error !== null || (result !== undefined && !success) distinction is sound (a success call always carries its result, so no renderer can get stuck on the pending state).
  • The MultiEdit and ListDirectory additions are correct: both really did render the red failed UI for an in-flight call before this.
  • bun scripts/check-locales.ts, bun run typecheck, full bun run test (4094 tests) all green on the branch.
  • Booted the built app and ran a live write_file + list_directory turn end to end: previews render through the new code path, both calls resolve to their success UI, zero console/page errors.

Also appreciated: real assertions in the new tests (exact preview strings, pending-not-failed markup) and the locale keys shipped to all 10 languages with parity passing. Merging. Looking forward to the next splits of #27.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants