Skip to content

feat(agents): deliver Attention watches and timers to conversations - #1578

Open
johnmatthewtennant wants to merge 21 commits into
mainfrom
jtennant/aaron/attention-delivery
Open

johnmatthewtennant wants to merge 21 commits into
mainfrom
jtennant/aaron/attention-delivery

Conversation

@johnmatthewtennant

@johnmatthewtennant johnmatthewtennant commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Why

An Attention watch can listen in one channel while its agent needs to continue work in another conversation. Watches and timers currently run independent turns with no default reply destination.

What

Add optional channel and root delivery fields to event watches and timers. An address selects the execution conversation and default posting destination. Explicit reporting instructions in the Interest take precedence. Omitting an address keeps the independent Interest turn.

Attention instructions retain their own framing, separate from plugin output. A channel-only address defaults to channel-level posting while allowing the Interest to direct a thread reply. Solo chats retain their reply restriction, and Pi continues to ignore ordinary plugin wakes. Each Interest keeps its existing execution lane.

An addressed timer waits without spending an occurrence until destination membership is confirmed. watch_show distinguishes held membership confirmation from blocked nonmembership. Expiry still applies while held. The Attention panel displays listening and delivery locations separately.

Validation

The service regression reproduces a one-shot timer being spent without a turn when its destination roster is cached or excludes the agent. With the fix, the timer retains its budget, exposes the reason and runs once after membership is confirmed. A cross-channel event fixture delivers to the configured channel and thread rather than its listening channel.

All four harness fixtures exercise channel-level Attention framing. The Codex runtime fixture also calls send with an existing thread reply from a channel-level wake and verifies the published reply tag. Existing Solo-chat tests retain the reply ban. Pi tests verify unrelated plugin wakes are ignored and recovered answers retain their saved posting destination. These fixtures mock the model process and signing boundary.

A queued Codex regression uses the latest Interest instructions when its wake starts. Held Goose and Pi fixtures verify that a different posting policy waits for the active turn and that cancellation drops queued work.

In the running combined daily driver, a one-occurrence timer delivered into an existing Codex conversation and a command source woke the same session, then was removed automatically. This live evidence uses the earlier combined build, not the final review-fix head. Cross-channel live delivery, native platform acceptance and human testing remain unverified.

Screenshots

The Attention panel shows a timer and event watch delivering to the review channel.

Attention listening and delivery locations

Limits

Queued wakes do not provide durable delivery acknowledgements across app exit. The Codex session key moves to v9 to pick up the changed tool contract, which starts fresh context once for existing Codex agent conversations.

johnmatthewtennant and others added 20 commits October 23, 2026 10:07
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Keep both independent service test groups and advance the combined Codex session schema to v9.

Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
@johnmatthewtennant
johnmatthewtennant marked this pull request as ready for review October 23, 2026 20:05
@johnmatthewtennant
johnmatthewtennant requested a review from a team as a code owner October 23, 2026 20:05

@loganj loganj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 Larry and Auto: an independent adversarial review of d8eaa206d. We only read the source: we did not run tests or the app. Each of us reviewed it alone, and this review combines both.

The direction is good. An optional delivery address on event watches and timers is a small, useful addition. We are not approving yet because of three must-fix items. Each one gives a realistic case where the agent gets the wrong instructions or a timer is spent silently, and the fixes change the behavior enough to need another look.

Must-fix

  1. An addressed wake is framed as a plugin wake, so the agent is told to treat its own Interest instructions as data (runner.ts:207).
  2. A channel-level address uses the Solo-chat posture in all four harnesses: a "continuous personal chat" prompt, and send rejects reply (claude-code/runtime.ts:456).
  3. A timer occurrence is counted before delivery. A wake dropped for an unconfirmed or missing membership spends the occurrence silently (runner.ts:2073).

Questions

  • Pi now accepts every plugin wake, not only Attention ones. Was that intended? (pi/runtime.ts:424)
  • The destination now lives in two places: the Interest instructions and the watch address. Which one wins? (buzz-mcp/attention.ts:144)

Smaller items (optional)

  • Completeness: the docs and the Janet parity doc still describe the old plugin-wake and runOnce contract (docs/agents.md:887).
  • Simplicity: the runner has redundant branches, and the delivery target is computed twice (runner.ts:1780).
  • Simplicity: each harness does (await wakeText?.()) ?? wake.text and then relies on a later current() check. wakePrompt returns undefined exactly when the wake should not run, so dropping on undefined in one place would be simpler and safer than falling back to stale text.
  • Advice: the Codex session key moves to v9 (codex/runtime.ts:620). That is correct by convention, but it resets every Codex agent's context once. Please say so in the description. #1553 will probably change the tool text again, so one bump for both PRs would avoid a second reset.
  • Convention: there are whitespace-only changes: the type enum and the clear loop braces in buzz-mcp/attention.ts, the enqueue(...) call in runner.ts, and a blank line in goose/runtime.ts.
  • Preference: in the Attention panel, an unnamed single-channel watch shows "Messages in #foo" and "Listens in foo". Every unaddressed row also gains "Independent turn for this Interest". Showing the delivery line only when an address is set would be quieter.

Checked and not a problem: the Claude Code open(…, 0) + touch change (the watermark uses max), the Codex steer and execute re-checks, Goose discarding a queued wake on Interrupt, and the lane hold for addressed turns (workingUntil holds the Interest lane until the conversation turn settles).

Comment thread src/features/agents/runner.ts Outdated
Comment thread src/bundled/claude-code/runtime.ts
Comment thread src/features/agents/runner.ts
Comment thread src/bundled/pi/runtime.ts Outdated
Comment thread src/buzz-mcp/attention.ts
Comment thread docs/agents.md Outdated
Comment thread src/features/agents/runner.ts Outdated
Comment thread src/buzz-mcp/attention.ts Outdated
@johnmatthewtennant
johnmatthewtennant marked this pull request as draft October 23, 2026 20:37
Separate conversation Attention wakes from plugin data, allow explicit thread replies from channel-level delivery, and hold timers until destination membership is confirmed.

Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
@johnmatthewtennant

Copy link
Copy Markdown
Contributor Author

🤖 The remaining review suggestions are dispositioned as follows:

  • The description now discloses the one-time Codex v9 context reset. Delivery remains the owner of that bump; source work can reuse it when integrated.
  • The runner reuses one wake anchor and restores the redundant branch to its simpler form. The unrelated enum, clear-loop and enqueue formatting were restored where compatible with the formatter.
  • I retained the existing prompt fallback plus the final current() cancellation checks. Those checks cover invalidation of the delivery and history as well as prompt construction; the queued-history and cancellation regressions verify that invalidated work never reaches the model. Changing every harness’s prompt callback cancellation contract solely for this optional simplification would expand this fix.
  • I retained the explicit independent-turn row text. It makes the absence of a conversation destination visible, which matters when a row otherwise looks like an addressed watch. I also retained the listening location for an unnamed watch so the same row structure identifies listening and delivery consistently. These are deliberate presentation choices, with no UI change in this fix batch.

The three must-fix cases and both contract questions are addressed in 056c602da. The PR remains draft while current-head CI runs.

@johnmatthewtennant
johnmatthewtennant marked this pull request as ready for review October 23, 2026 21:12
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.

2 participants