@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
@@ -1 +1 @@
1
- {"version":3,"file":"attachment.d.ts","names":[],"sources":["../../src/adapters/attachment.ts"],"mappings":";;;KAQY;EACV;EACA,IAAI;IACF,MAAM;MACJ,QAAQ,qBAAqB,eAAe;EAChD,OAAO,YAAY,aAAa;EAChC,KAAK,YAAY,oBAAoB,QAAQ;;cAGlC,wCAAwC;EAC5C;EAEM,IAAI;IAAS,MAAM;MAAS,QAAQ;EAWpC,KACX,YAAY,oBACX,QAAQ;EAaE,UAAM;;cA0BR,iBAAwB,MAAM,SAAO;cAarC,uCAAuC;EAC3C;EAGM,IAAI;IAAS,MAAM;MAAS,QAAQ;EAWpC,KACX,YAAY,oBACX,QAAQ;EAaE,UAAM;;iBAiBL,kBACd;EAAQ;EAAc;GACtB;iBAiCc,iBACd,YAAY,sBACZ,YAAY;iBAME,yBACd,MAAM,QAAQ;EAAyB;KACtC;iBA4Ca,iBACd,kBAAkB,0BACjB;cAUU,sCAAsC;UACzC;EAED;cAEK,UAAU;EAgBf,IAAI;IAAS,MAAM;MAAM,QAAA,qBAAA,eAAA;EASnB,KAAK,YAAY,oBAAiB,QAAA;EAUlC,OAAO,YAAY,aAAU"}
1
+ {"version":3,"file":"attachment.d.ts","names":[],"sources":["../../src/adapters/attachment.ts"],"mappings":";;;KAQY;EACV;EACA,IAAI;IACF,MAAM;MACJ,QAAQ,qBAAqB,eAAe;EAChD,OAAO,YAAY,aAAa;EAChC,KAAK,YAAY,oBAAoB,QAAQ;;cAGlC,wCAAwC;EAC5C;EAEM,IAAI;IAAS,MAAM;MAAS,QAAQ;EAWpC,KACX,YAAY,oBACX,QAAQ;EAaE,UAAM;;cA0BR,iBAAwB,MAAM,SAAO;cAarC,uCAAuC;EAC3C;EAGM,IAAI;IAAS,MAAM;MAAS,QAAQ;EAWpC,KACX,YAAY,oBACX,QAAQ;EAaE,UAAM;;iBAiBL,kBACd;EAAQ;EAAc;GACtB;iBAiCc,iBACd,YAAY,sBACZ,YAAY;iBAME,yBACd,MAAM,QAAQ;EAAyB;KACtC;iBA4Ca,iBACd,kBAAkB,0BACjB;cAUU,sCAAsC;UACzC;EAED;EAEK,YAAA,UAAU;EAgBf,IAAI;IAAS,MAAM;MAAM,QAAA,qBAAA,eAAA;EASnB,KAAK,YAAY,oBAAiB,QAAA;EAUlC,OAAO,YAAY,aAAU"}
@@ -1 +1 @@
1
- {"version":3,"file":"speech.d.ts","names":[],"sources":["../../src/adapters/speech.ts"],"mappings":";;kBAEiB;OACH;IAEN;;IAGA;IACA;IACA;;OAGM;IACV,QAAQ;IACR;IACA,YAAY,yBAAyB;;;KAI7B;EACV,QAAQ,iBAAiB,uBAAuB;;kBAGjC;OACH;IAEN;;IAGA;IACA;;OAGM;IACV;IACA;;OAGU;IACV,QAAQ;IACR,YAAY;IACZ;IACA,gBAAgB,yBAAyB;IACzC,cAAc,WAAW,QAAQ,oBAAoB;IACrD,WAAW,WAAW,QAAQ,oBAAoB;;;KAI1C;EACV,cAAc,iBAAiB;EAC/B;;cAGW,qCAAqC;EAChD,MAAM,eAAe,uBAAuB;;UA0EpC,kCAAkC;EAC1C;EACA;EACA;EACA;EACA;EACA;;UAGQ;UACA;;QAGF;YACI;IACR,oBAAoB;IACpB,0BAA0B;;;cAWjB,qCAAqC;UACxC;UACA;UACA;cAGN;IACE;IACA;IACA;;SAYG;EAIP,UAAU,iBAAiB"}
1
+ {"version":3,"file":"speech.d.ts","names":[],"sources":["../../src/adapters/speech.ts"],"mappings":";;kBAEiB;OACH;IAEN;;IAGA;IACA;IACA;;OAGM;IACV,QAAQ;IACR;IACA,YAAY,yBAAyB;;;KAI7B;EACV,QAAQ,iBAAiB,uBAAuB;;kBAkBjC;OACH;IAEN;;IAGA;IACA;;OAGM;IACV;IACA;;OAGU;IACV,QAAQ;IACR,YAAY;IACZ;IACA,gBAAgB,yBAAyB;IACzC,cAAc,WAAW,QAAQ,oBAAoB;IACrD,WAAW,WAAW,QAAQ,oBAAoB;;;KAI1C;EACV,cAAc,iBAAiB;EAC/B;;cAGW,qCAAqC;EAChD,MAAM,eAAe,uBAAuB;;UA0EpC,kCAAkC;EAC1C;EACA;EACA;EACA;EACA;EACA;;UAGQ;UACA;;QAGF;YACI;IACR,oBAAoB;IACpB,0BAA0B;;;cAWjB,qCAAqC;UACxC;UACA;UACA;EAGN,YAAA;IACE;IACA;IACA;;SAYG;EAIP,UAAU,iBAAiB"}
@@ -1,4 +1,11 @@
1
1
  //#region src/adapters/speech.ts
