@assistant-ui/react 0.14.14 → 0.14.15

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 (207) hide show
  1. package/README.md +5 -1
  2. package/dist/client/ExternalThread.d.ts +2 -12
  3. package/dist/client/ExternalThread.d.ts.map +1 -1
  4. package/dist/client/ExternalThread.js +30 -29
  5. package/dist/client/ExternalThread.js.map +1 -1
  6. package/dist/client/InMemoryThreadList.d.ts.map +1 -1
  7. package/dist/client/InMemoryThreadList.js +11 -10
  8. package/dist/client/InMemoryThreadList.js.map +1 -1
  9. package/dist/client/SingleThreadList.d.ts.map +1 -1
  10. package/dist/client/SingleThreadList.js +9 -8
  11. package/dist/client/SingleThreadList.js.map +1 -1
  12. package/dist/context/providers/ThreadViewportProvider.js +1 -1
  13. package/dist/context/providers/ThreadViewportProvider.js.map +1 -1
  14. package/dist/context/react/ThreadViewportContext.js +1 -1
  15. package/dist/context/react/utils/createContextHook.js +1 -1
  16. package/dist/context/react/utils/ensureBinding.js.map +1 -1
  17. package/dist/context/react/utils/useRuntimeState.js +1 -1
  18. package/dist/context/stores/ThreadViewport.js.map +1 -1
  19. package/dist/devtools/DevToolsHooks.js.map +1 -1
  20. package/dist/index.d.ts +4 -4
  21. package/dist/index.js +3 -3
  22. package/dist/legacy-runtime/AssistantRuntimeProvider.js +1 -1
  23. package/dist/legacy-runtime/cloud/auiV0.js +1 -1
  24. package/dist/legacy-runtime/hooks/AssistantContext.js.map +1 -1
  25. package/dist/legacy-runtime/hooks/AttachmentContext.js.map +1 -1
  26. package/dist/legacy-runtime/hooks/ComposerContext.js.map +1 -1
  27. package/dist/legacy-runtime/hooks/MessageContext.js.map +1 -1
  28. package/dist/legacy-runtime/hooks/MessagePartContext.js.map +1 -1
  29. package/dist/legacy-runtime/hooks/ThreadContext.js +1 -1
  30. package/dist/legacy-runtime/hooks/ThreadContext.js.map +1 -1
  31. package/dist/legacy-runtime/hooks/ThreadListItemContext.js.map +1 -1
  32. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js +1 -1
  33. package/dist/legacy-runtime/runtime-cores/assistant-transport/replayBoundaryStream.js +1 -1
  34. package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.js +1 -1
  35. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +1 -1
  36. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  37. package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js +1 -1
  38. package/dist/legacy-runtime/runtime-cores/assistant-transport/useLatestRef.js +1 -1
  39. package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  40. package/dist/mcp-apps/McpAppRenderer.js +7 -7
  41. package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
  42. package/dist/mcp-apps/McpAppsRemoteHost.d.ts.map +1 -1
  43. package/dist/mcp-apps/McpAppsRemoteHost.js +5 -4
  44. package/dist/mcp-apps/McpAppsRemoteHost.js.map +1 -1
  45. package/dist/mcp-apps/app-frame.d.ts +1 -1
  46. package/dist/mcp-apps/app-frame.d.ts.map +1 -1
  47. package/dist/mcp-apps/app-frame.js +82 -104
  48. package/dist/mcp-apps/app-frame.js.map +1 -1
  49. package/dist/mcp-apps/bridge.d.ts +3 -3
  50. package/dist/mcp-apps/bridge.d.ts.map +1 -1
  51. package/dist/mcp-apps/bridge.js +35 -10
  52. package/dist/mcp-apps/bridge.js.map +1 -1
  53. package/dist/mcp-apps/types.d.ts +2 -12
  54. package/dist/mcp-apps/types.d.ts.map +1 -1
  55. package/dist/mcp-apps/types.js.map +1 -1
  56. package/dist/model-context/frame/useAssistantFrameHost.js +1 -1
  57. package/dist/model-context/makeAssistantVisible.js +1 -1
  58. package/dist/model-context/makeAssistantVisible.js.map +1 -1
  59. package/dist/primitives/actionBar/ActionBarCopy.js +1 -1
  60. package/dist/primitives/actionBar/ActionBarExportMarkdown.js +1 -1
  61. package/dist/primitives/actionBar/ActionBarExportMarkdown.js.map +1 -1
  62. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +1 -1
  63. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +1 -1
  64. package/dist/primitives/actionBar/ActionBarInteractionContext.js +1 -1
  65. package/dist/primitives/actionBar/ActionBarRoot.js +1 -1
  66. package/dist/primitives/actionBar/ActionBarStopSpeaking.js +1 -1
  67. package/dist/primitives/actionBarMore/ActionBarMoreContent.js +1 -1
  68. package/dist/primitives/actionBarMore/ActionBarMoreItem.js +1 -1
  69. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js +1 -1
  70. package/dist/primitives/actionBarMore/ActionBarMoreSeparator.js +1 -1
  71. package/dist/primitives/actionBarMore/ActionBarMoreTrigger.js +1 -1
  72. package/dist/primitives/assistantModal/AssistantModalAnchor.js +1 -1
  73. package/dist/primitives/assistantModal/AssistantModalContent.js +1 -1
  74. package/dist/primitives/assistantModal/AssistantModalRoot.js +1 -1
  75. package/dist/primitives/assistantModal/AssistantModalTrigger.js +1 -1
  76. package/dist/primitives/attachment/AttachmentRemove.js +1 -1
  77. package/dist/primitives/attachment/AttachmentRemove.js.map +1 -1
  78. package/dist/primitives/attachment/AttachmentRoot.js +1 -1
  79. package/dist/primitives/attachment/AttachmentThumb.js +1 -1
  80. package/dist/primitives/branchPicker/BranchPickerRoot.js +1 -1
  81. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js +1 -1
  82. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js.map +1 -1
  83. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js +1 -1
  84. package/dist/primitives/composer/ComposerAddAttachment.js +1 -1
  85. package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
  86. package/dist/primitives/composer/ComposerAttachmentDropzone.js +1 -1
  87. package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
  88. package/dist/primitives/composer/ComposerDictationTranscript.js +1 -1
  89. package/dist/primitives/composer/ComposerInput.js +1 -1
  90. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  91. package/dist/primitives/composer/ComposerInputPluginContext.js +1 -1
  92. package/dist/primitives/composer/ComposerQuote.js +1 -1
  93. package/dist/primitives/composer/ComposerQuote.js.map +1 -1
  94. package/dist/primitives/composer/ComposerRoot.js +1 -1
  95. package/dist/primitives/composer/ComposerSend.js +1 -1
  96. package/dist/primitives/composer/ComposerStopDictation.js +1 -1
  97. package/dist/primitives/composer/ComposerStopDictation.js.map +1 -1
  98. package/dist/primitives/composer/trigger/TriggerPopover.js +2 -2
  99. package/dist/primitives/composer/trigger/TriggerPopover.js.map +1 -1
  100. package/dist/primitives/composer/trigger/TriggerPopoverAction.js +1 -1
  101. package/dist/primitives/composer/trigger/TriggerPopoverBack.js +1 -1
  102. package/dist/primitives/composer/trigger/TriggerPopoverCategories.js +1 -1
  103. package/dist/primitives/composer/trigger/TriggerPopoverDirective.js +1 -1
  104. package/dist/primitives/composer/trigger/TriggerPopoverItems.js +1 -1
  105. package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts.map +1 -1
  106. package/dist/primitives/composer/trigger/TriggerPopoverResource.js +8 -7
  107. package/dist/primitives/composer/trigger/TriggerPopoverResource.js.map +1 -1
  108. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js +1 -1
  109. package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts.map +1 -1
  110. package/dist/primitives/composer/trigger/triggerDetectionResource.js +5 -4
  111. package/dist/primitives/composer/trigger/triggerDetectionResource.js.map +1 -1
  112. package/dist/primitives/composer/trigger/triggerKeyboardResource.d.ts.map +1 -1
  113. package/dist/primitives/composer/trigger/triggerKeyboardResource.js +8 -7
  114. package/dist/primitives/composer/trigger/triggerKeyboardResource.js.map +1 -1
  115. package/dist/primitives/composer/trigger/triggerNavigationResource.d.ts.map +1 -1
  116. package/dist/primitives/composer/trigger/triggerNavigationResource.js +13 -12
  117. package/dist/primitives/composer/trigger/triggerNavigationResource.js.map +1 -1
  118. package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts.map +1 -1
  119. package/dist/primitives/composer/trigger/triggerSelectionResource.js +7 -6
  120. package/dist/primitives/composer/trigger/triggerSelectionResource.js.map +1 -1
  121. package/dist/primitives/error/ErrorMessage.js +1 -1
  122. package/dist/primitives/error/ErrorRoot.js +1 -1
  123. package/dist/primitives/message/MessagePartsGrouped.js +1 -1
  124. package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
  125. package/dist/primitives/message/MessageRoot.js +1 -1
  126. package/dist/primitives/message/MessageRoot.js.map +1 -1
  127. package/dist/primitives/messagePart/MessagePartImage.js +1 -1
  128. package/dist/primitives/messagePart/MessagePartText.js +1 -1
  129. package/dist/primitives/queueItem/QueueItemRemove.js +1 -1
  130. package/dist/primitives/queueItem/QueueItemRemove.js.map +1 -1
  131. package/dist/primitives/queueItem/QueueItemSteer.js +1 -1
  132. package/dist/primitives/queueItem/QueueItemSteer.js.map +1 -1
  133. package/dist/primitives/queueItem/QueueItemText.js +1 -1
  134. package/dist/primitives/reasoning/useScrollLock.js +1 -1
  135. package/dist/primitives/reasoning/useScrollLock.js.map +1 -1
  136. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js +1 -1
  137. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js.map +1 -1
  138. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js +1 -1
  139. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js.map +1 -1
  140. package/dist/primitives/suggestion/SuggestionDescription.js +1 -1
  141. package/dist/primitives/suggestion/SuggestionTitle.js +1 -1
  142. package/dist/primitives/suggestion/SuggestionTrigger.js +1 -1
  143. package/dist/primitives/suggestion/SuggestionTrigger.js.map +1 -1
  144. package/dist/primitives/thread/ThreadRoot.js +1 -1
  145. package/dist/primitives/thread/ThreadScrollToBottom.js +1 -1
  146. package/dist/primitives/thread/ThreadScrollToBottom.js.map +1 -1
  147. package/dist/primitives/thread/ThreadViewport.js +1 -1
  148. package/dist/primitives/thread/ThreadViewport.js.map +1 -1
  149. package/dist/primitives/thread/ThreadViewportFooter.js +1 -1
  150. package/dist/primitives/thread/ThreadViewportFooter.js.map +1 -1
  151. package/dist/primitives/thread/topAnchor/topAnchorTurn.js.map +1 -1
  152. package/dist/primitives/thread/topAnchor/topAnchorUtils.js.map +1 -1
  153. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.js +1 -1
  154. package/dist/primitives/thread/useThreadViewportAutoScroll.js +1 -1
  155. package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
  156. package/dist/primitives/threadList/ThreadListNew.js +1 -1
  157. package/dist/primitives/threadList/ThreadListRoot.js +1 -1
  158. package/dist/primitives/threadListItem/ThreadListItemRoot.js +1 -1
  159. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js +1 -1
  160. package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.js +1 -1
  161. package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.js +1 -1
  162. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js +1 -1
  163. package/dist/sandbox-host/SandboxHost.d.ts +50 -0
  164. package/dist/sandbox-host/SandboxHost.d.ts.map +1 -0
  165. package/dist/sandbox-host/SandboxHost.js +85 -0
  166. package/dist/sandbox-host/SandboxHost.js.map +1 -0
  167. package/dist/unstable/useMentionAdapter.js +1 -1
  168. package/dist/unstable/useMentionAdapter.js.map +1 -1
  169. package/dist/unstable/useSlashCommandAdapter.js +1 -1
  170. package/dist/unstable/useSlashCommandAdapter.js.map +1 -1
  171. package/dist/utils/Primitive.js +1 -1
  172. package/dist/utils/createActionButton.js +1 -1
  173. package/dist/utils/createActionButton.js.map +1 -1
  174. package/dist/utils/hooks/useManagedRef.js +1 -1
  175. package/dist/utils/hooks/useMediaQuery.js +1 -1
  176. package/dist/utils/hooks/useMediaQuery.js.map +1 -1
  177. package/dist/utils/hooks/useOnResizeContent.js +1 -1
  178. package/dist/utils/hooks/useOnScrollToBottom.js +1 -1
  179. package/dist/utils/hooks/useSizeHandle.js +1 -1
  180. package/dist/utils/json/is-json.js.map +1 -1
  181. package/dist/utils/smooth/SmoothContext.js +1 -1
  182. package/dist/utils/smooth/SmoothContext.js.map +1 -1
  183. package/dist/utils/smooth/useSmooth.js +1 -1
  184. package/dist/utils/smooth/useSmooth.js.map +1 -1
  185. package/dist/utils/useToolArgsFieldStatus.d.ts +2 -2
  186. package/dist/utils/useToolArgsFieldStatus.d.ts.map +1 -1
  187. package/package.json +21 -20
  188. package/src/client/ExternalThread.ts +484 -515
  189. package/src/client/InMemoryThreadList.ts +153 -162
  190. package/src/client/SingleThreadList.ts +87 -84
  191. package/src/context/providers/ThreadViewportProvider.tsx +2 -2
  192. package/src/index.ts +8 -1
  193. package/src/mcp-apps/McpAppRenderer.tsx +28 -35
  194. package/src/mcp-apps/McpAppsRemoteHost.ts +25 -24
  195. package/src/mcp-apps/app-frame.tsx +100 -141
  196. package/src/mcp-apps/bridge.test.ts +100 -60
  197. package/src/mcp-apps/bridge.ts +43 -21
  198. package/src/mcp-apps/types.ts +2 -12
  199. package/src/primitives/composer/trigger/TriggerPopover.tsx +1 -1
  200. package/src/primitives/composer/trigger/TriggerPopoverResource.ts +75 -76
  201. package/src/primitives/composer/trigger/triggerDetectionResource.ts +6 -5
  202. package/src/primitives/composer/trigger/triggerKeyboardResource.ts +9 -13
  203. package/src/primitives/composer/trigger/triggerNavigationResource.ts +14 -19
  204. package/src/primitives/composer/trigger/triggerSelectionResource.ts +8 -7
  205. package/src/sandbox-host/SandboxHost.test.tsx +231 -0
  206. package/src/sandbox-host/SandboxHost.tsx +185 -0
  207. package/src/tests/local-runtime-queue.test.tsx +305 -0
