feat: simplify exec render formatting

This commit is contained in:
banteg
2025-12-29 13:20:26 +04:00
parent 86d47e8a12
commit dd37e56ef6
2 changed files with 26 additions and 23 deletions
@@ -8,6 +8,7 @@ from typing import Any
STATUS_RUNNING = "" STATUS_RUNNING = ""
STATUS_DONE = "" STATUS_DONE = ""
STATUS_FAIL = ""
HEADER_SEP = " · " HEADER_SEP = " · "
HARD_BREAK = " \n" HARD_BREAK = " \n"
@@ -31,15 +32,17 @@ def format_elapsed(elapsed_s: float) -> str:
def format_header(elapsed_s: float, turn: int | None, item: int | None, label: str) -> str: def format_header(elapsed_s: float, turn: int | None, item: int | None, label: str) -> str:
elapsed = format_elapsed(elapsed_s) elapsed = format_elapsed(elapsed_s)
parts = [label, elapsed] parts = [label, elapsed]
if turn is not None:
parts.append(f"turn {turn}")
if item is not None: if item is not None:
parts.append(f"item {item}") parts.append(f"item {item}")
return HEADER_SEP.join(parts) return HEADER_SEP.join(parts)
def is_command_log_line(line: str) -> bool: def is_command_log_line(line: str) -> bool:
return f"{STATUS_RUNNING} running:" in line or f"{STATUS_DONE} ran:" in line return (
f"{STATUS_RUNNING} " in line
or f"{STATUS_DONE} " in line
or f"{STATUS_FAIL} " in line
)
def extract_numeric_id(item_id: object, fallback: int | None = None) -> int | None: def extract_numeric_id(item_id: object, fallback: int | None = None) -> int | None:
@@ -89,7 +92,7 @@ def format_event(
item = event["item"] item = event["item"]
item_num = extract_numeric_id(item["id"], last_item) item_num = extract_numeric_id(item["id"], last_item)
last_item = item_num if item_num is not None else last_item last_item = item_num if item_num is not None else last_item
prefix = f"[{item_num if item_num is not None else '?'}] " prefix = f"{item_num} "
match (item["type"], etype): match (item["type"], etype):
case ("agent_message", "item.completed"): case ("agent_message", "item.completed"):
@@ -106,7 +109,7 @@ def format_event(
if command_width is not None: if command_width is not None:
command = _shorten(command, command_width) command = _shorten(command, command_width)
command = f"`{command}`" command = f"`{command}`"
line = prefix + f"{STATUS_RUNNING} running: {command}" line = prefix + f"{STATUS_RUNNING} {command}"
return last_item, [line], line, prefix return last_item, [line], line, prefix
case ("command_execution", "item.completed"): case ("command_execution", "item.completed"):
command = item["command"] command = item["command"]
@@ -114,8 +117,13 @@ def format_event(
command = _shorten(command, command_width) command = _shorten(command, command_width)
command = f"`{command}`" command = f"`{command}`"
exit_code = item["exit_code"] exit_code = item["exit_code"]
exit_part = f" (exit {exit_code})" if exit_code is not None else "" if exit_code == 0:
line = prefix + f"{STATUS_DONE} ran: {command}{exit_part}" status = STATUS_DONE
exit_part = ""
else:
status = STATUS_FAIL if exit_code is not None else STATUS_DONE
exit_part = f" (exit {exit_code})" if exit_code is not None else ""
line = prefix + f"{status} {command}{exit_part}"
return last_item, [line], line, prefix return last_item, [line], line, prefix
case ("mcp_tool_call", "item.started"): case ("mcp_tool_call", "item.started"):
name = ".".join(part for part in (item["server"], item["tool"]) if part) or "tool" name = ".".join(part for part in (item["server"], item["tool"]) if part) or "tool"
@@ -195,17 +203,12 @@ class ExecProgressRenderer:
def render_progress(self, elapsed_s: float) -> str: def render_progress(self, elapsed_s: float) -> str:
header = format_header(elapsed_s, self.turn_count, self.last_item, label="working") header = format_header(elapsed_s, self.turn_count, self.last_item, label="working")
message = self._assemble(header, list(self.recent_actions)) return self._assemble(header, list(self.recent_actions))
return message if len(message) <= self.max_chars else header
def render_final(self, elapsed_s: float, answer: str, status: str = "done") -> str: def render_final(self, elapsed_s: float, answer: str, status: str = "done") -> str:
header = format_header(elapsed_s, self.turn_count, self.last_item, label=status) header = format_header(elapsed_s, self.turn_count, self.last_item, label=status)
lines = list(self.recent_actions)
if status == "done":
lines = [line for line in lines if not is_command_log_line(line)]
body = self._assemble(header, lines)
answer = (answer or "").strip() answer = (answer or "").strip()
return body + ("\n\n" + answer if answer else "") return header + ("\n\n" + answer if answer else "")
@staticmethod @staticmethod
def _assemble(header: str, lines: list[str]) -> str: def _assemble(header: str, lines: list[str]) -> str:
@@ -32,10 +32,10 @@ def test_render_event_cli_sample_stream() -> None:
assert out == [ assert out == [
"thread started", "thread started",
"turn started", "turn started",
"[0] **Searching for README files**", "0 **Searching for README files**",
"[1] ▸ running: `bash -lc ls`", "1 ▸ `bash -lc ls`",
"[1] ✓ ran: `bash -lc ls` (exit 0)", "1 ✓ `bash -lc ls`",
"[2] **Checking repository root for README**", "2 **Checking repository root for README**",
"assistant:", "assistant:",
" Yep — theres a `README.md` in the repository root.", " Yep — theres a `README.md` in the repository root.",
"turn completed", "turn completed",
@@ -54,8 +54,8 @@ def test_render_event_cli_real_run_fixture() -> None:
assert out[0] == "thread started" assert out[0] == "thread started"
assert "turn started" in out assert "turn started" in out
assert any(line.startswith("[0] ▸ running:") for line in out) assert any(line.startswith("0 ▸ `") for line in out)
assert any(line.startswith("[0] ✓ ran:") for line in out) assert any(line.startswith("0 ✓ `") for line in out)
assert "assistant:" in out assert "assistant:" in out
assert any("exec-bridge" in line for line in out) assert any("exec-bridge" in line for line in out)
assert out[-1] == "turn completed" assert out[-1] == "turn completed"
@@ -67,11 +67,11 @@ def test_progress_renderer_renders_progress_and_final() -> None:
r.note_event(evt) r.note_event(evt)
progress = r.render_progress(3.0) progress = r.render_progress(3.0)
assert progress.startswith("working · 3s · turn 1 · item 3") assert progress.startswith("working · 3s · item 3")
assert "[1] ✓ ran: `bash -lc ls` (exit 0)" in progress assert "1 ✓ `bash -lc ls`" in progress
final = r.render_final(3.0, "answer", status="done") final = r.render_final(3.0, "answer", status="done")
assert final.startswith("done · 3s · turn 1 · item 3") assert final.startswith("done · 3s · item 3")
assert "running:" not in final assert "running:" not in final
assert "ran:" not in final assert "ran:" not in final
assert final.endswith("answer") assert final.endswith("answer")