mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-09 13:21:42 +00:00
tui_gateway: send full unified diff (diff_unified) on file-edit tool.complete
This commit is contained in:
parent
84cbf5c1f3
commit
f76df0688c
2 changed files with 77 additions and 1 deletions
|
|
@ -219,6 +219,44 @@ def test_tui_verbose_tool_events_omit_details_when_redaction_fails(monkeypatch):
|
|||
assert "result_text" not in events[1][2]
|
||||
|
||||
|
||||
def test_tool_complete_emits_full_unified_diff(monkeypatch):
|
||||
events: list[tuple[str, str, dict]] = []
|
||||
monkeypatch.setattr(
|
||||
server, "_emit", lambda event_type, sid, payload: events.append((event_type, sid, payload))
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
server._sessions,
|
||||
"diff-test",
|
||||
{"tool_progress_mode": "concise", "tool_started_at": {}, "edit_snapshots": {}},
|
||||
)
|
||||
|
||||
diff = "--- a/x.py\n+++ b/x.py\n@@ -1 +1 @@\n-a = 1\n+a = 2\n"
|
||||
result = json.dumps({"success": True, "diff": diff})
|
||||
server._on_tool_complete("diff-test", "tool-1", "patch", {"mode": "replace", "path": "x.py"}, result)
|
||||
|
||||
assert events and events[0][0] == "tool.complete"
|
||||
payload = events[0][2]
|
||||
# the raw unified diff rides alongside the pretty/capped inline_diff
|
||||
assert payload["diff_unified"] == diff
|
||||
assert "inline_diff" in payload
|
||||
|
||||
|
||||
def test_cap_diff_unified_truncates_at_line_boundary():
|
||||
line = "+" + "x" * 63 # 64 bytes per line incl. newline
|
||||
diff = "\n".join([line] * 100)
|
||||
|
||||
capped = server._cap_diff_unified(diff, max_bytes=1000)
|
||||
|
||||
body, _, marker = capped.rpartition("\n")
|
||||
assert marker.startswith("# … diff truncated (")
|
||||
assert marker.endswith(" more bytes)")
|
||||
assert len(body.encode("utf-8")) <= 1000
|
||||
# cut on a line boundary: every surviving line is intact
|
||||
assert all(l == line for l in body.split("\n"))
|
||||
# under the cap → untouched
|
||||
assert server._cap_diff_unified("small", max_bytes=1000) == "small"
|
||||
|
||||
|
||||
def test_dispatch_rejects_non_object_request():
|
||||
resp = server.dispatch([])
|
||||
|
||||
|
|
|
|||
|
|
@ -1950,6 +1950,28 @@ def _cap_tui_verbose_text(text: str) -> str:
|
|||
return f"{label}{tail}"
|
||||
|
||||
|
||||
# The FULL raw unified diff shipped on file-edit tool.complete (`diff_unified`,
|
||||
# for clients with a native diff renderer — ui-opentui). Unlike the verbose
|
||||
# trail above this is rendered COLLAPSED by default and only on edit tools, so
|
||||
# it gets a far larger budget; 512KB is still a hard ceiling so a runaway
|
||||
# multi-megabyte edit can't flood the pipe.
|
||||
_DIFF_UNIFIED_MAX_BYTES = 512 * 1024
|
||||
|
||||
|
||||
def _cap_diff_unified(diff: str, max_bytes: int = _DIFF_UNIFIED_MAX_BYTES) -> str:
|
||||
raw = diff.encode("utf-8")
|
||||
if len(raw) <= max_bytes:
|
||||
return diff
|
||||
head = raw[:max_bytes].decode("utf-8", errors="ignore")
|
||||
# Truncate at a line boundary so the surviving diff stays parseable, then
|
||||
# append an honest marker line (never send more than the cap + marker).
|
||||
cut = head.rfind("\n")
|
||||
if cut > 0:
|
||||
head = head[:cut]
|
||||
omitted = len(raw) - len(head.encode("utf-8"))
|
||||
return f"{head}\n# … diff truncated ({omitted} more bytes)"
|
||||
|
||||
|
||||
def _redact_tui_verbose_text(text: str) -> str:
|
||||
try:
|
||||
from agent.redact import redact_sensitive_text
|
||||
|
|
@ -2096,7 +2118,23 @@ def _on_tool_complete(sid: str, tool_call_id: str, name: str, args: dict, result
|
|||
payload["inline_diff"] = "\n".join(rendered)
|
||||
except Exception:
|
||||
pass
|
||||
if _tool_progress_enabled(sid) or payload.get("inline_diff"):
|
||||
# Alongside the pretty-rendered/capped `inline_diff` (Ink consumes that), ship
|
||||
# the RAW unified diff for clients with a native diff renderer (ui-opentui's
|
||||
# file-tool view). Capped at _DIFF_UNIFIED_MAX_BYTES with an honest marker.
|
||||
try:
|
||||
from agent.display import extract_edit_diff
|
||||
|
||||
diff_unified = extract_edit_diff(
|
||||
name,
|
||||
result,
|
||||
function_args=args,
|
||||
snapshot=snapshot,
|
||||
)
|
||||
if diff_unified:
|
||||
payload["diff_unified"] = _cap_diff_unified(diff_unified)
|
||||
except Exception:
|
||||
pass
|
||||
if _tool_progress_enabled(sid) or payload.get("inline_diff") or payload.get("diff_unified"):
|
||||
_emit("tool.complete", sid, payload)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue