@assistant-ui/ai-sdk 0.0.6 → 0.0.7
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/vercelAttachmentAdapter.d.ts +1 -2
- package/dist/adapters/vercelAttachmentAdapter.d.ts.map +1 -1
- package/dist/aiSDKExtras.d.ts +2 -3
- package/dist/aiSDKExtras.d.ts.map +1 -1
- package/dist/converters/convertMessage.d.ts +5 -4
- package/dist/converters/convertMessage.d.ts.map +1 -1
- package/dist/converters/convertMessage.js +39 -3
- package/dist/converters/convertMessage.js.map +1 -1
- package/dist/converters/modelContentEnvelope.d.ts +4 -5
- package/dist/converters/modelContentEnvelope.d.ts.map +1 -1
- package/dist/converters/toCreateMessage.d.ts +1 -2
- package/dist/converters/toCreateMessage.d.ts.map +1 -1
- package/dist/converters/toolOutputConversion.d.ts +2 -3
- package/dist/converters/toolOutputConversion.d.ts.map +1 -1
- package/dist/hooks.d.ts +2 -3
- package/dist/hooks.d.ts.map +1 -1
- package/dist/model-context/injectInteractableContext.d.ts +1 -2
- package/dist/model-context/injectInteractableContext.d.ts.map +1 -1
- package/dist/model-context/injectQuoteContext.d.ts +1 -2
- package/dist/model-context/injectQuoteContext.d.ts.map +1 -1
- package/dist/runtime/AISDKChat.d.ts +2 -3
- package/dist/runtime/AISDKChat.d.ts.map +1 -1
- package/dist/runtime/AISDKThreads.d.ts +2 -3
- package/dist/runtime/AISDKThreads.d.ts.map +1 -1
- package/dist/runtime/AISDKThreads.js +4 -10
- package/dist/runtime/AISDKThreads.js.map +1 -1
- package/dist/runtime/sdkIdentity.d.ts +1 -2
- package/dist/runtime/sdkIdentity.d.ts.map +1 -1
- package/dist/runtime/sdkIdentity.js +1 -1
- package/dist/runtime/useAISDKRuntime.d.ts +17 -5
- package/dist/runtime/useAISDKRuntime.d.ts.map +1 -1
- package/dist/runtime/useAISDKRuntime.js +95 -37
- package/dist/runtime/useAISDKRuntime.js.map +1 -1
- package/dist/runtime/useChatRuntime.d.ts +2 -3
- package/dist/runtime/useChatRuntime.d.ts.map +1 -1
- package/dist/runtime/useChatThread.d.ts +19 -5
- package/dist/runtime/useChatThread.d.ts.map +1 -1
- package/dist/runtime/useChatThread.js +30 -9
- package/dist/runtime/useChatThread.js.map +1 -1
- package/dist/runtime/useExternalHistory.d.ts +2 -3
- package/dist/runtime/useExternalHistory.d.ts.map +1 -1
- package/dist/runtime/useExternalHistory.js +28 -20
- package/dist/runtime/useExternalHistory.js.map +1 -1
- package/dist/runtime/useResourceCleanup.d.ts +1 -2
- package/dist/runtime/useResourceCleanup.d.ts.map +1 -1
- package/dist/runtime/useStreamingTiming.d.ts +2 -3
- package/dist/runtime/useStreamingTiming.d.ts.map +1 -1
- package/dist/tools/frontendTools.d.ts +3 -4
- package/dist/tools/frontendTools.d.ts.map +1 -1
- package/dist/tools/generativeTools.d.ts +5 -6
- package/dist/tools/generativeTools.d.ts.map +1 -1
- package/dist/tools/mcp-stdio.unsupported.d.ts +1 -2
- package/dist/tools/mcp-stdio.unsupported.d.ts.map +1 -1
- package/dist/transport/AssistantChatTransport.d.ts +3 -4
- package/dist/transport/AssistantChatTransport.d.ts.map +1 -1
- package/dist/transport/resumable.d.ts +4 -5
- package/dist/transport/resumable.d.ts.map +1 -1
- package/dist/usage.d.ts +4 -5
- package/dist/usage.d.ts.map +1 -1
- package/dist/utils/getVercelAIMessages.d.ts +1 -2
- package/dist/utils/getVercelAIMessages.d.ts.map +1 -1
- package/dist/utils/sliceMessagesUntil.d.ts +1 -2
- package/dist/utils/sliceMessagesUntil.d.ts.map +1 -1
- package/package.json +15 -14
- package/src/converters/convertMessage.test.ts +138 -0
- package/src/converters/convertMessage.ts +94 -5
- package/src/runtime/AISDKChat.test.ts +4 -5
- package/src/runtime/AISDKThreads.test.ts +9 -5
- package/src/runtime/AISDKThreads.ts +3 -12
- package/src/runtime/useAISDKRuntime.approval.integration.test.tsx +287 -0
- package/src/runtime/useAISDKRuntime.approval.test.tsx +257 -1
- package/src/runtime/useAISDKRuntime.test.ts +7 -3
- package/src/runtime/useAISDKRuntime.ts +147 -23
- package/src/runtime/useAISDKRuntime.voice.test.tsx +270 -0
- package/src/runtime/useChatRuntime.test.ts +72 -4
- package/src/runtime/useChatThread.ts +44 -5
- package/src/runtime/useExternalHistory.test.ts +46 -0
- package/src/runtime/useExternalHistory.ts +24 -10
- package/src/tools/generativeTools.test.ts +7 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { useAISDKRuntime } from "./useAISDKRuntime.js";
|
|
3
3
|
import { AssistantChatTransport } from "../transport/AssistantChatTransport.js";
|
|
4
4
|
import { useResourceCleanup } from "./useResourceCleanup.js";
|
|
5
|
-
import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from "@assistant-ui/tap/react-shim";
|
|
5
|
+
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "@assistant-ui/tap/react-shim";
|
|
6
6
|
import { pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
7
|
-
import { useChat } from "@ai-sdk/react";
|
|
7
|
+
import { Chat, useChat } from "@ai-sdk/react";
|
|
8
8
|
//#region src/runtime/useChatThread.ts
|
|
9
9
|
const useDynamicChatTransport = (transport) => {
|
|
10
10
|
const transportRef = useRef(transport);
|
|
@@ -39,7 +39,7 @@ const getResumedStreamIds = (storage) => {
|
|
|
39
39
|
* same fields `useChat` would.
|
|
40
40
|
*/
|
|
41
41
|
const splitChatThreadOptions = (options) => {
|
|
42
|
-
const { adapters, transport, throttle, toCreateMessage, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, unstable_capabilities: _unstable_capabilities, suggestions: _suggestions, onResume, onResumeToolCall, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, ...chatInit } = options ?? {};
|
|
42
|
+
const { adapters, transport, throttle, toCreateMessage, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, unstable_capabilities: _unstable_capabilities, suggestions: _suggestions, onResume, onResumeToolCall, onRespondToToolApproval, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, ...chatInit } = options ?? {};
|
|
43
43
|
return {
|
|
44
44
|
adapters,
|
|
45
45
|
transport,
|
|
@@ -47,6 +47,7 @@ const splitChatThreadOptions = (options) => {
|
|
|
47
47
|
toCreateMessage,
|
|
48
48
|
onResume,
|
|
49
49
|
onResumeToolCall,
|
|
50
|
+
onRespondToToolApproval,
|
|
50
51
|
onResumeError,
|
|
51
52
|
joinStrategy,
|
|
52
53
|
messageRepository,
|
|
@@ -54,18 +55,37 @@ const splitChatThreadOptions = (options) => {
|
|
|
54
55
|
chatInit
|
|
55
56
|
};
|
|
56
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* Constructs a `Chat` whose callbacks read the latest options through
|
|
60
|
+
* `callbacksRef`, the forwarding `useChat` applies only to a chat it
|
|
61
|
+
* constructs itself.
|
|
62
|
+
*/
|
|
63
|
+
const createChat = (init, callbacksRef) => new Chat({
|
|
64
|
+
...init,
|
|
65
|
+
onToolCall: (arg) => callbacksRef.current?.onToolCall?.(arg),
|
|
66
|
+
onData: (arg) => callbacksRef.current?.onData?.(arg),
|
|
67
|
+
onFinish: (arg) => callbacksRef.current?.onFinish?.(arg),
|
|
68
|
+
onError: (arg) => callbacksRef.current?.onError?.(arg),
|
|
69
|
+
sendAutomaticallyWhen: (arg) => callbacksRef.current?.sendAutomaticallyWhen?.(arg) ?? false
|
|
70
|
+
});
|
|
57
71
|
const useChatThread = (options, env) => {
|
|
58
|
-
const { adapters, transport: transportOptions, throttle, toCreateMessage, onResume, onResumeToolCall, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, chatInit: chatOptions } = splitChatThreadOptions(options);
|
|
72
|
+
const { adapters, transport: transportOptions, throttle, toCreateMessage, onResume, onResumeToolCall, onRespondToToolApproval, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, chatInit: chatOptions } = splitChatThreadOptions(options);
|
|
59
73
|
const { id, isMainThread, getThreadListItem, stopOnClientDestroy = true, chat: externalChat, messageRepositoryInstance } = env;
|
|
60
74
|
const defaultTransport = useMemo(() => new AssistantChatTransport(), []);
|
|
61
75
|
const sourceTransport = transportOptions ?? defaultTransport;
|
|
62
76
|
const transport = useDynamicChatTransport(sourceTransport);
|
|
63
|
-
const
|
|
77
|
+
const latestChatOptionsRef = useRef(chatOptions);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
latestChatOptionsRef.current = chatOptions;
|
|
80
|
+
});
|
|
81
|
+
const [ownedChat] = useState(() => externalChat ?? createChat({
|
|
64
82
|
...chatOptions,
|
|
65
83
|
id,
|
|
66
|
-
transport
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
transport
|
|
85
|
+
}, latestChatOptionsRef));
|
|
86
|
+
const chat = useChat({
|
|
87
|
+
chat: externalChat ?? ownedChat,
|
|
88
|
+
...throttle !== void 0 && { throttle }
|
|
69
89
|
});
|
|
70
90
|
useResourceCleanup(stopOnClientDestroy, () => {
|
|
71
91
|
chat.stop().catch(() => {});
|
|
@@ -76,6 +96,7 @@ const useChatThread = (options, env) => {
|
|
|
76
96
|
...toCreateMessage && { toCreateMessage },
|
|
77
97
|
...onResume && { onResume },
|
|
78
98
|
...onResumeToolCall && { onResumeToolCall },
|
|
99
|
+
...onRespondToToolApproval && { onRespondToToolApproval },
|
|
79
100
|
...joinStrategy && { joinStrategy },
|
|
80
101
|
...messageRepository && { messageRepository },
|
|
81
102
|
...messageRepositoryInstance && { unstable_messageRepositoryInstance: messageRepositoryInstance },
|
|
@@ -136,6 +157,6 @@ const useChatThread = (options, env) => {
|
|
|
136
157
|
return runtime;
|
|
137
158
|
};
|
|
138
159
|
//#endregion
|
|
139
|
-
export { splitChatThreadOptions, useChatThread };
|
|
160
|
+
export { createChat, splitChatThreadOptions, useChatThread };
|
|
140
161
|
|
|
141
162
|
//# sourceMappingURL=useChatThread.js.map
|
|
@@ -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 = 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
|
+
{"version":3,"file":"useChatThread.js","names":["Chat","useChat","UIMessage","MessageRepository","pickExternalStoreSharedOptions","AssistantRuntime","ExternalStoreSharedOptions","useAISDKRuntime","AISDKRuntimeAdapter","CustomToCreateMessageFunction","ChatInit","ChatTransport","AssistantChatTransport","InitializableThreadListItem","AssistantChatResumableOptions","ResumableClientStorage","useCallback","useEffect","useMemo","useRef","useState","useSyncExternalStore","useResourceCleanup","ChatThreadOptions","UI_MESSAGE","throttle","adapters","toCreateMessage","onResume","onResumeToolCall","onRespondToToolApproval","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","ChatCallbacks","Pick","createChat","init","callbacksRef","onToolCall","arg","onData","onFinish","onError","sendAutomaticallyWhen","useChatThread","env","transportOptions","chatOptions","externalChat","defaultTransport","sourceTransport","latestChatOptionsRef","ownedChat","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 { Chat, useChat, 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 useState,\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 onRespondToToolApproval?: AISDKRuntimeAdapter[\"onRespondToToolApproval\"];\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 onRespondToToolApproval,\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 onRespondToToolApproval,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n chatInit,\n };\n};\n\ntype ChatCallbacks<UI_MESSAGE extends UIMessage> = Pick<\n ChatInit<UI_MESSAGE>,\n \"onToolCall\" | \"onData\" | \"onFinish\" | \"onError\" | \"sendAutomaticallyWhen\"\n>;\n\n/**\n * Constructs a `Chat` whose callbacks read the latest options through\n * `callbacksRef`, the forwarding `useChat` applies only to a chat it\n * constructs itself.\n */\nexport const createChat = <UI_MESSAGE extends UIMessage>(\n init: ChatInit<UI_MESSAGE>,\n callbacksRef: { readonly current: ChatCallbacks<UI_MESSAGE> | undefined },\n): Chat<UI_MESSAGE> =>\n new Chat<UI_MESSAGE>({\n ...init,\n onToolCall: (arg) => callbacksRef.current?.onToolCall?.(arg),\n onData: (arg) => callbacksRef.current?.onData?.(arg),\n onFinish: (arg) => callbacksRef.current?.onFinish?.(arg),\n onError: (arg) => callbacksRef.current?.onError?.(arg),\n sendAutomaticallyWhen: (arg) =>\n callbacksRef.current?.sendAutomaticallyWhen?.(arg) ?? false,\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 onRespondToToolApproval,\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 latestChatOptionsRef = useRef(chatOptions);\n useEffect(() => {\n latestChatOptionsRef.current = chatOptions;\n });\n // `useChat` stops a chat it constructs whenever it unmounts, and a\n // resource's soft unmount runs that cleanup, so the thread owns its chat.\n const [ownedChat] = useState(\n () =>\n externalChat ??\n createChat({ ...chatOptions, id, transport }, latestChatOptionsRef),\n );\n\n const chat = useChat({\n chat: externalChat ?? ownedChat,\n ...(throttle !== undefined && { throttle }),\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 ...(onRespondToToolApproval && { onRespondToToolApproval }),\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,11 +1,10 @@
|
|
|
1
1
|
import { RefObject } from "react";
|
|
2
2
|
import { AssistantRuntime, ExportedMessageRepository, MessageFormatAdapter, MessageFormatRepository, ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
|
|
3
3
|
//#region src/runtime/useExternalHistory.d.ts
|
|
4
|
-
declare const toExportedMessageRepository: <TMessage>(toThreadMessages: (messages: TMessage[]) => ThreadMessage[], messages: MessageFormatRepository<TMessage>) => ExportedMessageRepository;
|
|
5
|
-
declare const useExternalHistory: <TMessage>(runtimeRef: RefObject<AssistantRuntime>, historyAdapter: ThreadHistoryAdapter | undefined, toThreadMessages: (messages: TMessage[]) => ThreadMessage[], storageFormatAdapter: MessageFormatAdapter<TMessage, any>, onSetMessages: (messages: TMessage[]) => void) => {
|
|
4
|
+
export declare const toExportedMessageRepository: <TMessage>(toThreadMessages: (messages: TMessage[]) => ThreadMessage[], messages: MessageFormatRepository<TMessage>) => ExportedMessageRepository;
|
|
5
|
+
export declare const useExternalHistory: <TMessage>(runtimeRef: RefObject<AssistantRuntime>, historyAdapter: ThreadHistoryAdapter | undefined, toThreadMessages: (messages: TMessage[]) => ThreadMessage[], storageFormatAdapter: MessageFormatAdapter<TMessage, any>, onSetMessages: (messages: TMessage[]) => void) => {
|
|
6
6
|
isLoading: boolean;
|
|
7
7
|
deleteMessage: (messageId: string) => Promise<void>;
|
|
8
8
|
};
|
|
9
9
|
//#endregion
|
|
10
|
-
export { toExportedMessageRepository, useExternalHistory };
|
|
11
10
|
//# sourceMappingURL=useExternalHistory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExternalHistory.d.ts","names":[],"sources":["../../src/runtime/useExternalHistory.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"useExternalHistory.d.ts","names":[],"sources":["../../src/runtime/useExternalHistory.ts"],"mappings":";;;qBAuBa,8BAA+B,UAC1C,mBAAmB,UAAU,eAAe,iBAC5C,UAAU,wBAAwB,cACjC;qBAoCU,qBAAsB,UACjC,YAAY,UAAU,mBACtB,gBAAgB,kCAChB,mBAAmB,UAAU,eAAe,iBAC5C,sBAAsB,qBAAqB,gBAC3C,gBAAgB,UAAU;;EAuVN,gBAAA,sBAAM"}
|
|
@@ -25,6 +25,7 @@ const toExportedMessageRepository = (toThreadMessages, messages) => {
|
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
const isAwaitingToolApproval = (message) => message.status?.type === "requires-action" && message.status.reason === "tool-calls";
|
|
28
|
+
const isTerminalMessage = (message) => message.status === void 0 || message.status.type === "complete" || message.status.type === "incomplete";
|
|
28
29
|
const encodeContent = (storageFormatAdapter, item) => JSON.stringify(storageFormatAdapter.encode(item));
|
|
29
30
|
const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storageFormatAdapter, onSetMessages) => {
|
|
30
31
|
const loadedRef = useRef(false);
|
|
@@ -106,6 +107,8 @@ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storag
|
|
|
106
107
|
useEffect(() => {
|
|
107
108
|
if (!formatAdapter) return;
|
|
108
109
|
const adapter = formatAdapter;
|
|
110
|
+
const idleScheduledInnerIds = /* @__PURE__ */ new Set();
|
|
111
|
+
const unpersistedInnerIds = (message) => isTerminalMessage(message) ? getExternalStoreMessages(message).map((innerMessage) => storageFormatAdapter.getId(innerMessage)).filter((innerId) => !persistedInnerMessages.current.has(innerId)) : [];
|
|
109
112
|
const unsubscribe = runtimeRef.current.thread.subscribe(() => {
|
|
110
113
|
const threadState_0 = runtimeRef.current.thread.getState();
|
|
111
114
|
const { isRunning } = threadState_0;
|
|
@@ -134,8 +137,13 @@ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storag
|
|
|
134
137
|
}
|
|
135
138
|
return;
|
|
136
139
|
}
|
|
137
|
-
if (
|
|
138
|
-
|
|
140
|
+
if (wasRunning) {
|
|
141
|
+
if (runStartRef.current != null) stepBoundariesRef.current.push(Date.now() - runStartRef.current);
|
|
142
|
+
} else {
|
|
143
|
+
const pending = threadState_0.messages.flatMap(unpersistedInnerIds);
|
|
144
|
+
if (pending.every((innerId_0) => idleScheduledInnerIds.has(innerId_0))) return;
|
|
145
|
+
for (const innerId_1 of pending) idleScheduledInnerIds.add(innerId_1);
|
|
146
|
+
}
|
|
139
147
|
if (persistTimerRef.current) clearTimeout(persistTimerRef.current);
|
|
140
148
|
persistTimerRef.current = setTimeout(() => {
|
|
141
149
|
persistSettled(false);
|
|
@@ -187,25 +195,25 @@ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storag
|
|
|
187
195
|
parentId: idx === 0 ? lastInnerMessageId : storageFormatAdapter.getId(msgs_0[idx - 1]),
|
|
188
196
|
message: msg
|
|
189
197
|
}));
|
|
190
|
-
for (const
|
|
191
|
-
const innerMessages = getExternalStoreMessages(
|
|
192
|
-
const isTerminal =
|
|
193
|
-
const isAwaitingToolCalls = isAwaitingToolApproval(
|
|
198
|
+
for (const message_0 of messages_0) {
|
|
199
|
+
const innerMessages = getExternalStoreMessages(message_0);
|
|
200
|
+
const isTerminal = isTerminalMessage(message_0);
|
|
201
|
+
const isAwaitingToolCalls = isAwaitingToolApproval(message_0);
|
|
194
202
|
if (!(isTerminal || isAwaitingToolCalls && adapter.update !== void 0)) {
|
|
195
203
|
lastInnerMessageId = getLastInnerId(innerMessages) ?? lastInnerMessageId;
|
|
196
204
|
continue;
|
|
197
205
|
}
|
|
198
|
-
if (!historyIds.current.has(
|
|
199
|
-
historyIds.current.add(
|
|
200
|
-
deferredTelemetryIds.current.add(
|
|
206
|
+
if (!historyIds.current.has(message_0.id)) {
|
|
207
|
+
historyIds.current.add(message_0.id);
|
|
208
|
+
deferredTelemetryIds.current.add(message_0.id);
|
|
201
209
|
}
|
|
202
210
|
const batchItems = toBatchItems(innerMessages);
|
|
203
211
|
for (const item of batchItems) {
|
|
204
|
-
const
|
|
205
|
-
const persisted = persistedInnerMessages.current.get(
|
|
212
|
+
const innerId_2 = storageFormatAdapter.getId(item.message);
|
|
213
|
+
const persisted = persistedInnerMessages.current.get(innerId_2);
|
|
206
214
|
if (!persisted) {
|
|
207
215
|
await adapter.append(item);
|
|
208
|
-
persistedInnerMessages.current.set(
|
|
216
|
+
persistedInnerMessages.current.set(innerId_2, {
|
|
209
217
|
source: item.message,
|
|
210
218
|
content: encodeContent(storageFormatAdapter, item)
|
|
211
219
|
});
|
|
@@ -213,8 +221,8 @@ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storag
|
|
|
213
221
|
const content = encodeContent(storageFormatAdapter, item);
|
|
214
222
|
if (content === persisted.content) persisted.source = item.message;
|
|
215
223
|
else try {
|
|
216
|
-
await adapter.update(item,
|
|
217
|
-
persistedInnerMessages.current.set(
|
|
224
|
+
await adapter.update(item, innerId_2);
|
|
225
|
+
persistedInnerMessages.current.set(innerId_2, {
|
|
218
226
|
source: item.message,
|
|
219
227
|
content
|
|
220
228
|
});
|
|
@@ -222,11 +230,11 @@ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storag
|
|
|
222
230
|
}
|
|
223
231
|
}
|
|
224
232
|
lastInnerMessageId = getLastInnerId(innerMessages) ?? lastInnerMessageId;
|
|
225
|
-
if (deferredTelemetryIds.current.has(
|
|
226
|
-
deferredTelemetryIds.current.delete(
|
|
233
|
+
if (deferredTelemetryIds.current.has(message_0.id) && isTerminal) {
|
|
234
|
+
deferredTelemetryIds.current.delete(message_0.id);
|
|
227
235
|
adapter.reportTelemetry?.(batchItems, {
|
|
228
236
|
...telemetryOptions,
|
|
229
|
-
message
|
|
237
|
+
message: message_0
|
|
230
238
|
});
|
|
231
239
|
}
|
|
232
240
|
}
|
|
@@ -257,12 +265,12 @@ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storag
|
|
|
257
265
|
if (messageIndex === -1) return;
|
|
258
266
|
const previousInnerMessages = messages_1.slice(0, messageIndex).flatMap(getExternalStoreMessages);
|
|
259
267
|
let parentId = previousInnerMessages.at(-1) ? storageFormatAdapter.getId(previousInnerMessages.at(-1)) : null;
|
|
260
|
-
const itemsToDelete = getExternalStoreMessages(messages_1[messageIndex]).map((
|
|
268
|
+
const itemsToDelete = getExternalStoreMessages(messages_1[messageIndex]).map((message_1) => {
|
|
261
269
|
const item_0 = {
|
|
262
270
|
parentId,
|
|
263
|
-
message:
|
|
271
|
+
message: message_1
|
|
264
272
|
};
|
|
265
|
-
parentId = storageFormatAdapter.getId(
|
|
273
|
+
parentId = storageFormatAdapter.getId(message_1);
|
|
266
274
|
return item_0;
|
|
267
275
|
});
|
|
268
276
|
const deletion = persistInFlightRef.current.then(async () => {
|
|
@@ -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, {\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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"}
|
|
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","isTerminalMessage","undefined","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","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","idleScheduledInnerIds","unpersistedInnerIds","map","innerMessage","filter","innerId","unsubscribe","wasRunning","lastMsg","at","role","currentToolCallCount","p","push","Date","now","clearTimeout","pending","every","persistSettled","initialThreadState","ignoreRunning","latest","boundaries","durationMs","lastAssistant","findLast","tcCount","totalSteps","stepDur","i","Math","round","stepTimestamps","endMs","start_ms","end_ms","telemetryOptions","then","lastInnerMessageId","getLastInnerId","msgs","toBatchItems","msg","idx","innerMessages","isTerminal","isAwaitingToolCalls","isReady","update","batchItems","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 isTerminalMessage = (message: ThreadMessage) =>\n message.status === undefined ||\n message.status.type === \"complete\" ||\n message.status.type === \"incomplete\";\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 idleScheduledInnerIds = new Set<string>();\n const unpersistedInnerIds = (message: ThreadMessage) =>\n isTerminalMessage(message)\n ? getExternalStoreMessages<TMessage>(message)\n .map((innerMessage) => storageFormatAdapter.getId(innerMessage))\n .filter((innerId) => !persistedInnerMessages.current.has(innerId))\n : [];\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 if (wasRunning) {\n // Record step boundary offset (synchronous for accuracy)\n if (runStartRef.current != null) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n }\n } else {\n const pending = threadState.messages.flatMap(unpersistedInnerIds);\n if (pending.every((innerId) => idleScheduledInnerIds.has(innerId)))\n return;\n for (const innerId of pending) idleScheduledInnerIds.add(innerId);\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 = isTerminalMessage(message);\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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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
//#region src/runtime/useResourceCleanup.d.ts
|
|
2
|
-
declare const useResourceCleanup: (enabled: boolean, cleanup: () => void) => void;
|
|
2
|
+
export declare const useResourceCleanup: (enabled: boolean, cleanup: () => void) => void;
|
|
3
3
|
//#endregion
|
|
4
|
-
export { useResourceCleanup };
|
|
5
4
|
//# sourceMappingURL=useResourceCleanup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useResourceCleanup.d.ts","names":[],"sources":["../../src/runtime/useResourceCleanup.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"useResourceCleanup.d.ts","names":[],"sources":["../../src/runtime/useResourceCleanup.ts"],"mappings":";qBAGa,qBAAsB,kBAAkB"}
|
|
@@ -2,14 +2,13 @@ import { StreamingTimingAccessors } from "@assistant-ui/core/react";
|
|
|
2
2
|
import { MessageTiming } from "@assistant-ui/core";
|
|
3
3
|
import { UIMessage } from "@ai-sdk/react";
|
|
4
4
|
//#region src/runtime/useStreamingTiming.d.ts
|
|
5
|
-
declare const aiSdkStreamingTimingAccessors: StreamingTimingAccessors<UIMessage>;
|
|
5
|
+
export declare const aiSdkStreamingTimingAccessors: StreamingTimingAccessors<UIMessage>;
|
|
6
6
|
/**
|
|
7
7
|
* Tracks streaming timing for AI SDK messages client-side. Delegates to the
|
|
8
8
|
* shared `useStreamingTiming` primitive in `@assistant-ui/core/react`,
|
|
9
9
|
* adapted to the `UIMessage` shape. Timing is finalized when streaming ends
|
|
10
10
|
* and stored per message id.
|
|
11
11
|
*/
|
|
12
|
-
declare const useStreamingTiming: (messages: UIMessage[], isRunning: boolean) => Record<string, MessageTiming>;
|
|
12
|
+
export declare const useStreamingTiming: (messages: UIMessage[], isRunning: boolean) => Record<string, MessageTiming>;
|
|
13
13
|
//#endregion
|
|
14
|
-
export { aiSdkStreamingTimingAccessors, useStreamingTiming };
|
|
15
14
|
//# sourceMappingURL=useStreamingTiming.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStreamingTiming.d.ts","names":[],"sources":["../../src/runtime/useStreamingTiming.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"useStreamingTiming.d.ts","names":[],"sources":["../../src/runtime/useStreamingTiming.ts"],"mappings":";;;;qBA8Ca,+BAA+B,yBAAyB;;;;;;;qBAaxD,qBACX,UAAU,aACV,uBACC,eAAe"}
|
|
@@ -2,8 +2,8 @@ import { ToolSet } from "ai";
|
|
|
2
2
|
import { ToolJSONSchema } from "assistant-stream";
|
|
3
3
|
//#region src/tools/frontendTools.d.ts
|
|
4
4
|
/** Frontend tool definitions uploaded by AssistantChatTransport. */
|
|
5
|
-
type FrontendTools = Record<string, ToolJSONSchema>;
|
|
6
|
-
declare const defaultToModelOutput: ({ output }: {
|
|
5
|
+
export type FrontendTools = Record<string, ToolJSONSchema>;
|
|
6
|
+
export declare const defaultToModelOutput: ({ output }: {
|
|
7
7
|
output: unknown;
|
|
8
8
|
}) => {
|
|
9
9
|
type: "content";
|
|
@@ -27,7 +27,6 @@ declare const defaultToModelOutput: ({ output }: {
|
|
|
27
27
|
type: "json";
|
|
28
28
|
value: import("ai").JSONValue;
|
|
29
29
|
};
|
|
30
|
-
declare const frontendTools: (tools: FrontendTools) => ToolSet;
|
|
30
|
+
export declare const frontendTools: (tools: FrontendTools) => ToolSet;
|
|
31
31
|
//#endregion
|
|
32
|
-
export { FrontendTools, defaultToModelOutput, frontendTools };
|
|
33
32
|
//# sourceMappingURL=frontendTools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontendTools.d.ts","names":[],"sources":["../../src/tools/frontendTools.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"frontendTools.d.ts","names":[],"sources":["../../src/tools/frontendTools.ts"],"mappings":";;;;YASY,gBAAgB,eAAe;qBAE9B,yBAAwB;EAAc;;;;;;;;;;;;;;;;;;;;;;;qBAuDtC,gBAAiB,OAAO,kBAAgB"}
|
|
@@ -7,7 +7,7 @@ import { ToolSet } from "ai";
|
|
|
7
7
|
* {@link AISDKToolkit} with {@link AISDKToolkitOptions} /
|
|
8
8
|
* {@link AISDKToolkitToolsOptions} instead.
|
|
9
9
|
*/
|
|
10
|
-
interface GenerativeToolsOptions {
|
|
10
|
+
export interface GenerativeToolsOptions {
|
|
11
11
|
/**
|
|
12
12
|
* The server build of a generative toolkit (schema + server `execute`). Typed
|
|
13
13
|
* as the canonical {@link Toolkit} so callers don't need to cast; the server
|
|
@@ -21,10 +21,10 @@ interface GenerativeToolsOptions {
|
|
|
21
21
|
*/
|
|
22
22
|
frontendTools?: FrontendTools;
|
|
23
23
|
}
|
|
24
|
-
type AISDKToolkitOptions = {
|
|
24
|
+
export type AISDKToolkitOptions = {
|
|
25
25
|
toolkit: Toolkit;
|
|
26
26
|
};
|
|
27
|
-
type AISDKToolkitToolsOptions = {
|
|
27
|
+
export type AISDKToolkitToolsOptions = {
|
|
28
28
|
/**
|
|
29
29
|
* Tools uploaded by the frontend request body.
|
|
30
30
|
*/
|
|
@@ -61,13 +61,12 @@ type AISDKToolkitToolsOptions = {
|
|
|
61
61
|
* });
|
|
62
62
|
* ```
|
|
63
63
|
*/
|
|
64
|
-
declare const generativeTools: (options: GenerativeToolsOptions) => ToolSet;
|
|
65
|
-
declare class AISDKToolkit {
|
|
64
|
+
export declare const generativeTools: (options: GenerativeToolsOptions) => ToolSet;
|
|
65
|
+
export declare class AISDKToolkit {
|
|
66
66
|
#private;
|
|
67
67
|
constructor(options: AISDKToolkitOptions);
|
|
68
68
|
tools(options?: AISDKToolkitToolsOptions): Promise<ToolSet>;
|
|
69
69
|
close(): Promise<void>;
|
|
70
70
|
}
|
|
71
71
|
//#endregion
|
|
72
|
-
export { AISDKToolkit, AISDKToolkitOptions, AISDKToolkitToolsOptions, GenerativeToolsOptions, generativeTools };
|
|
73
72
|
//# sourceMappingURL=generativeTools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generativeTools.d.ts","names":[],"sources":["../../src/tools/generativeTools.ts"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"generativeTools.d.ts","names":[],"sources":["../../src/tools/generativeTools.ts"],"mappings":";;;;;;;;;iBAsFiB;;;;;;EAMf,SAAS;;;;;;EAMT,gBAAgB;;YAGN;EACV,SAAS;;YAGC;;;;EAIV,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkCA,kBAAmB,SAAS,2BAAyB;qBAYrD;;EAIC,YAAA,SAAS;EAIf,MAAM,UAAS,2BAAgC,QAAQ;EAsBvD,SAAS"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Experimental_StdioMCPTransport as Experimental_StdioMCPTransport$1 } from "@ai-sdk/mcp/mcp-stdio";
|
|
2
2
|
//#region src/tools/mcp-stdio.unsupported.d.ts
|
|
3
|
-
declare const Experimental_StdioMCPTransport: typeof Experimental_StdioMCPTransport$1;
|
|
3
|
+
export declare const Experimental_StdioMCPTransport: typeof Experimental_StdioMCPTransport$1;
|
|
4
4
|
//#endregion
|
|
5
|
-
export { Experimental_StdioMCPTransport };
|
|
6
5
|
//# sourceMappingURL=mcp-stdio.unsupported.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-stdio.unsupported.d.ts","names":[],"sources":["../../src/tools/mcp-stdio.unsupported.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"mcp-stdio.unsupported.d.ts","names":[],"sources":["../../src/tools/mcp-stdio.unsupported.ts"],"mappings":";;qBAUa,uCACuC"}
|
|
@@ -2,11 +2,11 @@ import { AssistantChatResumableOptions } from "./resumable.js";
|
|
|
2
2
|
import { DefaultChatTransport, HttpChatTransportInitOptions, UIMessage } from "ai";
|
|
3
3
|
import { AssistantRuntime, ThreadListItemRuntime } from "@assistant-ui/core";
|
|
4
4
|
//#region src/transport/AssistantChatTransport.d.ts
|
|
5
|
-
type InitializableThreadListItem = Pick<ThreadListItemRuntime, "initialize">;
|
|
6
|
-
type AssistantChatTransportInitOptions<UI_MESSAGE extends UIMessage> = HttpChatTransportInitOptions<UI_MESSAGE> & {
|
|
5
|
+
export type InitializableThreadListItem = Pick<ThreadListItemRuntime, "initialize">;
|
|
6
|
+
export type AssistantChatTransportInitOptions<UI_MESSAGE extends UIMessage> = HttpChatTransportInitOptions<UI_MESSAGE> & {
|
|
7
7
|
resumable?: AssistantChatResumableOptions;
|
|
8
8
|
};
|
|
9
|
-
declare class AssistantChatTransport<UI_MESSAGE extends UIMessage> extends DefaultChatTransport<UI_MESSAGE> {
|
|
9
|
+
export declare class AssistantChatTransport<UI_MESSAGE extends UIMessage> extends DefaultChatTransport<UI_MESSAGE> {
|
|
10
10
|
private runtime;
|
|
11
11
|
private getThreadListItem;
|
|
12
12
|
private readonly resumable;
|
|
@@ -19,5 +19,4 @@ declare class AssistantChatTransport<UI_MESSAGE extends UIMessage> extends Defau
|
|
|
19
19
|
__internal_setGetThreadListItem(getter: () => InitializableThreadListItem | undefined): void;
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
|
-
export { AssistantChatTransport, AssistantChatTransportInitOptions, InitializableThreadListItem };
|
|
23
22
|
//# sourceMappingURL=AssistantChatTransport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantChatTransport.d.ts","names":[],"sources":["../../src/transport/AssistantChatTransport.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"AssistantChatTransport.d.ts","names":[],"sources":["../../src/transport/AssistantChatTransport.ts"],"mappings":";;;;YAeY,8BAA8B,KACxC;YAaU,kCAAkC,mBAAmB,aAC/D,6BAA6B;EAC3B,YAAY;;qBAGH,uBACX,mBAAmB,mBACX,qBAAqB;UACrB;UACA;mBAGS;mBAEA;;EAKV,oBAAoB,uBAAuB;EAOtC,YAAA,cAAc,kCAAkC;EA0D5D,WAAW,SAAS;EAIpB,uBAAuB;EAIvB,gCACE,cAAc"}
|