@assistant-ui/ai-sdk 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/aiSDKFormatAdapter.d.ts +2 -8
- package/dist/adapters/aiSDKFormatAdapter.js +1 -25
- package/dist/converters/convertMessage.d.ts.map +1 -1
- package/dist/converters/convertMessage.js +1 -0
- package/dist/converters/convertMessage.js.map +1 -1
- package/dist/runtime/AISDKThreads.d.ts.map +1 -1
- package/dist/runtime/AISDKThreads.js +90 -65
- package/dist/runtime/AISDKThreads.js.map +1 -1
- package/dist/runtime/sdkIdentity.d.ts +6 -0
- package/dist/runtime/sdkIdentity.d.ts.map +1 -0
- package/dist/runtime/sdkIdentity.js +9 -0
- package/dist/runtime/sdkIdentity.js.map +1 -0
- package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
- package/dist/runtime/useAISDKRuntime.js +8 -1
- package/dist/runtime/useAISDKRuntime.js.map +1 -1
- package/dist/runtime/useChatRuntime.d.ts.map +1 -1
- package/dist/runtime/useChatRuntime.js +5 -1
- package/dist/runtime/useChatRuntime.js.map +1 -1
- package/dist/runtime/useChatThread.js +1 -1
- package/dist/runtime/useChatThread.js.map +1 -1
- package/dist/runtime/useExternalHistory.d.ts.map +1 -1
- package/dist/runtime/useExternalHistory.js +4 -1
- package/dist/runtime/useExternalHistory.js.map +1 -1
- package/package.json +6 -6
- package/src/adapters/aiSDKFormatAdapter.ts +4 -41
- package/src/converters/convertMessage.test.ts +14 -0
- package/src/converters/convertMessage.ts +1 -0
- package/src/runtime/AISDKThreads.cloud.test.ts +12 -3
- package/src/runtime/AISDKThreads.test.ts +131 -8
- package/src/runtime/AISDKThreads.ts +31 -3
- package/src/runtime/sdkIdentity.ts +9 -0
- package/src/runtime/useAISDKRuntime.test.ts +39 -1
- package/src/runtime/useAISDKRuntime.ts +17 -1
- package/src/runtime/useChatRuntime.test.ts +0 -1
- package/src/runtime/useChatRuntime.ts +2 -1
- package/src/runtime/useChatThread.test.ts +74 -0
- package/src/runtime/useChatThread.ts +1 -1
- package/src/runtime/useExternalHistory.test.ts +29 -0
- package/src/runtime/useExternalHistory.ts +4 -1
- package/src/transport/AssistantChatTransport.test.ts +1 -9
- package/dist/adapters/aiSDKFormatAdapter.d.ts.map +0 -1
- package/dist/adapters/aiSDKFormatAdapter.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAISDKRuntime.js","names":["c","_c","useCallback","useEffect","useInsertionEffect","useMemo","useRef","useState","UIMessage","useChat","CreateUIMessage","UseChatHelpers","isToolUIPart","generateId","useExternalStoreRuntime","useRuntimeAdapters","JoinStrategy","SuggestionAdapter","ThreadSuggestion","ToolExecutionStatus","ExternalStoreAdapter","ExternalStoreSharedOptions","ThreadHistoryAdapter","AssistantRuntime","ThreadMessage","MessageFormatAdapter","MessageFormatItem","MessageFormatRepository","AppendMessage","RunConfig","McpAppMetadata","getExternalStoreMessages","pickExternalStoreSharedOptions","consumeSuggestionResult","MessageRepository","ReadonlyJSONObject","sliceMessagesUntil","toCreateMessage","vercelAttachmentAdapter","getVercelAIMessages","AISDKMessageConverter","wrapModelContentEnvelope","AISDKStorageFormat","aiSDKV6FormatAdapter","useExternalHistory","toExportedMessageRepository","useStreamingTiming","aiSDKExtras","CustomToCreateMessageFunction","message","UI_MESSAGE","toUIMessage","createMessage","fallbackRole","id","role","AISDKRuntimeAdapter","adapters","NonNullable","history","suggestion","unstable_messageRepositoryInstance","cancelPendingToolCallsOnSend","onResume","onResumeToolCall","joinStrategy","messageRepository","unstable_onBranchChange","EMPTY_SUGGESTIONS","useGeneratedSuggestions","suggestionAdapter","messages","isRunning","$","suggestions","setSuggestions","controllerRef","wasRunningRef","messagesRef","t0","t1","current","adapterRef","t2","t3","hasAdapter","t4","clearSuggestions","abort","_temp","adapter","currentMessages","last","at","status","type","controller","AbortController","signal","promiseOrGenerator","generate","onUpdate","t5","t6","t7","Symbol","for","NO_CANCELLED_MESSAGE_IDS","ReadonlySet","Set","useAISDKRuntime","chatHelpers","ReturnType","customToCreateMessage","contextAdapters","toolStatuses","setToolStatuses","Record","cancelledMessages","setCancelledMessages","chatId","ids","toolArgsKeyOrderCacheRef","Map","toolLastInputCacheRef","mcpAppMetadataCacheRef","lastRunConfigRef","undefined","hasExecutingTools","Object","values","some","s","providerIsRunning","wasProviderRunningRef","messageTiming","lastMessage","optimisticMessageId","cancelledMessageIds","retractCancellation","messageId","prev","has","delete","resumedMessageId","wasProviderRunning","useThreadMessages","metadata","toolArgsKeyOrderCache","toolLastInputCache","mcpAppMetadataCache","error","size","exportedMessageRepository","converted","toThreadMessages","length","generatedSuggestions","runtimeRef","runtime","isLoading","deleteMessage","deleteHistoryMessage","setMessages","chatMessages","chatStatus","extras","provide","chat","completePendingToolCalls","hasChanges","parts","map","part","state","approval","_approval","rest","const","errorText","slice","hasSeededRepositoryRef","shouldFeedRepository","unstable_enableToolInvocations","filter","Boolean","flat","onImport","onExportExternalState","exported","thread","export","expandedMessages","lastInnerIdMap","item","innerMessages","parentId","get","innerMessage","push","getId","set","result","headId","onLoadExternalState","repo","exportedRepo","import","onCancel","cancelledId","liveIds","m","kept","stop","Error","name","onNew","startRun","runConfig","sendMessage","onEdit","onDelete","threadMessages","getState","messageIndex","findIndex","deleteIds","onReload","config","newMessages","regenerate","onAddToolResult","toolCallId","toolName","isError","modelContent","options","Promise","resolve","addToolOutput","tool","JSON","stringify","output","onRespondToToolApproval","approvalId","approved","reason","addToolApprovalResponse","attachments","setMessagesRef","tempRepo","getMessages","flatMap"],"sources":["../../src/runtime/useAISDKRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n UIMessage,\n useChat,\n CreateUIMessage,\n UseChatHelpers,\n} from \"@ai-sdk/react\";\nimport { isToolUIPart, generateId } from \"ai\";\nimport {\n useExternalStoreRuntime,\n useRuntimeAdapters,\n type JoinStrategy,\n} from \"@assistant-ui/core/react\";\nimport type {\n SuggestionAdapter,\n ThreadSuggestion,\n ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport type {\n ExternalStoreAdapter,\n ExternalStoreSharedOptions,\n ThreadHistoryAdapter,\n AssistantRuntime,\n ThreadMessage,\n MessageFormatAdapter,\n MessageFormatItem,\n MessageFormatRepository,\n AppendMessage,\n RunConfig,\n McpAppMetadata,\n} from \"@assistant-ui/core\";\nimport {\n getExternalStoreMessages,\n pickExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n consumeSuggestionResult,\n MessageRepository,\n} from \"@assistant-ui/core/internal\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport { sliceMessagesUntil } from \"../utils/sliceMessagesUntil\";\nimport { toCreateMessage } from \"../converters/toCreateMessage\";\nimport { vercelAttachmentAdapter } from \"../adapters/vercelAttachmentAdapter\";\nimport { getVercelAIMessages } from \"../utils/getVercelAIMessages\";\nimport { AISDKMessageConverter } from \"../converters/convertMessage\";\nimport { wrapModelContentEnvelope } from \"../converters/modelContentEnvelope\";\nimport {\n type AISDKStorageFormat,\n aiSDKV6FormatAdapter,\n} from \"../adapters/aiSDKFormatAdapter\";\nimport {\n useExternalHistory,\n toExportedMessageRepository,\n} from \"./useExternalHistory\";\nimport { useStreamingTiming } from \"./useStreamingTiming\";\nimport { aiSDKExtras } from \"../aiSDKExtras\";\n\nexport type CustomToCreateMessageFunction = <\n UI_MESSAGE extends UIMessage = UIMessage,\n>(\n message: AppendMessage,\n) => CreateUIMessage<UI_MESSAGE>;\n\nconst toUIMessage = <UI_MESSAGE extends UIMessage>(\n createMessage: CreateUIMessage<UI_MESSAGE>,\n fallbackRole: UI_MESSAGE[\"role\"],\n): UI_MESSAGE =>\n ({\n ...createMessage,\n id: createMessage.id ?? generateId(),\n role: createMessage.role ?? fallbackRole,\n }) as UI_MESSAGE;\n\nexport type AISDKRuntimeAdapter<UI_MESSAGE extends UIMessage = UIMessage> =\n ExternalStoreSharedOptions & {\n adapters?:\n | (NonNullable<ExternalStoreAdapter[\"adapters\"]> & {\n history?: ThreadHistoryAdapter | undefined;\n suggestion?: SuggestionAdapter | undefined;\n })\n | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n unstable_messageRepositoryInstance?: MessageRepository | undefined;\n /**\n * Whether to automatically cancel pending interactive tool calls when the user sends a new message.\n *\n * When enabled (default), the pending tool calls will be marked as failed with an error message\n * indicating the user cancelled the tool call by sending a new message.\n *\n * @default true\n */\n cancelPendingToolCallsOnSend?: boolean | undefined;\n /**\n * Called when `runtime.thread.resumeRun(config)` is invoked.\n *\n * When omitted, `resumeRun` throws `\"Runtime does not support resuming runs.\"`.\n * Provide this to bridge resume invocations into a custom replay channel\n * (for example, an SSE reconnect endpoint keyed by turn id).\n */\n onResume?: ExternalStoreAdapter[\"onResume\"];\n /**\n * Called when `runtime.thread.resumeToolCall(options)` is invoked for a tool call the in-process tracker does not own.\n *\n * When omitted, `resumeToolCall` throws `\"Tool call ${toolCallId} is not waiting for resume.\"`.\n * Provide this to bridge resume-tool-call invocations into a custom handler.\n */\n onResumeToolCall?: ExternalStoreAdapter[\"onResumeToolCall\"];\n /**\n * How consecutive assistant messages are rendered.\n *\n * `\"concat-content\"` (the default) merges them into a single thread message.\n * `\"none\"` keeps each assistant message as its own thread message, which is\n * useful when a backend persists proactive or consecutive assistant messages\n * as separate entries.\n */\n joinStrategy?: JoinStrategy | undefined;\n /**\n * A branch-aware AI SDK message tree seeded once when `useChat` is empty.\n * After that seed, live updates come only from `useChat`. A later empty\n * chat or a new object identity does not reload the tree.\n */\n messageRepository?: MessageFormatRepository<UI_MESSAGE>;\n /**\n * Called after an explicit `switchToBranch` (for example a BranchPicker\n * click). Complements `setMessages` and does not enable switching by itself.\n *\n * @deprecated This API is still under active development and might change without notice.\n */\n unstable_onBranchChange?: ExternalStoreAdapter[\"unstable_onBranchChange\"];\n };\n\nconst EMPTY_SUGGESTIONS: readonly ThreadSuggestion[] = [];\n\nconst useGeneratedSuggestions = (\n suggestionAdapter: SuggestionAdapter | undefined,\n messages: readonly ThreadMessage[],\n isRunning: boolean,\n): readonly ThreadSuggestion[] => {\n const [suggestions, setSuggestions] =\n useState<readonly ThreadSuggestion[]>(EMPTY_SUGGESTIONS);\n const controllerRef = useRef<AbortController | null>(null);\n const wasRunningRef = useRef(false);\n const messagesRef = useRef(messages);\n useInsertionEffect(() => {\n messagesRef.current = messages;\n }, [messages]);\n const adapterRef = useRef(suggestionAdapter);\n useInsertionEffect(() => {\n adapterRef.current = suggestionAdapter;\n }, [suggestionAdapter]);\n const hasAdapter = suggestionAdapter != null;\n\n useEffect(() => {\n const clearSuggestions = () => {\n controllerRef.current?.abort();\n controllerRef.current = null;\n setSuggestions((prev) => (prev.length === 0 ? prev : EMPTY_SUGGESTIONS));\n };\n\n const adapter = adapterRef.current;\n if (!adapter) {\n clearSuggestions();\n wasRunningRef.current = isRunning;\n return;\n }\n\n if (isRunning) {\n if (!wasRunningRef.current) {\n clearSuggestions();\n }\n wasRunningRef.current = true;\n return;\n }\n\n if (!wasRunningRef.current) return;\n wasRunningRef.current = false;\n\n const currentMessages = messagesRef.current;\n const last = currentMessages.at(-1);\n if (last?.role !== \"assistant\") return;\n if (last.status?.type === \"requires-action\") return;\n\n const controller = new AbortController();\n controllerRef.current = controller;\n const { signal } = controller;\n\n void (async () => {\n try {\n const promiseOrGenerator = adapter.generate({\n messages: currentMessages,\n signal,\n });\n\n await consumeSuggestionResult(promiseOrGenerator, {\n signal,\n onUpdate: setSuggestions,\n });\n } catch {}\n })();\n }, [hasAdapter, isRunning]);\n\n useEffect(() => {\n return () => {\n controllerRef.current?.abort();\n };\n }, []);\n\n return suggestions;\n};\n\nconst NO_CANCELLED_MESSAGE_IDS: ReadonlySet<string> = new Set();\n\nexport const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,\n adapter: AISDKRuntimeAdapter<UI_MESSAGE> = {},\n) => {\n const {\n adapters,\n toCreateMessage: customToCreateMessage,\n cancelPendingToolCallsOnSend = true,\n onResume,\n onResumeToolCall,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n } = adapter;\n const suggestionAdapter = adapters?.suggestion;\n const contextAdapters = useRuntimeAdapters();\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const [cancelledMessages, setCancelledMessages] = useState<{\n chatId: string;\n ids: ReadonlySet<string>;\n } | null>(null);\n const toolArgsKeyOrderCacheRef = useRef<Map<string, Map<string, string[]>>>(\n new Map(),\n );\n const toolLastInputCacheRef = useRef<Map<string, ReadonlyJSONObject>>(\n new Map(),\n );\n const mcpAppMetadataCacheRef = useRef<Map<string, McpAppMetadata>>(new Map());\n const lastRunConfigRef = useRef<RunConfig | undefined>(undefined);\n\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const providerIsRunning =\n chatHelpers.status === \"submitted\" || chatHelpers.status === \"streaming\";\n const isRunning = providerIsRunning || hasExecutingTools;\n const wasProviderRunningRef = useRef(providerIsRunning);\n\n const messageTiming = useStreamingTiming(chatHelpers.messages, isRunning);\n\n // Flag the streaming message optimistic: its id can be swapped for a server\n // id mid-run, and the repository then drops the orphaned pre-swap id (#4037).\n const lastMessage = chatHelpers.messages.at(-1);\n const optimisticMessageId =\n isRunning && lastMessage?.role === \"assistant\" ? lastMessage.id : undefined;\n\n const cancelledMessageIds =\n cancelledMessages?.chatId === chatHelpers.id\n ? cancelledMessages.ids\n : NO_CANCELLED_MESSAGE_IDS;\n\n const retractCancellation = useCallback(\n (chatId: string, messageId: string) => {\n setCancelledMessages((prev) => {\n if (prev?.chatId !== chatId || !prev.ids.has(messageId)) return prev;\n const ids = new Set(prev.ids);\n ids.delete(messageId);\n return { chatId, ids };\n });\n },\n [],\n );\n\n // A provider run that resumes the stopped response retracts its cancellation;\n // a run that starts a new response leaves the stopped one marked.\n const resumedMessageId =\n providerIsRunning && lastMessage?.role === \"assistant\"\n ? lastMessage.id\n : undefined;\n\n useEffect(() => {\n const wasProviderRunning = wasProviderRunningRef.current;\n wasProviderRunningRef.current = providerIsRunning;\n if (wasProviderRunning || !resumedMessageId) return;\n retractCancellation(chatHelpers.id, resumedMessageId);\n }, [\n providerIsRunning,\n resumedMessageId,\n chatHelpers.id,\n retractCancellation,\n ]);\n\n const messages = AISDKMessageConverter.useThreadMessages({\n isRunning,\n messages: chatHelpers.messages,\n joinStrategy,\n metadata: useMemo(\n () => ({\n toolStatuses,\n messageTiming,\n toolArgsKeyOrderCache: toolArgsKeyOrderCacheRef.current,\n toolLastInputCache: toolLastInputCacheRef.current,\n mcpAppMetadataCache: mcpAppMetadataCacheRef.current,\n ...(optimisticMessageId && { optimisticMessageId }),\n ...(chatHelpers.error && { error: chatHelpers.error.message }),\n ...(cancelledMessageIds.size > 0 && { cancelledMessageIds }),\n }),\n [\n toolStatuses,\n messageTiming,\n optimisticMessageId,\n chatHelpers.error,\n cancelledMessageIds,\n ],\n ),\n });\n\n const exportedMessageRepository = useMemo(() => {\n if (!messageRepository) return undefined;\n const converted = toExportedMessageRepository(\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n messageRepository,\n );\n return converted.messages.length > 0 ? converted : undefined;\n }, [messageRepository]);\n\n const generatedSuggestions = useGeneratedSuggestions(\n suggestionAdapter,\n messages,\n isRunning,\n );\n\n const [runtimeRef] = useState(() => ({\n get current(): AssistantRuntime {\n return runtime;\n },\n }));\n\n const { isLoading, deleteMessage: deleteHistoryMessage } = useExternalHistory(\n runtimeRef,\n adapters?.history ?? contextAdapters?.history,\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n aiSDKV6FormatAdapter as MessageFormatAdapter<\n UI_MESSAGE,\n AISDKStorageFormat\n >,\n (messages) => {\n chatHelpers.setMessages(messages);\n },\n );\n\n const {\n id: chatId,\n messages: chatMessages,\n status: chatStatus,\n error,\n } = chatHelpers;\n const extras = useMemo(\n () =>\n aiSDKExtras.provide({\n chat: chatHelpers as unknown as UseChatHelpers<UIMessage>,\n error,\n }),\n // oxlint-disable-next-line react/exhaustive-deps -- keyed on the chat's identity and reactive snapshots; useChat re-mints the helpers object every render while its remaining fields are instance-bound methods, and a render-stable extras identity is what lets the external-store core dedupe adapter updates\n [chatId, chatMessages, chatStatus, error],\n );\n\n const completePendingToolCalls = async () => {\n if (!cancelPendingToolCallsOnSend) return;\n\n // The runtime auto-aborts in-flight tool invocations when a new run\n // is dispatched (append() / startRun()). All we need to do here is\n // mark any tool without a result as cancelled in the UI message list.\n\n // Mark any tool without a result as cancelled (uses setMessages to avoid triggering sendAutomaticallyWhen)\n chatHelpers.setMessages((messages) => {\n const lastMessage = messages.at(-1);\n if (lastMessage?.role !== \"assistant\") return messages;\n\n let hasChanges = false;\n const parts = lastMessage.parts?.map((part) => {\n if (!isToolUIPart(part)) return part;\n if (\n part.state === \"output-available\" ||\n part.state === \"output-error\" ||\n part.state === \"output-denied\"\n )\n return part;\n\n hasChanges = true;\n const { approval: _approval, ...rest } = part;\n return {\n ...rest,\n state: \"output-error\" as const,\n errorText: \"User cancelled tool call by sending a new message.\",\n };\n });\n\n if (!hasChanges) return messages;\n return [...messages.slice(0, -1), { ...lastMessage, parts }];\n });\n };\n\n const hasSeededRepositoryRef = useRef(false);\n const shouldFeedRepository =\n exportedMessageRepository != null &&\n !hasSeededRepositoryRef.current &&\n messages.length === 0;\n\n const runtime = useExternalStoreRuntime({\n isRunning: providerIsRunning,\n ...(shouldFeedRepository\n ? { messageRepository: exportedMessageRepository }\n : { messages }),\n unstable_enableToolInvocations: true,\n setToolStatuses,\n setMessages: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onImport: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onExportExternalState: (): MessageFormatRepository<UI_MESSAGE> => {\n const exported = runtimeRef.current.thread.export();\n\n const expandedMessages: MessageFormatItem<UI_MESSAGE>[] = [];\n const lastInnerIdMap = new Map<string, string>();\n\n for (const item of exported.messages) {\n const innerMessages = getExternalStoreMessages<UI_MESSAGE>(\n item.message,\n );\n let parentId =\n item.parentId != null\n ? (lastInnerIdMap.get(item.parentId) ?? item.parentId)\n : null;\n for (const innerMessage of innerMessages) {\n expandedMessages.push({ parentId, message: innerMessage });\n parentId = aiSDKV6FormatAdapter.getId(innerMessage as UIMessage);\n }\n if (innerMessages.length > 0) {\n lastInnerIdMap.set(\n item.message.id,\n aiSDKV6FormatAdapter.getId(\n innerMessages[innerMessages.length - 1]! as UIMessage,\n ),\n );\n }\n }\n\n const result: MessageFormatRepository<UI_MESSAGE> = {\n messages: expandedMessages,\n };\n\n if (exported.headId != null) {\n result.headId = lastInnerIdMap.get(exported.headId) ?? exported.headId;\n }\n\n return result;\n },\n onLoadExternalState: (repo: MessageFormatRepository<UI_MESSAGE>) => {\n // Convert MessageFormatRepository to ExportedMessageRepository\n const exportedRepo = toExportedMessageRepository(\n AISDKMessageConverter.toThreadMessages,\n repo,\n );\n\n // Import into the thread's MessageRepository\n runtimeRef.current.thread.import(exportedRepo);\n },\n onCancel: async () => {\n const message = chatHelpers.messages.at(-1);\n const cancelledId =\n isRunning && message?.role === \"assistant\" ? message.id : undefined;\n if (cancelledId) {\n const liveIds = new Set(chatHelpers.messages.map((m) => m.id));\n setCancelledMessages((prev) => {\n const kept =\n prev?.chatId === chatHelpers.id\n ? [...prev.ids].filter((id) => liveIds.has(id))\n : [];\n return {\n chatId: chatHelpers.id,\n ids: new Set([...kept, cancelledId]),\n };\n });\n }\n try {\n await chatHelpers.stop();\n } catch (error) {\n if (!(error instanceof Error && error.name === \"AbortError\")) {\n if (cancelledId) retractCancellation(chatHelpers.id, cancelledId);\n throw error;\n }\n }\n },\n onNew: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n\n if (!(message.startRun ?? message.role === \"user\")) {\n chatHelpers.setMessages((current) => [\n ...current,\n toUIMessage<UI_MESSAGE>(createMessage, message.role),\n ]);\n return;\n }\n\n lastRunConfigRef.current = message.runConfig;\n await completePendingToolCalls();\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onEdit: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n\n if (!(message.startRun ?? message.role === \"user\")) {\n chatHelpers.setMessages((current) => [\n ...sliceMessagesUntil(current, message.parentId),\n toUIMessage<UI_MESSAGE>(createMessage, message.role),\n ]);\n return;\n }\n\n lastRunConfigRef.current = message.runConfig;\n chatHelpers.setMessages((current) =>\n sliceMessagesUntil(current, message.parentId),\n );\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onDelete: async (messageId) => {\n const threadMessages = runtimeRef.current.thread.getState().messages;\n const messageIndex = threadMessages.findIndex(\n (message) => message.id === messageId,\n );\n if (messageIndex === -1) return;\n\n await deleteHistoryMessage(messageId);\n\n const deleteIds = new Set(\n getExternalStoreMessages<UI_MESSAGE>(threadMessages[messageIndex]!).map(\n (message) => message.id,\n ),\n );\n chatHelpers.setMessages((current) =>\n current.filter((message) => !deleteIds.has(message.id)),\n );\n },\n onReload: async (parentId: string | null, config) => {\n lastRunConfigRef.current = config.runConfig;\n const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);\n chatHelpers.setMessages(newMessages);\n\n await chatHelpers.regenerate({ metadata: config.runConfig });\n },\n onAddToolResult: ({\n toolCallId,\n toolName,\n result,\n isError,\n modelContent,\n }) => {\n const options = { metadata: lastRunConfigRef.current };\n if (isError) {\n return Promise.resolve(\n chatHelpers.addToolOutput({\n state: \"output-error\",\n tool: toolName ?? toolCallId,\n toolCallId,\n errorText:\n typeof result === \"string\" ? result : JSON.stringify(result),\n options,\n }),\n );\n } else {\n const output =\n modelContent !== undefined\n ? wrapModelContentEnvelope(result, modelContent)\n : result;\n return Promise.resolve(\n chatHelpers.addToolOutput({\n tool: toolName,\n toolCallId,\n output,\n options,\n }),\n );\n }\n },\n onRespondToToolApproval: ({ approvalId, approved, reason }) =>\n Promise.resolve(\n chatHelpers.addToolApprovalResponse({\n id: approvalId,\n approved,\n ...(reason != null && { reason }),\n options: { metadata: lastRunConfigRef.current },\n }),\n ),\n ...pickExternalStoreSharedOptions(adapter),\n ...(adapter.unstable_messageRepositoryInstance && {\n unstable_messageRepositoryInstance:\n adapter.unstable_messageRepositoryInstance,\n }),\n ...(suggestionAdapter ? { suggestions: generatedSuggestions } : {}),\n ...(onResume && { onResume }),\n ...(onResumeToolCall && { onResumeToolCall }),\n ...(unstable_onBranchChange && { unstable_onBranchChange }),\n adapters: {\n attachments: vercelAttachmentAdapter,\n ...contextAdapters,\n ...adapters,\n },\n extras,\n isLoading,\n });\n\n const setMessagesRef = useRef(chatHelpers.setMessages);\n useInsertionEffect(() => {\n setMessagesRef.current = chatHelpers.setMessages;\n }, [chatHelpers.setMessages]);\n\n useEffect(() => {\n if (hasSeededRepositoryRef.current) return;\n if (!exportedMessageRepository) return;\n if (chatHelpers.messages.length > 0) {\n hasSeededRepositoryRef.current = true;\n return;\n }\n const tempRepo = new MessageRepository();\n tempRepo.import(exportedMessageRepository);\n setMessagesRef.current(\n tempRepo.getMessages().flatMap(getExternalStoreMessages<UI_MESSAGE>),\n );\n hasSeededRepositoryRef.current = true;\n }, [exportedMessageRepository, chatHelpers.messages.length]);\n return runtime;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useAISDKRuntime.js","names":["c","_c","useCallback","useEffect","useInsertionEffect","useMemo","useRef","useState","UIMessage","useChat","CreateUIMessage","UseChatHelpers","isToolUIPart","generateId","useExternalStoreRuntime","useRuntimeAdapters","JoinStrategy","SuggestionAdapter","ThreadSuggestion","ToolExecutionStatus","ExternalStoreAdapter","ExternalStoreSharedOptions","ThreadHistoryAdapter","AssistantRuntime","ThreadMessage","MessageFormatAdapter","MessageFormatItem","MessageFormatRepository","AppendMessage","RunConfig","McpAppMetadata","getExternalStoreMessages","pickExternalStoreSharedOptions","consumeSuggestionResult","MessageRepository","ReadonlyJSONObject","AssistantError","sliceMessagesUntil","toCreateMessage","vercelAttachmentAdapter","getVercelAIMessages","AISDKMessageConverter","wrapModelContentEnvelope","AISDKStorageFormat","aiSDKV6FormatAdapter","useExternalHistory","toExportedMessageRepository","useStreamingTiming","aiSDKExtras","CustomToCreateMessageFunction","message","UI_MESSAGE","toUIMessage","createMessage","fallbackRole","id","role","AISDKRuntimeAdapter","adapters","NonNullable","history","suggestion","unstable_messageRepositoryInstance","cancelPendingToolCallsOnSend","onResume","onResumeToolCall","joinStrategy","messageRepository","unstable_onBranchChange","EMPTY_SUGGESTIONS","useGeneratedSuggestions","suggestionAdapter","messages","isRunning","$","suggestions","setSuggestions","controllerRef","wasRunningRef","messagesRef","t0","t1","current","adapterRef","t2","t3","hasAdapter","t4","clearSuggestions","abort","_temp","adapter","currentMessages","last","at","status","type","controller","AbortController","signal","promiseOrGenerator","generate","onUpdate","t5","t6","t7","Symbol","for","NO_CANCELLED_MESSAGE_IDS","ReadonlySet","Set","toChatError","error","Error","code","name","useAISDKRuntime","chatHelpers","ReturnType","customToCreateMessage","contextAdapters","toolStatuses","setToolStatuses","Record","cancelledMessages","setCancelledMessages","chatId","ids","toolArgsKeyOrderCacheRef","Map","toolLastInputCacheRef","mcpAppMetadataCacheRef","lastRunConfigRef","undefined","hasExecutingTools","Object","values","some","s","providerIsRunning","wasProviderRunningRef","messageTiming","lastMessage","optimisticMessageId","cancelledMessageIds","retractCancellation","messageId","prev","has","delete","resumedMessageId","wasProviderRunning","useThreadMessages","metadata","toolArgsKeyOrderCache","toolLastInputCache","mcpAppMetadataCache","size","exportedMessageRepository","converted","toThreadMessages","length","generatedSuggestions","runtimeRef","runtime","isLoading","deleteMessage","deleteHistoryMessage","setMessages","chatMessages","chatStatus","extras","provide","chat","completePendingToolCalls","hasChanges","parts","map","part","state","approval","_approval","rest","const","errorText","slice","hasSeededRepositoryRef","shouldFeedRepository","unstable_enableToolInvocations","filter","Boolean","flat","onImport","onExportExternalState","exported","thread","export","expandedMessages","lastInnerIdMap","item","innerMessages","parentId","get","innerMessage","push","getId","set","result","headId","onLoadExternalState","repo","exportedRepo","import","onCancel","cancelledId","liveIds","m","kept","stop","onNew","startRun","runConfig","sendMessage","onEdit","onDelete","threadMessages","getState","messageIndex","findIndex","deleteIds","onReload","config","newMessages","regenerate","onAddToolResult","toolCallId","toolName","isError","modelContent","options","Promise","resolve","addToolOutput","tool","JSON","stringify","output","onRespondToToolApproval","approvalId","approved","reason","addToolApprovalResponse","attachments","setMessagesRef","tempRepo","getMessages","flatMap"],"sources":["../../src/runtime/useAISDKRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n UIMessage,\n useChat,\n CreateUIMessage,\n UseChatHelpers,\n} from \"@ai-sdk/react\";\nimport { isToolUIPart, generateId } from \"ai\";\nimport {\n useExternalStoreRuntime,\n useRuntimeAdapters,\n type JoinStrategy,\n} from \"@assistant-ui/core/react\";\nimport type {\n SuggestionAdapter,\n ThreadSuggestion,\n ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport type {\n ExternalStoreAdapter,\n ExternalStoreSharedOptions,\n ThreadHistoryAdapter,\n AssistantRuntime,\n ThreadMessage,\n MessageFormatAdapter,\n MessageFormatItem,\n MessageFormatRepository,\n AppendMessage,\n RunConfig,\n McpAppMetadata,\n} from \"@assistant-ui/core\";\nimport {\n getExternalStoreMessages,\n pickExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n consumeSuggestionResult,\n MessageRepository,\n} from \"@assistant-ui/core/internal\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport type { AssistantError } from \"@assistant-ui/core\";\nimport { sliceMessagesUntil } from \"../utils/sliceMessagesUntil\";\nimport { toCreateMessage } from \"../converters/toCreateMessage\";\nimport { vercelAttachmentAdapter } from \"../adapters/vercelAttachmentAdapter\";\nimport { getVercelAIMessages } from \"../utils/getVercelAIMessages\";\nimport { AISDKMessageConverter } from \"../converters/convertMessage\";\nimport { wrapModelContentEnvelope } from \"../converters/modelContentEnvelope\";\nimport {\n type AISDKStorageFormat,\n aiSDKV6FormatAdapter,\n} from \"../adapters/aiSDKFormatAdapter\";\nimport {\n useExternalHistory,\n toExportedMessageRepository,\n} from \"./useExternalHistory\";\nimport { useStreamingTiming } from \"./useStreamingTiming\";\nimport { aiSDKExtras } from \"../aiSDKExtras\";\n\nexport type CustomToCreateMessageFunction = <\n UI_MESSAGE extends UIMessage = UIMessage,\n>(\n message: AppendMessage,\n) => CreateUIMessage<UI_MESSAGE>;\n\nconst toUIMessage = <UI_MESSAGE extends UIMessage>(\n createMessage: CreateUIMessage<UI_MESSAGE>,\n fallbackRole: UI_MESSAGE[\"role\"],\n): UI_MESSAGE =>\n ({\n ...createMessage,\n id: createMessage.id ?? generateId(),\n role: createMessage.role ?? fallbackRole,\n }) as UI_MESSAGE;\n\nexport type AISDKRuntimeAdapter<UI_MESSAGE extends UIMessage = UIMessage> =\n ExternalStoreSharedOptions & {\n adapters?:\n | (NonNullable<ExternalStoreAdapter[\"adapters\"]> & {\n history?: ThreadHistoryAdapter | undefined;\n suggestion?: SuggestionAdapter | undefined;\n })\n | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n unstable_messageRepositoryInstance?: MessageRepository | undefined;\n /**\n * Whether to automatically cancel pending interactive tool calls when the user sends a new message.\n *\n * When enabled (default), the pending tool calls will be marked as failed with an error message\n * indicating the user cancelled the tool call by sending a new message.\n *\n * @default true\n */\n cancelPendingToolCallsOnSend?: boolean | undefined;\n /**\n * Called when `runtime.thread.resumeRun(config)` is invoked.\n *\n * When omitted, `resumeRun` throws `\"Runtime does not support resuming runs.\"`.\n * Provide this to bridge resume invocations into a custom replay channel\n * (for example, an SSE reconnect endpoint keyed by turn id).\n */\n onResume?: ExternalStoreAdapter[\"onResume\"];\n /**\n * Called when `runtime.thread.resumeToolCall(options)` is invoked for a tool call the in-process tracker does not own.\n *\n * When omitted, `resumeToolCall` throws `\"Tool call ${toolCallId} is not waiting for resume.\"`.\n * Provide this to bridge resume-tool-call invocations into a custom handler.\n */\n onResumeToolCall?: ExternalStoreAdapter[\"onResumeToolCall\"];\n /**\n * How consecutive assistant messages are rendered.\n *\n * `\"concat-content\"` (the default) merges them into a single thread message.\n * `\"none\"` keeps each assistant message as its own thread message, which is\n * useful when a backend persists proactive or consecutive assistant messages\n * as separate entries.\n */\n joinStrategy?: JoinStrategy | undefined;\n /**\n * A branch-aware AI SDK message tree seeded once when `useChat` is empty.\n * After that seed, live updates come only from `useChat`. A later empty\n * chat or a new object identity does not reload the tree.\n */\n messageRepository?: MessageFormatRepository<UI_MESSAGE>;\n /**\n * Called after an explicit `switchToBranch` (for example a BranchPicker\n * click). Complements `setMessages` and does not enable switching by itself.\n *\n * @deprecated This API is still under active development and might change without notice.\n */\n unstable_onBranchChange?: ExternalStoreAdapter[\"unstable_onBranchChange\"];\n };\n\nconst EMPTY_SUGGESTIONS: readonly ThreadSuggestion[] = [];\n\nconst useGeneratedSuggestions = (\n suggestionAdapter: SuggestionAdapter | undefined,\n messages: readonly ThreadMessage[],\n isRunning: boolean,\n): readonly ThreadSuggestion[] => {\n const [suggestions, setSuggestions] =\n useState<readonly ThreadSuggestion[]>(EMPTY_SUGGESTIONS);\n const controllerRef = useRef<AbortController | null>(null);\n const wasRunningRef = useRef(false);\n const messagesRef = useRef(messages);\n useInsertionEffect(() => {\n messagesRef.current = messages;\n }, [messages]);\n const adapterRef = useRef(suggestionAdapter);\n useInsertionEffect(() => {\n adapterRef.current = suggestionAdapter;\n }, [suggestionAdapter]);\n const hasAdapter = suggestionAdapter != null;\n\n useEffect(() => {\n const clearSuggestions = () => {\n controllerRef.current?.abort();\n controllerRef.current = null;\n setSuggestions((prev) => (prev.length === 0 ? prev : EMPTY_SUGGESTIONS));\n };\n\n const adapter = adapterRef.current;\n if (!adapter) {\n clearSuggestions();\n wasRunningRef.current = isRunning;\n return;\n }\n\n if (isRunning) {\n if (!wasRunningRef.current) {\n clearSuggestions();\n }\n wasRunningRef.current = true;\n return;\n }\n\n if (!wasRunningRef.current) return;\n wasRunningRef.current = false;\n\n const currentMessages = messagesRef.current;\n const last = currentMessages.at(-1);\n if (last?.role !== \"assistant\") return;\n if (last.status?.type === \"requires-action\") return;\n\n const controller = new AbortController();\n controllerRef.current = controller;\n const { signal } = controller;\n\n void (async () => {\n try {\n const promiseOrGenerator = adapter.generate({\n messages: currentMessages,\n signal,\n });\n\n await consumeSuggestionResult(promiseOrGenerator, {\n signal,\n onUpdate: setSuggestions,\n });\n } catch {}\n })();\n }, [hasAdapter, isRunning]);\n\n useEffect(() => {\n return () => {\n controllerRef.current?.abort();\n };\n }, []);\n\n return suggestions;\n};\n\nconst NO_CANCELLED_MESSAGE_IDS: ReadonlySet<string> = new Set();\n\nconst toChatError = (error: Error): AssistantError => {\n const code = (error as { code?: unknown }).code;\n return {\n code:\n typeof code === \"string\"\n ? code\n : error.name !== \"Error\"\n ? error.name\n : \"unknown\",\n message: error.message,\n };\n};\n\nexport const useAISDKRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n chatHelpers: ReturnType<typeof useChat<UI_MESSAGE>>,\n adapter: AISDKRuntimeAdapter<UI_MESSAGE> = {},\n) => {\n const {\n adapters,\n toCreateMessage: customToCreateMessage,\n cancelPendingToolCallsOnSend = true,\n onResume,\n onResumeToolCall,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n } = adapter;\n const suggestionAdapter = adapters?.suggestion;\n const contextAdapters = useRuntimeAdapters();\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const [cancelledMessages, setCancelledMessages] = useState<{\n chatId: string;\n ids: ReadonlySet<string>;\n } | null>(null);\n const toolArgsKeyOrderCacheRef = useRef<Map<string, Map<string, string[]>>>(\n new Map(),\n );\n const toolLastInputCacheRef = useRef<Map<string, ReadonlyJSONObject>>(\n new Map(),\n );\n const mcpAppMetadataCacheRef = useRef<Map<string, McpAppMetadata>>(new Map());\n const lastRunConfigRef = useRef<RunConfig | undefined>(undefined);\n\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const providerIsRunning =\n chatHelpers.status === \"submitted\" || chatHelpers.status === \"streaming\";\n const isRunning = providerIsRunning || hasExecutingTools;\n const wasProviderRunningRef = useRef(providerIsRunning);\n\n const messageTiming = useStreamingTiming(chatHelpers.messages, isRunning);\n\n // Flag the streaming message optimistic: its id can be swapped for a server\n // id mid-run, and the repository then drops the orphaned pre-swap id (#4037).\n const lastMessage = chatHelpers.messages.at(-1);\n const optimisticMessageId =\n isRunning && lastMessage?.role === \"assistant\" ? lastMessage.id : undefined;\n\n const cancelledMessageIds =\n cancelledMessages?.chatId === chatHelpers.id\n ? cancelledMessages.ids\n : NO_CANCELLED_MESSAGE_IDS;\n\n const retractCancellation = useCallback(\n (chatId: string, messageId: string) => {\n setCancelledMessages((prev) => {\n if (prev?.chatId !== chatId || !prev.ids.has(messageId)) return prev;\n const ids = new Set(prev.ids);\n ids.delete(messageId);\n return { chatId, ids };\n });\n },\n [],\n );\n\n // A provider run that resumes the stopped response retracts its cancellation;\n // a run that starts a new response leaves the stopped one marked.\n const resumedMessageId =\n providerIsRunning && lastMessage?.role === \"assistant\"\n ? lastMessage.id\n : undefined;\n\n useEffect(() => {\n const wasProviderRunning = wasProviderRunningRef.current;\n wasProviderRunningRef.current = providerIsRunning;\n if (wasProviderRunning || !resumedMessageId) return;\n retractCancellation(chatHelpers.id, resumedMessageId);\n }, [\n providerIsRunning,\n resumedMessageId,\n chatHelpers.id,\n retractCancellation,\n ]);\n\n const messages = AISDKMessageConverter.useThreadMessages({\n isRunning,\n messages: chatHelpers.messages,\n joinStrategy,\n metadata: useMemo(\n () => ({\n toolStatuses,\n messageTiming,\n toolArgsKeyOrderCache: toolArgsKeyOrderCacheRef.current,\n toolLastInputCache: toolLastInputCacheRef.current,\n mcpAppMetadataCache: mcpAppMetadataCacheRef.current,\n ...(optimisticMessageId && { optimisticMessageId }),\n ...(chatHelpers.error && {\n error: toChatError(chatHelpers.error),\n }),\n ...(cancelledMessageIds.size > 0 && { cancelledMessageIds }),\n }),\n [\n toolStatuses,\n messageTiming,\n optimisticMessageId,\n chatHelpers.error,\n cancelledMessageIds,\n ],\n ),\n });\n\n const exportedMessageRepository = useMemo(() => {\n if (!messageRepository) return undefined;\n const converted = toExportedMessageRepository(\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n messageRepository,\n );\n return converted.messages.length > 0 ? converted : undefined;\n }, [messageRepository]);\n\n const generatedSuggestions = useGeneratedSuggestions(\n suggestionAdapter,\n messages,\n isRunning,\n );\n\n const [runtimeRef] = useState(() => ({\n get current(): AssistantRuntime {\n return runtime;\n },\n }));\n\n const { isLoading, deleteMessage: deleteHistoryMessage } = useExternalHistory(\n runtimeRef,\n adapters?.history ?? contextAdapters?.history,\n AISDKMessageConverter.toThreadMessages as (\n messages: UI_MESSAGE[],\n ) => ThreadMessage[],\n aiSDKV6FormatAdapter as MessageFormatAdapter<\n UI_MESSAGE,\n AISDKStorageFormat\n >,\n (messages) => {\n chatHelpers.setMessages(messages);\n },\n );\n\n const {\n id: chatId,\n messages: chatMessages,\n status: chatStatus,\n error,\n } = chatHelpers;\n const extras = useMemo(\n () =>\n aiSDKExtras.provide({\n chat: chatHelpers as unknown as UseChatHelpers<UIMessage>,\n error,\n }),\n // oxlint-disable-next-line react/exhaustive-deps -- keyed on the chat's identity and reactive snapshots; useChat re-mints the helpers object every render while its remaining fields are instance-bound methods, and a render-stable extras identity is what lets the external-store core dedupe adapter updates\n [chatId, chatMessages, chatStatus, error],\n );\n\n const completePendingToolCalls = async () => {\n if (!cancelPendingToolCallsOnSend) return;\n\n // The runtime auto-aborts in-flight tool invocations when a new run\n // is dispatched (append() / startRun()). All we need to do here is\n // mark any tool without a result as cancelled in the UI message list.\n\n // Mark any tool without a result as cancelled (uses setMessages to avoid triggering sendAutomaticallyWhen)\n chatHelpers.setMessages((messages) => {\n const lastMessage = messages.at(-1);\n if (lastMessage?.role !== \"assistant\") return messages;\n\n let hasChanges = false;\n const parts = lastMessage.parts?.map((part) => {\n if (!isToolUIPart(part)) return part;\n if (\n part.state === \"output-available\" ||\n part.state === \"output-error\" ||\n part.state === \"output-denied\"\n )\n return part;\n\n hasChanges = true;\n const { approval: _approval, ...rest } = part;\n return {\n ...rest,\n state: \"output-error\" as const,\n errorText: \"User cancelled tool call by sending a new message.\",\n };\n });\n\n if (!hasChanges) return messages;\n return [...messages.slice(0, -1), { ...lastMessage, parts }];\n });\n };\n\n const hasSeededRepositoryRef = useRef(false);\n const shouldFeedRepository =\n exportedMessageRepository != null &&\n !hasSeededRepositoryRef.current &&\n messages.length === 0;\n\n const runtime = useExternalStoreRuntime({\n isRunning: providerIsRunning,\n ...(shouldFeedRepository\n ? { messageRepository: exportedMessageRepository }\n : { messages }),\n unstable_enableToolInvocations: true,\n setToolStatuses,\n setMessages: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onImport: (messages) =>\n chatHelpers.setMessages(\n messages\n .map(getVercelAIMessages<UI_MESSAGE>)\n .filter(Boolean)\n .flat(),\n ),\n onExportExternalState: (): MessageFormatRepository<UI_MESSAGE> => {\n const exported = runtimeRef.current.thread.export();\n\n const expandedMessages: MessageFormatItem<UI_MESSAGE>[] = [];\n const lastInnerIdMap = new Map<string, string>();\n\n for (const item of exported.messages) {\n const innerMessages = getExternalStoreMessages<UI_MESSAGE>(\n item.message,\n );\n let parentId =\n item.parentId != null\n ? (lastInnerIdMap.get(item.parentId) ?? item.parentId)\n : null;\n for (const innerMessage of innerMessages) {\n expandedMessages.push({ parentId, message: innerMessage });\n parentId = aiSDKV6FormatAdapter.getId(innerMessage as UIMessage);\n }\n if (innerMessages.length > 0) {\n lastInnerIdMap.set(\n item.message.id,\n aiSDKV6FormatAdapter.getId(\n innerMessages[innerMessages.length - 1]! as UIMessage,\n ),\n );\n }\n }\n\n const result: MessageFormatRepository<UI_MESSAGE> = {\n messages: expandedMessages,\n };\n\n if (exported.headId != null) {\n result.headId = lastInnerIdMap.get(exported.headId) ?? exported.headId;\n }\n\n return result;\n },\n onLoadExternalState: (repo: MessageFormatRepository<UI_MESSAGE>) => {\n // Convert MessageFormatRepository to ExportedMessageRepository\n const exportedRepo = toExportedMessageRepository(\n AISDKMessageConverter.toThreadMessages,\n repo,\n );\n\n // Import into the thread's MessageRepository\n runtimeRef.current.thread.import(exportedRepo);\n },\n onCancel: async () => {\n const message = chatHelpers.messages.at(-1);\n const cancelledId =\n isRunning && message?.role === \"assistant\" ? message.id : undefined;\n if (cancelledId) {\n const liveIds = new Set(chatHelpers.messages.map((m) => m.id));\n setCancelledMessages((prev) => {\n const kept =\n prev?.chatId === chatHelpers.id\n ? [...prev.ids].filter((id) => liveIds.has(id))\n : [];\n return {\n chatId: chatHelpers.id,\n ids: new Set([...kept, cancelledId]),\n };\n });\n }\n try {\n await chatHelpers.stop();\n } catch (error) {\n if (!(error instanceof Error && error.name === \"AbortError\")) {\n if (cancelledId) retractCancellation(chatHelpers.id, cancelledId);\n throw error;\n }\n }\n },\n onNew: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n\n if (!(message.startRun ?? message.role === \"user\")) {\n chatHelpers.setMessages((current) => [\n ...current,\n toUIMessage<UI_MESSAGE>(createMessage, message.role),\n ]);\n return;\n }\n\n lastRunConfigRef.current = message.runConfig;\n await completePendingToolCalls();\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onEdit: async (message) => {\n const createMessage = (\n customToCreateMessage ?? toCreateMessage\n )<UI_MESSAGE>(message);\n\n if (!(message.startRun ?? message.role === \"user\")) {\n chatHelpers.setMessages((current) => [\n ...sliceMessagesUntil(current, message.parentId),\n toUIMessage<UI_MESSAGE>(createMessage, message.role),\n ]);\n return;\n }\n\n lastRunConfigRef.current = message.runConfig;\n chatHelpers.setMessages((current) =>\n sliceMessagesUntil(current, message.parentId),\n );\n await chatHelpers.sendMessage(createMessage, {\n metadata: message.runConfig,\n });\n },\n onDelete: async (messageId) => {\n const threadMessages = runtimeRef.current.thread.getState().messages;\n const messageIndex = threadMessages.findIndex(\n (message) => message.id === messageId,\n );\n if (messageIndex === -1) return;\n\n await deleteHistoryMessage(messageId);\n\n const deleteIds = new Set(\n getExternalStoreMessages<UI_MESSAGE>(threadMessages[messageIndex]!).map(\n (message) => message.id,\n ),\n );\n chatHelpers.setMessages((current) =>\n current.filter((message) => !deleteIds.has(message.id)),\n );\n },\n onReload: async (parentId: string | null, config) => {\n lastRunConfigRef.current = config.runConfig;\n const newMessages = sliceMessagesUntil(chatHelpers.messages, parentId);\n chatHelpers.setMessages(newMessages);\n\n await chatHelpers.regenerate({ metadata: config.runConfig });\n },\n onAddToolResult: ({\n toolCallId,\n toolName,\n result,\n isError,\n modelContent,\n }) => {\n const options = { metadata: lastRunConfigRef.current };\n if (isError) {\n return Promise.resolve(\n chatHelpers.addToolOutput({\n state: \"output-error\",\n tool: toolName ?? toolCallId,\n toolCallId,\n errorText:\n typeof result === \"string\" ? result : JSON.stringify(result),\n options,\n }),\n );\n } else {\n const output =\n modelContent !== undefined\n ? wrapModelContentEnvelope(result, modelContent)\n : result;\n return Promise.resolve(\n chatHelpers.addToolOutput({\n tool: toolName,\n toolCallId,\n output,\n options,\n }),\n );\n }\n },\n onRespondToToolApproval: ({ approvalId, approved, reason }) =>\n Promise.resolve(\n chatHelpers.addToolApprovalResponse({\n id: approvalId,\n approved,\n ...(reason != null && { reason }),\n options: { metadata: lastRunConfigRef.current },\n }),\n ),\n ...pickExternalStoreSharedOptions(adapter),\n ...(adapter.unstable_messageRepositoryInstance && {\n unstable_messageRepositoryInstance:\n adapter.unstable_messageRepositoryInstance,\n }),\n ...(suggestionAdapter ? { suggestions: generatedSuggestions } : {}),\n ...(onResume && { onResume }),\n ...(onResumeToolCall && { onResumeToolCall }),\n ...(unstable_onBranchChange && { unstable_onBranchChange }),\n adapters: {\n attachments: vercelAttachmentAdapter,\n ...contextAdapters,\n ...adapters,\n },\n extras,\n isLoading,\n });\n\n const setMessagesRef = useRef(chatHelpers.setMessages);\n useInsertionEffect(() => {\n setMessagesRef.current = chatHelpers.setMessages;\n }, [chatHelpers.setMessages]);\n\n useEffect(() => {\n if (hasSeededRepositoryRef.current) return;\n if (!exportedMessageRepository) return;\n if (chatHelpers.messages.length > 0) {\n hasSeededRepositoryRef.current = true;\n return;\n }\n const tempRepo = new MessageRepository();\n tempRepo.import(exportedMessageRepository);\n setMessagesRef.current(\n tempRepo.getMessages().flatMap(getExternalStoreMessages<UI_MESSAGE>),\n );\n hasSeededRepositoryRef.current = true;\n }, [exportedMessageRepository, chatHelpers.messages.length]);\n return runtime;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatRuntime.d.ts","names":[],"sources":["../../src/runtime/useChatRuntime.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"useChatRuntime.d.ts","names":[],"sources":["../../src/runtime/useChatRuntime.ts"],"mappings":";;;;;KAaY,sBAAsB,mBAAmB,YAAY,aAC/D,kBAAkB;EAChB,QAAQ;EACR,qBAAqB;;cAoBZ,iBAAkB,mBAAmB,YAAY,aAAW,OAAA,qBAAA,YAItE,sBAAsB,gBAAmB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useChatThread } from "./useChatThread.js";
|
|
3
|
+
import { AI_SDK_SDK } from "./sdkIdentity.js";
|
|
3
4
|
import { useCloudThreadListAdapter, useRemoteThreadListRuntime } from "@assistant-ui/core/react";
|
|
4
5
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
5
6
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
@@ -31,7 +32,10 @@ const useChatThreadRuntime = (options) => {
|
|
|
31
32
|
return useChatThread(options, t1);
|
|
32
33
|
};
|
|
33
34
|
const useChatRuntime = ({ cloud, onThreadIdChange, ...options } = {}) => {
|
|
34
|
-
const cloudAdapter = useCloudThreadListAdapter({
|
|
35
|
+
const cloudAdapter = useCloudThreadListAdapter({
|
|
36
|
+
cloud,
|
|
37
|
+
sdk: AI_SDK_SDK
|
|
38
|
+
});
|
|
35
39
|
return useRemoteThreadListRuntime({
|
|
36
40
|
runtimeHook: function RuntimeHook() {
|
|
37
41
|
return useChatThreadRuntime(options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatRuntime.js","names":["c","_c","UIMessage","AssistantCloud","AssistantRuntime","useCloudThreadListAdapter","useRemoteThreadListRuntime","useAui","useAuiState","useChatThread","ChatThreadOptions","UseChatRuntimeOptions","UI_MESSAGE","cloud","onThreadIdChange","threadId","useChatThreadRuntime","options","$","id","_temp","isMainThread","_temp2","aui","t0","threadListItem","source","undefined","t1","getThreadListItem","stopOnClientDestroy","useChatRuntime","cloudAdapter","runtimeHook","RuntimeHook","adapter","allowNesting","s","s_0","threads","mainThreadId"],"sources":["../../src/runtime/useChatRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport type { UIMessage } from \"@ai-sdk/react\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport type { AssistantRuntime } from \"@assistant-ui/core\";\nimport {\n useCloudThreadListAdapter,\n useRemoteThreadListRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport { useChatThread, type ChatThreadOptions } from \"./useChatThread\";\n\nexport type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatThreadOptions<UI_MESSAGE> & {\n cloud?: AssistantCloud | undefined;\n onThreadIdChange?: ((threadId: string | undefined) => void) | undefined;\n };\n\nconst useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n options?: ChatThreadOptions<UI_MESSAGE>,\n): AssistantRuntime => {\n const id = useAuiState((s) => s.threadListItem.id);\n const isMainThread = useAuiState(\n (s) => s.threads.mainThreadId === s.threadListItem.id,\n );\n const aui = useAui();\n return useChatThread(options, {\n id,\n isMainThread,\n getThreadListItem: () =>\n aui.threadListItem.source ? aui.threadListItem : undefined,\n stopOnClientDestroy: true,\n });\n};\n\nexport const useChatRuntime = <UI_MESSAGE extends UIMessage = UIMessage>({\n cloud,\n onThreadIdChange,\n ...options\n}: UseChatRuntimeOptions<UI_MESSAGE> = {}): AssistantRuntime => {\n const cloudAdapter = useCloudThreadListAdapter({ cloud });\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useChatThreadRuntime(options);\n },\n adapter: cloudAdapter,\n allowNesting: true,\n onThreadIdChange,\n });\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"useChatRuntime.js","names":["c","_c","UIMessage","AssistantCloud","AssistantRuntime","useCloudThreadListAdapter","useRemoteThreadListRuntime","useAui","useAuiState","useChatThread","ChatThreadOptions","AI_SDK_SDK","UseChatRuntimeOptions","UI_MESSAGE","cloud","onThreadIdChange","threadId","useChatThreadRuntime","options","$","id","_temp","isMainThread","_temp2","aui","t0","threadListItem","source","undefined","t1","getThreadListItem","stopOnClientDestroy","useChatRuntime","cloudAdapter","sdk","runtimeHook","RuntimeHook","adapter","allowNesting","s","s_0","threads","mainThreadId"],"sources":["../../src/runtime/useChatRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport type { UIMessage } from \"@ai-sdk/react\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport type { AssistantRuntime } from \"@assistant-ui/core\";\nimport {\n useCloudThreadListAdapter,\n useRemoteThreadListRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport { useChatThread, type ChatThreadOptions } from \"./useChatThread\";\nimport { AI_SDK_SDK } from \"./sdkIdentity\";\n\nexport type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatThreadOptions<UI_MESSAGE> & {\n cloud?: AssistantCloud | undefined;\n onThreadIdChange?: ((threadId: string | undefined) => void) | undefined;\n };\n\nconst useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n options?: ChatThreadOptions<UI_MESSAGE>,\n): AssistantRuntime => {\n const id = useAuiState((s) => s.threadListItem.id);\n const isMainThread = useAuiState(\n (s) => s.threads.mainThreadId === s.threadListItem.id,\n );\n const aui = useAui();\n return useChatThread(options, {\n id,\n isMainThread,\n getThreadListItem: () =>\n aui.threadListItem.source ? aui.threadListItem : undefined,\n stopOnClientDestroy: true,\n });\n};\n\nexport const useChatRuntime = <UI_MESSAGE extends UIMessage = UIMessage>({\n cloud,\n onThreadIdChange,\n ...options\n}: UseChatRuntimeOptions<UI_MESSAGE> = {}): AssistantRuntime => {\n const cloudAdapter = useCloudThreadListAdapter({ cloud, sdk: AI_SDK_SDK });\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useChatThreadRuntime(options);\n },\n adapter: cloudAdapter,\n allowNesting: true,\n onThreadIdChange,\n });\n};\n"],"mappings":";;;;;;;AAmBA,MAAMiB,wBAAuBC,YAAA;CAAA,MAAAC,IAAAlB,EAAA,CAAA;CAG3B,MAAAmB,KAAWZ,YAAYa,KAA0B;CACjD,MAAAC,eAAqBd,YACnBe,MACF;CACA,MAAAC,MAAYjB,OAAO;CAAE,IAAAkB;CAAA,IAAAN,EAAA,OAAAK,KAAA;EAIAC,WACjBD,IAAGE,eAAeC,SAAUH,IAAGE,iBAA/BE,KAAAA;EAA0DT,EAAA,KAAAK;EAAAL,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CAAA,IAAAU;CAAA,IAAAV,EAAA,OAAAC,MAAAD,EAAA,OAAAG,gBAAAH,EAAA,OAAAM,IAAA;EAJhCI,KAAA;GAAAT;GAAAE;GAAAQ,mBAGTL;GACyCM,qBACvC;EACvB;EAACZ,EAAA,KAAAC;EAAAD,EAAA,KAAAG;EAAAH,EAAA,KAAAM;EAAAN,EAAA,KAAAU;CAAA,OAAAA,KAAAV,EAAA;CAAA,OANMV,cAAcS,SAASW,EAM7B;AAAC;AAGJ,MAAaG,kBAA4D,EACvElB,OACAC,kBACA,GAAGG,YACkC,CAAC,MAAwB;CAC9D,MAAMe,eAAe5B,0BAA0B;EAAES;EAAOoB,KAAKvB;CAAW,CAAC;CACzE,OAAOL,2BAA2B;EAChC6B,aAAa,SAASC,cAAc;GAClC,OAAOnB,qBAAqBC,OAAO;EACrC;EACAmB,SAASJ;EACTK,cAAc;EACdvB;CACF,CAAC;AACH;AA/B6B,SAAAM,MAAAkB,GAAA;CAAA,OAGGA,EAACb,eAAeN;AAAG;AAHtB,SAAAG,OAAAiB,KAAA;CAAA,OAKlBD,IAACE,QAAQC,iBAAkBH,IAACb,eAAeN;AAAG"}
|
|
@@ -56,7 +56,7 @@ const splitChatThreadOptions = (options) => {
|
|
|
56
56
|
};
|
|
57
57
|
const useChatThread = (options, env) => {
|
|
58
58
|
const { adapters, transport: transportOptions, throttle, toCreateMessage, onResume, onResumeToolCall, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, chatInit: chatOptions } = splitChatThreadOptions(options);
|
|
59
|
-
const { id, isMainThread, getThreadListItem, stopOnClientDestroy =
|
|
59
|
+
const { id, isMainThread, getThreadListItem, stopOnClientDestroy = true, chat: externalChat, messageRepositoryInstance } = env;
|
|
60
60
|
const defaultTransport = useMemo(() => new AssistantChatTransport(), []);
|
|
61
61
|
const sourceTransport = transportOptions ?? defaultTransport;
|
|
62
62
|
const transport = useDynamicChatTransport(sourceTransport);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatThread.js","names":["useChat","Chat","UIMessage","MessageRepository","pickExternalStoreSharedOptions","AssistantRuntime","ExternalStoreSharedOptions","useAISDKRuntime","AISDKRuntimeAdapter","CustomToCreateMessageFunction","ChatInit","ChatTransport","AssistantChatTransport","InitializableThreadListItem","AssistantChatResumableOptions","ResumableClientStorage","useCallback","useEffect","useMemo","useRef","useSyncExternalStore","useResourceCleanup","ChatThreadOptions","UI_MESSAGE","throttle","adapters","toCreateMessage","onResume","onResumeToolCall","onResumeError","error","joinStrategy","messageRepository","unstable_onBranchChange","ChatThreadEnvironment","id","isMainThread","getThreadListItem","stopOnClientDestroy","chat","messageRepositoryInstance","useDynamicChatTransport","transport","transportRef","current","dynamicTransport","Proxy","get","_","prop","res","bind","getResumableAdapter","candidate","undefined","call","getNoPendingStreamId","resumedStreamIdsByStorage","WeakMap","Set","getResumedStreamIds","storage","resumedStreamIds","set","splitChatThreadOptions","options","isDisabled","_isDisabled","isSendDisabled","_isSendDisabled","unstable_capabilities","_unstable_capabilities","suggestions","_suggestions","chatInit","useChatThread","env","transportOptions","chatOptions","externalChat","defaultTransport","sourceTransport","stop","catch","runtime","unstable_messageRepositoryInstance","setRuntime","__internal_setGetThreadListItem","subscribeToRuntime","callback","thread","subscribe","getHistoryLoadingSnapshot","getState","isLoading","isLoadingHistory","resumableStorage","subscribeToResumableStorage","getPendingStreamId","getStreamId","pendingStreamId","isChatRunning","status","onResumeErrorRef","has","add","resumeStream","err","console","warn","callbackError","clear"],"sources":["../../src/runtime/useChatThread.ts"],"sourcesContent":["\"use client\";\n\nimport { useChat, type Chat, type UIMessage } from \"@ai-sdk/react\";\nimport type { MessageRepository } from \"@assistant-ui/core/internal\";\nimport {\n pickExternalStoreSharedOptions,\n type AssistantRuntime,\n type ExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport type { ChatInit, ChatTransport } from \"ai\";\nimport {\n AssistantChatTransport,\n type InitializableThreadListItem,\n} from \"../transport/AssistantChatTransport\";\nimport type {\n AssistantChatResumableOptions,\n ResumableClientStorage,\n} from \"../transport/resumable\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport { useResourceCleanup } from \"./useResourceCleanup\";\n\nexport type ChatThreadOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> &\n ExternalStoreSharedOptions & {\n throttle?: number | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n onResume?: AISDKRuntimeAdapter[\"onResume\"];\n onResumeToolCall?: AISDKRuntimeAdapter[\"onResumeToolCall\"];\n /**\n * Called when an automatic resumable stream reconnect fails. Use this to\n * surface a toast, report telemetry, or mark the thread as needing a\n * retry. The failed stream id is cleared after the callback unless a\n * newer id has replaced it.\n */\n onResumeError?: ((error: unknown) => void) | undefined;\n joinStrategy?: AISDKRuntimeAdapter[\"joinStrategy\"];\n messageRepository?: AISDKRuntimeAdapter<UI_MESSAGE>[\"messageRepository\"];\n unstable_onBranchChange?: AISDKRuntimeAdapter[\"unstable_onBranchChange\"];\n };\n\nexport type ChatThreadEnvironment<UI_MESSAGE extends UIMessage = UIMessage> = {\n id: string;\n isMainThread: boolean;\n getThreadListItem: () => InitializableThreadListItem | undefined;\n stopOnClientDestroy?: boolean;\n /**\n * An externally owned chat instance. State lives on the instance, so it\n * survives the hosting resource unmounting; construction options are read\n * from the instance.\n */\n chat?: Chat<UI_MESSAGE> | undefined;\n /**\n * An externally owned per-thread message repository. Hosts that route\n * multiple threads through one mounting pass a distinct instance per\n * thread so histories and branches stay isolated.\n */\n messageRepositoryInstance?: MessageRepository | undefined;\n};\n\nconst useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): ChatTransport<UI_MESSAGE> => {\n const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n const dynamicTransport = useMemo(\n () =>\n new Proxy(transportRef.current, {\n get(_, prop) {\n const res =\n transportRef.current[prop as keyof ChatTransport<UI_MESSAGE>];\n return typeof res === \"function\"\n ? res.bind(transportRef.current)\n : res;\n },\n }),\n [],\n );\n return dynamicTransport;\n};\n\nconst getResumableAdapter = <UI_MESSAGE extends UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): AssistantChatResumableOptions | undefined => {\n if (transport instanceof AssistantChatTransport) {\n return transport.getResumableAdapter();\n }\n const candidate = (transport as { getResumableAdapter?: () => unknown })\n .getResumableAdapter;\n if (typeof candidate !== \"function\") return undefined;\n return candidate.call(transport) as AssistantChatResumableOptions | undefined;\n};\n\nconst getNoPendingStreamId = () => null;\n\nconst resumedStreamIdsByStorage = new WeakMap<\n ResumableClientStorage,\n Set<string>\n>();\n\nconst getResumedStreamIds = (storage: ResumableClientStorage | undefined) => {\n if (!storage) return new Set<string>();\n let resumedStreamIds = resumedStreamIdsByStorage.get(storage);\n if (!resumedStreamIds) {\n resumedStreamIds = new Set();\n resumedStreamIdsByStorage.set(storage, resumedStreamIds);\n }\n return resumedStreamIds;\n};\n\n/**\n * Splits the combined options into the assistant-ui side and the `ChatInit`\n * remainder the AI SDK consumes, so external `Chat` construction forwards the\n * same fields `useChat` would.\n */\nexport const splitChatThreadOptions = <UI_MESSAGE extends UIMessage>(\n options: ChatThreadOptions<UI_MESSAGE> | undefined,\n) => {\n const {\n adapters,\n transport,\n throttle,\n toCreateMessage,\n isDisabled: _isDisabled,\n isSendDisabled: _isSendDisabled,\n unstable_capabilities: _unstable_capabilities,\n suggestions: _suggestions,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n ...chatInit\n } = options ?? {};\n // peel guard: any shared key left in `chatInit` collapses this to `never`\n true satisfies keyof typeof chatInit &\n keyof ExternalStoreSharedOptions extends never\n ? true\n : never;\n return {\n adapters,\n transport,\n throttle,\n toCreateMessage,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n chatInit,\n };\n};\n\nexport const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(\n options: ChatThreadOptions<UI_MESSAGE> | undefined,\n env: ChatThreadEnvironment<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n throttle,\n toCreateMessage,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n chatInit: chatOptions,\n } = splitChatThreadOptions(options);\n\n const {\n id,\n isMainThread,\n getThreadListItem,\n stopOnClientDestroy = false,\n chat: externalChat,\n messageRepositoryInstance,\n } = env;\n\n const defaultTransport = useMemo(() => new AssistantChatTransport(), []);\n const sourceTransport = transportOptions ?? defaultTransport;\n const transport = useDynamicChatTransport(sourceTransport);\n\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n ...(throttle !== undefined && { throttle }),\n ...(externalChat !== undefined && { chat: externalChat }),\n });\n\n useResourceCleanup(stopOnClientDestroy, () => {\n void chat.stop().catch(() => {});\n });\n\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...pickExternalStoreSharedOptions(options ?? {}),\n ...(toCreateMessage && { toCreateMessage }),\n ...(onResume && { onResume }),\n ...(onResumeToolCall && { onResumeToolCall }),\n ...(joinStrategy && { joinStrategy }),\n ...(messageRepository && { messageRepository }),\n ...(messageRepositoryInstance && {\n unstable_messageRepositoryInstance: messageRepositoryInstance,\n }),\n ...(unstable_onBranchChange && { unstable_onBranchChange }),\n });\n\n if (sourceTransport instanceof AssistantChatTransport) {\n sourceTransport.setRuntime(runtime);\n sourceTransport.__internal_setGetThreadListItem(getThreadListItem);\n }\n\n const subscribeToRuntime = useCallback(\n (callback: () => void) => runtime.thread.subscribe(callback),\n [runtime],\n );\n const getHistoryLoadingSnapshot = useCallback(\n () => runtime.thread.getState().isLoading,\n [runtime],\n );\n const isLoadingHistory = useSyncExternalStore(\n subscribeToRuntime,\n getHistoryLoadingSnapshot,\n getHistoryLoadingSnapshot,\n );\n\n const resumableStorage = useMemo(\n () => getResumableAdapter(sourceTransport)?.storage,\n [sourceTransport],\n );\n const subscribeToResumableStorage = useCallback(\n (callback: () => void) =>\n isMainThread\n ? (resumableStorage?.subscribe?.(callback, id) ?? (() => {}))\n : () => {},\n [id, isMainThread, resumableStorage],\n );\n const getPendingStreamId = useCallback(\n () => (isMainThread ? (resumableStorage?.getStreamId(id) ?? null) : null),\n [id, isMainThread, resumableStorage],\n );\n const pendingStreamId = useSyncExternalStore(\n subscribeToResumableStorage,\n getPendingStreamId,\n getNoPendingStreamId,\n );\n const isChatRunning =\n chat.status === \"submitted\" || chat.status === \"streaming\";\n\n const resumedStreamIds = useMemo(\n () => getResumedStreamIds(resumableStorage),\n [resumableStorage],\n );\n const onResumeErrorRef = useRef(onResumeError);\n useEffect(() => {\n onResumeErrorRef.current = onResumeError;\n });\n useEffect(() => {\n if (!pendingStreamId || resumedStreamIds.has(pendingStreamId)) {\n return;\n }\n if (isChatRunning) {\n resumedStreamIds.add(pendingStreamId);\n return;\n }\n if (isLoadingHistory) return;\n resumedStreamIds.add(pendingStreamId);\n chat.resumeStream().catch((err: unknown) => {\n console.warn(\"[assistant-ui] resumable: resume failed\", err);\n try {\n onResumeErrorRef.current?.(err);\n } catch (callbackError) {\n console.error(\n \"[assistant-ui] resumable: onResumeError callback failed\",\n callbackError,\n );\n } finally {\n if (resumableStorage?.getStreamId(id) === pendingStreamId) {\n resumableStorage.clear(id);\n }\n }\n });\n }, [\n chat,\n id,\n isChatRunning,\n isLoadingHistory,\n pendingStreamId,\n resumableStorage,\n resumedStreamIds,\n ]);\n\n return runtime;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useChatThread.js","names":["useChat","Chat","UIMessage","MessageRepository","pickExternalStoreSharedOptions","AssistantRuntime","ExternalStoreSharedOptions","useAISDKRuntime","AISDKRuntimeAdapter","CustomToCreateMessageFunction","ChatInit","ChatTransport","AssistantChatTransport","InitializableThreadListItem","AssistantChatResumableOptions","ResumableClientStorage","useCallback","useEffect","useMemo","useRef","useSyncExternalStore","useResourceCleanup","ChatThreadOptions","UI_MESSAGE","throttle","adapters","toCreateMessage","onResume","onResumeToolCall","onResumeError","error","joinStrategy","messageRepository","unstable_onBranchChange","ChatThreadEnvironment","id","isMainThread","getThreadListItem","stopOnClientDestroy","chat","messageRepositoryInstance","useDynamicChatTransport","transport","transportRef","current","dynamicTransport","Proxy","get","_","prop","res","bind","getResumableAdapter","candidate","undefined","call","getNoPendingStreamId","resumedStreamIdsByStorage","WeakMap","Set","getResumedStreamIds","storage","resumedStreamIds","set","splitChatThreadOptions","options","isDisabled","_isDisabled","isSendDisabled","_isSendDisabled","unstable_capabilities","_unstable_capabilities","suggestions","_suggestions","chatInit","useChatThread","env","transportOptions","chatOptions","externalChat","defaultTransport","sourceTransport","stop","catch","runtime","unstable_messageRepositoryInstance","setRuntime","__internal_setGetThreadListItem","subscribeToRuntime","callback","thread","subscribe","getHistoryLoadingSnapshot","getState","isLoading","isLoadingHistory","resumableStorage","subscribeToResumableStorage","getPendingStreamId","getStreamId","pendingStreamId","isChatRunning","status","onResumeErrorRef","has","add","resumeStream","err","console","warn","callbackError","clear"],"sources":["../../src/runtime/useChatThread.ts"],"sourcesContent":["\"use client\";\n\nimport { useChat, type Chat, type UIMessage } from \"@ai-sdk/react\";\nimport type { MessageRepository } from \"@assistant-ui/core/internal\";\nimport {\n pickExternalStoreSharedOptions,\n type AssistantRuntime,\n type ExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport type { ChatInit, ChatTransport } from \"ai\";\nimport {\n AssistantChatTransport,\n type InitializableThreadListItem,\n} from \"../transport/AssistantChatTransport\";\nimport type {\n AssistantChatResumableOptions,\n ResumableClientStorage,\n} from \"../transport/resumable\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport { useResourceCleanup } from \"./useResourceCleanup\";\n\nexport type ChatThreadOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> &\n ExternalStoreSharedOptions & {\n throttle?: number | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n onResume?: AISDKRuntimeAdapter[\"onResume\"];\n onResumeToolCall?: AISDKRuntimeAdapter[\"onResumeToolCall\"];\n /**\n * Called when an automatic resumable stream reconnect fails. Use this to\n * surface a toast, report telemetry, or mark the thread as needing a\n * retry. The failed stream id is cleared after the callback unless a\n * newer id has replaced it.\n */\n onResumeError?: ((error: unknown) => void) | undefined;\n joinStrategy?: AISDKRuntimeAdapter[\"joinStrategy\"];\n messageRepository?: AISDKRuntimeAdapter<UI_MESSAGE>[\"messageRepository\"];\n unstable_onBranchChange?: AISDKRuntimeAdapter[\"unstable_onBranchChange\"];\n };\n\nexport type ChatThreadEnvironment<UI_MESSAGE extends UIMessage = UIMessage> = {\n id: string;\n isMainThread: boolean;\n getThreadListItem: () => InitializableThreadListItem | undefined;\n stopOnClientDestroy?: boolean;\n /**\n * An externally owned chat instance. State lives on the instance, so it\n * survives the hosting resource unmounting; construction options are read\n * from the instance.\n */\n chat?: Chat<UI_MESSAGE> | undefined;\n /**\n * An externally owned per-thread message repository. Hosts that route\n * multiple threads through one mounting pass a distinct instance per\n * thread so histories and branches stay isolated.\n */\n messageRepositoryInstance?: MessageRepository | undefined;\n};\n\nconst useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): ChatTransport<UI_MESSAGE> => {\n const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n const dynamicTransport = useMemo(\n () =>\n new Proxy(transportRef.current, {\n get(_, prop) {\n const res =\n transportRef.current[prop as keyof ChatTransport<UI_MESSAGE>];\n return typeof res === \"function\"\n ? res.bind(transportRef.current)\n : res;\n },\n }),\n [],\n );\n return dynamicTransport;\n};\n\nconst getResumableAdapter = <UI_MESSAGE extends UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): AssistantChatResumableOptions | undefined => {\n if (transport instanceof AssistantChatTransport) {\n return transport.getResumableAdapter();\n }\n const candidate = (transport as { getResumableAdapter?: () => unknown })\n .getResumableAdapter;\n if (typeof candidate !== \"function\") return undefined;\n return candidate.call(transport) as AssistantChatResumableOptions | undefined;\n};\n\nconst getNoPendingStreamId = () => null;\n\nconst resumedStreamIdsByStorage = new WeakMap<\n ResumableClientStorage,\n Set<string>\n>();\n\nconst getResumedStreamIds = (storage: ResumableClientStorage | undefined) => {\n if (!storage) return new Set<string>();\n let resumedStreamIds = resumedStreamIdsByStorage.get(storage);\n if (!resumedStreamIds) {\n resumedStreamIds = new Set();\n resumedStreamIdsByStorage.set(storage, resumedStreamIds);\n }\n return resumedStreamIds;\n};\n\n/**\n * Splits the combined options into the assistant-ui side and the `ChatInit`\n * remainder the AI SDK consumes, so external `Chat` construction forwards the\n * same fields `useChat` would.\n */\nexport const splitChatThreadOptions = <UI_MESSAGE extends UIMessage>(\n options: ChatThreadOptions<UI_MESSAGE> | undefined,\n) => {\n const {\n adapters,\n transport,\n throttle,\n toCreateMessage,\n isDisabled: _isDisabled,\n isSendDisabled: _isSendDisabled,\n unstable_capabilities: _unstable_capabilities,\n suggestions: _suggestions,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n ...chatInit\n } = options ?? {};\n // peel guard: any shared key left in `chatInit` collapses this to `never`\n true satisfies keyof typeof chatInit &\n keyof ExternalStoreSharedOptions extends never\n ? true\n : never;\n return {\n adapters,\n transport,\n throttle,\n toCreateMessage,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n chatInit,\n };\n};\n\nexport const useChatThread = <UI_MESSAGE extends UIMessage = UIMessage>(\n options: ChatThreadOptions<UI_MESSAGE> | undefined,\n env: ChatThreadEnvironment<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n throttle,\n toCreateMessage,\n onResume,\n onResumeToolCall,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n chatInit: chatOptions,\n } = splitChatThreadOptions(options);\n\n const {\n id,\n isMainThread,\n getThreadListItem,\n stopOnClientDestroy = true,\n chat: externalChat,\n messageRepositoryInstance,\n } = env;\n\n const defaultTransport = useMemo(() => new AssistantChatTransport(), []);\n const sourceTransport = transportOptions ?? defaultTransport;\n const transport = useDynamicChatTransport(sourceTransport);\n\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n ...(throttle !== undefined && { throttle }),\n ...(externalChat !== undefined && { chat: externalChat }),\n });\n\n useResourceCleanup(stopOnClientDestroy, () => {\n void chat.stop().catch(() => {});\n });\n\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...pickExternalStoreSharedOptions(options ?? {}),\n ...(toCreateMessage && { toCreateMessage }),\n ...(onResume && { onResume }),\n ...(onResumeToolCall && { onResumeToolCall }),\n ...(joinStrategy && { joinStrategy }),\n ...(messageRepository && { messageRepository }),\n ...(messageRepositoryInstance && {\n unstable_messageRepositoryInstance: messageRepositoryInstance,\n }),\n ...(unstable_onBranchChange && { unstable_onBranchChange }),\n });\n\n if (sourceTransport instanceof AssistantChatTransport) {\n sourceTransport.setRuntime(runtime);\n sourceTransport.__internal_setGetThreadListItem(getThreadListItem);\n }\n\n const subscribeToRuntime = useCallback(\n (callback: () => void) => runtime.thread.subscribe(callback),\n [runtime],\n );\n const getHistoryLoadingSnapshot = useCallback(\n () => runtime.thread.getState().isLoading,\n [runtime],\n );\n const isLoadingHistory = useSyncExternalStore(\n subscribeToRuntime,\n getHistoryLoadingSnapshot,\n getHistoryLoadingSnapshot,\n );\n\n const resumableStorage = useMemo(\n () => getResumableAdapter(sourceTransport)?.storage,\n [sourceTransport],\n );\n const subscribeToResumableStorage = useCallback(\n (callback: () => void) =>\n isMainThread\n ? (resumableStorage?.subscribe?.(callback, id) ?? (() => {}))\n : () => {},\n [id, isMainThread, resumableStorage],\n );\n const getPendingStreamId = useCallback(\n () => (isMainThread ? (resumableStorage?.getStreamId(id) ?? null) : null),\n [id, isMainThread, resumableStorage],\n );\n const pendingStreamId = useSyncExternalStore(\n subscribeToResumableStorage,\n getPendingStreamId,\n getNoPendingStreamId,\n );\n const isChatRunning =\n chat.status === \"submitted\" || chat.status === \"streaming\";\n\n const resumedStreamIds = useMemo(\n () => getResumedStreamIds(resumableStorage),\n [resumableStorage],\n );\n const onResumeErrorRef = useRef(onResumeError);\n useEffect(() => {\n onResumeErrorRef.current = onResumeError;\n });\n useEffect(() => {\n if (!pendingStreamId || resumedStreamIds.has(pendingStreamId)) {\n return;\n }\n if (isChatRunning) {\n resumedStreamIds.add(pendingStreamId);\n return;\n }\n if (isLoadingHistory) return;\n resumedStreamIds.add(pendingStreamId);\n chat.resumeStream().catch((err: unknown) => {\n console.warn(\"[assistant-ui] resumable: resume failed\", err);\n try {\n onResumeErrorRef.current?.(err);\n } catch (callbackError) {\n console.error(\n \"[assistant-ui] resumable: onResumeError callback failed\",\n callbackError,\n );\n } finally {\n if (resumableStorage?.getStreamId(id) === pendingStreamId) {\n resumableStorage.clear(id);\n }\n }\n });\n }, [\n chat,\n id,\n isChatRunning,\n isLoadingHistory,\n pendingStreamId,\n resumableStorage,\n resumedStreamIds,\n ]);\n\n return runtime;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExternalHistory.d.ts","names":[],"sources":["../../src/runtime/useExternalHistory.ts"],"mappings":";;;cAuBa,8BAA+B,UAC1C,mBAAmB,UAAU,eAAe,iBAC5C,UAAU,wBAAwB,cACjC;cA+BU,qBAAsB,UACjC,YAAY,UAAU,mBACtB,gBAAgB,kCAChB,mBAAmB,UAAU,eAAe,iBAC5C,sBAAsB,qBAAqB,gBAC3C,gBAAgB,UAAU;;
|
|
1
|
+
{"version":3,"file":"useExternalHistory.d.ts","names":[],"sources":["../../src/runtime/useExternalHistory.ts"],"mappings":";;;cAuBa,8BAA+B,UAC1C,mBAAmB,UAAU,eAAe,iBAC5C,UAAU,wBAAwB,cACjC;cA+BU,qBAAsB,UACjC,YAAY,UAAU,mBACtB,gBAAgB,kCAChB,mBAAmB,UAAU,eAAe,iBAC5C,sBAAsB,qBAAqB,gBAC3C,gBAAgB,UAAU;;EA8UN,gBAAA,sBAAM"}
|
|
@@ -224,7 +224,10 @@ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storag
|
|
|
224
224
|
lastInnerMessageId = getLastInnerId(innerMessages) ?? lastInnerMessageId;
|
|
225
225
|
if (deferredTelemetryIds.current.has(message.id) && isTerminal) {
|
|
226
226
|
deferredTelemetryIds.current.delete(message.id);
|
|
227
|
-
adapter.reportTelemetry?.(batchItems,
|
|
227
|
+
adapter.reportTelemetry?.(batchItems, {
|
|
228
|
+
...telemetryOptions,
|
|
229
|
+
message
|
|
230
|
+
});
|
|
228
231
|
}
|
|
229
232
|
}
|
|
230
233
|
}).catch((error_0) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExternalHistory.js","names":["AssistantRuntime","ThreadHistoryAdapter","ThreadMessage","MessageFormatAdapter","MessageFormatItem","MessageFormatRepository","ExportedMessageRepository","getExternalStoreMessages","MessageRepository","useAui","useRef","useEffect","useState","RefObject","useCallback","useMemo","toExportedMessageRepository","toThreadMessages","messages","TMessage","survivingIds","Set","survivors","flatMap","m","message","console","warn","parentId","has","add","id","headId","isAwaitingToolApproval","status","type","reason","encodeContent","storageFormatAdapter","item","JSON","stringify","encode","useExternalHistory","runtimeRef","historyAdapter","onSetMessages","loadedRef","itemEpoch","setItemEpoch","aui","optionalThreadListItem","threadListItem","source","hasLoaded","setHasLoaded","historyIds","deferredTelemetryIds","persistedInnerMessages","Map","content","onSetMessagesRef","current","formatAdapter","undefined","withFormat","Error","isLoading","loadHistory","repo","load","length","set","getId","converted","thread","import","tempRepo","getMessages","error","pin","remoteId","getState","subscribe","n","threadState","isRunning","runStartRef","persistTimerRef","ReturnType","setTimeout","persistInFlightRef","Promise","resolve","stepBoundariesRef","wasRunningRef","toolCallCountRef","adapter","unsubscribe","wasRunning","lastMsg","at","role","currentToolCallCount","filter","p","push","Date","now","clearTimeout","persistSettled","initialThreadState","ignoreRunning","latest","boundaries","durationMs","lastAssistant","findLast","tcCount","totalSteps","stepDur","i","Math","round","stepTimestamps","map","endMs","start_ms","end_ms","telemetryOptions","then","lastInnerMessageId","getLastInnerId","msgs","toBatchItems","msg","idx","innerMessages","isTerminal","isAwaitingToolCalls","isReady","update","batchItems","innerId","persisted","get","append","delete","reportTelemetry","catch","deleteMessage","messageId","deleteMessages","bind","messageIndex","findIndex","previousInnerMessages","slice","itemsToDelete","deletion"],"sources":["../../src/runtime/useExternalHistory.ts"],"sourcesContent":["\"use client\";\n\nimport type {\n AssistantRuntime,\n ThreadHistoryAdapter,\n ThreadMessage,\n MessageFormatAdapter,\n MessageFormatItem,\n MessageFormatRepository,\n ExportedMessageRepository,\n} from \"@assistant-ui/core\";\nimport { getExternalStoreMessages } from \"@assistant-ui/core\";\nimport { MessageRepository } from \"@assistant-ui/core/internal\";\nimport { useAui } from \"@assistant-ui/store\";\nimport {\n useRef,\n useEffect,\n useState,\n type RefObject,\n useCallback,\n useMemo,\n} from \"react\";\n\nexport const toExportedMessageRepository = <TMessage>(\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n messages: MessageFormatRepository<TMessage>,\n): ExportedMessageRepository => {\n const survivingIds = new Set<string>();\n const survivors = messages.messages.flatMap((m) => {\n const message = toThreadMessages([m.message])[0];\n if (!message) {\n console.warn(\"Skipping a stored message that could not be loaded.\");\n return [];\n }\n if (m.parentId && !survivingIds.has(m.parentId)) return [];\n survivingIds.add(message.id);\n return [{ ...m, message }];\n });\n\n return {\n headId:\n messages.headId && survivingIds.has(messages.headId)\n ? messages.headId\n : null,\n messages: survivors,\n };\n};\n\nconst isAwaitingToolApproval = (message: ThreadMessage) =>\n message.status?.type === \"requires-action\" &&\n message.status.reason === \"tool-calls\";\n\nconst encodeContent = <TMessage>(\n storageFormatAdapter: MessageFormatAdapter<TMessage, any>,\n item: MessageFormatItem<TMessage>,\n) => JSON.stringify(storageFormatAdapter.encode(item));\n\nexport const useExternalHistory = <TMessage>(\n runtimeRef: RefObject<AssistantRuntime>,\n historyAdapter: ThreadHistoryAdapter | undefined,\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n storageFormatAdapter: MessageFormatAdapter<TMessage, any>,\n onSetMessages: (messages: TMessage[]) => void,\n) => {\n const loadedRef = useRef(false);\n const [itemEpoch, setItemEpoch] = useState(0);\n\n const aui = useAui();\n const optionalThreadListItem = useCallback(\n () => (aui.threadListItem.source ? aui.threadListItem : null),\n [aui],\n );\n\n const [hasLoaded, setHasLoaded] = useState(false);\n\n const historyIds = useRef(new Set<string>());\n const deferredTelemetryIds = useRef(new Set<string>());\n // `content` is a snapshot taken at write time rather than a re-encode of `source`, because a retained message object can be mutated in place by the runtime that produced it.\n const persistedInnerMessages = useRef(\n new Map<string, { source: TMessage; content: string }>(),\n );\n\n const onSetMessagesRef = useRef(onSetMessages);\n useEffect(() => {\n onSetMessagesRef.current = onSetMessages;\n });\n\n const formatAdapter = useMemo(() => {\n if (!historyAdapter) return undefined;\n if (!historyAdapter.withFormat) {\n throw new Error(\n \"useAISDKRuntime: ThreadHistoryAdapter is missing the required `withFormat` method.\",\n );\n }\n return historyAdapter.withFormat<TMessage, any>(storageFormatAdapter);\n }, [historyAdapter, storageFormatAdapter]);\n\n const isLoading = formatAdapter != null && !hasLoaded;\n\n useEffect(() => {\n if (!formatAdapter || loadedRef.current) return undefined;\n\n const loadHistory = async () => {\n try {\n const repo = await formatAdapter.load();\n if (repo && repo.messages.length > 0) {\n for (const m of repo.messages) {\n persistedInnerMessages.current.set(\n storageFormatAdapter.getId(m.message),\n {\n source: m.message,\n content: encodeContent(storageFormatAdapter, m),\n },\n );\n }\n const converted = toExportedMessageRepository(toThreadMessages, repo);\n runtimeRef.current.thread.import(converted);\n\n const tempRepo = new MessageRepository();\n tempRepo.import(converted);\n const messages = tempRepo.getMessages();\n\n onSetMessagesRef.current(\n messages.flatMap(getExternalStoreMessages<TMessage>),\n );\n\n historyIds.current = new Set();\n for (const m of converted.messages) {\n historyIds.current.add(m.message.id);\n if (isAwaitingToolApproval(m.message)) {\n deferredTelemetryIds.current.add(m.message.id);\n }\n }\n }\n } catch (error) {\n console.error(\"Failed to load message history:\", error);\n } finally {\n setHasLoaded(true);\n }\n };\n\n formatAdapter.pin?.();\n\n const remoteId = optionalThreadListItem()?.getState().remoteId;\n if (!remoteId) {\n // History loads asynchronously against the thread list item; without a\n // remote id there is nothing to await, so the flag settles here.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setHasLoaded(true);\n return aui.subscribe(() => {\n if (optionalThreadListItem()?.getState().remoteId) {\n setItemEpoch((n) => n + 1);\n }\n });\n }\n\n const threadState = runtimeRef.current.thread.getState();\n if (threadState.isRunning || threadState.messages.length > 0) {\n loadedRef.current = true;\n setHasLoaded(true);\n return undefined;\n }\n\n loadedRef.current = true;\n void loadHistory();\n return undefined;\n }, [\n formatAdapter,\n toThreadMessages,\n runtimeRef,\n optionalThreadListItem,\n aui,\n itemEpoch,\n storageFormatAdapter,\n ]);\n\n const runStartRef = useRef<number | null>(null);\n const persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const persistInFlightRef = useRef<Promise<void>>(Promise.resolve());\n const stepBoundariesRef = useRef<number[]>([]);\n const wasRunningRef = useRef(false);\n const toolCallCountRef = useRef(0);\n\n useEffect(() => {\n if (!formatAdapter) return;\n const adapter = formatAdapter;\n\n const unsubscribe = runtimeRef.current.thread.subscribe(() => {\n const threadState = runtimeRef.current.thread.getState();\n const { isRunning } = threadState;\n const wasRunning = wasRunningRef.current;\n wasRunningRef.current = isRunning;\n\n // Track step boundaries by content changes (more reliable than isRunning)\n if (runStartRef.current != null) {\n const lastMsg = threadState.messages.at(-1);\n if (lastMsg?.role === \"assistant\") {\n const currentToolCallCount = lastMsg.content.filter(\n (p) => p.type === \"tool-call\",\n ).length;\n while (toolCallCountRef.current < currentToolCallCount) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n toolCallCountRef.current++;\n }\n }\n }\n\n if (isRunning) {\n if (runStartRef.current == null) {\n runStartRef.current = Date.now();\n stepBoundariesRef.current = [];\n toolCallCountRef.current = 0;\n adapter.pin?.();\n }\n // Cancel any pending persist — isRunning went back to true\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n }\n return;\n }\n\n // Only act on the true→false transition\n if (!wasRunning) return;\n\n // Record step boundary offset (synchronous for accuracy)\n if (runStartRef.current != null) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n }\n\n // Debounce: wait one macrotask so agentic step flickers are absorbed\n if (persistTimerRef.current) clearTimeout(persistTimerRef.current);\n persistTimerRef.current = setTimeout(() => {\n persistSettled(false);\n }, 0);\n });\n\n const initialThreadState = runtimeRef.current.thread.getState();\n wasRunningRef.current = initialThreadState.isRunning;\n if (initialThreadState.isRunning) {\n if (runStartRef.current == null) {\n runStartRef.current = Date.now();\n stepBoundariesRef.current = [];\n toolCallCountRef.current = 0;\n adapter.pin?.();\n }\n } else if (initialThreadState.messages.length > 0) {\n persistSettled(true);\n }\n\n function persistSettled(ignoreRunning: boolean) {\n persistTimerRef.current = null;\n const latest = runtimeRef.current.thread.getState();\n if (!ignoreRunning && latest.isRunning) return;\n\n const boundaries = stepBoundariesRef.current;\n const durationMs = boundaries.length > 0 ? boundaries.at(-1) : undefined;\n\n // Fallback: if only 1 boundary but message has multiple steps, distribute evenly\n if (boundaries.length === 1 && durationMs != null) {\n const lastAssistant = latest.messages.findLast(\n (m) => m.role === \"assistant\",\n );\n if (lastAssistant) {\n const tcCount = lastAssistant.content.filter(\n (p) => p.type === \"tool-call\",\n ).length;\n if (tcCount > 0) {\n const totalSteps = tcCount + 1;\n const stepDur = durationMs / totalSteps;\n boundaries.length = 0;\n for (let i = 0; i < totalSteps; i++) {\n boundaries.push(Math.round((i + 1) * stepDur));\n }\n }\n }\n }\n\n // Build per-step timestamps when there are multiple steps\n const stepTimestamps =\n boundaries.length > 1\n ? boundaries.map((endMs, i) => ({\n start_ms: i === 0 ? 0 : boundaries[i - 1]!,\n end_ms: endMs,\n }))\n : undefined;\n\n runStartRef.current = null;\n stepBoundariesRef.current = [];\n\n const telemetryOptions = {\n ...(durationMs != null ? { durationMs } : undefined),\n ...(stepTimestamps != null ? { stepTimestamps } : undefined),\n };\n\n persistInFlightRef.current = persistInFlightRef.current\n .then(async () => {\n const { messages } = latest;\n let lastInnerMessageId: string | null = null;\n\n const getLastInnerId = (msgs: TMessage[]): string | null =>\n msgs.length > 0 ? storageFormatAdapter.getId(msgs.at(-1)!) : null;\n\n const toBatchItems = (msgs: TMessage[]) =>\n msgs.map((msg, idx) => ({\n parentId:\n idx === 0\n ? lastInnerMessageId\n : storageFormatAdapter.getId(msgs[idx - 1]!),\n message: msg,\n }));\n\n for (const message of messages) {\n const innerMessages = getExternalStoreMessages<TMessage>(message);\n\n const isTerminal =\n message.status === undefined ||\n message.status.type === \"complete\" ||\n message.status.type === \"incomplete\";\n const isAwaitingToolCalls = isAwaitingToolApproval(message);\n // A paused message's later content can only reach storage via update, so it is persisted early only when the adapter supports update.\n const isReady =\n isTerminal ||\n (isAwaitingToolCalls && adapter.update !== undefined);\n\n if (!isReady) {\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n continue;\n }\n\n if (!historyIds.current.has(message.id)) {\n historyIds.current.add(message.id);\n deferredTelemetryIds.current.add(message.id);\n }\n\n const batchItems = toBatchItems(innerMessages);\n for (const item of batchItems) {\n const innerId = storageFormatAdapter.getId(item.message);\n const persisted = persistedInnerMessages.current.get(innerId);\n if (!persisted) {\n await adapter.append(item);\n persistedInnerMessages.current.set(innerId, {\n source: item.message,\n content: encodeContent(storageFormatAdapter, item),\n });\n } else if (\n persisted.source !== item.message &&\n durationMs !== undefined &&\n adapter.update\n ) {\n const content = encodeContent(storageFormatAdapter, item);\n if (content === persisted.content) {\n persisted.source = item.message;\n } else {\n try {\n await adapter.update(item, innerId);\n persistedInnerMessages.current.set(innerId, {\n source: item.message,\n content,\n });\n } catch {\n // A failed update leaves the stale baseline behind so the next run stop retries it.\n }\n }\n }\n }\n\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n\n if (deferredTelemetryIds.current.has(message.id) && isTerminal) {\n deferredTelemetryIds.current.delete(message.id);\n adapter.reportTelemetry?.(batchItems, telemetryOptions);\n }\n }\n })\n .catch((error) => {\n console.error(\"Failed to persist message history:\", error);\n });\n }\n\n return () => {\n unsubscribe();\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n persistSettled(false);\n }\n };\n }, [formatAdapter, storageFormatAdapter, runtimeRef]);\n\n const deleteMessage = useCallback(\n async (messageId: string) => {\n const deleteMessages = formatAdapter?.delete?.bind(formatAdapter);\n if (!deleteMessages) return;\n\n const messages = runtimeRef.current.thread.getState().messages;\n const messageIndex = messages.findIndex((m) => m.id === messageId);\n if (messageIndex === -1) return;\n\n const previousInnerMessages = messages\n .slice(0, messageIndex)\n .flatMap(getExternalStoreMessages<TMessage>);\n let parentId = previousInnerMessages.at(-1)\n ? storageFormatAdapter.getId(previousInnerMessages.at(-1)!)\n : null;\n const itemsToDelete = getExternalStoreMessages<TMessage>(\n messages[messageIndex]!,\n ).map((message) => {\n const item = { parentId, message };\n parentId = storageFormatAdapter.getId(message);\n return item;\n });\n\n const deletion = persistInFlightRef.current.then(async () => {\n await deleteMessages(itemsToDelete);\n\n historyIds.current.delete(messageId);\n deferredTelemetryIds.current.delete(messageId);\n for (const item of itemsToDelete) {\n persistedInnerMessages.current.delete(\n storageFormatAdapter.getId(item.message),\n );\n }\n });\n\n persistInFlightRef.current = deletion.catch(() => {});\n await deletion;\n },\n [formatAdapter, runtimeRef, storageFormatAdapter],\n );\n\n return { isLoading, deleteMessage };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useExternalHistory.js","names":["AssistantRuntime","ThreadHistoryAdapter","ThreadMessage","MessageFormatAdapter","MessageFormatItem","MessageFormatRepository","ExportedMessageRepository","getExternalStoreMessages","MessageRepository","useAui","useRef","useEffect","useState","RefObject","useCallback","useMemo","toExportedMessageRepository","toThreadMessages","messages","TMessage","survivingIds","Set","survivors","flatMap","m","message","console","warn","parentId","has","add","id","headId","isAwaitingToolApproval","status","type","reason","encodeContent","storageFormatAdapter","item","JSON","stringify","encode","useExternalHistory","runtimeRef","historyAdapter","onSetMessages","loadedRef","itemEpoch","setItemEpoch","aui","optionalThreadListItem","threadListItem","source","hasLoaded","setHasLoaded","historyIds","deferredTelemetryIds","persistedInnerMessages","Map","content","onSetMessagesRef","current","formatAdapter","undefined","withFormat","Error","isLoading","loadHistory","repo","load","length","set","getId","converted","thread","import","tempRepo","getMessages","error","pin","remoteId","getState","subscribe","n","threadState","isRunning","runStartRef","persistTimerRef","ReturnType","setTimeout","persistInFlightRef","Promise","resolve","stepBoundariesRef","wasRunningRef","toolCallCountRef","adapter","unsubscribe","wasRunning","lastMsg","at","role","currentToolCallCount","filter","p","push","Date","now","clearTimeout","persistSettled","initialThreadState","ignoreRunning","latest","boundaries","durationMs","lastAssistant","findLast","tcCount","totalSteps","stepDur","i","Math","round","stepTimestamps","map","endMs","start_ms","end_ms","telemetryOptions","then","lastInnerMessageId","getLastInnerId","msgs","toBatchItems","msg","idx","innerMessages","isTerminal","isAwaitingToolCalls","isReady","update","batchItems","innerId","persisted","get","append","delete","reportTelemetry","catch","deleteMessage","messageId","deleteMessages","bind","messageIndex","findIndex","previousInnerMessages","slice","itemsToDelete","deletion"],"sources":["../../src/runtime/useExternalHistory.ts"],"sourcesContent":["\"use client\";\n\nimport type {\n AssistantRuntime,\n ThreadHistoryAdapter,\n ThreadMessage,\n MessageFormatAdapter,\n MessageFormatItem,\n MessageFormatRepository,\n ExportedMessageRepository,\n} from \"@assistant-ui/core\";\nimport { getExternalStoreMessages } from \"@assistant-ui/core\";\nimport { MessageRepository } from \"@assistant-ui/core/internal\";\nimport { useAui } from \"@assistant-ui/store\";\nimport {\n useRef,\n useEffect,\n useState,\n type RefObject,\n useCallback,\n useMemo,\n} from \"react\";\n\nexport const toExportedMessageRepository = <TMessage>(\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n messages: MessageFormatRepository<TMessage>,\n): ExportedMessageRepository => {\n const survivingIds = new Set<string>();\n const survivors = messages.messages.flatMap((m) => {\n const message = toThreadMessages([m.message])[0];\n if (!message) {\n console.warn(\"Skipping a stored message that could not be loaded.\");\n return [];\n }\n if (m.parentId && !survivingIds.has(m.parentId)) return [];\n survivingIds.add(message.id);\n return [{ ...m, message }];\n });\n\n return {\n headId:\n messages.headId && survivingIds.has(messages.headId)\n ? messages.headId\n : null,\n messages: survivors,\n };\n};\n\nconst isAwaitingToolApproval = (message: ThreadMessage) =>\n message.status?.type === \"requires-action\" &&\n message.status.reason === \"tool-calls\";\n\nconst encodeContent = <TMessage>(\n storageFormatAdapter: MessageFormatAdapter<TMessage, any>,\n item: MessageFormatItem<TMessage>,\n) => JSON.stringify(storageFormatAdapter.encode(item));\n\nexport const useExternalHistory = <TMessage>(\n runtimeRef: RefObject<AssistantRuntime>,\n historyAdapter: ThreadHistoryAdapter | undefined,\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n storageFormatAdapter: MessageFormatAdapter<TMessage, any>,\n onSetMessages: (messages: TMessage[]) => void,\n) => {\n const loadedRef = useRef(false);\n const [itemEpoch, setItemEpoch] = useState(0);\n\n const aui = useAui();\n const optionalThreadListItem = useCallback(\n () => (aui.threadListItem.source ? aui.threadListItem : null),\n [aui],\n );\n\n const [hasLoaded, setHasLoaded] = useState(false);\n\n const historyIds = useRef(new Set<string>());\n const deferredTelemetryIds = useRef(new Set<string>());\n // `content` is a snapshot taken at write time rather than a re-encode of `source`, because a retained message object can be mutated in place by the runtime that produced it.\n const persistedInnerMessages = useRef(\n new Map<string, { source: TMessage; content: string }>(),\n );\n\n const onSetMessagesRef = useRef(onSetMessages);\n useEffect(() => {\n onSetMessagesRef.current = onSetMessages;\n });\n\n const formatAdapter = useMemo(() => {\n if (!historyAdapter) return undefined;\n if (!historyAdapter.withFormat) {\n throw new Error(\n \"useAISDKRuntime: ThreadHistoryAdapter is missing the required `withFormat` method.\",\n );\n }\n return historyAdapter.withFormat<TMessage, any>(storageFormatAdapter);\n }, [historyAdapter, storageFormatAdapter]);\n\n const isLoading = formatAdapter != null && !hasLoaded;\n\n useEffect(() => {\n if (!formatAdapter || loadedRef.current) return undefined;\n\n const loadHistory = async () => {\n try {\n const repo = await formatAdapter.load();\n if (repo && repo.messages.length > 0) {\n for (const m of repo.messages) {\n persistedInnerMessages.current.set(\n storageFormatAdapter.getId(m.message),\n {\n source: m.message,\n content: encodeContent(storageFormatAdapter, m),\n },\n );\n }\n const converted = toExportedMessageRepository(toThreadMessages, repo);\n runtimeRef.current.thread.import(converted);\n\n const tempRepo = new MessageRepository();\n tempRepo.import(converted);\n const messages = tempRepo.getMessages();\n\n onSetMessagesRef.current(\n messages.flatMap(getExternalStoreMessages<TMessage>),\n );\n\n historyIds.current = new Set();\n for (const m of converted.messages) {\n historyIds.current.add(m.message.id);\n if (isAwaitingToolApproval(m.message)) {\n deferredTelemetryIds.current.add(m.message.id);\n }\n }\n }\n } catch (error) {\n console.error(\"Failed to load message history:\", error);\n } finally {\n setHasLoaded(true);\n }\n };\n\n formatAdapter.pin?.();\n\n const remoteId = optionalThreadListItem()?.getState().remoteId;\n if (!remoteId) {\n // History loads asynchronously against the thread list item; without a\n // remote id there is nothing to await, so the flag settles here.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setHasLoaded(true);\n return aui.subscribe(() => {\n if (optionalThreadListItem()?.getState().remoteId) {\n setItemEpoch((n) => n + 1);\n }\n });\n }\n\n const threadState = runtimeRef.current.thread.getState();\n if (threadState.isRunning || threadState.messages.length > 0) {\n loadedRef.current = true;\n setHasLoaded(true);\n return undefined;\n }\n\n loadedRef.current = true;\n void loadHistory();\n return undefined;\n }, [\n formatAdapter,\n toThreadMessages,\n runtimeRef,\n optionalThreadListItem,\n aui,\n itemEpoch,\n storageFormatAdapter,\n ]);\n\n const runStartRef = useRef<number | null>(null);\n const persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const persistInFlightRef = useRef<Promise<void>>(Promise.resolve());\n const stepBoundariesRef = useRef<number[]>([]);\n const wasRunningRef = useRef(false);\n const toolCallCountRef = useRef(0);\n\n useEffect(() => {\n if (!formatAdapter) return;\n const adapter = formatAdapter;\n\n const unsubscribe = runtimeRef.current.thread.subscribe(() => {\n const threadState = runtimeRef.current.thread.getState();\n const { isRunning } = threadState;\n const wasRunning = wasRunningRef.current;\n wasRunningRef.current = isRunning;\n\n // Track step boundaries by content changes (more reliable than isRunning)\n if (runStartRef.current != null) {\n const lastMsg = threadState.messages.at(-1);\n if (lastMsg?.role === \"assistant\") {\n const currentToolCallCount = lastMsg.content.filter(\n (p) => p.type === \"tool-call\",\n ).length;\n while (toolCallCountRef.current < currentToolCallCount) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n toolCallCountRef.current++;\n }\n }\n }\n\n if (isRunning) {\n if (runStartRef.current == null) {\n runStartRef.current = Date.now();\n stepBoundariesRef.current = [];\n toolCallCountRef.current = 0;\n adapter.pin?.();\n }\n // Cancel any pending persist — isRunning went back to true\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n }\n return;\n }\n\n // Only act on the true→false transition\n if (!wasRunning) return;\n\n // Record step boundary offset (synchronous for accuracy)\n if (runStartRef.current != null) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n }\n\n // Debounce: wait one macrotask so agentic step flickers are absorbed\n if (persistTimerRef.current) clearTimeout(persistTimerRef.current);\n persistTimerRef.current = setTimeout(() => {\n persistSettled(false);\n }, 0);\n });\n\n const initialThreadState = runtimeRef.current.thread.getState();\n wasRunningRef.current = initialThreadState.isRunning;\n if (initialThreadState.isRunning) {\n if (runStartRef.current == null) {\n runStartRef.current = Date.now();\n stepBoundariesRef.current = [];\n toolCallCountRef.current = 0;\n adapter.pin?.();\n }\n } else if (initialThreadState.messages.length > 0) {\n persistSettled(true);\n }\n\n function persistSettled(ignoreRunning: boolean) {\n persistTimerRef.current = null;\n const latest = runtimeRef.current.thread.getState();\n if (!ignoreRunning && latest.isRunning) return;\n\n const boundaries = stepBoundariesRef.current;\n const durationMs = boundaries.length > 0 ? boundaries.at(-1) : undefined;\n\n // Fallback: if only 1 boundary but message has multiple steps, distribute evenly\n if (boundaries.length === 1 && durationMs != null) {\n const lastAssistant = latest.messages.findLast(\n (m) => m.role === \"assistant\",\n );\n if (lastAssistant) {\n const tcCount = lastAssistant.content.filter(\n (p) => p.type === \"tool-call\",\n ).length;\n if (tcCount > 0) {\n const totalSteps = tcCount + 1;\n const stepDur = durationMs / totalSteps;\n boundaries.length = 0;\n for (let i = 0; i < totalSteps; i++) {\n boundaries.push(Math.round((i + 1) * stepDur));\n }\n }\n }\n }\n\n // Build per-step timestamps when there are multiple steps\n const stepTimestamps =\n boundaries.length > 1\n ? boundaries.map((endMs, i) => ({\n start_ms: i === 0 ? 0 : boundaries[i - 1]!,\n end_ms: endMs,\n }))\n : undefined;\n\n runStartRef.current = null;\n stepBoundariesRef.current = [];\n\n const telemetryOptions = {\n ...(durationMs != null ? { durationMs } : undefined),\n ...(stepTimestamps != null ? { stepTimestamps } : undefined),\n };\n\n persistInFlightRef.current = persistInFlightRef.current\n .then(async () => {\n const { messages } = latest;\n let lastInnerMessageId: string | null = null;\n\n const getLastInnerId = (msgs: TMessage[]): string | null =>\n msgs.length > 0 ? storageFormatAdapter.getId(msgs.at(-1)!) : null;\n\n const toBatchItems = (msgs: TMessage[]) =>\n msgs.map((msg, idx) => ({\n parentId:\n idx === 0\n ? lastInnerMessageId\n : storageFormatAdapter.getId(msgs[idx - 1]!),\n message: msg,\n }));\n\n for (const message of messages) {\n const innerMessages = getExternalStoreMessages<TMessage>(message);\n\n const isTerminal =\n message.status === undefined ||\n message.status.type === \"complete\" ||\n message.status.type === \"incomplete\";\n const isAwaitingToolCalls = isAwaitingToolApproval(message);\n // A paused message's later content can only reach storage via update, so it is persisted early only when the adapter supports update.\n const isReady =\n isTerminal ||\n (isAwaitingToolCalls && adapter.update !== undefined);\n\n if (!isReady) {\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n continue;\n }\n\n if (!historyIds.current.has(message.id)) {\n historyIds.current.add(message.id);\n deferredTelemetryIds.current.add(message.id);\n }\n\n const batchItems = toBatchItems(innerMessages);\n for (const item of batchItems) {\n const innerId = storageFormatAdapter.getId(item.message);\n const persisted = persistedInnerMessages.current.get(innerId);\n if (!persisted) {\n await adapter.append(item);\n persistedInnerMessages.current.set(innerId, {\n source: item.message,\n content: encodeContent(storageFormatAdapter, item),\n });\n } else if (\n persisted.source !== item.message &&\n durationMs !== undefined &&\n adapter.update\n ) {\n const content = encodeContent(storageFormatAdapter, item);\n if (content === persisted.content) {\n persisted.source = item.message;\n } else {\n try {\n await adapter.update(item, innerId);\n persistedInnerMessages.current.set(innerId, {\n source: item.message,\n content,\n });\n } catch {\n // A failed update leaves the stale baseline behind so the next run stop retries it.\n }\n }\n }\n }\n\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n\n if (deferredTelemetryIds.current.has(message.id) && isTerminal) {\n deferredTelemetryIds.current.delete(message.id);\n adapter.reportTelemetry?.(batchItems, {\n ...telemetryOptions,\n message,\n });\n }\n }\n })\n .catch((error) => {\n console.error(\"Failed to persist message history:\", error);\n });\n }\n\n return () => {\n unsubscribe();\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n persistSettled(false);\n }\n };\n }, [formatAdapter, storageFormatAdapter, runtimeRef]);\n\n const deleteMessage = useCallback(\n async (messageId: string) => {\n const deleteMessages = formatAdapter?.delete?.bind(formatAdapter);\n if (!deleteMessages) return;\n\n const messages = runtimeRef.current.thread.getState().messages;\n const messageIndex = messages.findIndex((m) => m.id === messageId);\n if (messageIndex === -1) return;\n\n const previousInnerMessages = messages\n .slice(0, messageIndex)\n .flatMap(getExternalStoreMessages<TMessage>);\n let parentId = previousInnerMessages.at(-1)\n ? storageFormatAdapter.getId(previousInnerMessages.at(-1)!)\n : null;\n const itemsToDelete = getExternalStoreMessages<TMessage>(\n messages[messageIndex]!,\n ).map((message) => {\n const item = { parentId, message };\n parentId = storageFormatAdapter.getId(message);\n return item;\n });\n\n const deletion = persistInFlightRef.current.then(async () => {\n await deleteMessages(itemsToDelete);\n\n historyIds.current.delete(messageId);\n deferredTelemetryIds.current.delete(messageId);\n for (const item of itemsToDelete) {\n persistedInnerMessages.current.delete(\n storageFormatAdapter.getId(item.message),\n );\n }\n });\n\n persistInFlightRef.current = deletion.catch(() => {});\n await deletion;\n },\n [formatAdapter, runtimeRef, storageFormatAdapter],\n );\n\n return { isLoading, deleteMessage };\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/ai-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Vercel AI SDK adapter for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-sdk",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@ai-sdk/mcp": "^2.0.45",
|
|
50
50
|
"@ai-sdk/react": "^4.0.96",
|
|
51
|
-
"@assistant-ui/core": "^0.3.
|
|
51
|
+
"@assistant-ui/core": "^0.3.19",
|
|
52
52
|
"@assistant-ui/store": "^0.3.13",
|
|
53
53
|
"@assistant-ui/tap": "^0.9.17",
|
|
54
54
|
"ai": "^7.0.93",
|
|
55
|
-
"assistant-cloud": "
|
|
56
|
-
"assistant-stream": "^0.3.
|
|
55
|
+
"assistant-cloud": "^0.2.1",
|
|
56
|
+
"assistant-stream": "^0.3.43"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@types/react": "*",
|
|
@@ -68,14 +68,14 @@
|
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
71
|
+
"@assistant-ui/x-buildutils": "0.0.27",
|
|
72
72
|
"@testing-library/react": "^16.3.3",
|
|
73
73
|
"@types/json-schema": "^7.0.15",
|
|
74
74
|
"@types/react": "^19.2.18",
|
|
75
75
|
"@types/react-dom": "^19.2.7",
|
|
76
76
|
"jsdom": "^30.0.1",
|
|
77
77
|
"react": "^19.2.8",
|
|
78
|
-
"vitest": "^
|
|
78
|
+
"vitest": "^5.0.0"
|
|
79
79
|
},
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public",
|
|
@@ -1,41 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
MessageStorageEntry,
|
|
6
|
-
} from "@assistant-ui/core";
|
|
7
|
-
|
|
8
|
-
// Storage format for AI SDK messages - just the UIMessage
|
|
9
|
-
export type AISDKStorageFormat = Omit<UIMessage, "id">;
|
|
10
|
-
|
|
11
|
-
export const aiSDKV6FormatAdapter: MessageFormatAdapter<
|
|
12
|
-
UIMessage,
|
|
13
|
-
AISDKStorageFormat
|
|
14
|
-
> = {
|
|
15
|
-
format: "ai-sdk/v6",
|
|
16
|
-
|
|
17
|
-
encode({
|
|
18
|
-
message: { id, parts, ...message },
|
|
19
|
-
}: MessageFormatItem<UIMessage>): AISDKStorageFormat {
|
|
20
|
-
return {
|
|
21
|
-
...message,
|
|
22
|
-
parts,
|
|
23
|
-
};
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
decode(
|
|
27
|
-
stored: MessageStorageEntry<AISDKStorageFormat>,
|
|
28
|
-
): MessageFormatItem<UIMessage> {
|
|
29
|
-
return {
|
|
30
|
-
parentId: stored.parent_id,
|
|
31
|
-
message: {
|
|
32
|
-
id: stored.id,
|
|
33
|
-
...stored.content,
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
getId(message: UIMessage): string {
|
|
39
|
-
return message.id;
|
|
40
|
-
},
|
|
41
|
-
};
|
|
1
|
+
export {
|
|
2
|
+
aiSDKV6FormatAdapter,
|
|
3
|
+
type AISDKStorageFormat,
|
|
4
|
+
} from "assistant-cloud/ai-sdk";
|
|
@@ -48,6 +48,20 @@ describe("AISDKMessageConverter", () => {
|
|
|
48
48
|
expect(converted[0]?.metadata).not.toHaveProperty("usage");
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
it("keeps modality metadata at the top level", () => {
|
|
52
|
+
const converted = AISDKMessageConverter.toThreadMessages([
|
|
53
|
+
{
|
|
54
|
+
id: "a1",
|
|
55
|
+
role: "assistant",
|
|
56
|
+
parts: [{ type: "text", text: "yo" }],
|
|
57
|
+
metadata: { modality: "voice" },
|
|
58
|
+
},
|
|
59
|
+
] as any);
|
|
60
|
+
|
|
61
|
+
expect(converted[0]?.metadata.modality).toBe("voice");
|
|
62
|
+
expect(converted[0]?.metadata.custom).not.toHaveProperty("modality");
|
|
63
|
+
});
|
|
64
|
+
|
|
51
65
|
it("does not flag messages when no optimistic id is provided", () => {
|
|
52
66
|
const converted = AISDKMessageConverter.toThreadMessages([
|
|
53
67
|
{ id: "a1", role: "assistant", parts: [{ type: "text", text: "yo" }] },
|