Skip to content

[Bug]: TUI drops changed lines that start with a diff marker from its +N -M counter #2829

Description

@lihongyuan99

Prerequisites

  • I have searched the existing issues and discussions, and this is not a duplicate.
  • This is a bug, not a usage question. (For questions, please use Discussions instead.)

Background / Description

Edit and Write record the change they made as a unified diff in the tool result's metadata["diff"], and the TUI turns that diff into the +added -removed counter shown on a tool row and on a tool group (tui/_messages.py:384 and tui/_messages.py:441).

_diff_stats (tui/_messages.py:298) excludes the diff's file headers by prefix-testing every line:

if line.startswith("+") and not line.startswith("+++"):
    insertions += 1
elif line.startswith("-") and not line.startswith("---"):
    deletions += 1

But difflib.unified_diff — which is what both tools call (_edit.py:405, _write.py likewise) — writes the --- a/<path> / +++ b/<path> pair as its first two lines only. Any changed line whose own text starts with the marker collides with that test and silently disappears from the count:

  • removing a Markdown or YAML --- rule emits ----, which is dropped;
  • removing a line that is itself -- something (a shell or SQL comment, a diff printed inside a document) emits --- something, which is dropped;
  • adding a C/JS line such as ++counter; emits +++counter;, which is dropped.

So an edit whose whole change is one --- line becoming ++counter; — routine when an agent touches front matter, a document separator, or a counter — is reported as +0 -0. The group summary is worse: it adds the per-call counts and then guards on if added or removed: (tui/_messages.py:449), so when every changed line is swallowed it drops the +N -M section entirely, as if the group had made no changes at all.

Content lines are prefixed with a space, and a hunk header starts with @, so they were never the reason for the exclusion. The only lines that need excluding are the leading pair.

This also disagrees with how the same quantity is produced elsewhere in the repo: app/_service/_workspace.py:561 takes insertions and deletions from git diff --shortstat, i.e. from the tool that generated the diff, rather than from a prefix heuristic applied afterwards.

I have a fix ready: treat only the leading --- / +++ pair as headers and count every other +/- line. Two tests, one pinning the plain case so the header pair is still excluded once.

Error Messages

No exception is raised; the reported behavior is a wrong count. Reproduction output on main:

diff the Edit tool records:
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
----
+++counter;

_diff_stats -> (0, 0)  expected (1, 1)

real Edit metadata diff:
--- a/<tmp>/README.md
+++ b/<tmp>/README.md
@@ -1 +1 @@
----
+++counter;

_diff_stats -> (0, 0)

Steps to Reproduce

No network access and no API keys required.

  1. Code:
import asyncio
import difflib
import os
import tempfile

from agentscope.tool import Edit
from agentscope.tui._messages import _diff_stats


async def main() -> None:
    path = os.path.join(tempfile.mkdtemp(), "README.md")

    # What the producer emits, and what the counter makes of it.
    demo = "".join(
        difflib.unified_diff(
            ["---\n"],
            ["++counter;\n"],
            fromfile="a/README.md",
            tofile="b/README.md",
            n=3,
        ),
    )
    print("diff the Edit tool records:")
    print(demo)
    print("_diff_stats ->", _diff_stats(demo), " expected (1, 1)\n")

    with open(path, "w", encoding="utf-8") as f:
        f.write("---\n")
    chunk = await Edit()(
        file_path=path,
        old_string="---",
        new_string="++counter;",
    )
    print("real Edit metadata diff:")
    print(chunk.metadata["diff"])
    print("_diff_stats ->", _diff_stats(chunk.metadata["diff"]))


asyncio.run(main())
  1. Run: python repro.py on main at 2c885b5
  2. See: both counts are (0, 0) although the diff contains exactly one added and one removed line.

Environment

  • AgentScope Version: 2.0.8 (main @ 2c885b5)
  • Python Version: 3.12.12 (agentscope[tui] installed)
  • OS: macOS 15.6 (arm64) — pure string handling, reproduces identically on Linux and Windows

Activity

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

Metadata

Metadata

Assignees

Labels

triage/confirmedVerified: the reported defect exists

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions