import type { GatewayBrowserClient } from "../gateway"; export type ChatState = { client: GatewayBrowserClient | null; connected: boolean; sessionKey: string; chatLoading: boolean; chatMessages: unknown[]; chatThinkingLevel: string | null; chatSending: boolean; chatMessage: string; chatRunId: string | null; chatStream: string | null; lastError: string | null; }; type ChatEventPayload = { runId: string; sessionKey: string; state: "delta" | "final" | "aborted" | "error"; message?: unknown; errorMessage?: string; }; export async function loadChatHistory(state: ChatState) { if (!state.client || !state.connected) return; state.chatLoading = true; state.lastError = null; try { const res = (await state.client.request("chat.history", { sessionKey: state.sessionKey, limit: 200, })) as { messages?: unknown[]; thinkingLevel?: string | null }; state.chatMessages = Array.isArray(res.messages) ? res.messages : []; state.chatThinkingLevel = res.thinkingLevel ?? null; } catch (err) { state.lastError = String(err); } finally { state.chatLoading = false; } } export async function sendChat(state: ChatState) { if (!state.client || !state.connected) return; const msg = state.chatMessage.trim(); if (!msg) return; state.chatSending = true; state.chatMessage = ""; state.lastError = null; const runId = crypto.randomUUID(); state.chatRunId = runId; state.chatStream = ""; try { await state.client.request("chat.send", { sessionKey: state.sessionKey, message: msg, deliver: false, idempotencyKey: runId, }); } catch (err) { state.chatRunId = null; state.chatStream = null; state.chatMessage = msg; state.lastError = String(err); } finally { state.chatSending = false; } } export function handleChatEvent( state: ChatState, payload?: ChatEventPayload, ) { if (!payload) return null; if (payload.sessionKey !== state.sessionKey) return null; if (payload.runId && state.chatRunId && payload.runId !== state.chatRunId) return null; if (payload.state === "delta") { state.chatStream = extractText(payload.message) ?? state.chatStream; } else if (payload.state === "final") { state.chatStream = null; state.chatRunId = null; } else if (payload.state === "error") { state.chatStream = null; state.chatRunId = null; state.lastError = payload.errorMessage ?? "chat error"; } return payload.state; } function extractText(message: unknown): string | null { const m = message as Record; const content = m.content; if (typeof content === "string") return content; if (Array.isArray(content)) { const parts = content .map((p) => { const item = p as Record; if (item.type === "text" && typeof item.text === "string") return item.text; return null; }) .filter((v): v is string => typeof v === "string"); if (parts.length > 0) return parts.join("\n"); } if (typeof m.text === "string") return m.text; return null; }