@assistant-ui/core 0.2.17 → 0.2.19

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 (238) hide show
  1. package/dist/adapters/thread-history.d.ts +2 -0
  2. package/dist/adapters/thread-history.d.ts.map +1 -1
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +3 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal.d.ts +2 -1
  7. package/dist/internal.js +2 -1
  8. package/dist/model-context/interactable-composer-metadata.d.ts +105 -0
  9. package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -0
  10. package/dist/model-context/interactable-composer-metadata.js +259 -0
  11. package/dist/model-context/interactable-composer-metadata.js.map +1 -0
  12. package/dist/model-context/registry.d.ts.map +1 -1
  13. package/dist/model-context/registry.js +1 -0
  14. package/dist/model-context/registry.js.map +1 -1
  15. package/dist/model-context/types.d.ts +6 -0
  16. package/dist/model-context/types.d.ts.map +1 -1
  17. package/dist/model-context/types.js +4 -0
  18. package/dist/model-context/types.js.map +1 -1
  19. package/dist/react/AssistantProvider.d.ts +1 -1
  20. package/dist/react/AssistantProvider.js +1 -1
  21. package/dist/react/AssistantRuntimeProvider.d.ts +1 -1
  22. package/dist/react/RuntimeAdapter.js +1 -1
  23. package/dist/react/client/Interactables.d.ts +8 -2
  24. package/dist/react/client/Interactables.d.ts.map +1 -1
  25. package/dist/react/client/Interactables.js +190 -94
  26. package/dist/react/client/Interactables.js.map +1 -1
  27. package/dist/react/client/Tools.js +1 -1
  28. package/dist/react/client/interactable-model-context.d.ts +9 -6
  29. package/dist/react/client/interactable-model-context.d.ts.map +1 -1
  30. package/dist/react/client/interactable-model-context.js +154 -32
  31. package/dist/react/client/interactable-model-context.js.map +1 -1
  32. package/dist/react/index.d.ts +15 -6
  33. package/dist/react/index.js +12 -5
  34. package/dist/react/interactables-legacy/Interactables.d.ts +12 -0
  35. package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -0
  36. package/dist/react/interactables-legacy/Interactables.js +264 -0
  37. package/dist/react/interactables-legacy/Interactables.js.map +1 -0
  38. package/dist/react/interactables-legacy/interactable-model-context.d.ts +12 -0
  39. package/dist/react/interactables-legacy/interactable-model-context.d.ts.map +1 -0
  40. package/dist/react/interactables-legacy/interactable-model-context.js +54 -0
  41. package/dist/react/interactables-legacy/interactable-model-context.js.map +1 -0
  42. package/dist/react/interactables-legacy/scopes.d.ts +58 -0
  43. package/dist/react/interactables-legacy/scopes.d.ts.map +1 -0
  44. package/dist/react/interactables-legacy/scopes.js +0 -0
  45. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts +31 -0
  46. package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -0
  47. package/dist/react/{model-context → interactables-legacy}/useAssistantInteractable.js +6 -2
  48. package/dist/react/interactables-legacy/useAssistantInteractable.js.map +1 -0
  49. package/dist/react/interactables-legacy/useInteractableState.d.ts +21 -0
  50. package/dist/react/interactables-legacy/useInteractableState.d.ts.map +1 -0
  51. package/dist/react/interactables-legacy/useInteractableState.js +84 -0
  52. package/dist/react/interactables-legacy/useInteractableState.js.map +1 -0
  53. package/dist/react/model-context/interactableTool.d.ts +53 -0
  54. package/dist/react/model-context/interactableTool.d.ts.map +1 -0
  55. package/dist/react/model-context/interactableTool.js +188 -0
  56. package/dist/react/model-context/interactableTool.js.map +1 -0
  57. package/dist/react/model-context/useAssistantContext.js +1 -1
  58. package/dist/react/model-context/useAssistantDataUI.js +1 -1
  59. package/dist/react/model-context/useAssistantInstructions.js +1 -1
  60. package/dist/react/model-context/useAssistantTool.js +1 -1
  61. package/dist/react/model-context/useAssistantToolUI.js +1 -1
  62. package/dist/react/model-context/useAuiToolOverrides.js +1 -1
  63. package/dist/react/model-context/useInteractable.d.ts +73 -0
  64. package/dist/react/model-context/useInteractable.d.ts.map +1 -0
  65. package/dist/react/model-context/useInteractable.js +100 -0
  66. package/dist/react/model-context/useInteractable.js.map +1 -0
  67. package/dist/react/model-context/useInteractableState.d.ts +8 -5
  68. package/dist/react/model-context/useInteractableState.d.ts.map +1 -1
  69. package/dist/react/model-context/useInteractableState.js +48 -48
  70. package/dist/react/model-context/useInteractableState.js.map +1 -1
  71. package/dist/react/model-context/useInteractableVersions.d.ts +19 -0
  72. package/dist/react/model-context/useInteractableVersions.d.ts.map +1 -0
  73. package/dist/react/model-context/useInteractableVersions.js +51 -0
  74. package/dist/react/model-context/useInteractableVersions.js.map +1 -0
  75. package/dist/react/primitive-hooks/useThreadMessageIds.d.ts +15 -0
  76. package/dist/react/primitive-hooks/useThreadMessageIds.d.ts.map +1 -0
  77. package/dist/react/primitive-hooks/useThreadMessageIds.js +26 -0
  78. package/dist/react/primitive-hooks/useThreadMessageIds.js.map +1 -0
  79. package/dist/react/primitive-hooks/useVoice.js +1 -1
  80. package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -1
  81. package/dist/react/primitives/composer/ComposerAttachments.js +1 -1
  82. package/dist/react/primitives/composer/ComposerQueue.js +1 -1
  83. package/dist/react/primitives/generativeUI/GenerativeUI.js +1 -1
  84. package/dist/react/primitives/message/MessageAttachments.js +1 -1
  85. package/dist/react/primitives/message/MessageGroupedParts.js +1 -1
  86. package/dist/react/primitives/message/MessageParts.js +1 -1
  87. package/dist/react/primitives/message/MessageQuote.js +1 -1
  88. package/dist/react/primitives/part/PartMessages.d.ts +5 -2
  89. package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
  90. package/dist/react/primitives/part/PartMessages.js +8 -8
  91. package/dist/react/primitives/part/PartMessages.js.map +1 -1
  92. package/dist/react/primitives/thread/ThreadMessages.d.ts +31 -1
  93. package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
  94. package/dist/react/primitives/thread/ThreadMessages.js +64 -2
  95. package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
  96. package/dist/react/primitives/thread/ThreadSuggestions.js +1 -1
  97. package/dist/react/primitives/threadList/ThreadListItems.js +1 -1
  98. package/dist/react/providers/MessageByIdProvider.d.ts +9 -0
  99. package/dist/react/providers/MessageByIdProvider.d.ts.map +1 -0
  100. package/dist/react/providers/MessageByIdProvider.js +57 -0
  101. package/dist/react/providers/MessageByIdProvider.js.map +1 -0
  102. package/dist/react/providers/ReadonlyThreadProvider.js +1 -1
  103. package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +1 -1
  104. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +3 -0
  105. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  106. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +16 -1
  107. package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  108. package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +1 -1
  109. package/dist/react/runtimes/cloud/auiV0.js +1 -1
  110. package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +1 -1
  111. package/dist/react/runtimes/createRuntimeExtras.d.ts +20 -0
  112. package/dist/react/runtimes/createRuntimeExtras.d.ts.map +1 -0
  113. package/dist/react/runtimes/createRuntimeExtras.js +43 -0
  114. package/dist/react/runtimes/createRuntimeExtras.js.map +1 -0
  115. package/dist/react/runtimes/useLocalRuntime.js +1 -1
  116. package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
  117. package/dist/react/runtimes/useRemoteThreadListRuntime.js +6 -2
  118. package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
  119. package/dist/react/runtimes/useStreamingTiming.d.ts +26 -0
  120. package/dist/react/runtimes/useStreamingTiming.d.ts.map +1 -0
  121. package/dist/react/runtimes/useStreamingTiming.js +43 -0
  122. package/dist/react/runtimes/useStreamingTiming.js.map +1 -0
  123. package/dist/react/types/scopes/interactables.d.ts +40 -24
  124. package/dist/react/types/scopes/interactables.d.ts.map +1 -1
  125. package/dist/react/types/store-augmentation.d.ts +3 -1
  126. package/dist/react/types/store-augmentation.d.ts.map +1 -1
  127. package/dist/react/utils/useJSONEqual.d.ts +11 -0
  128. package/dist/react/utils/useJSONEqual.d.ts.map +1 -0
  129. package/dist/react/utils/useJSONEqual.js +30 -0
  130. package/dist/react/utils/useJSONEqual.js.map +1 -0
  131. package/dist/runtime/base/base-composer-runtime-core.d.ts +5 -0
  132. package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
  133. package/dist/runtime/base/base-composer-runtime-core.js +13 -0
  134. package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
  135. package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
  136. package/dist/runtime/base/default-edit-composer-runtime-core.js +6 -1
  137. package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
  138. package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
  139. package/dist/runtime/base/default-thread-composer-runtime-core.js +4 -1
  140. package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
  141. package/dist/runtime/utils/message-repository.d.ts +1 -0
  142. package/dist/runtime/utils/message-repository.d.ts.map +1 -1
  143. package/dist/runtime/utils/message-repository.js +6 -3
  144. package/dist/runtime/utils/message-repository.js.map +1 -1
  145. package/dist/runtime/utils/streaming-timing.d.ts +59 -0
  146. package/dist/runtime/utils/streaming-timing.d.ts.map +1 -0
  147. package/dist/runtime/utils/streaming-timing.js +76 -0
  148. package/dist/runtime/utils/streaming-timing.js.map +1 -0
  149. package/dist/runtime/utils/thread-message-like.d.ts +3 -0
  150. package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
  151. package/dist/runtime/utils/thread-message-like.js +5 -1
  152. package/dist/runtime/utils/thread-message-like.js.map +1 -1
  153. package/dist/runtimes/external-store/external-store-adapter.d.ts +26 -1
  154. package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
  155. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +9 -0
  156. package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
  157. package/dist/runtimes/external-store/external-store-thread-runtime-core.js +19 -0
  158. package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
  159. package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
  160. package/dist/runtimes/local/local-thread-runtime-core.js +1 -1
  161. package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
  162. package/dist/runtimes/remote-thread-list/types.d.ts +12 -0
  163. package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
  164. package/dist/store/clients/suggestions.js +1 -1
  165. package/dist/store/clients/thread-message-client.js +1 -1
  166. package/dist/store/runtime-clients/composer-runtime-client.js +1 -1
  167. package/dist/store/runtime-clients/message-runtime-client.js +1 -1
  168. package/dist/store/runtime-clients/thread-list-item-runtime-client.js +1 -1
  169. package/dist/store/runtime-clients/thread-runtime-client.js +1 -1
  170. package/dist/tests/remote-thread-list-test-helpers.d.ts +1 -1
  171. package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
  172. package/dist/tests/remote-thread-list-test-helpers.js +3 -2
  173. package/dist/tests/remote-thread-list-test-helpers.js.map +1 -1
  174. package/dist/utils/id.d.ts +3 -0
  175. package/dist/utils/id.d.ts.map +1 -1
  176. package/dist/utils/id.js +3 -0
  177. package/dist/utils/id.js.map +1 -1
  178. package/package.json +9 -9
  179. package/src/adapters/thread-history.ts +7 -1
  180. package/src/index.ts +17 -0
  181. package/src/internal.ts +7 -0
  182. package/src/model-context/interactable-composer-metadata.test.ts +550 -0
  183. package/src/model-context/interactable-composer-metadata.ts +395 -0
  184. package/src/model-context/registry.ts +5 -0
  185. package/src/model-context/types.ts +12 -0
  186. package/src/react/client/Interactables.test.ts +358 -0
  187. package/src/react/client/Interactables.ts +339 -86
  188. package/src/react/client/interactable-model-context.test.ts +418 -0
  189. package/src/react/client/interactable-model-context.ts +252 -58
  190. package/src/react/index.ts +72 -3
  191. package/src/react/interactables-legacy/Interactables.ts +332 -0
  192. package/src/react/interactables-legacy/interactable-model-context.test.ts +54 -0
  193. package/src/react/interactables-legacy/interactable-model-context.ts +80 -0
  194. package/src/react/interactables-legacy/scopes.ts +66 -0
  195. package/src/react/{model-context → interactables-legacy}/useAssistantInteractable.ts +10 -1
  196. package/src/react/interactables-legacy/useInteractableState.ts +67 -0
  197. package/src/react/model-context/interactableTool.tsx +175 -0
  198. package/src/react/model-context/useInteractable.ts +233 -0
  199. package/src/react/model-context/useInteractableState.ts +31 -23
  200. package/src/react/model-context/useInteractableVersions.ts +48 -0
  201. package/src/react/primitive-hooks/useThreadMessageIds.ts +27 -0
  202. package/src/react/primitives/part/PartMessages.test.tsx +17 -0
  203. package/src/react/primitives/part/PartMessages.tsx +13 -8
  204. package/src/react/primitives/thread/ThreadMessages.tsx +67 -0
  205. package/src/react/providers/MessageByIdProvider.tsx +23 -0
  206. package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +21 -1
  207. package/src/react/runtimes/createRuntimeExtras.test.ts +58 -0
  208. package/src/react/runtimes/createRuntimeExtras.ts +68 -0
  209. package/src/react/runtimes/createRuntimeExtras.use.test.ts +50 -0
  210. package/src/react/runtimes/useRemoteThreadListRuntime.ts +13 -1
  211. package/src/react/runtimes/useStreamingTiming.ts +68 -0
  212. package/src/react/types/scopes/interactables.ts +45 -23
  213. package/src/react/types/store-augmentation.ts +4 -2
  214. package/src/react/utils/useJSONEqual.ts +20 -0
  215. package/src/runtime/base/base-composer-runtime-core.ts +13 -0
  216. package/src/runtime/base/default-edit-composer-runtime-core.ts +18 -1
  217. package/src/runtime/base/default-thread-composer-runtime-core.ts +11 -1
  218. package/src/runtime/utils/message-repository.ts +11 -7
  219. package/src/runtime/utils/streaming-timing.test.ts +301 -0
  220. package/src/runtime/utils/streaming-timing.ts +161 -0
  221. package/src/runtime/utils/thread-message-like.ts +5 -1
  222. package/src/runtimes/external-store/external-store-adapter.ts +28 -0
  223. package/src/runtimes/external-store/external-store-thread-runtime-core.ts +33 -1
  224. package/src/runtimes/local/local-thread-runtime-core.ts +4 -1
  225. package/src/runtimes/remote-thread-list/types.ts +13 -0
  226. package/src/tests/MessageRepository.test.ts +2 -0
  227. package/src/tests/composer-can-send.test.ts +1 -0
  228. package/src/tests/default-edit-composer-runtime-core.test.ts +78 -1
  229. package/src/tests/default-thread-composer-runtime-core.test.ts +82 -0
  230. package/src/tests/external-store-thread-runtime-core.test.ts +337 -0
  231. package/src/tests/groupParts.test.ts +32 -0
  232. package/src/tests/remote-thread-list-reactive-threadId.test.ts +90 -0
  233. package/src/tests/remote-thread-list-test-helpers.ts +2 -1
  234. package/src/tests/thread-message-like.test.ts +50 -0
  235. package/src/utils/id.ts +3 -0
  236. package/dist/react/model-context/useAssistantInteractable.d.ts +0 -22
  237. package/dist/react/model-context/useAssistantInteractable.d.ts.map +0 -1
  238. package/dist/react/model-context/useAssistantInteractable.js.map +0 -1
