Repository navigation
Let a plugin leave a note for an agent's next turn - #1466
Conversation
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot review lanes.
Reviewed head 99884931cd8057dc47997e612e3e0082f315c601 against base/merge-base b2a272bd705350ba514ea6c512f6deb2c842818c. 8/10: one concrete recovery defect, detailed inline. The small runner-owned API and captured-note reuse otherwise fit the stated goal.
Reviewed the changed source/tests, runtime delivery and retry callers, plugin trust model, public PR description and feature commit messages. No public-material disclosure finding; the description has no image attachments.
Source-only: no tests, builds or app execution. One hosted-check snapshot showed CI required, JavaScript, Rust and browser checks successful; Windows validation and the conditional browser flake check were skipped. Live plugin-to-agent delivery, native timing, error/retry interaction and human acceptance remain unverified. This is a non-blocking COMMENT review, not approval or merge authorization.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot review lanes.
Reviewed head ffe3033fb8c8be904933912d451eeac787b6da27 against base b2a272bd705350ba514ea6c512f6deb2c842818c, concentrating on the changes since reviewed head 99884931cd8057dc47997e612e3e0082f315c601.
The explicit goose startup/expiry and Codex refusal paths now restore notes. One remaining Claude recovery path still loses them before a replacement turn starts; details and the smallest repair are inline. Source assessment: 8/10 pending that repair.
Validation: immutable-source inspection, callers and regression-test review, and git diff --check; no PR code, tests, builds or app executed. The public description has no attached images; no disclosure issue found in the inspected description and new commit messages. A single hosted-check snapshot still had JavaScript, Rust and browser jobs running; Windows validation was skipped. Live provider behavior, native acceptance, rendered focus/accessibility and performance remain unverified. This is non-blocking COMMENT feedback, not approval or merge authorization.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot review lanes.
Reviewed head d9f52febf0112a2607c22977352b2f0cfb5be1d1 against base b2a272bd705350ba514ea6c512f6deb2c842818c, focusing on the four-file follow-up since ffe3033fb8c8be904933912d451eeac787b6da27.
No actionable findings in this follow-up; source assessment: 9/10. The previously reported lost-note recovery path is fixed: failed saved-session deletion or fresh-prompt construction now returns an undelivered result, restoring the captured notes for a later turn and reporting the failure to the conversation. The new tests cover both failure points and next-turn note delivery.
Validation: source/caller and regression-test inspection plus git diff --check; no tests, builds or app execution. The public PR description has no image attachments, and it and the new commit message showed no disclosure issue. One hosted-check snapshot still had JavaScript, Rust and browser jobs running; Windows native validation was skipped. Live Claude recovery, native persistence failures, performance and rendered accessibility/focus behavior remain unverified. This is a non-blocking COMMENT review, not approval or merge authorization.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot review lanes.
Reviewed head 274f436b70eb57afbd6980cae4fcdb210e8be508 against base/merge-base b2a272bd705350ba514ea6c512f6deb2c842818c, focusing on the private-message addition since reviewed d9f52febf0112a2607c22977352b2f0cfb5be1d1 and its interaction with note delivery.
One actionable P2 is detailed inline. Source assessment: 8/10 until private-message timestamps preserve the precision required by Codex history. The earlier note-restoration fixes remain in place. No additional source-demonstrated defects found in queue admission, channel-session routing, private activity/typing/resume/title suppression or visible-turn answer ownership. Channel-only routing, in-memory lifetime and queue-acceptance returns are documented limits. No disclosure issue found in the public description or new commit; the description has no attached images.
Validation limits: source review only; no PR code, tests, builds or apps executed. The one hosted-check snapshot still had JavaScript, Rust and browser jobs running; Windows native validation was skipped. Real provider delivery, desktop behavior, performance, rendered accessibility/focus and human acceptance remain unverified. This COMMENT is not approval or merge authorization.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot review lanes.
No new actionable findings in the two-file follow-up from 274f436. The prior same-second history-cutoff finding (discussion_r4336242381) is addressed: runner.ts derives both created_at and the ms tag from one clock sample, preserving the earlier public message in the reported T+500ms/T+700ms example. The added service regression checks the dispatched timestamp and shared ordering helpers. Source assessment for this bounded repair: 9/10.
Reviewed head: a6f6e51. Base/merge-base: b2a272b. Checked the changed source and callers, hidden success/failure behavior, public PR description (no attached images), and new commit metadata. Existing clock-skew behavior is outside this follow-up’s scope.
Source-only: no tests, builds, app, live model or harness execution. The regression tests the runner and ordering helpers, not an end-to-end runtime history request. A single hosted-check snapshot showed JavaScript, Rust/tool integration, browser measurements and Vitest flake checks successful, with several browser journeys still running and Windows native validation skipped. Desktop behavior, accessibility, live-provider integration and human acceptance remain unverified. This COMMENT is not approval or merge authorization.
A plugin that acts for the owner outside the chat, such as a voice call where the owner talked over an agent's reply, had no way to tell the agent what happened except by posting a visible message. Add `Agents.note(pubkey, channelId, text)`: while this copy runs the agent, the text is held for its next turn in that channel and appended to that turn's prompt, before the Buzz tools' attention note, in the Claude Code, goose and Codex runtimes. It returns false otherwise, so the plugin can say it another way. Notes live in memory only. Signed-off-by: John Tennant <jtennant@block.xyz> Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each runtime took an agent's notes before preparing its turn, so a turn whose reads failed, or whose delivery was cancelled or ran past its deadline while it was prepared, lost notes `Agents.note` had accepted. Take them only once the prompt is ready to hand to the harness: Claude Code and goose just before giving it to the session, keeping them for a fresh session's rebuilt prompt, and Codex when the turn's input is first built, keeping them with the request if it is retried. Signed-off-by: John Tennant <jtennant@block.xyz> Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A mention takes its channel's notes when it is handed over, but goose can still give up opening its session, and Codex can refuse a steer. Either way no turn took the notes in, and the next mention had none. Put them back, ahead of any left since, when delivery definitely never happened: goose's expired opening, and Codex's refusal answer. A transport failure or timeout leaves them taken, since the turn may have begun. Signed-off-by: John Tennant <jtennant@block.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A message whose goose or Claude session could not open, or whose runtime stopped before a turn took it in, never reached a turn, and neither did one Codex refused to start. Their notes were lost all the same. Mark these failures before the message is handed to a session as undelivered, apart from failures after a turn took it in, and put the notes back for the next turn. Signed-off-by: John Tennant <jtennant@block.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A saved Claude session that no longer loads starts over: its saved entry is forgotten and the conversation rebuilt for a new one. If either fails, delivery rejected after the turn had taken its channel's notes, and nothing put them back. Nothing has taken the message in at that point, so report it as a failure that was never delivered, which restores the notes and tells the thread. Signed-off-by: John Tennant <jtennant@block.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1d80e02 to
8efcc5a
Compare
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot lanes.
9/10 — no new actionable findings in this rebase and plugin-wake integration. Range-diff against the previously reviewed note commits shows three recovery patches unchanged and two adjusted for the new base’s plugin-wake trigger. The two later private-message commits were removed; the current description correctly scopes this PR to notes alongside the base’s ctx.agents.wake.
Checked lazy note consumption, cancelled/ignored wake handling, Claude lost-session restoration, Goose startup/expiry restoration, Codex refused start/steer handling and retry ordering. The existing policy remains: restore notes ahead of newer notes when delivery definitely never began; do not restore after ambiguous transport failures. No new timer, process or pool owner is introduced. Public description and five commit messages inspected; no attached images or disclosure finding on those surfaces.
Reviewed head 8efcc5a9aa72215788d21b7e701b603287f99bdf, base d9793a8dcf9052271b0e87365a9c7b189c512fa5. All independent lanes completed and were reconciled against the pinned source. This is a follow-up review of the changed integration and prior repairs, not an exhaustive re-review of unrelated new-base changes.
Source-only: no PR code, tests, builds, app or live harness executed. Diff check passed. One hosted snapshot showed CI required and completed validation checks successful; Windows native validation and browser flake checks were skipped. Native timing/performance, live-provider recovery, end-to-end plugin-to-runtime delivery, rendered error/retry/focus behavior and human acceptance remain unverified. This COMMENT is not approval or merge authorization.
Co-authored-by: Aaron <f425b86c3b780d43f8d9cf1802429d04dd985bf92eac44fca9468b5ad3887c5e@buzz.block.builderlab.xyz> Signed-off-by: John Tennant <jtennant@block.xyz>
|
🤖 Please refresh the automated review of current head |
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot lanes.
9/10 — no required changes in the 10-file follow-up from 8efcc5a9aa72215788d21b7e701b603287f99bdf. Thread note consumption and restoration use the same captured conversation root in Claude, Goose and Codex. The runner keeps thread queues separate, preserves their order, and retains the existing definite-undelivered recovery policy without adding a lifecycle owner.
Optional recovery improvement: src/features/agents/runner.ts:2127–2137 restores every entry with the consuming session’s root. When a channel-scoped turn takes thread-targeted notes and never starts, restoring with undefined loses those original targets. If scope changes to thread before another turn, those notes remain unconsumed. Preserving the original per-note roots would cover this edge; this is optional and no change is required for this review. It is separate from the documented rule that deliberately rootless notes are channel-only.
Reviewed head a08d14ad164a6231fdb1d5ee8ef6f023c5bf1fde, base d9793a8dcf9052271b0e87365a9c7b189c512fa5. All three independent lanes completed and were reconciled. Public description and the follow-up commit inspected; no attached images or disclosure findings on those surfaces.
Source-only follow-up: no PR code, tests, builds, app or live harness executed; CI was not assessed this cycle. Diff check passed. The source tests cover runner isolation and runtime root arguments, while restoration mocks remain channel-keyed; this does not prove end-to-end plugin-to-runtime restoration. Native performance, live-provider failure/retry, rendered focus/accessibility and human acceptance remain unverified. This COMMENT is not approval or merge authorization.
|
🤖 Aaron: Disposition of the optional recovery suggestion: defer to a separate follow-up. The current contract restores to the consuming conversation; preserving each original target would extend the text-only runtime note handoff. The edge requires a channel-scoped turn to fail before starting and then a scope change before retry. Channel-scoped retry still consumes the restored notes. I have tracked a follow-up covering original-target retention and mixed-root ordering across failure/scope change, including deliberate rootless notes remaining channel-only. This limitation remains in the release; no code change or new validation is claimed. The current-head 9/10 review has no required changes. Required team approval is still outstanding. |
loganj
left a comment
There was a problem hiding this comment.
Scope concern addressed at a08d14a: thread sessions pass their root and take only that root's notes; channel sessions take channel-wide notes. Covered by the isolation and restore-order test in service.test.ts. Local-only delivery is a known limit; plugins get false and can fall back to a message.
Co-authored-by: John Tennant <jtennant@block.xyz> * origin/main: test(settings): match the Usage plugin name in scroll regression (#1488) Let a plugin leave a note for an agent's next turn (#1466) Read goose memory through the shared connection-scoped MemoryReads (#1476) Make Claude's standalone turns honour the runner's deadline signal (#1477) feat(plugins): simplify manual plugin management in settings (#1397) feat(relay-notes): add a folder-based shared notes reader (#1395) feat(buzz-mcp): create and list system channels (#1465) Unify profile headers and polish agent activity controls (#1405) Polish video timestamp chips and open videos with context (#1474) GitHub integration: gh-backed panel with checklist and merge, Solo PR link, and watch_pr (#1325) Estimate Codex costs in Usage with genai-prices (#1458) improve agent activity hierarchy and transcript spacing (#1421) Signed-off-by: Gigi <65cc00ce5da00abcd27be4a87ad29d7ef8431766d769a24d94f004fb8fe07066@buzz.block.builderlab.xyz>
Why
Plugins can reach an owned agent only by posting a visible message, or by waking it with
ctx.agents.wake. Sometimes a plugin acting for the owner just needs the agent to know something on its next turn, with no reason to wake it and nothing for the channel to see. The Berd Call plugin needs this. When a call starts, it tells the agent it is on a voice call, which shouldn't wake anyone. When you talk over an agent's spoken reply, it tells the agent how much you heard; today it posts "(I interrupted your reply after …)" in the chat, where everyone sees it.What
Agents.note(pubkey, channelId, text, root?)holds context for an agent’s next turn without waking it. A thread-scoped session consumes only notes addressed to that thread root. A channel-scoped session, DM or Solo chat consumes notes across its channel. Omitting the root targets the channel conversation, so a turn in another thread cannot take those notes. It returns false when this copy of Buzz doesn't run the agent, so the plugin can fall back to posting. Notes live in memory only, so any still waiting when the app quits are lost.turnNote). This works in Claude Code, goose and Codex, including a message that steers a running Codex turn.AgentHandle.notes(channelId, root?)andAgentHandle.restoreNotes(channelId, notes, root?)are optional, so agent types that don't take notes still compile.Validation
These checks exercise two boundaries.
Production service and runner. These tests use a fake relay, a fake native publisher and a stub agent type.
Each production runtime against a fake harness. Goose uses a fake ACP process, Claude Code a fake stream-json process, and Codex a fake app-server.
Thread-isolation coverage verifies that each thread consumes only its addressed notes.
No test runs the runner and a real runtime together, and nothing ran against a live model or in the desktop app.