UNPKG

@llamaindex/ui

Version:

A comprehensive UI component library built with React, TypeScript, and Tailwind CSS for LlamaIndex applications

841 lines (832 loc) 29 kB
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './chunk-WQSELGI3.mjs'; export { Checkbox } from './chunk-7RKMIYR6.mjs'; export { Calendar, CalendarDayButton } from './chunk-S7JTBJ5O.mjs'; export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from './chunk-UJ3O5PS5.mjs'; export { Avatar, AvatarFallback, AvatarImage } from './chunk-3TCRI4BE.mjs'; export { HoverCard, HoverCardContent, HoverCardTrigger } from './chunk-BR7JIMR3.mjs'; export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField } from './chunk-EFV6VMVK.mjs'; export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from './chunk-LMJBLECE.mjs'; export { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from './chunk-GS22VIAB.mjs'; export { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from './chunk-R2BYKSW4.mjs'; export { RadioGroup, RadioGroupItem } from './chunk-DKNYE4BS.mjs'; export { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, navigationMenuTriggerStyle } from './chunk-VJHFD65M.mjs'; export { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from './chunk-R6343CNL.mjs'; export { Toaster } from './chunk-FN23HJDE.mjs'; export { Skeleton } from './chunk-QFASJAVY.mjs'; export { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from './chunk-PAVNEVCL.mjs'; export { Separator } from './chunk-D2VCHEW3.mjs'; export { ScrollArea, ScrollBar } from './chunk-BQ4VTUAU.mjs'; export { ResizableHandle, ResizablePanel, ResizablePanelGroup } from './chunk-NS4OBKGT.mjs'; export { FilePreview, PdfPreview, useFileData } from './chunk-EH4MGBB4.mjs'; export { PdfNavigator } from './chunk-XIANQWOZ.mjs'; export { AcceptReject, ConfidenceThresholdSettings, EditableField, ExtractedDataDisplay, ListRenderer, PropertyRenderer, TableRenderer, getConfidenceBackgroundClass, useItemData } from './chunk-CU226N6Z.mjs'; export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from './chunk-YGYJH2KV.mjs'; export { Label } from './chunk-GJTDG4HZ.mjs'; export { Slider } from './chunk-XHJVNRXI.mjs'; export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './chunk-ETHWXTFI.mjs'; export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './chunk-ACWZ42IC.mjs'; export { Toggle, toggleVariants } from './chunk-4QZ4SDAN.mjs'; export { Textarea } from './chunk-BSMI5PLR.mjs'; export { Tabs, TabsContent, TabsList, TabsTrigger } from './chunk-R2YZKBS7.mjs'; export { Switch } from './chunk-PYUECJC6.mjs'; import './chunk-3IBS2UPL.mjs'; import { workflowStreamingManager, fetchHandlerEvents } from './chunk-K5V72JEW.mjs'; export { AgentStreamDisplay, WorkflowProgressBar, WorkflowTrigger, createHandlerStore, useHandlerStore, useWorkflowHandler, useWorkflowHandlerList, useWorkflowProgress, useWorkflowRun } from './chunk-K5V72JEW.mjs'; import './chunk-KI3KVHLZ.mjs'; export { ColumnHeader, EXTRACTED_DATA_COLUMN_NAMES, ExtractedDataItemGrid, FormattedDate, ItemGrid, PaginationControls, ReviewStatusBadge, STATUS_OPTIONS, SyncedIcon, createExtractedDataColumn, getExtractedDataItemsToReviewCount as getItemsToReviewCount, useItemGridData } from './chunk-EREFUPHC.mjs'; export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger } from './chunk-DJSXQ6E4.mjs'; export { Badge, badgeVariants } from './chunk-4SLZJPDY.mjs'; import './chunk-NH3TF2QK.mjs'; export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './chunk-77RHHXY2.mjs'; import './chunk-QQG6BRXU.mjs'; export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from './chunk-54HXPXVZ.mjs'; export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from './chunk-7UVHBMZO.mjs'; export { ItemCount } from './chunk-3FRLYLMY.mjs'; export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-2QBCG3BE.mjs'; export { useIndex, useIndexList, useIndexStore } from './chunk-JKRSZAN2.mjs'; import { useWorkflowsClient } from './chunk-FBUZYPY4.mjs'; export { ApiProvider, cloudApiClient, createAgentDataClient as createCloudAgentClient, createMockClients, createClient as createWorkflowsClient, createConfig as createWorkflowsConfig, useAgentDataClient, useApiClients, useCloudApiClient, useWorkflowsClient, workflowsClient } from './chunk-FBUZYPY4.mjs'; export { FILE_TYPE_GROUPS, FileType, FileUploader, UploadProgress, createFileTypeValidator, formatFileSize, getFileExtensions, getFileMimeTypes, getFileTypeDefinition, getFileTypesByCategory, isCryptoSupported, isFileApiSupported, isFileTypeMatch, useFileUpload, useUploadProgress, validateFile } from './chunk-FUT5SO57.mjs'; export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './chunk-ICIG4S2N.mjs'; export { Progress } from './chunk-KRVDHZW4.mjs'; export { Input } from './chunk-A734CEDD.mjs'; export { Button, buttonVariants } from './chunk-KPGB4IWL.mjs'; export { cn } from './chunk-MG2ARK3A.mjs'; import { __spreadProps, __spreadValues, __objRest, __restKey } from './chunk-JD6AELXS.mjs'; import { useMemo, useState, useCallback, useEffect } from 'react'; import { create } from 'zustand'; import { postEventsByHandlerId, postWorkflowsByNameRunNowait } from '@llamaindex/workflows-client'; // src/chat/components/chat.interface.ts var MessageRole = { Assistant: "assistant" }; async function createChatHandler(client, workflowName) { var _a; const response = await postWorkflowsByNameRunNowait({ client, path: { name: workflowName }, body: { start_event: {} } }); if (!((_a = response.data) == null ? void 0 : _a.handler_id)) { throw new Error("Failed to create chat handler: no handler_id returned"); } return response.data.handler_id; } async function sendEventToHandler(client, handlerId, event) { await postEventsByHandlerId({ client, path: { handler_id: handlerId }, body: { event: JSON.stringify(event) } }); } function subscribeToHandlerEvents(client, handlerId, callbacks) { const { onEvent, onError, onComplete } = callbacks; const { unsubscribe } = fetchHandlerEvents( { client, handlerId }, { onData: (event) => { onEvent == null ? void 0 : onEvent(event); }, onError: (error) => { onError == null ? void 0 : onError(error); }, onFinish: () => { onComplete == null ? void 0 : onComplete(); } } ); return unsubscribe; } function unsubscribeFromHandler(handlerId) { const streamKey = `handler:${handlerId}`; workflowStreamingManager.closeStream(streamKey); } // src/chat/components/message-parts/types.ts var TextPartType = "text"; var FilePartType = "data-file"; var ArtifactPartType = "data-artifact"; var EventPartType = "data-event"; var SourcesPartType = "data-sources"; var SuggestionPartType = "data-suggested_questions"; // src/chat/store/adapters.ts function extractTextFromParts(parts) { return parts.filter((part) => part.type === TextPartType).map((part) => part.text).join(" "); } function isDeltaEvent(event) { return event.type.includes("ChatDeltaEvent"); } function isStopEvent(event) { return event.type === "workflow.events.StopEvent" /* StopEvent */; } function isInputRequiredEvent(event) { return event.type === "workflow.events.InputRequiredEvent" /* InputRequiredEvent */; } function isMessageTerminator(event) { return isStopEvent(event) || isInputRequiredEvent(event); } function messageToEvent(message) { const text = extractTextFromParts(message.parts); if (!text || text.trim() === "") { throw new Error("Cannot send empty message"); } return { type: "workflow.events.HumanResponseEvent" /* HumanResponseEvent */, data: { response: text } }; } function autoCompleteMarkdown(text) { const stack = []; let i = 0; while (i < text.length) { const inFencedCode = stack[stack.length - 1] === "```"; if (text.slice(i, i + 3) === "```") { if (stack[stack.length - 1] === "```") { stack.pop(); } else { stack.push("```"); } i += 3; continue; } if (text.slice(i, i + 2) === "**") { if (stack[stack.length - 1] === "**") { stack.pop(); } else { stack.push("**"); } i += 2; continue; } if (text[i] === "*") { if (inFencedCode) { i++; continue; } if (text[i - 1] === "*") { i++; continue; } if (text[i + 1] === "*") { i++; continue; } if (i === text.length - 1) { if (stack[stack.length - 1] === "*") { stack.pop(); } i++; continue; } if (stack[stack.length - 1] === "*") { stack.pop(); } else { stack.push("*"); } i++; continue; } if (text[i] === "`") { if (inFencedCode) { i++; continue; } if (text[i - 1] === "`" && text[i - 2] === "`") { i++; continue; } if (text[i + 1] === "`" && text[i + 2] === "`") { i++; continue; } if (text[i + 1] === "*" && text[i - 1] === "*") { i++; continue; } if (i === text.length - 1) { if (stack[stack.length - 1] === "`") { stack.pop(); } i++; continue; } if (stack[stack.length - 1] === "`") { stack.pop(); } else { stack.push("`"); } i++; continue; } i++; } let completedText = text; while (stack.length > 0) { const marker = stack.pop(); if (marker === "```") { completedText += "\n"; } completedText += marker; } return completedText; } function parseTextWithXMLMarkers(text) { const parts = []; const completedText = autoCompleteMarkdown(text); const codeBlockRanges = findCodeBlockRanges(completedText); const xmlPattern = /<(\w+)>([\s\S]*?)<\/\1>/g; let lastIndex = 0; let match; while ((match = xmlPattern.exec(completedText)) !== null) { const [fullMatch, tagName, content] = match; const matchStart = match.index; const matchEnd = matchStart + fullMatch.length; if (isInsideCodeBlock(matchStart, matchEnd, codeBlockRanges)) { continue; } if (matchStart > lastIndex) { const plainText = completedText.slice(lastIndex, matchStart); const trimmed = plainText.trim(); if (trimmed) { parts.push({ type: TextPartType, text: trimmed }); } } const part = parseXMLMarker(tagName, content.trim()); if (part) { parts.push(part); } lastIndex = matchEnd; } if (lastIndex < completedText.length) { const remaining = completedText.slice(lastIndex); const startTagMatch = remaining.match(/<(\w+)>/); if (startTagMatch) { const tagStartIndex = lastIndex + (startTagMatch.index || 0); if (!isInsideCodeBlock(tagStartIndex, completedText.length, codeBlockRanges)) { const before = remaining.slice(0, startTagMatch.index); const trimmed = before.trim(); if (trimmed) { parts.push({ type: TextPartType, text: trimmed }); } } else { const trimmed = remaining.trim(); if (trimmed) parts.push({ type: TextPartType, text: trimmed }); } } else { const trimmed = remaining.trim(); if (trimmed) parts.push({ type: TextPartType, text: trimmed }); } } return parts; } function findCodeBlockRanges(text) { const ranges = []; const lines = text.split("\n"); let currentIndex = 0; let inFencedBlock = false; let fenceStart = 0; for (let i = 0; i < lines.length; i++) { const line = lines[i]; const lineStart = currentIndex; if (line.trim().startsWith("```")) { if (!inFencedBlock) { inFencedBlock = true; fenceStart = lineStart; } else { inFencedBlock = false; const fenceEnd = lineStart + line.length; ranges.push([fenceStart, fenceEnd]); } } currentIndex += line.length + 1; } const inlinePattern = /`[^`\n]+`/g; let match; while ((match = inlinePattern.exec(text)) !== null) { const matchStart = match.index; const matchEnd = matchStart + match[0].length; let isInFenced = false; for (const [blockStart, blockEnd] of ranges) { if (matchStart >= blockStart && matchEnd <= blockEnd) { isInFenced = true; break; } } if (!isInFenced) { ranges.push([matchStart, matchEnd]); } } return ranges; } function isInsideCodeBlock(start, end, codeBlockRanges) { for (const [blockStart, blockEnd] of codeBlockRanges) { if (start >= blockStart && start < blockEnd) { return true; } if (end > blockStart && end <= blockEnd) { return true; } if (start <= blockStart && end >= blockEnd) { return true; } } return false; } function parseXMLMarker(tagName, content) { try { const data = JSON.parse(content); switch (tagName) { case "sources": return { type: SourcesPartType, data // Expected: { nodes: SourceNode[] } }; case "suggested_questions": return { type: SuggestionPartType, data // Expected: string[] }; case "file": return { type: FilePartType, data // Expected: { filename, mediaType, url } }; case "artifact": return { type: ArtifactPartType, data // Expected: { type, created_at, data } }; case "event": return { type: EventPartType, data // Expected: { title, status, description?, data? } }; default: return { type: tagName, data }; } } catch (error) { console.warn( `[XML Protocol] Failed to parse <${tagName}> content:`, content, error ); return null; } } // src/chat/store/streaming-message.ts var StreamingMessage = class { constructor(messageId) { this.events = []; this.currentTextBuffer = ""; // Buffer for adjacent delta events this.currentTextParts = []; // Parsed parts from current buffer this.finalizedParts = []; // Finalized parts (flushed) this._status = "streaming"; this.messageId = messageId; } /** * Get current status */ get status() { return this._status; } /** * Add a new event and incrementally update the parsed result * Only adjacent delta events are merged together */ addEvent(event) { if (!event || !event.type) { return; } this.events.push(event); if (isStopEvent(event)) { return; } if (isDeltaEvent(event)) { const delta = event.data.delta; if (delta) { this.currentTextBuffer += delta; this.currentTextParts = this.currentTextBuffer ? parseTextWithXMLMarkers(this.currentTextBuffer) : []; } return; } this.flushTextBuffer(); this.finalizedParts.push({ type: event.type, data: event.data }); } /** * Mark the streaming as completed and flush any remaining text */ complete() { this.flushTextBuffer(); this._status = "completed"; } /** * Get current MessagePart[] (returns finalized + current, O(1)) */ getParts() { return [...this.finalizedParts, ...this.currentTextParts]; } /** * Get accumulated events (mainly for debugging) */ getEvents() { return [...this.events]; } /** * Get current text buffer (mainly for debugging) */ getTextBuffer() { return this.currentTextBuffer; } /** * Clear all accumulated state */ clear() { this.events = []; this.currentTextBuffer = ""; this.currentTextParts = []; this.finalizedParts = []; this._status = "streaming"; } /** * Flush the current text buffer (finalize adjacent delta events) * This is called when a non-delta event arrives or streaming completes */ flushTextBuffer() { if (!this.currentTextBuffer.trim()) { return; } this.finalizedParts.push(...this.currentTextParts); this.currentTextBuffer = ""; this.currentTextParts = []; } }; // src/chat/store/chat-store.ts var createChatStore = (client) => create()((set, get) => ({ // Initial state sessions: {}, // Session management createSession: async (options) => { const { workflowName, handlerId: providedHandlerId, initialMessages = [] } = options; const handlerId = providedHandlerId || await createChatHandler(client, workflowName); const session = { handlerId, workflowName, messages: initialMessages, status: "ready", error: null, streamingMessage: null }; set((state) => ({ sessions: __spreadProps(__spreadValues({}, state.sessions), { [handlerId]: session }) })); subscribeToHandlerEvents(client, handlerId, { onEvent: (event) => { const session2 = get().sessions[handlerId]; if (!session2) return; let streamingMsg = session2.streamingMessage; if (!streamingMsg) { const assistantMessageId = `assistant-${Date.now()}`; const assistantMessage = { id: assistantMessageId, role: MessageRole.Assistant, parts: [] }; get()._appendMessage(handlerId, assistantMessage); streamingMsg = new StreamingMessage(assistantMessageId); get()._setStreamingMessage(handlerId, streamingMsg); get().setStatus(handlerId, "streaming"); } streamingMsg.addEvent(event); const updatedParts = streamingMsg.getParts(); get()._updateAssistantMessage( handlerId, streamingMsg.messageId, updatedParts ); if (isMessageTerminator(event)) { streamingMsg.complete(); get().setStatus(handlerId, "ready"); get()._setStreamingMessage(handlerId, null); } }, onError: (error) => { if (error.name === "AbortError" || error.name === "TypeError" && error.message.includes("network error")) { return; } const session2 = get().sessions[handlerId]; if (session2 == null ? void 0 : session2.streamingMessage) { session2.streamingMessage.complete(); get()._setStreamingMessage(handlerId, null); } get().setError(handlerId, error); get().setStatus(handlerId, "error"); }, onComplete: () => { const session2 = get().sessions[handlerId]; if (session2 == null ? void 0 : session2.streamingMessage) { session2.streamingMessage.complete(); get()._setStreamingMessage(handlerId, null); } get().setStatus(handlerId, "ready"); } }); return handlerId; }, deleteSession: (handlerId) => { unsubscribeFromHandler(handlerId); set((state) => { const _a = state.sessions, { [handlerId]: _ } = _a, remainingSessions = __objRest(_a, [__restKey(handlerId)]); return { sessions: remainingSessions }; }); }, getSession: (handlerId) => { return get().sessions[handlerId]; }, // Message operations sendMessage: async (handlerId, message, _opts) => { const session = get().sessions[handlerId]; if (!session) { throw new Error(`Session ${handlerId} not found`); } get()._appendMessage(handlerId, message); const assistantMessageId = `assistant-${Date.now()}`; const assistantMessage = { id: assistantMessageId, role: MessageRole.Assistant, parts: [] }; get()._appendMessage(handlerId, assistantMessage); get().setStatus(handlerId, "submitted"); get()._setStreamingMessage( handlerId, new StreamingMessage(assistantMessageId) ); try { const event = messageToEvent(message); await sendEventToHandler(client, handlerId, event); get().setStatus(handlerId, "streaming"); } catch (error) { get().setError(handlerId, error); get().setStatus(handlerId, "error"); throw error; } }, setMessages: (handlerId, messages) => { set((state) => { const session = state.sessions[handlerId]; if (!session) return state; return { sessions: __spreadProps(__spreadValues({}, state.sessions), { [handlerId]: __spreadProps(__spreadValues({}, session), { messages }) }) }; }); }, _appendMessage: (handlerId, message) => { set((state) => { const session = state.sessions[handlerId]; if (!session) return state; return { sessions: __spreadProps(__spreadValues({}, state.sessions), { [handlerId]: __spreadProps(__spreadValues({}, session), { messages: [...session.messages, message] }) }) }; }); }, _updateAssistantMessage: (handlerId, messageId, parts) => { set((state) => { const session = state.sessions[handlerId]; if (!session) return state; const updatedMessages = session.messages.map( (msg) => msg.id === messageId ? __spreadProps(__spreadValues({}, msg), { parts }) : msg ); return { sessions: __spreadProps(__spreadValues({}, state.sessions), { [handlerId]: __spreadProps(__spreadValues({}, session), { messages: updatedMessages }) }) }; }); }, // Status management setStatus: (handlerId, status) => { set((state) => { const session = state.sessions[handlerId]; if (!session) return state; return { sessions: __spreadProps(__spreadValues({}, state.sessions), { [handlerId]: __spreadProps(__spreadValues({}, session), { status }) }) }; }); }, setError: (handlerId, error) => { set((state) => { const session = state.sessions[handlerId]; if (!session) return state; return { sessions: __spreadProps(__spreadValues({}, state.sessions), { [handlerId]: __spreadProps(__spreadValues({}, session), { error }) }) }; }); }, // Internal helper for setting streamingMessage _setStreamingMessage: (handlerId, streamingMessage) => { set((state) => { const session = state.sessions[handlerId]; if (!session) return state; return { sessions: __spreadProps(__spreadValues({}, state.sessions), { [handlerId]: __spreadProps(__spreadValues({}, session), { streamingMessage }) }) }; }); }, // Streaming control stop: async (handlerId) => { const session = get().sessions[handlerId]; if (!session) { throw new Error(`Session ${handlerId} not found`); } if (session.streamingMessage) { session.streamingMessage.complete(); } unsubscribeFromHandler(handlerId); get().setStatus(handlerId, "ready"); get()._setStreamingMessage(handlerId, null); }, regenerate: async (handlerId, messageId) => { const session = get().sessions[handlerId]; if (!session) { throw new Error(`Session ${handlerId} not found`); } let targetIndex = -1; if (messageId) { targetIndex = session.messages.findIndex((m) => m.id === messageId); } else { for (let i = session.messages.length - 1; i >= 0; i--) { if (session.messages[i].role === "user") { targetIndex = i; break; } } } if (targetIndex === -1) { throw new Error("No message found to regenerate"); } const messagesToKeep = session.messages.slice(0, targetIndex + 1); get().setMessages(handlerId, messagesToKeep); const assistantMessageId = `assistant-${Date.now()}`; const assistantMessage = { id: assistantMessageId, role: MessageRole.Assistant, parts: [] }; get()._appendMessage(handlerId, assistantMessage); get().setStatus(handlerId, "submitted"); get()._setStreamingMessage( handlerId, new StreamingMessage(assistantMessageId) ); try { const messageToResend = session.messages[targetIndex]; const event = messageToEvent(messageToResend); await sendEventToHandler(client, handlerId, event); get().setStatus(handlerId, "streaming"); } catch (error) { get().setError(handlerId, error); get().setStatus(handlerId, "error"); throw error; } } })); // src/chat/hooks/use-chat-store.ts var globalStore = null; function useChatStore(selector) { const client = useWorkflowsClient(); const store = useMemo(() => { if (!globalStore) { globalStore = createChatStore(client); } return globalStore; }, [client]); return selector ? store(selector) : store(); } // src/chat/hooks/use-chat.ts function useChat(options) { const { workflowName, handlerId: providedHandlerId, initialMessages, onReady, onError } = options; const store = useChatStore(); const [handlerId, setHandlerId] = useState( providedHandlerId || null ); const session = useChatStore( (state) => handlerId ? state.sessions[handlerId] : void 0 ); const initSession = useCallback(async () => { const id = await store.createSession({ workflowName, handlerId: providedHandlerId, initialMessages }); setHandlerId(id); onReady == null ? void 0 : onReady(id); return id; }, [workflowName, providedHandlerId, initialMessages, store, onReady]); useEffect(() => { if (providedHandlerId && !session) { initSession().catch((error) => { onError == null ? void 0 : onError(error); }); } }, [providedHandlerId, session, initSession, onError]); useEffect(() => { if (session == null ? void 0 : session.error) { onError == null ? void 0 : onError(session.error); } }, [session == null ? void 0 : session.error, onError]); const sendMessage = useCallback( async (message, opts) => { let currentHandlerId = handlerId; if (!currentHandlerId) { try { currentHandlerId = await initSession(); } catch (error) { onError == null ? void 0 : onError(error); throw error; } } await store.sendMessage(currentHandlerId, message, opts); }, [handlerId, initSession, store, onError] ); const stop = useCallback(async () => { if (!handlerId) return; await store.stop(handlerId); }, [handlerId, store]); const regenerate = useCallback( async (opts) => { if (!handlerId) { throw new Error("Cannot regenerate: no messages sent yet"); } await store.regenerate(handlerId, opts == null ? void 0 : opts.messageId); }, [handlerId, store] ); const setMessages = useCallback( (messages) => { if (!handlerId) return; store.setMessages(handlerId, messages); }, [handlerId, store] ); return useMemo( () => ({ handlerId, messages: (session == null ? void 0 : session.messages) || [], status: (session == null ? void 0 : session.status) || (handlerId ? "ready" : "idle"), sendMessage, stop, regenerate, setMessages }), [ handlerId, session == null ? void 0 : session.messages, session == null ? void 0 : session.status, sendMessage, stop, regenerate, setMessages ] ); } export { useChat, useChatStore };