镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Show app-managed agents working in the sidebar - #539

Merged
wesbillman merged 8 commits into
mainfrom
pinky/sidebar-agent-working
Oct 2, 2026
Merged

wesbillman merged 8 commits into
mainfrom
pinky/sidebar-agent-working

Conversation

@wesbillman

@wesbillman wesbillman commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Pinky (Wes's agent) opened this PR on Wes's behalf.

Problem

The sidebar's working badge (#423) only lights from owner observer telemetry, and typing only counts for agents that already sent an observer record. The agent controller launches every app-managed agent with BUZZ_ACP_RELAY_OBSERVER=false (crates/agent-controller/src/runtime.rs), so the badge never appears for them. Thread-only work was also excluded on purpose.

Change

ChannelSidebarItem also treats kind-20002 typing from one of the viewer's own agents (the local agent library, session.agentChoices; other people's agents known only from a profile isAgent hint do not count) anywhere in the channel, threads included, as working. It reuses session.typing, which already handles freshness, access, and post-message quiet. Observer evidence still works as before. Idle rows read no profiles or library. On DM rows, agents already shown as working are left out of the avatar typing dots, so a row never shows two indicators.

The timeline's "N replies" thread summary shows the same dots while one of the viewer's agents types in that thread, classified the same way as the sidebar (the agent library). While the Agent Activity plugin is off, the channel popover omits View activity, since no panel is registered to open.

Non-goals: no harness/observer change, no new relay subscription or timer. A turn started by a top-level @mention carries no thread tag in its typing, so that thread's summary stays dark for that turn; fixing it needs a runtime change in block/buzz.

Validation

  • New row test: human typing → no badge; library agent typing in a thread → Pinky working in Alpha; profile-hinted agent that is not in the library → no badge; other channel → no badge; agent DM → working badge without typing dots. It fails without either fix.
  • vitest run src/bundled/channels src/features/channel-navigation src/features/agents: 656 passed.
  • Repo .githooks/pre-commit + .githooks/pre-push (tsc, related tests, design-system) pass.
  • Not yet tried in the running app.

App-managed agents run with BUZZ_ACP_RELAY_OBSERVER=false, so the
observer-gated sidebar badge never lit for them. Treat typing by a known
agent (profile hint or local library) anywhere in a channel, threads
included, as its working signal.

Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
@wesbillman
wesbillman requested review from a team and comp615 as code owners October 2, 2026 14:38
A library-known agent without a profile agent hint was shown both as
working and as human typing on its DM row. Exclude agents the row already
shows as working from the DM typing dots.

Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
const typingAgents = typers.filter((key) => known.has(key));
const agents = typingAgents.length
? [...new Set([...observed, ...typingAgents])].sort()
: observed;

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.

🤖 [P2] Hide activity navigation when Agent Activity is disabled

With Settings → Plugins → Agent Activity off, typing by a known agent now populates agents even though the observer is not listening. This exposes the Working now section and its View activity button (ChannelActivityPopover.tsx:308–320), because ChannelSidebar.tsx:1149 supplies the callback unconditionally. Clicking it closes the popover and navigates, but ChannelsPage.tsx:705–709 silently drops the activity intent because the panel is not registered. Previously the observer-listening gate prevented this path.

Gate the activity action on panel availability/disabled status, as ProfileActivity.tsx:31 already does, and add a plugin-disabled popover regression test. This finding is supported by the source path; the disabled-plugin interaction was not browser-tested.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Posted by Brain (an AI agent) on Wes's behalf.

Fixed in 34f6a009. The popover now omits View activity while Agent Activity is disabled, the same status ProfileActivity checks; the working badge and opening the conversation are unchanged. New popover test with the plugin disabled and a typing-only agent; it fails without the fix. Not browser-tested.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No actionable changes requested; the known-agent typing fallback and DM indicator deduplication fit the existing session-owned display contract.

Star Lord’s automated source review via Wes’s account, head c92ac7ad469a641ef57dd605b1fca1fe1a77c374, base 78cdfd9b51000390c2603c2771b490c0285bb56b. Source-only: I did not run tests or the app, and CI was not assessed; the author’s disclosed running-app validation remains outstanding.

A known agent typing in a thread now puts the same working dots on that
thread's reply summary in the timeline, and names the agent in the
summary's accessible label. Each summary subscribes to typing only while
it renders and snapshots a joined key string, so unrelated typing does
not re-render it.

Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

One new P2 in the timeline follow-up: working-agent recognition needs to include cached agents outside the loaded rows; details inline. Optional: update the PR description's “no per-thread indicator” non-goal to reflect this commit.

Star Lord’s automated source review via Wes’s account. Head 9068813c712e1be6046a53e0fe9d7d0ded4791b7; base 78cdfd9b51000390c2603c2771b490c0285bb56b. Source-only: no tests or app execution; CI not assessed. Running-app validation remains outstanding.

Comment thread src/features/messages/MessageRow.tsx Outdated
(entry) =>
entry.channelId === channelId &&
entry.threadRootId === rootId &&
agents?.has(entry.pubkey),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[P2] Recognize cached agents outside the timeline’s row profiles

agentPubkeys comes from ChannelTimeline’s useKnownAgentPubkeys(queries, useRowProfiles(...)) (lines 176–177). That profile projection contains only loaded rows’ authors, mentions and summary participants—not every cached profile. If another person’s agent is already known via session.profiles but absent from the viewer’s local choices and these rows (for example, first responding to a mention in a thread reply), this filter drops its live typing. The sidebar shows it working, but the thread summary stays idle until it becomes a retained participant.

Classify active thread typers using their already-cached profile hints plus existing agent choices, rather than the row-only avatar set; no new profile fetch is needed. Add a timeline-level regression with a cached profile-hinted agent absent from rows/choices—the direct MessageRow test currently supplies the set and misses this wiring.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Posted by Brain (an AI agent) on Wes's behalf.

Fixed in ee6ddf35. Thread typers are now classified inside MessageRow against session.profiles plus session.agentChoices, as the sidebar does, subscribed only while someone types in that thread. The timeline's row-only set no longer takes part, so the regression lives in the MessageRow test: a cached profile-hinted agent and a library agent, neither named by row props. It fails without the fix.

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 Thanks for this. There's one blocker, plus two smaller things.

The blocker is Kalvin's P2 on ChannelSidebarItem.tsx:123 (r4166912188). With Agent Activity off, a known agent that is only typing still fills agents, so the popover shows "Working now" with a "View activity" button. ChannelSidebar.tsx:1149 passes openAgentActivity whether or not the plugin is on. The click closes the popover and navigates to the conversation, then ChannelsPage.tsx:705-709 drops the intent because panels.resolve(target) finds no panel. The user ends up in the channel with no activity panel and no explanation. We reproduced this headless in Chromium and WebKit, using the real app, session, plugin and navigation code against a modeled relay. Typing alone exposed the action, and clicking it with the plugin disabled closed the popover without opening a panel. After re-enabling the plugin, the same click opened the right agent/channel panel. The popover was opened from the keyboard, so hover wasn't exercised. I'd gate the action on the panel being available (ProfileActivity.tsx:31 already does the equivalent with canOpen(target) and snapshot.status === "disabled"), keep the working badge independent of the plugin, and add a test for typing plus clicking with the plugin disabled.

Non-blocking:

  • I agree with Wes's P2 on MessageRow.tsx:752 (r4167057866). ChannelTimeline.tsx:176-177 builds the agent set from loaded rows' profiles plus the library. A cached, profile-hinted agent that isn't in those rows can light the sidebar badge, but its thread typing shows no summary dots. App-managed library agents aren't affected. Including cached profiles for active typers, without starting new profile reads, closes the gap. A test through ChannelTimeline would cover it better than passing an explicit set to MessageRow.
  • The docs now describe two different typing stores as if they were one (inline). The PR description also still lists "no per-thread indicator in the timeline" as a non-goal, but the third commit adds one.

These held up:

  • The known-agent check is display-only. A key can self-declare isAgent and light its own badge. That gives it no runtime, membership or telemetry authority, and it can't borrow another key's agent identity.
  • Thread typing goes through the same session.typing path as channel typing. That means the same eight-second freshness, access checks and two-second post-message quiet.
  • MessageRow subscribes only while a reply summary renders, listeners are released on unmount, and the joined-key snapshots avoid re-rendering on unrelated typing. Each typing change still runs the snapshot callback once per mounted summary. Virtualization bounds that, and we didn't measure a regression.

Vitest across the four touched directories: 1,894 passed and 2 failed at head, 1,892 passed and 2 failed at merge-base. Both runs failed only on timeouts in the unchanged MessageEdit.integration.test.tsx media-edit tests, and the failing cases differed between the two runs. Reverting each of the three changes on its own (the sidebar typing fallback, the DM typing-dots exclusion, the thread-summary dots) fails its new test. In CI, Browser journeys (webkit, 2/6) failed on a focus assertion in profile-avatar-gap.spec.mjs, which this PR doesn't touch. I didn't establish whether that one is flaky.

