Skip to content

Async task completion leaves an idle parent conversation unwoken #126

Description

@nishu-builder

Problem

A parent conversation can start detached work with spawn_agent / run_async, finish its foreground turn while that work is pending, and never progress after the detached work completes.

The background wrapper successfully appends a terminal event to the parent conversation ref, but the parent remains idle and no continuation turn is admitted. This is especially confusing when the agent says it will continue or merge the result once the subagent completes.

Reproduction

  1. Start two subagents from a TUI conversation.
  2. Poll both with run_async.
  3. Let one finish and merge it while the other remains pending.
  4. Allow the parent agent to end its foreground turn with status: "idle".
  5. Let the remaining subagent finish.

The conversation ref advances with a terminal event such as:

{"async":{"result":"32d3537d346ce9f50943a910f9693f99794b6c96","status":"complete","task":"5e61048b87fae5db46e1d6754ce9b1f647408045"}}

The preceding parent event is still the last top-level lifecycle status and is idle. No further model turn runs, so the completed result is not inspected or merged until the user sends another message.

Observed behavior

  • The detached request and run-and-update-ref finish successfully.
  • The result object exists and the async.status: complete event is durably appended.
  • The TUI follows the new ref head, but the conversation projection remains idle because the event has no top-level queued/running status.
  • No component admits a new parent llm-step request.

This is separate from a subagent failure or a cold worker start.

Expected behavior

Completion should not silently strand a parent that is waiting for detached work. The eventual policy may require an explicit durable wait/subscription rather than waking on every detached completion, but the system and agent-facing contract should make the behavior reliable and visible.

At minimum, an idle parent should surface that background work completed and requires attention; ideally a parent that durably elected to wait should resume exactly once.

Related implementation notes

run-and-update-ref currently appends the terminal async event and returns. Conversation status projection reads top-level status, and TUI request reconciliation only joins conversations projected as queued or running. There is therefore no wakeup edge from a terminal async event to a new foreground request.

design/chat.md already lists durable async recovery as deferred work, but that note focuses on redispatching pending tasks after foreground exit. This report covers the corresponding terminal-completion/parent-continuation gap.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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