Files
multica/packages/core/realtime/hooks.ts
LinYushen 75dc70686b fix(realtime): include actor_type in WS broadcast messages (#2668)
* fix(realtime): include actor_type in WebSocket broadcast messages

The WS broadcast message format was {type, payload, actor_id} but missing
actor_type. This meant the web UI could not distinguish agent from human
operations in real-time events at the top level.

While payload data for comments (author_type) and activities (entry.actor_type)
already included the type, the top-level message did not — causing the web UI
to display agent CLI operations as human operations when relying on the
broadcast actor identity.

Changes:
- server/cmd/server/listeners.go: add actor_type to all broadcast messages
- packages/core/types/events.ts: add actor_type to WSMessage interface
- packages/core/api/ws-client.ts: pass actor_type to event handlers
- packages/core/realtime/hooks.ts: update EventHandler type signature
- packages/core/realtime/provider.tsx: update EventHandler type signature

Fixes MUL-2260

Co-authored-by: multica-agent <github@multica.ai>

* test: add frame-shape unit test asserting actor_type in WS frames

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: multica-agent <github@multica.ai>
2026-05-15 14:10:24 +08:00

34 lines
919 B
TypeScript

"use client";
import { useEffect } from "react";
import type { WSEventType } from "../types";
import { useWS } from "./provider";
type EventHandler = (payload: unknown, actorId?: string, actorType?: string) => void;
/**
* Hook that subscribes to a WebSocket event and calls the handler.
* Automatically unsubscribes on cleanup.
*/
export function useWSEvent(event: WSEventType, handler: EventHandler) {
const { subscribe } = useWS();
useEffect(() => {
const unsub = subscribe(event, handler);
return unsub;
}, [event, handler, subscribe]);
}
/**
* Hook that registers a callback to run on WebSocket reconnection.
* Useful for refetching component-local data after a network interruption.
*/
export function useWSReconnect(callback: () => void) {
const { onReconnect } = useWS();
useEffect(() => {
const unsub = onReconnect(callback);
return unsub;
}, [callback, onReconnect]);
}