feat(file_tools): write_file says when it just re-sent a large file that was already on disk

In the 1,393-agent refactor run write_file carried 92.8M chars of content
(23.2M output tokens, ~$580, 20% of all output tokens). 661 of those calls
were read -> whole-file rewrite of an existing file >20k chars (24.9M
chars, ~$155): 130k-char agent/model_metadata.py, 109k
model_setup_flows.py, 107k google_chat/adapter.py, re-sent in full to
change a few lines. Meanwhile patch succeeded 4,602/4,617 (99.7%) at 1.3k
chars per call. The tool result is the only place the model reads, so the
cost signal goes there.

When an overwrite targets an existing file and both old and new content
are >=20k chars, write_file diffs them by line (difflib, autojunk off)
and, if >=80% of lines are unchanged, adds a `hint` naming the unchanged
count, the changed count, the size, and "use patch". The write itself is
unchanged and still happens; new files, small files and genuine rewrites
get no hint. 300 ms on the 119k-char model_metadata.py.

Tests (2): a 40k-char file with 2 lines changed gets the hint and is
written; a new file, a small file and a wholly rewritten file get none.
This commit is contained in:
Teknium
2026-09-05 02:01:04 -07:00
parent f58fcc8118
commit a1ffb27ef8
2 changed files with 71 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
"""write_file tells the caller when it just re-sent a large file that was already on disk.
In one 1,393-agent run 661 read->whole-file-rewrites of >20k-char files cost ~25M output chars (~$155)
while `patch` (1.3k chars/call) succeeded 99.7% of the time; the tool result is the only place to say so.
"""
import json
from tools.file_tools import write_file_tool
def _big(n_lines=800):
return "\n".join(f"line {i}: " + "x" * 40 for i in range(n_lines)) + "\n" # ~40k chars
def test_rewrite_of_a_large_file_with_few_changes_gets_a_patch_hint(tmp_path):
f = tmp_path / "mod.py"
old = _big()
f.write_text(old, encoding="utf-8")
new = old.replace("line 400:", "line 400 (edited):").replace("line 401:", "line 401 (edited):")
r = json.loads(write_file_tool(str(f), new, task_id="t"))
assert r.get("error") is None and f.read_text(encoding="utf-8") == new # the write still happens
assert "use patch" in r["hint"] and "798 of 800 lines were already on disk" in r["hint"]
def test_new_files_small_files_and_real_rewrites_get_no_hint(tmp_path):
new_file = tmp_path / "new.py"
assert "hint" not in json.loads(write_file_tool(str(new_file), _big(), task_id="t"))
small = tmp_path / "small.py"
small.write_text("a\nb\n", encoding="utf-8")
assert "hint" not in json.loads(write_file_tool(str(small), "a\nc\n", task_id="t"))
big = tmp_path / "big.py"
big.write_text(_big(), encoding="utf-8")
rewritten = "\n".join(f"other {i}: " + "y" * 40 for i in range(800)) + "\n"
assert "hint" not in json.loads(write_file_tool(str(big), rewritten, task_id="t"))

View File

@@ -709,6 +709,40 @@ def _note_edited(task_id: str, paths: list[str], path_to_resolved: dict, session
file_state.note_write(task_id, path_to_resolved[p])
# Whole-file rewrite hint: an overwrite of an existing file this large whose new content keeps at least
# this fraction of the old lines is a patch written the expensive way. In one 1,393-agent run 661 such
# rewrites of >20k-char files cost ~25M output chars (~$155) where `patch` averaged 1.3k chars/call.
_REWRITE_HINT_MIN_CHARS = 20_000
_REWRITE_HINT_MIN_UNCHANGED = 0.80
def _whole_file_rewrite_hint(resolved: str | None, new_content: str) -> str | None:
"""Return a hint when ``new_content`` mostly re-sends what is already on disk at ``resolved``."""
if not resolved or len(new_content) < _REWRITE_HINT_MIN_CHARS:
return None
try:
old = Path(resolved).read_text(encoding="utf-8", errors="replace")
except OSError:
return None
if len(old) < _REWRITE_HINT_MIN_CHARS:
return None
old_lines, new_lines = old.splitlines(), new_content.splitlines()
if not old_lines:
return None
import difflib
matcher = difflib.SequenceMatcher(None, old_lines, new_lines, autojunk=False)
unchanged = sum(size for _, _, size in matcher.get_matching_blocks())
ratio = unchanged / max(len(old_lines), len(new_lines))
if ratio < _REWRITE_HINT_MIN_UNCHANGED:
return None
changed = max(len(old_lines), len(new_lines)) - unchanged
return (
f"{unchanged:,} of {len(new_lines):,} lines were already on disk ({ratio:.0%} unchanged); ~{changed:,} "
f"line(s) actually changed. Re-sending a {len(new_content):,}-char file costs output tokens for every "
"unchanged line; for edits like this use patch (old_string/new_string), which sends only the changed region."
)
def write_file_tool(path: str, content: str, task_id: str = "default",
cross_profile: bool = False,
session_id: str | None = None) -> str:
@@ -741,9 +775,12 @@ def write_file_tool(path: str, content: str, task_id: str = "default",
# subagents; different paths stay fully parallel.
_lock.enter_context(file_state.lock_path(_resolved))
warnings = _edit_warnings([path], path_to_resolved, task_id)
rewrite_hint = _whole_file_rewrite_hint(_resolved, content)
result_dict = _get_file_ops(task_id).write_file(_resolved or path, content).to_dict()
if warnings:
result_dict["_warning"] = warnings[0]
if rewrite_hint and not result_dict.get("error"):
result_dict["hint"] = rewrite_hint
if _resolved:
# Always report the ABSOLUTE path written so a wrong-cwd mismatch
# is visible in the response instead of silently landing elsewhere.