Skip to content

Feat/watch running summary#3962

Draft
pedrofrxncx wants to merge 10 commits into
mainfrom
feat/watch-running-summary
Draft

Feat/watch running summary#3962
pedrofrxncx wants to merge 10 commits into
mainfrom
feat/watch-running-summary

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

What is this contribution about?

Describe your changes and why they're needed.

Screenshots/Demonstration

Add screenshots or a Loom video if your changes affect the UI.

How to Test

Provide step-by-step instructions for reviewers to test your changes:

  1. Step one
  2. Step two
  3. Expected outcome

Migration Notes

If this PR requires database migrations, configuration changes, or other setup steps, document them here. Remove this section if not applicable.

Review Checklist

  • PR title is clear and descriptive
  • Changes are tested and working
  • Documentation is updated (if needed)
  • No breaking changes

Summary by cubic

Adds a live running summary to the home page: “X agents working on N tasks,” with a hover list and a scope toggle between “This org” and “All my work.” The /watch SSE sends org and per‑user snapshots on connect and broadcasts on every run transition, backed by a cross‑pod running set.

  • New Features

    • Home: running badge with hover list; scope toggle (“This org” / “All my work”); click to open a thread; shows agent avatar and, for cross‑org rows, the org icon; latest assistant snippet loads on hover; cross‑org view hides threads from the current org to avoid duplicates.
    • SSE: /watch streams decopilot.running.summary (org) and decopilot.running.summary.user (per‑user) snapshots on connect when requested; the reactor broadcasts fresh summaries on start/step/finish to org and user:<id> channels.
    • Running set: RunningThreadsStore with a JetStream KV backend (per‑org key, idle‑entry pruning, TTL) and a DB fallback when NATS is absent; storage adds summarizeRunning and summarizeRunningForUser; @decocms/mesh-sdk adds DECOPILOT_RUNNING_SUMMARY_EVENT, DECOPILOT_USER_RUNNING_SUMMARY_EVENT, buildRunningSummary, and createDecopilotRunningSummaryEvent.
  • Refactors

    • Unified /watch SSE pool shared by decopilot, workflows, and the running summary; one cross‑tab connection per org (Web Locks + BroadcastChannel), with view filters per consumer.
    • Running‑summary events are sticky and replay to late subscribers; client stores persist across unmounts to avoid flicker; server snapshots are gated by ?types and can include both org and per‑user scopes.
    • Per‑user summary emission is awaited in the run reactor to prevent stale “All my work” counts on completion; tests drop running‑summary broadcasts to keep lifecycle assertions focused.

Written for commit 791b47a. Summary will update on new commits.

Review in cubic

The /watch SSE stream emits a decopilot.running.summary snapshot on connect
(DB-backed, authoritative, cross-pod) and the run reactor broadcasts a fresh
summary through the SSE hub on every thread transition. A NATS JetStream KV
store (DB fallback when NATS is absent) materializes the cross-pod running set,
keyed by org with a per-entry progress timestamp so orphaned runs self-heal via
read-time pruning. The home page renders "X agents working on N tasks".
The shared decopilot SSE pool is opened once and ref-counted; a late
subscriber (RunningSummaryLine mounting after the pool was already open) never
receives the one-shot connect snapshot, so the badge stays at 0 until the next
transition. Give the running summary its own dedicated, ref-counted /watch
connection so every mount/reconnect gets a fresh snapshot.
Hovering the "X agents working on N tasks" badge reveals the running threads:
each row shows the agent avatar + name, the thread title, and the latest
assistant snippet (fetched lazily when the popover opens). Clicking a row opens
that thread.

Also fixes a title inconsistency: RunningThread.title is now consistently the
THREAD title (snapshot previously used the agent/connection title while the
reactor broadcast used the thread title). The agent is resolved client-side
from virtual_mcp_id, so the summarizeRunning join is dropped and the unused
per-agent breakdown removed from RunningSummary.
Adds an "All my work" scope alongside "This org": your in_progress threads
across every org you belong to, on the home badge + hover list, each row
linking to the right org+thread.

- RunningThread gains organization_id (cross-org nav) and agent_title
  (server-resolved; the client cannot resolve a cross-org agent).
- New summarizeRunningForUser(userId): membership-gated cross-org query.
- New authenticated, non-org GET /api/me/watch — snapshots the user set and
  registers on the synthetic SSE channel user:<id> (the hub keys channels by
  opaque string, so no hub/NATS changes). The reactor fire-and-forgets a
  per-user summary to that channel on each transition.
- Home: a persisted scope toggle; subscribes to both feeds so the badge stays
  visible and the toggle reachable; cross-org rows resolve org slug from the
  user org list, fetch the snippet with that org\047s client, and navigate via
  useNavigate.

Per-user broadcast computes from DB per transition (the org channel uses KV);
fine for an opt-in lower-traffic feed, optimizable to per-user KV later.
Defaults the scope to the per-user cross-org feed; only switches to "This org"
when explicitly chosen (persisted). The toggle is local state over two
always-subscribed feeds, so switching never reconnects or reloads.
…dentity

Connection exhaustion: the badge held two dedicated SSE streams (org + user)
per tab, so a few tabs blew past the browser per-domain limit and hung the app
(and the churn flickered the badge). Collapse to ONE thin /watch connection per
tab that carries both scopes: the server also listens on the user:<id> channel
and sends both snapshots on connect, distinguished by event type
(decopilot.running.summary[.user]). Drops /api/me/watch. The client caches both
scopes and no longer clears on unmount, so a re-render never flashes empty.

Cross-org agent identity: rows in "All my work" showed a generic "Agent" +
icon because useVirtualMCP only resolves current-org agents and the well-known
Decopilot agent has no connections row (server agent_title was null). Resolve
Decopilot client-side from the thread org id (name + capybara icon); custom
cross-org agents still use the server agent_title.
In "All my work", each row now shows the org icon + name (reusing OrgIcon from
account-popover) so cross-org tasks are disambiguated. Org scope is unchanged
(single org, no need to repeat it).
…flows

Consolidates the handling of running summaries and workflow events into a single, shared `/watch` connection per organization. This change optimizes resource usage by reducing the number of SSE connections, preventing browser connection limits from being exceeded. The new structure allows both running summary and workflow events to be streamed together, enhancing performance and simplifying the event handling logic. Updates include the introduction of a unified SSE pool and adjustments to the relevant hooks and components to utilize this new architecture.
Updated integration tests to include handling for both DECOPILOT_RUNNING_SUMMARY_EVENT and DECOPILOT_USER_RUNNING_SUMMARY_EVENT. This change ensures that the tests correctly drop these summary broadcasts during the run-lifecycle sequence assertions, improving clarity and accuracy in event processing. Additionally, refactored the export statements in the relevant test files for consistency.
@pedrofrxncx pedrofrxncx marked this pull request as draft June 17, 2026 00:42
…te state updates

Updated the emitUserRunningSummary function to be asynchronous, ensuring that the cross-org query completes within the reactor's flow. This change prevents stale state issues by awaiting the summary emission, and errors are now logged instead of thrown. Additionally, adjusted calls to emitUserRunningSummary to await its completion in relevant functions. Improved the user state handling in the home page layout to filter out duplicate threads from the current organization.
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.

1 participant