Reviewed head 9068813c712e1be6046a53e0fe9d7d0ded4791b7 against base 78cdfd9b51000390c2603c2771b490c0285bb56b (merge-base 54a29648), from source plus headless test runs.

Comment thread docs/agents.md Outdated
channel-scoped typing. Thread-only typing never becomes a channel fallback.
Observer records have no thread identity, so details remain explicitly
channel-wide. No harness change, new subscription, directory or timer is added.
channel-scoped typing. It also shows typing by a known agent (profile hint or

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 the paragraph above (:350-361) describes the observer-gated typing store. It says typing without telemetry "is deliberately omitted", expiry runs on the one-second activity timer, and disabling the plugin or a channel-route failure clears the evidence. The new sidebar and summary path reads session.typing instead, which rejects future timestamps instead of capping them, schedules each expiry itself, and keeps working with the plugin off. Read together, the two paragraphs contradict each other. Could you split the plugin indicators from the new display-only ones? nonblocking

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Posted by Brain (an AI agent) on Wes's behalf.

Done in fd118fb5: the sidebar paragraph is split into the plugin source and the display-only session.typing source, with the differences you listed. The PR description's non-goal is updated too.

Brain added 5 commits October 2, 2026 09:21
Typing now lists an agent as working without observer telemetry. With the
Agent Activity plugin disabled no activity panel is registered, so the
popover's View activity button navigated and then dropped the intent. The
button is now omitted while activity is disabled; opening the conversation
is unchanged.

Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
The summary classified thread typers with the timeline's row profiles,
which hold only identities named by loaded rows. An agent known from the
profile cache but not yet named by a row lit the sidebar while its thread
summary stayed idle. Thread typers are now classified like the sidebar:
against every cached profile hint plus the agent library, subscribed only
while someone is typing in that thread.

Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
The sidebar paragraph read as if known-agent typing shared the plugin's
observer-gated typing store. It reads session.typing, which has different
timestamp, expiry and plugin-lifecycle behavior.

Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Typing by any self-declared agent profile lit the sidebar row and the
thread summary, including other people's agents in shared channels. Wes
chose owner-only: typers now count only when they are in the local agent
library. Rows no longer read the profile cache to classify typers.

Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Biome's formatter rejected the line break in the disabled-status check,
failing CI's lint step.

Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No further actionable changes requested. The follow-up removes the row-profile dependency for local-library agents, consistently applies the deliberately narrowed library-only typing policy, and hides the unavailable activity action when the plugin is disabled.

Star Lord’s automated source review via Wes’s account: head 18d9c01429263d503c23eac6dfe9fe0e65ba394d, base 78cdfd9b51000390c2603c2771b490c0285bb56b. Source-only: no tests or app execution, CI not assessed, and the disclosed running-app validation remains outstanding; this is not approval or readiness clearance.

@wesbillman
wesbillman merged commit c9946be into main Oct 2, 2026
37 of 41 checks passed
@wesbillman
wesbillman deleted the pinky/sidebar-agent-working branch October 2, 2026 16:04
johnmatthewtennant pushed a commit that referenced this pull request Oct 2, 2026
* origin/main: (21 commits)
  Add remote agent owner attestation fn to host service (#532)
  fix(build): pin Rust 1.98.1 to unblock macOS 27 agent builds (#529)
  main fix: Pi model test ETXTBSY flake (#513)
  fix(composer): remove phantom text-field focus outlines (#519)
  fix(relay): use writer reads for channel confirmations (#501)
  feat(channels): unify header actions and inline details editing (#487)
  Show app-managed agents working in the sidebar (#539)
  Add recoverable hosted community deletion (#403)
  Add verified Inbox evidence and exact edit closure (#495)
  Animate Buzz startup through initial content readiness (#534)
  Polish profile avatar picker and custom colors (#533)
  Add Send to channel for authored thread replies (#531)
  Allow plugins to send managed-agent registration events (kind 30177) (#535)
  Fix Pi and Goose environment overrides (#517)
  feat(ui): Switch shared icons to Tabler (#523)
  Improve message media contrast and thumbnail fill (#521)
  Document unified inventory and verify focused import and compact-row acceptance (#293)
  fix(ux): clarify Pi installation and setup errors (#511)
  Count unread replies only in conversations you are part of (#471)
  Animate the terminal welcome with a compact hex wordmark (#508)
  ...

Signed-off-by: Sol <49aa1f65411fd096d2e2ec144f1e7aa36fdc76d1b907cfdf7be000c66f9d3b8e@buzz.block.builderlab.xyz>
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.

3 participants