feat(delegate): extend timeout diagnostics for N-API-call subagents - #17312
feat(delegate): extend timeout diagnostics for N-API-call subagents#17312YeahloYip wants to merge 2 commits into
Conversation
When override_provider is set (from delegation.provider config), clear effective_acp_command and effective_acp_args to prevent subagents from inheriting the parent's ACP transport. This ensures subagents use direct API calls with the configured provider instead of copilot-acp transport. Fixes: subagent using copilot-acp (qwen3.5-397b-a17b) instead of the configured delegation.provider/model (e.g. minimax-cn).
When a subagent times out after making N>0 API calls, the lead agent previously received no visibility into what tool was last running or whether its result was partial. This made it impossible to distinguish "tool ran to completion, next LLM request stalled" from "tool itself is hanging". Two prior commits addressed adjacent cases: - NousResearch#1175 (commit 7997569): tool_trace + tokens added to normal-completion results - NousResearch#15105 (commit 7634c13): diagnostic_path log written for 0-API-call timeouts This patch fills the gap for N-API-call timeouts by: 1. Building tool_trace from result["messages"] in the timeout path (mirrors the logic already present in the normal-completion path at ~line 1556). Returns tool_trace, last_tool, and last_tool_status in the timeout result dict so the lead can inspect the final tool outcome without a second round-trip. 2. Enriching the error message for api_calls>0 timeouts to include the value of current_tool from get_activity_summary(), replacing the generic "stuck on a slow API call" message with e.g.: "Subagent timed out after 300s with 3 API call(s) completed — last tool was 'web_fetch' (likely slow response). The tool may have completed; check tool_trace for result_bytes." 3. Adding a SKILL.md that documents the full diagnosis procedure for lead agents: diagnosis matrix (api_calls × last_tool × last_tool_status), step-by-step workflow, common pitfalls, and verification checklist. Also adds: skill/skills/software-development/subagent-timeout-diagnostics/
teknium1
left a comment
There was a problem hiding this comment.
Thanks for targeting an observability gap that still exists on current main: tools/delegate_tool.py:2003-2022 returns only a generic N-API-call timeout result.
Problems
- The new timeout trace cannot populate. The child result is assigned only after
_child_future.result()returns (tools/delegate_tool.py:1927-1929); on timeout, the exception path is entered first. The changedtools/delegate_tool.py:1539then reads undefinedresult, and its broadexceptclearstool_trace. - No regression test covers the proposed fields. Existing
tests/tools/test_delegate_subagent_timeout_diagnostic.py:269-284asserts the old N>0 behavior, while this PR changes no test file. - The skill documents
duration_ms(SKILL.md:104), but the existing trace schema has no duration field (tools/delegate_tool.py:2071-2085).
Suggested changes
- Build the timeout trace from live child state such as
_session_messages, and distinguish an unmatched final tool call from a completed tool. Linked #17329 contains a tested implementation direction. - Add timeout-path tests for completed, in-progress, error, and parallel tool calls.
- Drop the ACP inheritance commit already implemented on main at
tools/delegate_tool.py:1238-1244(commit6b6fc28e).
Automated hermes-sweeper review.
| last_tool: Optional[str] = None | ||
| last_tool_status: Optional[str] = None | ||
| try: | ||
| _msgs = result.get("messages") or [] |
There was a problem hiding this comment.
On a real FuturesTimeoutError, result was never assigned because _child_future.result(...) raised before returning. This broad handler therefore always clears the trace on the path this code is meant to diagnose. Read a live source such as child._session_messages instead, then add a timeout regression test.
| @@ -0,0 +1,183 @@ | |||
| --- | |||
| name: subagent-timeout-diagnostics | |||
| description: Use when a subagent times out and you need to diagnose what happened — identify whether it froze before any API call, stalled mid-request, or encountered an error in a long-running tool. | |||
There was a problem hiding this comment.
This description is well over the repository's 60-character skill-description limit. Shorten it to one sentence ending with a period before adding the skill.
| if tool_trace: | ||
| last = tool_trace[-1] | ||
| print(f"Last tool: {last.get('tool')}") | ||
| print(f"Duration: {last.get('duration_ms')}ms") |
There was a problem hiding this comment.
tool_trace currently contains args_bytes, result_bytes, and status, but no duration_ms field (tools/delegate_tool.py:2071-2085). Remove this claim or implement and test that field.
Summary
When a subagent running via
delegate_tasktimes out after making N>0 API calls, the lead agent previously received no visibility into what tool was last running or whether its result was partial. This made it impossible to distinguish:Background
Two prior commits addressed adjacent cases:
tool_traceadded to normal-completion resultsdiagnostic_pathlog written for 0-API-call timeoutsThis PR fills the remaining gap: N-API-call timeouts had no structured diagnostics.
Changes
tools/delegate_tool.py (+74 lines)
1. Enriched error message (lines ~1508-1525):
Replaces the generic "stuck on a slow API call" with a specific tool name.
2. tool_trace reconstruction on timeout (lines ~1535-1575):
Mirrors the tool_trace logic already present in the normal-completion path (~line 1556).
skills/software-development/subagent-timeout-diagnostics/SKILL.md (+183 lines)
Documents the full diagnosis procedure for lead agents: diagnosis matrix, step-by-step workflow, common pitfalls, and verification checklist.
Diagnosis Matrix
Verification