From a2d7f538d49c7cc282c25ebcc803c8349cae9cff Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Thu, 11 Jun 2026 05:10:10 -0700 Subject: [PATCH] fix(delegate): stop subagent tool completion lines leaking into parent CLI display (#44223) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 550b72dd8 changed the concurrent-path tool-result rendering gate from 'not agent.quiet_mode' to 'tool_progress_mode != off'. Subagents are constructed with quiet_mode=True but inherit the default tool_progress_mode='all', so every child tool call during delegate_task started printing raw '✅ Tool N completed in Xs - {json...}' lines into the parent's display, bypassing the curated tree-view relay in _build_child_progress_callback. Fix: require BOTH gates — quiet_mode must be off AND tool_progress_mode must not be 'off' — restoring subagent silence while preserving the #33860 fix (CLI verbose + tool-progress off stays suppressed). The same combined gate is applied to the three sibling print sites in tool_executor.py (concurrent header/args, sequential args, sequential completion) so the whole class is consistent. --- agent/tool_executor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/agent/tool_executor.py b/agent/tool_executor.py index cd24b63f393..144a2929782 100644 --- a/agent/tool_executor.py +++ b/agent/tool_executor.py @@ -417,7 +417,7 @@ def execute_tool_calls_concurrent(agent, assistant_message, messages: list, effe # ── Logging / callbacks ────────────────────────────────────────── tool_names_str = ", ".join(name for _, name, _, _, _, _ in parsed_calls) - if not agent.quiet_mode: + if not agent.quiet_mode and getattr(agent, "tool_progress_mode", "all") != "off": print(f" ⚡ Concurrent: {num_tools} tool calls — {tool_names_str}") for i, (tc, name, args, middleware_trace, block_result, blocked_by_guardrail) in enumerate(parsed_calls, 1): args_str = json.dumps(args, ensure_ascii=False) @@ -702,7 +702,7 @@ def execute_tool_calls_concurrent(agent, assistant_message, messages: list, effe if agent._should_emit_quiet_tool_messages(): cute_msg = _get_cute_tool_message_impl(name, args, tool_duration, result=function_result) agent._safe_print(f" {cute_msg}") - elif getattr(agent, "tool_progress_mode", "all") != "off": + elif not agent.quiet_mode and getattr(agent, "tool_progress_mode", "all") != "off": _preview_str = _multimodal_text_summary(function_result) if agent.verbose_logging: print(f" ✅ Tool {i+1} completed in {tool_duration:.2f}s") @@ -866,7 +866,7 @@ def execute_tool_calls_sequential(agent, assistant_message, messages: list, effe elif function_name == "skill_manage": agent._iters_since_skill = 0 - if not agent.quiet_mode: + if not agent.quiet_mode and getattr(agent, "tool_progress_mode", "all") != "off": args_str = json.dumps(function_args, ensure_ascii=False) if agent.verbose_logging: print(f" 📞 Tool {i}: {function_name}({list(function_args.keys())})") @@ -1384,7 +1384,7 @@ def execute_tool_calls_sequential(agent, assistant_message, messages: list, effe # entire batch. The model sees it on the next API iteration. agent._apply_pending_steer_to_tool_results(messages, 1) - if not agent.quiet_mode: + if not agent.quiet_mode and getattr(agent, "tool_progress_mode", "all") != "off": if agent.verbose_logging: print(f" ✅ Tool {i} completed in {tool_duration:.2f}s") print(agent._wrap_verbose("Result: ", function_result))