Skip to content

feat(agent): deliver child results to parent mailboxes - #1316

Draft
sentry-junior[bot] wants to merge 5 commits into
mainfrom
junior/agent-invocation-parent-delivery
Draft

feat(agent): deliver child results to parent mailboxes#1316
sentry-junior[bot] wants to merge 5 commits into
mainfrom
junior/agent-invocation-parent-delivery

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Durable parent-result delivery for terminal child agent invocations (#878 / #883).

  • terminal invocations stamp parentNotificationStatus: pending
  • one idempotent parent-mailbox result is appended, then marked notified
  • permanent builder/destination failures mark failed (queryable, no infinite retry)
  • heartbeat repairs pending parent notifications
  • parent-result delivery shares the synthetic inbound shape with resource events (task-execution/synthetic-inbound.ts) without reusing resource-event subscriptions
  • parent turn authority is restored from the invocation (actor + credentialContext), not a synthetic system principal
  • parent conversation id is always the mailbox identity; Slack envelope is attached when destination is Slack (including agent-dispatch:* parents)
  • dispatch parent-result wakes stay on the dispatch worker and only resume already-started turns
  • local CLI acks parent-result wakes without starting another turn

Design notes

Resource events and agent-invocation results now share one durable mailbox wake shape (stable id, kind + reference, rendered text, optional Slack envelope). They still differ where they should:

resource events parent results
subscription / TTL yes no (invocation-owned outbox)
authority system principal parent actor + credentials from invocation
parent identity subscription conversation parentConversationId on invocation

Policy cleanup

  • dropped dead re-exports / unused builders (createSlackAgentInvocationResultInboundMessage, permanent error wrapper, public render/build helpers)
  • collapsed duplicated dispatch parent-result handling into the shared worker path
  • split oversized invocation work tests; parent-delivery contracts live in agent-invocation-parent-delivery.test.ts
  • dispatch routing contracts live in the owning agent-dispatch-work suite (pending wake + resume)
  • integration tests assert product behavior (authority restore, failed notify, dispatch routing), not raw envelope metadata

Test plan

  • pnpm --filter @sentry/junior exec vitest run tests/integration/agent-invocation-work.test.ts (10/10)
  • pnpm --filter @sentry/junior exec vitest run tests/integration/agent-invocation-parent-delivery.test.ts (3/3)
  • pnpm --filter @sentry/junior exec vitest run tests/integration/agent-dispatch-work.test.ts (9/9)
  • pnpm --filter @sentry/junior exec tsc -p tsconfig.json --noEmit
  • oxlint + file-length + test-architecture checks clean
  • CI green on PR

Fixes #878
Refs #883

Persist terminal agent-invocation parent notification state and append one
idempotent parent-mailbox result so idle parents can resume from durable child
work. Heartbeat repair retries pending parent delivery, and Slack synthetic
result messages force a parent turn without depending on resource-event
subscriptions.

Fixes #878
Refs #883

Co-Authored-By: David Cramer <david@sentry.io>
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview Aug 8, 2026 2:12am

Request Review

@sentry-junior sentry-junior Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Self-review against #878 / #883 after opening this.

The pending → append → notified outbox shape fits the shared conversation worker story: durable invocation state, stable parent mailbox identity, queue-as-wake, heartbeat repair. Keep that.

Two design holes before this should land:

  1. Parent-result turns run as the synthetic system actor. Reply/resume treat agent_invocation_result like a resource event (AGENT_INVOCATION_RESULT_SYSTEM_ACTOR). The invocation already stores the parent run's actor + credentialContext, and #883 is explicit that child work must not broaden parent authority. Waking the parent under system credentials means tools/OAuth on that turn use the wrong principal, and bot-authored synthetic messages also pick up disabledFeatures: ["interactive-auth"]. Restore authority from the invocation (or another durable parent-turn reference) when handling the result, same spirit as dispatch routing restore.

  2. Slack synthetic delivery assumes parentConversationId is slack:channel:threadTs. createSlackAgentInvocationResultInboundMessage parses the parent id as a Slack conversation id. That matches ordinary Slack roots, but dispatch conversations are agent-dispatch:<id> (getDispatchConversationId), and production already wires bindSpawnAgent onto the shared runner. Once experimental subagents are on, a dispatch parent that spawns will hard-fail parent delivery in the Slack builder and stay parentNotificationStatus: "pending" forever. Delivery needs to target the real parent conversation work identity, and only build Slack thread metadata when the parent is actually a Slack conversation — not by assuming the conversation id format.

Secondary: #878 asks for permanent notification failure to stay queryable. Today a permanent builder/destination mismatch just leaves pending and retries forever with no terminal failure visibility. Worth a durable failed/notified-failed state (or equivalent) once the two issues above are fixed.

I can fix these next on this branch unless you want a different authority model for parent-result turns.

Co-Authored-By: David Cramer <david@sentry.io>
Share one synthetic inbound builder with resource events, restore parent
authority from the invocation, target non-Slack parents correctly, and
terminalize permanent notification failures.

Co-Authored-By: David Cramer <david@sentry.io>
Move parent-result delivery cases out of the oversized invocation work
suite and cover permanent notification failure terminalization.

Co-Authored-By: David Cramer <david@sentry.io>
Collapse duplicated dispatch parent-result handling into the shared worker
path, drop unused synthetic builders/re-exports, and move behavior-focused
parent delivery coverage into dedicated integration scenarios.

Co-Authored-By: David Cramer <david@sentry.io>

Co-Authored-By: David Cramer <david@sentry.io>
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.

Deliver subagent results through a durable parent outbox

0 participants