Skip to content

[Bug]: Slash commands do not work correctly during sub agent waves. #63463

Description

@MrTrenchTrucker

Bug Description

When a sub agent wave is ongoing, slash commands are broken! Each slash command is handled differently during the sub agent wave. /new does not work at all, /redraw worked, /clear did clear BUT agent still had full context.

Steps to Reproduce

  1. tell main agent to spawn a sub agent wave 4 sub agents.
  2. type: /new
  3. /new should never go thru even when wave is complete.
  4. same with /clear on the front end, the session is cleared but context is actually retained.

Expected Behavior

/new should immediately create a new session and NOT allow any context from the old session including any return from the sub agents.
/clear should clear the context under the same session immediately.

Actual Behavior

during the sub agent wave, I tried /new, /redraw (worked) and /clear (acted like it worked but did not).

Affected Component

Other

Messaging Platform (if gateway-related)

N/A (CLI only)

Debug Report

Zadie_bug_report_subagent_slash_interrupt.md
---
# Bug Report: Slash Command Failure During Active Subagent Delegation

Date: 2026-07-12
Reporter: Hermies Zadie (CONTAK Mr Trench Worker)  
Harness Version: 0.18.0 (v2026.7.1-dirty)
Severity: High (Blocks user interrupt/refresh during long-running tasks)
Status: Root Cause Identified, Fix Proposed

---

## 1. Executive Summary

Slash commands (specifically destructive ones like /new, /clear, and potentially /quit) fail to take effect when a user attempts them while a batch of subagents (via delegate_task) is actively running.

The parent agent ignores the command or queues it incorrectly, leaving the user stuck waiting for subagents to finish naturally. This breaks the core user expectation that destructive commands should immediately abort all work and start fresh.

---

## 2. The Symptom

User Experience:

1. User dispatches a multi-agent research task (e.g., "Find all X and write 3 chapters").
2. Subagents spawn and start working (takes 2-5 minutes).
3. User realizes they want to abort/correct the task and types /new "Better prompt".
4. Result: The command seems to do nothing. The UI shows "Agent busy" or the command output is swallowed. The subagents continue running until completion.
5. The user is forced to wait for the full delegation to finish or kill the terminal process (KILL9).

Expected Behavior:

- /new should immediately interrupt all running subagents, clear the context, and start a fresh session.
- /clear should abort all background work and reset the conversation history.

---

## 3. Root Cause Analysis

### 3.1 The Architecture

- Subagent Spawning: When delegate_task is called, the parent agent registers child agents in self.\_active_children (list) inside tools/delegate_tool.py.
- Interrupt Mechanism: The parent has \_interrupt_requested (bool) and \_active_children (list).
- Interrupt Propagation: The AIAgent.interrupt() method iterates over \_active_children and calls child.interrupt() on each.

### 3.2 The Code Defect

File: run_agent.pyFunction: clear_interrupt() (Lines 2686-2718)

The clear_interrupt() method ONLY clears the parent's flag. It does NOT propagate the "clear" signal to children.


def clear_interrupt(self) -> None:
    """Clear any pending interrupt request and the per-thread tool interrupt signal."""
    self._interrupt_requested = False
    self._interrupt_message = None
    self._interrupt_thread_signal_pending = False
    
    # ... clears tool worker threads ...
    
    # ❌ MISSING: Propagation to children
    # There is NO code here that says:
    # for child in self._active_children:
    #     child.clear_interrupt()


File: cli.pyFunction: process_command() (Lines 8370-8450)

When a destructive slash command like /new or /clear is executed:

1. It calls self.new_session() or self.clear_terminal().
2. Inside new_session(), the code calls self.agent.close() and self.agent.clear_interrupt().
3. The Critical Failure: clear_interrupt() returns immediately after clearing the parent flag.
4. The children are still running, still holding their own \_interrupt_requested = False (because they were never signaled to stop).

Contrast with interrupt():
The interrupt() method (Lines 2642-2684) DOES propagate to children correctly:


def interrupt(self, message=None):
    self._interrupt_requested = True
    # ... fan out to children ...
    with self._active_children_lock:
        children_copy = list(self._active_children)
    for child in children_copy:
        try:
            child.interrupt(message)  # ✅ Correct propagation


### 3.3 Why process_command Bypasses the Fix

The CLI's process_command method for /new and /clear calls clear_interrupt() directly (via new_session()) instead of going through a unified "abort everything" entry point.

The flow is:

