fix(cli): decouple tool_progress=verbose from global DEBUG logging (#31379)
PR #6a1aa420e coupled `display.tool_progress: verbose` (a per-tool display toggle for full args / results / think blocks) to `self.verbose` — which controls root-logger DEBUG level. Result: setting tool_progress: verbose in config silently flipped every module in the process to DEBUG and flooded the terminal with internal logging, far beyond just full tool calls. The two concepts are separate: - `tool_progress_mode == 'verbose'` → display behavior (tool rendering) - `self.verbose` → logging behavior (root logger → DEBUG, line 9795) This change keeps PR #6a1aa420e's argparse.SUPPRESS / config-fallback plumbing but severs the verbose-display → debug-logging link. Changes: - cli.py:2868 — `self.verbose` only follows explicit `verbose=` arg; no longer auto-True when tool_progress_mode == 'verbose'. - cli.py:_toggle_verbose — slash-cycle through tool progress modes no longer flips `self.verbose` / `agent.verbose_logging` / `agent.quiet_mode`. - cli.py:9355 — fix misleading label (drop 'and debug logs'). - tui_gateway/server.py:_make_agent — same decoupling on the TUI side (verbose_logging no longer derived from tool_progress_mode). - tests/cli/test_tool_progress_scrollback.py — invert the test that asserted the broken coupling; add coverage for explicit `--verbose` still enabling DEBUG independent of tool_progress. Live verified: - tool_progress: verbose, no --verbose flag → 0 DEBUG/INFO log lines - --verbose flag explicit → 32 DEBUG/INFO log lines (as expected)
This commit is contained in:
22
cli.py
22
cli.py
@@ -2857,7 +2857,12 @@ class HermesCLI:
|
||||
else:
|
||||
self.busy_input_mode = "interrupt"
|
||||
|
||||
self.verbose = verbose if verbose is not None else (self.tool_progress_mode == "verbose")
|
||||
# self.verbose ONLY controls global DEBUG logging (root logger level).
|
||||
# display.tool_progress="verbose" controls tool-call rendering (full args,
|
||||
# results, think blocks) and is independent — see _apply_logging_levels.
|
||||
# Coupling the two (PR #6a1aa420e) caused all module DEBUG logs to spew
|
||||
# to console whenever a user set tool_progress: verbose in config.
|
||||
self.verbose = bool(verbose) if verbose is not None else False
|
||||
|
||||
# streaming: stream tokens to the terminal as they arrive (display.streaming in config.yaml)
|
||||
self.streaming_enabled = CLI_CONFIG["display"].get("streaming", False)
|
||||
@@ -9329,18 +9334,23 @@ class HermesCLI:
|
||||
_cprint(" Failed to save runtime_footer setting to config.yaml")
|
||||
|
||||
def _toggle_verbose(self):
|
||||
"""Cycle tool progress mode: off → new → all → verbose → off."""
|
||||
"""Cycle tool progress mode: off → new → all → verbose → off.
|
||||
|
||||
Tool-progress display (full args / results / think blocks at the
|
||||
``verbose`` step) is INDEPENDENT of global DEBUG logging. Cycling
|
||||
through here does not change ``self.verbose`` or the agent's
|
||||
``verbose_logging`` / ``quiet_mode`` — those remain under the
|
||||
explicit ``-v``/``--verbose`` flag and the ``/verbose-logging``
|
||||
toggle. See PR #6a1aa420e for the history that decoupled them.
|
||||
"""
|
||||
cycle = ["off", "new", "all", "verbose"]
|
||||
try:
|
||||
idx = cycle.index(self.tool_progress_mode)
|
||||
except ValueError:
|
||||
idx = 2 # default to "all"
|
||||
self.tool_progress_mode = cycle[(idx + 1) % len(cycle)]
|
||||
self.verbose = self.tool_progress_mode == "verbose"
|
||||
|
||||
if self.agent:
|
||||
self.agent.verbose_logging = self.verbose
|
||||
self.agent.quiet_mode = not self.verbose
|
||||
self.agent.reasoning_callback = self._current_reasoning_callback()
|
||||
|
||||
# Use raw ANSI codes via _cprint so the output is routed through
|
||||
@@ -9352,7 +9362,7 @@ class HermesCLI:
|
||||
"off": f"{_Colors.DIM}Tool progress: OFF{_Colors.RESET} — silent mode, just the final response.",
|
||||
"new": f"{_Colors.YELLOW}Tool progress: NEW{_Colors.RESET} — show each new tool (skip repeats).",
|
||||
"all": f"{_Colors.GREEN}Tool progress: ALL{_Colors.RESET} — show every tool call.",
|
||||
"verbose": f"{_Colors.BOLD}{_Colors.GREEN}Tool progress: VERBOSE{_Colors.RESET} — full args, results, think blocks, and debug logs.",
|
||||
"verbose": f"{_Colors.BOLD}{_Colors.GREEN}Tool progress: VERBOSE{_Colors.RESET} — full args, results, and think blocks.",
|
||||
}
|
||||
_cprint(labels.get(self.tool_progress_mode, ""))
|
||||
|
||||
|
||||
@@ -178,15 +178,30 @@ class TestToolProgressScrollback:
|
||||
|
||||
mock_print.assert_not_called()
|
||||
|
||||
def test_verbose_mode_config_enables_cli_verbose_by_default(self):
|
||||
"""Config-only display.tool_progress=verbose should enable verbose output."""
|
||||
def test_verbose_mode_config_does_not_enable_global_debug_logging(self):
|
||||
"""display.tool_progress=verbose controls TOOL-CALL DISPLAY ONLY.
|
||||
|
||||
It must NOT auto-flip self.verbose, which controls root-logger DEBUG
|
||||
level for the entire process (every module spews to console). PR
|
||||
#6a1aa420e had coupled them, causing all debug logs to flood the
|
||||
terminal whenever a user picked tool_progress: verbose for richer
|
||||
per-tool rendering.
|
||||
"""
|
||||
cli = _make_cli(tool_progress="verbose")
|
||||
|
||||
assert cli.tool_progress_mode == "verbose"
|
||||
assert cli.verbose is False
|
||||
|
||||
def test_explicit_verbose_argument_wins_over_config(self):
|
||||
"""Explicit verbose=True from the CLI flag still enables DEBUG logging
|
||||
regardless of tool_progress_mode."""
|
||||
cli = _make_cli(tool_progress="off", verbose=True)
|
||||
|
||||
assert cli.tool_progress_mode == "off"
|
||||
assert cli.verbose is True
|
||||
|
||||
def test_explicit_non_verbose_argument_still_overrides_verbose_config(self):
|
||||
"""An explicit non-verbose value should keep overriding the config fallback."""
|
||||
def test_explicit_non_verbose_argument_keeps_debug_logging_off(self):
|
||||
"""Explicit verbose=False overrides any default to enable DEBUG."""
|
||||
cli = _make_cli(tool_progress="verbose", verbose=False)
|
||||
|
||||
assert cli.tool_progress_mode == "verbose"
|
||||
|
||||
@@ -2033,7 +2033,11 @@ def _make_agent(sid: str, key: str, session_id: str | None = None):
|
||||
acp_args=runtime.get("args"),
|
||||
credential_pool=runtime.get("credential_pool"),
|
||||
quiet_mode=True,
|
||||
verbose_logging=_load_tool_progress_mode() == "verbose",
|
||||
# verbose_logging controls DEBUG-level agent logging; it is intentionally
|
||||
# independent of tool_progress_mode (which only controls per-tool
|
||||
# display detail). See cli.py PR (decoupling fix) for the matching
|
||||
# change on the classic CLI side.
|
||||
verbose_logging=False,
|
||||
reasoning_config=_load_reasoning_config(),
|
||||
service_tier=_load_service_tier(),
|
||||
enabled_toolsets=_load_enabled_toolsets(),
|
||||
|
||||
Reference in New Issue
Block a user