Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Align CLI help output (#248)
Browse files* Align CLI help output
Co-authored-by: OpenAI Codex <codex@openai.com>
* Address CLI help review feedback
Co-authored-by: OpenAI Codex <codex@openai.com>
---------
Co-authored-by: OpenAI Codex <codex@openai.com>
- agent/utils/terminal_display.py +63 -13
- tests/unit/test_cli_rendering.py +45 -0
agent/utils/terminal_display.py
CHANGED
|
@@ -6,6 +6,7 @@ import asyncio
|
|
| 6 |
import re
|
| 7 |
|
| 8 |
from rich.console import Console
|
|
|
|
| 9 |
from rich.markdown import Heading, Markdown
|
| 10 |
from rich.panel import Panel
|
| 11 |
from rich.theme import Theme
|
|
@@ -446,23 +447,72 @@ def print_yolo_approve(count: int) -> None:
|
|
| 446 |
|
| 447 |
# ββ Help βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 448 |
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 461 |
|
| 462 |
|
| 463 |
def print_help() -> None:
|
| 464 |
_console.print()
|
| 465 |
-
_console.print(
|
| 466 |
_console.print()
|
| 467 |
|
| 468 |
|
|
|
|
| 6 |
import re
|
| 7 |
|
| 8 |
from rich.console import Console
|
| 9 |
+
from rich.markup import escape
|
| 10 |
from rich.markdown import Heading, Markdown
|
| 11 |
from rich.panel import Panel
|
| 12 |
from rich.theme import Theme
|
|
|
|
| 447 |
|
| 448 |
# ββ Help βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 449 |
|
| 450 |
+
HELP_ROWS: tuple[tuple[str, str, str], ...] = (
|
| 451 |
+
("/help", "", "Show this help"),
|
| 452 |
+
("/undo", "", "Undo last turn"),
|
| 453 |
+
("/compact", "", "Compact context window"),
|
| 454 |
+
("/resume", "[index|id|path]", "Pick up from ./session_logs"),
|
| 455 |
+
("/model", "[id]", "Show available models or switch"),
|
| 456 |
+
(
|
| 457 |
+
"/effort",
|
| 458 |
+
"[level]",
|
| 459 |
+
"Set reasoning effort preference",
|
| 460 |
+
),
|
| 461 |
+
("/yolo", "", "Toggle auto-approve mode"),
|
| 462 |
+
("/status", "", "Current model & turn count"),
|
| 463 |
+
(
|
| 464 |
+
"/share-traces",
|
| 465 |
+
"[public|private]",
|
| 466 |
+
"Show or change HF trace visibility",
|
| 467 |
+
),
|
| 468 |
+
("/quit", "", "Exit"),
|
| 469 |
+
)
|
| 470 |
+
|
| 471 |
+
|
| 472 |
+
def _help_column_widths(
|
| 473 |
+
rows: tuple[tuple[str, str, str], ...],
|
| 474 |
+
) -> tuple[int, int]:
|
| 475 |
+
return (
|
| 476 |
+
max(len(command) for command, _, _ in rows),
|
| 477 |
+
max(len(args) for _, args, _ in rows),
|
| 478 |
+
)
|
| 479 |
+
|
| 480 |
+
|
| 481 |
+
def _format_help_row(
|
| 482 |
+
command: str,
|
| 483 |
+
args: str,
|
| 484 |
+
description: str,
|
| 485 |
+
command_width: int,
|
| 486 |
+
args_width: int,
|
| 487 |
+
) -> str:
|
| 488 |
+
command_gap = " " * (command_width - len(command) + 2)
|
| 489 |
+
args_gap = " " * (args_width - len(args) + 2)
|
| 490 |
+
command_markup = f"[cyan]{escape(command)}[/cyan]"
|
| 491 |
+
args_markup = f"[muted]{escape(args)}[/muted]" if args else ""
|
| 492 |
+
return f"{_I} {command_markup}{command_gap}{args_markup}{args_gap}{description}"
|
| 493 |
+
|
| 494 |
+
|
| 495 |
+
def format_help_text(rows: tuple[tuple[str, str, str], ...] | None = None) -> str:
|
| 496 |
+
help_rows = HELP_ROWS if rows is None else rows
|
| 497 |
+
command_width, args_width = _help_column_widths(help_rows)
|
| 498 |
+
return "\n".join(
|
| 499 |
+
[f"{_I}[bold]Commands[/bold]"]
|
| 500 |
+
+ [
|
| 501 |
+
_format_help_row(
|
| 502 |
+
command,
|
| 503 |
+
args,
|
| 504 |
+
description,
|
| 505 |
+
command_width,
|
| 506 |
+
args_width,
|
| 507 |
+
)
|
| 508 |
+
for command, args, description in help_rows
|
| 509 |
+
]
|
| 510 |
+
)
|
| 511 |
|
| 512 |
|
| 513 |
def print_help() -> None:
|
| 514 |
_console.print()
|
| 515 |
+
_console.print(format_help_text())
|
| 516 |
_console.print()
|
| 517 |
|
| 518 |
|
tests/unit/test_cli_rendering.py
CHANGED
|
@@ -5,6 +5,7 @@ from io import StringIO
|
|
| 5 |
from types import SimpleNamespace
|
| 6 |
|
| 7 |
import pytest
|
|
|
|
| 8 |
|
| 9 |
import agent.main as main_mod
|
| 10 |
from agent.tools.research_tool import _get_research_model
|
|
@@ -29,6 +30,50 @@ def test_non_anthropic_research_model_is_unchanged():
|
|
| 29 |
assert _get_research_model("openai/gpt-5.4") == "openai/gpt-5.4"
|
| 30 |
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
def test_subagent_display_does_not_spawn_background_redraw(monkeypatch):
|
| 33 |
calls: list[object] = []
|
| 34 |
|
|
|
|
| 5 |
from types import SimpleNamespace
|
| 6 |
|
| 7 |
import pytest
|
| 8 |
+
from rich.console import Console
|
| 9 |
|
| 10 |
import agent.main as main_mod
|
| 11 |
from agent.tools.research_tool import _get_research_model
|
|
|
|
| 30 |
assert _get_research_model("openai/gpt-5.4") == "openai/gpt-5.4"
|
| 31 |
|
| 32 |
|
| 33 |
+
def test_help_output_keeps_descriptions_aligned(monkeypatch):
|
| 34 |
+
output = StringIO()
|
| 35 |
+
console = Console(
|
| 36 |
+
file=output,
|
| 37 |
+
color_system=None,
|
| 38 |
+
theme=terminal_display._THEME,
|
| 39 |
+
width=120,
|
| 40 |
+
)
|
| 41 |
+
monkeypatch.setattr(terminal_display, "_console", console)
|
| 42 |
+
|
| 43 |
+
terminal_display.print_help()
|
| 44 |
+
|
| 45 |
+
lines = [line.rstrip() for line in output.getvalue().splitlines() if line.strip()]
|
| 46 |
+
description_columns = []
|
| 47 |
+
for command, args, description in terminal_display.HELP_ROWS:
|
| 48 |
+
line = next(line for line in lines if command in line)
|
| 49 |
+
if args:
|
| 50 |
+
assert args in line
|
| 51 |
+
description_columns.append(line.index(description))
|
| 52 |
+
|
| 53 |
+
assert len(set(description_columns)) == 1
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def test_help_output_recomputes_widths_from_rows():
|
| 57 |
+
rows = terminal_display.HELP_ROWS + (
|
| 58 |
+
("/longer-command", "[longer-args]", "Synthetic help row"),
|
| 59 |
+
)
|
| 60 |
+
output = StringIO()
|
| 61 |
+
Console(
|
| 62 |
+
file=output,
|
| 63 |
+
color_system=None,
|
| 64 |
+
theme=terminal_display._THEME,
|
| 65 |
+
width=140,
|
| 66 |
+
).print(terminal_display.format_help_text(rows))
|
| 67 |
+
|
| 68 |
+
lines = [line.rstrip() for line in output.getvalue().splitlines() if line.strip()]
|
| 69 |
+
description_columns = [
|
| 70 |
+
next(line for line in lines if command in line).index(description)
|
| 71 |
+
for command, _args, description in rows
|
| 72 |
+
]
|
| 73 |
+
|
| 74 |
+
assert len(set(description_columns)) == 1
|
| 75 |
+
|
| 76 |
+
|
| 77 |
def test_subagent_display_does_not_spawn_background_redraw(monkeypatch):
|
| 78 |
calls: list[object] = []
|
| 79 |
|