@@ -1,30 +1,55 @@
1
+ import { findModelKnownState, interactableToolName } from "../../model-context/interactable-composer-metadata.js";
1
2
  import { ModelContext } from "../../store/clients/model-context-client.js";
2
3
  import { buildInteractableModelContext } from "./interactable-model-context.js";
3
4
  import { toJSONSchema, toPartialJSONSchema } from "assistant-stream";
4
- import { useCallback, useEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
5
5
  import { attachTransformScopes, useAssistantClientRef } from "@assistant-ui/store";
6
+ import { useCallback, useEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
6
7
  import { resource } from "@assistant-ui/tap";
7
8
  //#region src/react/client/Interactables.ts
8
9
  const PERSISTENCE_DEBOUNCE_MS = 500;
9
- const useInteractables = () => {
10
+ const hasInteractableCreateCall = (messages, id, name) => messages.some((message) => message.role === "assistant" && message.content?.some((part) => {
11
+ if (!part || typeof part !== "object") return false;
12
+ const p = part;
13
+ return p.type === "tool-call" && p.toolCallId === id && p.toolName === name;
14
+ }));
15
+ const useInteractablesResource = ({ persistence } = {}) => {
10
16
  const [state, setState] = useState(() => ({
11
17
  definitions: {},
12
18
  persistence: {}
13
19
  }));
14
20
  const clientRef = useAssistantClientRef();
15
21
  const stateRef = useRef(state);
16
- useEffect(() => {
17
- stateRef.current = state;
18
- }, [state]);
19
22
  const subscribersRef = useRef(/* @__PURE__ */ new Set());
20
23
  const partialSchemaCacheRef = useRef(/* @__PURE__ */ new Map());
21
- const detachedStateRef = useRef(/* @__PURE__ */ new Map());
24
+ const streamBaselinesRef = useRef(/* @__PURE__ */ new Map());
25
+ const detachedAppStateRef = useRef(/* @__PURE__ */ new Map());
26
+ const detachedThreadStateRef = useRef(/* @__PURE__ */ new Map());
27
+ const registrationCountsRef = useRef(/* @__PURE__ */ new Map());
28
+ const updateToolUIsRef = useRef(/* @__PURE__ */ new Map());
29
+ const loadedStateRef = useRef(/* @__PURE__ */ new Map());
30
+ const touchedIdsRef = useRef(/* @__PURE__ */ new Set());
22
31
  const adapterRef = useRef(void 0);
23
32
  const debounceTimerRef = useRef(void 0);
24
33
  const syncSeqRef = useRef(0);
25
34
  const hasPendingLocalChangeRef = useRef(false);
26
35
  const flushResolversRef = useRef([]);
27
36
  const dirtyIdsRef = useRef(/* @__PURE__ */ new Set());
37
+ const setStateAndRef = useCallback((updater) => {
38
+ const next = updater(stateRef.current);
39
+ stateRef.current = next;
40
+ setState(next);
41
+ }, []);
42
+ const exportState = useCallback(() => {
43
+ const result = {};
44
+ for (const [id, def] of Object.entries(stateRef.current.definitions)) {
45
+ if (def.scope === "thread") continue;
46
+ result[id] = {
47
+ name: def.name,
48
+ state: def.state
49
+ };
50
+ }
51
+ return result;
52
+ }, []);
28
53
  const runPersistence = useCallback(async () => {
29
54
  const adapter = adapterRef.current;
30
55
  if (!adapter) {
@@ -36,13 +61,8 @@ const useInteractables = () => {
36
61
  const dirtyIds = new Set(dirtyIdsRef.current);
37
62
  dirtyIdsRef.current.clear();
38
63
  hasPendingLocalChangeRef.current = true;
39
- const exported = stateRef.current.definitions;
40
- const payload = {};
41
- for (const [id, def] of Object.entries(exported)) payload[id] = {
42
- name: def.name,
43
- state: def.state
44
- };
45
- setState((prev) => ({
64
+ const payload = exportState();
65
+ setStateAndRef((prev) => ({
46
66
  ...prev,
47
67
  persistence: {
48
68
  ...prev.persistence,
@@ -56,19 +76,19 @@ const useInteractables = () => {
56
76
  await adapter.save(payload);
57
77
  if (syncSeqRef.current === seq) {
58
78
  hasPendingLocalChangeRef.current = false;
59
- setState((prev_1) => {
60
- const persistence = { ...prev_1.persistence };
61
- for (const id_2 of dirtyIds) delete persistence[id_2];
79
+ setStateAndRef((prev_1) => {
80
+ const persistence_0 = { ...prev_1.persistence };
81
+ for (const id_2 of dirtyIds) delete persistence_0[id_2];
62
82
  return {
63
83
  ...prev_1,
64
- persistence
84
+ persistence: persistence_0
65
85
  };
66
86
  });
67
87
  }
68
88
  } catch (e) {
69
89
  if (syncSeqRef.current === seq) {
70
90
  hasPendingLocalChangeRef.current = false;
71
- setState((prev_0) => ({
91
+ setStateAndRef((prev_0) => ({
72
92
  ...prev_0,
73
93
  persistence: {
74
94
  ...prev_0.persistence,
@@ -86,7 +106,7 @@ const useInteractables = () => {
86
106
  flushResolversRef.current = [];
87
107
  }
88
108
  }
89
- }, []);
109
+ }, [exportState, setStateAndRef]);
90
110
  const schedulePersistence = useCallback((id_3) => {
91
111
  if (!adapterRef.current) return;
92
112
  dirtyIdsRef.current.add(id_3);
@@ -100,35 +120,68 @@ const useInteractables = () => {
100
120
  }, PERSISTENCE_DEBOUNCE_MS);
101
121
  }, PERSISTENCE_DEBOUNCE_MS);
102
122
  }, [runPersistence]);
103
- const exportState = useCallback(() => {
104
- const result = {};
105
- for (const [id_4, def_0] of Object.entries(stateRef.current.definitions)) result[id_4] = {
106
- name: def_0.name,
107
- state: def_0.state
108
- };
109
- return result;
110
- }, []);
111
- const importState = useCallback((saved) => {
112
- for (const [id_5, entry] of Object.entries(saved)) detachedStateRef.current.set(id_5, entry.state);
113
- setState((prev_2) => {
123
+ const restorePersistedState = useCallback((saved, options) => {
124
+ const shouldStash = options.shouldStash ?? (() => true);
125
+ const shouldApply = options.shouldApply ?? (() => true);
126
+ for (const [id_4, entry] of Object.entries(saved)) if (shouldStash(id_4)) options.stash.set(id_4, entry.state);
127
+ setStateAndRef((prev_2) => {
114
128
  let changed = false;
115
129
  const definitions = { ...prev_2.definitions };
116
- for (const [id_6, entry_0] of Object.entries(saved)) if (definitions[id_6]) {
117
- definitions[id_6] = {
118
- ...definitions[id_6],
130
+ for (const [id_5, entry_0] of Object.entries(saved)) {
131
+ const def_0 = definitions[id_5];
132
+ if (!def_0 || !shouldApply(id_5, def_0)) continue;
133
+ definitions[id_5] = {
134
+ ...def_0,
119
135
  state: entry_0.state
120
136
  };
121
137
  changed = true;
122
138
  }
123
- return changed ? {
139
+ if (!changed) return prev_2;
140
+ return {
124
141
  ...prev_2,
125
142
  definitions
126
- } : prev_2;
143
+ };
127
144
  });
128
- }, []);
129
- const setPersistenceAdapter = useCallback((adapter_0) => {
130
- adapterRef.current = adapter_0;
131
- }, []);
145
+ }, [setStateAndRef]);
146
+ const importState = useCallback((saved_0) => {
147
+ restorePersistedState(saved_0, { stash: detachedAppStateRef.current });
148
+ }, [restorePersistedState]);
149
+ const applyLoadedState = useCallback((saved_1) => {
150
+ restorePersistedState(saved_1, {
151
+ stash: loadedStateRef.current,
152
+ shouldStash: (id_6) => !touchedIdsRef.current.has(id_6),
153
+ shouldApply: (id_7, def_1) => !touchedIdsRef.current.has(id_7) && def_1.scope !== "thread"
154
+ });
155
+ }, [restorePersistedState]);
156
+ const loadFromAdapter = useCallback(async (adapter_0) => {
157
+ if (!adapter_0.load) return;
158
+ try {
159
+ const saved_2 = await adapter_0.load();
160
+ if (!saved_2 || adapterRef.current !== adapter_0) return;
161
+ applyLoadedState(saved_2);
162
+ } catch (e_0) {
163
+ console.warn("[Interactables] Persistence load failed.", e_0);
164
+ }
165
+ }, [applyLoadedState]);
166
+ const setPersistenceAdapter = useCallback((adapter_1) => {
167
+ adapterRef.current = adapter_1;
168
+ if (adapter_1) loadFromAdapter(adapter_1);
169
+ }, [loadFromAdapter]);
170
+ const getCurrentThreadId = useCallback(() => {
171
+ const client = clientRef.current;
172
+ if (!client) return void 0;
173
+ const threadListItem = client.threadListItem;
174
+ if (threadListItem.source != null) return threadListItem().getState().id;
175
+ const threads = client.threads;
176
+ if (threads.source != null) return threads().getState().mainThreadId;
177
+ }, [clientRef]);
178
+ useEffect(() => {
179
+ if (!persistence) return;
180
+ setPersistenceAdapter(persistence);
181
+ return () => {
182
+ if (adapterRef.current === persistence) adapterRef.current = void 0;
183
+ };
184
+ }, [persistence, setPersistenceAdapter]);
132
185
  const flush = useCallback(async () => {
133
186
  if (debounceTimerRef.current !== void 0) {
134
187
  clearTimeout(debounceTimerRef.current);
@@ -149,43 +202,28 @@ const useInteractables = () => {
149
202
  runPersistence();
150
203
  }
151
204
  }, [runPersistence]);
152
- const setDefState = useCallback((id_7, updater) => {
153
- setState((prev_3) => {
154
- const existing = prev_3.definitions[id_7];
205
+ const setDefState = useCallback((id_8, updater_0) => {
206
+ touchedIdsRef.current.add(id_8);
207
+ setStateAndRef((prev_3) => {
208
+ const existing = prev_3.definitions[id_8];
155
209
  if (!existing) return prev_3;
156
210
  return {
157
211
  ...prev_3,
158
212
  definitions: {
159
213
  ...prev_3.definitions,
160
- [id_7]: {
161
- ...existing,
162
- state: updater(existing.state)
163
- }
164
- }
165
- };
166
- });
167
- if (stateRef.current.definitions[id_7]) schedulePersistence(id_7);
168
- }, [schedulePersistence]);
169
- const setDefSelected = useCallback((id_8, selected) => {
170
- setState((prev_4) => {
171
- const existing_0 = prev_4.definitions[id_8];
172
- if (!existing_0) return prev_4;
173
- return {
174
- ...prev_4,
175
- definitions: {
176
- ...prev_4.definitions,
177
214
  [id_8]: {
178
- ...existing_0,
179
- selected
215
+ ...existing,
216
+ state: updater_0(existing.state)
180
217
  }
181
218
  }
182
219
  };
183
220
  });
184
- }, []);
221
+ if (stateRef.current.definitions[id_8]?.scope !== "thread") schedulePersistence(id_8);
222
+ }, [schedulePersistence, setStateAndRef]);
185
223
  const provider = useMemo(() => ({
186
224
  getModelContext: () => {
187
225
  const defs = stateRef.current.definitions;
188
- return buildInteractableModelContext(defs, partialSchemaCacheRef.current, setDefState) ?? {};
226
+ return buildInteractableModelContext(defs, partialSchemaCacheRef.current, setDefState, streamBaselinesRef.current) ?? {};
189
227
  },
190
228
  subscribe: (callback) => {
191
229
  subscribersRef.current.add(callback);
@@ -201,59 +239,117 @@ const useInteractables = () => {
201
239
  return clientRef.current.modelContext().register(provider);
202
240
  }, [clientRef, provider]);
203
241
  return {
204
- getState: () => state,
205
- register: useCallback((def_1) => {
206
- try {
207
- const jsonSchema = toJSONSchema(def_1.stateSchema);
208
- partialSchemaCacheRef.current.set(def_1.id, toPartialJSONSchema(jsonSchema));
209
- } catch (e_0) {
210
- console.warn(`[Interactables] Failed to create partial schema for "${def_1.name}". The update tool will require all fields.`, e_0);
242
+ getState: () => stateRef.current,
243
+ register: useCallback((def_2) => {
244
+ const threadAccessor = clientRef.current?.thread;
245
+ const threadMessages = threadAccessor && threadAccessor.source != null ? threadAccessor().getState().messages ?? [] : [];
246
+ const scope = def_2.scope ?? (hasInteractableCreateCall(threadMessages, def_2.id, def_2.name) ? "thread" : "app");
247
+ if (process.env.NODE_ENV !== "production" && stateRef.current.definitions[def_2.id] && scope !== "thread") console.warn(`[Interactables] "${def_2.name}" (${def_2.id}) is already registered. Register an app-scoped interactable once (unstable_useInteractable) and read it from other components with unstable_useInteractableState.`);
248
+ registrationCountsRef.current.set(def_2.id, (registrationCountsRef.current.get(def_2.id) ?? 0) + 1);
249
+ let releaseUpdateToolUI;
250
+ if (def_2.updateRender) {
251
+ const toolsAccessor = clientRef.current?.tools;
252
+ if (toolsAccessor && toolsAccessor.source != null) {
253
+ const toolName = interactableToolName(def_2.name);
254
+ const existing_0 = updateToolUIsRef.current.get(def_2.name);
255
+ if (existing_0) existing_0.count++;
256
+ else updateToolUIsRef.current.set(def_2.name, {
257
+ count: 1,
258
+ unsubscribe: toolsAccessor().setToolUI(toolName, def_2.updateRender, { standalone: true })
259
+ });
260
+ releaseUpdateToolUI = () => {
261
+ const entry_1 = updateToolUIsRef.current.get(def_2.name);
262
+ if (!entry_1) return;
263
+ if (--entry_1.count === 0) {
264
+ updateToolUIsRef.current.delete(def_2.name);
265
+ entry_1.unsubscribe();
266
+ }
267
+ };
268
+ } else if (process.env.NODE_ENV !== "production") console.warn(`[Interactables] "${def_2.name}" supplied an updateRender, but no tools scope is available to install it into.`);
269
+ }
270
+ if (!partialSchemaCacheRef.current.has(def_2.id)) try {
271
+ const jsonSchema = toJSONSchema(def_2.stateSchema);
272
+ partialSchemaCacheRef.current.set(def_2.id, toPartialJSONSchema(jsonSchema));
273
+ } catch (e_1) {
274
+ console.warn(`[Interactables] Failed to create partial schema for "${def_2.name}". The update tool will accept arbitrary fields without validation.`, e_1);
211
275
  }
212
- const detached = detachedStateRef.current.get(def_1.id);
213
- detachedStateRef.current.delete(def_1.id);
214
- setState((prev_5) => ({
215
- ...prev_5,
276
+ const threadId = scope === "thread" ? getCurrentThreadId() : void 0;
277
+ const detached = scope === "thread" ? threadId ? detachedThreadStateRef.current.get(threadId)?.get(def_2.id) : void 0 : detachedAppStateRef.current.get(def_2.id);
278
+ if (scope === "thread") {
279
+ if (threadId) detachedThreadStateRef.current.get(threadId)?.delete(def_2.id);
280
+ } else detachedAppStateRef.current.delete(def_2.id);
281
+ const loaded = scope === "thread" ? void 0 : loadedStateRef.current.get(def_2.id);
282
+ const known = scope === "thread" ? findModelKnownState(threadMessages, def_2.id, def_2.name) : void 0;
283
+ setStateAndRef((prev_4) => ({
284
+ ...prev_4,
216
285
  definitions: {
217
- ...prev_5.definitions,
218
- [def_1.id]: {
219
- id: def_1.id,
220
- name: def_1.name,
221
- description: def_1.description,
222
- stateSchema: def_1.stateSchema,
223
- state: prev_5.definitions[def_1.id]?.state ?? detached ?? def_1.initialState,
224
- selected: def_1.selected
286
+ ...prev_4.definitions,
287
+ [def_2.id]: {
288
+ id: def_2.id,
289
+ name: def_2.name,
290
+ description: def_2.description,
291
+ stateSchema: def_2.stateSchema,
292
+ initialState: def_2.initialState,
293
+ scope,
294
+ state: prev_4.definitions[def_2.id]?.state ?? detached ?? known?.state ?? loaded ?? def_2.initialState
225
295
  }
226
296
  }
227
297
  }));
228
298
  return () => {
299
+ releaseUpdateToolUI?.();
300
+ const remaining = (registrationCountsRef.current.get(def_2.id) ?? 1) - 1;
301
+ if (remaining > 0) {
302
+ registrationCountsRef.current.set(def_2.id, remaining);
303
+ return;
304
+ }
305
+ registrationCountsRef.current.delete(def_2.id);
229
306
  flushIfPending();
230
- setState((prev_6) => {
231
- const existing_1 = prev_6.definitions[def_1.id];
232
- if (existing_1) detachedStateRef.current.set(def_1.id, existing_1.state);
233
- partialSchemaCacheRef.current.delete(def_1.id);
234
- const { [def_1.id]: _, ...rest } = prev_6.definitions;
235
- const { [def_1.id]: __, ...restPersistence } = prev_6.persistence;
307
+ setStateAndRef((prev_5) => {
308
+ const existing_1 = prev_5.definitions[def_2.id];
309
+ if (existing_1) if (existing_1.scope === "thread") {
310
+ const threadId_0 = getCurrentThreadId();
311
+ if (threadId_0) {
312
+ let stateById = detachedThreadStateRef.current.get(threadId_0);
313
+ if (!stateById) {
314
+ stateById = /* @__PURE__ */ new Map();
315
+ detachedThreadStateRef.current.set(threadId_0, stateById);
316
+ }
317
+ stateById.set(def_2.id, existing_1.state);
318
+ }
319
+ } else detachedAppStateRef.current.set(def_2.id, existing_1.state);
320
+ partialSchemaCacheRef.current.delete(def_2.id);
321
+ const { [def_2.id]: _, ...rest } = prev_5.definitions;
322
+ const { [def_2.id]: __, ...restPersistence } = prev_5.persistence;
236
323
  return {
237
- ...prev_6,
324
+ ...prev_5,
238
325
  definitions: rest,
239
326
  persistence: restPersistence
240
327
  };
241
328
  });
242
329
  };
243
- }, [flushIfPending]),
330
+ }, [
331
+ flushIfPending,
332
+ clientRef,
333
+ getCurrentThreadId,
334
+ setStateAndRef
335
+ ]),
244
336
  setState: setDefState,
245
- setSelected: setDefSelected,
246
337
  exportState,
247
338
  importState,
248
339
  setPersistenceAdapter,
249
340
  flush
250
341
  };
251
342
  };
252
- const Interactables = resource(useInteractables);
253
- attachTransformScopes(useInteractables, (scopes, parent) => {
343
+ /**
344
+ * Registers the unstable interactables store scope.
345
+ *
346
+ * @deprecated Unstable / Experimental (not actually removed).
347
+ */
348
+ const unstable_Interactables = resource(useInteractablesResource);
349
+ attachTransformScopes(useInteractablesResource, (scopes, parent) => {
254
350
  if (!scopes.modelContext && parent.modelContext.source === null) scopes.modelContext = ModelContext();
255
351
  });
256
352
  //#endregion
257
- export { Interactables };
353
+ export { unstable_Interactables };
258
354
 
259
355
  //# sourceMappingURL=Interactables.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Interactables.js","names":["useState","useEffect","useCallback","useRef","useMemo","resource","useAssistantClientRef","ClientOutput","attachTransformScopes","InteractablesState","InteractableRegistration","InteractableStateSchema","InteractablePersistedState","InteractablePersistenceAdapter","toJSONSchema","toPartialJSONSchema","ModelContext","buildInteractableModelContext","PERSISTENCE_DEBOUNCE_MS","useInteractables","state","setState","definitions","persistence","clientRef","stateRef","current","subscribersRef","Set","partialSchemaCacheRef","Map","detachedStateRef","adapterRef","undefined","debounceTimerRef","ReturnType","setTimeout","syncSeqRef","hasPendingLocalChangeRef","flushResolversRef","Array","dirtyIdsRef","runPersistence","adapter","resolve","seq","dirtyIds","clear","exported","payload","id","def","Object","entries","name","prev","fromEntries","map","isPending","error","save","e","size","schedulePersistence","add","clearTimeout","exportState","result","importState","saved","entry","set","changed","setPersistenceAdapter","flush","p","Promise","push","flushIfPending","setDefState","updater","existing","setDefSelected","selected","provider","getModelContext","defs","subscribe","callback","delete","cb","modelContext","register","jsonSchema","stateSchema","console","warn","detached","get","description","initialState","_","rest","__","restPersistence","getState","setSelected","Interactables","scopes","parent","source"],"sources":["../../../src/react/client/Interactables.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport {\n useAssistantClientRef,\n type ClientOutput,\n attachTransformScopes,\n} from \"@assistant-ui/store\";\nimport type {\n InteractablesState,\n InteractableRegistration,\n InteractableStateSchema,\n InteractablePersistedState,\n InteractablePersistenceAdapter,\n} from \"../types/scopes/interactables\";\nimport { toJSONSchema, toPartialJSONSchema } from \"assistant-stream\";\nimport { ModelContext } from \"../../store\";\nimport { buildInteractableModelContext } from \"./interactable-model-context\";\n\nconst PERSISTENCE_DEBOUNCE_MS = 500;\n\nconst useInteractables = (): ClientOutput<\"interactables\"> => {\n const [state, setState] = useState<InteractablesState>(() => ({\n definitions: {},\n persistence: {},\n }));\n\n const clientRef = useAssistantClientRef();\n\n const stateRef = useRef(state);\n useEffect(() => {\n stateRef.current = state;\n }, [state]);\n\n const subscribersRef = useRef(new Set<() => void>());\n const partialSchemaCacheRef = useRef(\n new Map<string, InteractableStateSchema>(),\n );\n const detachedStateRef = useRef(new Map<string, unknown>());\n\n const adapterRef = useRef<InteractablePersistenceAdapter | undefined>(\n undefined,\n );\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n const syncSeqRef = useRef(0);\n const hasPendingLocalChangeRef = useRef(false);\n const flushResolversRef = useRef<Array<() => void>>([]);\n const dirtyIdsRef = useRef(new Set<string>());\n\n const runPersistence = useCallback(async () => {\n const adapter = adapterRef.current;\n if (!adapter) {\n for (const resolve of flushResolversRef.current) resolve();\n flushResolversRef.current = [];\n return;\n }\n\n const seq = ++syncSeqRef.current;\n const dirtyIds = new Set(dirtyIdsRef.current);\n dirtyIdsRef.current.clear();\n hasPendingLocalChangeRef.current = true;\n\n // Snapshot before any await so unregistered definitions are still included.\n const exported = stateRef.current.definitions;\n const payload: InteractablePersistedState = {};\n for (const [id, def] of Object.entries(exported)) {\n payload[id] = { name: def.name, state: def.state };\n }\n\n setState((prev) => ({\n ...prev,\n persistence: {\n ...prev.persistence,\n ...Object.fromEntries(\n [...dirtyIds].map((id) => [\n id,\n { isPending: true, error: undefined },\n ]),\n ),\n },\n }));\n\n try {\n await adapter.save(payload);\n if (syncSeqRef.current === seq) {\n hasPendingLocalChangeRef.current = false;\n setState((prev) => {\n const persistence = { ...prev.persistence };\n for (const id of dirtyIds) delete persistence[id];\n return { ...prev, persistence };\n });\n }\n } catch (e) {\n if (syncSeqRef.current === seq) {\n hasPendingLocalChangeRef.current = false;\n setState((prev) => ({\n ...prev,\n persistence: {\n ...prev.persistence,\n ...Object.fromEntries(\n [...dirtyIds].map((id) => [id, { isPending: false, error: e }]),\n ),\n },\n }));\n }\n } finally {\n if (dirtyIdsRef.current.size > 0 && adapterRef.current) {\n runPersistence();\n } else {\n for (const resolve of flushResolversRef.current) resolve();\n flushResolversRef.current = [];\n }\n }\n }, []);\n\n const schedulePersistence = useCallback(\n (id: string) => {\n if (!adapterRef.current) return;\n dirtyIdsRef.current.add(id);\n if (debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n }\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = undefined;\n if (!hasPendingLocalChangeRef.current) {\n runPersistence();\n } else {\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = undefined;\n runPersistence();\n }, PERSISTENCE_DEBOUNCE_MS);\n }\n }, PERSISTENCE_DEBOUNCE_MS);\n },\n [runPersistence],\n );\n\n const exportState = useCallback((): InteractablePersistedState => {\n const result: InteractablePersistedState = {};\n for (const [id, def] of Object.entries(stateRef.current.definitions)) {\n result[id] = { name: def.name, state: def.state };\n }\n return result;\n }, []);\n\n const importState = useCallback((saved: InteractablePersistedState) => {\n for (const [id, entry] of Object.entries(saved)) {\n detachedStateRef.current.set(id, entry.state);\n }\n setState((prev) => {\n let changed = false;\n const definitions = { ...prev.definitions };\n for (const [id, entry] of Object.entries(saved)) {\n if (definitions[id]) {\n definitions[id] = { ...definitions[id], state: entry.state };\n changed = true;\n }\n }\n return changed ? { ...prev, definitions } : prev;\n });\n }, []);\n\n const setPersistenceAdapter = useCallback(\n (adapter: InteractablePersistenceAdapter | undefined) => {\n adapterRef.current = adapter;\n },\n [],\n );\n\n const flush = useCallback(async () => {\n if (debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n }\n if (!adapterRef.current) return;\n if (!hasPendingLocalChangeRef.current && dirtyIdsRef.current.size === 0)\n return;\n const p = new Promise<void>((resolve) => {\n flushResolversRef.current.push(resolve);\n });\n if (!hasPendingLocalChangeRef.current) {\n runPersistence();\n }\n return p;\n }, [runPersistence]);\n\n const flushIfPending = useCallback(() => {\n if (adapterRef.current && debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n runPersistence();\n }\n }, [runPersistence]);\n\n const setDefState = useCallback(\n (id: string, updater: (prev: unknown) => unknown) => {\n setState((prev) => {\n const existing = prev.definitions[id];\n if (!existing) return prev;\n return {\n ...prev,\n definitions: {\n ...prev.definitions,\n [id]: { ...existing, state: updater(existing.state) },\n },\n };\n });\n if (stateRef.current.definitions[id]) schedulePersistence(id);\n },\n [schedulePersistence],\n );\n\n const setDefSelected = useCallback((id: string, selected: boolean) => {\n setState((prev) => {\n const existing = prev.definitions[id];\n if (!existing) return prev;\n return {\n ...prev,\n definitions: {\n ...prev.definitions,\n [id]: { ...existing, selected },\n },\n };\n });\n }, []);\n\n const provider = useMemo(\n () => ({\n getModelContext: () => {\n const defs = stateRef.current.definitions;\n return (\n buildInteractableModelContext(\n defs,\n partialSchemaCacheRef.current,\n setDefState,\n ) ?? {}\n );\n },\n subscribe: (callback: () => void) => {\n subscribersRef.current.add(callback);\n return () => {\n subscribersRef.current.delete(callback);\n };\n },\n }),\n [setDefState],\n );\n\n useEffect(() => {\n for (const cb of subscribersRef.current) cb();\n }, [state]);\n\n useEffect(() => {\n return clientRef.current!.modelContext().register(provider);\n }, [clientRef, provider]);\n\n const register = useCallback(\n (def: InteractableRegistration) => {\n try {\n const jsonSchema = toJSONSchema(def.stateSchema);\n partialSchemaCacheRef.current.set(\n def.id,\n toPartialJSONSchema(jsonSchema),\n );\n } catch (e) {\n console.warn(\n `[Interactables] Failed to create partial schema for \"${def.name}\". The update tool will require all fields.`,\n e,\n );\n }\n\n const detached = detachedStateRef.current.get(def.id);\n detachedStateRef.current.delete(def.id);\n\n setState((prev) => ({\n ...prev,\n definitions: {\n ...prev.definitions,\n [def.id]: {\n id: def.id,\n name: def.name,\n description: def.description,\n stateSchema: def.stateSchema,\n state:\n prev.definitions[def.id]?.state ?? detached ?? def.initialState,\n selected: def.selected,\n },\n },\n }));\n\n return () => {\n flushIfPending();\n setState((prev) => {\n const existing = prev.definitions[def.id];\n if (existing) {\n detachedStateRef.current.set(def.id, existing.state);\n }\n partialSchemaCacheRef.current.delete(def.id);\n const { [def.id]: _, ...rest } = prev.definitions;\n const { [def.id]: __, ...restPersistence } = prev.persistence;\n return { ...prev, definitions: rest, persistence: restPersistence };\n });\n };\n },\n [flushIfPending],\n );\n\n return {\n getState: () => state,\n register,\n setState: setDefState,\n setSelected: setDefSelected,\n exportState,\n importState,\n setPersistenceAdapter,\n flush,\n };\n};\n\nexport const Interactables = resource(useInteractables);\n\nattachTransformScopes(useInteractables, (scopes, parent) => {\n if (!scopes.modelContext && parent.modelContext.source === null) {\n scopes.modelContext = ModelContext();\n }\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"Interactables.js","names":["useState","useEffect","useCallback","useRef","useMemo","resource","useAssistantClientRef","ClientOutput","attachTransformScopes","Unstable_InteractablesState","Unstable_InteractableRegistration","Unstable_InteractablePersistedState","Unstable_InteractablePersistenceAdapter","Unstable_InteractablesConfig","toJSONSchema","toPartialJSONSchema","ModelContext","buildInteractableModelContext","PartialJSONSchema","findModelKnownState","interactableToolName","PERSISTENCE_DEBOUNCE_MS","RestorePersistedStateOptions","stash","Map","shouldStash","id","shouldApply","def","ToolCallLikePart","type","toolCallId","toolName","MessageLike","role","content","InternalInteractableRegistration","scope","hasInteractableCreateCall","messages","name","some","message","part","p","useInteractablesResource","persistence","state","setState","definitions","clientRef","stateRef","subscribersRef","Set","partialSchemaCacheRef","streamBaselinesRef","targetId","detachedAppStateRef","detachedThreadStateRef","registrationCountsRef","updateToolUIsRef","count","unsubscribe","loadedStateRef","touchedIdsRef","adapterRef","undefined","debounceTimerRef","ReturnType","setTimeout","syncSeqRef","hasPendingLocalChangeRef","flushResolversRef","Array","dirtyIdsRef","setStateAndRef","updater","prev","next","current","exportState","result","Object","entries","runPersistence","adapter","resolve","seq","dirtyIds","clear","payload","fromEntries","map","isPending","error","save","e","size","schedulePersistence","add","clearTimeout","restorePersistedState","saved","options","entry","set","changed","importState","applyLoadedState","has","loadFromAdapter","load","console","warn","setPersistenceAdapter","getCurrentThreadId","client","threadListItem","source","getState","threads","mainThreadId","flush","Promise","push","flushIfPending","setDefState","existing","provider","getModelContext","defs","subscribe","callback","delete","cb","modelContext","register","threadAccessor","thread","threadMessages","process","env","NODE_ENV","get","releaseUpdateToolUI","updateRender","toolsAccessor","tools","setToolUI","standalone","jsonSchema","stateSchema","threadId","detached","loaded","known","description","initialState","remaining","stateById","_","rest","__","restPersistence","unstable_Interactables","scopes","parent"],"sources":["../../../src/react/client/Interactables.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport {\n useAssistantClientRef,\n type ClientOutput,\n attachTransformScopes,\n} from \"@assistant-ui/store\";\nimport type {\n Unstable_InteractablesState,\n Unstable_InteractableRegistration,\n Unstable_InteractablePersistedState,\n Unstable_InteractablePersistenceAdapter,\n Unstable_InteractablesConfig,\n} from \"../types/scopes/interactables\";\nimport { toJSONSchema, toPartialJSONSchema } from \"assistant-stream\";\nimport { ModelContext } from \"../../store\";\nimport {\n buildInteractableModelContext,\n type PartialJSONSchema,\n} from \"./interactable-model-context\";\nimport {\n findModelKnownState,\n interactableToolName,\n} from \"../../model-context/interactable-composer-metadata\";\n\nconst PERSISTENCE_DEBOUNCE_MS = 500;\n\ntype RestorePersistedStateOptions = {\n stash: Map<string, unknown>;\n shouldStash?: (id: string) => boolean;\n shouldApply?: (\n id: string,\n def: Unstable_InteractablesState[\"definitions\"][string],\n ) => boolean;\n};\n\ntype ToolCallLikePart = {\n type?: string;\n toolCallId?: string;\n toolName?: string;\n};\n\ntype MessageLike = {\n role?: string;\n content?: readonly unknown[] | undefined;\n};\n\ntype InternalInteractableRegistration = Unstable_InteractableRegistration & {\n scope?: \"thread\" | undefined;\n};\n\nconst hasInteractableCreateCall = (\n messages: readonly MessageLike[],\n id: string,\n name: string,\n) =>\n messages.some(\n (message) =>\n message.role === \"assistant\" &&\n message.content?.some((part) => {\n if (!part || typeof part !== \"object\") return false;\n const p = part as ToolCallLikePart;\n return (\n p.type === \"tool-call\" && p.toolCallId === id && p.toolName === name\n );\n }),\n );\n\nconst useInteractablesResource = ({\n persistence,\n}: Unstable_InteractablesConfig = {}): ClientOutput<\"unstable_interactables\"> => {\n const [state, setState] = useState<Unstable_InteractablesState>(() => ({\n definitions: {},\n persistence: {},\n }));\n\n const clientRef = useAssistantClientRef();\n\n const stateRef = useRef(state);\n\n const subscribersRef = useRef(new Set<() => void>());\n const partialSchemaCacheRef = useRef(new Map<string, PartialJSONSchema>());\n const streamBaselinesRef = useRef(\n new Map<string, { targetId: string; state: unknown }>(),\n );\n const detachedAppStateRef = useRef(new Map<string, unknown>());\n const detachedThreadStateRef = useRef(\n new Map<string, Map<string, unknown>>(),\n );\n // An instance may be registered from several anchors (its creating tool\n // call plus update_* calls); the definition lives until the last one leaves.\n const registrationCountsRef = useRef(new Map<string, number>());\n // One update-tool UI per interactable name, alive while any registrant\n // that supplied an updateRender is mounted.\n const updateToolUIsRef = useRef(\n new Map<string, { count: number; unsubscribe: () => void }>(),\n );\n // App-scoped state restored via adapter.load(), consumed as components register.\n const loadedStateRef = useRef(new Map<string, unknown>());\n // Ids edited locally this session — a local edit always wins over a slow load.\n const touchedIdsRef = useRef(new Set<string>());\n\n const adapterRef = useRef<\n Unstable_InteractablePersistenceAdapter | undefined\n >(undefined);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n const syncSeqRef = useRef(0);\n const hasPendingLocalChangeRef = useRef(false);\n const flushResolversRef = useRef<Array<() => void>>([]);\n const dirtyIdsRef = useRef(new Set<string>());\n\n const setStateAndRef = useCallback(\n (\n updater: (\n prev: Unstable_InteractablesState,\n ) => Unstable_InteractablesState,\n ) => {\n const next = updater(stateRef.current);\n stateRef.current = next;\n setState(next);\n },\n [],\n );\n\n const exportState = useCallback((): Unstable_InteractablePersistedState => {\n const result: Unstable_InteractablePersistedState = {};\n for (const [id, def] of Object.entries(stateRef.current.definitions)) {\n if (def.scope === \"thread\") continue; // thread items persist via snapshot, not the adapter\n result[id] = { name: def.name, state: def.state };\n }\n return result;\n }, []);\n\n const runPersistence = useCallback(async () => {\n const adapter = adapterRef.current;\n if (!adapter) {\n for (const resolve of flushResolversRef.current) resolve();\n flushResolversRef.current = [];\n return;\n }\n\n const seq = ++syncSeqRef.current;\n const dirtyIds = new Set(dirtyIdsRef.current);\n dirtyIdsRef.current.clear();\n hasPendingLocalChangeRef.current = true;\n\n // Snapshot before any await so unregistered definitions are still included.\n const payload = exportState();\n\n setStateAndRef((prev) => ({\n ...prev,\n persistence: {\n ...prev.persistence,\n ...Object.fromEntries(\n [...dirtyIds].map((id) => [\n id,\n { isPending: true, error: undefined },\n ]),\n ),\n },\n }));\n\n try {\n await adapter.save(payload);\n if (syncSeqRef.current === seq) {\n hasPendingLocalChangeRef.current = false;\n setStateAndRef((prev) => {\n const persistence = { ...prev.persistence };\n for (const id of dirtyIds) delete persistence[id];\n return { ...prev, persistence };\n });\n }\n } catch (e) {\n if (syncSeqRef.current === seq) {\n hasPendingLocalChangeRef.current = false;\n setStateAndRef((prev) => ({\n ...prev,\n persistence: {\n ...prev.persistence,\n ...Object.fromEntries(\n [...dirtyIds].map((id) => [id, { isPending: false, error: e }]),\n ),\n },\n }));\n }\n } finally {\n if (dirtyIdsRef.current.size > 0 && adapterRef.current) {\n runPersistence();\n } else {\n for (const resolve of flushResolversRef.current) resolve();\n flushResolversRef.current = [];\n }\n }\n }, [exportState, setStateAndRef]);\n\n const schedulePersistence = useCallback(\n (id: string) => {\n if (!adapterRef.current) return;\n dirtyIdsRef.current.add(id);\n if (debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n }\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = undefined;\n if (!hasPendingLocalChangeRef.current) {\n runPersistence();\n } else {\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = undefined;\n runPersistence();\n }, PERSISTENCE_DEBOUNCE_MS);\n }\n }, PERSISTENCE_DEBOUNCE_MS);\n },\n [runPersistence],\n );\n\n const restorePersistedState = useCallback(\n (\n saved: Unstable_InteractablePersistedState,\n options: RestorePersistedStateOptions,\n ) => {\n const shouldStash = options.shouldStash ?? (() => true);\n const shouldApply = options.shouldApply ?? (() => true);\n\n for (const [id, entry] of Object.entries(saved)) {\n if (shouldStash(id)) options.stash.set(id, entry.state);\n }\n setStateAndRef((prev) => {\n let changed = false;\n const definitions = { ...prev.definitions };\n for (const [id, entry] of Object.entries(saved)) {\n const def = definitions[id];\n if (!def || !shouldApply(id, def)) continue;\n definitions[id] = { ...def, state: entry.state };\n changed = true;\n }\n if (!changed) return prev;\n return { ...prev, definitions };\n });\n },\n [setStateAndRef],\n );\n\n const importState = useCallback(\n (saved: Unstable_InteractablePersistedState) => {\n restorePersistedState(saved, { stash: detachedAppStateRef.current });\n },\n [restorePersistedState],\n );\n\n // Applies adapter.load() output: a local edit made while the load was in\n // flight wins, and thread-scoped items never restore from the adapter.\n const applyLoadedState = useCallback(\n (saved: Unstable_InteractablePersistedState) => {\n restorePersistedState(saved, {\n stash: loadedStateRef.current,\n shouldStash: (id) => !touchedIdsRef.current.has(id),\n shouldApply: (id, def) =>\n !touchedIdsRef.current.has(id) && def.scope !== \"thread\",\n });\n },\n [restorePersistedState],\n );\n\n const loadFromAdapter = useCallback(\n async (adapter: Unstable_InteractablePersistenceAdapter) => {\n if (!adapter.load) return;\n try {\n const saved = await adapter.load();\n if (!saved || adapterRef.current !== adapter) return;\n applyLoadedState(saved);\n } catch (e) {\n console.warn(\"[Interactables] Persistence load failed.\", e);\n }\n },\n [applyLoadedState],\n );\n\n const setPersistenceAdapter = useCallback(\n (adapter: Unstable_InteractablePersistenceAdapter | undefined) => {\n adapterRef.current = adapter;\n if (adapter) void loadFromAdapter(adapter);\n },\n [loadFromAdapter],\n );\n\n const getCurrentThreadId = useCallback((): string | undefined => {\n const client = clientRef.current;\n if (!client) return undefined;\n\n const threadListItem = client.threadListItem;\n if (threadListItem.source != null) {\n return threadListItem().getState().id;\n }\n\n const threads = client.threads;\n if (threads.source != null) {\n return threads().getState().mainThreadId;\n }\n\n return undefined;\n }, [clientRef]);\n\n useEffect(() => {\n if (!persistence) return;\n setPersistenceAdapter(persistence);\n return () => {\n if (adapterRef.current === persistence) {\n adapterRef.current = undefined;\n }\n };\n }, [persistence, setPersistenceAdapter]);\n\n const flush = useCallback(async () => {\n if (debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n }\n if (!adapterRef.current) return;\n if (!hasPendingLocalChangeRef.current && dirtyIdsRef.current.size === 0)\n return;\n const p = new Promise<void>((resolve) => {\n flushResolversRef.current.push(resolve);\n });\n if (!hasPendingLocalChangeRef.current) {\n runPersistence();\n }\n return p;\n }, [runPersistence]);\n\n const flushIfPending = useCallback(() => {\n if (adapterRef.current && debounceTimerRef.current !== undefined) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n runPersistence();\n }\n }, [runPersistence]);\n\n const setDefState = useCallback(\n (id: string, updater: (prev: unknown) => unknown) => {\n touchedIdsRef.current.add(id);\n setStateAndRef((prev) => {\n const existing = prev.definitions[id];\n if (!existing) return prev;\n return {\n ...prev,\n definitions: {\n ...prev.definitions,\n [id]: { ...existing, state: updater(existing.state) },\n },\n };\n });\n if (stateRef.current.definitions[id]?.scope !== \"thread\") {\n schedulePersistence(id);\n }\n },\n [schedulePersistence, setStateAndRef],\n );\n\n const provider = useMemo(\n () => ({\n getModelContext: () => {\n const defs = stateRef.current.definitions;\n return (\n buildInteractableModelContext(\n defs,\n partialSchemaCacheRef.current,\n setDefState,\n streamBaselinesRef.current,\n ) ?? {}\n );\n },\n subscribe: (callback: () => void) => {\n subscribersRef.current.add(callback);\n return () => {\n subscribersRef.current.delete(callback);\n };\n },\n }),\n [setDefState],\n );\n\n useEffect(() => {\n for (const cb of subscribersRef.current) cb();\n }, [state]);\n\n useEffect(() => {\n return clientRef.current!.modelContext().register(provider);\n }, [clientRef, provider]);\n\n const register = useCallback(\n (def: InternalInteractableRegistration) => {\n const threadAccessor = clientRef.current?.thread;\n const threadMessages =\n threadAccessor && threadAccessor.source != null\n ? (threadAccessor().getState().messages ?? [])\n : [];\n const scope =\n def.scope ??\n (hasInteractableCreateCall(threadMessages, def.id, def.name)\n ? \"thread\"\n : \"app\");\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n stateRef.current.definitions[def.id] &&\n scope !== \"thread\"\n ) {\n console.warn(\n `[Interactables] \"${def.name}\" (${def.id}) is already registered. ` +\n `Register an app-scoped interactable once (unstable_useInteractable) and ` +\n `read it from other components with unstable_useInteractableState.`,\n );\n }\n\n registrationCountsRef.current.set(\n def.id,\n (registrationCountsRef.current.get(def.id) ?? 0) + 1,\n );\n\n let releaseUpdateToolUI: (() => void) | undefined;\n if (def.updateRender) {\n const toolsAccessor = clientRef.current?.tools;\n if (toolsAccessor && toolsAccessor.source != null) {\n const toolName = interactableToolName(def.name);\n const existing = updateToolUIsRef.current.get(def.name);\n if (existing) {\n existing.count++;\n } else {\n updateToolUIsRef.current.set(def.name, {\n count: 1,\n unsubscribe: toolsAccessor().setToolUI(\n toolName,\n def.updateRender,\n { standalone: true },\n ),\n });\n }\n releaseUpdateToolUI = () => {\n const entry = updateToolUIsRef.current.get(def.name);\n if (!entry) return;\n if (--entry.count === 0) {\n updateToolUIsRef.current.delete(def.name);\n entry.unsubscribe();\n }\n };\n } else if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[Interactables] \"${def.name}\" supplied an updateRender, but no ` +\n `tools scope is available to install it into.`,\n );\n }\n }\n\n // The same id re-registers once per anchor (its create call + each update_*).\n if (!partialSchemaCacheRef.current.has(def.id)) {\n try {\n const jsonSchema = toJSONSchema(def.stateSchema);\n partialSchemaCacheRef.current.set(\n def.id,\n toPartialJSONSchema(jsonSchema),\n );\n } catch (e) {\n console.warn(\n `[Interactables] Failed to create partial schema for \"${def.name}\". The update tool will accept arbitrary fields without validation.`,\n e,\n );\n }\n }\n\n const threadId = scope === \"thread\" ? getCurrentThreadId() : undefined;\n const detached =\n scope === \"thread\"\n ? threadId\n ? detachedThreadStateRef.current.get(threadId)?.get(def.id)\n : undefined\n : detachedAppStateRef.current.get(def.id);\n if (scope === \"thread\") {\n if (threadId)\n detachedThreadStateRef.current.get(threadId)?.delete(def.id);\n } else {\n detachedAppStateRef.current.delete(def.id);\n }\n const loaded =\n scope === \"thread\" ? undefined : loadedStateRef.current.get(def.id);\n\n // Tool-created items restore from what the model already knows in this\n // thread (the creating call's args, sent snapshots, and the model's own\n // update_* calls) on a fresh reload; detached (in-session remount) still\n // wins so an unsent edit survives a scroll/virtualization cycle.\n const known =\n scope === \"thread\"\n ? findModelKnownState(threadMessages, def.id, def.name)\n : undefined;\n\n setStateAndRef((prev) => ({\n ...prev,\n definitions: {\n ...prev.definitions,\n [def.id]: {\n id: def.id,\n name: def.name,\n description: def.description,\n stateSchema: def.stateSchema,\n initialState: def.initialState,\n scope,\n state:\n prev.definitions[def.id]?.state ??\n detached ??\n known?.state ??\n loaded ??\n def.initialState,\n },\n },\n }));\n\n return () => {\n releaseUpdateToolUI?.();\n\n const remaining = (registrationCountsRef.current.get(def.id) ?? 1) - 1;\n if (remaining > 0) {\n registrationCountsRef.current.set(def.id, remaining);\n return;\n }\n registrationCountsRef.current.delete(def.id);\n\n flushIfPending();\n setStateAndRef((prev) => {\n const existing = prev.definitions[def.id];\n if (existing) {\n if (existing.scope === \"thread\") {\n const threadId = getCurrentThreadId();\n if (threadId) {\n let stateById = detachedThreadStateRef.current.get(threadId);\n if (!stateById) {\n stateById = new Map();\n detachedThreadStateRef.current.set(threadId, stateById);\n }\n stateById.set(def.id, existing.state);\n }\n } else {\n detachedAppStateRef.current.set(def.id, existing.state);\n }\n }\n partialSchemaCacheRef.current.delete(def.id);\n const { [def.id]: _, ...rest } = prev.definitions;\n const { [def.id]: __, ...restPersistence } = prev.persistence;\n return { ...prev, definitions: rest, persistence: restPersistence };\n });\n };\n },\n [flushIfPending, clientRef, getCurrentThreadId, setStateAndRef],\n );\n\n return {\n getState: () => stateRef.current,\n register,\n setState: setDefState,\n exportState,\n importState,\n setPersistenceAdapter,\n flush,\n };\n};\n\n/**\n * Registers the unstable interactables store scope.\n *\n * @deprecated Unstable / Experimental (not actually removed).\n */\nexport const unstable_Interactables = resource(useInteractablesResource);\n\nattachTransformScopes(useInteractablesResource, (scopes, parent) => {\n if (!scopes.modelContext && parent.modelContext.source === null) {\n scopes.modelContext = ModelContext();\n }\n});\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { ModelContext } from "../../store/clients/model-context-client.js";
2
2
  import { isStandaloneToolDisplay, makeToolCallTextComponent } from "../model-context/toolbox.js";
3
- import { useEffect, useState } from "@assistant-ui/tap/react-shim";
4
3
  import { attachTransformScopes, useAssistantClientRef } from "@assistant-ui/store";
4
+ import { useEffect, useState } from "@assistant-ui/tap/react-shim";
5
5
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
6
6
  import { resource, useResources, withKey } from "@assistant-ui/tap";
7
7
  //#region src/react/client/Tools.ts
@@ -1,12 +1,15 @@
1
- import { InteractableDefinition, InteractableStateSchema } from "../types/scopes/interactables.js";
2
- import { Tool } from "assistant-stream";
1
+ import { Unstable_InteractableDefinition } from "../types/scopes/interactables.js";
2
+ import { Tool, toJSONSchema } from "assistant-stream";
3
3
 
4
4
  //#region src/react/client/interactable-model-context.d.ts
5
- declare function shallowMerge(prev: unknown, partial: unknown): unknown;
6
- declare function buildInteractableModelContext(definitions: Record<string, InteractableDefinition>, partialSchemaCache: Map<string, InteractableStateSchema>, setDefState: (id: string, updater: (prev: unknown) => unknown) => void): {
7
- system: string;
5
+ type PartialJSONSchema = ReturnType<typeof toJSONSchema>;
6
+ declare function buildInteractableModelContext(definitions: Record<string, Unstable_InteractableDefinition>, partialSchemaCache: Map<string, PartialJSONSchema>, setDefState: (id: string, updater: (prev: unknown) => unknown) => void, streamBaselines?: Map<string, {
7
+ targetId: string;
8
+ state: unknown;
9
+ }>): {
8
10
  tools: Record<string, Tool<any, any>>;
11
+ unstable_composerMetadata?: Record<string, unknown>;
9
12
  } | undefined;
10
13
  //#endregion
11
- export { buildInteractableModelContext, shallowMerge };
14
+ export { PartialJSONSchema, buildInteractableModelContext };
12
15
  //# sourceMappingURL=interactable-model-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactable-model-context.d.ts","names":[],"sources":["../../../src/react/client/interactable-model-context.ts"],"mappings":";;;;iBAMgB,YAAA,CAAa,IAAA,WAAe,OAAgB;AAAA,iBAiB5C,6BAAA,CACd,WAAA,EAAa,MAAA,SAAe,sBAAA,GAC5B,kBAAA,EAAoB,GAAA,SAAY,uBAAA,GAChC,WAAA,GAAc,EAAA,UAAY,OAAA,GAAU,IAAA;EACjC,MAAA;EAAgB,KAAA,EAAO,MAAA,SAAe,IAAA;AAAA"}
1
+ {"version":3,"file":"interactable-model-context.d.ts","names":[],"sources":["../../../src/react/client/interactable-model-context.ts"],"mappings":";;;;KAWY,iBAAA,GAAoB,UAAU,QAAQ,YAAA;AAAA,iBA2HlC,6BAAA,CACd,WAAA,EAAa,MAAA,SAAe,+BAAA,GAC5B,kBAAA,EAAoB,GAAA,SAAY,iBAAA,GAChC,WAAA,GAAc,EAAA,UAAY,OAAA,GAAU,IAAA,gCACpC,eAAA,GAAe,GAAA;;;;EAGX,KAAA,EAAO,MAAA,SAAe,IAAA;EACtB,yBAAA,GAA4B,MAAA;AAAA"}