@@ -1,13 +1,12 @@
1
- import { resource, tapState, tapMemo } from "@assistant-ui/tap";
1
+ import { useState, useMemo } from "react";
2
+ import { resource, withKey, type ResourceElement } from "@assistant-ui/tap";
2
3
  import {
3
4
  type ClientOutput,
4
- tapClientLookup,
5
+ useClientLookup,
5
6
  Derived,
6
7
  attachTransformScopes,
7
- tapClientResource,
8
+ useClientResource,
8
9
  } from "@assistant-ui/store";
9
- import { withKey } from "@assistant-ui/tap";
10
- import type { ResourceElement } from "@assistant-ui/tap";
11
10
 
12
11
  import { ModelContext, Suggestions } from "@assistant-ui/core/store";
13
12
  import { Tools, DataRenderers } from "@assistant-ui/core/react";
@@ -28,172 +27,164 @@ type ThreadData = {
28
27
  };
29
28
 
30
29
  // ThreadListItem Client
31
- const ThreadListItemClient = resource(
32
- (props: {
33
- data: ThreadData;
34
- onSwitchTo: () => void;
35
- onUpdateCustom: (custom: Record<string, unknown> | undefined) => void;
36
- onArchive: () => void;
37
- onUnarchive: () => void;
38
- onDelete: () => void;
39
- }): ClientOutput<"threadListItem"> => {
40
- const {
41
- data,
42
- onSwitchTo,
43
- onUpdateCustom,
44
- onArchive,
45
- onUnarchive,
46
- onDelete,
47
- } = props;
48
- const state = tapMemo(
49
- () => ({
50
- id: data.id,
51
- remoteId: undefined,
52
- externalId: undefined,
53
- title: data.title,
54
- status: data.status,
55
- custom: data.custom,
56
- }),
57
- [data.id, data.title, data.status, data.custom],
58
- );
59
-
60
- return {
61
- getState: () => state,
62
- switchTo: onSwitchTo,
63
- rename: () => {},
64
- updateCustom: onUpdateCustom,
65
- archive: onArchive,
66
- unarchive: onUnarchive,
67
- delete: onDelete,
68
- generateTitle: () => {},
69
- initialize: async () => ({ remoteId: data.id, externalId: undefined }),
70
- detach: () => {},
71
- };
72
- },
73
- );
30
+ const ThreadListItemClient = resource(function ThreadListItemClient(props: {
31
+ data: ThreadData;
32
+ onSwitchTo: () => void;
33
+ onUpdateCustom: (custom: Record<string, unknown> | undefined) => void;
34
+ onArchive: () => void;
35
+ onUnarchive: () => void;
36
+ onDelete: () => void;
37
+ }): ClientOutput<"threadListItem"> {
38
+ const { data, onSwitchTo, onUpdateCustom, onArchive, onUnarchive, onDelete } =
39
+ props;
40
+ const state = useMemo(
41
+ () => ({
42
+ id: data.id,
43
+ remoteId: undefined,
44
+ externalId: undefined,
45
+ title: data.title,
46
+ status: data.status,
47
+ custom: data.custom,
48
+ }),
49
+ [data.id, data.title, data.status, data.custom],
50
+ );
51
+
52
+ return {
53
+ getState: () => state,
54
+ switchTo: onSwitchTo,
55
+ rename: () => {},
56
+ updateCustom: onUpdateCustom,
57
+ archive: onArchive,
58
+ unarchive: onUnarchive,
59
+ delete: onDelete,
60
+ generateTitle: () => {},
61
+ initialize: async () => ({ remoteId: data.id, externalId: undefined }),
62
+ detach: () => {},
63
+ };
64
+ });
74
65
 