1. User types /new
2. cli.py → process_command("/new") → new_session()
3. new_session() → agent.close() → agent.clear_interrupt()
4. clear_interrupt() clears parent only. Children keep running.
5. new_session() spawns a new agent with a new ID.
6. The children are now orphaned: they are still attached to the old parent session ID but the parent session is dead.

---

## 4. Reproduction Steps

1. Start Hermes CLI.
2. Dispatch a long-running subagent task (e.g., "Write a 10-page report on X" or delegate_task with a sleep loop).
3. While subagents are running (check /kanban list or the TUI overlay), type:

   
   /new "Cancel everything and start fresh"
   
4. Observe:
   - The command prints a "starting new session" message but the prompt never returns.
   - Subagents continue to log work in the background.
   - The Kafka-stream of tool output from the subagents does not stop.
   - The new session does not actually start until the old subagents finish naturally.

---

## 5. Proposed Fix

### Option A: Patch clear_interrupt() (Recommended)

Modify run_agent.py to propagate the "clear" signal to all active children before clearing the parent flag.

File: run_agent.pyLocation: AIAgent.clear_interrupt() (after line 2688)


def clear_interrupt(self) -> None:
    """Clear any pending interrupt request and the per-thread tool interrupt signal."""
    
    # ✅ FIX: Propagate clear to active children BEFORE clearing parent flag
    with self._active_children_lock:
        children_copy = list(self._active_children)
    for child in children_copy:
        try:
            child.clear_interrupt()
        except Exception as e:
            logger.debug("Failed to clear interrupt on child agent: %s", e)
    
    self._interrupt_requested = False
    self._interrupt_message = None
    self._interrupt_thread_signal_pending = False
    
    # ... rest of existing clear_interrupt() logic ...


Why this works:

- Ensures that any code path that calls clear_interrupt() (slash commands, manual close) automatically wakes up and tells children to "stop."
- Maintains symmetry: interrupt() propagates down; clear_interrupt() propagates down.
- No changes needed in cli.py.

### Option B: Add a Unified abort() Method

Create AIAgent.abort() that calls interrupt() then close(), and route all destructive slash commands through this new method.

Pros: More explicit intent.
Cons: Requires changes in cli.py and run_agent.py. Slightly diffusing.

Option A is preferred for minimal churn and maximum backward compatibility.

---

## 6. Testing Strategy

After applying the fix:

1. Unit Test: Add a test in tests/cli/test_slash_command_interrupt.py or tests/cli/test_cli_interrupt_subagent.py.
   - Mock a parent with 2 active children.
   - Call parent.clear_interrupt().
   - Assert child1.\_interrupt_requested became False (or child1.interrupt_was_called flag set).
   - Assert child2.\_interrupt_requested became False.
2. Integration Test:
   - Start a subagent task that sleeps for 60 seconds.
   - Type /new at T+10s.
   - Verify the subagent logs "Interrupt requested" and exits within 5 seconds.
   - Verify the new session starts immediately without waiting for the 60s timer.
3. Edge Case:
   - Verify that clear_interrupt() on a parent with no children does not raise errors.

---

## 7. Impact Assessment

- Breaking Changes: None. This fixes a bug where commands failed, restoring expected behavior.
- Performance: Negligible. The loop over \_active_children is O(n) where n is usually < 5.
- Security: No impact.
- Backport Target: v0.18.0 (Current release).

---

## 8. Related Issues / References

- tests/cli/test_cli_interrupt_subagent.py: Existing test for user-typed interrupts (does not cover slash commands).
- run_agent.py: Lines 2642-2718 (interrupt() vs clear_interrupt()).
- cli.py: Lines 8240-8450 (process_command dispatch logic).
- tools/delegate_tool.py: Lines 45-54 (DELEGATE_BLOCKED_TOOLS and spawn logic).

---

## 9. Next Steps

1. Apply Option A fix to run_agent.py.
2. Run existing interrupt tests to ensure no regressions.
3. Add new integration test for slash command + subagent scenario.
4. Submit PR to main with label bugfix and high-priority.
5. Trigger hotfix release if necessary (if v0.18.0 is already shipped to users).

---

Report generated by Hermies Zadie, HANDS Worker.Harness Version: 0.18.0 | Date: 2026-07-12

Operating System

Linux Truenas Scale (goldeneye)

Python Version

No response

Hermes Version

v0.18.0

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

slash commands should work during sub agent waves.

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 existsbugcomp/cliCLI entry point, hermes_cli/, setup wizardduplicateThis issue or pull request already existstype/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions