fix(tui): surface verbose tool details (#30225)
* fix(tui): surface verbose tool details Emit redacted structured verbose args/results to the TUI so /verbose verbose can show full tool detail without reopening stdout, and fail closed if redaction is unavailable. Salvages #29011. Co-authored-by: helix4u <4317663+helix4u@users.noreply.github.com> * fix(tui): address verbose detail review Label verbose tool failures as errors, cover forced verbose reasoning, and avoid new diff type warnings from the redaction regression tests. * fix(tui): bound verbose tool payloads Cap verbose tool detail text before emitting JSON-RPC events and preserve verbose results on inline diff completions. * fix(tui): align termux argv test with gc flag Update the stale TUI launch expectation so the Termux freshness path matches the current direct Node argv. --------- Co-authored-by: helix4u <4317663+helix4u@users.noreply.github.com>
This commit is contained in:
@@ -168,7 +168,7 @@ def test_make_tui_argv_skips_build_only_on_termux_when_fresh(
|
||||
|
||||
argv, cwd = main_mod._make_tui_argv(tmp_path, tui_dev=False)
|
||||
|
||||
assert argv == ["/bin/node", str(tmp_path / "dist" / "entry.js")]
|
||||
assert argv == ["/bin/node", "--expose-gc", str(tmp_path / "dist" / "entry.js")]
|
||||
assert cwd == tmp_path
|
||||
|
||||
|
||||
|
||||
@@ -59,6 +59,59 @@ def test_write_json_returns_false_on_broken_pipe(monkeypatch):
|
||||
assert server.write_json({"ok": True}) is False
|
||||
|
||||
|
||||
def test_tui_verbose_tool_details_fail_closed_when_redaction_fails(monkeypatch):
|
||||
redact_module = types.ModuleType("agent.redact")
|
||||
|
||||
def fail_redaction(*_args, **_kwargs):
|
||||
raise RuntimeError("redaction unavailable")
|
||||
|
||||
setattr(redact_module, "redact_sensitive_text", fail_redaction)
|
||||
monkeypatch.setitem(sys.modules, "agent.redact", redact_module)
|
||||
|
||||
assert server._redact_tui_verbose_text("api_key=secret") == ""
|
||||
assert server._tool_args_text({"api_key": "secret"}) == ""
|
||||
assert server._tool_result_text("token=secret") == ""
|
||||
|
||||
|
||||
def test_tui_verbose_tool_details_are_capped_before_emit(monkeypatch):
|
||||
monkeypatch.setattr(server, "_TUI_VERBOSE_TEXT_MAX_CHARS", 12)
|
||||
monkeypatch.setattr(server, "_TUI_VERBOSE_TEXT_MAX_LINES", 2)
|
||||
|
||||
capped = server._cap_tui_verbose_text("one\ntwo\nthree\nfour")
|
||||
|
||||
assert capped.startswith("[showing verbose tail; omitted ")
|
||||
assert capped.endswith("three\nfour")
|
||||
assert "one" not in capped
|
||||
|
||||
|
||||
def test_tui_verbose_tool_events_omit_details_when_redaction_fails(monkeypatch):
|
||||
redact_module = types.ModuleType("agent.redact")
|
||||
|
||||
def fail_redaction(*_args, **_kwargs):
|
||||
raise RuntimeError("redaction unavailable")
|
||||
|
||||
setattr(redact_module, "redact_sensitive_text", fail_redaction)
|
||||
monkeypatch.setitem(sys.modules, "agent.redact", redact_module)
|
||||
|
||||
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,
|
||||
"redaction-test",
|
||||
{"tool_progress_mode": "verbose", "tool_started_at": {}},
|
||||
)
|
||||
|
||||
server._on_tool_start("redaction-test", "tool-1", "terminal", {"command": "pwd"})
|
||||
server._on_tool_complete("redaction-test", "tool-1", "terminal", {"command": "pwd"}, "done")
|
||||
|
||||
assert events[0][0] == "tool.start"
|
||||
assert events[1][0] == "tool.complete"
|
||||
assert "args_text" not in events[0][2]
|
||||
assert "result_text" not in events[1][2]
|
||||
|
||||
|
||||
def test_dispatch_rejects_non_object_request():
|
||||
resp = server.dispatch([])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user