Skip to content

📣 Pi agent completion: deliver on the same tick and mark consumed runs - #194

Merged
sdougbrown merged 1 commit into
mainfrom
fix/pi-notification-consumed
Sep 3, 2026
Merged

📣 Pi agent completion: deliver on the same tick and mark consumed runs#194
sdougbrown merged 1 commit into
mainfrom
fix/pi-notification-consumed

Conversation

@sdougbrown

Copy link
Copy Markdown
Owner

Why

The Pi extension's agent-completion notifications were posted in reverse order from intent:

  • A non-blocking sub-agent at terminal status deferred its completion by one poll cycle, then depended on a later cycle to send it. When that run was the last live one, polling stopped after the defer cycle, so the completion never arrived — the agent showed "done" without notifying the session.
  • A run that avenor_result was already awaiting still fired a brief status notification, and the deferred completion could be sent after the result had been consumed, producing redundant notifications.

Changes

  • Send the completion on the same poll tick it is observed, so the last-live-run case is no longer stranded.
  • Suppress the automatic completion once avenor_result has delivered the result. A new consumed flag is set only on a successful (result.ready) call; an interrupted call (aborted, timed out, still waiting) leaves it unset so the completion is still delivered later.
  • Replace the defer mechanism (completionPending) with the consumed flag and a two-state decideCompletion (skip | send).
  • Move the brief status notification into the delivery path, so awaited and consumed runs stay quiet.
  • Build a deterministic waitPollMatching harness helper so the notification tests no longer rely on timer sleeps.

Validation

bun test → 97 pass, 0 fail (3 new integration tests: last-live-run delivery, awaited/consumed suppression, interrupted-avenor_result delivery). bun run build → tsdown clean.

Notes

Removing the defer means a fire-and-forget run that finishes now gets its auto-completion on the next tick; if the caller also pulls avenor_result afterwards, that explicit call surfaces the result separately. This is the agreed tradeoff, not a duplicate status notification.

Non-blocking sub-agents that reached terminal status during a polling tick
deferred the completion message by one cycle, then relied on a later tick to
send it. When the completing run was the last live run, polling stopped after
the defer tick so the completion was never delivered — the sub-agent showed
"done" without notifying the session. The status notification also fired for
runs that avenor_result was already awaiting, producing redundant toasts.

Changes:
- Send the completion on the same tick it is observed, so last-live runs are
  no longer stranded.
- Suppress the automatic completion once avenor_result has delivered the
  result: `consumed` is set only on a successful (non-interrupted) result, and
  re-authorizes delivery if avenor_result is aborted, times out, or still
  waits.
- Replace the defer mechanism (completionPending) with a `consumed` flag and a
  two-state decideCompletion (`skip` | `send`).
- Move the brief status notification inside the delivery path so awaited and
  consumed runs stay quiet.

@umpire-bot umpire-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is marked... SAFE! 🙌

All changed files reviewed — no issues found.

@sdougbrown
sdougbrown merged commit 2d299e0 into main Sep 3, 2026
4 checks passed
@sdougbrown
sdougbrown deleted the fix/pi-notification-consumed branch September 3, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant