Skip to content

feat(web): show edit diffs inline in tool call cards - #1103

Merged
wbxl2000 merged 15 commits into
mainfrom
feat/web-tool-edit-diff
Jun 25, 2026
Merged

feat(web): show edit diffs inline in tool call cards#1103
wbxl2000 merged 15 commits into
mainfrom
feat/web-tool-edit-diff

Conversation

@wbxl2000

Copy link
Copy Markdown
Collaborator

Related Issue

N/A — no linked issue.

Problem

When the agent edits or writes a file in the web chat, the tool card only showed a one-line summary (e.g. "Replaced 1 occurrence(s) in path") as plain text. Users could not see what actually changed without opening the file, unlike the CLI/TUI which renders the diff inline.

What changed

Render a line-by-line diff inside Edit/Write tool cards in the web chat, reusing the existing diff-line visual style from the changes panel.

  • Extracted the shared line-by-line diff rendering into a reusable component used by both the changes panel and the tool card.
  • Build the diff client-side from the tool input, so no protocol or server changes were needed.
  • The header chip now shows the real +/- counts instead of guessing from the summary text.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

Render a line-by-line diff inside Edit/Write tool cards in the web chat, reusing the existing diff-line style from the changes panel. The diff is built client-side from the tool input, so no protocol or server changes are needed; the header chip now shows real +/- counts.
@changeset-bot

changeset-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cc92e55

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 25, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@cc92e55
npx https://pkg.pr.new/@moonshot-ai/kimi-code@cc92e55

commit: cc92e55

@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: 7a2665d66b

ℹ️ 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 on lines +196 to +199
<template v-if="editDiff">
<div v-if="editDiff.length > 0" class="bb-diff"><DiffLines :lines="editDiff" /></div>
<div v-else class="bb-empty">No changes.</div>
</template>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve failed edit/write output

When an Edit/Write call fails (for example Edit returns old_string not found), editDiff is still derived from the requested input, so this branch renders the proposed diff and suppresses tool.output. The card shows an error mark but hides the actual diagnostic, making a failed edit look like a successful change preview; gate the diff view on successful status or fall back to the output on errors.

Useful? React with 👍 / 👎.

wbxl2000 added 3 commits June 25, 2026 19:07
Diff rows were only as wide as the viewport, so the add/del background stopped where long lines overflowed and the area revealed by horizontal scroll had no color. Size each row to its content so the background paints the full line.
Size the diff container to the longest line and have every row fill it, so add/del backgrounds form one continuous band across the whole horizontal scroll instead of stopping at each line's own length.
Use Array.at(-1) and Array.from instead of index access and new Array(length), which oxlint flags as errors.
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@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: 78ff1e1f27

ℹ️ 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 on lines +196 to +197
<template v-if="editDiff">
<div v-if="editDiff.length > 0" class="bb-diff"><DiffLines :lines="editDiff" /></div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve tool output when edit/write calls fail

For failed Edit/Write calls with normal JSON args, editDiff is still truthy, so the expanded card takes this branch and never renders tool.output, which is where the actual failure reason lives (for example old_string not found or a write error). This makes an error card show the requested diff instead of why no change was applied; gate the diff view to successful calls or render the error output for tool.status === 'error'.

Useful? React with 👍 / 👎.

wbxl2000 added 2 commits June 25, 2026 19:28
# Conflicts:
#	apps/kimi-web/src/components/chat/ToolCall.vue
When an Edit/Write call fails, render the tool output (the failure reason) instead of the requested diff, so error cards explain why no change was applied.
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@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: 2e0ef1959d