75
66
  // InMemoryThreadList Client
76
- export const InMemoryThreadList = resource(
77
- (props: InMemoryThreadListProps): ClientOutput<"threads"> => {
78
- const {
79
- thread: threadFactory,
80
- onSwitchToThread,
81
- onSwitchToNewThread,
82
- } = props;
83
-
84
- const [mainThreadId, setMainThreadId] = tapState("main");
85
- const [threads, setThreads] = tapState<readonly ThreadData[]>(() => [
86
- { id: "main", title: "Main Thread", status: "regular" },
87
- ]);
88
-
89
- const handleSwitchToThread = (threadId: string) => {
90
- setMainThreadId(threadId);
91
- onSwitchToThread?.(threadId);
92
- };
93
-
94
- const handleArchive = (threadId: string) => {
95
- setThreads((prev) =>
96
- prev.map((t) =>
97
- t.id === threadId ? { ...t, status: "archived" as const } : t,
98
- ),
99
- );
100
- };
67
+ export const InMemoryThreadList = resource(function InMemoryThreadList(
68
+ props: InMemoryThreadListProps,
69
+ ): ClientOutput<"threads"> {
70
+ const {
71
+ thread: threadFactory,
72
+ onSwitchToThread,
73
+ onSwitchToNewThread,
74
+ } = props;
75
+
76
+ const [mainThreadId, setMainThreadId] = useState("main");
77
+ const [threads, setThreads] = useState<readonly ThreadData[]>(() => [
78
+ { id: "main", title: "Main Thread", status: "regular" },
79
+ ]);
80
+
81
+ const handleSwitchToThread = (threadId: string) => {
82
+ setMainThreadId(threadId);
83
+ onSwitchToThread?.(threadId);
84
+ };
85
+
86
+ const handleArchive = (threadId: string) => {
87
+ setThreads((prev) =>
88
+ prev.map((t) =>
89
+ t.id === threadId ? { ...t, status: "archived" as const } : t,
90
+ ),
91
+ );
92
+ };
101
93
 
102
- const handleUnarchive = (threadId: string) => {
103
- setThreads((prev) =>
104
- prev.map((t) =>
105
- t.id === threadId ? { ...t, status: "regular" as const } : t,
94
+ const handleUnarchive = (threadId: string) => {
95
+ setThreads((prev) =>
96
+ prev.map((t) =>
97
+ t.id === threadId ? { ...t, status: "regular" as const } : t,
98
+ ),
99
+ );
100
+ };
101
+
102
+ const handleUpdateCustom = (
103
+ threadId: string,
104
+ custom: Record<string, unknown> | undefined,
105
+ ) => {
106
+ setThreads((prev) =>
107
+ prev.map((t) => (t.id === threadId ? { ...t, custom } : t)),
108
+ );
109
+ };
110
+
111
+ const handleDelete = (threadId: string) => {
112
+ setThreads((prev) => prev.filter((t) => t.id !== threadId));
113
+ if (mainThreadId === threadId) {
114
+ const remaining = threads.filter((t) => t.id !== threadId);
115
+ setMainThreadId(remaining[0]?.id || "main");
116
+ }
117
+ };
118
+
119
+ const handleSwitchToNewThread = () => {
120
+ const newId = `thread-${Date.now()}`;
121
+ setThreads((prev) => [
122
+ ...prev,
123
+ { id: newId, title: "New Thread", status: "regular" },
124
+ ]);
125
+ setMainThreadId(newId);
126
+ onSwitchToNewThread?.();
127
+ };
128
+
129
+ const threadListItems = useClientLookup(
130
+ () =>
131
+ threads.map((t) =>
132
+ withKey(
133
+ t.id,
134
+ ThreadListItemClient({
135
+ data: t,
136
+ onSwitchTo: () => handleSwitchToThread(t.id),
137
+ onUpdateCustom: (custom) => handleUpdateCustom(t.id, custom),
138
+ onArchive: () => handleArchive(t.id),
139
+ onUnarchive: () => handleUnarchive(t.id),
140
+ onDelete: () => handleDelete(t.id),
141
+ }),
106
142
  ),
107
- );
108
- };
109
-
110
- const handleUpdateCustom = (
111
- threadId: string,
112
- custom: Record<string, unknown> | undefined,
113
- ) => {
114
- setThreads((prev) =>
115
- prev.map((t) => (t.id === threadId ? { ...t, custom } : t)),
116
- );
117
- };
118
-
119
- const handleDelete = (threadId: string) => {
120
- setThreads((prev) => prev.filter((t) => t.id !== threadId));
121
- if (mainThreadId === threadId) {
122
- const remaining = threads.filter((t) => t.id !== threadId);
123
- setMainThreadId(remaining[0]?.id || "main");
124
- }
125
- };
143
+ ),
144
+ [threads],
145
+ );
126
146
 
127
- const handleSwitchToNewThread = () => {
128
- const newId = `thread-${Date.now()}`;
129
- setThreads((prev) => [
130
- ...prev,
131
- { id: newId, title: "New Thread", status: "regular" },
132
- ]);
133
- setMainThreadId(newId);
134
- onSwitchToNewThread?.();
135
- };
136
-
137
- const threadListItems = tapClientLookup(
138
- () =>
139
- threads.map((t) =>
140
- withKey(
141
- t.id,
142
- ThreadListItemClient({
143
- data: t,
144
- onSwitchTo: () => handleSwitchToThread(t.id),
145
- onUpdateCustom: (custom) => handleUpdateCustom(t.id, custom),
146
- onArchive: () => handleArchive(t.id),
147
- onUnarchive: () => handleUnarchive(t.id),
148
- onDelete: () => handleDelete(t.id),
149
- }),
150
- ),
151
- ),
152
- [threads],
153
- );
147
+ // Create the main thread
148
+ const mainThreadClient = useClientResource(threadFactory(mainThreadId));
154
149
 
155
- // Create the main thread
156
- const mainThreadClient = tapClientResource(threadFactory(mainThreadId));
157
-
158
- const state = tapMemo(() => {
159
- const regularThreads = threads.filter((t) => t.status === "regular");
160
- const archivedThreads = threads.filter((t) => t.status === "archived");
161
-
162
- return {
163
- mainThreadId,
164
- newThreadId: null,
165
- isLoading: false,
166
- isLoadingMore: false,
167
- hasMore: false,
168
- threadIds: regularThreads.map((t) => t.id),
169
- archivedThreadIds: archivedThreads.map((t) => t.id),
170
- threadItems: threadListItems.state,
171
- main: mainThreadClient.state,
172
- };
173
- }, [mainThreadId, threads, threadListItems.state, mainThreadClient.state]);
150
+ const state = useMemo(() => {
151
+ const regularThreads = threads.filter((t) => t.status === "regular");
152
+ const archivedThreads = threads.filter((t) => t.status === "archived");
174
153
 
175
154
  return {
176
- getState: () => state,
177
- switchToThread: handleSwitchToThread,
178
- switchToNewThread: handleSwitchToNewThread,
179
- getLoadThreadsPromise: () => RESOLVED_PROMISE,
180
- reload: () => RESOLVED_PROMISE,
181
- loadMore: () => RESOLVED_PROMISE,
182
- item: (selector) => {
183
- if (selector === "main") {
184
- const index = threads.findIndex((t) => t.id === mainThreadId);
185
- return threadListItems.get({ index: index === -1 ? 0 : index });
186
- }
187
- if ("id" in selector) {
188
- const index = threads.findIndex((t) => t.id === selector.id);
189
- return threadListItems.get({ index });
190
- }
191
- return threadListItems.get(selector);
192
- },
193
- thread: () => mainThreadClient.methods,
155
+ mainThreadId,
156
+ newThreadId: null,
157
+ isLoading: false,
158
+ isLoadingMore: false,
159
+ hasMore: false,
160
+ threadIds: regularThreads.map((t) => t.id),
161
+ archivedThreadIds: archivedThreads.map((t) => t.id),
162
+ threadItems: threadListItems.state,
163
+ main: mainThreadClient.state,
194
164
  };
195
- },
196
- );
165
+ }, [mainThreadId, threads, threadListItems.state, mainThreadClient.state]);
166
+
167
+ return {
168
+ getState: () => state,
169
+ switchToThread: handleSwitchToThread,
170
+ switchToNewThread: handleSwitchToNewThread,
171
+ getLoadThreadsPromise: () => RESOLVED_PROMISE,
172
+ reload: () => RESOLVED_PROMISE,
173
+ loadMore: () => RESOLVED_PROMISE,
174
+ item: (selector) => {
175
+ if (selector === "main") {
176
+ const index = threads.findIndex((t) => t.id === mainThreadId);
177
+ return threadListItems.get({ index: index === -1 ? 0 : index });
178
+ }
179
+ if ("id" in selector) {
180
+ const index = threads.findIndex((t) => t.id === selector.id);
181
+ return threadListItems.get({ index });
182
+ }
183
+ return threadListItems.get(selector);
184
+ },
185
+ thread: () => mainThreadClient.methods,
186
+ };
187
+ });
197
188
 
198
189
  attachTransformScopes(InMemoryThreadList, (scopes, parent) => {
199
190
  scopes.thread ??= Derived({
@@ -1,36 +1,39 @@
1
- import { resource, tapMemo, tapState } from "@assistant-ui/tap";
1
+ import { useMemo, useState } from "react";
2
+ import { resource } from "@assistant-ui/tap";
2
3
  import {
3
4
  type ClientElement,
4
5
  type ClientOutput,
5
- tapClientResource,
6
+ useClientResource,
6
7
  } from "@assistant-ui/store";
7
8
 
8
9
  const RESOLVED_PROMISE = Promise.resolve();
9
10
  const THREAD_ID = "default";
10
11
 
11
- const SingleThreadListItem = resource((): ClientOutput<"threadListItem"> => {
12
- const [custom, setCustom] = tapState<Record<string, unknown> | undefined>();
12
+ const SingleThreadListItem = resource(
13
+ function SingleThreadListItem(): ClientOutput<"threadListItem"> {
14
+ const [custom, setCustom] = useState<Record<string, unknown> | undefined>();
13
15
 
14
- return {
15
- getState: () => ({
16
- id: THREAD_ID,
17
- remoteId: undefined,
18
- externalId: undefined,
19
- title: undefined,
20
- status: "regular",
21
- custom,
22
- }),
23
- switchTo: () => {},
24
- rename: () => {},
25
- updateCustom: setCustom,
26
- archive: () => {},
27
- unarchive: () => {},
28
- delete: () => {},
29
- generateTitle: () => {},
30
- initialize: async () => ({ remoteId: THREAD_ID, externalId: undefined }),
31
- detach: () => {},
32
- };
33
- });
16
+ return {
17
+ getState: () => ({
18
+ id: THREAD_ID,
19
+ remoteId: undefined,
20
+ externalId: undefined,
21
+ title: undefined,
22
+ status: "regular",
23
+ custom,
24
+ }),
25
+ switchTo: () => {},
26
+ rename: () => {},
27
+ updateCustom: setCustom,
28
+ archive: () => {},
29
+ unarchive: () => {},
30
+ delete: () => {},
31
+ generateTitle: () => {},
32
+ initialize: async () => ({ remoteId: THREAD_ID, externalId: undefined }),
33
+ detach: () => {},
34
+ };
35
+ },
36
+ );
34
37
 
35
38
  type SingleThreadListProps = {
36
39
  thread: ClientElement<"thread">;
@@ -41,65 +44,65 @@ type SingleThreadListProps = {
41
44
  * Automatically provided by ExternalThread when no threads scope exists.
42
45
  * Mounts the provided thread resource element.
43
46
  */
44
- export const SingleThreadList = resource(
45
- ({ thread }: SingleThreadListProps): ClientOutput<"threads"> => {
46
- const itemClient = tapClientResource(SingleThreadListItem());
47
- const threadClient = tapClientResource(thread);
47
+ export const SingleThreadList = resource(function SingleThreadList({
48
+ thread,
49
+ }: SingleThreadListProps): ClientOutput<"threads"> {
50
+ const itemClient = useClientResource(SingleThreadListItem());
51
+ const threadClient = useClientResource(thread);
48
52
 
49
- const state = tapMemo(
50
- () => ({
51
- mainThreadId: THREAD_ID,
52
- newThreadId: null,
53
- isLoading: false,
54
- isLoadingMore: false,
55
- hasMore: false,
56
- threadIds: [THREAD_ID],
57
- archivedThreadIds: [],
58
- threadItems: [itemClient.state],
59
- main: threadClient.state,
60
- }),
61
- [itemClient.state, threadClient.state],
62
- );
53
+ const state = useMemo(
54
+ () => ({
55
+ mainThreadId: THREAD_ID,
56
+ newThreadId: null,
57
+ isLoading: false,
58
+ isLoadingMore: false,
59
+ hasMore: false,
60
+ threadIds: [THREAD_ID],
61
+ archivedThreadIds: [],
62
+ threadItems: [itemClient.state],
63
+ main: threadClient.state,
64
+ }),
65
+ [itemClient.state, threadClient.state],
66
+ );
63
67
 
64
- return {
65
- getState: () => state,
66
- switchToThread: () => {
67
- throw new Error("SingleThreadList does not support switchToThread");
68
- },
69
- switchToNewThread: () => {
70
- throw new Error("SingleThreadList does not support switchToNewThread");
71
- },
72
- getLoadThreadsPromise: () => RESOLVED_PROMISE,
73
- reload: () => RESOLVED_PROMISE,
74
- loadMore: () => RESOLVED_PROMISE,
75
- item: (selector) => {
76
- if (
77
- selector !== "main" &&
78
- !(
79
- typeof selector === "object" &&
80
- "id" in selector &&
81
- selector.id === THREAD_ID
82
- ) &&
83
- !(
84
- typeof selector === "object" &&
85
- "index" in selector &&
86
- selector.index === 0
87
- )
88
- ) {
89
- throw new Error(
90
- `SingleThreadList: unknown item selector ${JSON.stringify(selector)}`,
91
- );
92
- }
93
- return itemClient.methods;
94
- },
95
- thread: (selector) => {
96
- if (selector !== "main" && selector !== THREAD_ID) {
97
- throw new Error(
98
- `SingleThreadList: unknown thread selector ${JSON.stringify(selector)}`,
99
- );
100
- }
101
- return threadClient.methods;
102
- },
103
- };
104
- },
105
- );
68
+ return {
69
+ getState: () => state,
70
+ switchToThread: () => {
71
+ throw new Error("SingleThreadList does not support switchToThread");
72
+ },
73
+ switchToNewThread: () => {
74
+ throw new Error("SingleThreadList does not support switchToNewThread");
75
+ },
76
+ getLoadThreadsPromise: () => RESOLVED_PROMISE,
77
+ reload: () => RESOLVED_PROMISE,
78
+ loadMore: () => RESOLVED_PROMISE,
79
+ item: (selector) => {
80
+ if (
81
+ selector !== "main" &&
82
+ !(
83
+ typeof selector === "object" &&
84
+ "id" in selector &&
85
+ selector.id === THREAD_ID
86
+ ) &&
87
+ !(
88
+ typeof selector === "object" &&
89
+ "index" in selector &&
90
+ selector.index === 0
91
+ )
92
+ ) {
93
+ throw new Error(
94
+ `SingleThreadList: unknown item selector ${JSON.stringify(selector)}`,
95
+ );
96
+ }
97
+ return itemClient.methods;
98
+ },
99
+ thread: (selector) => {
100
+ if (selector !== "main" && selector !== THREAD_ID) {
101
+ throw new Error(
102
+ `SingleThreadList: unknown thread selector ${JSON.stringify(selector)}`,
103
+ );
104
+ }
105
+ return threadClient.methods;
106
+ },
107
+ };
108
+ });
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
- import type { FC, PropsWithChildren } from "react";
4
- import { useEffect, useState } from "react";
3
+ import { type FC, type PropsWithChildren, useEffect, useState } from "react";
4
+
5
5
  import {
6
6
  makeThreadViewportStore,
7
7
  type ThreadViewportStoreOptions,
package/src/index.ts CHANGED
@@ -136,6 +136,12 @@ export type {
136
136
  ExternalStoreThreadListAdapter,
137
137
  ExternalStoreThreadData,
138
138
  } from "@assistant-ui/core";
139
+ export {
140
+ createMessageQueue,
141
+ type MessageQueueDriver,
142
+ type MessageQueueController,
143
+ type ExternalThreadQueueAdapter,
144
+ } from "@assistant-ui/core";
139
145
  export { useExternalStoreRuntime } from "./legacy-runtime/runtime-cores/external-store/useExternalStoreRuntime";
140
146
  export { useExternalStoreSharedOptions } from "@assistant-ui/core/react";
141
147
  export {
@@ -192,9 +198,11 @@ export {
192
198
  type ToolkitDefinitionEntry,
193
199
  defineToolkit,
194
200
  stubTool,
201
+ externalTool,
195
202
  useAuiToolOverrides,
196
203
  hitl,
197
204
  hitlTool,
205
+ humanTool,
198
206
  providerTool,
199
207
  type ProviderToolConfig,
200
208
  defineMcpToolkit,
@@ -365,7 +373,6 @@ export {
365
373
  ExternalThread,
366
374
  type ExternalThreadProps,
367
375
  type ExternalThreadMessage,
368
- type ExternalThreadQueueAdapter,
369
376
  } from "./client/ExternalThread";
370
377
  export {
371
378
  InMemoryThreadList,
@@ -14,13 +14,8 @@ import type {
14
14
  ToolCallMessagePartProps,
15
15
  } from "@assistant-ui/core/react";
16
16
  import { useAui } from "@assistant-ui/store";
17
- import {
18
- resource,
19
- tapConst,
20
- tapRef,
21
- tapResource,
22
- type ResourceElement,
23
- } from "@assistant-ui/tap";
17
+
18
+ import { useResource, resource, type ResourceElement } from "@assistant-ui/tap";
24
19
  import { McpAppFrame } from "./app-frame";
25
20
  import type {
26
21
  McpAppBridgeHandlers,
@@ -136,7 +131,7 @@ function InlineRenderer({
136
131
  return () => {
137
132
  cancelled = true;
138
133
  };
139
- // oxlint-disable-next-line tap-hooks/exhaustive-deps -- re-fetch only when URI changes; appForRender identity is unstable and internalsRef is a stable ref
134
+ // oxlint-disable-next-line react/exhaustive-deps -- re-fetch only when URI changes; appForRender identity is unstable and internalsRef is a stable ref
140
135
  }, [resourceUri]);
141
136
 
142
137
  const bridgeHandlers = useMemo<McpAppBridgeHandlers>(
@@ -200,30 +195,28 @@ function InlineRenderer({
200
195
  * renderer loads that resource from the configured host and displays it in a
201
196
  * sandboxed frame.
202
197
  */
203
- export const McpAppRenderer = resource(
204
- (
205
- options: McpAppRendererOptions,
206
- ): { readonly render: ToolCallMessagePartComponent } => {
207
- const host = tapResource(options.host);
208
-
209
- const optionsRef = tapRef<McpAppRendererOptions>(options);
210
- optionsRef.current = options;
211
-
212
- const internalsRef = tapRef<{ host: McpAppsHost }>({ host });
213
- internalsRef.current = { host };
214
-
215
- const render = tapConst((): ToolCallMessagePartComponent => {
216
- const Render: ToolCallMessagePartComponent = (props) => (
217
- <InlineRenderer
218
- part={props}
219
- internalsRef={internalsRef}
220
- optionsRef={optionsRef}
221
- />
222
- );
223
- Render.displayName = "McpAppRenderer";
224
- return Render;
225
- }, []);
226
-
227
- return { render };
228
- },
229
- );
198
+ export const McpAppRenderer = resource(function McpAppRenderer(
199
+ options: McpAppRendererOptions,
200
+ ): { readonly render: ToolCallMessagePartComponent } {
201
+ const host = useResource(options.host);
202
+
203
+ const optionsRef = useRef<McpAppRendererOptions>(options);
204
+ optionsRef.current = options;
205
+
206
+ const internalsRef = useRef<{ host: McpAppsHost }>({ host });
207
+ internalsRef.current = { host };
208
+
209
+ const render = useMemo((): ToolCallMessagePartComponent => {
210
+ const Render: ToolCallMessagePartComponent = (props) => (
211
+ <InlineRenderer
212
+ part={props}
213
+ internalsRef={internalsRef}
214
+ optionsRef={optionsRef}
215
+ />
216
+ );
217
+ Render.displayName = "McpAppRenderer";
218
+ return Render;
219
+ }, []);
220
+
221
+ return { render };
222
+ });