Skip to content

feat: add explicit collect/ack lifecycle for async delegation results #79080

Description

@wayidido

Problem

Top-level delegate_task calls are intentionally asynchronous: the tool returns a handle, and the consolidated result later re-enters the originating session as a fresh [ASYNC DELEGATION BATCH COMPLETE] turn.

That default is useful and should remain unchanged. The missing lifecycle operation is an explicit collect/ack path for a parent that wants to join the delegation before publishing its final report.

Today a parent can inspect the live transcript, manifest, or cached summary, but those reads do not acknowledge the durable completion. If the parent incorporates that result and finishes first, the normal completion event still arrives later and looks like a duplicate post-final notification.

This is different from wrong-session routing or restart recovery: the event is correctly routed and durable; there is simply no public consumption operation equivalent to process(wait/log).

Existing precedent

Background terminal processes already coordinate the direct tool-return and notification paths:

Async delegation already has the underlying durable primitives in tools/async_delegation.py, including claim/complete delivery and mark_completion_delivered(), but they are private implementation details and should not be called by user workflows.

Requested capability

Expose one supported operation, for example:

delegation_collect(delegation_id, timeout=...)

or a process-style action:

delegation(action="wait" | "collect", delegation_id="deleg_...")

Required semantics:

  1. Wait for or read the consolidated result for the named delegation.
  2. Return that result to the current parent turn.
  3. Atomically claim and mark the durable completion delivered/consumed for the owning session.
  4. Suppress the later synthetic completion turn only after the result has actually been returned.
  5. Preserve current automatic async delivery as the default when collect/ack is not used.
  6. Fail closed for a foreign session/delegation ID.

A delivery="auto" | "manual" dispatch option could be considered, but an explicit collect operation is sufficient and mirrors the existing process lifecycle more closely.

Regression coverage

  • Default auto-delivery remains unchanged.
  • Collect after completion returns the result and prevents a second synthetic turn.
  • Collect before completion blocks/times out predictably and can be retried.
  • Competing auto-drain and collect consumers produce exactly one winner.
  • Durable completion survives restart and remains collectable by the originating/resumed session.
  • Foreign sessions cannot collect or acknowledge the result.
  • Reading live transcript/cache alone does not count as consumption.

This keeps delegate_task convenient for native Hermes orchestration while giving parent workflows a supported join boundary before final reporting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions