Skip to content

Pending asks become undismissable after sender disconnects #34

Description

@adityavkk

Summary

If an ask/contact_supervisor(reason: "need_decision") sender disconnects before the recipient replies, the recipient can be left with a pending ask that cannot be answered or dismissed. intercom({ action: "pending" }) keeps showing the ask, but intercom({ action: "reply", ... }) fails with Session not found because the original sender session no longer exists.

This creates noisy, unresolvable supervisor-decision prompts after timed-out or interrupted subagent runs.

Environment observed

  • pi-intercom: 0.6.0
  • pi-subagents: 0.28.0
  • OS: macOS / Darwin arm64
  • Install: pi install npm:pi-intercom / pi install npm:pi-subagents

Reproduction

A minimal repro does not require subagents:

  1. Start two Pi sessions with pi-intercom enabled.

  2. Name them so targeting is easy:

    • Session A: /name supervisor
    • Session B: /name worker
  3. In session B, send a blocking ask to A:

    intercom({ action: "ask", to: "supervisor", message: "Please reply after I disconnect." })
  4. Before session A replies, terminate session B. For example, close the terminal, kill the process, or interrupt the child process if using a subagent.

  5. In session A, inspect pending asks:

    intercom({ action: "pending" })
  6. Try to reply using either the default reply or the specific replyTo id shown by pending:

    intercom({ action: "reply", message: "ok" })
    // or
    intercom({ action: "reply", replyTo: "<message-id>", message: "ok" })
  7. Inspect pending asks again:

    intercom({ action: "pending" })

Actual result

The reply cannot be delivered because the sender session is gone, and the pending ask remains listed.

Observed in a subagent run:

Pending asks:
- subagent-researcher-48715e9b-1 · f9c19b2c-64e9-40b5-a232-baddda294ec9 · ... · Subagent needs a supervisor decision.

Reply attempt:

Reply to "subagent-researcher-48715e9b-1" was not delivered: Session not found

Running pending again still showed the same ask.

Expected result

A pending ask whose sender is no longer connected should not remain permanently unresolved.

Any of these would be acceptable:

  • automatically mark the pending ask stale when the sender disconnects
  • remove/resolve the pending ask when a reply attempt fails with Session not found
  • add an explicit dismiss/clear action, e.g. intercom({ action: "dismiss", replyTo: "..." })
  • make pending show stale/unreachable state and provide a one-command cleanup hint

Why this matters

Subagent runs often time out, get interrupted, or get superseded by a rerun. If a child sent contact_supervisor(reason: "need_decision") shortly before exiting, the supervisor session can keep receiving/seeing stale asks that are no longer actionable.

Suspected area

reply-tracker.ts stores pending asks and only removes them on explicit markReplied(...) or timeout cleanup. In the failed delivery path for reply, the tracker does not appear to mark the ask as stale or remove it.

Likely relevant paths:

  • reply-tracker.ts
  • index.ts reply action around replyTracker.resolveReplyTarget(...) / connectedClient.send(...)
  • broker delivery failure reason: Session not found

Suggested fix

When sending a reply to a pending ask returns delivered: false with reason: "Session not found", mark that pending ask stale or remove it from replyTracker. Also consider exposing explicit dismissal so users/agents can clear known-stale asks without waiting for the configured timeout.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions