@assistant-ui/core 0.2.21 → 0.2.22

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 (209) hide show
  1. package/dist/adapters/attachment.d.ts.map +1 -1
  2. package/dist/adapters/speech.d.ts.map +1 -1
  3. package/dist/adapters/speech.js +9 -2
  4. package/dist/adapters/speech.js.map +1 -1
  5. package/dist/adapters/voice.d.ts.map +1 -1
  6. package/dist/adapters/voice.js +13 -5
  7. package/dist/adapters/voice.js.map +1 -1
  8. package/dist/internal.d.ts +3 -1
  9. package/dist/internal.js +3 -1
  10. package/dist/model-context/frame/host.d.ts +1 -0
  11. package/dist/model-context/frame/host.d.ts.map +1 -1
  12. package/dist/model-context/frame/host.js +5 -0
  13. package/dist/model-context/frame/host.js.map +1 -1
  14. package/dist/model-context/frame/provider.d.ts.map +1 -1
  15. package/dist/model-context/frame/provider.js +1 -0
  16. package/dist/model-context/frame/provider.js.map +1 -1
  17. package/dist/model-context/interactable-composer-metadata.js.map +1 -1
  18. package/dist/react/AssistantProvider.js.map +1 -1
  19. package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
  20. package/dist/react/adapters/LocalStorageThreadListAdapter.js +77 -50
  21. package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
  22. package/dist/react/client/Interactables.js.map +1 -1
  23. package/dist/react/client/Tools.d.ts.map +1 -1
  24. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  25. package/dist/react/model-context/useInteractable.js.map +1 -1
  26. package/dist/react/primitive-hooks/useActionBarCopy.js +13 -13
  27. package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
  28. package/dist/react/primitive-hooks/useComposerAddAttachment.d.ts.map +1 -1
  29. package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
  30. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -1
  31. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -1
  32. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
  33. package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
  34. package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
  35. package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
  36. package/dist/react/primitives/generativeUI/GenerativeUI.d.ts.map +1 -1
  37. package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
  38. package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
  39. package/dist/react/primitives/message/MessageParts.d.ts +2 -1
  40. package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
  41. package/dist/react/primitives/message/MessageParts.js +46 -36
  42. package/dist/react/primitives/message/MessageParts.js.map +1 -1
  43. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  44. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  45. package/dist/react/primitives/thread/ThreadSuggestions.js.map +1 -1
  46. package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
  47. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
  48. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js +18 -30
  49. package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -1
  50. package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
  51. package/dist/react/providers/PartByIndexProvider.js +18 -30
  52. package/dist/react/providers/PartByIndexProvider.js.map +1 -1
  53. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  54. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +1 -0
  55. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
  56. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +9 -2
  57. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  58. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +49 -8
  59. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  60. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +1 -1
  61. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
  62. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
  63. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +2 -1
  64. package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
  65. package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
  66. package/dist/react/runtimes/external-message-converter.js +1 -1
  67. package/dist/react/runtimes/external-message-converter.js.map +1 -1
  68. package/dist/react/runtimes/useLocalRuntime.d.ts +1 -0
  69. package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
  70. package/dist/react/runtimes/useLocalRuntime.js +9 -1
  71. package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
  72. package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
  73. package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
  74. package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
  75. package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
  76. package/dist/runtime/api/message-runtime.d.ts.map +1 -1
  77. package/dist/runtime/api/message-runtime.js +4 -4
  78. package/dist/runtime/api/message-runtime.js.map +1 -1
  79. package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
  80. package/dist/runtime/api/thread-list-item-runtime.js +2 -1
  81. package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
  82. package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
  83. package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
  84. package/dist/runtime/base/base-composer-runtime-core.d.ts +4 -1
  85. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  86. package/dist/runtime/base/base-composer-runtime-core.js +41 -14
  87. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  88. package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
  89. package/dist/runtime/base/base-thread-runtime-core.js +2 -1
  90. package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
  91. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  92. package/dist/runtime/base/default-edit-composer-runtime-core.js +4 -2
  93. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  94. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  95. package/dist/runtime/base/default-thread-composer-runtime-core.js +2 -2
  96. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  97. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  98. package/dist/runtime/utils/thread-message-like.js +4 -1
  99. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  100. package/dist/runtimes/external-store/external-store-runtime-core.d.ts.map +1 -1
  101. package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
  102. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  103. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  104. package/dist/runtimes/local/local-runtime-core.d.ts.map +1 -1
  105. package/dist/runtimes/local/local-thread-list-runtime-core.d.ts.map +1 -1
  106. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  107. package/dist/runtimes/local/local-thread-runtime-core.js +5 -2
  108. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  109. package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
  110. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +4 -4
  111. package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
  112. package/dist/runtimes/remote-thread-list/optimistic-state.js +22 -9
  113. package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
  114. package/dist/runtimes/remote-thread-list/types.d.ts +1 -1
  115. package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
  116. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +1 -2
  117. package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
  118. package/dist/store/clients/chain-of-thought-client.d.ts.map +1 -1
  119. package/dist/store/clients/no-op-composer-client.d.ts.map +1 -1
  120. package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
  121. package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
  122. package/dist/store/runtime-clients/message-part-runtime-client.d.ts.map +1 -1
  123. package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
  124. package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
  125. package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
  126. package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
  127. package/dist/subscribable/subscribable.d.ts +1 -1
  128. package/dist/subscribable/subscribable.d.ts.map +1 -1
  129. package/dist/subscribable/subscribable.js +11 -3
  130. package/dist/subscribable/subscribable.js.map +1 -1
  131. package/dist/tests/remote-thread-list-test-helpers.d.ts +2 -1
  132. package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
  133. package/dist/tests/remote-thread-list-test-helpers.js +5 -2
  134. package/dist/tests/remote-thread-list-test-helpers.js.map +1 -1
  135. package/dist/types/attachment.d.ts +2 -1
  136. package/dist/types/attachment.d.ts.map +1 -1
  137. package/dist/types/attachment.js +6 -0
  138. package/dist/types/attachment.js.map +1 -0
  139. package/dist/types/message.d.ts +1 -0
  140. package/dist/types/message.d.ts.map +1 -1
  141. package/dist/types/message.js.map +1 -1
  142. package/dist/utils/data-url.d.ts +9 -0
  143. package/dist/utils/data-url.d.ts.map +1 -0
  144. package/dist/utils/data-url.js +14 -0
  145. package/dist/utils/data-url.js.map +1 -0
  146. package/dist/utils/notify-event-listeners.d.ts +6 -0
  147. package/dist/utils/notify-event-listeners.d.ts.map +1 -0
  148. package/dist/utils/notify-event-listeners.js +16 -0
  149. package/dist/utils/notify-event-listeners.js.map +1 -0
  150. package/package.json +10 -9
  151. package/src/adapters/speech.test.ts +88 -0
  152. package/src/adapters/speech.ts +17 -2
  153. package/src/adapters/voice.test.ts +130 -0
  154. package/src/adapters/voice.ts +26 -6
  155. package/src/internal.ts +5 -0
  156. package/src/model-context/frame/host.test.ts +100 -0
  157. package/src/model-context/frame/host.ts +10 -0
  158. package/src/model-context/frame/provider.test.ts +83 -0
  159. package/src/model-context/frame/provider.ts +1 -0
  160. package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +82 -0
  161. package/src/react/adapters/LocalStorageThreadListAdapter.tsx +94 -54
  162. package/src/react/primitive-hooks/useActionBarCopy.test.ts +79 -0
  163. package/src/react/primitive-hooks/useActionBarCopy.ts +4 -3
  164. package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -3
  165. package/src/react/primitives/message/MessageParts.tsx +48 -35
  166. package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +19 -2
  167. package/src/react/providers/PartByIndexProvider.tsx +16 -2
  168. package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +18 -0
  169. package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +1 -0
  170. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +48 -7
  171. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +69 -0
  172. package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +1 -1
  173. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +16 -0
  174. package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +2 -1
  175. package/src/react/runtimes/external-message-converter.test.tsx +21 -0
  176. package/src/react/runtimes/external-message-converter.ts +1 -1
  177. package/src/react/runtimes/useLocalRuntime.test.tsx +56 -0
  178. package/src/react/runtimes/useLocalRuntime.ts +13 -1
  179. package/src/runtime/api/message-runtime.test.ts +81 -0
  180. package/src/runtime/api/message-runtime.ts +4 -6
  181. package/src/runtime/api/thread-list-item-runtime.ts +6 -1
  182. package/src/runtime/base/base-composer-runtime-core.ts +77 -31
  183. package/src/runtime/base/base-thread-runtime-core.ts +2 -1
  184. package/src/runtime/base/default-edit-composer-runtime-core.ts +4 -2
  185. package/src/runtime/base/default-thread-composer-runtime-core.ts +2 -2
  186. package/src/runtime/utils/thread-message-like.ts +1 -0
  187. package/src/runtimes/local/local-thread-runtime-core.test.ts +150 -1
  188. package/src/runtimes/local/local-thread-runtime-core.ts +4 -2
  189. package/src/runtimes/remote-thread-list/optimistic-state.test.ts +63 -0
  190. package/src/runtimes/remote-thread-list/optimistic-state.ts +49 -17
  191. package/src/runtimes/remote-thread-list/types.ts +1 -1
  192. package/src/runtimes/tool-invocations/EDGE_CASES.md +13 -19
  193. package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +127 -6
  194. package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +4 -2
  195. package/src/subscribable/subscribable.test.ts +58 -0
  196. package/src/subscribable/subscribable.ts +13 -3
  197. package/src/tests/OptimisticState-list-race.test.ts +33 -0
  198. package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-order.test.ts +223 -0
  199. package/src/tests/base-composer-runtime-core-addAttachment.test.ts +44 -0
  200. package/src/tests/base-composer-runtime-core-send.test.ts +433 -5
  201. package/src/tests/default-edit-composer-runtime-core.test.ts +43 -5
  202. package/src/tests/event-subscription-listener-errors.test.ts +205 -0
  203. package/src/tests/remote-thread-list-test-helpers.ts +14 -7
  204. package/src/tests/thread-message-like.test.ts +57 -0
  205. package/src/types/attachment.ts +5 -0
  206. package/src/types/message.ts +1 -0
  207. package/src/utils/data-url.test.ts +50 -0
  208. package/src/utils/data-url.ts +9 -0
  209. package/src/utils/notify-event-listeners.ts +30 -0
