From c9b3eeabdc0b7624d38fd7a6de85b66f3183c39b Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sun, 24 May 2026 02:19:20 -0700 Subject: [PATCH] fix(cli): decouple tool_progress=verbose from global DEBUG logging (#31379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- cli.py | 22 +++++++++++++++------ tests/cli/test_tool_progress_scrollback.py | 23 ++++++++++++++++++---- tui_gateway/server.py | 6 +++++- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/cli.py b/cli.py index 678574984bc..11317019560 100644 --- a/cli.py +++ b/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, "")) diff --git a/tests/cli/test_tool_progress_scrollback.py b/tests/cli/test_tool_progress_scrollback.py index f99358aa141..d6af08deab9 100644 --- a/tests/cli/test_tool_progress_scrollback.py +++ b/tests/cli/test_tool_progress_scrollback.py @@ -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" diff --git a/tui_gateway/server.py b/tui_gateway/server.py index 15dbf19ddeb..dc13969f1be 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -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(),