ℹ️ 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 on lines +88 to +92
if (kind === 'edit') {
const before = typeof d.old_string === 'string' ? d.old_string : undefined;
const after = typeof d.new_string === 'string' ? d.new_string : undefined;
if (before === undefined || after === undefined) return null;
return buildDiffLines(before, after);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle replace_all before showing a single-edit diff

When an Edit call includes replace_all: true, the core tool replaces every occurrence and reports the actual occurrence count, but this path builds a preview from only one old_string/new_string pair and the expanded card then suppresses tool.output. In sessions where the agent intentionally replaces multiple occurrences, the web card will show a one-occurrence diff and chip counts such as +1 −1, hiding the real Replaced N occurrences... result.

Useful? React with 👍 / 👎.

Comment on lines +94 to +96
const content = typeof d.content === 'string' ? d.content : undefined;
if (content === undefined) return null;
return buildDiffLines('', content);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not render append writes as new-file diffs

For Write calls with mode: 'append', this always diffs from an empty file, so appended chunks are displayed as if they start at line 1 of a newly written file while the actual Appended ... bytes output is hidden by the diff branch. This makes append writes to existing files misleading; skip the synthetic diff for append mode or preserve the tool output in that case.

Useful? React with 👍 / 👎.

wbxl2000 added 2 commits June 25, 2026 19:45
A single-pair diff misrepresents replace_all edits (which change many occurrences) and from-empty diffs misrepresent append writes (which extend an existing file). Skip the synthetic diff in those cases and render the truthful tool output instead.
Move the Edit/Write diff out of the inline tool-card body into the shared right-side detail layer, opened by clicking the card (like the subagent detail panel). The panel shows the line diff when it faithfully represents the operation, otherwise the tool output (replace_all, append, errors), so failed calls explain why no change was applied.
@github-actions

Copy link
Copy Markdown
Contributor

❌ Nix build failed

    copying path '/nix/store/y4v5k2dj6ism3wslc8nh3xmr6b5qw4zm-libuv-1.51.0' from 'https://cache.nixos.org'...
    copying path '/nix/store/djjc508wnfdwmkv5xrxxqx5r2v09yxfp-gnumake-4.4.1' from 'https://cache.nixos.org'...
    copying path '/nix/store/fcn7j45ia0vf1x6cjbmmff725xza1l4b-libxcrypt-4.5.2' from 'https://cache.nixos.org'...
    copying path '/nix/store/xj19x5ivzayr418kv9pg5rwvp6bm404n-libyaml-0.2.5' from 'https://cache.nixos.org'...
    copying path '/nix/store/g36v1ss2ywkqp751wlkhnd8n9zaqkg2w-bzip2-1.0.8-bin' from 'https://cache.nixos.org'...
    copying path '/nix/store/mc5phzxsq1a7l15il4zam170y75k8y4v-mpdecimal-4.0.1' from 'https://cache.nixos.org'...
    copying path '/nix/store/f9zy83r51fxj1j8db10pv5ccvvakrsyd-acl-2.3.2' from 'https://cache.nixos.org'...
    copying path '/nix/store/ffyzkisqs4vc4mg28bwwlyqjf8i9ph6b-ncurses-6.5' from 'https://cache.nixos.org'...
    copying path '/nix/store/ammry9gjdzz6q1nilriax65zc75f5q4f-oniguruma-6.9.10-lib' from 'https://cache.nixos.org'...
    copying path '/nix/store/by19gg2pqp2b1gqphdf6bwk2g3hgak79-openssl-3.6.2' from 'https://cache.nixos.org'...
    copying path '/nix/store/nm1r86xxvj45gyqpxha74cddb3d28wzm-pcre2-10.46' from 'https://cache.nixos.org'...
    copying path '/nix/store/wgnxx41q3d2cx6j5wk2s5bkjyzrr3ggn-patch-2.8' from 'https://cache.nixos.org'...
    copying path '/nix/store/rhp8ph1q699irvmacp27x3sw84slk32i-gzip-1.14' from 'https://cache.nixos.org'...
    copying path '/nix/store/hz66ly95w3cz40m121v39nz9z5djyl5s-libuv-1.51.0-dev' from 'https://cache.nixos.org'...
    copying path '/nix/store/5xk1n7bw6y25szrwkjbdpppxrdchjjrq-make-shell-wrapper-hook' from 'https://cache.nixos.org'...
    copying path '/nix/store/56yrgvnlr4l5gzxk6axglw9l05lmc7ag-perl5.40.0-IO-Tty-1.20' from 'https://cache.nixos.org'...
    copying path '/nix/store/pgkgcrhsdiz08rinb4crlcykd5fj15l2-xz-5.8.3' from 'https://cache.nixos.org'...
    copying path '/nix/store/lf793zr9yfa0dpph8jlxbbdnvnahvq8b-zlib-1.3.2' from 'https://cache.nixos.org'...
    copying path '/nix/store/c1g2l2ki0rgf30amwkd2jag992qkv8qm-util-linux-minimal-2.41.4-lib' from 'https://cache.nixos.org'...
    copying path '/nix/store/xl6pd2spjajwcpq09fnmnjv5psqmlmma-gnutar-1.35' from 'https://cache.nixos.org'...
    copying path '/nix/store/39l6rhxg9qb07q3862p4zcr2s4146p1r-glibc-2.40-224-dev' from 'https://cache.nixos.org'...
    copying path '/nix/store/agj742h6zh3d5xwr1z0kd83jbf466fv3-isl-0.20' from 'https://cache.nixos.org'...
    copying path '/nix/store/sr8p0j0answrr398k1izaad3d18xafzp-jq-1.8.1' from 'https://cache.nixos.org'...
    copying path '/nix/store/xns8hyvcxcj38sn3zfqdyzjs0647g0hx-mpfr-4.2.2' from 'https://cache.nixos.org'...
    copying path '/nix/store/y9907xl81fqrp9zpng2dv5pn4il934m3-perl5.40.0-IPC-Run-20231003.0' from 'https://cache.nixos.org'...
    copying path '/nix/store/hfi7wfmjsap0l5jzjgphz4m76w3s9sm4-sqlite-3.50.4-bin' from 'https://cache.nixos.org'...
    copying path '/nix/store/p0070ky52z5qq0s7815dc93v1xh9bnd4-sqlite-3.50.4' from 'https://cache.nixos.org'...
    copying path '/nix/store/y2my9k2qqbm3ldcgflkmfp9rz2595v8c-binutils-2.44-lib' from 'https://cache.nixos.org'...
    copying path '/nix/store/018l43lbsqbrsasrfdcxxb5s4s161fkr-file-5.45' from 'https://cache.nixos.org'...
    copying path '/nix/store/wkvc3p6ih0f7v7aqchj7lmn6j816sapf-zlib-1.3.2-dev' from 'https://cache.nixos.org'...
    copying path '/nix/store/k3wiv3qqa4y0im5v1iq2jy4h9cm32dfc-gnugrep-3.12' from 'https://cache.nixos.org'...
    copying path '/nix/store/3x3p3mhwn18q7qplxn34i13rdmswi0qm-xz-5.8.3-bin' from 'https://cache.nixos.org'...
    copying path '/nix/store/dw8qxi3l3j5ip7i6kjyp9jnr4nsp63g7-gmp-with-cxx-6.3.0' from 'https://cache.nixos.org'...
    copying path '/nix/store/8im6szkvnmqd5pfkri0khy2w6scpapdy-jemalloc-5.3.0-unstable-2025-09-12' from 'https://cache.nixos.org'...
    copying path '/nix/store/8vx8avzfcpcldsipwd7iz65r7ig9p4dv-icu4c-76.1' from 'https://cache.nixos.org'...
    copying path '/nix/store/qq7kkpgsdfkq4xdgvwgdibvcqicwvd7a-jq-1.8.1-bin' from 'https://cache.nixos.org'...
    copying path '/nix/store/5mrhn7sj5hmx1sqqj1568sya450yarvx-patchelf-0.15.2' from 'https://cache.nixos.org'...
    copying path '/nix/store/9vsr9qjlcdldwjqxsvhk4khjqyikgp5f-ripgrep-15.1.0' from 'https://cache.nixos.org'...
    copying path '/nix/store/yjvlpi792ihsf7n6ciwfzb4r0avsa4wd-libmpc-1.3.1' from 'https://cache.nixos.org'...
    copying path '/nix/store/4sq0awhi6w9zw9qb08amnams96a0kwp5-zstd-1.5.7' from 'https://cache.nixos.org'...
    copying path '/nix/store/i7mdvmliqcb5lz0nqija8rq55vws6gi8-binutils-2.44' from 'https://cache.nixos.org'...
    copying path '/nix/store/3ffi89rlwcqww9x71pf95miyik5jhnv9-openssl-3.6.2-bin' from 'https://cache.nixos.org'...
    copying path '/nix/store/nq6zznmqx4fq4k88p8iplsxmka9a3v1c-jq-1.8.1-dev' from 'https://cache.nixos.org'...
    copying path '/nix/store/hqkszxk2c0cxvd04xa4gsaqs182dw8l2-coreutils-9.8' from 'https://cache.nixos.org'...
    copying path '/nix/store/7cysvl3fn6h723h5hk7vykl7kwkwvpmn-sqlite-3.50.4-dev' from 'https://cache.nixos.org'...
    copying path '/nix/store/ipr6y28viyqkhkg58rdvy27m01q5j5nh-gcc-14.3.0' from 'https://cache.nixos.org'...
    copying path '/nix/store/qap9s0ndw3bc2x54r44wbvr7m1kz69k5-zstd-1.5.7-bin' from 'https://cache.nixos.org'...
    copying path '/nix/store/2yvwl8xp707jicp5xb51ijsclhq7wc1f-fd-10.3.0' from 'https://cache.nixos.org'...
    copying path '/nix/store/cqkz127l4l98xgp7p6y1j2cqvyx0w3jl-openssl-3.6.2-dev' from 'https://cache.nixos.org'...
    copying path '/nix/store/8xhaz2ysixijy8sgzmwmhlialqqind1p-findutils-4.10.0' from 'https://cache.nixos.org'...
    copying path '/nix/store/55c9z5n6flgs7mcsw9rsy0ldnxkbxwnn-perl-5.40.0' from 'https://cache.nixos.org'...
    copying path '/nix/store/cw3a3yz8vrfsz53ypjw8hspy5hzzx2py-diffutils-3.12' from 'https://cache.nixos.org'...
    copying path '/nix/store/h3a9w4pxf9p73d0dqc3rdplahyszxl2v-zstd-1.5.7-dev' from 'https://cache.nixos.org'...
    copying path '/nix/store/brb97wgi4lld4km09dy5cnklkjr48fdq-readline-8.3p1' from 'https://cache.nixos.org'...
    copying path '/nix/store/7wlxfjp63zs4wipznx3pb11n9jiplqw6-pnpm-config-hook' from 'https://cache.nixos.org'...
    copying path '/nix/store/lfbzxs5wyqd2122mpbj5azkxhxspw9cd-bash-interactive-5.3p3' from 'https://cache.nixos.org'...
    copying path '/nix/store/sdfysgb89zdysrknjavcr0crs4qxpk8r-python3-3.13.12' from 'https://cache.nixos.org'...
    copying path '/nix/store/pvir9l70j66xb9prq9cvq313r2n2na58-stdenv-linux' from 'https://cache.nixos.org'...
    copying path '/nix/store/iz5lckcsg66r223si2gck7csk2hihj0m-binutils-wrapper-2.44' from 'https://cache.nixos.org'...
    copying path '/nix/store/8pr908sqkiw8ljbvy97w3dkzyc6gp33c-icu4c-76.1-dev' from 'https://cache.nixos.org'...
    copying path '/nix/store/chsxa1iw7s3m51v4kj43yd1nw26xvi21-nodejs-24.15.0' from 'https://cache.nixos.org'...
    warning: unable to download 'https://cache.nixos.org/nar/0a56zdfy7zv8zzq078vf759jkd5sbq096ilvg97ijqq1kdz4llyz.nar.zst': HTTP error 200 (curl error: Failure when receiving data from the peer); retrying from offset 19577335 in 284 ms (attempt 1/5)
    warning: unable to download 'https://cache.nixos.org/nar/0fsxv6h9lz2hhngn7sz9wzw00hk2cv58n6fp1imas4aqiykwczli.nar.xz': Failed sending data to the peer (55) OpenSSL SSL_read: OpenSSL/3.6.1: error:0A000126:SSL routines::unexpected eof while reading, errno 0; retrying in 273 ms (attempt 1/5)
    warning: unable to download 'https://cache.nixos.org/nar/05m4b5zaang6dbmcvrvvmim6cwkww9y8s0kwysi13zg08cms4zkn.nar.zst': HTTP error 200 (curl error: Failed sending data to the peer); retrying from offset 13411758 in 274 ms (attempt 1/5)
    warning: unable to download 'https://cache.nixos.org/nar/1y0s8hiczlnccb7028l54ld99ijd3nbnk4ygrf592dpq2zmaw3ys.nar.xz': HTTP error 200 (curl error: Failed sending data to the peer); retrying from offset 15313866 in 306 ms (attempt 1/5)
    error: unable to download 'https://cache.nixos.org/nar/05m4b5zaang6dbmcvrvvmim6cwkww9y8s0kwysi13zg08cms4zkn.nar.zst': HTTP error 416
    error: path '/nix/store/55c9z5n6flgs7mcsw9rsy0ldnxkbxwnn-perl-5.40.0' is required, but there is no substituter that can build it
    error: some references of path '/nix/store/329mivmib3802jlxh28x068s5w12l814-perl-5.40.0-env' could not be realised
    error: some references of path '/nix/store/l0qhyid5kagg1b8zss8im3brp6xmbj8s-moreutils-0.70' could not be realised
    error: some substitutes for the outputs of derivation '/nix/store/8wcxyj7szvj1axq6gcz86hi47pjzixcd-moreutils-0.70.drv' failed (usually happens due to networking issues); try '--fallback' to build derivation from source
    error: Cannot build '/nix/store/1r9is59c0ij269q4kxr76bz10ym4j3bg-kimi-code-pnpm-deps.drv'.
           Reason: 1 dependency failed.
           Output paths:
             /nix/store/ja3xrfdhzbjkwybq24ds5bxd5j4h1akz-kimi-code-pnpm-deps
    error: Build failed due to failed dependency
    error: Cannot build '/nix/store/sqln0hr247i2x7r792wmvpc4prkzbi1v-kimi-code-0.19.2.drv'.
           Reason: 1 dependency failed.
           Output paths:
             /nix/store/97rrg191r2i9k4f69mkciznw44wl7g3n-kimi-code-0.19.2
    error: Build failed due to failed dependency

…again

Clicking the same Edit/Write card, file link, or git-status area a second time now collapses the right-side detail panel, matching the existing thinking / compaction / subagent toggle behavior.
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@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: b23ebdb5af

ℹ️ 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".

return;
}
detailTarget.value = 'toolDiff';
toolDiffTarget.value = target;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep open tool diffs tied to live tool state

