feat(FN-1975): stream chat session updates through SSE
- Emit chat:session:updated from ChatStore when message deletion mutates a session and cover deleteMessage false returns - Pass ChatStore into SSE setup and forward chat session update events to connected clients - Update useChat to consume SSE updates in real time with safer EnrichedChatSession typing - Add core and dashboard tests for chat-store emissions, SSE forwarding, route wiring, and hook behavior
This commit is contained in:
@@ -9,6 +9,7 @@ import type {
|
||||
MessageStore,
|
||||
MissionValidatorRun,
|
||||
FixFeatureCreatedPayload,
|
||||
ChatStore,
|
||||
} from "@fusion/core";
|
||||
import type { AiSessionStore } from "./ai-session-store.js";
|
||||
|
||||
@@ -191,6 +192,7 @@ export function createSSE(
|
||||
options?: CreateSSEOptions,
|
||||
agentStore?: AgentStore,
|
||||
messageStore?: MessageStore,
|
||||
chatStore?: ChatStore,
|
||||
) {
|
||||
const { projectId } = options ?? {};
|
||||
|
||||
@@ -389,6 +391,27 @@ export function createSSE(
|
||||
send(`event: message:deleted\ndata: ${JSON.stringify({ id: messageId })}\n\n`);
|
||||
};
|
||||
|
||||
// --- Chat store event handlers ---
|
||||
const onChatSessionCreated = (session: any) => {
|
||||
send(`event: chat:session:created\ndata: ${JSON.stringify(session)}\n\n`);
|
||||
};
|
||||
|
||||
const onChatSessionUpdated = (session: any) => {
|
||||
send(`event: chat:session:updated\ndata: ${JSON.stringify(session)}\n\n`);
|
||||
};
|
||||
|
||||
const onChatSessionDeleted = (sessionId: string) => {
|
||||
send(`event: chat:session:deleted\ndata: ${JSON.stringify({ id: sessionId })}\n\n`);
|
||||
};
|
||||
|
||||
const onChatMessageAdded = (message: any) => {
|
||||
send(`event: chat:message:added\ndata: ${JSON.stringify(message)}\n\n`);
|
||||
};
|
||||
|
||||
const onChatMessageDeleted = (messageId: string) => {
|
||||
send(`event: chat:message:deleted\ndata: ${JSON.stringify({ id: messageId })}\n\n`);
|
||||
};
|
||||
|
||||
// --- Cleanup (all handlers are defined above, safe to reference) ---
|
||||
|
||||
let cleaned = false;
|
||||
@@ -452,6 +475,13 @@ export function createSSE(
|
||||
messageStore.off("message:read", onMessageRead);
|
||||
messageStore.off("message:deleted", onMessageDeleted);
|
||||
}
|
||||
if (chatStore) {
|
||||
chatStore.off("chat:session:created", onChatSessionCreated);
|
||||
chatStore.off("chat:session:updated", onChatSessionUpdated);
|
||||
chatStore.off("chat:session:deleted", onChatSessionDeleted);
|
||||
chatStore.off("chat:message:added", onChatMessageAdded);
|
||||
chatStore.off("chat:message:deleted", onChatMessageDeleted);
|
||||
}
|
||||
};
|
||||
|
||||
// --- Subscribe ---
|
||||
@@ -517,6 +547,14 @@ export function createSSE(
|
||||
messageStore.on("message:deleted", onMessageDeleted);
|
||||
}
|
||||
|
||||
if (chatStore) {
|
||||
chatStore.on("chat:session:created", onChatSessionCreated);
|
||||
chatStore.on("chat:session:updated", onChatSessionUpdated);
|
||||
chatStore.on("chat:session:deleted", onChatSessionDeleted);
|
||||
chatStore.on("chat:message:added", onChatMessageAdded);
|
||||
chatStore.on("chat:message:deleted", onChatMessageDeleted);
|
||||
}
|
||||
|
||||
// Heartbeat every 30s to keep connection alive.
|
||||
// Sent as a named event so the client's EventSource can detect it
|
||||
// (SSE comments starting with ":" are silently consumed and never
|
||||
|
||||
Reference in New Issue
Block a user