Skip to content

feat: non-blocking background agent delegation (async_delegation toolset) #5586

@iRonin

Description

@iRonin

Summary

Add non-blocking background agent execution as agent-callable tools. Unlike delegate_task which blocks the parent until all children complete, this lets the parent agent spawn long-running background agents and continue working immediately.

Motivation

delegate_task is synchronous — the parent agent is blocked in a tool call waiting for all subagents. This prevents Hermes from implementing workflows like:

  • Start a long research/coding agent and do other work while it runs
  • Run multiple independent agents across turns without waiting
  • Check in on running agents periodically and steer them
  • Collect results only when convenient

Proposed tools (new async_delegation toolset)

Tool Description
delegate_task_async(goal, ...) Spawn a background agent, return task_id immediately
check_task(task_id) Non-blocking: status + last 10 lines of output
collect_task(task_id, timeout) Block until done, return full result
steer_task(task_id, message) Inject steering mid-run (via _steering_injection)
cancel_task(task_id) Stop a running background agent
list_tasks() All async tasks for this session

Example workflow

# Start three research tasks
t1 = delegate_task_async(goal="Research CDAL environmental violations")
t2 = delegate_task_async(goal="Find relevant ECSC case law on nuisance")
t3 = delegate_task_async(goal="Draft outline for affidavit")

# Check progress while doing other work
check_task(t1["task_id"])  # → {status: running, output_preview: "..."}

# Steer one mid-run
steer_task(t2["task_id"], "Focus on post-2020 cases only")

# Collect when ready
results = [collect_task(t["task_id"]) for t in [t1, t2, t3]]

Design

  • In-process threads — reuses the existing AIAgent machinery, same credentials/toolsets as delegate_task
  • Output capture — child's _print_fn redirected to an in-memory ring buffer (200 lines × 500 chars)
  • Steering — direct _steering_injection queue wiring, same as synchronous subagents
  • Registryparent_agent._async_tasks dict keyed by task_id, session-scoped

Relationship to #4949

This is intentionally different from #4949 (Persistent ACP background subagents):

  • Persistent ACP background subagents #4949 proposes ACP-over-stdio with sandboxed containers and cross-turn persistence — the right long-term architecture for production multi-agent systems
  • This PR implements in-process threads with no external dependencies — works today, useful for single-session workflows

These are complementary. When #4949 ships, the API could be unified under the same tool names.

Tests

68 unit tests covering all 6 tools and the AsyncTask dataclass. No real LLM calls — all child agents are mocked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havecomp/agentCore agent loop, run_agent.py, prompt buildertool/delegateSubagent delegationtype/featureNew feature or request

    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