When an Edit/Write card is opened before the tool finishes, this stores the current payload as a snapshot, so later status/output changes from the same tool call are not reflected in the already-open panel. In that scenario append/replace_all calls stay on “No diff”, and a tool that later errors can continue showing the attempted diff instead of the failure output until the user closes and reopens it; keep only the live tool id/lookup or refresh the stored target when the tool updates.

Useful? React with 👍 / 👎.

const m = newLines.length;
if (n === 0 && m === 0) return [];

const dp: number[][] = Array.from({ length: n + 1 }, () => Array.from({ length: m + 1 }, () => 0));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Cap client-side LCS for large edit payloads

Rendering an Edit card now computes chip() from editDiff, which calls this LCS builder even before the user opens the panel. For an Edit that replaces a large block or whole generated file, this allocates an (oldLines + 1) * (newLines + 1) matrix (for example, 5k changed lines is 25M cells) and can freeze or exhaust the web chat/history view; add a line/size cap or use a cheaper diff/fallback for large inputs.

Useful? React with 👍 / 👎.

wbxl2000 added 2 commits June 25, 2026 21:53
The line-level LCS allocates an (oldLines+1) x (newLines+1) matrix and runs eagerly when an Edit/Write card renders. For large edits (e.g. a 5k x 5k block, ~25M cells) this can freeze or exhaust the chat. Cap the matrix at 1M cells and fall back to the raw tool output beyond that.
Store only the tool id and re-derive the diff panel payload from the live tool call in the session turns, so a panel opened while the tool is still running reflects later status/output changes (e.g. an eventual error shows the failure output instead of the stale attempted diff).
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@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: 5950c7c9bf

ℹ️ 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 apps/kimi-web/src/lib/toolDiff.ts Outdated
if (d.mode === 'append') return null;
const content = typeof d.content === 'string' ? d.content : undefined;
if (content === undefined) return null;
return buildDiffLines('', content);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid treating Write overwrites as new-file diffs

When a Write call targets an existing file, the tool defaults to overwrite mode, but this builds the preview from an empty before-state, so the card/panel reports every resulting line as added and no removed lines. In the common complete-replacement case the +/- chip and diff are therefore materially inaccurate; if the client cannot know the previous contents, fall back to the tool output for Write overwrites unless the operation is known to be a new file.

Useful? React with 👍 / 👎.

Write only reports the new content, so the client cannot tell a new file from an overwrite of an existing one. A from-empty diff showed overwrites as all additions and no deletions, which is misleading. Fall back to the tool output for every Write (append already did).
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@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: c66ad2179f

ℹ️ 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".

const n = oldLines.length;
const m = newLines.length;
if (n === 0 && m === 0) return [];
if ((n + 1) * (m + 1) > MAX_DIFF_CELLS) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Cap diff rows as well as LCS cells

When an Edit replaces a short old_string with a very large new_string (for example one line to hundreds of thousands of lines), this product check still passes, so buildDiffLines constructs a huge row array; ToolCall computes that diff just to render the chip, so the chat can freeze before the user even opens the panel. Add a total old/new line or output-row cap in addition to the matrix-size cap.

