@ulearning/ai-sdk-adapter 0.0.0-stage → 1.0.0-next.0

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.
Files changed (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -2
  3. package/dist/adapters/aiSDKFormatAdapter.d.ts +6 -0
  4. package/dist/adapters/aiSDKFormatAdapter.d.ts.map +1 -0
  5. package/dist/adapters/aiSDKFormatAdapter.js +17 -0
  6. package/dist/adapters/aiSDKFormatAdapter.js.map +1 -0
  7. package/dist/adapters/vercelAttachmentAdapter.d.ts +3 -0
  8. package/dist/adapters/vercelAttachmentAdapter.d.ts.map +1 -0
  9. package/dist/adapters/vercelAttachmentAdapter.js +36 -0
  10. package/dist/adapters/vercelAttachmentAdapter.js.map +1 -0
  11. package/dist/aiSDKExtras.d.ts +13 -0
  12. package/dist/aiSDKExtras.d.ts.map +1 -0
  13. package/dist/aiSDKExtras.js +6 -0
  14. package/dist/aiSDKExtras.js.map +1 -0
  15. package/dist/converters/convertMessage.d.ts +44 -0
  16. package/dist/converters/convertMessage.d.ts.map +1 -0
  17. package/dist/converters/convertMessage.js +465 -0
  18. package/dist/converters/convertMessage.js.map +1 -0
  19. package/dist/converters/toCreateMessage.d.ts +4 -0
  20. package/dist/converters/toCreateMessage.d.ts.map +1 -0
  21. package/dist/converters/toCreateMessage.js +65 -0
  22. package/dist/converters/toCreateMessage.js.map +1 -0
  23. package/dist/converters/toolApprovalAnswers.d.ts +3 -0
  24. package/dist/converters/toolApprovalAnswers.d.ts.map +1 -0
  25. package/dist/converters/toolApprovalAnswers.js +16 -0
  26. package/dist/converters/toolApprovalAnswers.js.map +1 -0
  27. package/dist/hooks.d.ts +17 -0
  28. package/dist/hooks.d.ts.map +1 -0
  29. package/dist/hooks.js +19 -0
  30. package/dist/hooks.js.map +1 -0
  31. package/dist/index.d.ts +17 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +13 -0
  34. package/dist/model-context/injectInteractableContext.d.ts +37 -0
  35. package/dist/model-context/injectInteractableContext.d.ts.map +1 -0
  36. package/dist/model-context/injectInteractableContext.js +54 -0
  37. package/dist/model-context/injectInteractableContext.js.map +1 -0
  38. package/dist/model-context/injectQuoteContext.d.ts +25 -0
  39. package/dist/model-context/injectQuoteContext.d.ts.map +1 -0
  40. package/dist/model-context/injectQuoteContext.js +51 -0
  41. package/dist/model-context/injectQuoteContext.js.map +1 -0
  42. package/dist/runtime/AISDKChat.d.ts +13 -0
  43. package/dist/runtime/AISDKChat.d.ts.map +1 -0
  44. package/dist/runtime/AISDKChat.js +34 -0
  45. package/dist/runtime/AISDKChat.js.map +1 -0
  46. package/dist/runtime/AISDKThreads.d.ts +24 -0
  47. package/dist/runtime/AISDKThreads.d.ts.map +1 -0
  48. package/dist/runtime/AISDKThreads.js +92 -0
  49. package/dist/runtime/AISDKThreads.js.map +1 -0
  50. package/dist/runtime/DynamicChatTransport.d.ts +50 -0
  51. package/dist/runtime/DynamicChatTransport.d.ts.map +1 -0
  52. package/dist/runtime/DynamicChatTransport.js +153 -0
  53. package/dist/runtime/DynamicChatTransport.js.map +1 -0
  54. package/dist/runtime/getResumableAdapter.d.ts +5 -0
  55. package/dist/runtime/getResumableAdapter.d.ts.map +1 -0
  56. package/dist/runtime/getResumableAdapter.js +11 -0
  57. package/dist/runtime/getResumableAdapter.js.map +1 -0
  58. package/dist/runtime/toolHistoryCodec.d.ts +20 -0
  59. package/dist/runtime/toolHistoryCodec.d.ts.map +1 -0
  60. package/dist/runtime/toolHistoryCodec.js +122 -0
  61. package/dist/runtime/toolHistoryCodec.js.map +1 -0
  62. package/dist/runtime/useAISDKRuntime.d.ts +95 -0
  63. package/dist/runtime/useAISDKRuntime.d.ts.map +1 -0
  64. package/dist/runtime/useAISDKRuntime.js +754 -0
  65. package/dist/runtime/useAISDKRuntime.js.map +1 -0
  66. package/dist/runtime/useChatRuntime.d.ts +17 -0
  67. package/dist/runtime/useChatRuntime.d.ts.map +1 -0
  68. package/dist/runtime/useChatRuntime.js +50 -0
  69. package/dist/runtime/useChatRuntime.js.map +1 -0
  70. package/dist/runtime/useChatSnapshot.d.ts +6 -0
  71. package/dist/runtime/useChatSnapshot.d.ts.map +1 -0
  72. package/dist/runtime/useChatSnapshot.js +62 -0
  73. package/dist/runtime/useChatSnapshot.js.map +1 -0
  74. package/dist/runtime/useChatThread.d.ts +121 -0
  75. package/dist/runtime/useChatThread.d.ts.map +1 -0
  76. package/dist/runtime/useChatThread.js +255 -0
  77. package/dist/runtime/useChatThread.js.map +1 -0
  78. package/dist/runtime/useDynamicChatTransport.d.ts +4 -0
  79. package/dist/runtime/useDynamicChatTransport.d.ts.map +1 -0
  80. package/dist/runtime/useDynamicChatTransport.js +26 -0
  81. package/dist/runtime/useDynamicChatTransport.js.map +1 -0
  82. package/dist/runtime/useExternalHistory.d.ts +12 -0
  83. package/dist/runtime/useExternalHistory.d.ts.map +1 -0
  84. package/dist/runtime/useExternalHistory.js +556 -0
  85. package/dist/runtime/useExternalHistory.js.map +1 -0
  86. package/dist/runtime/useMessageQueue.d.ts +14 -0
  87. package/dist/runtime/useMessageQueue.d.ts.map +1 -0
  88. package/dist/runtime/useMessageQueue.js +142 -0
  89. package/dist/runtime/useMessageQueue.js.map +1 -0
  90. package/dist/runtime/useResourceCleanup.d.ts +2 -0
  91. package/dist/runtime/useResourceCleanup.d.ts.map +1 -0
  92. package/dist/runtime/useResourceCleanup.js +47 -0
  93. package/dist/runtime/useResourceCleanup.js.map +1 -0
  94. package/dist/runtime/useStreamingTiming.d.ts +12 -0
  95. package/dist/runtime/useStreamingTiming.d.ts.map +1 -0
  96. package/dist/runtime/useStreamingTiming.js +36 -0
  97. package/dist/runtime/useStreamingTiming.js.map +1 -0
  98. package/dist/tools/generativeTools.d.ts +71 -0
  99. package/dist/tools/generativeTools.d.ts.map +1 -0
  100. package/dist/tools/generativeTools.js +258 -0
  101. package/dist/tools/generativeTools.js.map +1 -0
  102. package/dist/tools/mcp-stdio.node.d.ts +2 -0
  103. package/dist/tools/mcp-stdio.node.d.ts.map +1 -0
  104. package/dist/tools/mcp-stdio.node.js +1 -0
  105. package/dist/tools/mcp-stdio.unsupported.d.ts +3 -0
  106. package/dist/tools/mcp-stdio.unsupported.d.ts.map +1 -0
  107. package/dist/tools/mcp-stdio.unsupported.js +10 -0
  108. package/dist/tools/mcp-stdio.unsupported.js.map +1 -0
  109. package/dist/transport/AssistantChatTransport.d.ts +20 -0
  110. package/dist/transport/AssistantChatTransport.d.ts.map +1 -0
  111. package/dist/transport/AssistantChatTransport.js +151 -0
  112. package/dist/transport/AssistantChatTransport.js.map +1 -0
  113. package/dist/transport/resumable.d.ts +36 -0
  114. package/dist/transport/resumable.d.ts.map +1 -0
  115. package/dist/transport/resumable.js +112 -0
  116. package/dist/transport/resumable.js.map +1 -0
  117. package/dist/usage.d.ts +24 -0
  118. package/dist/usage.d.ts.map +1 -0
  119. package/dist/usage.js +121 -0
  120. package/dist/usage.js.map +1 -0
  121. package/dist/utils/getVercelAIMessages.d.ts +4 -0
  122. package/dist/utils/getVercelAIMessages.d.ts.map +1 -0
  123. package/dist/utils/getVercelAIMessages.js +8 -0
  124. package/dist/utils/getVercelAIMessages.js.map +1 -0
  125. package/dist/utils/sliceMessagesUntil.d.ts +3 -0
  126. package/dist/utils/sliceMessagesUntil.d.ts.map +1 -0
  127. package/dist/utils/sliceMessagesUntil.js +10 -0
  128. package/dist/utils/sliceMessagesUntil.js.map +1 -0
  129. package/package.json +96 -3
  130. package/src/__tests__/standalone.e2e.ts +118 -0
  131. package/src/adapters/aiSDKFormatAdapter.test.ts +36 -0
  132. package/src/adapters/aiSDKFormatAdapter.ts +18 -0
  133. package/src/adapters/vercelAttachmentAdapter.test.ts +52 -0
  134. package/src/adapters/vercelAttachmentAdapter.ts +36 -0
  135. package/src/aiSDKExtras.ts +31 -0
  136. package/src/converters/convertMessage.metadata-key.test.tsx +182 -0
  137. package/src/converters/convertMessage.test.ts +2428 -0
  138. package/src/converters/convertMessage.tool-args-status.test.tsx +185 -0
  139. package/src/converters/convertMessage.ts +919 -0
  140. package/src/converters/toCreateMessage.test.ts +716 -0
  141. package/src/converters/toCreateMessage.ts +110 -0
  142. package/src/converters/toolApprovalAnswers.ts +27 -0
  143. package/src/hooks.test.ts +168 -0
  144. package/src/hooks.ts +26 -0
  145. package/src/index.ts +29 -0
  146. package/src/model-context/injectInteractableContext.test.ts +167 -0
  147. package/src/model-context/injectInteractableContext.ts +64 -0
  148. package/src/model-context/injectQuoteContext.test.ts +33 -0
  149. package/src/model-context/injectQuoteContext.ts +63 -0
  150. package/src/runtime/AISDKChat.artifacts.test.ts +48 -0
  151. package/src/runtime/AISDKChat.integration.test.tsx +148 -0
  152. package/src/runtime/AISDKChat.test.ts +241 -0
  153. package/src/runtime/AISDKChat.ts +43 -0
  154. package/src/runtime/AISDKThreads.test.ts +811 -0
  155. package/src/runtime/AISDKThreads.ts +194 -0
  156. package/src/runtime/DynamicChatTransport.test.ts +228 -0
  157. package/src/runtime/DynamicChatTransport.ts +281 -0
  158. package/src/runtime/__tests__/controlled-transport.ts +70 -0
  159. package/src/runtime/__tests__/tap.ts +80 -0
  160. package/src/runtime/__tests__/vue.ts +46 -0
  161. package/src/runtime/getResumableAdapter.ts +16 -0
  162. package/src/runtime/toolHistoryCodec.test.ts +187 -0
  163. package/src/runtime/toolHistoryCodec.ts +245 -0
  164. package/src/runtime/useAISDKRuntime.approval.integration.test.tsx +1956 -0
  165. package/src/runtime/useAISDKRuntime.approval.test.tsx +580 -0
  166. package/src/runtime/useAISDKRuntime.denied-tool.test.tsx +122 -0
  167. package/src/runtime/useAISDKRuntime.fast-refresh.test.tsx +302 -0
  168. package/src/runtime/useAISDKRuntime.metadata-cache.test.tsx +157 -0
  169. package/src/runtime/useAISDKRuntime.queue.test.tsx +707 -0
  170. package/src/runtime/useAISDKRuntime.reload.test.tsx +217 -0
  171. package/src/runtime/useAISDKRuntime.test.ts +2345 -0
  172. package/src/runtime/useAISDKRuntime.tool-output.test.tsx +113 -0
  173. package/src/runtime/useAISDKRuntime.ts +1503 -0
  174. package/src/runtime/useAISDKRuntime.voice.test.tsx +319 -0
  175. package/src/runtime/useChatOnTap.test.ts +60 -0
  176. package/src/runtime/useChatRuntime.fast-refresh.test.tsx +83 -0
  177. package/src/runtime/useChatRuntime.integration.test.tsx +661 -0
  178. package/src/runtime/useChatRuntime.local-storage.test.tsx +114 -0
  179. package/src/runtime/useChatRuntime.native.test.ts +147 -0
  180. package/src/runtime/useChatRuntime.run-telemetry.test.tsx +226 -0
  181. package/src/runtime/useChatRuntime.test.ts +619 -0
  182. package/src/runtime/useChatRuntime.ts +80 -0
  183. package/src/runtime/useChatSnapshot.test.ts +60 -0
  184. package/src/runtime/useChatSnapshot.ts +86 -0
  185. package/src/runtime/useChatThread.binding.test.tsx +140 -0
  186. package/src/runtime/useChatThread.test.ts +993 -0
  187. package/src/runtime/useChatThread.transport.test.tsx +149 -0
  188. package/src/runtime/useChatThread.ts +533 -0
  189. package/src/runtime/useDynamicChatTransport.ts +26 -0
  190. package/src/runtime/useExternalHistory.test.ts +4187 -0
  191. package/src/runtime/useExternalHistory.ts +902 -0
  192. package/src/runtime/useMessageQueue.effects.test.tsx +88 -0
  193. package/src/runtime/useMessageQueue.test.tsx +256 -0
  194. package/src/runtime/useMessageQueue.ts +189 -0
  195. package/src/runtime/useResourceCleanup.ts +58 -0
  196. package/src/runtime/useStreamingTiming.test.tsx +96 -0
  197. package/src/runtime/useStreamingTiming.ts +69 -0
  198. package/src/tools/generativeTools.test.ts +1058 -0
  199. package/src/tools/generativeTools.ts +491 -0
  200. package/src/tools/mcp-stdio.node.ts +1 -0
  201. package/src/tools/mcp-stdio.unsupported.ts +12 -0
  202. package/src/transport/AssistantChatTransport.test.ts +631 -0
  203. package/src/transport/AssistantChatTransport.ts +236 -0
  204. package/src/transport/resumable.test.ts +262 -0
  205. package/src/transport/resumable.ts +162 -0
  206. package/src/usage.test.ts +204 -0
  207. package/src/usage.ts +179 -0
  208. package/src/utils/getVercelAIMessages.ts +11 -0
  209. package/src/utils/sliceMessagesUntil.test.ts +51 -0
  210. package/src/utils/sliceMessagesUntil.ts +16 -0
@@ -0,0 +1,255 @@
1
+ "use client";
2
+ import { useAISDKRuntime } from "./useAISDKRuntime.js";
3
+ import { AssistantChatTransport } from "../transport/AssistantChatTransport.js";
4
+ import { useChatSnapshot } from "./useChatSnapshot.js";
5
+ import { useResourceCleanup } from "./useResourceCleanup.js";
6
+ import { getResumableAdapter } from "./getResumableAdapter.js";
7
+ import { DynamicChatTransport, getResumedStreamIds } from "./DynamicChatTransport.js";
8
+ import { useDynamicChatTransport } from "./useDynamicChatTransport.js";
9
+ import { pickExternalStoreSharedOptions } from "@ulearning/ai-core";
10
+ import { useCallback, useEffect, useEffectEvent, useInsertionEffect, useMemo, useRef, useState, useSyncExternalStore } from "@ulearning/ai-tap";
11
+ import { Chat } from "@ai-sdk/vue";
12
+ // src/runtime/useChatThread.ts
13
+ const getNoPendingStreamId = () => null;
14
+ /**
15
+ * Splits the combined options into the assistant-ui side and the `ChatInit`
16
+ * remainder the AI SDK consumes, so external `Chat` construction forwards the
17
+ * same fields `useChat` would.
18
+ */
19
+ const splitChatThreadOptions = (options) => {
20
+ const { adapters, transport, throttle, toCreateMessage, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, unstable_capabilities: _unstable_capabilities, suggestions: _suggestions, onResume, canResume, onResumeToolCall, onRespondToToolApproval, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, unstable_enableMessageQueue, ...chatInit } = options ?? {};
21
+ return {
22
+ adapters,
23
+ transport,
24
+ throttle,
25
+ toCreateMessage,
26
+ onResume,
27
+ canResume,
28
+ onResumeToolCall,
29
+ onRespondToToolApproval,
30
+ onResumeError,
31
+ joinStrategy,
32
+ messageRepository,
33
+ unstable_onBranchChange,
34
+ unstable_enableMessageQueue,
35
+ chatInit
36
+ };
37
+ };
38
+ const requestsByChat = /* @__PURE__ */ new WeakMap();
39
+ /**
40
+ * Constructs a `Chat` whose callbacks read the latest options through
41
+ * `callbacksRef`, the forwarding `useChat` applies only to a chat it
42
+ * constructs itself.
43
+ */
44
+ const createChat = (init, callbacksRef) => {
45
+ const transport = init.transport;
46
+ const chat = new Chat({
47
+ ...init,
48
+ ...transport && { transport: {
49
+ get resumeStreamIsReplay() {
50
+ return transport.resumeStreamIsReplay ?? false;
51
+ },
52
+ sendMessages: (options) => {
53
+ requestsByChat.set(chat, {});
54
+ if (callbacksRef.current?.canResume) (callbacksRef.current.resumableStorage ?? getResumableAdapter(transport)?.storage)?.clear(options.chatId);
55
+ return transport.sendMessages(options);
56
+ },
57
+ reconnectToStream: async (options) => {
58
+ const request = {};
59
+ requestsByChat.set(chat, request);
60
+ try {
61
+ return await transport.reconnectToStream(options);
62
+ } catch (error) {
63
+ if (typeof error !== "object" || error === null || !("name" in error) || error.name !== "AbortError") request.reconnectFailure = { error };
64
+ throw error;
65
+ }
66
+ }
67
+ } },
68
+ onToolCall: (arg) => callbacksRef.current?.onToolCall?.(arg),
69
+ onData: (arg) => callbacksRef.current?.onData?.(arg),
70
+ onFinish: (arg) => callbacksRef.current?.onFinish?.(arg),
71
+ onError: (arg) => callbacksRef.current?.onError?.(arg),
72
+ sendAutomaticallyWhen: (arg) => callbacksRef.current?.sendAutomaticallyWhen?.(arg) ?? false
73
+ });
74
+ return chat;
75
+ };
76
+ const useChatThread = (options, env) => {
77
+ const { adapters, transport: transportOptions, throttle, toCreateMessage, onResume, canResume, onResumeToolCall, onRespondToToolApproval, onResumeError, joinStrategy, messageRepository, unstable_onBranchChange, unstable_enableMessageQueue, chatInit: chatOptions } = splitChatThreadOptions(options);
78
+ const { id, isMainThread, getThreadListItem, stopOnClientDestroy = true, hostDestroySignal, chat: externalChat, messageRepositoryInstance } = env;
79
+ const defaultTransport = useMemo(() => new AssistantChatTransport(), []);
80
+ const configuredTransport = transportOptions ?? defaultTransport;
81
+ const transport = useDynamicChatTransport(configuredTransport, externalChat === void 0);
82
+ const transportContextOwner = useMemo(() => ({}), []);
83
+ const getThreadListItemRef = useRef(getThreadListItem);
84
+ useInsertionEffect(() => {
85
+ getThreadListItemRef.current = getThreadListItem;
86
+ }, [getThreadListItem]);
87
+ const getCurrentThreadListItem = useCallback(() => getThreadListItemRef.current(), []);
88
+ const resumableStorage = useMemo(() => transport instanceof DynamicChatTransport ? transport.getCurrentResumableStorage() : getResumableAdapter(transport)?.storage, [transport]);
89
+ const transportBindingRef = useRef(null);
90
+ let initialTransportBinding = null;
91
+ const chatTransport = useMemo(() => transport instanceof DynamicChatTransport ? transport.createThreadProxy(transportContextOwner, () => {
92
+ const binding = transportBindingRef.current ?? initialTransportBinding;
93
+ if (!binding) throw new Error("Chat transport used before runtime setup");
94
+ return binding;
95
+ }) : transport, [
96
+ initialTransportBinding,
97
+ transport,
98
+ transportContextOwner
99
+ ]);
100
+ const latestChatOptionsRef = useRef({
101
+ ...chatOptions,
102
+ canResume,
103
+ resumableStorage
104
+ });
105
+ useEffect(() => {
106
+ latestChatOptionsRef.current = {
107
+ ...chatOptions,
108
+ canResume,
109
+ resumableStorage
110
+ };
111
+ });
112
+ const [ownedChat] = useState(() => externalChat ?? createChat({
113
+ ...chatOptions,
114
+ id,
115
+ transport: chatTransport
116
+ }, latestChatOptionsRef));
117
+ const chat = useChatSnapshot(externalChat ?? ownedChat, throttle);
118
+ useResourceCleanup(stopOnClientDestroy, () => {
119
+ chat.stop().catch(() => {});
120
+ }, hostDestroySignal);
121
+ const subscribeToResumableStorage = useCallback((callback) => isMainThread ? resumableStorage?.subscribe?.(callback, id) ?? (() => {}) : () => {}, [
122
+ id,
123
+ isMainThread,
124
+ resumableStorage
125
+ ]);
126
+ const getPendingStreamId = useCallback(() => isMainThread ? resumableStorage?.getStreamId(id) ?? null : null, [
127
+ id,
128
+ isMainThread,
129
+ resumableStorage
130
+ ]);
131
+ const pendingStreamId = useSyncExternalStore(subscribeToResumableStorage, getPendingStreamId, getNoPendingStreamId);
132
+ const isChatRunning = chat.status === "submitted" || chat.status === "streaming";
133
+ const staticResumedStreamIds = useMemo(() => getResumedStreamIds(resumableStorage), [resumableStorage]);
134
+ const onResumeErrorRef = useRef(onResumeError);
135
+ useEffect(() => {
136
+ onResumeErrorRef.current = onResumeError;
137
+ });
138
+ const resumeChatStream = chat.resumeStream;
139
+ const resumeStream = useCallback(async () => {
140
+ const resumedStreamIds = transport instanceof DynamicChatTransport ? transport.getResumedStreamIds() : staticResumedStreamIds;
141
+ const streamId = resumableStorage?.getStreamId(id);
142
+ if (!streamId) return;
143
+ resumedStreamIds.add(streamId);
144
+ try {
145
+ const activeChat = externalChat ?? ownedChat;
146
+ activeChat.clearError();
147
+ const pending = resumeChatStream();
148
+ const request = requestsByChat.get(activeChat);
149
+ await pending;
150
+ if (request?.reconnectFailure) throw request.reconnectFailure.error;
151
+ if (requestsByChat.get(activeChat) === request && activeChat.error) throw activeChat.error;
152
+ } catch (error) {
153
+ try {
154
+ onResumeErrorRef.current?.(error);
155
+ } catch (callbackError) {
156
+ console.error("[assistant-ui] resumable: onResumeError callback failed", callbackError);
157
+ } finally {
158
+ if (!canResume && resumableStorage?.getStreamId(id) === streamId) resumableStorage.clear(id);
159
+ }
160
+ throw error;
161
+ }
162
+ }, [
163
+ canResume,
164
+ externalChat,
165
+ id,
166
+ ownedChat,
167
+ resumeChatStream,
168
+ resumableStorage,
169
+ staticResumedStreamIds,
170
+ transport
171
+ ]);
172
+ const handleBranchChange = useCallback((event) => {
173
+ if (canResume) resumableStorage?.clear(id);
174
+ unstable_onBranchChange?.(event);
175
+ }, [
176
+ canResume,
177
+ id,
178
+ resumableStorage,
179
+ unstable_onBranchChange
180
+ ]);
181
+ const runtime = useAISDKRuntime(chat, {
182
+ adapters: {
183
+ ...adapters,
184
+ threadList: {
185
+ threadId: id,
186
+ ...adapters?.threadList
187
+ }
188
+ },
189
+ ...pickExternalStoreSharedOptions(options ?? {}),
190
+ ...toCreateMessage && { toCreateMessage },
191
+ ...onResume ? { onResume } : canResume && resumableStorage ? { onResume: resumeStream } : {},
192
+ canResume: onResume ? !!canResume : !!canResume && !!pendingStreamId && !isChatRunning,
193
+ ...onResumeToolCall && { onResumeToolCall },
194
+ ...onRespondToToolApproval && { onRespondToToolApproval },
195
+ ...joinStrategy && { joinStrategy },
196
+ ...messageRepository && { messageRepository },
197
+ ...messageRepositoryInstance && { unstable_messageRepositoryInstance: messageRepositoryInstance },
198
+ unstable_hostApprovalOwner: externalChat ?? ownedChat,
199
+ ...(canResume && resumableStorage || unstable_onBranchChange) && { unstable_onBranchChange: handleBranchChange },
200
+ ...unstable_enableMessageQueue && { unstable_enableMessageQueue }
201
+ });
202
+ initialTransportBinding = {
203
+ runtime,
204
+ getThreadListItem: getCurrentThreadListItem
205
+ };
206
+ useInsertionEffect(() => {
207
+ transportBindingRef.current = {
208
+ runtime,
209
+ getThreadListItem: getCurrentThreadListItem
210
+ };
211
+ }, [runtime, getCurrentThreadListItem]);
212
+ const registerTransportContext = useEffectEvent((dynamicTransport, chatId) => {
213
+ dynamicTransport.setThreadContext(chatId, transportContextOwner, runtime, getCurrentThreadListItem);
214
+ return () => dynamicTransport.unregisterThread(chatId, transportContextOwner);
215
+ });
216
+ useInsertionEffect(() => {
217
+ if (!(transport instanceof DynamicChatTransport)) return void 0;
218
+ return registerTransportContext(transport, id);
219
+ }, [
220
+ id,
221
+ runtime,
222
+ transport,
223
+ transportContextOwner
224
+ ]);
225
+ if (!(transport instanceof DynamicChatTransport) && configuredTransport instanceof AssistantChatTransport) {
226
+ configuredTransport.setRuntime(runtime);
227
+ configuredTransport.__internal_setGetThreadListItem(getCurrentThreadListItem);
228
+ }
229
+ const subscribeToRuntime = useCallback((callback) => runtime.thread.subscribe(callback), [runtime]);
230
+ const getHistoryLoadingSnapshot = useCallback(() => runtime.thread.getState().isLoading, [runtime]);
231
+ const isLoadingHistory = useSyncExternalStore(subscribeToRuntime, getHistoryLoadingSnapshot, getHistoryLoadingSnapshot);
232
+ useEffect(() => {
233
+ const resumedStreamIds = transport instanceof DynamicChatTransport ? transport.getResumedStreamIds() : staticResumedStreamIds;
234
+ if (!pendingStreamId || resumedStreamIds.has(pendingStreamId)) return;
235
+ if (isChatRunning) {
236
+ resumedStreamIds.add(pendingStreamId);
237
+ return;
238
+ }
239
+ if (isLoadingHistory) return;
240
+ resumeStream().catch((err) => {
241
+ console.warn("[assistant-ui] resumable: resume failed", err);
242
+ });
243
+ }, [
244
+ isChatRunning,
245
+ isLoadingHistory,
246
+ pendingStreamId,
247
+ resumeStream,
248
+ staticResumedStreamIds,
249
+ transport
250
+ ]);
251
+ return runtime;
252
+ };
253
+ export { createChat, splitChatThreadOptions, useChatThread };
254
+
255
+ //# sourceMappingURL=useChatThread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useChatThread.js","names":[],"sources":["../../src/runtime/useChatThread.ts"],"sourcesContent":["\"use client\";\n\nimport { Chat } from \"@ai-sdk/vue\";\nimport type { UIMessage } from \"ai\";\nimport { useChatSnapshot } from \"./useChatSnapshot\";\nimport type { MessageRepository } from \"@ulearning/ai-core/internal\";\nimport {\n pickExternalStoreSharedOptions,\n type AssistantRuntime,\n type ExternalStoreSharedOptions,\n} from \"@ulearning/ai-core\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport type { ChatInit } from \"ai\";\nimport {\n AssistantChatTransport,\n type InitializableThreadListItem,\n} from \"../transport/AssistantChatTransport\";\nimport {\n useCallback,\n useEffect,\n useEffectEvent,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"@ulearning/ai-tap\";\nimport { useResourceCleanup } from \"./useResourceCleanup\";\nimport {\n DynamicChatTransport,\n getResumedStreamIds,\n} from \"./DynamicChatTransport\";\nimport type { ResumableClientStorage } from \"../transport/resumable\";\nimport { getResumableAdapter } from \"./getResumableAdapter\";\nimport { useDynamicChatTransport } from \"./useDynamicChatTransport\";\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 canResume?: AISDKRuntimeAdapter[\"canResume\"];\n onResumeToolCall?: AISDKRuntimeAdapter[\"onResumeToolCall\"];\n onRespondToToolApproval?: AISDKRuntimeAdapter[\"onRespondToToolApproval\"];\n /**\n * Called when a resumable stream reconnect fails. Use this to\n * surface a toast, report telemetry, or mark the thread as needing a\n * retry. With `canResume: true`, transient errors keep the stream id for\n * manual retry. Otherwise, a failed reconnect clears the matching id.\n * A 204 or 404 from the resume endpoint always clears the matching id.\n */\n onResumeError?: ((error: unknown) => void) | undefined;\n joinStrategy?: AISDKRuntimeAdapter[\"joinStrategy\"];\n messageRepository?: AISDKRuntimeAdapter<UI_MESSAGE>[\"messageRepository\"];\n /** @deprecated Experimental since 2026-06-23. Not scheduled for removal; the API may change in any release. */\n unstable_onBranchChange?: AISDKRuntimeAdapter[\"unstable_onBranchChange\"];\n /** @deprecated Experimental since 2026-10-15. Not scheduled for removal; the API may change in any release. */\n unstable_enableMessageQueue?: AISDKRuntimeAdapter[\"unstable_enableMessageQueue\"];\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 * Aborts when the Vue scope hosting the runtime is deleted. A nested\n * runtime resolves the destroy signal of the provider above it, which\n * outlives the nested component, so this stops the chat on its own unmount.\n */\n hostDestroySignal?: AbortSignal | undefined;\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\ntype ChatThreadTransportBinding = {\n runtime: AssistantRuntime;\n getThreadListItem: () => InitializableThreadListItem | undefined;\n};\n\nconst getNoPendingStreamId = () => null;\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 canResume,\n onResumeToolCall,\n onRespondToToolApproval,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n unstable_enableMessageQueue,\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 canResume,\n onResumeToolCall,\n onRespondToToolApproval,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n unstable_enableMessageQueue,\n chatInit,\n };\n};\n\ntype ChatCallbacks<UI_MESSAGE extends UIMessage> = Pick<\n ChatInit<UI_MESSAGE>,\n \"onToolCall\" | \"onData\" | \"onFinish\" | \"onError\" | \"sendAutomaticallyWhen\"\n> & {\n canResume?: boolean | undefined;\n resumableStorage?: ResumableClientStorage | undefined;\n};\n\ntype ChatRequest = {\n reconnectFailure?: { error: unknown };\n};\n\nconst requestsByChat = new WeakMap<object, ChatRequest>();\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 const transport = init.transport;\n const chat = new Chat<UI_MESSAGE>({\n ...init,\n ...(transport && {\n transport: {\n get resumeStreamIsReplay() {\n return transport.resumeStreamIsReplay ?? false;\n },\n sendMessages: (options) => {\n requestsByChat.set(chat, {});\n // A new send or regeneration changes the replay target even when\n // the request fails before returning a replacement checkpoint.\n if (callbacksRef.current?.canResume) {\n const storage =\n callbacksRef.current.resumableStorage ??\n getResumableAdapter(transport)?.storage;\n storage?.clear(options.chatId);\n }\n return transport.sendMessages(options);\n },\n reconnectToStream: async (options) => {\n const request: ChatRequest = {};\n requestsByChat.set(chat, request);\n try {\n return await transport.reconnectToStream(options);\n } catch (error) {\n // SDK 7 suppresses a superseded reconnect's rejection after its\n // abort signal fires. Preserve the actual transport failure for\n // the resume invocation that owns it, without borrowing Chat.error\n // from a newer send or resume. Genuine aborts remain cancellation.\n if (\n typeof error !== \"object\" ||\n error === null ||\n !(\"name\" in error) ||\n error.name !== \"AbortError\"\n ) {\n request.reconnectFailure = { error };\n }\n throw error;\n }\n },\n },\n }),\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 return chat;\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 canResume,\n onResumeToolCall,\n onRespondToToolApproval,\n onResumeError,\n joinStrategy,\n messageRepository,\n unstable_onBranchChange,\n unstable_enableMessageQueue,\n chatInit: chatOptions,\n } = splitChatThreadOptions(options);\n\n const {\n id,\n isMainThread,\n getThreadListItem,\n stopOnClientDestroy = true,\n hostDestroySignal,\n chat: externalChat,\n messageRepositoryInstance,\n } = env;\n\n const defaultTransport = useMemo(() => new AssistantChatTransport(), []);\n const configuredTransport = transportOptions ?? defaultTransport;\n const transport = useDynamicChatTransport(\n configuredTransport,\n externalChat === undefined,\n );\n const transportContextOwner = useMemo(() => ({}), []);\n const getThreadListItemRef = useRef(getThreadListItem);\n useInsertionEffect(() => {\n getThreadListItemRef.current = getThreadListItem;\n }, [getThreadListItem]);\n const getCurrentThreadListItem = useCallback(\n () => getThreadListItemRef.current(),\n [],\n );\n const resumableStorage = useMemo(\n () =>\n transport instanceof DynamicChatTransport\n ? transport.getCurrentResumableStorage()\n : getResumableAdapter(transport)?.storage,\n [transport],\n );\n\n const transportBindingRef = useRef<ChatThreadTransportBinding | null>(null);\n // This is null when useMemo runs, so the proxy pins its mount render's binding. The fallback\n // serves only pre-commit sends; after insertion effects, transportBindingRef is authoritative.\n let initialTransportBinding: ChatThreadTransportBinding | null = null;\n const chatTransport = useMemo(\n () =>\n transport instanceof DynamicChatTransport\n ? transport.createThreadProxy(transportContextOwner, () => {\n const binding =\n transportBindingRef.current ?? initialTransportBinding;\n if (!binding) {\n throw new Error(\"Chat transport used before runtime setup\");\n }\n return binding;\n })\n : transport,\n [initialTransportBinding, transport, transportContextOwner],\n );\n\n const latestChatOptionsRef = useRef({\n ...chatOptions,\n canResume,\n resumableStorage,\n });\n useEffect(() => {\n latestChatOptionsRef.current = {\n ...chatOptions,\n canResume,\n resumableStorage,\n };\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(\n { ...chatOptions, id, transport: chatTransport },\n latestChatOptionsRef,\n ),\n );\n\n const chat = useChatSnapshot(externalChat ?? ownedChat, throttle);\n\n useResourceCleanup(\n stopOnClientDestroy,\n () => {\n void chat.stop().catch(() => {});\n },\n hostDestroySignal,\n );\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 staticResumedStreamIds = useMemo(\n () => getResumedStreamIds(resumableStorage),\n [resumableStorage],\n );\n const onResumeErrorRef = useRef(onResumeError);\n useEffect(() => {\n onResumeErrorRef.current = onResumeError;\n });\n const resumeChatStream = chat.resumeStream;\n const resumeStream = useCallback(async () => {\n const resumedStreamIds =\n transport instanceof DynamicChatTransport\n ? transport.getResumedStreamIds()\n : staticResumedStreamIds;\n const streamId = resumableStorage?.getStreamId(id);\n if (!streamId) return;\n resumedStreamIds.add(streamId);\n try {\n const activeChat = externalChat ?? ownedChat;\n activeChat.clearError();\n const pending = resumeChatStream();\n const request = requestsByChat.get(activeChat);\n await pending;\n if (request?.reconnectFailure) {\n throw request.reconnectFailure.error;\n }\n // Chat.error is shared with sends and resumes that can start before\n // this promise settles, including inside the caller's onFinish.\n if (requestsByChat.get(activeChat) === request && activeChat.error) {\n throw activeChat.error;\n }\n } catch (error) {\n try {\n onResumeErrorRef.current?.(error);\n } catch (callbackError) {\n console.error(\n \"[assistant-ui] resumable: onResumeError callback failed\",\n callbackError,\n );\n } finally {\n if (!canResume && resumableStorage?.getStreamId(id) === streamId) {\n resumableStorage.clear(id);\n }\n }\n throw error;\n }\n }, [\n canResume,\n externalChat,\n id,\n ownedChat,\n resumeChatStream,\n resumableStorage,\n staticResumedStreamIds,\n transport,\n ]);\n\n const handleBranchChange = useCallback<\n NonNullable<AISDKRuntimeAdapter[\"unstable_onBranchChange\"]>\n >(\n (event) => {\n if (canResume) resumableStorage?.clear(id);\n unstable_onBranchChange?.(event);\n },\n [canResume, id, resumableStorage, unstable_onBranchChange],\n );\n\n const runtime = useAISDKRuntime(chat, {\n adapters: {\n ...adapters,\n threadList: { threadId: id, ...adapters?.threadList },\n },\n ...pickExternalStoreSharedOptions(options ?? {}),\n ...(toCreateMessage && { toCreateMessage }),\n ...(onResume\n ? { onResume }\n : canResume && resumableStorage\n ? { onResume: resumeStream }\n : {}),\n // AI SDK 7 starts resume-stream with fresh message state (chat.ts), so the\n // host must replay the full message with its original start.messageId.\n // Without that ID the replay appends a second message. A stored stream ID\n // alone cannot establish this contract; only the host can opt in.\n canResume: onResume\n ? !!canResume\n : !!canResume && !!pendingStreamId && !isChatRunning,\n ...(onResumeToolCall && { onResumeToolCall }),\n ...(onRespondToToolApproval && { onRespondToToolApproval }),\n ...(joinStrategy && { joinStrategy }),\n ...(messageRepository && { messageRepository }),\n ...(messageRepositoryInstance && {\n unstable_messageRepositoryInstance: messageRepositoryInstance,\n }),\n // The chat outlives this runtime when a host mounts only the visible\n // thread, so a host approval answer is kept with it. This is the Chat\n // instance, not the useChat helpers, which are re-minted every render and\n // would be a dead WeakMap key by the next one.\n unstable_hostApprovalOwner: externalChat ?? ownedChat,\n ...(((canResume && resumableStorage) || unstable_onBranchChange) && {\n unstable_onBranchChange: handleBranchChange,\n }),\n ...(unstable_enableMessageQueue && { unstable_enableMessageQueue }),\n });\n\n initialTransportBinding = {\n runtime,\n getThreadListItem: getCurrentThreadListItem,\n };\n useInsertionEffect(() => {\n transportBindingRef.current = {\n runtime,\n getThreadListItem: getCurrentThreadListItem,\n };\n }, [runtime, getCurrentThreadListItem]);\n\n const registerTransportContext = useEffectEvent(\n (dynamicTransport: DynamicChatTransport<UI_MESSAGE>, chatId: string) => {\n dynamicTransport.setThreadContext(\n chatId,\n transportContextOwner,\n runtime,\n getCurrentThreadListItem,\n );\n return () =>\n dynamicTransport.unregisterThread(chatId, transportContextOwner);\n },\n );\n useInsertionEffect(() => {\n if (!(transport instanceof DynamicChatTransport)) return undefined;\n return registerTransportContext(transport, id);\n }, [id, runtime, transport, transportContextOwner]);\n\n if (\n !(transport instanceof DynamicChatTransport) &&\n configuredTransport instanceof AssistantChatTransport\n ) {\n configuredTransport.setRuntime(runtime);\n configuredTransport.__internal_setGetThreadListItem(\n getCurrentThreadListItem,\n );\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 useEffect(() => {\n const resumedStreamIds =\n transport instanceof DynamicChatTransport\n ? transport.getResumedStreamIds()\n : staticResumedStreamIds;\n if (!pendingStreamId || resumedStreamIds.has(pendingStreamId)) {\n return;\n }\n if (isChatRunning) {\n resumedStreamIds.add(pendingStreamId);\n return;\n }\n if (isLoadingHistory) return;\n resumeStream().catch((err: unknown) => {\n console.warn(\"[assistant-ui] resumable: resume failed\", err);\n });\n }, [\n isChatRunning,\n isLoadingHistory,\n pendingStreamId,\n resumeStream,\n staticResumedStreamIds,\n transport,\n ]);\n\n return runtime;\n};\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { UIMessage } from "ai";
2
+ import type { ChatTransport } from "ai";
3
+ export declare const useDynamicChatTransport: <UI_MESSAGE extends UIMessage>(transport: ChatTransport<UI_MESSAGE>, enabled?: boolean) => ChatTransport<UI_MESSAGE>;
4
+ //# sourceMappingURL=useDynamicChatTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDynamicChatTransport.d.ts","mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI;AAIvC,eAAO,MAAM,uBAAuB,GAAI,UAAU,SAAS,SAAS,EAClE,WAAW,aAAa,CAAC,UAAU,CAAC,EACpC,iBAAc,KACb,aAAa,CAAC,UAAU,CAiB1B","names":[],"ignoreList":[],"sources":["../../src/runtime/useDynamicChatTransport.ts"],"sourcesContent":[null]}
@@ -0,0 +1,26 @@
1
+ import { DynamicChatTransport } from "./DynamicChatTransport.js";
2
+ import { useEffect, useInsertionEffect, useState } from "@ulearning/ai-tap";
3
+ // src/runtime/useDynamicChatTransport.ts
4
+ const useDynamicChatTransport = (transport, enabled = true) => {
5
+ const [dynamicTransport] = useState(() => transport instanceof DynamicChatTransport ? transport : new DynamicChatTransport(transport));
6
+ useInsertionEffect(() => {
7
+ if (!enabled || dynamicTransport === transport) return;
8
+ dynamicTransport.setTransport(transport);
9
+ }, [
10
+ dynamicTransport,
11
+ enabled,
12
+ transport
13
+ ]);
14
+ useEffect(() => {
15
+ if (!enabled || dynamicTransport === transport) return;
16
+ dynamicTransport.flushTransportChange();
17
+ }, [
18
+ dynamicTransport,
19
+ enabled,
20
+ transport
21
+ ]);
22
+ return enabled ? dynamicTransport : transport;
23
+ };
24
+ export { useDynamicChatTransport };
25
+
26
+ //# sourceMappingURL=useDynamicChatTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDynamicChatTransport.js","names":[],"sources":["../../src/runtime/useDynamicChatTransport.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport type { ChatTransport } from \"ai\";\nimport { useEffect, useInsertionEffect, useState } from \"@ulearning/ai-tap\";\nimport { DynamicChatTransport } from \"./DynamicChatTransport\";\n\nexport const useDynamicChatTransport = <UI_MESSAGE extends UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n enabled = true,\n): ChatTransport<UI_MESSAGE> => {\n const [dynamicTransport] = useState(() =>\n transport instanceof DynamicChatTransport\n ? transport\n : new DynamicChatTransport(transport),\n );\n\n useInsertionEffect(() => {\n if (!enabled || dynamicTransport === transport) return;\n dynamicTransport.setTransport(transport);\n }, [dynamicTransport, enabled, transport]);\n useEffect(() => {\n if (!enabled || dynamicTransport === transport) return;\n dynamicTransport.flushTransportChange();\n }, [dynamicTransport, enabled, transport]);\n\n return enabled ? dynamicTransport : transport;\n};\n"],"mappings":";;;AAKA,MAAa,2BACX,WACA,UAAU,SACoB;CAC9B,MAAM,CAAC,oBAAoB,eACzB,qBAAqB,uBACjB,YACA,IAAI,qBAAqB,SAAS,CACxC;CAEA,yBAAyB;EACvB,IAAI,CAAC,WAAW,qBAAqB,WAAW;EAChD,iBAAiB,aAAa,SAAS;CACzC,GAAG;EAAC;EAAkB;EAAS;CAAS,CAAC;CACzC,gBAAgB;EACd,IAAI,CAAC,WAAW,qBAAqB,WAAW;EAChD,iBAAiB,qBAAqB;CACxC,GAAG;EAAC;EAAkB;EAAS;CAAS,CAAC;CAEzC,OAAO,UAAU,mBAAmB;AACtC"}
@@ -0,0 +1,12 @@
1
+ import type { AssistantRuntime, ThreadHistoryAdapter, ThreadMessage, MessageFormatAdapter, MessageFormatRepository, ExportedMessageRepository, RespondToToolApprovalOptions, Unstable_ToolInteractionLog } from "@ulearning/ai-core";
2
+ export declare const toExportedMessageRepository: <TMessage>(toThreadMessages: (messages: TMessage[]) => ThreadMessage[], messages: MessageFormatRepository<TMessage>) => ExportedMessageRepository;
3
+ export declare const useExternalHistory: <TMessage>(runtimeRef: {
4
+ current: AssistantRuntime;
5
+ }, historyAdapter: ThreadHistoryAdapter | undefined, toThreadMessages: (messages: TMessage[]) => ThreadMessage[], storageFormatAdapter: MessageFormatAdapter<TMessage, any>, onSetMessages: (messages: TMessage[]) => void, getToolArtifacts?: () => ReadonlyMap<string, unknown>, onToolArtifactsRestored?: (next: Map<string, unknown>) => void, getToolInteractions?: () => ReadonlyMap<string, Unstable_ToolInteractionLog>, onToolInteractionsRestored?: (next: Map<string, Unstable_ToolInteractionLog>) => void, toolApprovalResponses?: Map<string, RespondToToolApprovalOptions>, onToolApprovalResponsesRestored?: () => void) => {
6
+ isLoading: boolean;
7
+ deleteMessage: (messageId: string) => Promise<void>;
8
+ markRunCancelled: () => void;
9
+ persistToolInteractions: (messageId: string) => Promise<void>;
10
+ persistToolApprovalResponses: (messageId: string) => Promise<void>;
11
+ };
12
+ //# sourceMappingURL=useExternalHistory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExternalHistory.d.ts","mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAEhB,oBAAoB,EACpB,aAAa,EACb,oBAAoB,EAEpB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,EAC5B,2BAA2B,EAC5B,MAAM,oBAAoB;AAwB3B,eAAO,MAAM,2BAA2B,GAAI,QAAQ,EAClD,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,EAC3D,UAAU,uBAAuB,CAAC,QAAQ,CAAC,KAC1C,yBAyBF;AA0DD,eAAO,MAAM,kBAAkB,GAAI,QAAQ,EACzC,YAAY;IAAE,OAAO,EAAE,gBAAgB;CAAE,EACzC,gBAAgB,oBAAoB,GAAG,SAAS,EAChD,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,EAC3D,sBAAsB,oBAAoB,CAAC,QAAQ,EAAE,GAAG,CAAC,EACzD,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,IAAI,EAC7C,mBAAmB,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EACrD,0BAA0B,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,EAC9D,sBAAsB,MAAM,WAAW,CAAC,MAAM,EAAE,2BAA2B,CAAC,EAC5E,6BAA6B,CAC3B,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,2BAA2B,CAAC,KAC3C,IAAI,EACT,wBAAwB,GAAG,CAAC,MAAM,EAAE,4BAA4B,CAAC,EACjE,kCAAkC,MAAM,IAAI;;+BAqtBxB,MAAM;;yCAreZ,MAAM;8CAAN,MAAM;CA6gBrB","names":[],"ignoreList":[],"sources":["../../src/runtime/useExternalHistory.ts"],"sourcesContent":[null]}