@@ -4,6 +4,28 @@ import { useAui } from "@assistant-ui/store";
4
4
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/react/adapters/LocalStorageThreadListAdapter.tsx
7
+ var KeyedMutationQueue = class {
8
+ tails = /* @__PURE__ */ new Map();
9
+ run(key, mutation) {
10
+ const previous = this.tails.get(key);
11
+ const result = previous ? previous.then(mutation) : mutation();
12
+ const tail = result.then(() => void 0, () => void 0);
13
+ this.tails.set(key, tail);
14
+ tail.then(() => {
15
+ if (this.tails.get(key) === tail) this.tails.delete(key);
16
+ });
17
+ return result;
18
+ }
19
+ };
20
+ const mutationQueues = /* @__PURE__ */ new WeakMap();
21
+ const getMutationQueue = (storage) => {
22
+ let queue = mutationQueues.get(storage);
23
+ if (!queue) {
24
+ queue = new KeyedMutationQueue();
25
+ mutationQueues.set(storage, queue);
26
+ }
27
+ return queue;
28
+ };
7
29
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8
30
  const parseJSON = (raw) => {
9
31
  if (!raw) return void 0;
@@ -123,10 +145,12 @@ var AsyncStorageHistoryAdapter = class {
123
145
  storage;
124
146
  aui;
125
147
  prefix;
126
- constructor(storage, aui, prefix) {
148
+ mutationQueue;
149
+ constructor(storage, aui, prefix, mutationQueue) {
127
150
  this.storage = storage;
128
151
  this.aui = aui;
129
152
  this.prefix = prefix;
153
+ this.mutationQueue = mutationQueue;
130
154
  }
131
155
  _messagesKey(remoteId) {
132
156
  return `${this.prefix}messages:${remoteId}`;
@@ -140,23 +164,25 @@ var AsyncStorageHistoryAdapter = class {
140
164
  async append(item) {
141
165
  const { remoteId } = await this.aui.threadListItem().initialize();
142
166
  const key = this._messagesKey(remoteId);
143
- const raw = await this.storage.getItem(key);
144
- const repo = parseStoredMessageRepository(raw);
145
- const idx = repo.messages.findIndex((m) => m.message.id === item.message.id);
146
- if (idx >= 0) repo.messages[idx] = item;
147
- else repo.messages.push(item);
148
- repo.headId = item.message.id;
149
- await this.storage.setItem(key, JSON.stringify(repo));
167
+ await this.mutationQueue.run(key, async () => {
168
+ const raw = await this.storage.getItem(key);
169
+ const repo = parseStoredMessageRepository(raw);
170
+ const idx = repo.messages.findIndex((m) => m.message.id === item.message.id);
171
+ if (idx >= 0) repo.messages[idx] = item;
172
+ else repo.messages.push(item);
173
+ repo.headId = item.message.id;
174
+ await this.storage.setItem(key, JSON.stringify(repo));
175
+ });
150
176
  }
151
177
  };
152
- const createHistoryProvider = (storage, prefix) => {
178
+ const createHistoryProvider = (storage, prefix, mutationQueue) => {
153
179
  const Provider = (t0) => {
154
180
  const $ = c(7);
155
181
  const { children } = t0;
156
182
  const aui = useAui();
157
183
  let t1;
158
184
  if ($[0] !== aui) {
159
- t1 = new AsyncStorageHistoryAdapter(storage, aui, prefix);
185
+ t1 = new AsyncStorageHistoryAdapter(storage, aui, prefix, mutationQueue);
160
186
  $[0] = aui;
161
187
  $[1] = t1;
162
188
  } else t1 = $[1];
@@ -186,6 +212,7 @@ const createLocalStorageAdapter = (options) => {
186
212
  const { storage, prefix = "@assistant-ui:", titleGenerator } = options;
187
213
  const threadsKey = `${prefix}threads`;
188
214
  const messagesKey = (threadId) => `${prefix}messages:${threadId}`;
215
+ const mutationQueue = getMutationQueue(storage);
189
216
  const loadThreadMetadata = async () => {
190
217
  const raw = await storage.getItem(threadsKey);
191
218
  return parseStoredThreadMetadata(raw);
@@ -193,8 +220,18 @@ const createLocalStorageAdapter = (options) => {
193
220
  const saveThreadMetadata = async (threads) => {
194
221
  await storage.setItem(threadsKey, JSON.stringify(threads));
195
222
  };
223
+ const updateThreadMetadata = async (remoteId, update) => {
224
+ await mutationQueue.run(threadsKey, async () => {
225
+ const threads = await loadThreadMetadata();
226
+ const thread = threads.find((item) => item.remoteId === remoteId);
227
+ if (thread) {
228
+ update(thread);
229
+ await saveThreadMetadata(threads);
230
+ }
231
+ });
232
+ };
196
233
  return {
197
- unstable_Provider: createHistoryProvider(storage, prefix),
234
+ unstable_Provider: createHistoryProvider(storage, prefix, mutationQueue),
198
235
  async list() {
199
236
  return { threads: (await loadThreadMetadata()).map((t) => ({
200
237
  remoteId: t.remoteId,
@@ -206,55 +243,48 @@ const createLocalStorageAdapter = (options) => {
206
243
  },
207
244
  async initialize(threadId) {
208
245
  const remoteId = threadId;
209
- const threads = await loadThreadMetadata();
210
- if (!threads.some((t) => t.remoteId === remoteId)) {
211
- threads.unshift({
246
+ return mutationQueue.run(threadsKey, async () => {
247
+ const threads = await loadThreadMetadata();
248
+ if (!threads.some((t) => t.remoteId === remoteId)) {
249
+ threads.unshift({
250
+ remoteId,
251
+ status: "regular"
252
+ });
253
+ await saveThreadMetadata(threads);
254
+ }
255
+ return {
212
256
  remoteId,
213
- status: "regular"
214
- });
215
- await saveThreadMetadata(threads);
216
- }
217
- return {
218
- remoteId,
219
- externalId: void 0
220
- };
257
+ externalId: void 0
258
+ };
259
+ });
221
260
  },
222
261
  async rename(remoteId, newTitle) {
223
- const threads = await loadThreadMetadata();
224
- const thread = threads.find((t) => t.remoteId === remoteId);
225
- if (thread) {
262
+ await updateThreadMetadata(remoteId, (thread) => {
226
263
  thread.title = newTitle;
227
- await saveThreadMetadata(threads);
228
- }
264
+ });
229
265
  },
230
266
  async updateCustom(remoteId, custom) {
231
- const threads = await loadThreadMetadata();
232
- const thread = threads.find((t) => t.remoteId === remoteId);
233
- if (thread) {
267
+ await updateThreadMetadata(remoteId, (thread) => {
234
268
  thread.custom = custom;
235
- await saveThreadMetadata(threads);
236
- }
269
+ });
237
270
  },
238
271
  async archive(remoteId) {
239
- const threads = await loadThreadMetadata();
240
- const thread = threads.find((t) => t.remoteId === remoteId);
241
- if (thread) {
272
+ await updateThreadMetadata(remoteId, (thread) => {
242
273
  thread.status = "archived";
243
- await saveThreadMetadata(threads);
244
- }
274
+ });
245
275
  },
246
276
  async unarchive(remoteId) {
247
- const threads = await loadThreadMetadata();
248
- const thread = threads.find((t) => t.remoteId === remoteId);
249
- if (thread) {
277
+ await updateThreadMetadata(remoteId, (thread) => {
250
278
  thread.status = "regular";
251
- await saveThreadMetadata(threads);
252
- }
279
+ });
253
280
  },
254
281
  async delete(remoteId) {
255
- const filtered = (await loadThreadMetadata()).filter((t) => t.remoteId !== remoteId);
256
- await saveThreadMetadata(filtered);
257
- await storage.removeItem(messagesKey(remoteId));
282
+ await mutationQueue.run(threadsKey, async () => {
283
+ const filtered = (await loadThreadMetadata()).filter((t) => t.remoteId !== remoteId);
284
+ await saveThreadMetadata(filtered);
285
+ });
286
+ const key = messagesKey(remoteId);
287
+ await mutationQueue.run(key, () => storage.removeItem(key));
258
288
  },
259
289
  async fetch(threadId) {
260
290
  const thread = (await loadThreadMetadata()).find((t) => t.remoteId === threadId);
@@ -270,12 +300,9 @@ const createLocalStorageAdapter = (options) => {
270
300
  async generateTitle(remoteId, messages) {
271
301
  if (titleGenerator) {
272
302
  const title = await titleGenerator.generateTitle(messages);
273
- const threads = await loadThreadMetadata();
274
- const thread = threads.find((t) => t.remoteId === remoteId);
275
- if (thread) {
303
+ await updateThreadMetadata(remoteId, (thread) => {
276
304
  thread.title = title;
277
- await saveThreadMetadata(threads);
278
- }
305
+ });
279
306
  return createAssistantStream((controller) => {
280
307
  controller.appendText(title);
281
308
  });
@@ -1 +1 @@
1
- {"version":3,"file":"LocalStorageThreadListAdapter.js","names":["AssistantStream","createAssistantStream","FC","PropsWithChildren","useMemo","useAui","RemoteThreadInitializeResponse","RemoteThreadListAdapter","RemoteThreadListResponse","RemoteThreadMetadata","ThreadHistoryAdapter","ThreadMessage","RunConfig","ExportedMessageRepository","ExportedMessageRepositoryItem","RuntimeAdapterProvider","TitleGenerationAdapter","AsyncStorageLike","getItem","key","Promise","setItem","value","removeItem","LocalStorageAdapterOptions","storage","prefix","titleGenerator","StoredThreadMetadata","remoteId","externalId","status","title","custom","Record","StoredSystemMessage","Extract","role","StoredUserMessage","StoredAssistantMessage","isRecord","Array","isArray","parseJSON","raw","undefined","JSON","parse","parseStoredThread","parseDate","Date","Number","isNaN","getTime","date","isMessageRole","parseStoredThreadMessage","id","content","createdAt","metadata","type","submittedFeedback","submittedFeedbackType","unstable_state","unstable_annotations","unstable_data","steps","timing","NonNullable","isOptimistic","attachments","length","parseStoredThreadMetadata","parsed","flatMap","item","thread","parseStoredMessageRepositoryItem","message","parentId","runConfig","parseStoredMessageRepository","messages","candidateMessages","parsedItem","acceptedIds","Set","has","add","headId","some","AsyncStorageHistoryAdapter","constructor","aui","ReturnType","_messagesKey","load","threadListItem","getState","append","initialize","repo","idx","findIndex","m","push","stringify","createHistoryProvider","Provider","t0","$","_c","children","t1","history","t2","adapters","t3","createLocalStorageAdapter","options","threadsKey","messagesKey","threadId","loadThreadMetadata","saveThreadMetadata","threads","adapter","unstable_Provider","list","map","t","unshift","rename","newTitle","find","updateCustom","archive","unarchive","delete","filtered","filter","fetch","Error","generateTitle","controller","appendText"],"sources":["../../../src/react/adapters/LocalStorageThreadListAdapter.tsx"],"sourcesContent":["import { type AssistantStream, createAssistantStream } from \"assistant-stream\";\nimport { type FC, type PropsWithChildren, useMemo } from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type {\n RemoteThreadInitializeResponse,\n RemoteThreadListAdapter,\n RemoteThreadListResponse,\n RemoteThreadMetadata,\n ThreadHistoryAdapter,\n ThreadMessage,\n RunConfig,\n} from \"../../index\";\nimport type {\n ExportedMessageRepository,\n ExportedMessageRepositoryItem,\n} from \"../../internal\";\nimport { RuntimeAdapterProvider } from \"../runtimes/RuntimeAdapterProvider\";\nimport type { TitleGenerationAdapter } from \"./TitleGenerationAdapter\";\n\nexport type AsyncStorageLike = {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n};\n\ntype LocalStorageAdapterOptions = {\n storage: AsyncStorageLike;\n prefix?: string | undefined;\n titleGenerator?: TitleGenerationAdapter | undefined;\n};\n\ntype StoredThreadMetadata = {\n remoteId: string;\n externalId?: string;\n status: \"regular\" | \"archived\";\n title?: string;\n custom?: Record<string, unknown> | undefined;\n};\n\ntype StoredSystemMessage = Extract<ThreadMessage, { role: \"system\" }>;\ntype StoredUserMessage = Extract<ThreadMessage, { role: \"user\" }>;\ntype StoredAssistantMessage = Extract<ThreadMessage, { role: \"assistant\" }>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst parseJSON = (raw: string | null): unknown => {\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return undefined;\n }\n};\n\nconst parseStoredThread = (value: unknown): StoredThreadMetadata | null => {\n if (!isRecord(value) || typeof value.remoteId !== \"string\") return null;\n\n const status = value.status ?? \"regular\";\n if (status !== \"regular\" && status !== \"archived\") return null;\n\n return {\n remoteId: value.remoteId,\n status,\n ...(typeof value.externalId === \"string\"\n ? { externalId: value.externalId }\n : undefined),\n ...(typeof value.title === \"string\" ? { title: value.title } : undefined),\n ...(isRecord(value.custom) ? { custom: value.custom } : undefined),\n };\n};\n\nconst parseDate = (value: unknown): Date | null => {\n if (value instanceof Date && !Number.isNaN(value.getTime())) return value;\n if (typeof value !== \"string\" && typeof value !== \"number\") return null;\n\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n};\n\nconst isMessageRole = (value: unknown): value is ThreadMessage[\"role\"] =>\n value === \"system\" || value === \"user\" || value === \"assistant\";\n\nconst parseStoredThreadMessage = (value: unknown): ThreadMessage | null => {\n if (!isRecord(value) || typeof value.id !== \"string\") return null;\n if (!isMessageRole(value.role)) return null;\n if (!Array.isArray(value.content)) return null;\n\n const createdAt = parseDate(value.createdAt);\n if (!createdAt) return null;\n\n const metadata = value.metadata;\n if (!isRecord(metadata) || !isRecord(metadata.custom)) return null;\n\n if (value.role === \"assistant\") {\n const status = value.status;\n if (!isRecord(status) || typeof status.type !== \"string\") return null;\n\n const submittedFeedback = isRecord(metadata.submittedFeedback)\n ? metadata.submittedFeedback\n : undefined;\n const submittedFeedbackType = submittedFeedback?.type;\n\n return {\n id: value.id,\n role: \"assistant\",\n content: value.content as StoredAssistantMessage[\"content\"],\n status: status as StoredAssistantMessage[\"status\"],\n createdAt,\n metadata: {\n unstable_state: (metadata.unstable_state ??\n null) as StoredAssistantMessage[\"metadata\"][\"unstable_state\"],\n unstable_annotations: Array.isArray(metadata.unstable_annotations)\n ? (metadata.unstable_annotations as StoredAssistantMessage[\"metadata\"][\"unstable_annotations\"])\n : [],\n unstable_data: Array.isArray(metadata.unstable_data)\n ? (metadata.unstable_data as StoredAssistantMessage[\"metadata\"][\"unstable_data\"])\n : [],\n steps: Array.isArray(metadata.steps)\n ? (metadata.steps as StoredAssistantMessage[\"metadata\"][\"steps\"])\n : [],\n ...(submittedFeedbackType === \"positive\" ||\n submittedFeedbackType === \"negative\"\n ? {\n submittedFeedback: {\n type: submittedFeedbackType,\n },\n }\n : undefined),\n ...(metadata.timing !== undefined\n ? {\n timing: metadata.timing as NonNullable<\n StoredAssistantMessage[\"metadata\"][\"timing\"]\n >,\n }\n : undefined),\n ...(metadata.isOptimistic === true\n ? { isOptimistic: true }\n : undefined),\n custom: metadata.custom,\n },\n };\n }\n\n if (value.role === \"user\") {\n return {\n id: value.id,\n role: \"user\",\n content: value.content as StoredUserMessage[\"content\"],\n attachments: Array.isArray(value.attachments)\n ? (value.attachments as StoredUserMessage[\"attachments\"])\n : [],\n createdAt,\n metadata: {\n custom: metadata.custom,\n },\n };\n }\n\n if (value.content.length !== 1) return null;\n\n return {\n id: value.id,\n role: \"system\",\n content: [value.content[0] as StoredSystemMessage[\"content\"][0]],\n createdAt,\n metadata: {\n custom: metadata.custom,\n },\n };\n};\n\nexport const parseStoredThreadMetadata = (\n raw: string | null,\n): StoredThreadMetadata[] => {\n const parsed = parseJSON(raw);\n if (!Array.isArray(parsed)) return [];\n\n return parsed.flatMap((item) => {\n const thread = parseStoredThread(item);\n return thread ? [thread] : [];\n });\n};\n\nconst parseStoredMessageRepositoryItem = (\n value: unknown,\n): ExportedMessageRepositoryItem | null => {\n if (!isRecord(value)) return null;\n\n const message = parseStoredThreadMessage(value.message);\n if (!message) return null;\n\n const parentId = value.parentId;\n if (\n parentId !== undefined &&\n parentId !== null &&\n typeof parentId !== \"string\"\n ) {\n return null;\n }\n\n return {\n message,\n parentId: parentId ?? null,\n ...(isRecord(value.runConfig)\n ? { runConfig: value.runConfig as RunConfig }\n : undefined),\n };\n};\n\nexport const parseStoredMessageRepository = (\n raw: string | null,\n): ExportedMessageRepository => {\n const parsed = parseJSON(raw);\n if (!isRecord(parsed) || !Array.isArray(parsed.messages)) {\n return { messages: [] };\n }\n\n const candidateMessages = parsed.messages.flatMap((item) => {\n const parsedItem = parseStoredMessageRepositoryItem(item);\n return parsedItem ? [parsedItem] : [];\n });\n\n const acceptedIds = new Set<string>();\n const messages = candidateMessages.flatMap((item) => {\n if (acceptedIds.has(item.message.id)) return [];\n if (item.parentId !== null && !acceptedIds.has(item.parentId)) return [];\n\n acceptedIds.add(item.message.id);\n return [item];\n });\n\n const headId =\n parsed.headId === null ||\n (typeof parsed.headId === \"string\" &&\n messages.some((item) => item.message.id === parsed.headId))\n ? parsed.headId\n : undefined;\n\n return {\n ...(headId !== undefined ? { headId } : undefined),\n messages,\n };\n};\n\nclass AsyncStorageHistoryAdapter implements ThreadHistoryAdapter {\n constructor(\n private storage: AsyncStorageLike,\n private aui: ReturnType<typeof useAui>,\n private prefix: string,\n ) {}\n\n private _messagesKey(remoteId: string) {\n return `${this.prefix}messages:${remoteId}`;\n }\n\n async load(): Promise<ExportedMessageRepository> {\n const remoteId = this.aui.threadListItem().getState().remoteId;\n if (!remoteId) return { messages: [] };\n\n const raw = await this.storage.getItem(this._messagesKey(remoteId));\n return parseStoredMessageRepository(raw);\n }\n\n async append(item: ExportedMessageRepositoryItem): Promise<void> {\n const { remoteId } = await this.aui.threadListItem().initialize();\n\n const key = this._messagesKey(remoteId);\n const raw = await this.storage.getItem(key);\n const repo = parseStoredMessageRepository(raw);\n\n const idx = repo.messages.findIndex(\n (m) => m.message.id === item.message.id,\n );\n if (idx >= 0) {\n repo.messages[idx] = item;\n } else {\n repo.messages.push(item);\n }\n repo.headId = item.message.id;\n\n await this.storage.setItem(key, JSON.stringify(repo));\n }\n}\n\nconst createHistoryProvider = (\n storage: AsyncStorageLike,\n prefix: string,\n): FC<PropsWithChildren> => {\n const Provider: FC<PropsWithChildren> = ({ children }) => {\n const aui = useAui();\n const history = useMemo(\n () => new AsyncStorageHistoryAdapter(storage, aui, prefix),\n [aui],\n );\n const adapters = useMemo(() => ({ history }), [history]);\n\n return (\n <RuntimeAdapterProvider adapters={adapters}>\n {children}\n </RuntimeAdapterProvider>\n );\n };\n return Provider;\n};\n\nexport const createLocalStorageAdapter = (\n options: LocalStorageAdapterOptions,\n): RemoteThreadListAdapter => {\n const { storage, prefix = \"@assistant-ui:\", titleGenerator } = options;\n\n const threadsKey = `${prefix}threads`;\n const messagesKey = (threadId: string) => `${prefix}messages:${threadId}`;\n\n const loadThreadMetadata = async (): Promise<StoredThreadMetadata[]> => {\n const raw = await storage.getItem(threadsKey);\n return parseStoredThreadMetadata(raw);\n };\n\n const saveThreadMetadata = async (\n threads: StoredThreadMetadata[],\n ): Promise<void> => {\n await storage.setItem(threadsKey, JSON.stringify(threads));\n };\n\n const adapter: RemoteThreadListAdapter = {\n unstable_Provider: createHistoryProvider(storage, prefix),\n\n async list(): Promise<RemoteThreadListResponse> {\n const threads = await loadThreadMetadata();\n return {\n threads: threads.map((t) => ({\n remoteId: t.remoteId,\n externalId: t.externalId,\n status: t.status,\n title: t.title,\n custom: t.custom,\n })),\n };\n },\n\n async initialize(\n threadId: string,\n ): Promise<RemoteThreadInitializeResponse> {\n const remoteId = threadId;\n const threads = await loadThreadMetadata();\n\n // Only add if not already present\n if (!threads.some((t) => t.remoteId === remoteId)) {\n threads.unshift({\n remoteId,\n status: \"regular\",\n });\n await saveThreadMetadata(threads);\n }\n\n return { remoteId, externalId: undefined };\n },\n\n async rename(remoteId: string, newTitle: string): Promise<void> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.title = newTitle;\n await saveThreadMetadata(threads);\n }\n },\n\n async updateCustom(\n remoteId: string,\n custom: Record<string, unknown> | undefined,\n ): Promise<void> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.custom = custom;\n await saveThreadMetadata(threads);\n }\n },\n\n async archive(remoteId: string): Promise<void> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.status = \"archived\";\n await saveThreadMetadata(threads);\n }\n },\n\n async unarchive(remoteId: string): Promise<void> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.status = \"regular\";\n await saveThreadMetadata(threads);\n }\n },\n\n async delete(remoteId: string): Promise<void> {\n const threads = await loadThreadMetadata();\n const filtered = threads.filter((t) => t.remoteId !== remoteId);\n await saveThreadMetadata(filtered);\n await storage.removeItem(messagesKey(remoteId));\n },\n\n async fetch(threadId: string): Promise<RemoteThreadMetadata> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === threadId);\n if (!thread)\n throw new Error(\n `Stored thread \"${threadId}\" not found while fetching thread metadata.`,\n );\n return {\n remoteId: thread.remoteId,\n externalId: thread.externalId,\n status: thread.status,\n title: thread.title,\n custom: thread.custom,\n };\n },\n\n async generateTitle(\n remoteId: string,\n messages: readonly ThreadMessage[],\n ): Promise<AssistantStream> {\n if (titleGenerator) {\n const title = await titleGenerator.generateTitle(messages);\n\n // Update the stored title\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === remoteId);\n if (thread) {\n thread.title = title;\n await saveThreadMetadata(threads);\n }\n\n // Return a stream with a single text part\n return createAssistantStream((controller) => {\n controller.appendText(title);\n });\n }\n\n // No title generator — return empty stream\n return createAssistantStream(() => {});\n },\n };\n\n return adapter;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"LocalStorageThreadListAdapter.js","names":["AssistantStream","createAssistantStream","FC","PropsWithChildren","useMemo","useAui","RemoteThreadInitializeResponse","RemoteThreadListAdapter","RemoteThreadListResponse","RemoteThreadMetadata","ThreadHistoryAdapter","ThreadMessage","RunConfig","ExportedMessageRepository","ExportedMessageRepositoryItem","RuntimeAdapterProvider","TitleGenerationAdapter","AsyncStorageLike","getItem","key","Promise","setItem","value","removeItem","KeyedMutationQueue","tails","Map","run","mutation","T","previous","get","result","then","tail","undefined","set","delete","mutationQueues","WeakMap","getMutationQueue","storage","queue","LocalStorageAdapterOptions","prefix","titleGenerator","StoredThreadMetadata","remoteId","externalId","status","title","custom","Record","StoredSystemMessage","Extract","role","StoredUserMessage","StoredAssistantMessage","isRecord","Array","isArray","parseJSON","raw","JSON","parse","parseStoredThread","parseDate","Date","Number","isNaN","getTime","date","isMessageRole","parseStoredThreadMessage","id","content","createdAt","metadata","type","submittedFeedback","submittedFeedbackType","unstable_state","unstable_annotations","unstable_data","steps","timing","NonNullable","isOptimistic","attachments","length","parseStoredThreadMetadata","parsed","flatMap","item","thread","parseStoredMessageRepositoryItem","message","parentId","runConfig","parseStoredMessageRepository","messages","candidateMessages","parsedItem","acceptedIds","Set","has","add","headId","some","AsyncStorageHistoryAdapter","constructor","aui","ReturnType","mutationQueue","_messagesKey","load","threadListItem","getState","append","initialize","repo","idx","findIndex","m","push","stringify","createHistoryProvider","Provider","t0","$","_c","children","t1","history","t2","adapters","t3","createLocalStorageAdapter","options","threadsKey","messagesKey","threadId","loadThreadMetadata","saveThreadMetadata","threads","updateThreadMetadata","update","find","adapter","unstable_Provider","list","map","t","unshift","rename","newTitle","updateCustom","archive","unarchive","filtered","filter","fetch","Error","generateTitle","controller","appendText"],"sources":["../../../src/react/adapters/LocalStorageThreadListAdapter.tsx"],"sourcesContent":["import { type AssistantStream, createAssistantStream } from \"assistant-stream\";\nimport { type FC, type PropsWithChildren, useMemo } from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type {\n RemoteThreadInitializeResponse,\n RemoteThreadListAdapter,\n RemoteThreadListResponse,\n RemoteThreadMetadata,\n ThreadHistoryAdapter,\n ThreadMessage,\n RunConfig,\n} from \"../../index\";\nimport type {\n ExportedMessageRepository,\n ExportedMessageRepositoryItem,\n} from \"../../internal\";\nimport { RuntimeAdapterProvider } from \"../runtimes/RuntimeAdapterProvider\";\nimport type { TitleGenerationAdapter } from \"./TitleGenerationAdapter\";\n\nexport type AsyncStorageLike = {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n};\n\nclass KeyedMutationQueue {\n private readonly tails = new Map<string, Promise<void>>();\n\n run<T>(key: string, mutation: () => Promise<T>): Promise<T> {\n const previous = this.tails.get(key);\n const result = previous ? previous.then(mutation) : mutation();\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n\n this.tails.set(key, tail);\n void tail.then(() => {\n if (this.tails.get(key) === tail) this.tails.delete(key);\n });\n\n return result;\n }\n}\n\nconst mutationQueues = new WeakMap<AsyncStorageLike, KeyedMutationQueue>();\n\nconst getMutationQueue = (storage: AsyncStorageLike): KeyedMutationQueue => {\n let queue = mutationQueues.get(storage);\n if (!queue) {\n queue = new KeyedMutationQueue();\n mutationQueues.set(storage, queue);\n }\n return queue;\n};\n\ntype LocalStorageAdapterOptions = {\n storage: AsyncStorageLike;\n prefix?: string | undefined;\n titleGenerator?: TitleGenerationAdapter | undefined;\n};\n\ntype StoredThreadMetadata = {\n remoteId: string;\n externalId?: string;\n status: \"regular\" | \"archived\";\n title?: string;\n custom?: Record<string, unknown> | undefined;\n};\n\ntype StoredSystemMessage = Extract<ThreadMessage, { role: \"system\" }>;\ntype StoredUserMessage = Extract<ThreadMessage, { role: \"user\" }>;\ntype StoredAssistantMessage = Extract<ThreadMessage, { role: \"assistant\" }>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst parseJSON = (raw: string | null): unknown => {\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return undefined;\n }\n};\n\nconst parseStoredThread = (value: unknown): StoredThreadMetadata | null => {\n if (!isRecord(value) || typeof value.remoteId !== \"string\") return null;\n\n const status = value.status ?? \"regular\";\n if (status !== \"regular\" && status !== \"archived\") return null;\n\n return {\n remoteId: value.remoteId,\n status,\n ...(typeof value.externalId === \"string\"\n ? { externalId: value.externalId }\n : undefined),\n ...(typeof value.title === \"string\" ? { title: value.title } : undefined),\n ...(isRecord(value.custom) ? { custom: value.custom } : undefined),\n };\n};\n\nconst parseDate = (value: unknown): Date | null => {\n if (value instanceof Date && !Number.isNaN(value.getTime())) return value;\n if (typeof value !== \"string\" && typeof value !== \"number\") return null;\n\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n};\n\nconst isMessageRole = (value: unknown): value is ThreadMessage[\"role\"] =>\n value === \"system\" || value === \"user\" || value === \"assistant\";\n\nconst parseStoredThreadMessage = (value: unknown): ThreadMessage | null => {\n if (!isRecord(value) || typeof value.id !== \"string\") return null;\n if (!isMessageRole(value.role)) return null;\n if (!Array.isArray(value.content)) return null;\n\n const createdAt = parseDate(value.createdAt);\n if (!createdAt) return null;\n\n const metadata = value.metadata;\n if (!isRecord(metadata) || !isRecord(metadata.custom)) return null;\n\n if (value.role === \"assistant\") {\n const status = value.status;\n if (!isRecord(status) || typeof status.type !== \"string\") return null;\n\n const submittedFeedback = isRecord(metadata.submittedFeedback)\n ? metadata.submittedFeedback\n : undefined;\n const submittedFeedbackType = submittedFeedback?.type;\n\n return {\n id: value.id,\n role: \"assistant\",\n content: value.content as StoredAssistantMessage[\"content\"],\n status: status as StoredAssistantMessage[\"status\"],\n createdAt,\n metadata: {\n unstable_state: (metadata.unstable_state ??\n null) as StoredAssistantMessage[\"metadata\"][\"unstable_state\"],\n unstable_annotations: Array.isArray(metadata.unstable_annotations)\n ? (metadata.unstable_annotations as StoredAssistantMessage[\"metadata\"][\"unstable_annotations\"])\n : [],\n unstable_data: Array.isArray(metadata.unstable_data)\n ? (metadata.unstable_data as StoredAssistantMessage[\"metadata\"][\"unstable_data\"])\n : [],\n steps: Array.isArray(metadata.steps)\n ? (metadata.steps as StoredAssistantMessage[\"metadata\"][\"steps\"])\n : [],\n ...(submittedFeedbackType === \"positive\" ||\n submittedFeedbackType === \"negative\"\n ? {\n submittedFeedback: {\n type: submittedFeedbackType,\n },\n }\n : undefined),\n ...(metadata.timing !== undefined\n ? {\n timing: metadata.timing as NonNullable<\n StoredAssistantMessage[\"metadata\"][\"timing\"]\n >,\n }\n : undefined),\n ...(metadata.isOptimistic === true\n ? { isOptimistic: true }\n : undefined),\n custom: metadata.custom,\n },\n };\n }\n\n if (value.role === \"user\") {\n return {\n id: value.id,\n role: \"user\",\n content: value.content as StoredUserMessage[\"content\"],\n attachments: Array.isArray(value.attachments)\n ? (value.attachments as StoredUserMessage[\"attachments\"])\n : [],\n createdAt,\n metadata: {\n custom: metadata.custom,\n },\n };\n }\n\n if (value.content.length !== 1) return null;\n\n return {\n id: value.id,\n role: \"system\",\n content: [value.content[0] as StoredSystemMessage[\"content\"][0]],\n createdAt,\n metadata: {\n custom: metadata.custom,\n },\n };\n};\n\nexport const parseStoredThreadMetadata = (\n raw: string | null,\n): StoredThreadMetadata[] => {\n const parsed = parseJSON(raw);\n if (!Array.isArray(parsed)) return [];\n\n return parsed.flatMap((item) => {\n const thread = parseStoredThread(item);\n return thread ? [thread] : [];\n });\n};\n\nconst parseStoredMessageRepositoryItem = (\n value: unknown,\n): ExportedMessageRepositoryItem | null => {\n if (!isRecord(value)) return null;\n\n const message = parseStoredThreadMessage(value.message);\n if (!message) return null;\n\n const parentId = value.parentId;\n if (\n parentId !== undefined &&\n parentId !== null &&\n typeof parentId !== \"string\"\n ) {\n return null;\n }\n\n return {\n message,\n parentId: parentId ?? null,\n ...(isRecord(value.runConfig)\n ? { runConfig: value.runConfig as RunConfig }\n : undefined),\n };\n};\n\nexport const parseStoredMessageRepository = (\n raw: string | null,\n): ExportedMessageRepository => {\n const parsed = parseJSON(raw);\n if (!isRecord(parsed) || !Array.isArray(parsed.messages)) {\n return { messages: [] };\n }\n\n const candidateMessages = parsed.messages.flatMap((item) => {\n const parsedItem = parseStoredMessageRepositoryItem(item);\n return parsedItem ? [parsedItem] : [];\n });\n\n const acceptedIds = new Set<string>();\n const messages = candidateMessages.flatMap((item) => {\n if (acceptedIds.has(item.message.id)) return [];\n if (item.parentId !== null && !acceptedIds.has(item.parentId)) return [];\n\n acceptedIds.add(item.message.id);\n return [item];\n });\n\n const headId =\n parsed.headId === null ||\n (typeof parsed.headId === \"string\" &&\n messages.some((item) => item.message.id === parsed.headId))\n ? parsed.headId\n : undefined;\n\n return {\n ...(headId !== undefined ? { headId } : undefined),\n messages,\n };\n};\n\nclass AsyncStorageHistoryAdapter implements ThreadHistoryAdapter {\n constructor(\n private storage: AsyncStorageLike,\n private aui: ReturnType<typeof useAui>,\n private prefix: string,\n private mutationQueue: KeyedMutationQueue,\n ) {}\n\n private _messagesKey(remoteId: string) {\n return `${this.prefix}messages:${remoteId}`;\n }\n\n async load(): Promise<ExportedMessageRepository> {\n const remoteId = this.aui.threadListItem().getState().remoteId;\n if (!remoteId) return { messages: [] };\n\n const raw = await this.storage.getItem(this._messagesKey(remoteId));\n return parseStoredMessageRepository(raw);\n }\n\n async append(item: ExportedMessageRepositoryItem): Promise<void> {\n const { remoteId } = await this.aui.threadListItem().initialize();\n\n const key = this._messagesKey(remoteId);\n await this.mutationQueue.run(key, async () => {\n const raw = await this.storage.getItem(key);\n const repo = parseStoredMessageRepository(raw);\n\n const idx = repo.messages.findIndex(\n (m) => m.message.id === item.message.id,\n );\n if (idx >= 0) {\n repo.messages[idx] = item;\n } else {\n repo.messages.push(item);\n }\n repo.headId = item.message.id;\n\n await this.storage.setItem(key, JSON.stringify(repo));\n });\n }\n}\n\nconst createHistoryProvider = (\n storage: AsyncStorageLike,\n prefix: string,\n mutationQueue: KeyedMutationQueue,\n): FC<PropsWithChildren> => {\n const Provider: FC<PropsWithChildren> = ({ children }) => {\n const aui = useAui();\n const history = useMemo(\n () => new AsyncStorageHistoryAdapter(storage, aui, prefix, mutationQueue),\n [aui],\n );\n const adapters = useMemo(() => ({ history }), [history]);\n\n return (\n <RuntimeAdapterProvider adapters={adapters}>\n {children}\n </RuntimeAdapterProvider>\n );\n };\n return Provider;\n};\n\nexport const createLocalStorageAdapter = (\n options: LocalStorageAdapterOptions,\n): RemoteThreadListAdapter => {\n const { storage, prefix = \"@assistant-ui:\", titleGenerator } = options;\n\n const threadsKey = `${prefix}threads`;\n const messagesKey = (threadId: string) => `${prefix}messages:${threadId}`;\n const mutationQueue = getMutationQueue(storage);\n\n const loadThreadMetadata = async (): Promise<StoredThreadMetadata[]> => {\n const raw = await storage.getItem(threadsKey);\n return parseStoredThreadMetadata(raw);\n };\n\n const saveThreadMetadata = async (\n threads: StoredThreadMetadata[],\n ): Promise<void> => {\n await storage.setItem(threadsKey, JSON.stringify(threads));\n };\n\n const updateThreadMetadata = async (\n remoteId: string,\n update: (thread: StoredThreadMetadata) => void,\n ): Promise<void> => {\n await mutationQueue.run(threadsKey, async () => {\n const threads = await loadThreadMetadata();\n const thread = threads.find((item) => item.remoteId === remoteId);\n if (thread) {\n update(thread);\n await saveThreadMetadata(threads);\n }\n });\n };\n\n const adapter: RemoteThreadListAdapter = {\n unstable_Provider: createHistoryProvider(storage, prefix, mutationQueue),\n\n async list(): Promise<RemoteThreadListResponse> {\n const threads = await loadThreadMetadata();\n return {\n threads: threads.map((t) => ({\n remoteId: t.remoteId,\n externalId: t.externalId,\n status: t.status,\n title: t.title,\n custom: t.custom,\n })),\n };\n },\n\n async initialize(\n threadId: string,\n ): Promise<RemoteThreadInitializeResponse> {\n const remoteId = threadId;\n return mutationQueue.run(threadsKey, async () => {\n const threads = await loadThreadMetadata();\n\n // Only add if not already present\n if (!threads.some((t) => t.remoteId === remoteId)) {\n threads.unshift({\n remoteId,\n status: \"regular\",\n });\n await saveThreadMetadata(threads);\n }\n\n return { remoteId, externalId: undefined };\n });\n },\n\n async rename(remoteId: string, newTitle: string): Promise<void> {\n await updateThreadMetadata(remoteId, (thread) => {\n thread.title = newTitle;\n });\n },\n\n async updateCustom(\n remoteId: string,\n custom: Record<string, unknown> | undefined,\n ): Promise<void> {\n await updateThreadMetadata(remoteId, (thread) => {\n thread.custom = custom;\n });\n },\n\n async archive(remoteId: string): Promise<void> {\n await updateThreadMetadata(remoteId, (thread) => {\n thread.status = \"archived\";\n });\n },\n\n async unarchive(remoteId: string): Promise<void> {\n await updateThreadMetadata(remoteId, (thread) => {\n thread.status = \"regular\";\n });\n },\n\n async delete(remoteId: string): Promise<void> {\n await mutationQueue.run(threadsKey, async () => {\n const threads = await loadThreadMetadata();\n const filtered = threads.filter((t) => t.remoteId !== remoteId);\n await saveThreadMetadata(filtered);\n });\n const key = messagesKey(remoteId);\n await mutationQueue.run(key, () => storage.removeItem(key));\n },\n\n async fetch(threadId: string): Promise<RemoteThreadMetadata> {\n const threads = await loadThreadMetadata();\n const thread = threads.find((t) => t.remoteId === threadId);\n if (!thread)\n throw new Error(\n `Stored thread \"${threadId}\" not found while fetching thread metadata.`,\n );\n return {\n remoteId: thread.remoteId,\n externalId: thread.externalId,\n status: thread.status,\n title: thread.title,\n custom: thread.custom,\n };\n },\n\n async generateTitle(\n remoteId: string,\n messages: readonly ThreadMessage[],\n ): Promise<AssistantStream> {\n if (titleGenerator) {\n const title = await titleGenerator.generateTitle(messages);\n\n // Update the stored title\n await updateThreadMetadata(remoteId, (thread) => {\n thread.title = title;\n });\n\n // Return a stream with a single text part\n return createAssistantStream((controller) => {\n controller.appendText(title);\n });\n }\n\n // No title generator — return empty stream\n return createAssistantStream(() => {});\n },\n };\n\n return adapter;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Interactables.js","names":["useState","useEffect","useCallback","useRef","useMemo","resource","useAssistantClientRef","ClientOutput","attachTransformScopes","Unstable_InteractablesState","Unstable_InteractableRegistration","Unstable_InteractablePersistedState","Unstable_InteractablePersistenceAdapter","Unstable_InteractablesConfig","toJSONSchema","toPartialJSONSchema","ModelContext","buildInteractableModelContext","PartialJSONSchema","findModelKnownState","interactableToolName","PERSISTENCE_DEBOUNCE_MS","RestorePersistedStateOptions","stash","Map","shouldStash","id","shouldApply","def","ToolCallLikePart","type","toolCallId","toolName","MessageLike","role","content","InternalInteractableRegistration","scope","hasInteractableCreateCall","messages","name","some","message","part","p","useInteractablesResource","persistence","state","setState","definitions","clientRef","stateRef","subscribersRef","Set","partialSchemaCacheRef","streamBaselinesRef","targetId","detachedAppStateRef","detachedThreadStateRef","registrationCountsRef","updateToolUIsRef","count","unsubscribe","loadedStateRef","touchedIdsRef","adapterRef","undefined","debounceTimerRef","ReturnType","setTimeout","syncSeqRef","hasPendingLocalChangeRef","flushResolversRef","Array","dirtyIdsRef","setStateAndRef","updater","prev","next","current","exportState","result","Object","entries","runPersistence","adapter","resolve","seq","dirtyIds","clear","payload","fromEntries","map","isPending","error","save","e","size","schedulePersistence","add","clearTimeout","restorePersistedState","saved","options","entry","set","changed","importState","applyLoadedState","has","loadFromAdapter","load","console","warn","setPersistenceAdapter","getCurrentThreadId","client","threadListItem","source","getState","threads","mainThreadId","flush","Promise","push","flushIfPending","setDefState","existing","provider","getModelContext","defs","subscribe","callback","delete","cb","modelContext","register","threadAccessor","thread","threadMessages","process","env","NODE_ENV","get","releaseUpdateToolUI","updateRender","toolsAccessor","tools","setToolUI","standalone","jsonSchema","stateSchema","threadId","detached","loaded","known","description","initialState","remaining","stateById","_","rest","__","restPersistence","unstable_Interactables","scopes","parent"],"sources":["../../../src/react/client/Interactables.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport {\n useAssistantClientRef,\n type ClientOutput,\n attachTransformScopes,\n} from \"@assistant-ui/store\";\nimport type {\n Unstable_InteractablesState,\n Unstable_InteractableRegistration,\n Unstable_InteractablePersistedState,\n Unstable_InteractablePersistenceAdapter,\n Unstable_InteractablesConfig,\n} from \"../types/scopes/interactables\";\nimport { toJSONSchema, toPartialJSONSchema } from \"assistant-stream\";\nimport { ModelContext } from \"../../store\";\nimport {\n buildInteractableModelContext,\n type PartialJSONSchema,\n} from \"./interactable-model-context\";\nimport {\n findModelKnownState,\n interactableToolName,\n} from \"../../model-context/interactable-composer-metadata\";\n\nconst PERSISTENCE_DEBOUNCE_MS = 500;\n\ntype RestorePersistedStateOptions = {\n stash: Map<string, unknown>;\n shouldStash?: (id: string) => boolean;\n shouldApply?: (\n id: string,\n def: Unstable_InteractablesState[\"definitions\"][string],\n ) => boolean;\n};\n\ntype ToolCallLikePart = {\n type?: string;\n toolCallId?: string;\n toolName?: string;\n};\n\ntype MessageLike = {\n role?: string;\n content?: readonly unknown[] | undefined;\n};\n\ntype InternalInteractableRegistration = Unstable_InteractableRegistration & {\n scope?: \"thread\" | undefined;\n};\n\nconst hasInteractableCreateCall = (\n messages: readonly MessageLike[],\n id: string,\n name: string,\n) =>\n messages.some(\n (message) =>\n message.role === \"assistant\" &&\n message.content?.some((part) => {\n if (!part || typeof part !== \"object\") return false;\n const p = part as ToolCallLikePart;\n return (\n p.type === \"tool-call\" && p.toolCallId === id && p.toolName === name\n );\n }),\n );\n\nconst useInteractablesResource = ({\n persistence,\n}: Unstable_InteractablesConfig = {}): ClientOutput<\"unstable_interactables\"> => {\n const [state, setState] = useState<Unstable_InteractablesState>(() => ({\n definitions: {},\n persistence: {},\n }));\n\n const clientRef = useAssistantClientRef();\n\n const stateRef = useRef(state);\n\n const subscribersRef = useRef(new Set<() => void>());\n const partialSchemaCacheRef = useRef(new Map<string, PartialJSONSchema>());\n const streamBaselinesRef = useRef(\n new Map<string, { targetId: string; state: unknown }>(),\n );\n const detachedAppStateRef = useRef(new Map<string, unknown>());\n const detachedThreadStateRef = useRef(\n new Map<string, Map<string, unknown>>(),\n );\n // An instance may be registered from several anchors (its creating tool\n // call plus update_* calls); the definition lives until the last one leaves.\n const registrationCountsRef = useRef(new Map<string, number>());\n // One update-tool UI per interactable name, alive while any registrant\n // that supplied an updateRender is mounted.\n const updateToolUIsRef = useRef(\n new Map<string, { count: number; unsubscribe: () => void }>(),\n );\n // App-scoped state restored via adapter.load(), consumed as components register.\n const loadedStateRef = useRef(new Map<string, unknown>());\n // Ids edited locally this session — a local edit always wins over a slow load.\n const touchedIdsRef = useRef(new Set<string>());\n\n const adapterRef = useRef<\n Unstable_InteractablePersistenceAdapter | undefined\n >(undefined);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n const syncSeqRef = useRef(0);\n const hasPendingLocalChangeRef = useRef(false);\n const flushResolversRef = useRef<Array<() => void>>([]);\n const dirtyIdsRef = useRef(new Set<string>());\n\n const setStateAndRef = useCallback(\n (\n updater: (\n prev: Unstable_InteractablesState,\n ) => Unstable_InteractablesState,\n ) => {\n const next = updater(stateRef.current);\n stateRef.current = next;\n setState(next);\n },\n [],\n );\n\n const exportState = useCallback((): Unstable_InteractablePersistedState => {\n const result: Unstable_InteractablePersistedState = {};\n for (const [id, def] of Object.entries(stateRef.current.definitions)) {\n if (def.scope === \"thread\") continue; // thread items persist via snapshot, not the adapter\n result[id] = { name: def.name, state: def.state };\n }\n return result;\n }, []);\n\n const runPersistence = useCallback(async () => {\n const adapter = adapterRef.current;\n if (!adapter) {\n for (const resolve of flushResolversRef.current) resolve();\n flushResolversRef.current = [];\n return;\n }\n\n const seq = ++syncSeqRef.current;\n const dirtyIds = new Set(dirtyIdsRef.current);\n dirtyIdsRef.current.clear();\n hasPendingLocalChangeRef.current = true;\n\n // Snapshot before any await so unregistered definitions are still included.\n const payload = exportState();\n\n setStateAndRef((prev) => ({\n ...prev,\n persistence: {\n ...prev.persistence,\n ...Object.fromEntries(\n [...dirtyIds].map((id) => [\n id,\n { isPending: true, error: undefined },\n ]),\n ),\n },\n }));\n\n try {\n await adapter.save(payload);\n if (syncSeqRef.current === seq) {\n hasPendingLocalChangeRef.current = false;\n setStateAndRef((prev) => {\n const persistence = { ...prev.persistence };\n for (const id of dirtyIds) delete persistence[id];\n return { ...prev, persistence };\n });\n }\n } catch (e) {\n if (syncSeqRef.current === seq) {\n hasPendingLocalChangeRef.current = false;\n setStateAndRef((prev) => ({\n ...prev,\n persistence: {\n ...prev.persistence,\n ...Object.fromEntries(\n [...dirtyIds].map((id) => [id, { isPending: false, error: e }]),\n ),\n },\n }));\n }\n } finally {\n if (dirtyIdsRef.current.size > 0 && adapterRef.current) {\n runPersistence();\n } else {\n for (const resolve of flushResolversRef.current) resolve();\n flushResolversRef.current = [];\n }\n }\n }, [exportState, setStateAndRef]);\n\n const schedulePersistence = useCallback(\n (id: string) => {\n if (!adapterRef.current) return;\n dirtyIdsRef.current.add(id);\n if (debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n }\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = undefined;\n if (!hasPendingLocalChangeRef.current) {\n runPersistence();\n } else {\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = undefined;\n runPersistence();\n }, PERSISTENCE_DEBOUNCE_MS);\n }\n }, PERSISTENCE_DEBOUNCE_MS);\n },\n [runPersistence],\n );\n\n const restorePersistedState = useCallback(\n (\n saved: Unstable_InteractablePersistedState,\n options: RestorePersistedStateOptions,\n ) => {\n const shouldStash = options.shouldStash ?? (() => true);\n const shouldApply = options.shouldApply ?? (() => true);\n\n for (const [id, entry] of Object.entries(saved)) {\n if (shouldStash(id)) options.stash.set(id, entry.state);\n }\n setStateAndRef((prev) => {\n let changed = false;\n const definitions = { ...prev.definitions };\n for (const [id, entry] of Object.entries(saved)) {\n const def = definitions[id];\n if (!def || !shouldApply(id, def)) continue;\n definitions[id] = { ...def, state: entry.state };\n changed = true;\n }\n if (!changed) return prev;\n return { ...prev, definitions };\n });\n },\n [setStateAndRef],\n );\n\n const importState = useCallback(\n (saved: Unstable_InteractablePersistedState) => {\n restorePersistedState(saved, { stash: detachedAppStateRef.current });\n },\n [restorePersistedState],\n );\n\n // Applies adapter.load() output: a local edit made while the load was in\n // flight wins, and thread-scoped items never restore from the adapter.\n const applyLoadedState = useCallback(\n (saved: Unstable_InteractablePersistedState) => {\n restorePersistedState(saved, {\n stash: loadedStateRef.current,\n shouldStash: (id) => !touchedIdsRef.current.has(id),\n shouldApply: (id, def) =>\n !touchedIdsRef.current.has(id) && def.scope !== \"thread\",\n });\n },\n [restorePersistedState],\n );\n\n const loadFromAdapter = useCallback(\n async (adapter: Unstable_InteractablePersistenceAdapter) => {\n if (!adapter.load) return;\n try {\n const saved = await adapter.load();\n if (!saved || adapterRef.current !== adapter) return;\n applyLoadedState(saved);\n } catch (e) {\n console.warn(\"[Interactables] Persistence load failed.\", e);\n }\n },\n [applyLoadedState],\n );\n\n const setPersistenceAdapter = useCallback(\n (adapter: Unstable_InteractablePersistenceAdapter | undefined) => {\n adapterRef.current = adapter;\n if (adapter) void loadFromAdapter(adapter);\n },\n [loadFromAdapter],\n );\n\n const getCurrentThreadId = useCallback((): string | undefined => {\n const client = clientRef.current;\n if (!client) return undefined;\n\n const threadListItem = client.threadListItem;\n if (threadListItem.source != null) {\n return threadListItem().getState().id;\n }\n\n const threads = client.threads;\n if (threads.source != null) {\n return threads().getState().mainThreadId;\n }\n\n return undefined;\n }, [clientRef]);\n\n useEffect(() => {\n if (!persistence) return;\n setPersistenceAdapter(persistence);\n return () => {\n if (adapterRef.current === persistence) {\n adapterRef.current = undefined;\n }\n };\n }, [persistence, setPersistenceAdapter]);\n\n const flush = useCallback(async () => {\n if (debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n }\n if (!adapterRef.current) return;\n if (!hasPendingLocalChangeRef.current && dirtyIdsRef.current.size === 0)\n return;\n const p = new Promise<void>((resolve) => {\n flushResolversRef.current.push(resolve);\n });\n if (!hasPendingLocalChangeRef.current) {\n runPersistence();\n }\n return p;\n }, [runPersistence]);\n\n const flushIfPending = useCallback(() => {\n if (adapterRef.current && debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n runPersistence();\n }\n }, [runPersistence]);\n\n const setDefState = useCallback(\n (id: string, updater: (prev: unknown) => unknown) => {\n touchedIdsRef.current.add(id);\n setStateAndRef((prev) => {\n const existing = prev.definitions[id];\n if (!existing) return prev;\n return {\n ...prev,\n definitions: {\n ...prev.definitions,\n [id]: { ...existing, state: updater(existing.state) },\n },\n };\n });\n if (stateRef.current.definitions[id]?.scope !== \"thread\") {\n schedulePersistence(id);\n }\n },\n [schedulePersistence, setStateAndRef],\n );\n\n const provider = useMemo(\n () => ({\n getModelContext: () => {\n const defs = stateRef.current.definitions;\n return (\n buildInteractableModelContext(\n defs,\n partialSchemaCacheRef.current,\n setDefState,\n streamBaselinesRef.current,\n ) ?? {}\n );\n },\n subscribe: (callback: () => void) => {\n subscribersRef.current.add(callback);\n return () => {\n subscribersRef.current.delete(callback);\n };\n },\n }),\n [setDefState],\n );\n\n useEffect(() => {\n for (const cb of subscribersRef.current) cb();\n }, [state]);\n\n useEffect(() => {\n return clientRef.current!.modelContext().register(provider);\n }, [clientRef, provider]);\n\n const register = useCallback(\n (def: InternalInteractableRegistration) => {\n const threadAccessor = clientRef.current?.thread;\n const threadMessages =\n threadAccessor && threadAccessor.source != null\n ? (threadAccessor().getState().messages ?? [])\n : [];\n const scope =\n def.scope ??\n (hasInteractableCreateCall(threadMessages, def.id, def.name)\n ? \"thread\"\n : \"app\");\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n stateRef.current.definitions[def.id] &&\n scope !== \"thread\"\n ) {\n console.warn(\n `[Interactables] \"${def.name}\" (${def.id}) is already registered. ` +\n `Register an app-scoped interactable once (unstable_useInteractable) and ` +\n `read it from other components with unstable_useInteractableState.`,\n );\n }\n\n registrationCountsRef.current.set(\n def.id,\n (registrationCountsRef.current.get(def.id) ?? 0) + 1,\n );\n\n let releaseUpdateToolUI: (() => void) | undefined;\n if (def.updateRender) {\n const toolsAccessor = clientRef.current?.tools;\n if (toolsAccessor && toolsAccessor.source != null) {\n const toolName = interactableToolName(def.name);\n const existing = updateToolUIsRef.current.get(def.name);\n if (existing) {\n existing.count++;\n } else {\n updateToolUIsRef.current.set(def.name, {\n count: 1,\n unsubscribe: toolsAccessor().setToolUI(\n toolName,\n def.updateRender,\n { standalone: true },\n ),\n });\n }\n releaseUpdateToolUI = () => {\n const entry = updateToolUIsRef.current.get(def.name);\n if (!entry) return;\n if (--entry.count === 0) {\n updateToolUIsRef.current.delete(def.name);\n entry.unsubscribe();\n }\n };\n } else if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[Interactables] \"${def.name}\" supplied an updateRender, but no ` +\n `tools scope is available to install it into.`,\n );\n }\n }\n\n // The same id re-registers once per anchor (its create call + each update_*).\n if (!partialSchemaCacheRef.current.has(def.id)) {\n try {\n const jsonSchema = toJSONSchema(def.stateSchema);\n partialSchemaCacheRef.current.set(\n def.id,\n toPartialJSONSchema(jsonSchema),\n );\n } catch (e) {\n console.warn(\n `[Interactables] Failed to create partial schema for \"${def.name}\". The update tool will accept arbitrary fields without validation.`,\n e,\n );\n }\n }\n\n const threadId = scope === \"thread\" ? getCurrentThreadId() : undefined;\n const detached =\n scope === \"thread\"\n ? threadId\n ? detachedThreadStateRef.current.get(threadId)?.get(def.id)\n : undefined\n : detachedAppStateRef.current.get(def.id);\n if (scope === \"thread\") {\n if (threadId)\n detachedThreadStateRef.current.get(threadId)?.delete(def.id);\n } else {\n detachedAppStateRef.current.delete(def.id);\n }\n const loaded =\n scope === \"thread\" ? undefined : loadedStateRef.current.get(def.id);\n\n // Tool-created items restore from what the model already knows in this\n // thread (the creating call's args, sent snapshots, and the model's own\n // update_* calls) on a fresh reload; detached (in-session remount) still\n // wins so an unsent edit survives a scroll/virtualization cycle.\n const known =\n scope === \"thread\"\n ? findModelKnownState(threadMessages, def.id, def.name)\n : undefined;\n\n setStateAndRef((prev) => ({\n ...prev,\n definitions: {\n ...prev.definitions,\n [def.id]: {\n id: def.id,\n name: def.name,\n description: def.description,\n stateSchema: def.stateSchema,\n initialState: def.initialState,\n scope,\n state:\n prev.definitions[def.id]?.state ??\n detached ??\n known?.state ??\n loaded ??\n def.initialState,\n },\n },\n }));\n\n return () => {\n releaseUpdateToolUI?.();\n\n const remaining = (registrationCountsRef.current.get(def.id) ?? 1) - 1;\n if (remaining > 0) {\n registrationCountsRef.current.set(def.id, remaining);\n return;\n }\n registrationCountsRef.current.delete(def.id);\n\n flushIfPending();\n setStateAndRef((prev) => {\n const existing = prev.definitions[def.id];\n if (existing) {\n if (existing.scope === \"thread\") {\n const threadId = getCurrentThreadId();\n if (threadId) {\n let stateById = detachedThreadStateRef.current.get(threadId);\n if (!stateById) {\n stateById = new Map();\n detachedThreadStateRef.current.set(threadId, stateById);\n }\n stateById.set(def.id, existing.state);\n }\n } else {\n detachedAppStateRef.current.set(def.id, existing.state);\n }\n }\n partialSchemaCacheRef.current.delete(def.id);\n const { [def.id]: _, ...rest } = prev.definitions;\n const { [def.id]: __, ...restPersistence } = prev.persistence;\n return { ...prev, definitions: rest, persistence: restPersistence };\n });\n };\n },\n [flushIfPending, clientRef, getCurrentThreadId, setStateAndRef],\n );\n\n return {\n getState: () => stateRef.current,\n register,\n setState: setDefState,\n exportState,\n importState,\n setPersistenceAdapter,\n flush,\n };\n};\n\n/**\n * Registers the unstable interactables store scope.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport const unstable_Interactables = resource(useInteractablesResource);\n\nattachTransformScopes(useInteractablesResource, (scopes, parent) => {\n if (!scopes.modelContext && parent.modelContext.source === null) {\n scopes.modelContext = ModelContext();\n }\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"Interactables.js","names":["useState","useEffect","useCallback","useRef","useMemo","resource","useAssistantClientRef","ClientOutput","attachTransformScopes","Unstable_InteractablesState","Unstable_InteractableRegistration","Unstable_InteractablePersistedState","Unstable_InteractablePersistenceAdapter","Unstable_InteractablesConfig","toJSONSchema","toPartialJSONSchema","ModelContext","buildInteractableModelContext","PartialJSONSchema","findModelKnownState","interactableToolName","PERSISTENCE_DEBOUNCE_MS","RestorePersistedStateOptions","stash","Map","shouldStash","id","shouldApply","def","ToolCallLikePart","type","toolCallId","toolName","MessageLike","role","content","InternalInteractableRegistration","scope","hasInteractableCreateCall","messages","name","some","message","part","p","useInteractablesResource","persistence","state","setState","definitions","clientRef","stateRef","subscribersRef","Set","partialSchemaCacheRef","streamBaselinesRef","targetId","detachedAppStateRef","detachedThreadStateRef","registrationCountsRef","updateToolUIsRef","count","unsubscribe","loadedStateRef","touchedIdsRef","adapterRef","undefined","debounceTimerRef","ReturnType","setTimeout","syncSeqRef","hasPendingLocalChangeRef","flushResolversRef","Array","dirtyIdsRef","setStateAndRef","updater","prev","next","current","exportState","result","Object","entries","runPersistence","adapter","resolve","seq","dirtyIds","clear","payload","fromEntries","map","isPending","error","save","e","size","schedulePersistence","add","clearTimeout","restorePersistedState","saved","options","entry","set","changed","importState","applyLoadedState","has","loadFromAdapter","load","console","warn","setPersistenceAdapter","getCurrentThreadId","client","threadListItem","source","getState","threads","mainThreadId","flush","Promise","push","flushIfPending","setDefState","existing","provider","getModelContext","defs","subscribe","callback","delete","cb","modelContext","register","threadAccessor","thread","threadMessages","process","env","NODE_ENV","get","releaseUpdateToolUI","updateRender","toolsAccessor","tools","setToolUI","standalone","jsonSchema","stateSchema","threadId","detached","loaded","known","description","initialState","remaining","stateById","_","rest","__","restPersistence","unstable_Interactables","scopes","parent"],"sources":["../../../src/react/client/Interactables.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport {\n useAssistantClientRef,\n type ClientOutput,\n attachTransformScopes,\n} from \"@assistant-ui/store\";\nimport type {\n Unstable_InteractablesState,\n Unstable_InteractableRegistration,\n Unstable_InteractablePersistedState,\n Unstable_InteractablePersistenceAdapter,\n Unstable_InteractablesConfig,\n} from \"../types/scopes/interactables\";\nimport { toJSONSchema, toPartialJSONSchema } from \"assistant-stream\";\nimport { ModelContext } from \"../../store\";\nimport {\n buildInteractableModelContext,\n type PartialJSONSchema,\n} from \"./interactable-model-context\";\nimport {\n findModelKnownState,\n interactableToolName,\n} from \"../../model-context/interactable-composer-metadata\";\n\nconst PERSISTENCE_DEBOUNCE_MS = 500;\n\ntype RestorePersistedStateOptions = {\n stash: Map<string, unknown>;\n shouldStash?: (id: string) => boolean;\n shouldApply?: (\n id: string,\n def: Unstable_InteractablesState[\"definitions\"][string],\n ) => boolean;\n};\n\ntype ToolCallLikePart = {\n type?: string;\n toolCallId?: string;\n toolName?: string;\n};\n\ntype MessageLike = {\n role?: string;\n content?: readonly unknown[] | undefined;\n};\n\ntype InternalInteractableRegistration = Unstable_InteractableRegistration & {\n scope?: \"thread\" | undefined;\n};\n\nconst hasInteractableCreateCall = (\n messages: readonly MessageLike[],\n id: string,\n name: string,\n) =>\n messages.some(\n (message) =>\n message.role === \"assistant\" &&\n message.content?.some((part) => {\n if (!part || typeof part !== \"object\") return false;\n const p = part as ToolCallLikePart;\n return (\n p.type === \"tool-call\" && p.toolCallId === id && p.toolName === name\n );\n }),\n );\n\nconst useInteractablesResource = ({\n persistence,\n}: Unstable_InteractablesConfig = {}): ClientOutput<\"unstable_interactables\"> => {\n const [state, setState] = useState<Unstable_InteractablesState>(() => ({\n definitions: {},\n persistence: {},\n }));\n\n const clientRef = useAssistantClientRef();\n\n const stateRef = useRef(state);\n\n const subscribersRef = useRef(new Set<() => void>());\n const partialSchemaCacheRef = useRef(new Map<string, PartialJSONSchema>());\n const streamBaselinesRef = useRef(\n new Map<string, { targetId: string; state: unknown }>(),\n );\n const detachedAppStateRef = useRef(new Map<string, unknown>());\n const detachedThreadStateRef = useRef(\n new Map<string, Map<string, unknown>>(),\n );\n // An instance may be registered from several anchors (its creating tool\n // call plus update_* calls); the definition lives until the last one leaves.\n const registrationCountsRef = useRef(new Map<string, number>());\n // One update-tool UI per interactable name, alive while any registrant\n // that supplied an updateRender is mounted.\n const updateToolUIsRef = useRef(\n new Map<string, { count: number; unsubscribe: () => void }>(),\n );\n // App-scoped state restored via adapter.load(), consumed as components register.\n const loadedStateRef = useRef(new Map<string, unknown>());\n // Ids edited locally this session — a local edit always wins over a slow load.\n const touchedIdsRef = useRef(new Set<string>());\n\n const adapterRef = useRef<\n Unstable_InteractablePersistenceAdapter | undefined\n >(undefined);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n const syncSeqRef = useRef(0);\n const hasPendingLocalChangeRef = useRef(false);\n const flushResolversRef = useRef<Array<() => void>>([]);\n const dirtyIdsRef = useRef(new Set<string>());\n\n const setStateAndRef = useCallback(\n (\n updater: (\n prev: Unstable_InteractablesState,\n ) => Unstable_InteractablesState,\n ) => {\n const next = updater(stateRef.current);\n stateRef.current = next;\n setState(next);\n },\n [],\n );\n\n const exportState = useCallback((): Unstable_InteractablePersistedState => {\n const result: Unstable_InteractablePersistedState = {};\n for (const [id, def] of Object.entries(stateRef.current.definitions)) {\n if (def.scope === \"thread\") continue; // thread items persist via snapshot, not the adapter\n result[id] = { name: def.name, state: def.state };\n }\n return result;\n }, []);\n\n const runPersistence = useCallback(async () => {\n const adapter = adapterRef.current;\n if (!adapter) {\n for (const resolve of flushResolversRef.current) resolve();\n flushResolversRef.current = [];\n return;\n }\n\n const seq = ++syncSeqRef.current;\n const dirtyIds = new Set(dirtyIdsRef.current);\n dirtyIdsRef.current.clear();\n hasPendingLocalChangeRef.current = true;\n\n // Snapshot before any await so unregistered definitions are still included.\n const payload = exportState();\n\n setStateAndRef((prev) => ({\n ...prev,\n persistence: {\n ...prev.persistence,\n ...Object.fromEntries(\n [...dirtyIds].map((id) => [\n id,\n { isPending: true, error: undefined },\n ]),\n ),\n },\n }));\n\n try {\n await adapter.save(payload);\n if (syncSeqRef.current === seq) {\n hasPendingLocalChangeRef.current = false;\n setStateAndRef((prev) => {\n const persistence = { ...prev.persistence };\n for (const id of dirtyIds) delete persistence[id];\n return { ...prev, persistence };\n });\n }\n } catch (e) {\n if (syncSeqRef.current === seq) {\n hasPendingLocalChangeRef.current = false;\n setStateAndRef((prev) => ({\n ...prev,\n persistence: {\n ...prev.persistence,\n ...Object.fromEntries(\n [...dirtyIds].map((id) => [id, { isPending: false, error: e }]),\n ),\n },\n }));\n }\n } finally {\n if (dirtyIdsRef.current.size > 0 && adapterRef.current) {\n runPersistence();\n } else {\n for (const resolve of flushResolversRef.current) resolve();\n flushResolversRef.current = [];\n }\n }\n }, [exportState, setStateAndRef]);\n\n const schedulePersistence = useCallback(\n (id: string) => {\n if (!adapterRef.current) return;\n dirtyIdsRef.current.add(id);\n if (debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n }\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = undefined;\n if (!hasPendingLocalChangeRef.current) {\n runPersistence();\n } else {\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = undefined;\n runPersistence();\n }, PERSISTENCE_DEBOUNCE_MS);\n }\n }, PERSISTENCE_DEBOUNCE_MS);\n },\n [runPersistence],\n );\n\n const restorePersistedState = useCallback(\n (\n saved: Unstable_InteractablePersistedState,\n options: RestorePersistedStateOptions,\n ) => {\n const shouldStash = options.shouldStash ?? (() => true);\n const shouldApply = options.shouldApply ?? (() => true);\n\n for (const [id, entry] of Object.entries(saved)) {\n if (shouldStash(id)) options.stash.set(id, entry.state);\n }\n setStateAndRef((prev) => {\n let changed = false;\n const definitions = { ...prev.definitions };\n for (const [id, entry] of Object.entries(saved)) {\n const def = definitions[id];\n if (!def || !shouldApply(id, def)) continue;\n definitions[id] = { ...def, state: entry.state };\n changed = true;\n }\n if (!changed) return prev;\n return { ...prev, definitions };\n });\n },\n [setStateAndRef],\n );\n\n const importState = useCallback(\n (saved: Unstable_InteractablePersistedState) => {\n restorePersistedState(saved, { stash: detachedAppStateRef.current });\n },\n [restorePersistedState],\n );\n\n // Applies adapter.load() output: a local edit made while the load was in\n // flight wins, and thread-scoped items never restore from the adapter.\n const applyLoadedState = useCallback(\n (saved: Unstable_InteractablePersistedState) => {\n restorePersistedState(saved, {\n stash: loadedStateRef.current,\n shouldStash: (id) => !touchedIdsRef.current.has(id),\n shouldApply: (id, def) =>\n !touchedIdsRef.current.has(id) && def.scope !== \"thread\",\n });\n },\n [restorePersistedState],\n );\n\n const loadFromAdapter = useCallback(\n async (adapter: Unstable_InteractablePersistenceAdapter) => {\n if (!adapter.load) return;\n try {\n const saved = await adapter.load();\n if (!saved || adapterRef.current !== adapter) return;\n applyLoadedState(saved);\n } catch (e) {\n console.warn(\"[Interactables] Persistence load failed.\", e);\n }\n },\n [applyLoadedState],\n );\n\n const setPersistenceAdapter = useCallback(\n (adapter: Unstable_InteractablePersistenceAdapter | undefined) => {\n adapterRef.current = adapter;\n if (adapter) void loadFromAdapter(adapter);\n },\n [loadFromAdapter],\n );\n\n const getCurrentThreadId = useCallback((): string | undefined => {\n const client = clientRef.current;\n if (!client) return undefined;\n\n const threadListItem = client.threadListItem;\n if (threadListItem.source != null) {\n return threadListItem().getState().id;\n }\n\n const threads = client.threads;\n if (threads.source != null) {\n return threads().getState().mainThreadId;\n }\n\n return undefined;\n }, [clientRef]);\n\n useEffect(() => {\n if (!persistence) return;\n setPersistenceAdapter(persistence);\n return () => {\n if (adapterRef.current === persistence) {\n adapterRef.current = undefined;\n }\n };\n }, [persistence, setPersistenceAdapter]);\n\n const flush = useCallback(async () => {\n if (debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n }\n if (!adapterRef.current) return;\n if (!hasPendingLocalChangeRef.current && dirtyIdsRef.current.size === 0)\n return;\n const p = new Promise<void>((resolve) => {\n flushResolversRef.current.push(resolve);\n });\n if (!hasPendingLocalChangeRef.current) {\n runPersistence();\n }\n return p;\n }, [runPersistence]);\n\n const flushIfPending = useCallback(() => {\n if (adapterRef.current && debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n runPersistence();\n }\n }, [runPersistence]);\n\n const setDefState = useCallback(\n (id: string, updater: (prev: unknown) => unknown) => {\n touchedIdsRef.current.add(id);\n setStateAndRef((prev) => {\n const existing = prev.definitions[id];\n if (!existing) return prev;\n return {\n ...prev,\n definitions: {\n ...prev.definitions,\n [id]: { ...existing, state: updater(existing.state) },\n },\n };\n });\n if (stateRef.current.definitions[id]?.scope !== \"thread\") {\n schedulePersistence(id);\n }\n },\n [schedulePersistence, setStateAndRef],\n );\n\n const provider = useMemo(\n () => ({\n getModelContext: () => {\n const defs = stateRef.current.definitions;\n return (\n buildInteractableModelContext(\n defs,\n partialSchemaCacheRef.current,\n setDefState,\n streamBaselinesRef.current,\n ) ?? {}\n );\n },\n subscribe: (callback: () => void) => {\n subscribersRef.current.add(callback);\n return () => {\n subscribersRef.current.delete(callback);\n };\n },\n }),\n [setDefState],\n );\n\n useEffect(() => {\n for (const cb of subscribersRef.current) cb();\n }, [state]);\n\n useEffect(() => {\n return clientRef.current!.modelContext().register(provider);\n }, [clientRef, provider]);\n\n const register = useCallback(\n (def: InternalInteractableRegistration) => {\n const threadAccessor = clientRef.current?.thread;\n const threadMessages =\n threadAccessor && threadAccessor.source != null\n ? (threadAccessor().getState().messages ?? [])\n : [];\n const scope =\n def.scope ??\n (hasInteractableCreateCall(threadMessages, def.id, def.name)\n ? \"thread\"\n : \"app\");\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n stateRef.current.definitions[def.id] &&\n scope !== \"thread\"\n ) {\n console.warn(\n `[Interactables] \"${def.name}\" (${def.id}) is already registered. ` +\n `Register an app-scoped interactable once (unstable_useInteractable) and ` +\n `read it from other components with unstable_useInteractableState.`,\n );\n }\n\n registrationCountsRef.current.set(\n def.id,\n (registrationCountsRef.current.get(def.id) ?? 0) + 1,\n );\n\n let releaseUpdateToolUI: (() => void) | undefined;\n if (def.updateRender) {\n const toolsAccessor = clientRef.current?.tools;\n if (toolsAccessor && toolsAccessor.source != null) {\n const toolName = interactableToolName(def.name);\n const existing = updateToolUIsRef.current.get(def.name);\n if (existing) {\n existing.count++;\n } else {\n updateToolUIsRef.current.set(def.name, {\n count: 1,\n unsubscribe: toolsAccessor().setToolUI(\n toolName,\n def.updateRender,\n { standalone: true },\n ),\n });\n }\n releaseUpdateToolUI = () => {\n const entry = updateToolUIsRef.current.get(def.name);\n if (!entry) return;\n if (--entry.count === 0) {\n updateToolUIsRef.current.delete(def.name);\n entry.unsubscribe();\n }\n };\n } else if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[Interactables] \"${def.name}\" supplied an updateRender, but no ` +\n `tools scope is available to install it into.`,\n );\n }\n }\n\n // The same id re-registers once per anchor (its create call + each update_*).\n if (!partialSchemaCacheRef.current.has(def.id)) {\n try {\n const jsonSchema = toJSONSchema(def.stateSchema);\n partialSchemaCacheRef.current.set(\n def.id,\n toPartialJSONSchema(jsonSchema),\n );\n } catch (e) {\n console.warn(\n `[Interactables] Failed to create partial schema for \"${def.name}\". The update tool will accept arbitrary fields without validation.`,\n e,\n );\n }\n }\n\n const threadId = scope === \"thread\" ? getCurrentThreadId() : undefined;\n const detached =\n scope === \"thread\"\n ? threadId\n ? detachedThreadStateRef.current.get(threadId)?.get(def.id)\n : undefined\n : detachedAppStateRef.current.get(def.id);\n if (scope === \"thread\") {\n if (threadId)\n detachedThreadStateRef.current.get(threadId)?.delete(def.id);\n } else {\n detachedAppStateRef.current.delete(def.id);\n }\n const loaded =\n scope === \"thread\" ? undefined : loadedStateRef.current.get(def.id);\n\n // Tool-created items restore from what the model already knows in this\n // thread (the creating call's args, sent snapshots, and the model's own\n // update_* calls) on a fresh reload; detached (in-session remount) still\n // wins so an unsent edit survives a scroll/virtualization cycle.\n const known =\n scope === \"thread\"\n ? findModelKnownState(threadMessages, def.id, def.name)\n : undefined;\n\n setStateAndRef((prev) => ({\n ...prev,\n definitions: {\n ...prev.definitions,\n [def.id]: {\n id: def.id,\n name: def.name,\n description: def.description,\n stateSchema: def.stateSchema,\n initialState: def.initialState,\n scope,\n state:\n prev.definitions[def.id]?.state ??\n detached ??\n known?.state ??\n loaded ??\n def.initialState,\n },\n },\n }));\n\n return () => {\n releaseUpdateToolUI?.();\n\n const remaining = (registrationCountsRef.current.get(def.id) ?? 1) - 1;\n if (remaining > 0) {\n registrationCountsRef.current.set(def.id, remaining);\n return;\n }\n registrationCountsRef.current.delete(def.id);\n\n flushIfPending();\n setStateAndRef((prev) => {\n const existing = prev.definitions[def.id];\n if (existing) {\n if (existing.scope === \"thread\") {\n const threadId = getCurrentThreadId();\n if (threadId) {\n let stateById = detachedThreadStateRef.current.get(threadId);\n if (!stateById) {\n stateById = new Map();\n detachedThreadStateRef.current.set(threadId, stateById);\n }\n stateById.set(def.id, existing.state);\n }\n } else {\n detachedAppStateRef.current.set(def.id, existing.state);\n }\n }\n partialSchemaCacheRef.current.delete(def.id);\n const { [def.id]: _, ...rest } = prev.definitions;\n const { [def.id]: __, ...restPersistence } = prev.persistence;\n return { ...prev, definitions: rest, persistence: restPersistence };\n });\n };\n },\n [flushIfPending, clientRef, getCurrentThreadId, setStateAndRef],\n );\n\n return {\n getState: () => stateRef.current,\n register,\n setState: setDefState,\n exportState,\n importState,\n setPersistenceAdapter,\n flush,\n };\n};\n\n/**\n * Registers the unstable interactables store scope.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport const unstable_Interactables = resource(useInteractablesResource);\n\nattachTransformScopes(useInteractablesResource, (scopes, parent) => {\n if (!scopes.modelContext && parent.modelContext.source === null) {\n scopes.modelContext = ModelContext();\n }\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tools.d.ts","names":[],"sources":["../../../src/react/client/Tools.ts"],"mappings":";;;;;cA6Ja,mCAAK,SAAA;;YAxHN;;WAED,gBAAgB"}
1
+ {"version":3,"file":"Tools.d.ts","names":[],"sources":["../../../src/react/client/Tools.ts"],"mappings":";;;;;cA6Ja,mCAAK,SAAA;;EAxHN,UAAA;;EAED,SAAA,gBAAgB"}
@@ -1 +1 @@
1
- {"version":3,"file":"interactable-model-context.d.ts","names":[],"sources":["../../../src/react/client/interactable-model-context.ts"],"mappings":";;;KAWY,oBAAoB,kBAAkB;iBA2HlC,8BACd,aAAa,eAAe,kCAC5B,oBAAoB,YAAY,oBAChC,cAAc,YAAY,UAAU,oCACpC,kBAAe;;;;EAGX,OAAO,eAAe;EACtB,4BAA4B"}
1
+ {"version":3,"file":"interactable-model-context.d.ts","names":[],"sources":["../../../src/react/client/interactable-model-context.ts"],"mappings":";;;KAWY,oBAAoB,kBAAkB;iBA2HlC,8BACd,aAAa,eAAe,kCAC5B,oBAAoB,YAAY,oBAChC,cAAc,YAAY,UAAU,oCACpC,kBAAe;EAA+B;EAAe;;EAGzD,OAAO,eAAe;EACtB,4BAA4B"}
@@ -1 +1 @@
1
- {"version":3,"file":"useInteractable.js","names":["useEffect","useId","useMemo","useRef","useAui","useAuiState","Unstable_InteractableStateSchema","ToolCallMessagePartComponent","unstable_getInteractableVersions","getInteractableVersions","interactableToolName","unstable_useInteractableState","useInteractableState","useJSONEqual","Unstable_InferInteractableState","TSchema","types","output","TOutput","Unstable_InteractableVersionInfo","state","TState","isLatest","restore","Unstable_InteractableConfig","description","stateSchema","initialState","id","updateRender","useInteractable","name","config","version","setState","updater","prev","isPending","error","flush","Promise","aui","autoId","replace","inPart","part","source","updateToolName","s","undefined","p","type","inferredId","toolName","result","Record","args","success","internalScope","stateSchemaRef","current","initialStateRef","interactables","unstable_interactables","register","scope","Parameters","myToolCallId","toolCallId","registeredState","methods","versionValue","versions","thread","messages","some","v","origin","mine","find","latestToolCallId","findLast","const","unstable_useInteractable"],"sources":["../../../src/react/model-context/useInteractable.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useMemo, useRef } from \"react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type { Unstable_InteractableStateSchema } from \"../types/scopes/interactables\";\nimport type { ToolCallMessagePartComponent } from \"../types/MessagePartComponentTypes\";\nimport {\n unstable_getInteractableVersions as getInteractableVersions,\n interactableToolName,\n} from \"../../model-context/interactable-composer-metadata\";\nimport { unstable_useInteractableState as useInteractableState } from \"./useInteractableState\";\nimport { useJSONEqual } from \"../utils/useJSONEqual\";\n\n/**\n * The state type described by an interactable's `stateSchema`. Resolves the\n * output type of a StandardSchemaV1 schema (e.g. Zod); plain JSON Schema\n * falls back to `unknown`.\n */\nexport type Unstable_InferInteractableState<TSchema> = TSchema extends {\n \"~standard\": { types?: { output: infer TOutput } | undefined };\n}\n ? TOutput\n : unknown;\n\n/**\n * One message's version of an interactable, for components rendered inside\n * tool-call parts. Show `state` to display history; call `restore()` to set\n * the live instance back to it.\n */\nexport type Unstable_InteractableVersionInfo<TState> = {\n /** The interactable's state as it was at this message. */\n state: TState;\n /** Whether this message holds the instance's most recent tool-driven version. */\n isLatest: boolean;\n /** Sets the live state back to this version. */\n restore: () => void;\n};\n\n/**\n * Unstable / Experimental — the interactables API is still evolving and may change in any release.\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport type Unstable_InteractableConfig<\n TSchema extends Unstable_InteractableStateSchema,\n> = {\n description: string;\n stateSchema: TSchema;\n initialState: Unstable_InferInteractableState<TSchema>;\n /** Unique instance ID; required to address this instance when multiple interactables share a name. Auto-generated if omitted. */\n id?: string | undefined;\n /**\n * Component installed as the tool UI for this interactable's `update_{name}`\n * tool calls, so a model edit re-renders the interactable at the message\n * that made it instead of only mutating an earlier one. Prefer\n * `unstable_interactableTool`, which wires this up. Pass a stable component reference;\n * changing identity re-registers the tool UI.\n */\n updateRender?: ToolCallMessagePartComponent | undefined;\n};\n\nconst useInteractable = <TSchema extends Unstable_InteractableStateSchema>(\n name: string,\n config: Unstable_InteractableConfig<TSchema>,\n): readonly [\n Unstable_InferInteractableState<TSchema>,\n {\n id: string;\n /**\n * This message's version of the instance, when rendered inside a\n * tool-created interactable message part; `undefined` elsewhere.\n */\n version:\n | Unstable_InteractableVersionInfo<\n Unstable_InferInteractableState<TSchema>\n >\n | undefined;\n setState: (\n updater:\n | Unstable_InferInteractableState<TSchema>\n | ((\n prev: Unstable_InferInteractableState<TSchema>,\n ) => Unstable_InferInteractableState<TSchema>),\n ) => void;\n isPending: boolean;\n error: unknown;\n flush: () => Promise<void>;\n },\n] => {\n const aui = useAui();\n\n const autoId = useId().replace(/[^a-zA-Z0-9]/g, \"\");\n\n // Whether this component renders inside a message part is fixed for its\n // lifetime, so conditioning the selectors on it is safe.\n const inPart = aui.part.source != null;\n const updateToolName = interactableToolName(name);\n const part = useAuiState((s) => {\n if (!inPart) return undefined;\n const p = s.part;\n return p.type === \"tool-call\" ? p : undefined;\n });\n\n // Inside an update_{name} part, the instance id comes from the call itself:\n // the result's resolved id (covers id-less calls), or the id argument.\n let inferredId: string | undefined;\n if (part?.toolName === updateToolName) {\n const result = part.result as Record<string, unknown> | undefined;\n const args = part.args as Record<string, unknown> | undefined;\n if (result?.success !== false) {\n if (typeof result?.id === \"string\") inferredId = result.id;\n else if (typeof args?.id === \"string\") inferredId = args.id;\n }\n }\n\n const id = config.id ?? inferredId ?? autoId;\n const internalScope =\n part?.toolName === name || part?.toolName === updateToolName\n ? \"thread\"\n : undefined;\n\n const stateSchemaRef = useRef(config.stateSchema);\n stateSchemaRef.current = config.stateSchema;\n const initialStateRef = useRef(config.initialState);\n initialStateRef.current = config.initialState;\n\n const interactables = useAuiState(() => aui.unstable_interactables());\n\n useEffect(() => {\n return interactables.register({\n id,\n name,\n description: config.description,\n stateSchema: stateSchemaRef.current,\n initialState: initialStateRef.current,\n updateRender: config.updateRender,\n ...(internalScope ? { scope: internalScope } : {}),\n } as Parameters<typeof interactables.register>[0] & {\n scope?: \"thread\" | undefined;\n });\n }, [\n interactables,\n id,\n name,\n config.description,\n internalScope,\n config.updateRender,\n ]);\n\n const myToolCallId = part?.toolCallId;\n\n const [registeredState, methods] =\n useInteractableState<Unstable_InferInteractableState<TSchema>>(id);\n const { setState } = methods;\n\n const versionValue = useAuiState(\n useJSONEqual((s) => {\n if (!internalScope || !myToolCallId) return undefined;\n const versions = getInteractableVersions(s.thread.messages, id, name);\n if (!versions.some((v) => v.origin === \"create\" && v.toolCallId === id)) {\n return undefined;\n }\n const mine = versions.find((v) => v.toolCallId === myToolCallId);\n if (!mine) return undefined;\n const latestToolCallId = versions.findLast(\n (v) => v.toolCallId !== undefined,\n )?.toolCallId;\n return { state: mine.state, isLatest: latestToolCallId === myToolCallId };\n }),\n );\n\n const version = useMemo(\n () =>\n versionValue && {\n state: versionValue.state as Unstable_InferInteractableState<TSchema>,\n isLatest: versionValue.isLatest,\n restore: () =>\n setState(\n versionValue.state as Unstable_InferInteractableState<TSchema>,\n ),\n },\n [versionValue, setState],\n );\n\n const state =\n registeredState === undefined ? config.initialState : registeredState;\n\n return [state, { id, version, ...methods }] as const;\n};\n\n/**\n * Registers an interactable with the AI assistant and returns its live state,\n * like `useState` that the model can also read and update.\n *\n * Call this once per place that shows the interactable. Other components can\n * read and write the same instance by passing its `id` to\n * `unstable_useInteractableState`.\n *\n * For tool-created interactables rendered inside tool-call message parts,\n * `version` carries this message's version of the instance — its state as of\n * that point in the conversation, whether it is the most recent tool-driven\n * version, and a `restore()` back to it. Whether older messages render frozen history or stay\n * live-editable is the component's choice. Inside an `update_{name}` part the\n * instance `id` is inferred from the call, so the same component works at the\n * creating call and at update calls.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport const unstable_useInteractable: <\n TSchema extends Unstable_InteractableStateSchema,\n>(\n name: string,\n config: Unstable_InteractableConfig<TSchema>,\n) => readonly [\n Unstable_InferInteractableState<TSchema>,\n {\n id: string;\n version:\n | Unstable_InteractableVersionInfo<\n Unstable_InferInteractableState<TSchema>\n >\n | undefined;\n setState: (\n updater:\n | Unstable_InferInteractableState<TSchema>\n | ((\n prev: Unstable_InferInteractableState<TSchema>,\n ) => Unstable_InferInteractableState<TSchema>),\n ) => void;\n isPending: boolean;\n error: unknown;\n flush: () => Promise<void>;\n },\n] = useInteractable;\n"],"mappings":";;;;;;;AA4DA,MAAM8B,mBACJC,MACAC,WAyBG;CACH,MAAMS,MAAMrC,OAAO;CAEnB,MAAMsC,SAASzC,MAAM,CAAC,CAAC0C,QAAQ,iBAAiB,EAAE;CAIlD,MAAMC,SAASH,IAAII,KAAKC,UAAU;CAClC,MAAMC,iBAAiBrC,qBAAqBqB,IAAI;CAChD,MAAMc,OAAOxC,aAAa2C,MAAM;EAC9B,IAAI,CAACJ,QAAQ,OAAOK,KAAAA;EACpB,MAAMC,IAAIF,EAAEH;EACZ,OAAOK,EAAEC,SAAS,cAAcD,IAAID,KAAAA;CACtC,CAAC;CAID,IAAIG;CACJ,IAAIP,MAAMQ,aAAaN,gBAAgB;EACrC,MAAMO,SAAST,KAAKS;EACpB,MAAME,OAAOX,KAAKW;EAClB,IAAIF,QAAQG,YAAY;OAClB,OAAOH,QAAQ1B,OAAO,UAAUwB,aAAaE,OAAO1B;QACnD,IAAI,OAAO4B,MAAM5B,OAAO,UAAUwB,aAAaI,KAAK5B;EAAAA;CAE7D;CAEA,MAAMA,KAAKI,OAAOJ,MAAMwB,cAAcV;CACtC,MAAMgB,gBACJb,MAAMQ,aAAatB,QAAQc,MAAMQ,aAAaN,iBAC1C,WACAE,KAAAA;CAEN,MAAMU,iBAAiBxD,OAAO6B,OAAON,WAAW;CAChDiC,eAAeC,UAAU5B,OAAON;CAChC,MAAMmC,kBAAkB1D,OAAO6B,OAAOL,YAAY;CAClDkC,gBAAgBD,UAAU5B,OAAOL;CAEjC,MAAMmC,gBAAgBzD,kBAAkBoC,IAAIsB,uBAAuB,CAAC;CAEpE/D,gBAAgB;EACd,OAAO8D,cAAcE,SAAS;GAC5BpC;GACAG;GACAN,aAAaO,OAAOP;GACpBC,aAAaiC,eAAeC;GAC5BjC,cAAckC,gBAAgBD;GAC9B/B,cAAcG,OAAOH;GACrB,GAAI6B,gBAAgB,EAAEO,OAAOP,cAAc,IAAI,CAAC;EAClD,CAEC;CACH,GAAG;EACDI;EACAlC;EACAG;EACAC,OAAOP;EACPiC;EACA1B,OAAOH;CAAY,CACpB;CAED,MAAMsC,eAAetB,MAAMuB;CAE3B,MAAM,CAACC,iBAAiBC,WACtB1D,8BAA+DgB,EAAE;CACnE,MAAM,EAAEM,aAAaoC;CAErB,MAAMC,eAAelE,YACnBQ,cAAcmC,QAAM;EAClB,IAAI,CAACU,iBAAiB,CAACS,cAAc,OAAOlB,KAAAA;EAC5C,MAAMuB,WAAW/D,iCAAwBuC,IAAEyB,OAAOC,UAAU9C,IAAIG,IAAI;EACpE,IAAI,CAACyC,SAASG,MAAMC,MAAMA,EAAEC,WAAW,YAAYD,EAAER,eAAexC,EAAE,GACpE;EAEF,MAAMkD,OAAON,SAASO,MAAMH,QAAMA,IAAER,eAAeD,YAAY;EAC/D,IAAI,CAACW,MAAM,OAAO7B,KAAAA;EAClB,MAAM+B,mBAAmBR,SAASS,UAC/BL,QAAMA,IAAER,eAAenB,KAAAA,CAC1B,CAAC,EAAEmB;EACH,OAAO;GAAEhD,OAAO0D,KAAK1D;GAAOE,UAAU0D,qBAAqBb;EAAa;CAC1E,CAAC,CACH;CAEA,MAAMlC,UAAU/B,cAEZqE,gBAAgB;EACdnD,OAAOmD,aAAanD;EACpBE,UAAUiD,aAAajD;EACvBC,eACEW,SACEqC,aAAanD,KACf;CACJ,GACF,CAACmD,cAAcrC,QAAQ,CACzB;CAKA,OAAO,CAFLmC,oBAAoBpB,KAAAA,IAAYjB,OAAOL,eAAe0C,iBAEzC;EAAEzC;EAAIK;EAAS,GAAGqC;CAAQ,CAAC;AAC5C;;;;;;;;;;;;;;;;;;;AAoBA,MAAaa,2BAyBTrD"}
1
+ {"version":3,"file":"useInteractable.js","names":["useEffect","useId","useMemo","useRef","useAui","useAuiState","Unstable_InteractableStateSchema","ToolCallMessagePartComponent","unstable_getInteractableVersions","getInteractableVersions","interactableToolName","unstable_useInteractableState","useInteractableState","useJSONEqual","Unstable_InferInteractableState","TSchema","types","output","TOutput","Unstable_InteractableVersionInfo","state","TState","isLatest","restore","Unstable_InteractableConfig","description","stateSchema","initialState","id","updateRender","useInteractable","name","config","version","setState","updater","prev","isPending","error","flush","Promise","aui","autoId","replace","inPart","part","source","updateToolName","s","undefined","p","type","inferredId","toolName","result","Record","args","success","internalScope","stateSchemaRef","current","initialStateRef","interactables","unstable_interactables","register","scope","Parameters","myToolCallId","toolCallId","registeredState","methods","versionValue","versions","thread","messages","some","v","origin","mine","find","latestToolCallId","findLast","const","unstable_useInteractable"],"sources":["../../../src/react/model-context/useInteractable.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useMemo, useRef } from \"react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type { Unstable_InteractableStateSchema } from \"../types/scopes/interactables\";\nimport type { ToolCallMessagePartComponent } from \"../types/MessagePartComponentTypes\";\nimport {\n unstable_getInteractableVersions as getInteractableVersions,\n interactableToolName,\n} from \"../../model-context/interactable-composer-metadata\";\nimport { unstable_useInteractableState as useInteractableState } from \"./useInteractableState\";\nimport { useJSONEqual } from \"../utils/useJSONEqual\";\n\n/**\n * The state type described by an interactable's `stateSchema`. Resolves the\n * output type of a StandardSchemaV1 schema (e.g. Zod); plain JSON Schema\n * falls back to `unknown`.\n */\nexport type Unstable_InferInteractableState<TSchema> = TSchema extends {\n \"~standard\": { types?: { output: infer TOutput } | undefined };\n}\n ? TOutput\n : unknown;\n\n/**\n * One message's version of an interactable, for components rendered inside\n * tool-call parts. Show `state` to display history; call `restore()` to set\n * the live instance back to it.\n */\nexport type Unstable_InteractableVersionInfo<TState> = {\n /** The interactable's state as it was at this message. */\n state: TState;\n /** Whether this message holds the instance's most recent tool-driven version. */\n isLatest: boolean;\n /** Sets the live state back to this version. */\n restore: () => void;\n};\n\n/**\n * Unstable / Experimental — the interactables API is still evolving and may change in any release.\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport type Unstable_InteractableConfig<\n TSchema extends Unstable_InteractableStateSchema,\n> = {\n description: string;\n stateSchema: TSchema;\n initialState: Unstable_InferInteractableState<TSchema>;\n /** Unique instance ID; required to address this instance when multiple interactables share a name. Auto-generated if omitted. */\n id?: string | undefined;\n /**\n * Component installed as the tool UI for this interactable's `update_{name}`\n * tool calls, so a model edit re-renders the interactable at the message\n * that made it instead of only mutating an earlier one. Prefer\n * `unstable_interactableTool`, which wires this up. Pass a stable component reference;\n * changing identity re-registers the tool UI.\n */\n updateRender?: ToolCallMessagePartComponent | undefined;\n};\n\nconst useInteractable = <TSchema extends Unstable_InteractableStateSchema>(\n name: string,\n config: Unstable_InteractableConfig<TSchema>,\n): readonly [\n Unstable_InferInteractableState<TSchema>,\n {\n id: string;\n /**\n * This message's version of the instance, when rendered inside a\n * tool-created interactable message part; `undefined` elsewhere.\n */\n version:\n | Unstable_InteractableVersionInfo<\n Unstable_InferInteractableState<TSchema>\n >\n | undefined;\n setState: (\n updater:\n | Unstable_InferInteractableState<TSchema>\n | ((\n prev: Unstable_InferInteractableState<TSchema>,\n ) => Unstable_InferInteractableState<TSchema>),\n ) => void;\n isPending: boolean;\n error: unknown;\n flush: () => Promise<void>;\n },\n] => {\n const aui = useAui();\n\n const autoId = useId().replace(/[^a-zA-Z0-9]/g, \"\");\n\n // Whether this component renders inside a message part is fixed for its\n // lifetime, so conditioning the selectors on it is safe.\n const inPart = aui.part.source != null;\n const updateToolName = interactableToolName(name);\n const part = useAuiState((s) => {\n if (!inPart) return undefined;\n const p = s.part;\n return p.type === \"tool-call\" ? p : undefined;\n });\n\n // Inside an update_{name} part, the instance id comes from the call itself:\n // the result's resolved id (covers id-less calls), or the id argument.\n let inferredId: string | undefined;\n if (part?.toolName === updateToolName) {\n const result = part.result as Record<string, unknown> | undefined;\n const args = part.args as Record<string, unknown> | undefined;\n if (result?.success !== false) {\n if (typeof result?.id === \"string\") inferredId = result.id;\n else if (typeof args?.id === \"string\") inferredId = args.id;\n }\n }\n\n const id = config.id ?? inferredId ?? autoId;\n const internalScope =\n part?.toolName === name || part?.toolName === updateToolName\n ? \"thread\"\n : undefined;\n\n const stateSchemaRef = useRef(config.stateSchema);\n stateSchemaRef.current = config.stateSchema;\n const initialStateRef = useRef(config.initialState);\n initialStateRef.current = config.initialState;\n\n const interactables = useAuiState(() => aui.unstable_interactables());\n\n useEffect(() => {\n return interactables.register({\n id,\n name,\n description: config.description,\n stateSchema: stateSchemaRef.current,\n initialState: initialStateRef.current,\n updateRender: config.updateRender,\n ...(internalScope ? { scope: internalScope } : {}),\n } as Parameters<typeof interactables.register>[0] & {\n scope?: \"thread\" | undefined;\n });\n }, [\n interactables,\n id,\n name,\n config.description,\n internalScope,\n config.updateRender,\n ]);\n\n const myToolCallId = part?.toolCallId;\n\n const [registeredState, methods] =\n useInteractableState<Unstable_InferInteractableState<TSchema>>(id);\n const { setState } = methods;\n\n const versionValue = useAuiState(\n useJSONEqual((s) => {\n if (!internalScope || !myToolCallId) return undefined;\n const versions = getInteractableVersions(s.thread.messages, id, name);\n if (!versions.some((v) => v.origin === \"create\" && v.toolCallId === id)) {\n return undefined;\n }\n const mine = versions.find((v) => v.toolCallId === myToolCallId);\n if (!mine) return undefined;\n const latestToolCallId = versions.findLast(\n (v) => v.toolCallId !== undefined,\n )?.toolCallId;\n return { state: mine.state, isLatest: latestToolCallId === myToolCallId };\n }),\n );\n\n const version = useMemo(\n () =>\n versionValue && {\n state: versionValue.state as Unstable_InferInteractableState<TSchema>,\n isLatest: versionValue.isLatest,\n restore: () =>\n setState(\n versionValue.state as Unstable_InferInteractableState<TSchema>,\n ),\n },\n [versionValue, setState],\n );\n\n const state =\n registeredState === undefined ? config.initialState : registeredState;\n\n return [state, { id, version, ...methods }] as const;\n};\n\n/**\n * Registers an interactable with the AI assistant and returns its live state,\n * like `useState` that the model can also read and update.\n *\n * Call this once per place that shows the interactable. Other components can\n * read and write the same instance by passing its `id` to\n * `unstable_useInteractableState`.\n *\n * For tool-created interactables rendered inside tool-call message parts,\n * `version` carries this message's version of the instance — its state as of\n * that point in the conversation, whether it is the most recent tool-driven\n * version, and a `restore()` back to it. Whether older messages render frozen history or stay\n * live-editable is the component's choice. Inside an `update_{name}` part the\n * instance `id` is inferred from the call, so the same component works at the\n * creating call and at update calls.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport const unstable_useInteractable: <\n TSchema extends Unstable_InteractableStateSchema,\n>(\n name: string,\n config: Unstable_InteractableConfig<TSchema>,\n) => readonly [\n Unstable_InferInteractableState<TSchema>,\n {\n id: string;\n version:\n | Unstable_InteractableVersionInfo<\n Unstable_InferInteractableState<TSchema>\n >\n | undefined;\n setState: (\n updater:\n | Unstable_InferInteractableState<TSchema>\n | ((\n prev: Unstable_InferInteractableState<TSchema>,\n ) => Unstable_InferInteractableState<TSchema>),\n ) => void;\n isPending: boolean;\n error: unknown;\n flush: () => Promise<void>;\n },\n] = useInteractable;\n"],"mappings":";;;;;;;AA4DA,MAAM8B,mBACJC,MACAC,WAyBG;CACH,MAAMS,MAAMrC,OAAO;CAEnB,MAAMsC,SAASzC,MAAM,CAAC,CAAC0C,QAAQ,iBAAiB,EAAE;CAIlD,MAAMC,SAASH,IAAII,KAAKC,UAAU;CAClC,MAAMC,iBAAiBrC,qBAAqBqB,IAAI;CAChD,MAAMc,OAAOxC,aAAa2C,MAAM;EAC9B,IAAI,CAACJ,QAAQ,OAAOK,KAAAA;EACpB,MAAMC,IAAIF,EAAEH;EACZ,OAAOK,EAAEC,SAAS,cAAcD,IAAID,KAAAA;CACtC,CAAC;CAID,IAAIG;CACJ,IAAIP,MAAMQ,aAAaN,gBAAgB;EACrC,MAAMO,SAAST,KAAKS;EACpB,MAAME,OAAOX,KAAKW;EAClB,IAAIF,QAAQG,YAAY,OAClB;OAAA,OAAOH,QAAQ1B,OAAO,UAAUwB,aAAaE,OAAO1B;QACnD,IAAI,OAAO4B,MAAM5B,OAAO,UAAUwB,aAAaI,KAAK5B;EAAAA;CAE7D;CAEA,MAAMA,KAAKI,OAAOJ,MAAMwB,cAAcV;CACtC,MAAMgB,gBACJb,MAAMQ,aAAatB,QAAQc,MAAMQ,aAAaN,iBAC1C,WACAE,KAAAA;CAEN,MAAMU,iBAAiBxD,OAAO6B,OAAON,WAAW;CAChDiC,eAAeC,UAAU5B,OAAON;CAChC,MAAMmC,kBAAkB1D,OAAO6B,OAAOL,YAAY;CAClDkC,gBAAgBD,UAAU5B,OAAOL;CAEjC,MAAMmC,gBAAgBzD,kBAAkBoC,IAAIsB,uBAAuB,CAAC;CAEpE/D,gBAAgB;EACd,OAAO8D,cAAcE,SAAS;GAC5BpC;GACAG;GACAN,aAAaO,OAAOP;GACpBC,aAAaiC,eAAeC;GAC5BjC,cAAckC,gBAAgBD;GAC9B/B,cAAcG,OAAOH;GACrB,GAAI6B,gBAAgB,EAAEO,OAAOP,cAAc,IAAI,CAAC;EAClD,CAEC;CACH,GAAG;EACDI;EACAlC;EACAG;EACAC,OAAOP;EACPiC;EACA1B,OAAOH;CAAY,CACpB;CAED,MAAMsC,eAAetB,MAAMuB;CAE3B,MAAM,CAACC,iBAAiBC,WACtB1D,8BAA+DgB,EAAE;CACnE,MAAM,EAAEM,aAAaoC;CAErB,MAAMC,eAAelE,YACnBQ,cAAcmC,QAAM;EAClB,IAAI,CAACU,iBAAiB,CAACS,cAAc,OAAOlB,KAAAA;EAC5C,MAAMuB,WAAW/D,iCAAwBuC,IAAEyB,OAAOC,UAAU9C,IAAIG,IAAI;EACpE,IAAI,CAACyC,SAASG,MAAMC,MAAMA,EAAEC,WAAW,YAAYD,EAAER,eAAexC,EAAE,GACpE;EAEF,MAAMkD,OAAON,SAASO,MAAMH,QAAMA,IAAER,eAAeD,YAAY;EAC/D,IAAI,CAACW,MAAM,OAAO7B,KAAAA;EAClB,MAAM+B,mBAAmBR,SAASS,UAC/BL,QAAMA,IAAER,eAAenB,KAAAA,CAC1B,CAAC,EAAEmB;EACH,OAAO;GAAEhD,OAAO0D,KAAK1D;GAAOE,UAAU0D,qBAAqBb;EAAa;CAC1E,CAAC,CACH;CAEA,MAAMlC,UAAU/B,cAEZqE,gBAAgB;EACdnD,OAAOmD,aAAanD;EACpBE,UAAUiD,aAAajD;EACvBC,eACEW,SACEqC,aAAanD,KACf;CACJ,GACF,CAACmD,cAAcrC,QAAQ,CACzB;CAKA,OAAO,CAFLmC,oBAAoBpB,KAAAA,IAAYjB,OAAOL,eAAe0C,iBAEzC;EAAEzC;EAAIK;EAAS,GAAGqC;CAAQ,CAAC;AAC5C;;;;;;;;;;;;;;;;;;;AAoBA,MAAaa,2BAyBTrD"}
@@ -19,13 +19,13 @@ const useActionBarCopy = (t0) => {
19
19
  let t3;
20
20
  if ($[2] !== aui || $[3] !== composerValue || $[4] !== copiedDuration || $[5] !== copyToClipboard || $[6] !== isEditing) {
21
21
  t3 = () => {
22
+ if (!copyToClipboard) return;
22
23
  const valueToCopy = isEditing ? composerValue : aui.message().getCopyText();
23
24
  if (!valueToCopy) return;
24
- const write = copyToClipboard ?? _temp6;
25
- Promise.resolve(write(valueToCopy)).then(() => {
25
+ Promise.resolve(copyToClipboard(valueToCopy)).then(() => {
26
26
  aui.message().setIsCopied(true);
27
27
  setTimeout(() => aui.message().setIsCopied(false), copiedDuration);
28
- }, _temp7);
28
+ }, _temp6);
29
29
  };
30
30
  $[2] = aui;
31
31
  $[3] = composerValue;
@@ -35,19 +35,20 @@ const useActionBarCopy = (t0) => {
35
35
  $[7] = t3;
36
36
  } else t3 = $[7];
37
37
  const copy = t3;
38
- let t4;
39
- if ($[8] !== copy || $[9] !== disabled || $[10] !== isCopied) {
40
- t4 = {
38
+ const t4 = disabled || !copyToClipboard;
39
+ let t5;
40
+ if ($[8] !== copy || $[9] !== isCopied || $[10] !== t4) {
41
+ t5 = {
41
42
  copy,
42
- disabled,
43
+ disabled: t4,
43
44
  isCopied
44
45
  };
45
46
  $[8] = copy;
46
- $[9] = disabled;
47
- $[10] = isCopied;
48
- $[11] = t4;
49
- } else t4 = $[11];
50
- return t4;
47
+ $[9] = isCopied;
48
+ $[10] = t4;
49
+ $[11] = t5;
50
+ } else t5 = $[11];
51
+ return t5;
51
52
  };
52
53
  function _temp(c) {
53
54
  return c.type === "text" && c.text.length > 0;
@@ -65,7 +66,6 @@ function _temp5(s_2) {
65
66
  return s_2.composer.text;
66
67
  }
67
68
  function _temp6() {}
68
- function _temp7() {}
69
69
  //#endregion
70
70
  export { useActionBarCopy };
71
71