You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
refactor(frontend/ws): unify three WebSocket managers (useWebSocket + useGlobalWebSocket + useLiveEvents) into single useEventBus #6488
The frontend has three independent WebSocket subsystems with identical state-enum values defined twice and 14 callers split across patterns. Each wires to a different backend bus, so collapsing them is partially blocked on #6486 (backend event-bus unification).
Both define exactly: 'disconnected' | 'connecting' | 'connected' | 'error'.
Backend coupling
Today the frontend's split mirrors the backend's split: /api/ws → EventManager, /api/ws/live → LiveEventManager. Once #6486 unifies the backend buses, the frontend can collapse to one transport.
Proposed Solution
Single composable useEventBus() built on GlobalWebSocketService with channel-scoped subscriptions folded in.
Various useWebSocket callers — ad-hoc URL construction, some include token, some don't
Filed #6700 as the precursor: extract a shared buildAuthenticatedWsUrl() helper. It's a 30-line mechanical change that fixes the immediate bug and lays a clean foundation for this consolidation.
Recommend this issue depend on #6700 — once auth is centralized, the unification can focus on lifecycle/channel/event-bus semantics without re-litigating authentication.
Discovery
The frontend has three independent WebSocket subsystems with identical state-enum values defined twice and 14 callers split across patterns. Each wires to a different backend bus, so collapsing them is partially blocked on #6486 (backend event-bus unification).
ConnectionState/api/ws(EventManager)LiveEventConnectionState(identical values toConnectionState)/api/ws/live(LiveEventManager)State enum collision (pure duplication)
Both define exactly:
'disconnected' | 'connecting' | 'connected' | 'error'.Backend coupling
Today the frontend's split mirrors the backend's split:
/api/ws→EventManager,/api/ws/live→LiveEventManager. Once #6486 unifies the backend buses, the frontend can collapse to one transport.Proposed Solution
Single composable
useEventBus()built onGlobalWebSocketServicewith channel-scoped subscriptions folded in.Channel format unchanged from
useLiveEvents:'global','agent:{id}','task:{id}','workflow:{id}'.Caller migration (14 total)
Terminal.vue,SSHTerminal.vue,usePrometheusMetrics.ts,useOversoverAgent.ts,useWorkflowBuilder.ts,KnowledgeResearchPanel.vue,CodeQualityDashboard.vue(8 callers of useWebSocket)useWebSocket(url)useEventBus().subscribe(channel, handler)useCaptchaStatus.ts,ChatInterface.ts(3 callers of useGlobalWebSocket).on(event, cb)useEventBus().subscribe('global', cb)HeartbeatPanel.vue,WorkflowLiveDashboard.vue,useToolApproval.ts(3 callers of useLiveEvents).subscribe('agent:X', cb)useEventBus().subscribe('agent:X', cb)Steps
/api/wsendpoint togetherConnectionStatefromGlobalWebSocketService, deleteLiveEventConnectionStateGlobalWebSocketService— foldLiveEventServicechannel logic inuseEventBus()composable — thin wrapper, supports both'global'and'agent:X'syntaxuseWebSocket,useLiveEventskeep working for one release with deprecation warningsAcceptance Criteria
ConnectionStatetype exported;LiveEventConnectionStateremoveduseEventBus()composable created and supports channels:'global','agent:{id}','task:{id}','workflow:{id}'git grep "useWebSocket\\|useLiveEvents"returns 0 in non-shim codeGlobalWebSocketServiceagent:123do NOT leak toagent:456subscribers (integration test){ type, payload }structure preserved for backward compatRisks
'connecting'/'error'literals before mergeTerminal.vue) — audit each caller for assumptionsFiles Affected
services/GlobalWebSocketService.ts(add channel routing)composables/useEventBus.tscomposables/useWebSocket.ts,composables/useLiveEvents.ts,services/LiveEventService.tsRelated / Dependencies
LiveEventConnectionStateandConnectionStateenum duplication