molecule-core/canvas/src/components/tabs
Hongming Wang 4028b81e04 refactor(canvas): route panel WS subscriptions through global socket
Both AgentCommsPanel and ChatTab's activity-feed opened raw
`new WebSocket(WS_URL)` instances per mount, with no onclose handler
and no reconnect logic. When the underlying connection dropped — idle
timeout, browser background-tab throttle, network jitter — the per-
panel sockets stayed dead until the panel re-mounted (refresh or
sub-tab unmount/remount). Live agent-comms bubbles and live activity
feed lines silently went missing in the gap, manifesting as "the
delegation didn't show up until I refreshed."

The global ReconnectingSocket in store/socket.ts already owns
reconnect, exponential backoff, health-check, and HTTP fallback poll.
Routing component subscribers through it gives every consumer those
guarantees for free, with one TCP connection per tab instead of N.

Three new pieces:

  - store/socket-events.ts: tiny pub/sub bus. emitSocketEvent fan-outs
    every decoded WSMessage to the listener Set; subscribeSocketEvents
    returns an unsubscribe. A throwing listener is logged and isolated
    so it can't break siblings.

  - store/socket.ts: ws.onmessage now calls emitSocketEvent(msg) right
    after applyEvent(msg), so the store's derived state and component
    subscribers stay in lockstep on every event arrival.

  - hooks/useSocketEvent.ts: React hook that registers exactly once
    per mount, capturing the latest handler in a ref so the closure
    sees current state/props without re-subscribing on every render.

Refactored sites:

  - AgentCommsPanel: replaced its WebSocket-in-useEffect block with
    useSocketEvent. Same parsing logic; the panel no longer opens its
    own connection.

  - ChatTab activity feed: split the previous useEffect in two — one
    seeds the activity log when `sending` flips, the other subscribes
    unconditionally and gates work on `sending` inside the handler.
    Hooks can't be conditional, so the gate has to live in the body
    rather than around the effect.

The ws-close graceful-close helper is no longer needed in either
site; the global socket owns its own teardown.

Tests: 6 new tests for the bus contract (single delivery, fan-out
order, unsubscribe, throwing-listener isolation, no-subscriber emit,
duplicate-subscribe Set semantics). All 27 existing socket tests
still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:12:47 -07:00
..
__tests__ merge(staging): resolve conflicts + fix 7 test regressions on top of #2061 2026-04-24 13:50:39 -07:00
chat refactor(canvas): route panel WS subscriptions through global socket 2026-04-27 13:12:47 -07:00
config fix(canvas/a11y): add type=button to tab toolbar and settings buttons 2026-04-24 14:41:35 +00:00
FilesTab fix(canvas/a11y): add type=button to tab toolbar and settings buttons 2026-04-24 14:41:35 +00:00
ActivityTab.tsx fix(a2a): review-driven hardening — prefix-anchored type check, error_detail cap, shared hint module 2026-04-24 23:47:44 -07:00
BudgetSection.tsx fix(canvas): add ?? 0 guard for optional budget_used in progressPct (#1324) (#1327) 2026-04-21 07:21:27 +00:00
ChannelsTab.tsx feat(channels): first-class Lark/Feishu support via schema-driven config 2026-04-24 11:51:15 -07:00
ChatTab.tsx refactor(canvas): route panel WS subscriptions through global socket 2026-04-27 13:12:47 -07:00
ConfigTab.tsx merge(staging): resolve conflicts + fix 7 test regressions on top of #2061 2026-04-24 13:50:39 -07:00
DetailsTab.tsx fix(canvas): cascade delete locally so children disappear without WS 2026-04-24 20:51:09 -07:00
EventsTab.tsx initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
FilesTab.tsx fix(canvas/a11y): add type=button to 24 buttons across DetailsTab, ConfigTab, FilesTab, MemoryTab 2026-04-24 12:39:43 +00:00
MemoryTab.tsx fix(canvas/a11y): add type=button to 24 buttons across DetailsTab, ConfigTab, FilesTab, MemoryTab 2026-04-24 12:39:43 +00:00
ScheduleTab.tsx fix(canvas/a11y): dialog aria-modal, icon-button labels, focus management 2026-04-22 19:03:00 +00:00
SkillsTab.tsx fix(canvas): plug timer leak + optimistic-install semantics in SkillsTab 2026-04-24 22:47:46 -07:00
TerminalTab.tsx fix: code review findings — token UI, auth hardening, WS dedup 2026-04-16 10:42:26 -07:00
TracesTab.tsx fix(canvas/a11y): add type=button to tab toolbar and settings buttons 2026-04-24 14:41:35 +00:00