mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 23:47:54 +08:00
core/tools: mark only displayed lines read on truncated read_file
read_file(with_lineno=true) marked the whole requested slice before applying the max_chars cap, so a truncated read silently unlocked every line of the file for edit_lineno even though the model never saw them. Mark only the complete numbered lines actually returned (excluding the [Truncated] marker); the unseen tail stays unread.
This commit is contained in:
@@ -83,14 +83,10 @@ async def read_file(
|
|||||||
if start >= len(lines):
|
if start >= len(lines):
|
||||||
return ""
|
return ""
|
||||||
slice_lines = lines[start:end]
|
slice_lines = lines[start:end]
|
||||||
if with_lineno:
|
body = _format_with_lineno(slice_lines, start_lineno=start + 1) if with_lineno else "".join(slice_lines)
|
||||||
mark_lineno_read(str(target), set(range(start + 1, end + 1)))
|
|
||||||
body = _format_with_lineno(slice_lines, start_lineno=start + 1)
|
|
||||||
else:
|
|
||||||
body = "".join(slice_lines)
|
|
||||||
if max_chars >= 1:
|
if max_chars >= 1:
|
||||||
char_start = len("".join(lines[:start]))
|
char_start = len("".join(lines[:start]))
|
||||||
body, _ = truncate_with_token(
|
body, token = truncate_with_token(
|
||||||
body,
|
body,
|
||||||
max_chars,
|
max_chars,
|
||||||
kind="file",
|
kind="file",
|
||||||
@@ -102,10 +98,21 @@ async def read_file(
|
|||||||
# returned slice itself was cut by max_chars (not just "file continues").
|
# returned slice itself was cut by max_chars (not just "file continues").
|
||||||
emit_more_after=False,
|
emit_more_after=False,
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
token = None
|
||||||
if not body:
|
if not body:
|
||||||
return ""
|
return ""
|
||||||
if with_lineno:
|
if with_lineno:
|
||||||
return body # per-line numbers already show the range
|
# Mark only the lines actually displayed: complete numbered lines in the
|
||||||
|
# returned body (the [Truncated] marker, when present, is not a file line).
|
||||||
|
# The max_chars-truncated tail was never shown, so it stays unread —
|
||||||
|
# edit_lineno must not trust line numbers the model never saw.
|
||||||
|
counted = body
|
||||||
|
if token is not None:
|
||||||
|
counted = body.split("\n[Truncated", 1)[0]
|
||||||
|
shown = counted.count("\n")
|
||||||
|
mark_lineno_read(str(target), set(range(start + 1, start + 1 + shown)))
|
||||||
|
return body
|
||||||
begin = start + 1
|
begin = start + 1
|
||||||
end_line = start + len(slice_lines)
|
end_line = start + len(slice_lines)
|
||||||
return f"L{begin}-{end_line}\n{body}"
|
return f"L{begin}-{end_line}\n{body}"
|
||||||
|
|||||||
@@ -22,6 +22,22 @@ def test_edit_lineno_replace_middle(workspace: object) -> None:
|
|||||||
assert call_sync(read_file, "a.txt") == "L1-4\none\nTWO\nTHREE\nfour\n"
|
assert call_sync(read_file, "a.txt") == "L1-4\none\nTWO\nTHREE\nfour\n"
|
||||||
|
|
||||||
|
|
||||||
|
def test_edit_lineno_read_truncated_marks_only_displayed_lines(workspace: object) -> None:
|
||||||
|
"""A max_chars-truncated numbered read must not mark the unseen tail."""
|
||||||
|
del workspace
|
||||||
|
_ = call_sync(write_file, "t.txt", "".join(f"line {i}\n" for i in range(1, 101)))
|
||||||
|
# Displayed complete lines are editable...
|
||||||
|
_ = reset_lineno_tracker()
|
||||||
|
_ = call_sync(read_file, "t.txt", with_lineno=True, max_chars=80)
|
||||||
|
out = call_sync(edit_lineno, "t.txt", 5, 5, "FIVE\n")
|
||||||
|
assert "replaced lines 5-5" in out
|
||||||
|
# ...but the truncated tail (never shown) stays unread.
|
||||||
|
_ = reset_lineno_tracker()
|
||||||
|
_ = call_sync(read_file, "t.txt", with_lineno=True, max_chars=80)
|
||||||
|
out = call_sync(edit_lineno, "t.txt", 90, 90, "X\n")
|
||||||
|
assert "not read" in out and "90" in out
|
||||||
|
|
||||||
|
|
||||||
def test_edit_lineno_requires_all_lines_read(workspace: object) -> None:
|
def test_edit_lineno_requires_all_lines_read(workspace: object) -> None:
|
||||||
del workspace
|
del workspace
|
||||||
_ = call_sync(write_file, "r.txt", "a\nb\nc\nd\ne\n")
|
_ = call_sync(write_file, "r.txt", "a\nb\nc\nd\ne\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user