@assistant-ui/react 0.12.28 → 0.14.2

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 (187) hide show
  1. package/README.md +58 -42
  2. package/dist/client/ExternalThread.d.ts +7 -0
  3. package/dist/client/ExternalThread.d.ts.map +1 -1
  4. package/dist/client/ExternalThread.js +24 -18
  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 +3 -0
  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 +3 -0
  11. package/dist/client/SingleThreadList.js.map +1 -1
  12. package/dist/context/providers/ThreadViewportProvider.d.ts.map +1 -1
  13. package/dist/context/providers/ThreadViewportProvider.js +2 -10
  14. package/dist/context/providers/ThreadViewportProvider.js.map +1 -1
  15. package/dist/context/stores/ThreadViewport.d.ts +46 -4
  16. package/dist/context/stores/ThreadViewport.d.ts.map +1 -1
  17. package/dist/context/stores/ThreadViewport.js +51 -7
  18. package/dist/context/stores/ThreadViewport.js.map +1 -1
  19. package/dist/index.d.ts +5 -30
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +3 -28
  22. package/dist/index.js.map +1 -1
  23. package/dist/legacy-runtime/cloud/auiV0.d.ts +10 -1
  24. package/dist/legacy-runtime/cloud/auiV0.d.ts.map +1 -1
  25. package/dist/legacy-runtime/cloud/auiV0.js +21 -3
  26. package/dist/legacy-runtime/cloud/auiV0.js.map +1 -1
  27. package/dist/legacy-runtime/runtime-cores/assistant-transport/utils.d.ts +1 -1
  28. package/dist/legacy-runtime/runtime-cores/assistant-transport/utils.d.ts.map +1 -1
  29. package/dist/legacy-runtime/runtime-cores/assistant-transport/utils.js +1 -1
  30. package/dist/legacy-runtime/runtime-cores/assistant-transport/utils.js.map +1 -1
  31. package/dist/mcp-apps/McpAppRenderer.d.ts +28 -0
  32. package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -0
  33. package/dist/mcp-apps/McpAppRenderer.js +115 -0
  34. package/dist/mcp-apps/McpAppRenderer.js.map +1 -0
  35. package/dist/mcp-apps/McpAppsRemoteHost.d.ts +3 -0
  36. package/dist/mcp-apps/McpAppsRemoteHost.d.ts.map +1 -0
  37. package/dist/mcp-apps/McpAppsRemoteHost.js +27 -0
  38. package/dist/mcp-apps/McpAppsRemoteHost.js.map +1 -0
  39. package/dist/mcp-apps/app-frame.d.ts +3 -0
  40. package/dist/mcp-apps/app-frame.d.ts.map +1 -0
  41. package/dist/mcp-apps/app-frame.js +203 -0
  42. package/dist/mcp-apps/app-frame.js.map +1 -0
  43. package/dist/mcp-apps/bridge.d.ts +18 -0
  44. package/dist/mcp-apps/bridge.d.ts.map +1 -0
  45. package/dist/mcp-apps/bridge.js +290 -0
  46. package/dist/mcp-apps/bridge.js.map +1 -0
  47. package/dist/mcp-apps/index.d.ts +4 -0
  48. package/dist/mcp-apps/index.d.ts.map +1 -0
  49. package/dist/mcp-apps/index.js +3 -0
  50. package/dist/mcp-apps/index.js.map +1 -0
  51. package/dist/mcp-apps/types.d.ts +144 -0
  52. package/dist/mcp-apps/types.d.ts.map +1 -0
  53. package/dist/mcp-apps/types.js +3 -0
  54. package/dist/mcp-apps/types.js.map +1 -0
  55. package/dist/mcp-apps/utils.d.ts +5 -0
  56. package/dist/mcp-apps/utils.d.ts.map +1 -0
  57. package/dist/mcp-apps/utils.js +10 -0
  58. package/dist/mcp-apps/utils.js.map +1 -0
  59. package/dist/primitives/composer/ComposerInput.d.ts +6 -0
  60. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  61. package/dist/primitives/composer/ComposerInput.js +28 -6
  62. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  63. package/dist/primitives/composer/trigger/TriggerPopover.d.ts.map +1 -1
  64. package/dist/primitives/composer/trigger/TriggerPopover.js +17 -1
  65. package/dist/primitives/composer/trigger/TriggerPopover.js.map +1 -1
  66. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts +33 -0
  67. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts.map +1 -1
  68. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js +80 -11
  69. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js.map +1 -1
  70. package/dist/primitives/composer/trigger/triggerKeyboardResource.d.ts.map +1 -1
  71. package/dist/primitives/composer/trigger/triggerKeyboardResource.js +2 -1
  72. package/dist/primitives/composer/trigger/triggerKeyboardResource.js.map +1 -1
  73. package/dist/primitives/message/MessageRoot.d.ts +6 -30
  74. package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
  75. package/dist/primitives/message/MessageRoot.js +68 -25
  76. package/dist/primitives/message/MessageRoot.js.map +1 -1
  77. package/dist/primitives/messagePart/useMessagePartSource.d.ts +22 -3
  78. package/dist/primitives/messagePart/useMessagePartSource.d.ts.map +1 -1
  79. package/dist/primitives/thread/ThreadViewport.d.ts +38 -0
  80. package/dist/primitives/thread/ThreadViewport.d.ts.map +1 -1
  81. package/dist/primitives/thread/ThreadViewport.js +53 -5
  82. package/dist/primitives/thread/ThreadViewport.js.map +1 -1
  83. package/dist/primitives/thread/ThreadViewportFooter.d.ts +2 -1
  84. package/dist/primitives/thread/ThreadViewportFooter.d.ts.map +1 -1
  85. package/dist/primitives/thread/ThreadViewportFooter.js +2 -1
  86. package/dist/primitives/thread/ThreadViewportFooter.js.map +1 -1
  87. package/dist/primitives/thread/topAnchor/computeTopAnchorSlack.d.ts +22 -0
  88. package/dist/primitives/thread/topAnchor/computeTopAnchorSlack.d.ts.map +1 -0
  89. package/dist/primitives/thread/topAnchor/computeTopAnchorSlack.js +53 -0
  90. package/dist/primitives/thread/topAnchor/computeTopAnchorSlack.js.map +1 -0
  91. package/dist/primitives/thread/topAnchor/createReserveObservers.d.ts +5 -0
  92. package/dist/primitives/thread/topAnchor/createReserveObservers.d.ts.map +1 -0
  93. package/dist/primitives/thread/topAnchor/createReserveObservers.js +38 -0
  94. package/dist/primitives/thread/topAnchor/createReserveObservers.js.map +1 -0
  95. package/dist/primitives/thread/topAnchor/mountTopAnchorReserve.d.ts +22 -0
  96. package/dist/primitives/thread/topAnchor/mountTopAnchorReserve.d.ts.map +1 -0
  97. package/dist/primitives/thread/topAnchor/mountTopAnchorReserve.js +75 -0
  98. package/dist/primitives/thread/topAnchor/mountTopAnchorReserve.js.map +1 -0
  99. package/dist/primitives/thread/topAnchor/topAnchorTurn.d.ts +15 -0
  100. package/dist/primitives/thread/topAnchor/topAnchorTurn.d.ts.map +1 -0
  101. package/dist/primitives/thread/topAnchor/topAnchorTurn.js +13 -0
  102. package/dist/primitives/thread/topAnchor/topAnchorTurn.js.map +1 -0
  103. package/dist/primitives/thread/topAnchor/topAnchorUtils.d.ts +15 -0
  104. package/dist/primitives/thread/topAnchor/topAnchorUtils.d.ts.map +1 -0
  105. package/dist/primitives/thread/topAnchor/topAnchorUtils.js +51 -0
  106. package/dist/primitives/thread/topAnchor/topAnchorUtils.js.map +1 -0
  107. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.d.ts +7 -0
  108. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.d.ts.map +1 -0
  109. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.js +18 -0
  110. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.js.map +1 -0
  111. package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
  112. package/dist/primitives/thread/useThreadViewportAutoScroll.js +13 -1
  113. package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
  114. package/dist/primitives/thread.d.ts +0 -1
  115. package/dist/primitives/thread.d.ts.map +1 -1
  116. package/dist/primitives/thread.js +0 -1
  117. package/dist/primitives/thread.js.map +1 -1
  118. package/dist/primitives/threadList/ThreadListLoadMore.d.ts +13 -0
  119. package/dist/primitives/threadList/ThreadListLoadMore.d.ts.map +1 -0
  120. package/dist/primitives/threadList/ThreadListLoadMore.js +11 -0
  121. package/dist/primitives/threadList/ThreadListLoadMore.js.map +1 -0
  122. package/dist/primitives/threadList.d.ts +1 -0
  123. package/dist/primitives/threadList.d.ts.map +1 -1
  124. package/dist/primitives/threadList.js +1 -0
  125. package/dist/primitives/threadList.js.map +1 -1
  126. package/dist/utils/hooks/useManagedRef.d.ts.map +1 -1
  127. package/dist/utils/hooks/useManagedRef.js +1 -0
  128. package/dist/utils/hooks/useManagedRef.js.map +1 -1
  129. package/dist/utils/hooks/useOnResizeContent.d.ts.map +1 -1
  130. package/dist/utils/hooks/useOnResizeContent.js +1 -2
  131. package/dist/utils/hooks/useOnResizeContent.js.map +1 -1
  132. package/package.json +13 -13
  133. package/src/client/ExternalThread.ts +32 -19
  134. package/src/client/InMemoryThreadList.ts +3 -0
  135. package/src/client/SingleThreadList.ts +3 -0
  136. package/src/context/providers/ThreadViewportProvider.tsx +2 -12
  137. package/src/context/stores/ThreadViewport.ts +111 -11
  138. package/src/index.ts +20 -34
  139. package/src/legacy-runtime/cloud/auiV0.ts +37 -4
  140. package/src/legacy-runtime/runtime-cores/assistant-transport/utils.ts +1 -5
  141. package/src/mcp-apps/McpAppRenderer.tsx +215 -0
  142. package/src/mcp-apps/McpAppsRemoteHost.ts +52 -0
  143. package/src/mcp-apps/app-frame.tsx +280 -0
  144. package/src/mcp-apps/bridge.test.ts +391 -0
  145. package/src/mcp-apps/bridge.ts +435 -0
  146. package/src/mcp-apps/index.ts +16 -0
  147. package/src/mcp-apps/types.ts +158 -0
  148. package/src/mcp-apps/utils.ts +16 -0
  149. package/src/primitives/composer/ComposerInput.test.tsx +280 -0
  150. package/src/primitives/composer/ComposerInput.tsx +29 -6
  151. package/src/primitives/composer/trigger/TriggerPopover.tsx +21 -1
  152. package/src/primitives/composer/trigger/TriggerPopoverRootContext.test.tsx +152 -0
  153. package/src/primitives/composer/trigger/TriggerPopoverRootContext.tsx +134 -17
  154. package/src/primitives/composer/trigger/triggerKeyboardResource.test.ts +236 -0
  155. package/src/primitives/composer/trigger/triggerKeyboardResource.ts +2 -1
  156. package/src/primitives/message/MessageRoot.tsx +135 -57
  157. package/src/primitives/thread/ThreadViewport.tsx +95 -4
  158. package/src/primitives/thread/ThreadViewportFooter.tsx +2 -1
  159. package/src/primitives/thread/topAnchor/computeTopAnchorSlack.test.ts +131 -0
  160. package/src/primitives/thread/topAnchor/computeTopAnchorSlack.ts +94 -0
  161. package/src/primitives/thread/topAnchor/createReserveObservers.ts +50 -0
  162. package/src/primitives/thread/topAnchor/mountTopAnchorReserve.test.ts +131 -0
  163. package/src/primitives/thread/topAnchor/mountTopAnchorReserve.ts +127 -0
  164. package/src/primitives/thread/topAnchor/topAnchorTurn.test.ts +46 -0
  165. package/src/primitives/thread/topAnchor/topAnchorTurn.ts +30 -0
  166. package/src/primitives/thread/topAnchor/topAnchorUtils.ts +58 -0
  167. package/src/primitives/thread/topAnchor/useTopAnchorReserve.ts +19 -0
  168. package/src/primitives/thread/useThreadViewportAutoScroll.ts +15 -1
  169. package/src/primitives/thread.ts +0 -1
  170. package/src/primitives/threadList/ThreadListLoadMore.tsx +24 -0
  171. package/src/primitives/threadList.ts +1 -0
  172. package/src/tests/BaseComposerRuntimeCore.test.ts +4 -0
  173. package/src/tests/RemoteThreadListRuntime.adapterProvider.test.tsx +138 -0
  174. package/src/tests/RemoteThreadListRuntime.deferredProvider.test.tsx +28 -17
  175. package/src/tests/auiV0Encode.test.ts +55 -0
  176. package/src/utils/hooks/useManagedRef.ts +1 -0
  177. package/src/utils/hooks/useOnResizeContent.ts +1 -2
  178. package/dist/legacy-runtime/runtime-cores/external-store/getExternalStoreMessage.d.ts +0 -3
  179. package/dist/legacy-runtime/runtime-cores/external-store/getExternalStoreMessage.d.ts.map +0 -1
  180. package/dist/legacy-runtime/runtime-cores/external-store/getExternalStoreMessage.js +0 -3
  181. package/dist/legacy-runtime/runtime-cores/external-store/getExternalStoreMessage.js.map +0 -1
  182. package/dist/primitives/thread/ThreadViewportSlack.d.ts +0 -20
  183. package/dist/primitives/thread/ThreadViewportSlack.d.ts.map +0 -1
  184. package/dist/primitives/thread/ThreadViewportSlack.js +0 -80
  185. package/dist/primitives/thread/ThreadViewportSlack.js.map +0 -1
  186. package/src/legacy-runtime/runtime-cores/external-store/getExternalStoreMessage.ts +0 -6
  187. package/src/primitives/thread/ThreadViewportSlack.tsx +0 -116
@@ -50,6 +50,13 @@ export type ExternalThreadQueueAdapter = {
50
50
  export type ExternalThreadProps = {
51
51
  messages: readonly ExternalThreadMessage[];
52
52
  isRunning?: boolean;
53
+ /**
54
+ * Whether sending new messages is currently disabled. When `true`, the
55
+ * thread composer's input remains usable but `send()` is a no-op and
56
+ * `composer.canSend` is `false`. Edit composers (saving message edits)
57
+ * intentionally ignore this flag.
58
+ */
59
+ isSendDisabled?: boolean;
53
60
  /**
54
61
  * Callback for new messages (non-queue runtimes).
55
62
  * @note Unused when `queue` is provided — new messages are routed through `queue.enqueue` instead.
@@ -146,7 +153,6 @@ const MessageClient = resource(
146
153
  branchNumber: 1,
147
154
  branchCount: 1,
148
155
  speech: undefined,
149
- submittedFeedback: undefined,
150
156
  parts: partClients.state,
151
157
  isCopied,
152
158
  isHovering,
@@ -242,6 +248,7 @@ type ComposerClientResourceProps = {
242
248
  type: "thread" | "edit";
243
249
  isEditing: boolean;
244
250
  canCancel: boolean;
251
+ isSendDisabled?: boolean;
245
252
  onCancel: () => void;
246
253
  onBeginEdit?: () => void;
247
254
  onSend?: (message: AppendMessage) => void;
@@ -273,6 +280,7 @@ const ComposerClientResource = resource(
273
280
  type,
274
281
  isEditing,
275
282
  canCancel,
283
+ isSendDisabled = false,
276
284
  onCancel,
277
285
  onBeginEdit,
278
286
  onSend,
@@ -342,34 +350,36 @@ const ComposerClientResource = resource(
342
350
  [queueItems],
343
351
  );
344
352
 
345
- const state = tapMemo(
346
- () => ({
353
+ const state = tapMemo(() => {
354
+ const isEmpty = !text.trim() && !attachments.length;
355
+ return {
347
356
  text,
348
357
  role,
349
358
  attachments: attachmentClients.state,
350
359
  runConfig,
351
360
  isEditing,
352
361
  canCancel,
362
+ canSend: isEditing && !isEmpty && !isSendDisabled,
353
363
  attachmentAccept: "*",
354
- isEmpty: !text.trim() && !attachments.length,
364
+ isEmpty,
355
365
  type,
356
366
  dictation: undefined,
357
367
  quote,
358
368
  queue: queueItems,
359
- }),
360
- [
361
- text,
362
- role,
363
- attachmentClients.state,
364
- runConfig,
365
- isEditing,
366
- canCancel,
367
- type,
368
- attachments.length,
369
- quote,
370
- queueItems,
371
- ],
372
- );
369
+ };
370
+ }, [
371
+ text,
372
+ role,
373
+ attachmentClients.state,
374
+ runConfig,
375
+ isEditing,
376
+ canCancel,
377
+ isSendDisabled,
378
+ type,
379
+ attachments.length,
380
+ quote,
381
+ queueItems,
382
+ ]);
373
383
 
374
384
  return {
375
385
  getState: () => state,
@@ -417,6 +427,8 @@ const ComposerClientResource = resource(
417
427
  setQuote(undefined);
418
428
  },
419
429
  send: (opts?: ComposerSendOptions) => {
430
+ if (!state.canSend) return;
431
+
420
432
  const currentQuote = quote;
421
433
  const composedMessage: AppendMessage = {
422
434
  role,
@@ -459,6 +471,7 @@ export const ExternalThread = resource(
459
471
  ({
460
472
  messages,
461
473
  isRunning = false,
474
+ isSendDisabled = false,
462
475
  onNew,
463
476
  onEdit,
464
477
  onReload,
@@ -504,6 +517,7 @@ export const ExternalThread = resource(
504
517
  type: "thread",
505
518
  isEditing: true,
506
519
  canCancel: isRunning,
520
+ isSendDisabled,
507
521
  onCancel: handleCancelRun,
508
522
  onSend: handleSendNew,
509
523
  queue,
@@ -589,7 +603,6 @@ export const ExternalThread = resource(
589
603
  onStartRun?.();
590
604
  },
591
605
  resumeRun: () => {},
592
- unstable_resumeRun: () => {},
593
606
  cancelRun: handleCancelRun,
594
607
  getModelContext: () => ({ tools: {}, config: {} }),
595
608
  export: () => ({ messages: [] }),
@@ -142,6 +142,8 @@ export const InMemoryThreadList = resource(
142
142
  mainThreadId,
143
143
  newThreadId: null,
144
144
  isLoading: false,
145
+ isLoadingMore: false,
146
+ hasMore: false,
145
147
  threadIds: regularThreads.map((t) => t.id),
146
148
  archivedThreadIds: archivedThreads.map((t) => t.id),
147
149
  threadItems: threadListItems.state,
@@ -155,6 +157,7 @@ export const InMemoryThreadList = resource(
155
157
  switchToNewThread: handleSwitchToNewThread,
156
158
  getLoadThreadsPromise: () => RESOLVED_PROMISE,
157
159
  reload: () => RESOLVED_PROMISE,
160
+ loadMore: () => RESOLVED_PROMISE,
158
161
  item: (selector) => {
159
162
  if (selector === "main") {
160
163
  const index = threads.findIndex((t) => t.id === mainThreadId);
@@ -47,6 +47,8 @@ export const SingleThreadList = resource(
47
47
  mainThreadId: THREAD_ID,
48
48
  newThreadId: null,
49
49
  isLoading: false,
50
+ isLoadingMore: false,
51
+ hasMore: false,
50
52
  threadIds: [THREAD_ID],
51
53
  archivedThreadIds: [],
52
54
  threadItems: [itemClient.state],
@@ -65,6 +67,7 @@ export const SingleThreadList = resource(
65
67
  },
66
68
  getLoadThreadsPromise: () => RESOLVED_PROMISE,
67
69
  reload: () => RESOLVED_PROMISE,
70
+ loadMore: () => RESOLVED_PROMISE,
68
71
  item: (selector) => {
69
72
  if (
70
73
  selector !== "main" &&
@@ -19,6 +19,8 @@ export type ThreadViewportProviderProps = PropsWithChildren<{
19
19
 
20
20
  const useThreadViewportStoreValue = (options: ThreadViewportStoreOptions) => {
21
21
  const outerViewport = useThreadViewportStore({ optional: true });
22
+ // Viewport options are initial configuration. Keeping them non-reactive avoids
23
+ // fanout through every message in long threads when anchoring config changes.
22
24
  const [store] = useState(() => makeThreadViewportStore(options));
23
25
 
24
26
  // Forward scrollToBottom from outer viewport to inner viewport
@@ -37,18 +39,6 @@ const useThreadViewportStoreValue = (options: ThreadViewportStoreOptions) => {
37
39
  });
38
40
  }, [store, outerViewport]);
39
41
 
40
- // Sync options to store when they change
41
- useEffect(() => {
42
- const nextState = {
43
- turnAnchor: options.turnAnchor ?? "bottom",
44
- };
45
-
46
- const currentState = store.getState();
47
- if (currentState.turnAnchor !== nextState.turnAnchor) {
48
- writableStore(store).setState(nextState);
49
- }
50
- }, [store, options.turnAnchor]);
51
-
52
42
  return store;
53
43
  };
54
44
 
@@ -60,28 +60,80 @@ export type ThreadViewportState = {
60
60
  /** Controls scroll anchoring: "top" anchors user messages at top, "bottom" is classic behavior */
61
61
  readonly turnAnchor: "top" | "bottom";
62
62
 
63
+ /** Clamps tall user messages so the assistant response stays in view. */
64
+ readonly topAnchorMessageClamp: {
65
+ readonly tallerThan: string;
66
+ readonly visibleHeight: string;
67
+ };
68
+
63
69
  /** Raw height values from registered elements */
64
70
  readonly height: {
65
71
  /** Total viewport height */
66
72
  readonly viewport: number;
67
73
  /** Total content inset height (footer, anchor message, etc.) */
68
74
  readonly inset: number;
69
- /** Height of the anchor user message (full height) */
70
- readonly userMessage: number;
71
75
  };
72
76
 
77
+ /** Current DOM elements used for geometry-based top anchoring */
78
+ readonly element: {
79
+ readonly viewport: HTMLElement | null;
80
+ readonly anchor: HTMLElement | null;
81
+ readonly target: HTMLElement | null;
82
+ };
83
+
84
+ /** Numeric clamp configuration for the active top-anchor target message */
85
+ readonly targetConfig: {
86
+ readonly tallerThan: number;
87
+ readonly visibleHeight: number;
88
+ } | null;
89
+
90
+ /**
91
+ * The current top-anchor turn activated in this viewport session.
92
+ * History-loaded messages do not populate this; it is set when a run creates
93
+ * a live user/assistant pair and remains after the run completes.
94
+ */
95
+ readonly topAnchorTurn: {
96
+ readonly anchorId: string;
97
+ readonly targetId: string;
98
+ } | null;
99
+
73
100
  /** Register a viewport and get a handle to update its height */
74
101
  readonly registerViewport: () => SizeHandle;
75
102
 
76
103
  /** Register a content inset (footer, anchor message, etc.) and get a handle to update its height */
77
104
  readonly registerContentInset: () => SizeHandle;
78
105
 
79
- /** Register the anchor user message height */
80
- readonly registerUserMessageHeight: () => SizeHandle;
106
+ /** Register the scroll viewport element */
107
+ readonly registerViewportElement: (
108
+ element: HTMLElement | null,
109
+ ) => Unsubscribe;
110
+
111
+ /** Register the current anchor user message element */
112
+ readonly registerAnchorElement: (element: HTMLElement | null) => Unsubscribe;
113
+
114
+ /**
115
+ * Register the current top-anchor target (last assistant response) element
116
+ * along with its numeric clamp configuration. When unregistered, both
117
+ * `element.target` and `targetConfig` clear together.
118
+ */
119
+ readonly registerAnchorTargetElement: (
120
+ element: HTMLElement | null,
121
+ config?: { readonly tallerThan: number; readonly visibleHeight: number },
122
+ ) => Unsubscribe;
123
+
124
+ readonly setTopAnchorTurn: (
125
+ turn: { readonly anchorId: string; readonly targetId: string } | null,
126
+ ) => void;
81
127
  };
82
128
 
83
129
  export type ThreadViewportStoreOptions = {
84
130
  turnAnchor?: "top" | "bottom" | undefined;
131
+ topAnchorMessageClamp?:
132
+ | {
133
+ tallerThan?: string | undefined;
134
+ visibleHeight?: string | undefined;
135
+ }
136
+ | undefined;
85
137
  };
86
138
 
87
139
  export const makeThreadViewportStore = (
@@ -107,14 +159,27 @@ export const makeThreadViewportStore = (
107
159
  },
108
160
  });
109
161
  });
110
- const userMessageRegistry = createSizeRegistry((total) => {
162
+ const registerElementSlot = (
163
+ key: "viewport" | "anchor",
164
+ element: HTMLElement | null,
165
+ ) => {
111
166
  store.setState({
112
- height: {
113
- ...store.getState().height,
114
- userMessage: total,
167
+ element: {
168
+ ...store.getState().element,
169
+ [key]: element,
115
170
  },
116
171
  });
117
- });
172
+
173
+ return () => {
174
+ if (store.getState().element[key] !== element) return;
175
+ store.setState({
176
+ element: {
177
+ ...store.getState().element,
178
+ [key]: null,
179
+ },
180
+ });
181
+ };
182
+ };
118
183
 
119
184
  const store = create<ThreadViewportState>(() => ({
120
185
  isAtBottom: true,
@@ -131,16 +196,51 @@ export const makeThreadViewportStore = (
131
196
  },
132
197
 
133
198
  turnAnchor: options.turnAnchor ?? "bottom",
199
+ topAnchorMessageClamp: {
200
+ tallerThan: options.topAnchorMessageClamp?.tallerThan ?? "10em",
201
+ visibleHeight: options.topAnchorMessageClamp?.visibleHeight ?? "6em",
202
+ },
134
203
 
135
204
  height: {
136
205
  viewport: 0,
137
206
  inset: 0,
138
- userMessage: 0,
139
207
  },
208
+ element: {
209
+ viewport: null,
210
+ anchor: null,
211
+ target: null,
212
+ },
213
+ targetConfig: null,
214
+ topAnchorTurn: null,
140
215
 
141
216
  registerViewport: viewportRegistry.register,
142
217
  registerContentInset: insetRegistry.register,
143
- registerUserMessageHeight: userMessageRegistry.register,
218
+ registerViewportElement: (element) =>
219
+ registerElementSlot("viewport", element),
220
+ registerAnchorElement: (element) => registerElementSlot("anchor", element),
221
+ registerAnchorTargetElement: (element, config) => {
222
+ store.setState({
223
+ element: {
224
+ ...store.getState().element,
225
+ target: element,
226
+ },
227
+ targetConfig: element && config ? config : null,
228
+ });
229
+
230
+ return () => {
231
+ if (store.getState().element.target !== element) return;
232
+ store.setState({
233
+ element: {
234
+ ...store.getState().element,
235
+ target: null,
236
+ },
237
+ targetConfig: null,
238
+ });
239
+ };
240
+ },
241
+ setTopAnchorTurn: (topAnchorTurn) => {
242
+ store.setState({ topAnchorTurn });
243
+ },
144
244
  }));
145
245
 
146
246
  return store;
package/src/index.ts CHANGED
@@ -125,7 +125,6 @@ export type {
125
125
  // --- external-store ---
126
126
  export type { ThreadMessageLike } from "@assistant-ui/core";
127
127
  export {
128
- getExternalStoreMessage,
129
128
  getExternalStoreMessages,
130
129
  bindExternalStoreMessage,
131
130
  } from "@assistant-ui/core";
@@ -151,25 +150,13 @@ export type {
151
150
  LocalRuntimeOptionsBase,
152
151
  } from "@assistant-ui/core";
153
152
  export { useLocalRuntime } from "./legacy-runtime/runtime-cores/local/useLocalRuntime";
154
- /**
155
- * @deprecated Use `useLocalRuntime` instead.
156
- */
157
- export { useLocalRuntime as useLocalThreadRuntime } from "./legacy-runtime/runtime-cores/local/useLocalRuntime";
158
153
  export type { LocalRuntimeOptions } from "./legacy-runtime/runtime-cores/local/LocalRuntimeOptions";
159
154
 
160
155
  // --- remote-thread-list ---
161
156
  export { useRemoteThreadListRuntime } from "./legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime";
162
- /** @deprecated Use `useRemoteThreadListRuntime` instead. */
163
- export { useRemoteThreadListRuntime as unstable_useRemoteThreadListRuntime } from "./legacy-runtime/runtime-cores/remote-thread-list/useRemoteThreadListRuntime";
164
157
  export { useCloudThreadListAdapter } from "./legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud";
165
- /** @deprecated Use `useCloudThreadListAdapter` instead. */
166
- export { useCloudThreadListAdapter as unstable_useCloudThreadListAdapter } from "./legacy-runtime/runtime-cores/remote-thread-list/adapter/cloud";
167
158
  export type { RemoteThreadListAdapter } from "@assistant-ui/core";
168
- /** @deprecated Use `RemoteThreadListAdapter` instead. */
169
- export type { RemoteThreadListAdapter as unstable_RemoteThreadListAdapter } from "@assistant-ui/core";
170
159
  export { InMemoryThreadListAdapter } from "@assistant-ui/core";
171
- /** @deprecated Use `InMemoryThreadListAdapter` instead. */
172
- export { InMemoryThreadListAdapter as unstable_InMemoryThreadListAdapter } from "@assistant-ui/core";
173
160
 
174
161
  // Re-export from @assistant-ui/core (runtime-cores root)
175
162
  export type { ExportedMessageRepositoryItem } from "@assistant-ui/core";
@@ -287,12 +274,14 @@ export type {
287
274
  AppendMessage,
288
275
  TextMessagePart,
289
276
  ReasoningMessagePart,
277
+ SourceProviderMetadata,
290
278
  SourceMessagePart,
291
279
  ImageMessagePart,
292
280
  FileMessagePart,
293
281
  DataMessagePart,
294
282
  Unstable_AudioMessagePart,
295
283
  ToolCallMessagePart,
284
+ ToolModelContentPart,
296
285
  MessageStatus,
297
286
  MessagePartStatus,
298
287
  ToolCallMessagePartStatus,
@@ -392,24 +381,21 @@ export {
392
381
 
393
382
  export type { Assistant } from "./augmentations";
394
383
 
395
- // Backwards compatibility — deprecated exports, to be removed in v0.13
396
-
397
- /**
398
- * @deprecated Use `useAui` instead. This alias will be removed in v0.13.
399
- */
400
- export { useAui as useAssistantApi } from "@assistant-ui/store";
401
-
402
- /**
403
- * @deprecated Use `useAuiState` instead. This alias will be removed in v0.13.
404
- */
405
- export { useAuiState as useAssistantState } from "@assistant-ui/store";
406
-
407
- /**
408
- * @deprecated Use `useAuiEvent` instead. This alias will be removed in v0.13.
409
- */
410
- export { useAuiEvent as useAssistantEvent } from "@assistant-ui/store";
411
-
412
- /**
413
- * @deprecated Use `AuiIf` instead. This alias will be removed in v0.13.
414
- */
415
- export { AuiIf as AssistantIf } from "@assistant-ui/store";
384
+ // --- mcp-apps ---
385
+ export { McpAppRenderer, McpAppsRemoteHost } from "./mcp-apps";
386
+ export type {
387
+ McpAppRendererOptions,
388
+ McpAppMetadata,
389
+ McpAppResource,
390
+ McpAppResourceMeta,
391
+ McpAppResourceCSP,
392
+ McpAppSandboxConfig,
393
+ McpAppHostInfo,
394
+ McpAppHostContext,
395
+ McpAppDisplayMode,
396
+ McpAppsHost,
397
+ McpAppsRemoteHostOptions,
398
+ McpAppToolCallParams,
399
+ ToolCallMessagePartMcpMetadata,
400
+ } from "./mcp-apps";
401
+ export type { McpAppResourceOutput } from "@assistant-ui/core/react";
@@ -1,4 +1,8 @@
1
- import type { MessageStatus, ThreadMessage } from "@assistant-ui/core";
1
+ import type {
2
+ MessageStatus,
3
+ SourceProviderMetadata,
4
+ ThreadMessage,
5
+ } from "@assistant-ui/core";
2
6
  import { fromThreadMessageLike } from "../runtime-cores/external-store/ThreadMessageLike";
3
7
  import type { CloudMessage } from "assistant-cloud";
4
8
  import { isJSONValue } from "../../utils/json/is-json";
@@ -23,6 +27,16 @@ type AuiV0MessagePart =
23
27
  readonly id: string;
24
28
  readonly url: string;
25
29
  readonly title?: string;
30
+ readonly providerMetadata?: SourceProviderMetadata;
31
+ }
32
+ | {
33
+ readonly type: "source";
34
+ readonly sourceType: "document";
35
+ readonly id: string;
36
+ readonly title: string;
37
+ readonly mediaType: string;
38
+ readonly filename?: string;
39
+ readonly providerMetadata?: SourceProviderMetadata;
26
40
  }
27
41
  | {
28
42
  readonly type: "tool-call";
@@ -90,12 +104,31 @@ export function auiV0Encode(message: ThreadMessage): AuiV0Message {
90
104
  return { type: "reasoning", text: part.text };
91
105
 
92
106
  case "source":
107
+ if (part.sourceType === "url") {
108
+ return {
109
+ type: "source",
110
+ sourceType: "url",
111
+ id: part.id,
112
+ url: part.url,
113
+ ...(part.title != null ? { title: part.title } : undefined),
114
+ ...(part.providerMetadata != null
115
+ ? { providerMetadata: part.providerMetadata }
116
+ : undefined),
117
+ };
118
+ }
119
+
93
120
  return {
94
121
  type: "source",
95
- sourceType: part.sourceType,
122
+ sourceType: "document",
96
123
  id: part.id,
97
- url: part.url,
98
- ...(part.title ? { title: part.title } : undefined),
124
+ title: part.title,
125
+ mediaType: part.mediaType,
126
+ ...(part.filename != null
127
+ ? { filename: part.filename }
128
+ : undefined),
129
+ ...(part.providerMetadata != null
130
+ ? { providerMetadata: part.providerMetadata }
131
+ : undefined),
99
132
  };
100
133
 
101
134
  case "tool-call": {
@@ -1,5 +1 @@
1
- export {
2
- toAISDKTools,
3
- getEnabledTools,
4
- createRequestHeaders,
5
- } from "@assistant-ui/core";
1
+ export { createRequestHeaders } from "@assistant-ui/core";