Skip to content

feat: shared tool metadata with diff rendering for Claude and Codex#16

Merged
tyql688 merged 10 commits intomasterfrom
feat/shared-tool-metadata
Apr 11, 2026
Merged

feat: shared tool metadata with diff rendering for Claude and Codex#16
tyql688 merged 10 commits intomasterfrom
feat/shared-tool-metadata

Conversation

@tyql688
Copy link
Copy Markdown
Owner

@tyql688 tyql688 commented Apr 11, 2026

Summary

  • Introduce shared tool metadata so Claude and Codex tool calls render with canonical names, structured displays, and line-level diffs in both the timeline and HTML/Markdown exports
  • Harden path handling in diffs, dedupe Claude edit entries, and preserve Claude tool names / task status labels
  • Hide usage-only assistant placeholders (messages carrying only token usage) from the rendered timeline and exports

Test plan

  • cd src-tauri && cargo test
  • cd src-tauri && cargo clippy
  • npm test
  • npx tsc --noEmit
  • Manual: open a Claude + Codex session, verify tool diffs render correctly and empty usage-only turns are hidden

tyql688 added 10 commits April 11, 2026 11:52
Claude Code 2.1 transcripts now include task, skill, web, MCP, and structured toolUseResult payloads that were only partially visible through raw tool text. Add a provider-neutral metadata builder so Claude can be the first adapter without forcing future providers to depend on Claude-specific parsing.

Constraint: Preserve existing Message tool_name/tool_input/content compatibility for all providers.\nConstraint: Provider parsers keep raw transcript pairing logic; shared metadata only normalizes already-extracted tool facts.\nRejected: Keep metadata helpers inside Claude parser | would make future provider support duplicate or depend on Claude internals.\nRejected: Replace tool_name/content with typed tool events | too broad and risky for existing provider/UI compatibility.\nConfidence: high\nScope-risk: moderate\nDirective: New provider tool support should feed ToolCallFacts/ToolResultFacts instead of copying Claude metadata logic.\nTested: npm test\nTested: npx tsc --noEmit\nTested: npm run lint\nTested: npm run format:check\nTested: cd src-tauri && cargo test\nTested: cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings\nTested: cd src-tauri && cargo fmt --check\nTested: git diff --check
Edit tool cards were showing oldString and newString as two large red/green blocks, making small changes look like whole-file rewrites. Use jsdiff to build compact line-level diff rows for tool card rendering while keeping backend metadata unchanged.

Constraint: Keep diff generation in the frontend because it is presentation-only and based on already delivered old/new strings.\nRejected: Use a full diff viewer such as diff2html | too heavy for compact message tool cards and harder to integrate with Solid styling.\nConfidence: high\nScope-risk: narrow\nDirective: Preserve old/new strings in ToolDetail; renderers may choose richer views without changing parser contracts.\nTested: npm test\nTested: npx tsc --noEmit\nTested: npm run lint\nTested: npm run format:check\nTested: cd src-tauri && cargo test\nTested: cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings\nTested: cd src-tauri && cargo fmt --check\nTested: git diff --check
Codex transcripts already pair function/custom tool calls by call_id, but the provider was only populating legacy tool_name/tool_input/content fields. Feed Codex call and output facts into the shared metadata builder so exec_command, apply_patch, update_plan, request_user_input, write_stdin, Agent, and MCP tools get the same structured display path as Claude.

Constraint: Keep Codex provider responsible for transcript-specific call_id pairing and output extraction.\nRejected: Leave Codex on legacy fallback | current project session uses many Codex tools and would not benefit from the new tool display model.\nRejected: Revive map_codex_tool_name in parallel | duplicate canonical mapping belongs in shared tool_metadata.\nConfidence: high\nScope-risk: moderate\nDirective: Future Codex tool aliases should be added to shared canonical_tool_name/input_summary, not a provider-local display mapper.\nTested: npm test\nTested: npx tsc --noEmit\nTested: npm run lint\nTested: npm run format:check\nTested: cd src-tauri && cargo test\nTested: cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings\nTested: cd src-tauri && cargo fmt --check\nTested: git diff --check
Codex records apply_patch as patch text rather than Claude-style oldString/newString pairs, so the line diff renderer still fell back to raw patch text. Parse apply_patch hunks into the same compact diff row model used by Edit cards.

Constraint: Codex apply_patch inputs are patch text embedded in custom_tool_call input.\nRejected: Convert patches to synthetic old/new strings | hunk headers and multi-file patches lose important context.\nConfidence: high\nScope-risk: narrow\nDirective: Keep patch parsing presentation-only; provider metadata should continue to expose raw patch text.\nTested: npm test\nTested: npx tsc --noEmit\nTested: npm run lint\nTested: npm run format:check\nTested: cd src-tauri && cargo test\nTested: cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings\nTested: cd src-tauri && cargo fmt --check\nTested: git diff --check
HTML export still rendered Edit oldString/newString and Codex apply_patch as large raw red/green blocks. Use the Rust similar crate for exported old/new line diffs and render patch hunks with the same compact diff classes used by tool cards.