2
+ const notifySpeechSynthesisListeners = (listeners) => {
3
+ for (const listener of listeners) try {
4
+ listener();
5
+ } catch (error) {
6
+ console.error("[assistant-ui] Speech synthesis listener threw an error", error);
7
+ }
8
+ };
2
9
  var WebSpeechSynthesisAdapter = class {
3
10
  speak(text) {
4
11
  const utterance = new SpeechSynthesisUtterance(text);
@@ -10,7 +17,7 @@ var WebSpeechSynthesisAdapter = class {
10
17
  reason,
11
18
  error
12
19
  };
13
- subscribers.forEach((handler) => handler());
20
+ notifySpeechSynthesisListeners(subscribers);
14
21
  };
15
22
  utterance.addEventListener("end", () => handleEnd("finished"));
16
23
  utterance.addEventListener("error", (e) => handleEnd("error", e.error));
@@ -25,7 +32,7 @@ var WebSpeechSynthesisAdapter = class {
25
32
  if (res.status.type === "ended") {
26
33
  let cancelled = false;
27
34
  queueMicrotask(() => {
28
- if (!cancelled) callback();
35
+ if (!cancelled) notifySpeechSynthesisListeners([callback]);
29
36
  });
30
37
  return () => {
31
38
  cancelled = true;
@@ -1 +1 @@
1
- {"version":3,"file":"speech.js","names":["Unsubscribe","SpeechSynthesisAdapter","Status","type","reason","error","Utterance","status","cancel","subscribe","callback","speak","text","DictationAdapter","Result","transcript","isFinal","Session","stop","Promise","onSpeechStart","onSpeechEnd","result","onSpeech","listen","disableInputDuringDictation","WebSpeechSynthesisAdapter","utterance","SpeechSynthesisUtterance","subscribers","Set","handleEnd","res","forEach","handler","addEventListener","e","window","speechSynthesis","cancelled","queueMicrotask","add","delete","SpeechRecognitionResultItem","confidence","SpeechRecognitionResult","length","item","index","SpeechRecognitionResultList","SpeechRecognitionEvent","Event","resultIndex","results","SpeechRecognitionErrorEvent","message","SpeechRecognitionInstance","EventTarget","lang","continuous","interimResults","start","abort","SpeechRecognitionConstructor","global","Window","SpeechRecognition","webkitSpeechRecognition","getSpeechRecognitionAPI","undefined","WebSpeechDictationAdapter","_language","_continuous","_interimResults","constructor","options","language","defaultLanguage","navigator","isSupported","SpeechRecognitionAPI","Error","recognition","speechStartCallbacks","speechEndCallbacks","speechCallbacks","finalTranscript","session","resolve","checkEnded","setTimeout","updateStatus","newStatus","cb","event","speechEvent","i","currentStatus","errorEvent","console"],"sources":["../../src/adapters/speech.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\n\nexport namespace SpeechSynthesisAdapter {\n export type Status =\n | {\n type: \"starting\" | \"running\";\n }\n | {\n type: \"ended\";\n reason: \"finished\" | \"cancelled\" | \"error\";\n error?: unknown;\n };\n\n export type Utterance = {\n status: Status;\n cancel: () => void;\n subscribe: (callback: () => void) => Unsubscribe;\n };\n}\n\nexport type SpeechSynthesisAdapter = {\n speak: (text: string) => SpeechSynthesisAdapter.Utterance;\n};\n\nexport namespace DictationAdapter {\n export type Status =\n | {\n type: \"starting\" | \"running\";\n }\n | {\n type: \"ended\";\n reason: \"stopped\" | \"cancelled\" | \"error\";\n };\n\n export type Result = {\n transcript: string;\n isFinal?: boolean;\n };\n\n export type Session = {\n status: Status;\n stop: () => Promise<void>;\n cancel: () => void;\n onSpeechStart: (callback: () => void) => Unsubscribe;\n onSpeechEnd: (callback: (result: Result) => void) => Unsubscribe;\n onSpeech: (callback: (result: Result) => void) => Unsubscribe;\n };\n}\n\nexport type DictationAdapter = {\n listen: () => DictationAdapter.Session;\n disableInputDuringDictation?: boolean;\n};\n\nexport class WebSpeechSynthesisAdapter implements SpeechSynthesisAdapter {\n speak(text: string): SpeechSynthesisAdapter.Utterance {\n const utterance = new SpeechSynthesisUtterance(text);\n\n const subscribers = new Set<() => void>();\n const handleEnd = (\n reason: \"finished\" | \"error\" | \"cancelled\",\n error?: unknown,\n ) => {\n if (res.status.type === \"ended\") return;\n\n res.status = { type: \"ended\", reason, error };\n subscribers.forEach((handler) => handler());\n };\n\n utterance.addEventListener(\"end\", () => handleEnd(\"finished\"));\n utterance.addEventListener(\"error\", (e) => handleEnd(\"error\", e.error));\n\n window.speechSynthesis.speak(utterance);\n\n const res: SpeechSynthesisAdapter.Utterance = {\n status: { type: \"running\" },\n cancel: () => {\n window.speechSynthesis.cancel();\n handleEnd(\"cancelled\");\n },\n subscribe: (callback) => {\n if (res.status.type === \"ended\") {\n let cancelled = false;\n queueMicrotask(() => {\n if (!cancelled) callback();\n });\n return () => {\n cancelled = true;\n };\n } else {\n subscribers.add(callback);\n return () => {\n subscribers.delete(callback);\n };\n }\n },\n };\n return res;\n }\n}\n\ninterface SpeechRecognitionResultItem {\n transcript: string;\n confidence: number;\n}\n\ninterface SpeechRecognitionResult {\n readonly length: number;\n item(index: number): SpeechRecognitionResultItem;\n readonly isFinal: boolean;\n [index: number]: SpeechRecognitionResultItem;\n}\n\ninterface SpeechRecognitionResultList {\n readonly length: number;\n item(index: number): SpeechRecognitionResult;\n [index: number]: SpeechRecognitionResult;\n}\n\ninterface SpeechRecognitionEvent extends Event {\n readonly resultIndex: number;\n readonly results: SpeechRecognitionResultList;\n}\n\ninterface SpeechRecognitionErrorEvent extends Event {\n readonly error: string;\n readonly message: string;\n}\n\ninterface SpeechRecognitionInstance extends EventTarget {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n start(): void;\n stop(): void;\n abort(): void;\n}\n\ninterface SpeechRecognitionConstructor {\n new (): SpeechRecognitionInstance;\n}\n\ndeclare global {\n interface Window {\n SpeechRecognition?: SpeechRecognitionConstructor;\n webkitSpeechRecognition?: SpeechRecognitionConstructor;\n }\n}\n\nconst getSpeechRecognitionAPI = ():\n | SpeechRecognitionConstructor\n | undefined => {\n if (typeof window === \"undefined\") return undefined;\n return window.SpeechRecognition ?? window.webkitSpeechRecognition;\n};\n\nexport class WebSpeechDictationAdapter implements DictationAdapter {\n private _language: string;\n private _continuous: boolean;\n private _interimResults: boolean;\n\n constructor(\n options: {\n language?: string;\n continuous?: boolean;\n interimResults?: boolean;\n } = {},\n ) {\n const defaultLanguage =\n typeof navigator !== \"undefined\" && navigator.language\n ? navigator.language\n : \"en-US\";\n this._language = options.language ?? defaultLanguage;\n this._continuous = options.continuous ?? true;\n this._interimResults = options.interimResults ?? true;\n }\n\n static isSupported(): boolean {\n return getSpeechRecognitionAPI() !== undefined;\n }\n\n listen(): DictationAdapter.Session {\n const SpeechRecognitionAPI = getSpeechRecognitionAPI();\n if (!SpeechRecognitionAPI) {\n throw new Error(\n \"SpeechRecognition is not supported in this browser. \" +\n \"Try using Chrome, Edge, or Safari.\",\n );\n }\n\n const recognition = new SpeechRecognitionAPI();\n recognition.lang = this._language;\n recognition.continuous = this._continuous;\n recognition.interimResults = this._interimResults;\n\n const speechStartCallbacks = new Set<() => void>();\n const speechEndCallbacks = new Set<\n (result: DictationAdapter.Result) => void\n >();\n const speechCallbacks = new Set<\n (result: DictationAdapter.Result) => void\n >();\n\n let finalTranscript = \"\";\n\n const session: DictationAdapter.Session = {\n status: { type: \"starting\" },\n\n stop: async () => {\n recognition.stop();\n return new Promise<void>((resolve) => {\n const checkEnded = () => {\n if (session.status.type === \"ended\") {\n resolve();\n } else {\n setTimeout(checkEnded, 50);\n }\n };\n checkEnded();\n });\n },\n\n cancel: () => {\n recognition.abort();\n },\n\n onSpeechStart: (callback: () => void): Unsubscribe => {\n speechStartCallbacks.add(callback);\n return () => {\n speechStartCallbacks.delete(callback);\n };\n },\n\n onSpeechEnd: (\n callback: (result: DictationAdapter.Result) => void,\n ): Unsubscribe => {\n speechEndCallbacks.add(callback);\n return () => {\n speechEndCallbacks.delete(callback);\n };\n },\n\n onSpeech: (\n callback: (result: DictationAdapter.Result) => void,\n ): Unsubscribe => {\n speechCallbacks.add(callback);\n return () => {\n speechCallbacks.delete(callback);\n };\n },\n };\n\n const updateStatus = (newStatus: DictationAdapter.Status) => {\n session.status = newStatus;\n };\n\n recognition.addEventListener(\"speechstart\", () => {\n for (const cb of speechStartCallbacks) cb();\n });\n\n recognition.addEventListener(\"start\", () => {\n updateStatus({ type: \"running\" });\n });\n\n recognition.addEventListener(\"result\", (event) => {\n const speechEvent = event as unknown as SpeechRecognitionEvent;\n\n for (\n let i = speechEvent.resultIndex;\n i < speechEvent.results.length;\n i++\n ) {\n const result = speechEvent.results[i];\n if (!result) continue;\n\n const transcript = result[0]?.transcript ?? \"\";\n\n if (result.isFinal) {\n finalTranscript += transcript;\n for (const cb of speechCallbacks) cb({ transcript, isFinal: true });\n } else {\n for (const cb of speechCallbacks) cb({ transcript, isFinal: false });\n }\n }\n });\n\n recognition.addEventListener(\"speechend\", () => {\n // speechend fires when user stops speaking, but 'end' handles final cleanup\n });\n\n recognition.addEventListener(\"end\", () => {\n const currentStatus = session.status;\n if (currentStatus.type !== \"ended\") {\n updateStatus({ type: \"ended\", reason: \"stopped\" });\n }\n if (finalTranscript) {\n for (const cb of speechEndCallbacks)\n cb({ transcript: finalTranscript });\n finalTranscript = \"\";\n }\n });\n\n recognition.addEventListener(\"error\", (event) => {\n const errorEvent = event as unknown as SpeechRecognitionErrorEvent;\n if (errorEvent.error === \"aborted\") {\n updateStatus({ type: \"ended\", reason: \"cancelled\" });\n } else {\n updateStatus({ type: \"ended\", reason: \"error\" });\n console.error(\"Dictation error:\", errorEvent.error, errorEvent.message);\n }\n });\n\n try {\n recognition.start();\n } catch (error) {\n updateStatus({ type: \"ended\", reason: \"error\" });\n throw error;\n }\n\n return session;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"speech.js","names":["Unsubscribe","SpeechSynthesisAdapter","Status","type","reason","error","Utterance","status","cancel","subscribe","callback","speak","text","notifySpeechSynthesisListeners","listeners","Iterable","listener","console","DictationAdapter","Result","transcript","isFinal","Session","stop","Promise","onSpeechStart","onSpeechEnd","result","onSpeech","listen","disableInputDuringDictation","WebSpeechSynthesisAdapter","utterance","SpeechSynthesisUtterance","subscribers","Set","handleEnd","res","addEventListener","e","window","speechSynthesis","cancelled","queueMicrotask","add","delete","SpeechRecognitionResultItem","confidence","SpeechRecognitionResult","length","item","index","SpeechRecognitionResultList","SpeechRecognitionEvent","Event","resultIndex","results","SpeechRecognitionErrorEvent","message","SpeechRecognitionInstance","EventTarget","lang","continuous","interimResults","start","abort","SpeechRecognitionConstructor","global","Window","SpeechRecognition","webkitSpeechRecognition","getSpeechRecognitionAPI","undefined","WebSpeechDictationAdapter","_language","_continuous","_interimResults","constructor","options","language","defaultLanguage","navigator","isSupported","SpeechRecognitionAPI","Error","recognition","speechStartCallbacks","speechEndCallbacks","speechCallbacks","finalTranscript","session","resolve","checkEnded","setTimeout","updateStatus","newStatus","cb","event","speechEvent","i","currentStatus","errorEvent"],"sources":["../../src/adapters/speech.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\n\nexport namespace SpeechSynthesisAdapter {\n export type Status =\n | {\n type: \"starting\" | \"running\";\n }\n | {\n type: \"ended\";\n reason: \"finished\" | \"cancelled\" | \"error\";\n error?: unknown;\n };\n\n export type Utterance = {\n status: Status;\n cancel: () => void;\n subscribe: (callback: () => void) => Unsubscribe;\n };\n}\n\nexport type SpeechSynthesisAdapter = {\n speak: (text: string) => SpeechSynthesisAdapter.Utterance;\n};\n\nconst notifySpeechSynthesisListeners = (\n listeners: Iterable<() => void>,\n): void => {\n for (const listener of listeners) {\n try {\n listener();\n } catch (error) {\n console.error(\n \"[assistant-ui] Speech synthesis listener threw an error\",\n error,\n );\n }\n }\n};\n\nexport namespace DictationAdapter {\n export type Status =\n | {\n type: \"starting\" | \"running\";\n }\n | {\n type: \"ended\";\n reason: \"stopped\" | \"cancelled\" | \"error\";\n };\n\n export type Result = {\n transcript: string;\n isFinal?: boolean;\n };\n\n export type Session = {\n status: Status;\n stop: () => Promise<void>;\n cancel: () => void;\n onSpeechStart: (callback: () => void) => Unsubscribe;\n onSpeechEnd: (callback: (result: Result) => void) => Unsubscribe;\n onSpeech: (callback: (result: Result) => void) => Unsubscribe;\n };\n}\n\nexport type DictationAdapter = {\n listen: () => DictationAdapter.Session;\n disableInputDuringDictation?: boolean;\n};\n\nexport class WebSpeechSynthesisAdapter implements SpeechSynthesisAdapter {\n speak(text: string): SpeechSynthesisAdapter.Utterance {\n const utterance = new SpeechSynthesisUtterance(text);\n\n const subscribers = new Set<() => void>();\n const handleEnd = (\n reason: \"finished\" | \"error\" | \"cancelled\",\n error?: unknown,\n ) => {\n if (res.status.type === \"ended\") return;\n\n res.status = { type: \"ended\", reason, error };\n notifySpeechSynthesisListeners(subscribers);\n };\n\n utterance.addEventListener(\"end\", () => handleEnd(\"finished\"));\n utterance.addEventListener(\"error\", (e) => handleEnd(\"error\", e.error));\n\n window.speechSynthesis.speak(utterance);\n\n const res: SpeechSynthesisAdapter.Utterance = {\n status: { type: \"running\" },\n cancel: () => {\n window.speechSynthesis.cancel();\n handleEnd(\"cancelled\");\n },\n subscribe: (callback) => {\n if (res.status.type === \"ended\") {\n let cancelled = false;\n queueMicrotask(() => {\n if (!cancelled) notifySpeechSynthesisListeners([callback]);\n });\n return () => {\n cancelled = true;\n };\n } else {\n subscribers.add(callback);\n return () => {\n subscribers.delete(callback);\n };\n }\n },\n };\n return res;\n }\n}\n\ninterface SpeechRecognitionResultItem {\n transcript: string;\n confidence: number;\n}\n\ninterface SpeechRecognitionResult {\n readonly length: number;\n item(index: number): SpeechRecognitionResultItem;\n readonly isFinal: boolean;\n [index: number]: SpeechRecognitionResultItem;\n}\n\ninterface SpeechRecognitionResultList {\n readonly length: number;\n item(index: number): SpeechRecognitionResult;\n [index: number]: SpeechRecognitionResult;\n}\n\ninterface SpeechRecognitionEvent extends Event {\n readonly resultIndex: number;\n readonly results: SpeechRecognitionResultList;\n}\n\ninterface SpeechRecognitionErrorEvent extends Event {\n readonly error: string;\n readonly message: string;\n}\n\ninterface SpeechRecognitionInstance extends EventTarget {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n start(): void;\n stop(): void;\n abort(): void;\n}\n\ninterface SpeechRecognitionConstructor {\n new (): SpeechRecognitionInstance;\n}\n\ndeclare global {\n interface Window {\n SpeechRecognition?: SpeechRecognitionConstructor;\n webkitSpeechRecognition?: SpeechRecognitionConstructor;\n }\n}\n\nconst getSpeechRecognitionAPI = ():\n | SpeechRecognitionConstructor\n | undefined => {\n if (typeof window === \"undefined\") return undefined;\n return window.SpeechRecognition ?? window.webkitSpeechRecognition;\n};\n\nexport class WebSpeechDictationAdapter implements DictationAdapter {\n private _language: string;\n private _continuous: boolean;\n private _interimResults: boolean;\n\n constructor(\n options: {\n language?: string;\n continuous?: boolean;\n interimResults?: boolean;\n } = {},\n ) {\n const defaultLanguage =\n typeof navigator !== \"undefined\" && navigator.language\n ? navigator.language\n : \"en-US\";\n this._language = options.language ?? defaultLanguage;\n this._continuous = options.continuous ?? true;\n this._interimResults = options.interimResults ?? true;\n }\n\n static isSupported(): boolean {\n return getSpeechRecognitionAPI() !== undefined;\n }\n\n listen(): DictationAdapter.Session {\n const SpeechRecognitionAPI = getSpeechRecognitionAPI();\n if (!SpeechRecognitionAPI) {\n throw new Error(\n \"SpeechRecognition is not supported in this browser. \" +\n \"Try using Chrome, Edge, or Safari.\",\n );\n }\n\n const recognition = new SpeechRecognitionAPI();\n recognition.lang = this._language;\n recognition.continuous = this._continuous;\n recognition.interimResults = this._interimResults;\n\n const speechStartCallbacks = new Set<() => void>();\n const speechEndCallbacks = new Set<\n (result: DictationAdapter.Result) => void\n >();\n const speechCallbacks = new Set<\n (result: DictationAdapter.Result) => void\n >();\n\n let finalTranscript = \"\";\n\n const session: DictationAdapter.Session = {\n status: { type: \"starting\" },\n\n stop: async () => {\n recognition.stop();\n return new Promise<void>((resolve) => {\n const checkEnded = () => {\n if (session.status.type === \"ended\") {\n resolve();\n } else {\n setTimeout(checkEnded, 50);\n }\n };\n checkEnded();\n });\n },\n\n cancel: () => {\n recognition.abort();\n },\n\n onSpeechStart: (callback: () => void): Unsubscribe => {\n speechStartCallbacks.add(callback);\n return () => {\n speechStartCallbacks.delete(callback);\n };\n },\n\n onSpeechEnd: (\n callback: (result: DictationAdapter.Result) => void,\n ): Unsubscribe => {\n speechEndCallbacks.add(callback);\n return () => {\n speechEndCallbacks.delete(callback);\n };\n },\n\n onSpeech: (\n callback: (result: DictationAdapter.Result) => void,\n ): Unsubscribe => {\n speechCallbacks.add(callback);\n return () => {\n speechCallbacks.delete(callback);\n };\n },\n };\n\n const updateStatus = (newStatus: DictationAdapter.Status) => {\n session.status = newStatus;\n };\n\n recognition.addEventListener(\"speechstart\", () => {\n for (const cb of speechStartCallbacks) cb();\n });\n\n recognition.addEventListener(\"start\", () => {\n updateStatus({ type: \"running\" });\n });\n\n recognition.addEventListener(\"result\", (event) => {\n const speechEvent = event as unknown as SpeechRecognitionEvent;\n\n for (\n let i = speechEvent.resultIndex;\n i < speechEvent.results.length;\n i++\n ) {\n const result = speechEvent.results[i];\n if (!result) continue;\n\n const transcript = result[0]?.transcript ?? \"\";\n\n if (result.isFinal) {\n finalTranscript += transcript;\n for (const cb of speechCallbacks) cb({ transcript, isFinal: true });\n } else {\n for (const cb of speechCallbacks) cb({ transcript, isFinal: false });\n }\n }\n });\n\n recognition.addEventListener(\"speechend\", () => {\n // speechend fires when user stops speaking, but 'end' handles final cleanup\n });\n\n recognition.addEventListener(\"end\", () => {\n const currentStatus = session.status;\n if (currentStatus.type !== \"ended\") {\n updateStatus({ type: \"ended\", reason: \"stopped\" });\n }\n if (finalTranscript) {\n for (const cb of speechEndCallbacks)\n cb({ transcript: finalTranscript });\n finalTranscript = \"\";\n }\n });\n\n recognition.addEventListener(\"error\", (event) => {\n const errorEvent = event as unknown as SpeechRecognitionErrorEvent;\n if (errorEvent.error === \"aborted\") {\n updateStatus({ type: \"ended\", reason: \"cancelled\" });\n } else {\n updateStatus({ type: \"ended\", reason: \"error\" });\n console.error(\"Dictation error:\", errorEvent.error, errorEvent.message);\n }\n });\n\n try {\n recognition.start();\n } catch (error) {\n updateStatus({ type: \"ended\", reason: \"error\" });\n throw error;\n }\n\n return session;\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"voice.d.ts","names":[],"sources":["../../src/adapters/voice.ts"],"mappings":";;kBAEiB;OACH;IAEN;;IAGA;IACA;IACA;;OAGM;OAEA;IACV;IACA;IACA;;OAGU;IACV,QAAQ;IACR;IAEA;IACA;IACA;IAEA,iBAAiB,WAAW,QAAQ,oBAAoB;IACxD,eACE,WAAW,YAAY,4BACpB;IACL,eAAe,WAAW,MAAM,kBAAkB;IAClD,iBAAiB,WAAW,4BAA4B;;;KAIhD;EACV,UAAU;IACR,cAAc;QACV,qBAAqB;;KAGjB;EACV;EACA;EACA;;KAGU;EACV,YAAY,QAAQ,qBAAqB;EACzC,MAAM,4CAA4C;EAClD,iBAAiB,MAAM,qBAAqB;EAC5C,WAAW,MAAM,qBAAqB;EACtC,aAAa;EACb;;iBAGc,mBACd;EAAW,cAAc;GACzB,QAAQ,SAAS,wBAAwB,QAAQ,wBAChD,qBAAqB"}
1
+ {"version":3,"file":"voice.d.ts","names":[],"sources":["../../src/adapters/voice.ts"],"mappings":";;kBAEiB;OACH;IAEN;;IAGA;IACA;IACA;;OAGM;OAEA;IACV;IACA;IACA;;OAGU;IACV,QAAQ;IACR;IAEA;IACA;IACA;IAEA,iBAAiB,WAAW,QAAQ,oBAAoB;IACxD,eACE,WAAW,YAAY,4BACpB;IACL,eAAe,WAAW,MAAM,kBAAkB;IAClD,iBAAiB,WAAW,4BAA4B;;;KAIhD;EACV,UAAU;IACR,cAAc;QACV,qBAAqB;;KAGjB;EACV;EACA;EACA;;KAGU;EACV,YAAY,QAAQ,qBAAqB;EACzC,MAAM,4CAA4C;EAClD,iBAAiB,MAAM,qBAAqB;EAC5C,WAAW,MAAM,qBAAqB;EACtC,aAAa;EACb;;iBAmBc,mBACd;EAAW,cAAc;GACzB,QAAQ,SAAS,wBAAwB,QAAQ,wBAChD,qBAAqB"}
@@ -1,4 +1,11 @@
1
1
  //#region src/adapters/voice.ts
2
+ const notifyListeners = (listeners, value) => {
3
+ for (const listener of listeners) try {
4
+ listener(value);
5
+ } catch (error) {
6
+ console.error("[assistant-ui] Voice session listener threw an error", error);
7
+ }
8
+ };
2
9
  function createVoiceSession(options, setup) {
3
10
  const statusCbs = /* @__PURE__ */ new Set();
4
11
  const transcriptCbs = /* @__PURE__ */ new Set();
@@ -19,7 +26,7 @@ function createVoiceSession(options, setup) {
19
26
  setStatus: (status) => {
20
27
  if (disposed) return;
21
28
  currentStatus = status;
22
- for (const cb of statusCbs) cb(status);
29
+ notifyListeners(statusCbs, status);
23
30
  },
24
31
  end: (reason, error) => {
25
32
  if (disposed) return;
@@ -28,20 +35,20 @@ function createVoiceSession(options, setup) {
28
35
  reason,
29
36
  error
30
37
  };
31
- for (const cb of statusCbs) cb(currentStatus);
38
+ notifyListeners(statusCbs, currentStatus);
32
39
  cleanup();
33
40
  },
34
41
  emitTranscript: (item) => {
35
42
  if (disposed) return;
36
- for (const cb of transcriptCbs) cb(item);
43
+ notifyListeners(transcriptCbs, item);
37
44
  },
38
45
  emitMode: (mode) => {
39
46
  if (disposed) return;
40
- for (const cb of modeCbs) cb(mode);
47
+ notifyListeners(modeCbs, mode);
41
48
  },
42
49
  emitVolume: (volume) => {
43
50
  if (disposed) return;
44
- for (const cb of volumeCbs) cb(volume);
51
+ notifyListeners(volumeCbs, volume);
45
52
  },
46
53
  isDisposed: () => disposed
47
54
  };
@@ -87,6 +94,7 @@ function createVoiceSession(options, setup) {
87
94
  if (disposed) return;
88
95
  controls = await setup(helpers);
89
96
  if (disposed) controls.disconnect();
97
+ else if (isMuted) controls.mute();
90
98
  } catch (error) {
91
99
  helpers.end("error", error);
92
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"voice.js","names":["Unsubscribe","RealtimeVoiceAdapter","Status","type","reason","error","Mode","TranscriptItem","role","text","isFinal","Session","status","isMuted","disconnect","mute","unmute","onStatusChange","callback","onTranscript","transcript","onModeChange","mode","onVolumeChange","volume","connect","options","abortSignal","AbortSignal","VoiceSessionControls","VoiceSessionHelpers","setStatus","end","emitTranscript","item","emitMode","emitVolume","isDisposed","createVoiceSession","setup","helpers","Promise","statusCbs","Set","s","transcriptCbs","t","modeCbs","m","volumeCbs","v","currentStatus","disposed","controls","cleanup","clear","cb","session","add","delete","addEventListener","once","doSetup"],"sources":["../../src/adapters/voice.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\n\nexport namespace RealtimeVoiceAdapter {\n export type Status =\n | {\n type: \"starting\" | \"running\";\n }\n | {\n type: \"ended\";\n reason: \"finished\" | \"cancelled\" | \"error\";\n error?: unknown;\n };\n\n export type Mode = \"listening\" | \"speaking\";\n\n export type TranscriptItem = {\n role: \"user\" | \"assistant\";\n text: string;\n isFinal?: boolean;\n };\n\n export type Session = {\n status: Status;\n isMuted: boolean;\n\n disconnect: () => void;\n mute: () => void;\n unmute: () => void;\n\n onStatusChange: (callback: (status: Status) => void) => Unsubscribe;\n onTranscript: (\n callback: (transcript: TranscriptItem) => void,\n ) => Unsubscribe;\n onModeChange: (callback: (mode: Mode) => void) => Unsubscribe;\n onVolumeChange: (callback: (volume: number) => void) => Unsubscribe;\n };\n}\n\nexport type RealtimeVoiceAdapter = {\n connect: (options: {\n abortSignal?: AbortSignal;\n }) => RealtimeVoiceAdapter.Session;\n};\n\nexport type VoiceSessionControls = {\n disconnect: () => void;\n mute: () => void;\n unmute: () => void;\n};\n\nexport type VoiceSessionHelpers = {\n setStatus: (status: RealtimeVoiceAdapter.Status) => void;\n end: (reason: \"finished\" | \"cancelled\" | \"error\", error?: unknown) => void;\n emitTranscript: (item: RealtimeVoiceAdapter.TranscriptItem) => void;\n emitMode: (mode: RealtimeVoiceAdapter.Mode) => void;\n emitVolume: (volume: number) => void;\n isDisposed: () => boolean;\n};\n\nexport function createVoiceSession(\n options: { abortSignal?: AbortSignal },\n setup: (helpers: VoiceSessionHelpers) => Promise<VoiceSessionControls>,\n): RealtimeVoiceAdapter.Session {\n const statusCbs = new Set<(s: RealtimeVoiceAdapter.Status) => void>();\n const transcriptCbs = new Set<\n (t: RealtimeVoiceAdapter.TranscriptItem) => void\n >();\n const modeCbs = new Set<(m: RealtimeVoiceAdapter.Mode) => void>();\n const volumeCbs = new Set<(v: number) => void>();\n\n let currentStatus: RealtimeVoiceAdapter.Status = { type: \"starting\" };\n let isMuted = false;\n let disposed = false;\n let controls: VoiceSessionControls | null = null;\n\n const cleanup = () => {\n disposed = true;\n statusCbs.clear();\n transcriptCbs.clear();\n modeCbs.clear();\n volumeCbs.clear();\n };\n\n const helpers: VoiceSessionHelpers = {\n setStatus: (status) => {\n if (disposed) return;\n currentStatus = status;\n for (const cb of statusCbs) cb(status);\n },\n end: (reason, error?) => {\n if (disposed) return;\n currentStatus = { type: \"ended\", reason, error };\n for (const cb of statusCbs) cb(currentStatus);\n cleanup();\n },\n emitTranscript: (item) => {\n if (disposed) return;\n for (const cb of transcriptCbs) cb(item);\n },\n emitMode: (mode) => {\n if (disposed) return;\n for (const cb of modeCbs) cb(mode);\n },\n emitVolume: (volume) => {\n if (disposed) return;\n for (const cb of volumeCbs) cb(volume);\n },\n isDisposed: () => disposed,\n };\n\n const session: RealtimeVoiceAdapter.Session = {\n get status() {\n return currentStatus;\n },\n get isMuted() {\n return isMuted;\n },\n disconnect: () => {\n controls?.disconnect();\n cleanup();\n },\n mute: () => {\n controls?.mute();\n isMuted = true;\n },\n unmute: () => {\n controls?.unmute();\n isMuted = false;\n },\n onStatusChange: (cb) => {\n statusCbs.add(cb);\n return () => statusCbs.delete(cb);\n },\n onTranscript: (cb) => {\n transcriptCbs.add(cb);\n return () => transcriptCbs.delete(cb);\n },\n onModeChange: (cb) => {\n modeCbs.add(cb);\n return () => modeCbs.delete(cb);\n },\n onVolumeChange: (cb) => {\n volumeCbs.add(cb);\n return () => volumeCbs.delete(cb);\n },\n };\n\n if (options.abortSignal) {\n options.abortSignal.addEventListener(\"abort\", () => session.disconnect(), {\n once: true,\n });\n }\n\n const doSetup = async () => {\n try {\n if (disposed) return;\n controls = await setup(helpers);\n if (disposed) controls.disconnect();\n } catch (error) {\n helpers.end(\"error\", error);\n }\n };\n\n doSetup();\n return session;\n}\n"],"mappings":";AA2DA,SAAgBsC,mBACdZ,SACAa,OAC8B;CAC9B,MAAMG,4BAAY,IAAIC,IAA8C;CACpE,MAAME,gCAAgB,IAAIF,IAExB;CACF,MAAMI,0BAAU,IAAIJ,IAA4C;CAChE,MAAMM,4BAAY,IAAIN,IAAyB;CAE/C,IAAIQ,gBAA6C,EAAEhD,MAAM,WAAW;CACpE,IAAIU,UAAU;CACd,IAAIuC,WAAW;CACf,IAAIC,WAAwC;CAE5C,MAAMC,gBAAgB;EACpBF,WAAW;EACXV,UAAUa,MAAM;EAChBV,cAAcU,MAAM;EACpBR,QAAQQ,MAAM;EACdN,UAAUM,MAAM;CAClB;CAEA,MAAMf,UAA+B;EACnCT,YAAYnB,WAAW;GACrB,IAAIwC,UAAU;GACdD,gBAAgBvC;GAChB,KAAK,MAAM4C,MAAMd,WAAWc,GAAG5C,MAAM;EACvC;EACAoB,MAAM5B,QAAQC,UAAW;GACvB,IAAI+C,UAAU;GACdD,gBAAgB;IAAEhD,MAAM;IAASC;IAAQC;GAAM;GAC/C,KAAK,MAAMmD,MAAMd,WAAWc,GAAGL,aAAa;GAC5CG,QAAQ;EACV;EACArB,iBAAiBC,SAAS;GACxB,IAAIkB,UAAU;GACd,KAAK,MAAMI,MAAMX,eAAeW,GAAGtB,IAAI;EACzC;EACAC,WAAWb,SAAS;GAClB,IAAI8B,UAAU;GACd,KAAK,MAAMI,MAAMT,SAASS,GAAGlC,IAAI;EACnC;EACAc,aAAaZ,WAAW;GACtB,IAAI4B,UAAU;GACd,KAAK,MAAMI,MAAMP,WAAWO,GAAGhC,MAAM;EACvC;EACAa,kBAAkBe;CACpB;CAEA,MAAMK,UAAwC;EAC5C,IAAI7C,SAAS;GACX,OAAOuC;EACT;EACA,IAAItC,UAAU;GACZ,OAAOA;EACT;EACAC,kBAAkB;GAChBuC,UAAUvC,WAAW;GACrBwC,QAAQ;EACV;EACAvC,YAAY;GACVsC,UAAUtC,KAAK;GACfF,UAAU;EACZ;EACAG,cAAc;GACZqC,UAAUrC,OAAO;GACjBH,UAAU;EACZ;EACAI,iBAAiBuC,OAAO;GACtBd,UAAUgB,IAAIF,EAAE;GAChB,aAAad,UAAUiB,OAAOH,EAAE;EAClC;EACArC,eAAeqC,OAAO;GACpBX,cAAca,IAAIF,EAAE;GACpB,aAAaX,cAAcc,OAAOH,EAAE;EACtC;EACAnC,eAAemC,OAAO;GACpBT,QAAQW,IAAIF,EAAE;GACd,aAAaT,QAAQY,OAAOH,EAAE;EAChC;EACAjC,iBAAiBiC,OAAO;GACtBP,UAAUS,IAAIF,EAAE;GAChB,aAAaP,UAAUU,OAAOH,EAAE;EAClC;CACF;CAEA,IAAI9B,QAAQC,aACVD,QAAQC,YAAYiC,iBAAiB,eAAeH,QAAQ3C,WAAW,GAAG,EACxE+C,MAAM,KACR,CAAC;CAGH,MAAMC,UAAU,YAAY;EAC1B,IAAI;GACF,IAAIV,UAAU;GACdC,WAAW,MAAMd,MAAMC,OAAO;GAC9B,IAAIY,UAAUC,SAASvC,WAAW;EACpC,SAAST,OAAO;GACdmC,QAAQR,IAAI,SAAS3B,KAAK;EAC5B;CACF;CAEAyD,QAAQ;CACR,OAAOL;AACT"}
1
+ {"version":3,"file":"voice.js","names":["Unsubscribe","RealtimeVoiceAdapter","Status","type","reason","error","Mode","TranscriptItem","role","text","isFinal","Session","status","isMuted","disconnect","mute","unmute","onStatusChange","callback","onTranscript","transcript","onModeChange","mode","onVolumeChange","volume","connect","options","abortSignal","AbortSignal","VoiceSessionControls","VoiceSessionHelpers","setStatus","end","emitTranscript","item","emitMode","emitVolume","isDisposed","notifyListeners","listeners","ReadonlySet","value","T","listener","console","createVoiceSession","setup","helpers","Promise","statusCbs","Set","s","transcriptCbs","t","modeCbs","m","volumeCbs","v","currentStatus","disposed","controls","cleanup","clear","session","cb","add","delete","addEventListener","once","doSetup"],"sources":["../../src/adapters/voice.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\n\nexport namespace RealtimeVoiceAdapter {\n export type Status =\n | {\n type: \"starting\" | \"running\";\n }\n | {\n type: \"ended\";\n reason: \"finished\" | \"cancelled\" | \"error\";\n error?: unknown;\n };\n\n export type Mode = \"listening\" | \"speaking\";\n\n export type TranscriptItem = {\n role: \"user\" | \"assistant\";\n text: string;\n isFinal?: boolean;\n };\n\n export type Session = {\n status: Status;\n isMuted: boolean;\n\n disconnect: () => void;\n mute: () => void;\n unmute: () => void;\n\n onStatusChange: (callback: (status: Status) => void) => Unsubscribe;\n onTranscript: (\n callback: (transcript: TranscriptItem) => void,\n ) => Unsubscribe;\n onModeChange: (callback: (mode: Mode) => void) => Unsubscribe;\n onVolumeChange: (callback: (volume: number) => void) => Unsubscribe;\n };\n}\n\nexport type RealtimeVoiceAdapter = {\n connect: (options: {\n abortSignal?: AbortSignal;\n }) => RealtimeVoiceAdapter.Session;\n};\n\nexport type VoiceSessionControls = {\n disconnect: () => void;\n mute: () => void;\n unmute: () => void;\n};\n\nexport type VoiceSessionHelpers = {\n setStatus: (status: RealtimeVoiceAdapter.Status) => void;\n end: (reason: \"finished\" | \"cancelled\" | \"error\", error?: unknown) => void;\n emitTranscript: (item: RealtimeVoiceAdapter.TranscriptItem) => void;\n emitMode: (mode: RealtimeVoiceAdapter.Mode) => void;\n emitVolume: (volume: number) => void;\n isDisposed: () => boolean;\n};\n\nconst notifyListeners = <T>(\n listeners: ReadonlySet<(value: T) => void>,\n value: T,\n) => {\n for (const listener of listeners) {\n try {\n listener(value);\n } catch (error) {\n console.error(\n \"[assistant-ui] Voice session listener threw an error\",\n error,\n );\n }\n }\n};\n\nexport function createVoiceSession(\n options: { abortSignal?: AbortSignal },\n setup: (helpers: VoiceSessionHelpers) => Promise<VoiceSessionControls>,\n): RealtimeVoiceAdapter.Session {\n const statusCbs = new Set<(s: RealtimeVoiceAdapter.Status) => void>();\n const transcriptCbs = new Set<\n (t: RealtimeVoiceAdapter.TranscriptItem) => void\n >();\n const modeCbs = new Set<(m: RealtimeVoiceAdapter.Mode) => void>();\n const volumeCbs = new Set<(v: number) => void>();\n\n let currentStatus: RealtimeVoiceAdapter.Status = { type: \"starting\" };\n let isMuted = false;\n let disposed = false;\n let controls: VoiceSessionControls | null = null;\n\n const cleanup = () => {\n disposed = true;\n statusCbs.clear();\n transcriptCbs.clear();\n modeCbs.clear();\n volumeCbs.clear();\n };\n\n const helpers: VoiceSessionHelpers = {\n setStatus: (status) => {\n if (disposed) return;\n currentStatus = status;\n notifyListeners(statusCbs, status);\n },\n end: (reason, error?) => {\n if (disposed) return;\n currentStatus = { type: \"ended\", reason, error };\n notifyListeners(statusCbs, currentStatus);\n cleanup();\n },\n emitTranscript: (item) => {\n if (disposed) return;\n notifyListeners(transcriptCbs, item);\n },\n emitMode: (mode) => {\n if (disposed) return;\n notifyListeners(modeCbs, mode);\n },\n emitVolume: (volume) => {\n if (disposed) return;\n notifyListeners(volumeCbs, volume);\n },\n isDisposed: () => disposed,\n };\n\n const session: RealtimeVoiceAdapter.Session = {\n get status() {\n return currentStatus;\n },\n get isMuted() {\n return isMuted;\n },\n disconnect: () => {\n controls?.disconnect();\n cleanup();\n },\n mute: () => {\n controls?.mute();\n isMuted = true;\n },\n unmute: () => {\n controls?.unmute();\n isMuted = false;\n },\n onStatusChange: (cb) => {\n statusCbs.add(cb);\n return () => statusCbs.delete(cb);\n },\n onTranscript: (cb) => {\n transcriptCbs.add(cb);\n return () => transcriptCbs.delete(cb);\n },\n onModeChange: (cb) => {\n modeCbs.add(cb);\n return () => modeCbs.delete(cb);\n },\n onVolumeChange: (cb) => {\n volumeCbs.add(cb);\n return () => volumeCbs.delete(cb);\n },\n };\n\n if (options.abortSignal) {\n options.abortSignal.addEventListener(\"abort\", () => session.disconnect(), {\n once: true,\n });\n }\n\n const doSetup = async () => {\n try {\n if (disposed) return;\n controls = await setup(helpers);\n if (disposed) {\n controls.disconnect();\n } else if (isMuted) {\n controls.mute();\n }\n } catch (error) {\n helpers.end(\"error\", error);\n }\n };\n\n doSetup();\n return session;\n}\n"],"mappings":";AA2DA,MAAMsC,mBACJC,WACAE,UACG;CACH,KAAK,MAAME,YAAYJ,WACrB,IAAI;EACFI,SAASF,KAAK;CAChB,SAASpC,OAAO;EACduC,QAAQvC,MACN,wDACAA,KACF;CACF;AAEJ;AAEA,SAAgBwC,mBACdnB,SACAoB,OAC8B;CAC9B,MAAMG,4BAAY,IAAIC,IAA8C;CACpE,MAAME,gCAAgB,IAAIF,IAExB;CACF,MAAMI,0BAAU,IAAIJ,IAA4C;CAChE,MAAMM,4BAAY,IAAIN,IAAyB;CAE/C,IAAIQ,gBAA6C,EAAEvD,MAAM,WAAW;CACpE,IAAIU,UAAU;CACd,IAAI8C,WAAW;CACf,IAAIC,WAAwC;CAE5C,MAAMC,gBAAgB;EACpBF,WAAW;EACXV,UAAUa,MAAM;EAChBV,cAAcU,MAAM;EACpBR,QAAQQ,MAAM;EACdN,UAAUM,MAAM;CAClB;CAEA,MAAMf,UAA+B;EACnChB,YAAYnB,WAAW;GACrB,IAAI+C,UAAU;GACdD,gBAAgB9C;GAChB0B,gBAAgBW,WAAWrC,MAAM;EACnC;EACAoB,MAAM5B,QAAQC,UAAW;GACvB,IAAIsD,UAAU;GACdD,gBAAgB;IAAEvD,MAAM;IAASC;IAAQC;GAAM;GAC/CiC,gBAAgBW,WAAWS,aAAa;GACxCG,QAAQ;EACV;EACA5B,iBAAiBC,SAAS;GACxB,IAAIyB,UAAU;GACdrB,gBAAgBc,eAAelB,IAAI;EACrC;EACAC,WAAWb,SAAS;GAClB,IAAIqC,UAAU;GACdrB,gBAAgBgB,SAAShC,IAAI;EAC/B;EACAc,aAAaZ,WAAW;GACtB,IAAImC,UAAU;GACdrB,gBAAgBkB,WAAWhC,MAAM;EACnC;EACAa,kBAAkBsB;CACpB;CAEA,MAAMI,UAAwC;EAC5C,IAAInD,SAAS;GACX,OAAO8C;EACT;EACA,IAAI7C,UAAU;GACZ,OAAOA;EACT;EACAC,kBAAkB;GAChB8C,UAAU9C,WAAW;GACrB+C,QAAQ;EACV;EACA9C,YAAY;GACV6C,UAAU7C,KAAK;GACfF,UAAU;EACZ;EACAG,cAAc;GACZ4C,UAAU5C,OAAO;GACjBH,UAAU;EACZ;EACAI,iBAAiB+C,OAAO;GACtBf,UAAUgB,IAAID,EAAE;GAChB,aAAaf,UAAUiB,OAAOF,EAAE;EAClC;EACA7C,eAAe6C,OAAO;GACpBZ,cAAca,IAAID,EAAE;GACpB,aAAaZ,cAAcc,OAAOF,EAAE;EACtC;EACA3C,eAAe2C,OAAO;GACpBV,QAAQW,IAAID,EAAE;GACd,aAAaV,QAAQY,OAAOF,EAAE;EAChC;EACAzC,iBAAiByC,OAAO;GACtBR,UAAUS,IAAID,EAAE;GAChB,aAAaR,UAAUU,OAAOF,EAAE;EAClC;CACF;CAEA,IAAItC,QAAQC,aACVD,QAAQC,YAAYwC,iBAAiB,eAAeJ,QAAQjD,WAAW,GAAG,EACxEsD,MAAM,KACR,CAAC;CAGH,MAAMC,UAAU,YAAY;EAC1B,IAAI;GACF,IAAIV,UAAU;GACdC,WAAW,MAAMd,MAAMC,OAAO;GAC9B,IAAIY,UACFC,SAAS9C,WAAW;QACf,IAAID,SACT+C,SAAS7C,KAAK;EAElB,SAASV,OAAO;GACd0C,QAAQf,IAAI,SAAS3B,KAAK;EAC5B;CACF;CAEAgE,QAAQ;CACR,OAAON;AACT"}
@@ -1,3 +1,4 @@
1
+ import { isCreateAttachment } from "./types/attachment.js";
1
2
  import { getFileDataURL } from "./adapters/attachment.js";
2
3
  import { fromThreadMessageLike } from "./runtime/utils/thread-message-like.js";
3
4
  import { ExportedMessageRepository, ExportedMessageRepositoryItem, MessageRepository } from "./runtime/utils/message-repository.js";
@@ -9,6 +10,7 @@ import { resolveToolApprovalResponse } from "./runtime/utils/resolveToolApproval
9
10
  import { CompositeContextProvider } from "./utils/composite-context-provider.js";
10
11
  import { stableStringifyToolArgs, trackToolArgsKeyOrder } from "./utils/json/stable-stringify-tool-args.js";
11
12
  import { isJSONValue, isRecord } from "./utils/json/is-json.js";
13
+ import { httpUrlPattern, parseDataUrl } from "./utils/data-url.js";
12
14
  import { RuntimeExtras, createRuntimeExtras } from "./react/runtimes/createRuntimeExtras.js";
13
15
  import { ComposerRuntimeCoreBinding, EditComposerRuntimeCoreBinding, MessageStateBinding, ThreadComposerRuntimeCoreBinding } from "./runtime/api/bindings.js";
14
16
  import { BaseAssistantRuntimeCore } from "./runtime/base/base-assistant-runtime-core.js";
@@ -42,4 +44,4 @@ import { RemoteThreadData, RemoteThreadState, THREAD_MAPPING_ID, createThreadMap
42
44
  import "./runtimes/internal.js";
43
45
  import { ThreadListItemRuntimeBinding, ThreadRuntimeCoreBinding, ThreadRuntimeImpl, getThreadState } from "./runtime/api/thread-runtime.js";
44
46
  import { AssistantRuntimeImpl } from "./runtime/api/assistant-runtime.js";
45
- export { AssistantRuntimeImpl, AttachmentRuntimeImpl, BaseAssistantRuntimeCore, BaseComposerRuntimeCore, BaseSubject, BaseSubscribable, BaseThreadRuntimeCore, type ComposerRuntimeCoreBinding, ComposerRuntimeImpl, CompositeContextProvider, type ConverterCallback, DefaultEditComposerRuntimeCore, DefaultThreadComposerRuntimeCore, EMPTY_THREAD_CORE, EditComposerAttachmentRuntimeImpl, type EditComposerRuntimeCoreBinding, EditComposerRuntimeImpl, type EventSubscribable, EventSubscriptionSubject, ExportedMessageRepository, type ExportedMessageRepositoryItem, ExternalStoreRuntimeCore, type ExternalStoreThreadFactory, ExternalStoreThreadListRuntimeCore, ExternalStoreThreadRuntimeCore, LazyMemoizeSubject, LocalRuntimeCore, type LocalRuntimeOptionsBase, type LocalThreadFactory, LocalThreadListRuntimeCore, LocalThreadRuntimeCore, MessageAttachmentRuntimeImpl, MessagePartRuntimeImpl, MessageRepository, MessageRuntimeImpl, type MessageStateBinding, type NestedSubscribable, NestedSubscriptionSubject, OptimisticState, ReadonlyThreadRuntimeCore, type RemoteThreadData, type RemoteThreadInitializeResponse, type RemoteThreadListOptions, type RemoteThreadState, type RuntimeExtras, SKIP_UPDATE, type SKIP_UPDATE as SKIP_UPDATE_TYPE, ShallowMemoizeSubject, type Subscribable, type SubscribableWithState, type THREAD_MAPPING_ID, ThreadComposerAttachmentRuntimeImpl, type ThreadComposerRuntimeCoreBinding, ThreadComposerRuntimeImpl, type ThreadListItemRuntimeBinding, ThreadListItemRuntimeImpl, type ThreadListItemStateBinding, type ThreadListRuntimeCoreBinding, ThreadListRuntimeImpl, ThreadMessageConverter, type ThreadRuntimeCoreBinding, ThreadRuntimeImpl, consumeSuggestionResult, createRuntimeExtras, createThreadMappingId, fromThreadMessageLike, generateErrorMessageId, generateId, getAutoStatus, getFileDataURL, getThreadData, getThreadMessageText, getThreadState, hasUpcomingMessage, isAutoStatus, isErrorMessageId, isJSONValue, isRecord, resolveToolApprovalResponse, shouldContinue, stableStringifyToolArgs, symbolInnerMessage, trackToolArgsKeyOrder, updateStatusReducer };
47
+ export { AssistantRuntimeImpl, AttachmentRuntimeImpl, BaseAssistantRuntimeCore, BaseComposerRuntimeCore, BaseSubject, BaseSubscribable, BaseThreadRuntimeCore, type ComposerRuntimeCoreBinding, ComposerRuntimeImpl, CompositeContextProvider, type ConverterCallback, DefaultEditComposerRuntimeCore, DefaultThreadComposerRuntimeCore, EMPTY_THREAD_CORE, EditComposerAttachmentRuntimeImpl, type EditComposerRuntimeCoreBinding, EditComposerRuntimeImpl, type EventSubscribable, EventSubscriptionSubject, ExportedMessageRepository, type ExportedMessageRepositoryItem, ExternalStoreRuntimeCore, type ExternalStoreThreadFactory, ExternalStoreThreadListRuntimeCore, ExternalStoreThreadRuntimeCore, LazyMemoizeSubject, LocalRuntimeCore, type LocalRuntimeOptionsBase, type LocalThreadFactory, LocalThreadListRuntimeCore, LocalThreadRuntimeCore, MessageAttachmentRuntimeImpl, MessagePartRuntimeImpl, MessageRepository, MessageRuntimeImpl, type MessageStateBinding, type NestedSubscribable, NestedSubscriptionSubject, OptimisticState, ReadonlyThreadRuntimeCore, type RemoteThreadData, type RemoteThreadInitializeResponse, type RemoteThreadListOptions, type RemoteThreadState, type RuntimeExtras, SKIP_UPDATE, type SKIP_UPDATE as SKIP_UPDATE_TYPE, ShallowMemoizeSubject, type Subscribable, type SubscribableWithState, type THREAD_MAPPING_ID, ThreadComposerAttachmentRuntimeImpl, type ThreadComposerRuntimeCoreBinding, ThreadComposerRuntimeImpl, type ThreadListItemRuntimeBinding, ThreadListItemRuntimeImpl, type ThreadListItemStateBinding, type ThreadListRuntimeCoreBinding, ThreadListRuntimeImpl, ThreadMessageConverter, type ThreadRuntimeCoreBinding, ThreadRuntimeImpl, consumeSuggestionResult, createRuntimeExtras, createThreadMappingId, fromThreadMessageLike, generateErrorMessageId, generateId, getAutoStatus, getFileDataURL, getThreadData, getThreadMessageText, getThreadState, hasUpcomingMessage, httpUrlPattern, isAutoStatus, isCreateAttachment, isErrorMessageId, isJSONValue, isRecord, parseDataUrl, resolveToolApprovalResponse, shouldContinue, stableStringifyToolArgs, symbolInnerMessage, trackToolArgsKeyOrder, updateStatusReducer };
package/dist/internal.js CHANGED
@@ -10,7 +10,9 @@ import { ExportedMessageRepository, MessageRepository } from "./runtime/utils/me
10
10
  import { BaseSubject, BaseSubscribable, EventSubscriptionSubject, LazyMemoizeSubject, NestedSubscriptionSubject, SKIP_UPDATE, ShallowMemoizeSubject } from "./subscribable/subscribable.js";
11
11
  import { resolveToolApprovalResponse } from "./runtime/utils/resolveToolApprovalResponse.js";
12
12
  import { CompositeContextProvider } from "./utils/composite-context-provider.js";
13
+ import { isCreateAttachment } from "./types/attachment.js";
13
14
  import { stableStringifyToolArgs, trackToolArgsKeyOrder } from "./utils/json/stable-stringify-tool-args.js";
15
+ import { httpUrlPattern, parseDataUrl } from "./utils/data-url.js";
14
16
  import { createRuntimeExtras } from "./react/runtimes/createRuntimeExtras.js";
15
17
  import { BaseAssistantRuntimeCore } from "./runtime/base/base-assistant-runtime-core.js";
16
18
  import { BaseComposerRuntimeCore } from "./runtime/base/base-composer-runtime-core.js";
@@ -37,4 +39,4 @@ import { ReadonlyThreadRuntimeCore } from "./runtimes/readonly/ReadonlyThreadRun
37
39
  import { OptimisticState } from "./runtimes/remote-thread-list/optimistic-state.js";
38
40
  import { EMPTY_THREAD_CORE } from "./runtimes/remote-thread-list/empty-thread-core.js";
39
41
  import { createThreadMappingId, getThreadData, updateStatusReducer } from "./runtimes/remote-thread-list/remote-thread-state.js";
40
- export { AssistantRuntimeImpl, AttachmentRuntimeImpl, BaseAssistantRuntimeCore, BaseComposerRuntimeCore, BaseSubject, BaseSubscribable, BaseThreadRuntimeCore, ComposerRuntimeImpl, CompositeContextProvider, DefaultEditComposerRuntimeCore, DefaultThreadComposerRuntimeCore, EMPTY_THREAD_CORE, EditComposerAttachmentRuntimeImpl, EditComposerRuntimeImpl, EventSubscriptionSubject, ExportedMessageRepository, ExternalStoreRuntimeCore, ExternalStoreThreadListRuntimeCore, ExternalStoreThreadRuntimeCore, LazyMemoizeSubject, LocalRuntimeCore, LocalThreadListRuntimeCore, LocalThreadRuntimeCore, MessageAttachmentRuntimeImpl, MessagePartRuntimeImpl, MessageRepository, MessageRuntimeImpl, NestedSubscriptionSubject, OptimisticState, ReadonlyThreadRuntimeCore, SKIP_UPDATE, ShallowMemoizeSubject, ThreadComposerAttachmentRuntimeImpl, ThreadComposerRuntimeImpl, ThreadListItemRuntimeImpl, ThreadListRuntimeImpl, ThreadMessageConverter, ThreadRuntimeImpl, consumeSuggestionResult, createRuntimeExtras, createThreadMappingId, fromThreadMessageLike, generateErrorMessageId, generateId, getAutoStatus, getFileDataURL, getThreadData, getThreadMessageText, getThreadState, hasUpcomingMessage, isAutoStatus, isErrorMessageId, isJSONValue, isRecord, resolveToolApprovalResponse, shouldContinue, stableStringifyToolArgs, symbolInnerMessage, trackToolArgsKeyOrder, updateStatusReducer };
42
+ export { AssistantRuntimeImpl, AttachmentRuntimeImpl, BaseAssistantRuntimeCore, BaseComposerRuntimeCore, BaseSubject, BaseSubscribable, BaseThreadRuntimeCore, ComposerRuntimeImpl, CompositeContextProvider, DefaultEditComposerRuntimeCore, DefaultThreadComposerRuntimeCore, EMPTY_THREAD_CORE, EditComposerAttachmentRuntimeImpl, EditComposerRuntimeImpl, EventSubscriptionSubject, ExportedMessageRepository, ExternalStoreRuntimeCore, ExternalStoreThreadListRuntimeCore, ExternalStoreThreadRuntimeCore, LazyMemoizeSubject, LocalRuntimeCore, LocalThreadListRuntimeCore, LocalThreadRuntimeCore, MessageAttachmentRuntimeImpl, MessagePartRuntimeImpl, MessageRepository, MessageRuntimeImpl, NestedSubscriptionSubject, OptimisticState, ReadonlyThreadRuntimeCore, SKIP_UPDATE, ShallowMemoizeSubject, ThreadComposerAttachmentRuntimeImpl, ThreadComposerRuntimeImpl, ThreadListItemRuntimeImpl, ThreadListRuntimeImpl, ThreadMessageConverter, ThreadRuntimeImpl, consumeSuggestionResult, createRuntimeExtras, createThreadMappingId, fromThreadMessageLike, generateErrorMessageId, generateId, getAutoStatus, getFileDataURL, getThreadData, getThreadMessageText, getThreadState, hasUpcomingMessage, httpUrlPattern, isAutoStatus, isCreateAttachment, isErrorMessageId, isJSONValue, isRecord, parseDataUrl, resolveToolApprovalResponse, shouldContinue, stableStringifyToolArgs, symbolInnerMessage, trackToolArgsKeyOrder, updateStatusReducer };
@@ -8,6 +8,7 @@ declare class AssistantFrameHost implements ModelContextProvider {
8
8
  private _requestCounter;
9
9
  private _iframeWindow;
10
10
  private _targetOrigin;
11
+ private _disposed;
11
12
  constructor(iframeWindow: Window, targetOrigin?: string);
12
13
  private handleMessage;
13
14
  private updateContext;
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","names":[],"sources":["../../../src/model-context/frame/host.ts"],"mappings":";;;cA0Ca,8BAA8B;UACjC;UACA;UACA;UAOA;UACA;UACA;cAEI,cAAc,QAAQ;UAU1B;UA6BA;UAmBA;UAaA;UAqCA;UAYA;EAIR,mBAAmB;EAInB,UAAU,uBAAuB;EAKjC"}
1
+ {"version":3,"file":"host.d.ts","names":[],"sources":["../../../src/model-context/frame/host.ts"],"mappings":";;;cA0Ca,8BAA8B;UACjC;UACA;UACA;UAOA;UACA;UACA;UACA;EAEI,YAAA,cAAc,QAAQ;UAU1B;UA6BA;UAmBA;UAaA;UAyCA;UAYA;EAIR,mBAAmB;EAInB,UAAU,uBAAuB;EAKjC"}
@@ -23,6 +23,7 @@ var AssistantFrameHost = class {
23
23
  _requestCounter = 0;
24
24
  _iframeWindow;
25
25
  _targetOrigin;
26
+ _disposed = false;
26
27
  constructor(iframeWindow, targetOrigin = "*") {
27
28
  this._iframeWindow = iframeWindow;
28
29
  this._targetOrigin = targetOrigin;
@@ -70,6 +71,7 @@ var AssistantFrameHost = class {
70
71
  }, 3e4, `Tool call "${toolName}" timed out`);
71
72
  }
72
73
  sendRequest(message, timeout = 3e4, timeoutMessage = "Request timed out") {
74
+ if (this._disposed) return Promise.reject(/* @__PURE__ */ new Error("AssistantFrameHost has been disposed"));
73
75
  return new Promise((resolve, reject) => {
74
76
  this._pendingRequests.set(message.id, {
75
77
  resolve,
@@ -117,8 +119,11 @@ var AssistantFrameHost = class {
117
119
  return () => this._subscribers.delete(callback);
118
120
  }
119
121
  dispose() {
122
+ this._disposed = true;
120
123
  window.removeEventListener("message", this.handleMessage);
121
124
  this._subscribers.clear();
125
+ const error = /* @__PURE__ */ new Error("AssistantFrameHost has been disposed");
126
+ for (const pending of this._pendingRequests.values()) pending.reject(error);
122
127
  this._pendingRequests.clear();
123
128
  }
124
129
  };
@@ -1 +1 @@
1
- {"version":3,"file":"host.js","names":["ModelContextProvider","ModelContext","Unsubscribe","Tool","FrameMessage","FRAME_MESSAGE_CHANNEL","SerializedModelContext","SerializedTool","deserializeTool","serializedTool","parameters","description","disabled","undefined","type","deserializeModelContext","serialized","system","tools","Object","fromEntries","entries","map","name","tool","AssistantFrameHost","_context","_subscribers","Set","_pendingRequests","Map","resolve","value","reject","error","_requestCounter","_iframeWindow","Window","_targetOrigin","constructor","iframeWindow","targetOrigin","handleMessage","bind","window","addEventListener","requestContext","event","MessageEvent","origin","source","data","channel","message","updateContext","context","pending","get","id","Error","result","delete","serializedContext","execute","args","callTool","notifySubscribers","toolName","Promise","sendRequest","T","timeout","timeoutMessage","set","postMessage","timeoutId","setTimeout","originalResolve","originalReject","clearTimeout","forEach","callback","getModelContext","subscribe","add","dispose","removeEventListener","clear"],"sources":["../../../src/model-context/frame/host.ts"],"sourcesContent":["import type { ModelContextProvider, ModelContext } from \"../types\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { Tool } from \"assistant-stream\";\nimport {\n type FrameMessage,\n FRAME_MESSAGE_CHANNEL,\n type SerializedModelContext,\n type SerializedTool,\n} from \"./types\";\n\n/**\n * Deserializes tools from JSON Schema format back to Tool objects\n */\nconst deserializeTool = (serializedTool: SerializedTool): Tool<any, any> =>\n ({\n parameters: serializedTool.parameters,\n ...(serializedTool.description && {\n description: serializedTool.description,\n }),\n ...(serializedTool.disabled !== undefined && {\n disabled: serializedTool.disabled,\n }),\n ...(serializedTool.type && { type: serializedTool.type }),\n }) as Tool<any, any>;\n\n/**\n * Deserializes a ModelContext from transmission format\n */\nconst deserializeModelContext = (\n serialized: SerializedModelContext,\n): ModelContext => ({\n ...(serialized.system !== undefined && { system: serialized.system }),\n ...(serialized.tools && {\n tools: Object.fromEntries(\n Object.entries(serialized.tools).map(([name, tool]) => [\n name,\n deserializeTool(tool),\n ]),\n ),\n }),\n});\n\nexport class AssistantFrameHost implements ModelContextProvider {\n private _context: ModelContext = {};\n private _subscribers = new Set<() => void>();\n private _pendingRequests = new Map<\n string,\n {\n resolve: (value: any) => void;\n reject: (error: any) => void;\n }\n >();\n private _requestCounter = 0;\n private _iframeWindow: Window;\n private _targetOrigin: string;\n\n constructor(iframeWindow: Window, targetOrigin: string = \"*\") {\n this._iframeWindow = iframeWindow;\n this._targetOrigin = targetOrigin;\n\n this.handleMessage = this.handleMessage.bind(this);\n window.addEventListener(\"message\", this.handleMessage);\n\n this.requestContext();\n }\n\n private handleMessage(event: MessageEvent) {\n if (this._targetOrigin !== \"*\" && event.origin !== this._targetOrigin)\n return;\n if (event.source !== this._iframeWindow) return;\n if (event.data?.channel !== FRAME_MESSAGE_CHANNEL) return;\n\n const message = event.data.message as FrameMessage;\n\n switch (message.type) {\n case \"model-context-update\": {\n this.updateContext(message.context);\n break;\n }\n\n case \"tool-result\": {\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n if (message.error) {\n pending.reject(new Error(message.error));\n } else {\n pending.resolve(message.result);\n }\n this._pendingRequests.delete(message.id);\n }\n break;\n }\n }\n }\n\n private updateContext(serializedContext: SerializedModelContext) {\n const context = deserializeModelContext(serializedContext);\n this._context = {\n ...context,\n tools:\n context.tools &&\n Object.fromEntries(\n Object.entries(context.tools).map(([name, tool]) => [\n name,\n {\n ...tool,\n execute: (args: any) => this.callTool(name, args),\n } as Tool<any, any>,\n ]),\n ),\n };\n this.notifySubscribers();\n }\n\n private callTool(toolName: string, args: any): Promise<any> {\n return this.sendRequest(\n {\n type: \"tool-call\",\n id: `tool-${this._requestCounter++}`,\n toolName,\n args,\n },\n 30000,\n `Tool call \"${toolName}\" timed out`,\n );\n }\n\n private sendRequest<T extends FrameMessage & { id: string }>(\n message: T,\n timeout = 30000,\n timeoutMessage = \"Request timed out\",\n ): Promise<any> {\n return new Promise((resolve, reject) => {\n this._pendingRequests.set(message.id, { resolve, reject });\n\n this._iframeWindow.postMessage(\n { channel: FRAME_MESSAGE_CHANNEL, message },\n this._targetOrigin,\n );\n\n const timeoutId = setTimeout(() => {\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n pending.reject(new Error(timeoutMessage));\n this._pendingRequests.delete(message.id);\n }\n }, timeout);\n\n const originalResolve = this._pendingRequests.get(message.id)!.resolve;\n const originalReject = this._pendingRequests.get(message.id)!.reject;\n\n this._pendingRequests.set(message.id, {\n resolve: (value: any) => {\n clearTimeout(timeoutId);\n originalResolve(value);\n },\n reject: (error: any) => {\n clearTimeout(timeoutId);\n originalReject(error);\n },\n });\n });\n }\n\n private requestContext() {\n this._iframeWindow.postMessage(\n {\n channel: FRAME_MESSAGE_CHANNEL,\n message: {\n type: \"model-context-request\",\n } as FrameMessage,\n },\n this._targetOrigin,\n );\n }\n\n private notifySubscribers() {\n this._subscribers.forEach((callback) => callback());\n }\n\n getModelContext(): ModelContext {\n return this._context;\n }\n\n subscribe(callback: () => void): Unsubscribe {\n this._subscribers.add(callback);\n return () => this._subscribers.delete(callback);\n }\n\n dispose() {\n window.removeEventListener(\"message\", this.handleMessage);\n this._subscribers.clear();\n this._pendingRequests.clear();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"host.js","names":["ModelContextProvider","ModelContext","Unsubscribe","Tool","FrameMessage","FRAME_MESSAGE_CHANNEL","SerializedModelContext","SerializedTool","deserializeTool","serializedTool","parameters","description","disabled","undefined","type","deserializeModelContext","serialized","system","tools","Object","fromEntries","entries","map","name","tool","AssistantFrameHost","_context","_subscribers","Set","_pendingRequests","Map","resolve","value","reject","error","_requestCounter","_iframeWindow","Window","_targetOrigin","_disposed","constructor","iframeWindow","targetOrigin","handleMessage","bind","window","addEventListener","requestContext","event","MessageEvent","origin","source","data","channel","message","updateContext","context","pending","get","id","Error","result","delete","serializedContext","execute","args","callTool","notifySubscribers","toolName","Promise","sendRequest","T","timeout","timeoutMessage","set","postMessage","timeoutId","setTimeout","originalResolve","originalReject","clearTimeout","forEach","callback","getModelContext","subscribe","add","dispose","removeEventListener","clear","values"],"sources":["../../../src/model-context/frame/host.ts"],"sourcesContent":["import type { ModelContextProvider, ModelContext } from \"../types\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { Tool } from \"assistant-stream\";\nimport {\n type FrameMessage,\n FRAME_MESSAGE_CHANNEL,\n type SerializedModelContext,\n type SerializedTool,\n} from \"./types\";\n\n/**\n * Deserializes tools from JSON Schema format back to Tool objects\n */\nconst deserializeTool = (serializedTool: SerializedTool): Tool<any, any> =>\n ({\n parameters: serializedTool.parameters,\n ...(serializedTool.description && {\n description: serializedTool.description,\n }),\n ...(serializedTool.disabled !== undefined && {\n disabled: serializedTool.disabled,\n }),\n ...(serializedTool.type && { type: serializedTool.type }),\n }) as Tool<any, any>;\n\n/**\n * Deserializes a ModelContext from transmission format\n */\nconst deserializeModelContext = (\n serialized: SerializedModelContext,\n): ModelContext => ({\n ...(serialized.system !== undefined && { system: serialized.system }),\n ...(serialized.tools && {\n tools: Object.fromEntries(\n Object.entries(serialized.tools).map(([name, tool]) => [\n name,\n deserializeTool(tool),\n ]),\n ),\n }),\n});\n\nexport class AssistantFrameHost implements ModelContextProvider {\n private _context: ModelContext = {};\n private _subscribers = new Set<() => void>();\n private _pendingRequests = new Map<\n string,\n {\n resolve: (value: any) => void;\n reject: (error: any) => void;\n }\n >();\n private _requestCounter = 0;\n private _iframeWindow: Window;\n private _targetOrigin: string;\n private _disposed = false;\n\n constructor(iframeWindow: Window, targetOrigin: string = \"*\") {\n this._iframeWindow = iframeWindow;\n this._targetOrigin = targetOrigin;\n\n this.handleMessage = this.handleMessage.bind(this);\n window.addEventListener(\"message\", this.handleMessage);\n\n this.requestContext();\n }\n\n private handleMessage(event: MessageEvent) {\n if (this._targetOrigin !== \"*\" && event.origin !== this._targetOrigin)\n return;\n if (event.source !== this._iframeWindow) return;\n if (event.data?.channel !== FRAME_MESSAGE_CHANNEL) return;\n\n const message = event.data.message as FrameMessage;\n\n switch (message.type) {\n case \"model-context-update\": {\n this.updateContext(message.context);\n break;\n }\n\n case \"tool-result\": {\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n if (message.error) {\n pending.reject(new Error(message.error));\n } else {\n pending.resolve(message.result);\n }\n this._pendingRequests.delete(message.id);\n }\n break;\n }\n }\n }\n\n private updateContext(serializedContext: SerializedModelContext) {\n const context = deserializeModelContext(serializedContext);\n this._context = {\n ...context,\n tools:\n context.tools &&\n Object.fromEntries(\n Object.entries(context.tools).map(([name, tool]) => [\n name,\n {\n ...tool,\n execute: (args: any) => this.callTool(name, args),\n } as Tool<any, any>,\n ]),\n ),\n };\n this.notifySubscribers();\n }\n\n private callTool(toolName: string, args: any): Promise<any> {\n return this.sendRequest(\n {\n type: \"tool-call\",\n id: `tool-${this._requestCounter++}`,\n toolName,\n args,\n },\n 30000,\n `Tool call \"${toolName}\" timed out`,\n );\n }\n\n private sendRequest<T extends FrameMessage & { id: string }>(\n message: T,\n timeout = 30000,\n timeoutMessage = \"Request timed out\",\n ): Promise<any> {\n if (this._disposed) {\n return Promise.reject(new Error(\"AssistantFrameHost has been disposed\"));\n }\n\n return new Promise((resolve, reject) => {\n this._pendingRequests.set(message.id, { resolve, reject });\n\n this._iframeWindow.postMessage(\n { channel: FRAME_MESSAGE_CHANNEL, message },\n this._targetOrigin,\n );\n\n const timeoutId = setTimeout(() => {\n const pending = this._pendingRequests.get(message.id);\n if (pending) {\n pending.reject(new Error(timeoutMessage));\n this._pendingRequests.delete(message.id);\n }\n }, timeout);\n\n const originalResolve = this._pendingRequests.get(message.id)!.resolve;\n const originalReject = this._pendingRequests.get(message.id)!.reject;\n\n this._pendingRequests.set(message.id, {\n resolve: (value: any) => {\n clearTimeout(timeoutId);\n originalResolve(value);\n },\n reject: (error: any) => {\n clearTimeout(timeoutId);\n originalReject(error);\n },\n });\n });\n }\n\n private requestContext() {\n this._iframeWindow.postMessage(\n {\n channel: FRAME_MESSAGE_CHANNEL,\n message: {\n type: \"model-context-request\",\n } as FrameMessage,\n },\n this._targetOrigin,\n );\n }\n\n private notifySubscribers() {\n this._subscribers.forEach((callback) => callback());\n }\n\n getModelContext(): ModelContext {\n return this._context;\n }\n\n subscribe(callback: () => void): Unsubscribe {\n this._subscribers.add(callback);\n return () => this._subscribers.delete(callback);\n }\n\n dispose() {\n this._disposed = true;\n window.removeEventListener(\"message\", this.handleMessage);\n this._subscribers.clear();\n const error = new Error(\"AssistantFrameHost has been disposed\");\n for (const pending of this._pendingRequests.values()) {\n pending.reject(error);\n }\n this._pendingRequests.clear();\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","names":[],"sources":["../../../src/model-context/frame/provider.ts"],"mappings":";;;cA+Ba;iBACI;UAEP;UACA;UAIA;UAED;iBAQQ;UASP;UAqBM;UAoCN;UAOA;UAkBA;SAcD,wBACL,UAAU,sBACV,wBACC;SAmBI"}
1
+ {"version":3,"file":"provider.d.ts","names":[],"sources":["../../../src/model-context/frame/provider.ts"],"mappings":";;;cA+Ba;iBACI;UAEP;UACA;UAIA;UAED;iBAQQ;UASP;UAsBM;UAoCN;UAOA;UAkBA;SAcD,wBACL,UAAU,sBACV,wBACC;SAmBI"}
@@ -28,6 +28,7 @@ var AssistantFrameProvider = class AssistantFrameProvider {
28
28
  }
29
29
  handleMessage(event) {
30
30
  if (this._targetOrigin !== "*" && event.origin !== this._targetOrigin) return;
31
+ if (event.source !== window.parent) return;
31
32
  if (event.data?.channel !== "assistant-ui-frame") return;
32
33
  const message = event.data.message;
33
34
  switch (message.type) {
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","names":["ModelContextProvider","ModelContext","Unsubscribe","Tool","toJSONSchema","FrameMessage","FRAME_MESSAGE_CHANNEL","SerializedModelContext","SerializedTool","serializeTool","tool","description","parameters","undefined","disabled","type","serializeModelContext","context","system","tools","Object","fromEntries","entries","map","name","AssistantFrameProvider","_instance","_providers","Set","_providerUnsubscribes","Map","_targetOrigin","constructor","targetOrigin","handleMessage","bind","window","addEventListener","setTimeout","broadcastUpdate","getInstance","event","MessageEvent","origin","data","channel","message","sendMessage","getModelContext","handleToolCall","Extract","toolName","result","error","execute","args","toolCallId","id","abortSignal","AbortController","signal","human","Error","e","String","source","postMessage","contexts","Array","from","p","reduce","merged","parent","updateMessage","addModelContextProvider","provider","instance","add","unsubscribe","subscribe","set","delete","get","dispose","removeEventListener","forEach","clear"],"sources":["../../../src/model-context/frame/provider.ts"],"sourcesContent":["import type { ModelContextProvider, ModelContext } from \"../types\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport { type Tool, toJSONSchema } from \"assistant-stream\";\nimport {\n type FrameMessage,\n FRAME_MESSAGE_CHANNEL,\n type SerializedModelContext,\n type SerializedTool,\n} from \"./types\";\n\nconst serializeTool = (tool: Tool<any, any>): SerializedTool => ({\n ...(tool.description && { description: tool.description }),\n parameters: tool.parameters ? toJSONSchema(tool.parameters) : undefined,\n ...(tool.disabled !== undefined && { disabled: tool.disabled }),\n ...(tool.type && { type: tool.type }),\n});\n\nconst serializeModelContext = (\n context: ModelContext,\n): SerializedModelContext => ({\n ...(context.system !== undefined && { system: context.system }),\n ...(context.tools && {\n tools: Object.fromEntries(\n Object.entries(context.tools).map(([name, tool]) => [\n name,\n serializeTool(tool),\n ]),\n ),\n }),\n});\n\nexport class AssistantFrameProvider {\n private static _instance: AssistantFrameProvider | null = null;\n\n private _providers = new Set<ModelContextProvider>();\n private _providerUnsubscribes = new Map<\n ModelContextProvider,\n Unsubscribe | undefined\n >();\n private _targetOrigin: string;\n\n private constructor(targetOrigin: string = \"*\") {\n this._targetOrigin = targetOrigin;\n this.handleMessage = this.handleMessage.bind(this);\n window.addEventListener(\"message\", this.handleMessage);\n\n setTimeout(() => this.broadcastUpdate(), 0);\n }\n\n private static getInstance(targetOrigin?: string): AssistantFrameProvider {\n if (!AssistantFrameProvider._instance) {\n AssistantFrameProvider._instance = new AssistantFrameProvider(\n targetOrigin,\n );\n }\n return AssistantFrameProvider._instance;\n }\n\n private handleMessage(event: MessageEvent) {\n if (this._targetOrigin !== \"*\" && event.origin !== this._targetOrigin)\n return;\n if (event.data?.channel !== FRAME_MESSAGE_CHANNEL) return;\n\n const message = event.data.message as FrameMessage;\n\n switch (message.type) {\n case \"model-context-request\":\n this.sendMessage(event, {\n type: \"model-context-update\",\n context: serializeModelContext(this.getModelContext()),\n });\n break;\n\n case \"tool-call\":\n this.handleToolCall(message, event);\n break;\n }\n }\n\n private async handleToolCall(\n message: Extract<FrameMessage, { type: \"tool-call\" }>,\n event: MessageEvent,\n ) {\n const tool = this.getModelContext().tools?.[message.toolName];\n\n let result: any;\n let error: string | undefined;\n\n if (!tool) {\n error = `Tool \"${message.toolName}\" not found`;\n } else {\n try {\n result = tool.execute\n ? await tool.execute(message.args, {\n toolCallId: message.id,\n abortSignal: new AbortController().signal,\n human: async () => {\n throw new Error(\n \"Tool human input is not supported in frame context\",\n );\n },\n })\n : undefined;\n } catch (e) {\n error = e instanceof Error ? e.message : String(e);\n }\n }\n\n this.sendMessage(event, {\n type: \"tool-result\",\n id: message.id,\n ...(error ? { error } : { result }),\n });\n }\n\n private sendMessage(event: MessageEvent, message: FrameMessage) {\n event.source?.postMessage(\n { channel: FRAME_MESSAGE_CHANNEL, message },\n { targetOrigin: event.origin },\n );\n }\n\n private getModelContext(): ModelContext {\n const contexts = Array.from(this._providers).map((p) =>\n p.getModelContext(),\n );\n\n return contexts.reduce(\n (merged, context) => ({\n system: context.system\n ? merged.system\n ? `${merged.system}\\n\\n${context.system}`\n : context.system\n : merged.system,\n tools: { ...(merged.tools || {}), ...(context.tools || {}) },\n }),\n {} as ModelContext,\n );\n }\n\n private broadcastUpdate() {\n if (window.parent && window.parent !== window) {\n const updateMessage: FrameMessage = {\n type: \"model-context-update\",\n context: serializeModelContext(this.getModelContext()),\n };\n\n window.parent.postMessage(\n { channel: FRAME_MESSAGE_CHANNEL, message: updateMessage },\n this._targetOrigin,\n );\n }\n }\n\n static addModelContextProvider(\n provider: ModelContextProvider,\n targetOrigin?: string,\n ): Unsubscribe {\n const instance = AssistantFrameProvider.getInstance(targetOrigin);\n instance._providers.add(provider);\n\n const unsubscribe = provider.subscribe?.(() => instance.broadcastUpdate());\n if (unsubscribe) {\n instance._providerUnsubscribes.set(provider, unsubscribe);\n }\n\n instance.broadcastUpdate();\n\n return () => {\n instance._providers.delete(provider);\n instance._providerUnsubscribes.get(provider)?.();\n instance._providerUnsubscribes.delete(provider);\n instance.broadcastUpdate();\n };\n }\n\n static dispose() {\n if (AssistantFrameProvider._instance) {\n const instance = AssistantFrameProvider._instance;\n window.removeEventListener(\"message\", instance.handleMessage);\n\n instance._providerUnsubscribes.forEach((unsubscribe) => unsubscribe?.());\n instance._providerUnsubscribes.clear();\n instance._providers.clear();\n\n AssistantFrameProvider._instance = null;\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"provider.js","names":["ModelContextProvider","ModelContext","Unsubscribe","Tool","toJSONSchema","FrameMessage","FRAME_MESSAGE_CHANNEL","SerializedModelContext","SerializedTool","serializeTool","tool","description","parameters","undefined","disabled","type","serializeModelContext","context","system","tools","Object","fromEntries","entries","map","name","AssistantFrameProvider","_instance","_providers","Set","_providerUnsubscribes","Map","_targetOrigin","constructor","targetOrigin","handleMessage","bind","window","addEventListener","setTimeout","broadcastUpdate","getInstance","event","MessageEvent","origin","source","parent","data","channel","message","sendMessage","getModelContext","handleToolCall","Extract","toolName","result","error","execute","args","toolCallId","id","abortSignal","AbortController","signal","human","Error","e","String","postMessage","contexts","Array","from","p","reduce","merged","updateMessage","addModelContextProvider","provider","instance","add","unsubscribe","subscribe","set","delete","get","dispose","removeEventListener","forEach","clear"],"sources":["../../../src/model-context/frame/provider.ts"],"sourcesContent":["import type { ModelContextProvider, ModelContext } from \"../types\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport { type Tool, toJSONSchema } from \"assistant-stream\";\nimport {\n type FrameMessage,\n FRAME_MESSAGE_CHANNEL,\n type SerializedModelContext,\n type SerializedTool,\n} from \"./types\";\n\nconst serializeTool = (tool: Tool<any, any>): SerializedTool => ({\n ...(tool.description && { description: tool.description }),\n parameters: tool.parameters ? toJSONSchema(tool.parameters) : undefined,\n ...(tool.disabled !== undefined && { disabled: tool.disabled }),\n ...(tool.type && { type: tool.type }),\n});\n\nconst serializeModelContext = (\n context: ModelContext,\n): SerializedModelContext => ({\n ...(context.system !== undefined && { system: context.system }),\n ...(context.tools && {\n tools: Object.fromEntries(\n Object.entries(context.tools).map(([name, tool]) => [\n name,\n serializeTool(tool),\n ]),\n ),\n }),\n});\n\nexport class AssistantFrameProvider {\n private static _instance: AssistantFrameProvider | null = null;\n\n private _providers = new Set<ModelContextProvider>();\n private _providerUnsubscribes = new Map<\n ModelContextProvider,\n Unsubscribe | undefined\n >();\n private _targetOrigin: string;\n\n private constructor(targetOrigin: string = \"*\") {\n this._targetOrigin = targetOrigin;\n this.handleMessage = this.handleMessage.bind(this);\n window.addEventListener(\"message\", this.handleMessage);\n\n setTimeout(() => this.broadcastUpdate(), 0);\n }\n\n private static getInstance(targetOrigin?: string): AssistantFrameProvider {\n if (!AssistantFrameProvider._instance) {\n AssistantFrameProvider._instance = new AssistantFrameProvider(\n targetOrigin,\n );\n }\n return AssistantFrameProvider._instance;\n }\n\n private handleMessage(event: MessageEvent) {\n if (this._targetOrigin !== \"*\" && event.origin !== this._targetOrigin)\n return;\n if (event.source !== window.parent) return;\n if (event.data?.channel !== FRAME_MESSAGE_CHANNEL) return;\n\n const message = event.data.message as FrameMessage;\n\n switch (message.type) {\n case \"model-context-request\":\n this.sendMessage(event, {\n type: \"model-context-update\",\n context: serializeModelContext(this.getModelContext()),\n });\n break;\n\n case \"tool-call\":\n this.handleToolCall(message, event);\n break;\n }\n }\n\n private async handleToolCall(\n message: Extract<FrameMessage, { type: \"tool-call\" }>,\n event: MessageEvent,\n ) {\n const tool = this.getModelContext().tools?.[message.toolName];\n\n let result: any;\n let error: string | undefined;\n\n if (!tool) {\n error = `Tool \"${message.toolName}\" not found`;\n } else {\n try {\n result = tool.execute\n ? await tool.execute(message.args, {\n toolCallId: message.id,\n abortSignal: new AbortController().signal,\n human: async () => {\n throw new Error(\n \"Tool human input is not supported in frame context\",\n );\n },\n })\n : undefined;\n } catch (e) {\n error = e instanceof Error ? e.message : String(e);\n }\n }\n\n this.sendMessage(event, {\n type: \"tool-result\",\n id: message.id,\n ...(error ? { error } : { result }),\n });\n }\n\n private sendMessage(event: MessageEvent, message: FrameMessage) {\n event.source?.postMessage(\n { channel: FRAME_MESSAGE_CHANNEL, message },\n { targetOrigin: event.origin },\n );\n }\n\n private getModelContext(): ModelContext {\n const contexts = Array.from(this._providers).map((p) =>\n p.getModelContext(),\n );\n\n return contexts.reduce(\n (merged, context) => ({\n system: context.system\n ? merged.system\n ? `${merged.system}\\n\\n${context.system}`\n : context.system\n : merged.system,\n tools: { ...(merged.tools || {}), ...(context.tools || {}) },\n }),\n {} as ModelContext,\n );\n }\n\n private broadcastUpdate() {\n if (window.parent && window.parent !== window) {\n const updateMessage: FrameMessage = {\n type: \"model-context-update\",\n context: serializeModelContext(this.getModelContext()),\n };\n\n window.parent.postMessage(\n { channel: FRAME_MESSAGE_CHANNEL, message: updateMessage },\n this._targetOrigin,\n );\n }\n }\n\n static addModelContextProvider(\n provider: ModelContextProvider,\n targetOrigin?: string,\n ): Unsubscribe {\n const instance = AssistantFrameProvider.getInstance(targetOrigin);\n instance._providers.add(provider);\n\n const unsubscribe = provider.subscribe?.(() => instance.broadcastUpdate());\n if (unsubscribe) {\n instance._providerUnsubscribes.set(provider, unsubscribe);\n }\n\n instance.broadcastUpdate();\n\n return () => {\n instance._providers.delete(provider);\n instance._providerUnsubscribes.get(provider)?.();\n instance._providerUnsubscribes.delete(provider);\n instance.broadcastUpdate();\n };\n }\n\n static dispose() {\n if (AssistantFrameProvider._instance) {\n const instance = AssistantFrameProvider._instance;\n window.removeEventListener(\"message\", instance.handleMessage);\n\n instance._providerUnsubscribes.forEach((unsubscribe) => unsubscribe?.());\n instance._providerUnsubscribes.clear();\n instance._providers.clear();\n\n AssistantFrameProvider._instance = null;\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"interactable-composer-metadata.js","names":["isJSONValueEqual","isJSONValue","isRecord","Unstable_InteractableSnapshotEntry","id","name","state","partial","SnapshotCarrierMessage","role","metadata","content","unstable_getInteractableSnapshots","message","undefined","custom","Record","items","interactables","Array","isArray","unstable_formatInteractableSnapshot","entry","JSON","stringify","interactableToolName","replace","getArrayItemId","item","applyArrayUpdate","prev","update","mintId","next","set","clear","remove","length","ids","Set","filter","has","patches","map","patch","find","candidate","add","added","shallowMergeInteractableState","options","arrayBaseline","idFactory","field","idKeyedFields","ReadonlySet","baseline","key","value","Object","entries","baseValue","shallowDiffInteractableState","known","keys","diff","changed","ToolCallLikePart","type","toolCallId","toolName","args","result","asToolCallPart","part","p","updateCallTargets","success","argsId","createAddedItemIdFactory","addedItemIds","idsByField","Map","stringIds","size","get","shift","Unstable_InteractableVersion","origin","versionsCache","WeakMap","unstable_getInteractableVersions","messages","byName","byId","cached","versions","current","msg","it","push","_id","findModelKnownState","last","gateInteractableComposerMetadata","meta","rest","gated","pending","process","env","NODE_ENV","console","warn"],"sources":["../../src/model-context/interactable-composer-metadata.ts"],"sourcesContent":["import { isJSONValueEqual } from \"../utils/json/is-json-equal\";\nimport { isJSONValue, isRecord } from \"../utils/json/is-json\";\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_InteractableSnapshotEntry = {\n id: string;\n name: string;\n state: unknown;\n /**\n * When true, `state` carries only the top-level fields that changed since\n * the model's last known state; omitted fields are unchanged. The first\n * snapshot of an instance is always full.\n */\n partial?: boolean | undefined;\n};\n\n/**\n * Minimal message shape needed to read snapshots and `update_*` tool calls out\n * of history. Structurally compatible with both `ThreadMessage` and the AI\n * SDK's `UIMessage`.\n */\ntype SnapshotCarrierMessage = {\n role: string;\n metadata?: unknown;\n content?: readonly unknown[] | undefined;\n};\n\n/**\n * Reads the interactable snapshots stamped on a message's\n * `metadata.custom.interactables`, or `undefined` if none. This is the read\n * half of the snapshot channel — integrations use it to surface interactable\n * state to the model (see `unstable_injectInteractableContext` in\n * `@assistant-ui/react-ai-sdk` for the AI SDK implementation).\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_getInteractableSnapshots(message: {\n metadata?: unknown;\n}): Unstable_InteractableSnapshotEntry[] | undefined {\n const metadata = message.metadata;\n if (!metadata || typeof metadata !== \"object\") return undefined;\n const custom = (metadata as Record<string, unknown>).custom;\n if (!custom || typeof custom !== \"object\") return undefined;\n const items = (custom as Record<string, unknown>).interactables;\n return Array.isArray(items)\n ? (items as Unstable_InteractableSnapshotEntry[])\n : undefined;\n}\n\n/**\n * Canonical model-facing wording for one snapshot entry.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_formatInteractableSnapshot(\n entry: Unstable_InteractableSnapshotEntry,\n): string {\n if (entry.partial) {\n return `[State of \"${entry.name}\" (id: ${JSON.stringify(entry.id)}) changed — updated fields: ${JSON.stringify(entry.state)}; fields not listed are unchanged]`;\n }\n return `[Current state of \"${entry.name}\" (id: ${JSON.stringify(entry.id)}): ${JSON.stringify(entry.state)}]`;\n}\n\n/** The model-facing tool name for an interactable `name`. One tool per name. */\nexport function interactableToolName(name: string): string {\n return `update_${name.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n}\n\nconst getArrayItemId = (item: unknown): string | number | undefined => {\n if (!isRecord(item)) return undefined;\n const id = item.id;\n return typeof id === \"string\" || typeof id === \"number\" ? id : undefined;\n};\n\nfunction applyArrayUpdate(\n prev: unknown[],\n update: Record<string, unknown>,\n mintId?: () => string | undefined,\n) {\n let next = Array.isArray(update.set) ? [...update.set] : [...prev];\n\n if (update.clear === true) next = [];\n\n if (Array.isArray(update.remove) && update.remove.length > 0) {\n const ids = new Set(update.remove);\n next = next.filter((item) => {\n const id = getArrayItemId(item);\n return id !== undefined ? !ids.has(id) : !ids.has(item);\n });\n }\n\n const patches = update.update;\n if (Array.isArray(patches) && patches.length > 0) {\n next = next.map((item) => {\n const id = getArrayItemId(item);\n if (id === undefined || !isRecord(item)) return item;\n const patch = patches.find(\n (candidate) => isRecord(candidate) && candidate.id === id,\n );\n return patch ? { ...item, ...patch } : item;\n });\n }\n\n if (Array.isArray(update.add) && update.add.length > 0) {\n const added = mintId\n ? update.add.map((item) => {\n if (!isRecord(item) || item.id !== undefined) return item;\n const id = mintId();\n return id === undefined ? item : { ...item, id };\n })\n : update.add;\n next = [...next, ...added];\n }\n\n return next;\n}\n\n/**\n * The merge `update_*` tools apply: top-level keys replace, rest preserved.\n * Array fields also accept operation objects (`add`, `update`, `remove`,\n * `clear`, `set`) so collection edits do not need a companion manage_* tool.\n */\nexport function shallowMergeInteractableState(\n prev: unknown,\n partial: unknown,\n options?:\n | {\n arrayBaseline?: unknown;\n /**\n * Supplies ids for added items in id-keyed array fields. The live\n * execute path mints fresh ids; history folds replay ids previously\n * returned by execute.\n */\n idFactory?: (field: string) => string | undefined;\n idKeyedFields?: ReadonlySet<string>;\n }\n | undefined,\n): unknown {\n if (!isRecord(prev) || !isRecord(partial)) return partial;\n const baseline = isRecord(options?.arrayBaseline)\n ? options.arrayBaseline\n : prev;\n const next = { ...prev };\n for (const [key, value] of Object.entries(partial)) {\n const baseValue = baseline[key];\n if (Array.isArray(baseValue) && isRecord(value)) {\n const mintId =\n options?.idFactory &&\n (options.idKeyedFields === undefined || options.idKeyedFields.has(key))\n ? () => options.idFactory?.(key)\n : undefined;\n next[key] = applyArrayUpdate(baseValue, value, mintId);\n } else {\n next[key] = value;\n }\n }\n return next;\n}\n\n/**\n * The top-level fields of `next` that differ from `known`, for stamping a\n * partial snapshot. Returns `undefined` when a partial stamp has no benefit:\n * the change is not expressible as a shallow merge (non-object states, or a\n * top-level key was removed), or every field changed anyway — the caller\n * falls back to a full snapshot.\n */\nfunction shallowDiffInteractableState(\n known: unknown,\n next: unknown,\n): Record<string, unknown> | undefined {\n if (!isRecord(known) || !isRecord(next)) return undefined;\n for (const key of Object.keys(known)) {\n if (!(key in next)) return undefined;\n }\n const diff: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(next)) {\n if (!(key in known) || !isJSONValueEqual(known[key], value)) {\n diff[key] = value;\n }\n }\n const changed = Object.keys(diff).length;\n if (changed === 0 || changed === Object.keys(next).length) return undefined;\n return diff;\n}\n\ntype ToolCallLikePart = {\n type?: string;\n toolCallId?: string;\n toolName?: string;\n args?: unknown;\n result?: unknown;\n};\n\nconst asToolCallPart = (part: unknown): ToolCallLikePart | undefined => {\n if (!part || typeof part !== \"object\") return undefined;\n const p = part as ToolCallLikePart;\n return p.type === \"tool-call\" ? p : undefined;\n};\n\n/** Whether an accepted `update_*` call addressed instance `id`. */\nconst updateCallTargets = (p: ToolCallLikePart, id: string): boolean => {\n if (!p.args || typeof p.args !== \"object\") return false;\n const result = isRecord(p.result) ? p.result : undefined;\n if (result?.success === false) return false;\n if (typeof result?.id === \"string\") return result.id === id;\n const argsId = (p.args as Record<string, unknown>).id;\n return argsId === id || argsId === undefined;\n};\n\nconst createAddedItemIdFactory = (result: unknown) => {\n const value = isRecord(result) ? result.addedItemIds : undefined;\n if (!isRecord(value)) return undefined;\n\n const idsByField = new Map<string, string[]>();\n for (const [field, ids] of Object.entries(value)) {\n if (!Array.isArray(ids)) continue;\n const stringIds = ids.filter(\n (item): item is string => typeof item === \"string\",\n );\n if (stringIds.length > 0) idsByField.set(field, stringIds);\n }\n if (idsByField.size === 0) return undefined;\n\n return (field: string) => idsByField.get(field)?.shift();\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_InteractableVersion = {\n /** The full state as of this version. */\n state: unknown;\n origin: \"create\" | \"update\" | \"user-edit\";\n /** For create/update versions, the tool call that produced this version. */\n toolCallId?: string | undefined;\n};\n\n// Without this, every mounted anchor re-folds the whole thread on each streaming\n// token, since the repository hands out a new messages array per token.\nconst versionsCache = new WeakMap<\n readonly SnapshotCarrierMessage[],\n Map<string, Map<string, Unstable_InteractableVersion[]>>\n>();\n\n/**\n * Every version of interactable `id` recorded in the thread, oldest first,\n * folded chronologically:\n *\n * - the tool call whose `toolCallId` equals `id` seeds the baseline with its\n * args (`origin: \"create\"`) — the `id: toolCallId` convention for\n * tool-created interactables,\n * - a snapshot stamped on a user message is a `\"user-edit\"` version (a full\n * snapshot replaces the state; a partial one shallow-merges),\n * - each accepted `update_*` call shallow-merges an `\"update\"` version.\n *\n * The last entry is the state the model knows. Partial snapshots and update\n * calls with no baseline to merge into are skipped.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_getInteractableVersions(\n messages: readonly SnapshotCarrierMessage[],\n id: string,\n name: string,\n): Unstable_InteractableVersion[] {\n let byName = versionsCache.get(messages);\n if (!byName) {\n byName = new Map();\n versionsCache.set(messages, byName);\n }\n let byId = byName.get(name);\n if (!byId) {\n byId = new Map();\n byName.set(name, byId);\n }\n const cached = byId.get(id);\n if (cached) return cached;\n\n const toolName = interactableToolName(name);\n const versions: Unstable_InteractableVersion[] = [];\n const current = () => versions[versions.length - 1];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n const entry = unstable_getInteractableSnapshots(msg)?.find(\n (it) => it.id === id,\n );\n if (!entry) continue;\n if (entry.partial) {\n const prev = current();\n if (prev) {\n versions.push({\n state: shallowMergeInteractableState(prev.state, entry.state),\n origin: \"user-edit\",\n });\n }\n } else {\n versions.push({ state: entry.state, origin: \"user-edit\" });\n }\n continue;\n }\n\n if (msg.role !== \"assistant\") continue;\n for (const part of msg.content ?? []) {\n const p = asToolCallPart(part);\n if (!p) continue;\n if (p.toolCallId === id && p.toolName === name) {\n if (p.args && typeof p.args === \"object\") {\n versions.push({ state: p.args, origin: \"create\", toolCallId: id });\n }\n } else if (p.toolName === toolName && updateCallTargets(p, id)) {\n const prev = current();\n if (prev) {\n const { id: _id, ...partial } = p.args as Record<string, unknown>;\n const idFactory = createAddedItemIdFactory(p.result);\n versions.push({\n state: idFactory\n ? shallowMergeInteractableState(prev.state, partial, {\n idFactory,\n })\n : shallowMergeInteractableState(prev.state, partial),\n origin: \"update\",\n toolCallId: p.toolCallId,\n });\n }\n }\n }\n }\n byId.set(id, versions);\n return versions;\n}\n\n/**\n * The state the model knows for interactable `id` — its latest recorded\n * version, or `undefined` when no baseline exists yet.\n */\nexport function findModelKnownState(\n messages: readonly SnapshotCarrierMessage[],\n id: string,\n name: string,\n): { state: unknown } | undefined {\n const versions = unstable_getInteractableVersions(messages, id, name);\n const last = versions[versions.length - 1];\n return last ? { state: last.state } : undefined;\n}\n\n/**\n * Snapshot gate. Stamps an interactable only when the model doesn't already\n * know its state (no baseline yet, or the live state differs from the folded\n * thread record). A change that fits a shallow merge is stamped as a partial\n * snapshot carrying just the changed fields; otherwise the full state is\n * stamped. Other metadata keys pass through untouched.\n */\nexport function gateInteractableComposerMetadata(\n meta: Record<string, unknown> | undefined,\n messages: readonly SnapshotCarrierMessage[],\n): Record<string, unknown> | undefined {\n if (!meta) return undefined;\n const { interactables, ...rest } = meta as {\n interactables?: Unstable_InteractableSnapshotEntry[];\n } & Record<string, unknown>;\n\n const gated: Record<string, unknown> = { ...rest };\n if (Array.isArray(interactables)) {\n const pending: Unstable_InteractableSnapshotEntry[] = [];\n for (const it of interactables) {\n if (process.env.NODE_ENV !== \"production\" && !isJSONValue(it.state)) {\n console.warn(\n `[Interactables] state for \"${it.name}\" (${it.id}) is not JSON-equatable ` +\n `(an undefined, NaN, Infinity, function, or symbol value?). It will be ` +\n `re-snapshotted on every send, recreating per-message growth. Use plain ` +\n `JSON values.`,\n );\n }\n const known = findModelKnownState(messages, it.id, it.name);\n if (!known) {\n pending.push({ id: it.id, name: it.name, state: it.state });\n continue;\n }\n if (isJSONValueEqual(it.state, known.state)) continue;\n const diff = shallowDiffInteractableState(known.state, it.state);\n pending.push(\n diff\n ? { id: it.id, name: it.name, state: diff, partial: true }\n : { id: it.id, name: it.name, state: it.state },\n );\n }\n if (pending.length) gated.interactables = pending;\n }\n return Object.keys(gated).length ? gated : undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"interactable-composer-metadata.js","names":["isJSONValueEqual","isJSONValue","isRecord","Unstable_InteractableSnapshotEntry","id","name","state","partial","SnapshotCarrierMessage","role","metadata","content","unstable_getInteractableSnapshots","message","undefined","custom","Record","items","interactables","Array","isArray","unstable_formatInteractableSnapshot","entry","JSON","stringify","interactableToolName","replace","getArrayItemId","item","applyArrayUpdate","prev","update","mintId","next","set","clear","remove","length","ids","Set","filter","has","patches","map","patch","find","candidate","add","added","shallowMergeInteractableState","options","arrayBaseline","idFactory","field","idKeyedFields","ReadonlySet","baseline","key","value","Object","entries","baseValue","shallowDiffInteractableState","known","keys","diff","changed","ToolCallLikePart","type","toolCallId","toolName","args","result","asToolCallPart","part","p","updateCallTargets","success","argsId","createAddedItemIdFactory","addedItemIds","idsByField","Map","stringIds","size","get","shift","Unstable_InteractableVersion","origin","versionsCache","WeakMap","unstable_getInteractableVersions","messages","byName","byId","cached","versions","current","msg","it","push","_id","findModelKnownState","last","gateInteractableComposerMetadata","meta","rest","gated","pending","process","env","NODE_ENV","console","warn"],"sources":["../../src/model-context/interactable-composer-metadata.ts"],"sourcesContent":["import { isJSONValueEqual } from \"../utils/json/is-json-equal\";\nimport { isJSONValue, isRecord } from \"../utils/json/is-json\";\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_InteractableSnapshotEntry = {\n id: string;\n name: string;\n state: unknown;\n /**\n * When true, `state` carries only the top-level fields that changed since\n * the model's last known state; omitted fields are unchanged. The first\n * snapshot of an instance is always full.\n */\n partial?: boolean | undefined;\n};\n\n/**\n * Minimal message shape needed to read snapshots and `update_*` tool calls out\n * of history. Structurally compatible with both `ThreadMessage` and the AI\n * SDK's `UIMessage`.\n */\ntype SnapshotCarrierMessage = {\n role: string;\n metadata?: unknown;\n content?: readonly unknown[] | undefined;\n};\n\n/**\n * Reads the interactable snapshots stamped on a message's\n * `metadata.custom.interactables`, or `undefined` if none. This is the read\n * half of the snapshot channel — integrations use it to surface interactable\n * state to the model (see `unstable_injectInteractableContext` in\n * `@assistant-ui/react-ai-sdk` for the AI SDK implementation).\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_getInteractableSnapshots(message: {\n metadata?: unknown;\n}): Unstable_InteractableSnapshotEntry[] | undefined {\n const metadata = message.metadata;\n if (!metadata || typeof metadata !== \"object\") return undefined;\n const custom = (metadata as Record<string, unknown>).custom;\n if (!custom || typeof custom !== \"object\") return undefined;\n const items = (custom as Record<string, unknown>).interactables;\n return Array.isArray(items)\n ? (items as Unstable_InteractableSnapshotEntry[])\n : undefined;\n}\n\n/**\n * Canonical model-facing wording for one snapshot entry.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_formatInteractableSnapshot(\n entry: Unstable_InteractableSnapshotEntry,\n): string {\n if (entry.partial) {\n return `[State of \"${entry.name}\" (id: ${JSON.stringify(entry.id)}) changed — updated fields: ${JSON.stringify(entry.state)}; fields not listed are unchanged]`;\n }\n return `[Current state of \"${entry.name}\" (id: ${JSON.stringify(entry.id)}): ${JSON.stringify(entry.state)}]`;\n}\n\n/** The model-facing tool name for an interactable `name`. One tool per name. */\nexport function interactableToolName(name: string): string {\n return `update_${name.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n}\n\nconst getArrayItemId = (item: unknown): string | number | undefined => {\n if (!isRecord(item)) return undefined;\n const id = item.id;\n return typeof id === \"string\" || typeof id === \"number\" ? id : undefined;\n};\n\nfunction applyArrayUpdate(\n prev: unknown[],\n update: Record<string, unknown>,\n mintId?: () => string | undefined,\n) {\n let next = Array.isArray(update.set) ? [...update.set] : [...prev];\n\n if (update.clear === true) next = [];\n\n if (Array.isArray(update.remove) && update.remove.length > 0) {\n const ids = new Set(update.remove);\n next = next.filter((item) => {\n const id = getArrayItemId(item);\n return id !== undefined ? !ids.has(id) : !ids.has(item);\n });\n }\n\n const patches = update.update;\n if (Array.isArray(patches) && patches.length > 0) {\n next = next.map((item) => {\n const id = getArrayItemId(item);\n if (id === undefined || !isRecord(item)) return item;\n const patch = patches.find(\n (candidate) => isRecord(candidate) && candidate.id === id,\n );\n return patch ? { ...item, ...patch } : item;\n });\n }\n\n if (Array.isArray(update.add) && update.add.length > 0) {\n const added = mintId\n ? update.add.map((item) => {\n if (!isRecord(item) || item.id !== undefined) return item;\n const id = mintId();\n return id === undefined ? item : { ...item, id };\n })\n : update.add;\n next = [...next, ...added];\n }\n\n return next;\n}\n\n/**\n * The merge `update_*` tools apply: top-level keys replace, rest preserved.\n * Array fields also accept operation objects (`add`, `update`, `remove`,\n * `clear`, `set`) so collection edits do not need a companion manage_* tool.\n */\nexport function shallowMergeInteractableState(\n prev: unknown,\n partial: unknown,\n options?:\n | {\n arrayBaseline?: unknown;\n /**\n * Supplies ids for added items in id-keyed array fields. The live\n * execute path mints fresh ids; history folds replay ids previously\n * returned by execute.\n */\n idFactory?: (field: string) => string | undefined;\n idKeyedFields?: ReadonlySet<string>;\n }\n | undefined,\n): unknown {\n if (!isRecord(prev) || !isRecord(partial)) return partial;\n const baseline = isRecord(options?.arrayBaseline)\n ? options.arrayBaseline\n : prev;\n const next = { ...prev };\n for (const [key, value] of Object.entries(partial)) {\n const baseValue = baseline[key];\n if (Array.isArray(baseValue) && isRecord(value)) {\n const mintId =\n options?.idFactory &&\n (options.idKeyedFields === undefined || options.idKeyedFields.has(key))\n ? () => options.idFactory?.(key)\n : undefined;\n next[key] = applyArrayUpdate(baseValue, value, mintId);\n } else {\n next[key] = value;\n }\n }\n return next;\n}\n\n/**\n * The top-level fields of `next` that differ from `known`, for stamping a\n * partial snapshot. Returns `undefined` when a partial stamp has no benefit:\n * the change is not expressible as a shallow merge (non-object states, or a\n * top-level key was removed), or every field changed anyway — the caller\n * falls back to a full snapshot.\n */\nfunction shallowDiffInteractableState(\n known: unknown,\n next: unknown,\n): Record<string, unknown> | undefined {\n if (!isRecord(known) || !isRecord(next)) return undefined;\n for (const key of Object.keys(known)) {\n if (!(key in next)) return undefined;\n }\n const diff: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(next)) {\n if (!(key in known) || !isJSONValueEqual(known[key], value)) {\n diff[key] = value;\n }\n }\n const changed = Object.keys(diff).length;\n if (changed === 0 || changed === Object.keys(next).length) return undefined;\n return diff;\n}\n\ntype ToolCallLikePart = {\n type?: string;\n toolCallId?: string;\n toolName?: string;\n args?: unknown;\n result?: unknown;\n};\n\nconst asToolCallPart = (part: unknown): ToolCallLikePart | undefined => {\n if (!part || typeof part !== \"object\") return undefined;\n const p = part as ToolCallLikePart;\n return p.type === \"tool-call\" ? p : undefined;\n};\n\n/** Whether an accepted `update_*` call addressed instance `id`. */\nconst updateCallTargets = (p: ToolCallLikePart, id: string): boolean => {\n if (!p.args || typeof p.args !== \"object\") return false;\n const result = isRecord(p.result) ? p.result : undefined;\n if (result?.success === false) return false;\n if (typeof result?.id === \"string\") return result.id === id;\n const argsId = (p.args as Record<string, unknown>).id;\n return argsId === id || argsId === undefined;\n};\n\nconst createAddedItemIdFactory = (result: unknown) => {\n const value = isRecord(result) ? result.addedItemIds : undefined;\n if (!isRecord(value)) return undefined;\n\n const idsByField = new Map<string, string[]>();\n for (const [field, ids] of Object.entries(value)) {\n if (!Array.isArray(ids)) continue;\n const stringIds = ids.filter(\n (item): item is string => typeof item === \"string\",\n );\n if (stringIds.length > 0) idsByField.set(field, stringIds);\n }\n if (idsByField.size === 0) return undefined;\n\n return (field: string) => idsByField.get(field)?.shift();\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_InteractableVersion = {\n /** The full state as of this version. */\n state: unknown;\n origin: \"create\" | \"update\" | \"user-edit\";\n /** For create/update versions, the tool call that produced this version. */\n toolCallId?: string | undefined;\n};\n\n// Without this, every mounted anchor re-folds the whole thread on each streaming\n// token, since the repository hands out a new messages array per token.\nconst versionsCache = new WeakMap<\n readonly SnapshotCarrierMessage[],\n Map<string, Map<string, Unstable_InteractableVersion[]>>\n>();\n\n/**\n * Every version of interactable `id` recorded in the thread, oldest first,\n * folded chronologically:\n *\n * - the tool call whose `toolCallId` equals `id` seeds the baseline with its\n * args (`origin: \"create\"`) — the `id: toolCallId` convention for\n * tool-created interactables,\n * - a snapshot stamped on a user message is a `\"user-edit\"` version (a full\n * snapshot replaces the state; a partial one shallow-merges),\n * - each accepted `update_*` call shallow-merges an `\"update\"` version.\n *\n * The last entry is the state the model knows. Partial snapshots and update\n * calls with no baseline to merge into are skipped.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport function unstable_getInteractableVersions(\n messages: readonly SnapshotCarrierMessage[],\n id: string,\n name: string,\n): Unstable_InteractableVersion[] {\n let byName = versionsCache.get(messages);\n if (!byName) {\n byName = new Map();\n versionsCache.set(messages, byName);\n }\n let byId = byName.get(name);\n if (!byId) {\n byId = new Map();\n byName.set(name, byId);\n }\n const cached = byId.get(id);\n if (cached) return cached;\n\n const toolName = interactableToolName(name);\n const versions: Unstable_InteractableVersion[] = [];\n const current = () => versions[versions.length - 1];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n const entry = unstable_getInteractableSnapshots(msg)?.find(\n (it) => it.id === id,\n );\n if (!entry) continue;\n if (entry.partial) {\n const prev = current();\n if (prev) {\n versions.push({\n state: shallowMergeInteractableState(prev.state, entry.state),\n origin: \"user-edit\",\n });\n }\n } else {\n versions.push({ state: entry.state, origin: \"user-edit\" });\n }\n continue;\n }\n\n if (msg.role !== \"assistant\") continue;\n for (const part of msg.content ?? []) {\n const p = asToolCallPart(part);\n if (!p) continue;\n if (p.toolCallId === id && p.toolName === name) {\n if (p.args && typeof p.args === \"object\") {\n versions.push({ state: p.args, origin: \"create\", toolCallId: id });\n }\n } else if (p.toolName === toolName && updateCallTargets(p, id)) {\n const prev = current();\n if (prev) {\n const { id: _id, ...partial } = p.args as Record<string, unknown>;\n const idFactory = createAddedItemIdFactory(p.result);\n versions.push({\n state: idFactory\n ? shallowMergeInteractableState(prev.state, partial, {\n idFactory,\n })\n : shallowMergeInteractableState(prev.state, partial),\n origin: \"update\",\n toolCallId: p.toolCallId,\n });\n }\n }\n }\n }\n byId.set(id, versions);\n return versions;\n}\n\n/**\n * The state the model knows for interactable `id` — its latest recorded\n * version, or `undefined` when no baseline exists yet.\n */\nexport function findModelKnownState(\n messages: readonly SnapshotCarrierMessage[],\n id: string,\n name: string,\n): { state: unknown } | undefined {\n const versions = unstable_getInteractableVersions(messages, id, name);\n const last = versions[versions.length - 1];\n return last ? { state: last.state } : undefined;\n}\n\n/**\n * Snapshot gate. Stamps an interactable only when the model doesn't already\n * know its state (no baseline yet, or the live state differs from the folded\n * thread record). A change that fits a shallow merge is stamped as a partial\n * snapshot carrying just the changed fields; otherwise the full state is\n * stamped. Other metadata keys pass through untouched.\n */\nexport function gateInteractableComposerMetadata(\n meta: Record<string, unknown> | undefined,\n messages: readonly SnapshotCarrierMessage[],\n): Record<string, unknown> | undefined {\n if (!meta) return undefined;\n const { interactables, ...rest } = meta as {\n interactables?: Unstable_InteractableSnapshotEntry[];\n } & Record<string, unknown>;\n\n const gated: Record<string, unknown> = { ...rest };\n if (Array.isArray(interactables)) {\n const pending: Unstable_InteractableSnapshotEntry[] = [];\n for (const it of interactables) {\n if (process.env.NODE_ENV !== \"production\" && !isJSONValue(it.state)) {\n console.warn(\n `[Interactables] state for \"${it.name}\" (${it.id}) is not JSON-equatable ` +\n `(an undefined, NaN, Infinity, function, or symbol value?). It will be ` +\n `re-snapshotted on every send, recreating per-message growth. Use plain ` +\n `JSON values.`,\n );\n }\n const known = findModelKnownState(messages, it.id, it.name);\n if (!known) {\n pending.push({ id: it.id, name: it.name, state: it.state });\n continue;\n }\n if (isJSONValueEqual(it.state, known.state)) continue;\n const diff = shallowDiffInteractableState(known.state, it.state);\n pending.push(\n diff\n ? { id: it.id, name: it.name, state: diff, partial: true }\n : { id: it.id, name: it.name, state: it.state },\n );\n }\n if (pending.length) gated.interactables = pending;\n }\n return Object.keys(gated).length ? gated : undefined;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantProvider.js","names":["memo","ComponentType","FC","PropsWithChildren","useAui","AuiProvider","AssistantClient","AssistantRuntime","AssistantRuntimeCore","RuntimeAdapter","getRenderComponent","runtime","_core","RenderComponent","AssistantProviderBaseProps","aui","AssistantProviderBase","parent","children","threads","inner"],"sources":["../../src/react/AssistantProvider.tsx"],"sourcesContent":["import {\n memo,\n type ComponentType,\n type FC,\n type PropsWithChildren,\n} from \"react\";\nimport { useAui, AuiProvider, type AssistantClient } from \"@assistant-ui/store\";\nimport type { AssistantRuntime } from \"../runtime/api/assistant-runtime\";\nimport type { AssistantRuntimeCore } from \"../runtime/interfaces/assistant-runtime-core\";\nimport { RuntimeAdapter } from \"./RuntimeAdapter\";\n\nexport const getRenderComponent = (runtime: AssistantRuntime) => {\n return (runtime as { _core?: AssistantRuntimeCore })._core\n ?.RenderComponent as ComponentType | undefined;\n};\n\nexport type AssistantProviderBaseProps = PropsWithChildren<{\n runtime: AssistantRuntime;\n aui?: AssistantClient | null;\n}>;\n\nexport const AssistantProviderBase: FC<AssistantProviderBaseProps> = memo(\n ({ runtime, aui: parent = null, children }) => {\n // The runtime has a stable identity but mutates in place: its options are\n // pushed in by an unconditional effect inside <RenderComponent />, so that\n // element must be re-created every commit for React to re-render it and\n // re-run the effect. React Compiler caches <RenderComponent /> on the\n // stable RenderComponent type, which silences the effect and stops option\n // changes (e.g. unstable_enableMessageQueue) from reaching the runtime.\n \"use no memo\";\n const aui = useAui({ threads: RuntimeAdapter(runtime) }, { parent });\n const RenderComponent = getRenderComponent(runtime);\n const inner = (\n <AuiProvider value={aui}>\n {RenderComponent && <RenderComponent />}\n {children}\n </AuiProvider>\n );\n if (!parent) return inner;\n return <AuiProvider value={parent}>{inner}</AuiProvider>;\n },\n);\n"],"mappings":";;;;;AAWA,MAAaU,sBAAsBC,YAA8B;CAC/D,OAAQA,QAA6CC,OACjDC;AACN;AAOA,MAAaG,wBAAwDhB,MAClE,EAAEW,SAASI,KAAKE,SAAS,MAAMC,eAAe;CAO7C;CACA,MAAMH,MAAMX,OAAO,EAAEe,SAASV,eAAeE,OAAO,EAAE,GAAG,EAAEM,OAAO,CAAC;CACnE,MAAMJ,kBAAkBH,mBAAmBC,OAAO;CAClD,MAAMS,QACJ,qBAAC,aAAD;EAAa,OAAOL;YAApB,CACGF,mBAAmB,oBAAC,iBAAD,CAAgB,CAAA,GACnCK,QACU;;CAEf,IAAI,CAACD,QAAQ,OAAOG;CACpB,OAAO,oBAAC,aAAD;EAAa,OAAOH;YAASG;CAAmB,CAAA;AACzD,CACF"}
1
+ {"version":3,"file":"AssistantProvider.js","names":["memo","ComponentType","FC","PropsWithChildren","useAui","AuiProvider","AssistantClient","AssistantRuntime","AssistantRuntimeCore","RuntimeAdapter","getRenderComponent","runtime","_core","RenderComponent","AssistantProviderBaseProps","aui","AssistantProviderBase","parent","children","threads","inner"],"sources":["../../src/react/AssistantProvider.tsx"],"sourcesContent":["import {\n memo,\n type ComponentType,\n type FC,\n type PropsWithChildren,\n} from \"react\";\nimport { useAui, AuiProvider, type AssistantClient } from \"@assistant-ui/store\";\nimport type { AssistantRuntime } from \"../runtime/api/assistant-runtime\";\nimport type { AssistantRuntimeCore } from \"../runtime/interfaces/assistant-runtime-core\";\nimport { RuntimeAdapter } from \"./RuntimeAdapter\";\n\nexport const getRenderComponent = (runtime: AssistantRuntime) => {\n return (runtime as { _core?: AssistantRuntimeCore })._core\n ?.RenderComponent as ComponentType | undefined;\n};\n\nexport type AssistantProviderBaseProps = PropsWithChildren<{\n runtime: AssistantRuntime;\n aui?: AssistantClient | null;\n}>;\n\nexport const AssistantProviderBase: FC<AssistantProviderBaseProps> = memo(\n ({ runtime, aui: parent = null, children }) => {\n // The runtime has a stable identity but mutates in place: its options are\n // pushed in by an unconditional effect inside <RenderComponent />, so that\n // element must be re-created every commit for React to re-render it and\n // re-run the effect. React Compiler caches <RenderComponent /> on the\n // stable RenderComponent type, which silences the effect and stops option\n // changes (e.g. unstable_enableMessageQueue) from reaching the runtime.\n \"use no memo\";\n const aui = useAui({ threads: RuntimeAdapter(runtime) }, { parent });\n const RenderComponent = getRenderComponent(runtime);\n const inner = (\n <AuiProvider value={aui}>\n {RenderComponent && <RenderComponent />}\n {children}\n </AuiProvider>\n );\n if (!parent) return inner;\n return <AuiProvider value={parent}>{inner}</AuiProvider>;\n },\n);\n"],"mappings":";;;;;AAWA,MAAaU,sBAAsBC,YAA8B;CAC/D,OAAQA,QAA6CC,OACjDC;AACN;AAOA,MAAaG,wBAAwDhB,MAClE,EAAEW,SAASI,KAAKE,SAAS,MAAMC,eAAe;CAO7C;CACA,MAAMH,MAAMX,OAAO,EAAEe,SAASV,eAAeE,OAAO,EAAE,GAAG,EAAEM,OAAO,CAAC;CACnE,MAAMJ,kBAAkBH,mBAAmBC,OAAO;CAClD,MAAMS,QACJ,qBAAC,aAAD;EAAa,OAAOL;EAApB,UAAA,CACGF,mBAAmB,oBAAC,iBAAD,CAAgB,CAAA,GACnCK,QACU;;CAEf,IAAI,CAACD,QAAQ,OAAOG;CACpB,OAAO,oBAAC,aAAD;EAAa,OAAOH;EAASG,UAAAA;CAAmB,CAAA;AACzD,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"LocalStorageThreadListAdapter.d.ts","names":[],"sources":["../../../src/react/adapters/LocalStorageThreadListAdapter.tsx"],"mappings":";;;;;;KAmBY;EACV,QAAQ,cAAc;EACtB,QAAQ,aAAa,gBAAgB;EACrC,WAAW,cAAc;;KAGtB;EACH,SAAS;EACT;EACA,iBAAiB;;KAGd;EACH;EACA;EACA;EACA;EACA,SAAS;;cAwIE,4BACX,uBACC;cAoCU,+BACX,uBACC;cA8FU,4BACX,SAAS,+BACR"}
1
+ {"version":3,"file":"LocalStorageThreadListAdapter.d.ts","names":[],"sources":["../../../src/react/adapters/LocalStorageThreadListAdapter.tsx"],"mappings":";;;;;;KAmBY;EACV,QAAQ,cAAc;EACtB,QAAQ,aAAa,gBAAgB;EACrC,WAAW,cAAc;;KAkCtB;EACH,SAAS;EACT;EACA,iBAAiB;;KAGd;EACH;EACA;EACA;EACA;EACA,SAAS;;cAwIE,4BACX,uBACC;cAoCU,+BACX,uBACC;cAkGU,4BACX,SAAS,+BACR"}