import { useState, useCallback, useEffect } from "react"; import { getMeshChatHistory, clearMeshChatHistory, chatWithMeshContext, type MeshChatMessageRecord, type MeshChatContext, type MeshChatResponse, type LlmModel, } from "../lib/api"; export interface MeshChatState { conversationId: string | null; messages: MeshChatMessageRecord[]; loading: boolean; error: string | null; sending: boolean; } export function useMeshChatHistory() { const [state, setState] = useState({ conversationId: null, messages: [], loading: true, error: null, sending: false, }); const fetchHistory = useCallback(async () => { setState((prev) => ({ ...prev, loading: true, error: null })); try { const response = await getMeshChatHistory(); setState((prev) => ({ ...prev, conversationId: response.conversationId, messages: response.messages, loading: false, })); } catch (e) { setState((prev) => ({ ...prev, error: e instanceof Error ? e.message : "Failed to fetch chat history", loading: false, })); } }, []); const clearHistory = useCallback(async (): Promise => { setState((prev) => ({ ...prev, loading: true, error: null })); try { const response = await clearMeshChatHistory(); setState({ conversationId: response.conversationId, messages: [], loading: false, error: null, sending: false, }); return true; } catch (e) { setState((prev) => ({ ...prev, error: e instanceof Error ? e.message : "Failed to clear chat history", loading: false, })); return false; } }, []); const sendMessage = useCallback( async ( message: string, context: MeshChatContext, model?: LlmModel ): Promise => { setState((prev) => ({ ...prev, sending: true, error: null })); // Optimistically add user message (will be refetched after response) const tempUserMessage: MeshChatMessageRecord = { id: `temp-${Date.now()}`, conversationId: state.conversationId || "", role: "user", content: message, contextType: context.type, contextTaskId: context.taskId || null, toolCalls: null, pendingQuestions: null, createdAt: new Date().toISOString(), }; setState((prev) => ({ ...prev, messages: [...prev.messages, tempUserMessage], })); try { const response = await chatWithMeshContext(message, context, model); // Refetch to get the actual saved messages (with proper IDs) await fetchHistory(); setState((prev) => ({ ...prev, sending: false })); return response; } catch (e) { // Remove optimistic message on error setState((prev) => ({ ...prev, messages: prev.messages.filter((m) => m.id !== tempUserMessage.id), error: e instanceof Error ? e.message : "Failed to send message", sending: false, })); return null; } }, [state.conversationId, fetchHistory] ); // Initial fetch on mount useEffect(() => { fetchHistory(); }, [fetchHistory]); return { conversationId: state.conversationId, messages: state.messages, loading: state.loading, error: state.error, sending: state.sending, fetchHistory, clearHistory, sendMessage, }; }