Repository navigation
feat(agents): open a working agent's transcript from its activity - #2276
Conversation
Choosing an agent in the activity under a message now opens that conversation's transcript, as the composer's Working now bubble does. The sidebar's Working now list does the same when the conversation is known: a Solo chat, or a request whose message is loaded. A profile opened from a Solo chat or DM treats it as one conversation, as agents keep it, so the transcript is found at once instead of after a search for a thread session that cannot exist. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
A transcript opening now opens the agent's one Activity destination and asks for the transcript alongside it, so an Activity tab already open is reused instead of joined by a second one. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
…ranscript A transcript request now switches a reused profile tab to its Activity section, through the same unsaved-change guard as choosing the tab, so the transcript opens without another click. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
kalvinnchau
left a comment
There was a problem hiding this comment.
🤖 One target-normalization issue remains; see inline comment.
The transcript is asked for alongside the Activity destination, never as a variant of it, so no link can open a second Activity tab. Openers that know the conversation ask with openProfileTranscript. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, with independent Rocket, Mantis and Groot coverage.
No actionable findings or required changes at head ee499d745216b66d69571f796671e4cfdb52bff4 against base 5adf97f5cb5652dda0d0833d4b869b5c8dab3cda. Reviewed the message/sidebar/composer openers, one Activity destination, context retargeting, Solo/DM normalization, request consumption, save/discard guards and transcript lookup/refresh/focus lifecycle. The public description and feature commit messages were inspected; there are no attached images.
Source-only limitations: no tests, builds or app execution were performed for this review. Native sidebar behavior, rendered accessibility/focus and performance remain unverified. Pi retains its existing manual transcript picker rather than automatically opening a transcript. The description’s sidebar integration and non-owned profile test gaps remain. A one-time hosted-check snapshot reported 39 successes and two skips (browser flake check and Windows native validation); that does not establish those unexercised workflows. This is a COMMENT review, not approval or merge authorization.
Keep one Activity destination per agent: main's new "View full activity" and "View transcript" entry points now open the plain Activity target and ask for the transcript through openProfileTranscript. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
kalvinnchau
left a comment
There was a problem hiding this comment.
🤖 One transcript-navigation defect and one regression-coverage gap; see inline comments.
| if ( | ||
| target && | ||
| props.canOpen(target) && | ||
| openProfileTranscript(target, props.open) |
There was a problem hiding this comment.
🤖 [P2] Preserve the message root for response activity. For a thread-scoped agent with a saved request transcript, choosing the agent here or “View full activity” opens channel Activity instead of that transcript. Reproduced in Chromium and WebKit: lookup receives only the channel ID, performs zero transcript reads, and shows “This channel” / “No Claude session here yet”; opening the same work from the sidebar reads the saved transcript. This accessory now uses response placement (index.tsx:33), but MessageRow.tsx:1389 still supplies raw onOpenLink to that slot, losing row.threadRootId ?? row.id. Pass openLink to the response slot and extend MessageRow.test.tsx:1667 to cover response placement.
There was a problem hiding this comment.
🤖 Fixed in e30b1a5. The response slot now gets the row's openLink, so it keeps row.threadRootId ?? row.id. The MessageRow test now covers both message and response placements, and with the old onOpenLink the response cases fail.
| fireEvent.click(popup.getByRole("button", { name: "View full activity" })); | ||
| expect(f.props.open).toHaveBeenCalledExactlyOnceWith( | ||
| `buzz:profile?agent=${A}&tab=activity&open=transcript`, | ||
| `buzz:profile?agent=${A}&tab=activity`, |
There was a problem hiding this comment.
🤖 [P3] Retain transcript-request assertions for the converted entry points. This assertion and the recorded-history assertion around line 1450 now check only the plain Activity target. Replacing either openProfileTranscript call with a bare open would still pass while losing transcript-first behavior; the old target assertion included open=transcript. Add expect(claimProfileTranscript(target)).toBeDefined() after each open assertion, as the per-entry test already does. The helper is already imported.
There was a problem hiding this comment.
🤖 Done in e30b1a5. The recorded-history "View transcript" test now asserts claimProfileTranscript(target). In the "View full activity" test, opening fails on purpose, so it records profileTranscriptRequest at the moment open runs, asserts it was set, and checks that no request is left afterwards. I swapped each openProfileTranscript call for a bare open to confirm these tests then fail.
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account, with independent Rocket, Mantis and Groot coverage.
No new actionable findings or required changes at head 0762fe40190741cd75a031492879db23a196f20a against base d1c9c54d1592fdd5b71d7c79560da310d462071d.
This follow-up checked the merge since reviewed head ee499d745216b66d69571f796671e4cfdb52bff4. The four feature commits remain unchanged; the merge adapts the newer message activity, recorded-activity transcript and composer entry points to the single Activity destination. Reviewed their callers, conversation context, request consumption, tab reuse and existing lookup/cancellation/focus owners. The public description and feature/merge commit messages were inspected; no images are attached.
Source-only limitations: no tests, builds, app execution or CI verification were performed. Rendered focus/accessibility, native sidebar behavior and performance remain unverified. The description’s sidebar integration and non-owned profile test gaps remain; Pi retains its existing manual transcript picker. The description’s human check and test results concern the earlier feature revision, not observed validation of this merge by this review. COMMENT only; no approval or merge authorization.
Agent activity now renders in the response slot, which still passed the row's raw link opener, so its transcript opened channel Activity instead of the message's thread. Give the response slot the row's opener, cover both placements, and assert the transcript request at each converted entry point. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
kalvinnchau
left a comment
There was a problem hiding this comment.
🤖 One remaining test-isolation finding.
| ); | ||
| const activity = `buzz:profile?agent=${A}&tab=activity`; | ||
| expect(f.props.open).toHaveBeenCalledWith(activity, { rootId: root }); | ||
| expect(claimProfileTranscript(activity)).toBeDefined(); |
There was a problem hiding this comment.
🤖 [P3] Isolate the recorded-history transcript request before asserting it. The earlier test around lines 407–445 leaves an unclaimed request for the same Activity target in the module-level map, so this assertion can consume that stale request. Replacing ActivityGroupActions.tsx:133's openProfileTranscript call with bare open makes this test fail alone (-t "hands request controls"), but the complete file still passes 40/40. Clear/claim the target before the click, or assert a newly created request distinct from the previous one, so the normal file run detects loss of transcript-first behavior.
There was a problem hiding this comment.
🤖 Fixed in db1d721. The file's afterEach now claims any leftover transcript request for each agent's Activity target, and the local-failure test claims the request it makes. With the file run as a whole, replacing openProfileTranscript with a bare open now fails the recorded-history test in ActivityGroupActions, and the two accessory tests in ActivityAccessory.
Transcript requests live in a module-level map, so a request one test left unclaimed could satisfy a later test's assertion. Clear them after each test and claim the request the local-failure test makes. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
Both activity popups opened the same transcript twice: an "Activity" heading and the agent's own row. Remove the heading. In the working preview, an agent's row now opens its Activity on the conversation's transcript wherever the work is, instead of opening a thread from the timeline; work in several threads still opens Activity without a transcript. Rows fall back to the conversation when Activity can't open. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
kalvinnchau
left a comment
There was a problem hiding this comment.
🤖 Two validation findings: browser journeys still target the removed heading, and typing-indicator tests retain transcript request state.
🤖 [P2] Update browser journeys alongside the removed heading. agent-activity.spec.mjs:217,243,633 and agent-activity-overhaul.spec.mjs:280 still select View full activity. Two unchanged journeys fail in both Chromium and WebKit at this head, preventing downstream navigation/focus/recovery assertions; CI run 41869896491 corroborates the failures. Retarget the locators to the agent rows and update the keyboard tab step while retaining downstream assertions. Copies of the channel/thread journeys with only those adaptations pass 4/4. Also update the stale locators in solo-workspace.spec.mjs:191,203,224 (their failures were not separately reproduced).
🤖 [P3] Clear transcript requests between typing-indicator tests. The retained-trigger and click/Enter/Space tests around lines 467 and 493 leave requests in the module-level map, while afterEach only unmounts components. A temporary assertion that no request exists at the start of the line-575 test fails with expected 7 to be undefined; this assertion therefore consumes state that can predate its own click. Mirror the ActivityAccessory test cleanup by claiming both agents' Activity targets after each test. The leak is reproduced; a currently masked production regression was not demonstrated, since disabling the shared opener still fails this file.
The activity popups no longer have a separate "View full activity" heading. Browser journeys now open an agent's Activity from its row, check that the heading is gone, and expect keyboard opening to focus the first agent row. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
Requests that one test left unclaimed could satisfy a later test's assertion. Claim both agents' Activity targets after each test, as the ActivityAccessory tests do. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
|
🤖 Both addressed:
The JavaScript (1/4) failure in |
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Carl, an automated reviewer, commenting via Wes's GitHub account.
No blockers at cc12da476. Reviewed with independent lanes for user-facing behavior, state/contracts (request registration and claim, reused-tab retargeting and discard guard, sidebar handoff, Solo/DM normalization) and tests (browser locator retargeting, request-map cleanup, both accessory placements). Earlier resolved threads were not re-filed.
Two non-blocking suggestions on the sidebar path are inline. Optional, already true before this PR: ActivityAccessory rows don't hand focus back to the trigger before opening the way the composer's AgentChooser does, so closing the panel has nowhere to return focus.
Not verified by this review: no suites or browser runs were executed. Current-head CI was still pending (7 pass, 34 pending, 1 skipped). The sidebar-to-panel integration and timeline per-request row gaps remain as the description says. Merge criteria: green current-head CI. This is a comment, not an approval.
| const channel = channels | ||
| .list() | ||
| .channels.find((item) => item.id === channelId); | ||
| if (channel?.channelType === "solo") return {}; |
There was a problem hiding this comment.
🤖 [P3, non-blocking] Treat a DM like a Solo chat here. ProfilePanel.openedFrom and the runtimes key a DM as one conversation, but this only special-cases solo. A DM in the sidebar therefore opens the transcript only when the request row is in the loaded window and workingAgentDetails has a single messageId, and otherwise falls back to the overview. The same click gives different results depending on cache state. Suggest if (kind === "solo" || kind === "dm") return {};, plus a DM case in working-agents.test.ts.
There was a problem hiding this comment.
🤖 Done in bf7243e. activityTranscript now treats dm like solo, matching ProfilePanel.openedFrom, and working-agents.test.ts has a DM case whose request message isn't loaded.
| if (channel?.channelType === "solo") return {}; | ||
| const row = | ||
| messageId && | ||
| channels.window(channelId).rows.find((item) => item.id === messageId); |
There was a problem hiding this comment.
🤖 [P3, non-blocking] For streams, this finds the conversation only when the request row is already in that channel's loaded window. The sidebar matters most for a channel you aren't viewing, and if its window wasn't loaded this session, the click always opens the overview. Hosted local agents, the ones with transcripts, already carry threadRootId on their LocalWork (local-activity.ts:23), and workingAgentDetails already picks the single active work. Consider returning that root with messageId when exactly one local work is active, and using the window row only as the fallback for relay turns. This is within the description's stated limit, so it can be a follow-up.
There was a problem hiding this comment.
🤖 Agreed. Taking the root from the single active LocalWork would cover streams that aren't loaded. Since it's within the stated limit, I'll leave it for a follow-up rather than grow this PR, and the description's "Not yet covered" section now notes it.
A DM is one conversation, as ProfilePanel and the agent runtimes treat it, but the sidebar only special-cased Solo chats. A DM opened the transcript only when its request message happened to be loaded. Treat a DM like a Solo chat. Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: tulsi <tulsi@block.xyz>
Picks up #2444, which fixes the harness-kit workflow-mention test that was failing on main. Signed-off-by: tulsi <tulsi@block.xyz> Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: John Tennant <jtennant@block.xyz> Co-authored-by: Damon <8a08290d889f1c68921542bfe9631d4cd671be9bea5f1114951f386819e4c10a@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * origin/main: feat(agents): identify plugins in native hook output (#2299) [4/5] Add protection to the Codex harness plugin (#1879) feat(search): show member counts on channel results (#2333) Fix the mute icon flashing when selecting a channel (#2287) feat(agents): open a working agent's transcript from its activity (#2276) test(agents): refuse a real relay workflow mention in the harness kit (#2444) fix(agents): catch up every event watch on the kinds it watches (#1852) Keep local artifact collections current (#1507) feat(members): add several people to a chat in one write (#2010)
Co-authored-by: Honor <e0bf479eeebe47dde1e35705212a4df70616a7bc834d907ddfb18cf0405f8b1b@seiler-test.communities.public.builderlabstaging.xyz> * origin/main: feat(agents): identify plugins in native hook output (#2299) [4/5] Add protection to the Codex harness plugin (#1879) feat(search): show member counts on channel results (#2333) Fix the mute icon flashing when selecting a channel (#2287) feat(agents): open a working agent's transcript from its activity (#2276) test(agents): refuse a real relay workflow mention in the harness kit (#2444) fix(agents): catch up every event watch on the kinds it watches (#1852) Keep local artifact collections current (#1507) feat(members): add several people to a chat in one write (#2010) Signed-off-by: Brad Seiler <seiler@squareup.com>
* origin/main: Open any Inbox filter view by route (#2394) fix(bestie): deleting an agent saves no Bestie record where there was none (#2420) fix(unread): never treat agents-audience messages as unread (#1552) feat(focus): add an optional Focus plugin that quiets everything except Solo chats (#2277) [5/5] Add protection to the Goose harness plugin (#839) feat(agents): identify plugins in native hook output (#2299) [4/5] Add protection to the Codex harness plugin (#1879) feat(search): show member counts on channel results (#2333) Fix the mute icon flashing when selecting a channel (#2287) feat(agents): open a working agent's transcript from its activity (#2276) Signed-off-by: Michael Neale <michael.neale@gmail.com> # Conflicts: # crates/plugin-manager/tests/management.rs # src/app/pages.integration.test.mjs # src/features/agent-harness/acp/process.ts
…-service * origin/main: (73 commits) fix(bestie): deleting an agent saves no Bestie record where there was none (#2420) fix(unread): never treat agents-audience messages as unread (#1552) feat(focus): add an optional Focus plugin that quiets everything except Solo chats (#2277) [5/5] Add protection to the Goose harness plugin (#839) feat(agents): identify plugins in native hook output (#2299) [4/5] Add protection to the Codex harness plugin (#1879) feat(search): show member counts on channel results (#2333) Fix the mute icon flashing when selecting a channel (#2287) feat(agents): open a working agent's transcript from its activity (#2276) test(agents): refuse a real relay workflow mention in the harness kit (#2444) fix(agents): catch up every event watch on the kinds it watches (#1852) Keep local artifact collections current (#1507) feat(members): add several people to a chat in one write (#2010) feat(solo): let viewers join read-only spaces (#2301) [3/5] Add protection to the Claude harness plugin (#1878) fix(settings): keep the bottom padding on long sections (#2361) fix(mermaid): cap diagram output size (#2231) feat(agents): give plugin agent types the Buzz side of a turn (#2364) feat(plugins): pin buzz://plugin-install links to a path and commit (#2315) feat(plugins): tint currentColor SVG page icons like host icons (#2314) ... # Conflicts: # src-tauri/src/host_process.rs # src-tauri/src/lib.rs # src/bundled/claude-code/claude.ts # src/bundled/codex/rpc.ts # src/bundled/goose/goose.ts # src/bundled/goose/runtime.ts # src/bundled/goose/sessions.test.ts # src/bundled/goose/sessions.ts # src/features/agent-harness/acp/process.ts
* origin/main: (22 commits) feat(mentions): quieter mention menu that marks agents and their owners (#2328) feat: add a Canvas View tab, History diffs and a 256 KiB limit (#2318) feat(plugins): let local agents write and reload plugins (#2435) feat(onboarding): offer Create a community after public Builderlab sign-in (#2397) Open any Inbox filter view by route (#2394) fix(bestie): deleting an agent saves no Bestie record where there was none (#2420) fix(unread): never treat agents-audience messages as unread (#1552) feat(focus): add an optional Focus plugin that quiets everything except Solo chats (#2277) [5/5] Add protection to the Goose harness plugin (#839) feat(agents): identify plugins in native hook output (#2299) [4/5] Add protection to the Codex harness plugin (#1879) feat(search): show member counts on channel results (#2333) Fix the mute icon flashing when selecting a channel (#2287) feat(agents): open a working agent's transcript from its activity (#2276) test(agents): refuse a real relay workflow mention in the harness kit (#2444) fix(agents): catch up every event watch on the kinds it watches (#1852) Keep local artifact collections current (#1507) feat(members): add several people to a chat in one write (#2010) feat(solo): let viewers join read-only spaces (#2301) [3/5] Add protection to the Claude harness plugin (#1878) ... Signed-off-by: Gil Birman <gil@squareup.com> Co-authored-by: Claude <noreply@anthropic.com>
…r-load-perf * origin/main: Open any Inbox filter view by route (#2394) fix(bestie): deleting an agent saves no Bestie record where there was none (#2420) fix(unread): never treat agents-audience messages as unread (#1552) feat(focus): add an optional Focus plugin that quiets everything except Solo chats (#2277) [5/5] Add protection to the Goose harness plugin (#839) feat(agents): identify plugins in native hook output (#2299) [4/5] Add protection to the Codex harness plugin (#1879) feat(search): show member counts on channel results (#2333) Fix the mute icon flashing when selecting a channel (#2287) feat(agents): open a working agent's transcript from its activity (#2276) Signed-off-by: Will Pfleger <wpfleger@block.xyz> # Conflicts: # src/features/agent-harness/acp/agent-sessions.ts
What
How
ActivityAccessoryopens the agent's Activity target throughopenProfileTranscript, the same mechanism the composer bubble uses.MessageRowopens message accessories in the row's own thread, as links in its body already do.ChannelsPagethrough the existing activity-agent handoff (activityTranscriptinworking-agents.ts).&open=transcriptvariant from feat(agents): open the latest transcript from agent activity #1830 is gone, so no link can open a second Activity tab. Openers that know the conversation callopenProfileTranscript, which keys the request by that target.ProfilePanelreads requests for any Activity target.ProfilePanel.openedFrommakes the Solo/DM rule apply to every route that opens a profile.Validation
tscand biome are clean. Full vitest run onee499d745: 884 files and 15,655 tests passed. An earlier run, on a heavily loaded machine, failed once in an unchanged MessageComposer mention-completion test, which passed on rerun.Not yet covered
LocalWork.threadRootId), as Wes suggested.ChannelsPageto the open panel, for either a known conversation or the fallback. The pieces are unit-tested.ProfileDetails) gets the same switch to Activity but has no test of its own.🤖 Generated with Claude Code