Skip to content

fix(components): keep serialized tool-input JSON out of Markdown math - #711

Merged
Leeeon233 merged 3 commits into
LodyAI:mainfrom
tommy0103:fix/tool-call-input-json-math
Sep 16, 2026
Merged

Leeeon233 merged 3 commits into
LodyAI:mainfrom
tommy0103:fix/tool-call-input-json-math

Conversation

@tommy0103

@tommy0103 tommy0103 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Related issue

Closes #710

Problem / pressure

Expanding a tool call showed its raw input JSON mangled. Tool calls report their raw input as a text content block holding serialized JSON (e.g. {"command":"…","timeout":60}); routing that text through the Markdown pipeline lets single-$ inline math treat shell fragments like $(git -C …) as TeX and drop characters like the & in 2>&1. The expanded view displayed a command that was not the command that ran — the stored history and the executed command were both intact, so the damage was render-time only.

Summary

  • Add detectToolCallJsonText (packages/components/src/lib/tool-call-json-text.ts): returns the original text, trimmed but otherwise untouched, when a text block parses as a JSON object or array; null otherwise (prose, primitives, broken JSON).
  • JSON.parse only validates — the payload is never re-serialized, so integer lexemes beyond 2^53 (64-bit IDs) and forms like 1e10 keep their exact digits. (Addresses the P1 review finding: a parse/stringify round trip would corrupt large numeric IDs and recreate the same displayed-differs-from-actual defect.)
  • StandardToolContentBlock's text case renders a detected payload in the same monospace <pre> treatment already used for raw tool output; everything else continues to MarkdownBlock unchanged.
  • The classifier lives in a leaf lib module so the regression test can assert it without pulling the whole view.tsx import graph into the test module graph (package rule).
  • Regression test covers the real-world payload shape (a git commit --amend command with $(...), 2>&1, nested quotes), integer lexemes beyond 2^53, exponent forms, plus prose/primitive/malformed-JSON negatives.
  • Agent Note (EN+ZH): .agents/notes/implemented/bug-fix/2026-09-15-tool-call-json-markdown-math.md.

Visual explanation

Simple change: one pure classifier plus one new branch in a render switch; the diff is the structure, and no multi-step flow changes.

Before / after

Before After
Raw tool-input JSON rendered as Markdown: $(...) spans became italic TeX (user.name="(git−C/…)"), 2>&1 lost its & — displayed command ≠ executed command Detected JSON payloads render byte-faithfully in a monospace block: shell fragments, big integer IDs, and exponent forms all preserved exactly; prose still gets full Markdown including $...$ math

Test plan

  • packages/components: tests/tool-call-json-text.test.ts 8/8 pass; related suites (markdown-math-delimiters, markdown-autolink, assistant-turn-render-blocks, markdown-streamdown-mode, assistant-message-render-items) pass.
  • packages/components pnpm typecheck: clean.
  • oxlint on touched files: 0 errors (pre-existing warnings only); Prettier: clean.
  • Root lint:i18n, check:code-collab-imports, check:platform-boundaries, check:public-boundary, docs check: all exit 0.
  • Skipped: full root pnpm check (monorepo test:ci). In a fresh worktree, markdown-idle-rerender and markdown-streaming-reparse fail identically on the unmodified base (jotai storage environment), so they are unrelated to this change; verified by A/B against a stash of this branch.
  • Not verified: live UI click-through; the mangling was observed on recorded history predating this branch, so rendering is verified by code inspection plus the classifier contract test.

Context handoff

Instructions for reviewing agents

  • Review focus: packages/components/src/lib/tool-call-json-text.ts (classifier contract, validation-only parse) and the text case of StandardToolContentBlock in packages/components/src/components/ai-gui/view.tsx (new render branch).
  • Decisions to challenge: any JSON object/array text is rendered as code rather than Markdown (a tool returning legitimate JSON-shaped prose loses Markdown rendering); single-line payloads stay single-line (no pretty-print) to keep numeric lexemes exact; the resource text case was deliberately left on the Markdown path and can still hit the artifact.
  • Plausible failures / evidence gaps: no live UI verification on this branch; the two failing suites listed in the test plan fail on the unmodified base too — re-check if CI disagrees.

Authoring context

  • User goal / directives: investigate a mangled tool-call JSON display, confirm upstream had no fix, then implement the fix on a clean worktree branch and open a PR; a P1 review finding on numeric literals was addressed by switching from pretty-print to verbatim display.
  • Constraints / non-goals: minimal scope — producer (CLI/ACP) data format untouched; resource text blocks untouched; no new user-visible copy (no i18n changes); no new AGENTS.md rules (owning files are near their size gate; rationale lives in the Agent Note).
  • Risk-bearing decisions: render-path classification changes what some tool text looks like (JSON-shaped prose now renders as code); renderer-side fix chosen over producer-side because existing recorded history already carries these blocks.
  • Destructive or irreversible behavior: none; display-only change, no storage or wire format changes.
  • Deliberately not done or tested: full monorepo test:ci (see test plan); live UI click-through; resource text case; lexeme-preserving pretty-printer (rejected as disproportionate tokenizer complexity for a display path).
  • Unknowns / confidence: high confidence in the classifier contract (unit-tested against the real payload and large-number forms); moderate confidence there is no other consumer relying on Markdown rendering of JSON text blocks.

Original user prompt

Show original prompt
我的意思就是这个,这个显示肯定不是你点开 toolcall 时所期望的
你看一下上游有没有人修这个问题

你拉一个干净的 worktree 分支来做这个修复

开一个 PR 吧

Tool calls report their raw input as a text content block holding serialized
JSON. Routing that text through the Markdown pipeline let single-$ inline math
consume shell fragments like $(...) and drop the & in 2>&1, so an expanded
tool call displayed a command that was not the command that ran. Detect JSON
payloads in StandardToolContentBlock's text case via a pure leaf-module
classifier and render them as verbatim pretty-printed code, matching the raw
tool output treatment; prose keeps the Markdown path and its math.

Model: kimi-code/k3
@tommy0103
tommy0103 marked this pull request as ready for review September 14, 2026 16:40

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f669025f6e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/components/src/lib/tool-call-json-text.ts Outdated
…xemes

Review on LodyAI#711 pointed out that the parse/stringify round trip corrupts
integers beyond 2^53 (64-bit IDs render as ...776000) and rewrites forms
like 1e10, recreating the same displayed-differs-from-actual defect on the
digits. JSON.parse now only validates; the original payload text is shown
untouched. Pretty-printing is dropped rather than replaced with a
lexeme-preserving formatter, which would hand-roll a JSON tokenizer into a
display path.

Model: kimi-code/k3
@Leeeon233
Leeeon233 merged commit 7b995b7 into LodyAI:main Sep 16, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Expanded tool call mangles raw input JSON: single-$ math eats $(...) and the & in 2>&1

2 participants