Useful? React with 👍 / 👎.

The matrix-size cap alone let through asymmetric edits (e.g. one line replaced by hundreds of thousands) whose small matrix still produced a huge row array that the chip computed on render. Cap each side's line count too, so the diff output is bounded.
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@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: 0975c95194

ℹ️ 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 on lines +35 to +37
if (isEditWrite.value) {
emit('openToolDiff', props.tool.id);
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve expansion when no diff panel handler exists

When an Edit/Write tool card is rendered inside SideChatPanel, the nested ChatPane is not wired with @open-tool-diff (checked apps/kimi-web/src/components/chat/SideChatPanel.vue, where the ChatPane only receives turns/approvals/running/sending). This early return therefore makes those BTW side-chat cards do nothing on click, so users can no longer expand the card to see the tool output or error; only the main conversation path handles the new event.

Useful? React with 👍 / 👎.

…ired

Clicking an Edit/Write card opens the right-side diff panel, but the nested ChatPane in the side chat does not wire that event, so the click became a no-op and the card could no longer expand to show its output. Gate the panel behavior behind a toolDiffPanel prop (enabled only in the main conversation); elsewhere the cards expand inline as before.
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@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: 6ae9e0d65a

ℹ️ 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".

if (detailTarget.value === 'thinking' && thinkingVisible.value) { closeThinkingPanel(); return true; }
if (detailTarget.value === 'compaction' && compactionPanelVisible.value) { closeCompactionPanel(); return true; }
if (detailTarget.value === 'agent' && agentPanelVisible.value) { closeAgentPanel(); return true; }
if (detailTarget.value === 'toolDiff' && toolDiffVisible.value) { closeToolDiff(); return true; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate the tool diff panel on a live target

The new toolDiffVisible is only used here, but sidePanelVisible does not gate detailTarget === 'toolDiff' on it. In a same-session resync (the WebSocket resync path replaces messagesBySession[sessionId] from a fresh snapshot), an opened diff for a tool call that is no longer in the latest snapshot makes toolDiffTarget null while detailTarget stays 'toolDiff'; the aside remains open with no ToolDiffPanel/close button, and this Escape branch refuses to close it because toolDiffVisible is false. Please either include the tool-diff visibility check in sidePanelVisible or clear the tool-diff target when it disappears.

Useful? React with 👍 / 👎.

When a session resync removes the tool call an open diff panel is showing, toolDiffTarget becomes null but detailTarget stayed 'toolDiff', leaving an empty aside that Escape would not close. Gate sidePanelVisible on toolDiffVisible so the panel collapses once its target is gone.
@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@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: cc92e55b89

ℹ️ 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 on lines +25 to +28
const lines = s.split('\n');
// A trailing newline produces a trailing empty element that is not a real
// content line — drop exactly one of them.
if (lines.at(-1) === '') lines.pop();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve terminal newline-only edits

When an Edit changes only the final newline, dropping the trailing empty split entry makes the old and new line arrays identical (for example old_string: "a", new_string: "a\n"). The new tool diff panel then renders only context and the +/- chip reports no change, even though the file content did change; keep enough information to show EOF-newline additions/removals or a no-newline marker.

Useful? React with 👍 / 👎.

@wbxl2000
wbxl2000 merged commit 18f7c34 into main Jun 25, 2026
8 checks passed
@wbxl2000
wbxl2000 deleted the feat/web-tool-edit-diff branch June 25, 2026 15:18
@github-actions github-actions Bot mentioned this pull request Jun 25, 2026
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