Constraint: HTML export runs in Rust, so it cannot reuse the frontend jsdiff package directly.\nRejected: Keep hand-written old/new comparison | fails common insert/delete alignment and duplicates the ugly block behavior.\nRejected: Use diff2html in export | JS/CSS renderer is too heavy for the Rust static exporter path.\nConfidence: high\nScope-risk: narrow\nDirective: Keep exporter diff classes aligned with the in-app compact diff styles when changing tool rendering.\nTested: cd src-tauri && cargo test test_render_tool_detail_golden\nTested: npm test\nTested: npx tsc --noEmit\nTested: npm run lint\nTested: npm run format:check\nTested: cd src-tauri && cargo test\nTested: cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings\nTested: cd src-tauri && cargo fmt --check\nTested: git diff --check
Claude Edit messages can contain the same old/new data in both tool input and structured toolUseResult metadata. Rendering both produced duplicate diff blocks in the expanded tool card, so prefer the structured result diff when present and suppress the redundant input diff/raw output.

Constraint: Codex apply_patch still needs input patch rendering because it does not carry Claude-style old/new result metadata.\nRejected: Drop input detail for all tools with metadata | would hide useful command and query inputs for non-diff tools.\nConfidence: high\nScope-risk: narrow\nTested: npm test\nTested: npx tsc --noEmit\nTested: npm run lint\nTested: npm run format:check\nTested: cd src-tauri && cargo test\nTested: cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings\nTested: cd src-tauri && cargo fmt --check\nTested: git diff --check
The app tool cards now render from Message.tool_metadata, but HTML export still used a legacy tool_name/tool_input-only renderer. Move export tool rendering into a metadata-aware Rust module so exported sessions show the same structured summaries, MCP labels, file diffs, Codex patch diffs, and duplicate-output suppression.

Constraint: HTML export is static Rust output and cannot reuse Solid components or TypeScript tool helpers.\nRejected: Keep extending html.rs directly | the exporter needs a dedicated tool renderer to stay aligned with the app without bloating the session renderer.\nRejected: Only patch Edit diffs | would still leave MCP/task/structured result exports behind the app UI.\nConfidence: high\nScope-risk: moderate\nDirective: Future tool display changes should update both src/lib/tools.ts and exporter/tool_html.rs, or move shared semantics into Message.tool_metadata.\nTested: cd src-tauri && cargo test test_render_session_html_uses_tool_metadata\nTested: cd src-tauri && cargo test test_render_tool_detail_golden\nTested: npm test\nTested: npx tsc --noEmit\nTested: npm run lint\nTested: npm run format:check\nTested: cd src-tauri && cargo test\nTested: cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings\nTested: cd src-tauri && cargo fmt --check\nTested: git diff --check
Tool displays need to hide local home directories consistently while preserving the structured diff data used by Claude and Codex renderers. The change routes frontend path display through shortenHomePath and backend/export path display through shorten_home_path, including embedded patch headers, instead of maintaining parallel tool-specific path helpers.

Constraint: Tool result paths must remain usable for filesystem reads; only display/export strings are redacted.

Rejected: Keep separate compact tool path helpers | introduced inconsistent ~/… abbreviations and duplicated privacy logic.

Rejected: Redact only final HTML output | does not protect live frontend tool rows or patch header text.

Confidence: high

Scope-risk: moderate

Directive: Do not add new tool-specific path redaction helpers; extend shortenHomePath/shorten_home_path instead.

Tested: npm test

Tested: npx tsc --noEmit

Tested: npm run lint

Tested: npm run format:check

Tested: cargo test

Tested: cargo clippy --all-targets --all-features -- -D warnings

Tested: cargo fmt --check

Tested: git diff --check
Claude transcripts can reuse the same message id and request id across separate assistant chunks, so id-only deduping skipped later tool_use entries and left matching results displayed as raw toolu identifiers. The parser now dedups on message content too and caches early tool results until their tool_use arrives.\n\nTaskUpdate metadata can also include nested statusChange objects, so UI and HTML export now format object values as readable field summaries instead of object stringification.\n\nConstraint: Claude logs can emit tool_result before the matching tool_use while also reusing assistant message ids across chunks\nRejected: Disable assistant deduplication entirely | risks replaying duplicate assistant chunks in normal transcripts\nConfidence: high\nScope-risk: moderate\nTested: npm test; npx tsc --noEmit; npm run lint; npm run format:check; cd src-tauri && cargo test; cargo clippy --all-targets --all-features -- -D warnings; cargo fmt --check; git diff --check
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@tyql688 tyql688 merged commit 3492239 into master Apr 11, 2026
3 checks passed
@tyql688 tyql688 deleted the feat/shared-tool-metadata branch April 11, 2026 15:01
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.

1 participant