Skip to content

[Bug]: fix: delegate_task status misclassification + missing interrupt on batch parent interrupt #25819

@netkr

Description

@netkr

Bug Description

Two bugs in tools/delegate_tool.py reduce delegate_task subagent reliability:

Bug A — Status misclassification (line ~1609-1617)

When a child agent completes normally (completed=True) but returns an empty final_response, the status is set to "failed" instead of "completed". This causes parents to treat successfully-completed children as failures.

The current logic only checks elif summary: (non-empty final_response) to determine "completed" status, ignoring the completed flag entirely.

Bug B — Missing interrupt on batch parent interrupt (line ~2104-2139)

When a parent is interrupted during batch execution, pending child futures are abandoned with a fabricated "interrupted" status — but child_agent.interrupt() is never called. The child threads continue running, making API calls and consuming tokens as orphan processes.

Steps to Reproduce

  1. Use delegate_task in batch mode with 2+ children
  2. Interrupt the parent while children are still running (e.g. via /stop or sending a new message)
  3. Observe that pending children continue consuming API tokens in background
  4. Also: trigger a child to complete with an empty final_response (e.g. reasoning exhaustion)
  5. Check the returned status — it will be "failed" despite the child having completed normally

Expected Behavior

  • Bug A: Child agents that complete normally should report status: "completed" regardless of whether final_response is empty. The completed flag from run_conversation() should be respected.
  • Bug B: When the parent is interrupted, all pending child agents should have .interrupt() called on them before the parent abandons the batch, preventing orphan thread resource consumption.

Actual Behavior

  • Bug A: status = "failed" even when completed = True and final_response = ""
  • Bug B: Child threads keep running after parent interrupt. Each abandoned child continues to make LLM API calls, consuming tokens and holding open connections until they naturally exhaust their own iteration budget.

Affected Component

Agent Core (conversation loop, context compression, memory)

Messaging Platform (if gateway-related)

No response

Debug Report

Report       https://paste.rs/KV3eM
agent.log    https://paste.rs/0ymtC
gateway.log  https://paste.rs/MvObr

Operating System

Linux (Debian-based, kernel 5.15)

Python Version

3.11.2

Hermes Version

v0.13.0 (2026.5.7)

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

**Bug A** — `tools/delegate_tool.py` `_run_single_child()` around line 1609:

```python

# CURRENT (buggy):
if interrupted:
    status = "interrupted"
elif summary:          # ← only checks final_response emptiness
    status = "completed"
else:
    status = "failed"  # ← even if completed=True!

The completed flag (from result.get("completed", False)) is read but never used in the status determination. It's only used later for exit_reason, creating contradictory results where exit_reason="completed" but status="failed".
Bug Btools/delegate_tool.py batch execution path around line 2104:

# CURRENT (buggy):
if getattr(parent_agent, "_interrupt_requested", False) is True:
    for f in pending:
        # ...fabricates "interrupted" entry, never calls interrupt()

The _child_by_index map (line 2100) already provides access to each child agent, but it's not used in the interrupt path. The interrupt_subagent() function (line 183) and agent.interrupt() method both exist but aren't called.

---

**Proposed Fix:**

Bug A — Add completed to the status check:

if interrupted:
    status = "interrupted"
elif completed or summary:    # ← respect the completed flag
    status = "completed"
else:
    status = "failed"

Bug B — Call child_agent.interrupt() on pending children before abandoning:

if getattr(parent_agent, "_interrupt_requested", False) is True: # Interrupt running children first for f in pending: if not f.done(): idx = futures[f] child_agent = _child_by_index.get(idx) if child_agent is not None: try: child_agent.interrupt("Batch parent interrupted") except Exception: pass # Then collect results as before for f in pending: ...

Both fixes pass existing tests (127/127 in `test_delegate.py`).

Proposed Fix (optional)

No response

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/agentCore agent loop, run_agent.py, prompt buildertool/delegateSubagent delegationtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions