@assistant-ui/react 0.14.28 → 0.15.0
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.
- package/dist/client/ExternalThread.d.ts +11 -1
- package/dist/client/ExternalThread.d.ts.map +1 -1
- package/dist/client/ExternalThread.js +762 -516
- package/dist/client/ExternalThread.js.map +1 -1
- package/dist/client/InMemoryThreadList.js +3 -3
- package/dist/client/InMemoryThreadList.js.map +1 -1
- package/dist/context/index.d.ts +1 -8
- package/dist/context/index.js +1 -8
- package/dist/index.d.ts +1 -8
- package/dist/index.js +1 -8
- package/dist/legacy-runtime/cloud/auiV0.d.ts +12 -1
- package/dist/legacy-runtime/cloud/auiV0.d.ts.map +1 -1
- package/dist/legacy-runtime/cloud/auiV0.js +2 -1
- package/dist/legacy-runtime/cloud/auiV0.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.d.ts +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js +7 -6
- package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.js +30 -15
- package/dist/legacy-runtime/runtime-cores/assistant-transport/runManager.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +11 -7
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js +1 -0
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useConvertedState.js.map +1 -1
- package/dist/mcp-apps/McpAppRenderer.js +1 -1
- package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/model-context/makeAssistantVisible.js +26 -25
- package/dist/model-context/makeAssistantVisible.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarExportMarkdown.js +3 -3
- package/dist/primitives/actionBar/ActionBarExportMarkdown.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarRoot.js +3 -3
- package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
- package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts +7 -6
- package/dist/primitives/actionBar/useActionBarFloatStatus.d.ts.map +1 -1
- package/dist/primitives/actionBar/useActionBarFloatStatus.js +10 -11
- package/dist/primitives/actionBar/useActionBarFloatStatus.js.map +1 -1
- package/dist/primitives/attachment/AttachmentRemove.js +4 -3
- package/dist/primitives/attachment/AttachmentRemove.js.map +1 -1
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js +4 -3
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js.map +1 -1
- package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAddAttachment.js +11 -5
- package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
- package/dist/primitives/composer/ComposerAttachmentDropzone.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAttachmentDropzone.js +2 -4
- package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
- package/dist/primitives/composer/ComposerInput.js +18 -16
- package/dist/primitives/composer/ComposerInput.js.map +1 -1
- package/dist/primitives/composer/ComposerQuote.js +1 -1
- package/dist/primitives/composer/ComposerQuote.js.map +1 -1
- package/dist/primitives/composer/ComposerSend.js +1 -0
- package/dist/primitives/composer/ComposerSend.js.map +1 -1
- package/dist/primitives/composer/ComposerStopDictation.js +4 -3
- package/dist/primitives/composer/ComposerStopDictation.js.map +1 -1
- package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/triggerSelectionResource.js +3 -3
- package/dist/primitives/composer/trigger/triggerSelectionResource.js.map +1 -1
- package/dist/primitives/message/MessagePartsGrouped.d.ts.map +1 -1
- package/dist/primitives/message/MessagePartsGrouped.js +67 -89
- package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
- package/dist/primitives/message/MessageRoot.js +3 -3
- package/dist/primitives/message/MessageRoot.js.map +1 -1
- package/dist/primitives/queueItem/QueueItemRemove.js +4 -3
- package/dist/primitives/queueItem/QueueItemRemove.js.map +1 -1
- package/dist/primitives/queueItem/QueueItemSteer.js +4 -3
- package/dist/primitives/queueItem/QueueItemSteer.js.map +1 -1
- package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js +1 -1
- package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js.map +1 -1
- package/dist/primitives/suggestion/SuggestionTrigger.js +17 -15
- package/dist/primitives/suggestion/SuggestionTrigger.js.map +1 -1
- package/dist/primitives/thread/ThreadScrollToBottom.js +1 -0
- package/dist/primitives/thread/ThreadScrollToBottom.js.map +1 -1
- package/dist/unstable/useComposerInput.js +2 -2
- package/dist/unstable/useComposerInput.js.map +1 -1
- package/dist/unstable/useComposerInputHistory.js +6 -6
- package/dist/unstable/useComposerInputHistory.js.map +1 -1
- package/dist/unstable/useMentionAdapter.js +1 -1
- package/dist/unstable/useMentionAdapter.js.map +1 -1
- package/dist/utils/hooks/useOnResizeContent.js +1 -0
- package/dist/utils/hooks/useOnResizeContent.js.map +1 -1
- package/dist/utils/hooks/useSizeHandle.js +1 -0
- package/dist/utils/hooks/useSizeHandle.js.map +1 -1
- package/dist/utils/smooth/SmoothContext.js +3 -3
- package/dist/utils/smooth/SmoothContext.js.map +1 -1
- package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
- package/dist/utils/smooth/useSmooth.js +3 -3
- package/dist/utils/smooth/useSmooth.js.map +1 -1
- package/package.json +9 -9
- package/src/client/ExternalThread.ts +345 -56
- package/src/client/InMemoryThreadList.ts +3 -3
- package/src/context/index.ts +0 -44
- package/src/legacy-runtime/cloud/auiV0.ts +14 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/commandQueue.ts +4 -1
- package/src/legacy-runtime/runtime-cores/assistant-transport/runManager.ts +37 -10
- package/src/legacy-runtime/runtime-cores/assistant-transport/transport-delivery.test.tsx +79 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/transport-parentid.test.tsx +97 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/transport-scheduling.test.ts +113 -2
- package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransport.spec.md +10 -2
- package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.test.tsx +185 -0
- package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.ts +21 -5
- package/src/mcp-apps/McpAppRenderer.tsx +1 -1
- package/src/model-context/makeAssistantVisible.test.tsx +1 -1
- package/src/model-context/makeAssistantVisible.tsx +1 -1
- package/src/primitives/actionBar/ActionBarExportMarkdown.tsx +1 -1
- package/src/primitives/actionBar/useActionBarFloatStatus.ts +7 -5
- package/src/primitives/attachment/AttachmentRemove.ts +1 -1
- package/src/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.ts +1 -1
- package/src/primitives/composer/ComposerAddAttachment.test.tsx +108 -0
- package/src/primitives/composer/ComposerAddAttachment.ts +11 -5
- package/src/primitives/composer/ComposerAttachmentDropzone.test.tsx +5 -4
- package/src/primitives/composer/ComposerAttachmentDropzone.tsx +4 -3
- package/src/primitives/composer/ComposerInput.test.tsx +104 -7
- package/src/primitives/composer/ComposerInput.tsx +22 -20
- package/src/primitives/composer/ComposerQuote.tsx +1 -1
- package/src/primitives/composer/ComposerStopDictation.ts +1 -1
- package/src/primitives/composer/trigger/triggerSelectionResource.ts +7 -9
- package/src/primitives/message/MessagePartsGrouped.tsx +6 -8
- package/src/primitives/message/MessageRoot.tsx +1 -1
- package/src/primitives/queueItem/QueueItemRemove.ts +1 -1
- package/src/primitives/queueItem/QueueItemSteer.ts +1 -1
- package/src/primitives/selectionToolbar/SelectionToolbarQuote.tsx +1 -1
- package/src/primitives/suggestion/SuggestionTrigger.ts +9 -9
- package/src/tests/DataRenderers.test.tsx +212 -0
- package/src/tests/RemoteThreadListRuntime.adapterProvider.test.tsx +1 -11
- package/src/tests/RemoteThreadListRuntime.deferredProvider.test.tsx +3 -3
- package/src/tests/external-thread-attachments.test.tsx +300 -11
- package/src/tests/external-thread-branches.test.tsx +10 -10
- package/src/tests/external-thread-parity.test.tsx +230 -0
- package/src/tests/generative-ui.test.tsx +1 -46
- package/src/tests/local-runtime-queue.test.tsx +29 -34
- package/src/tests/messagePartSwitchRace.test.tsx +46 -15
- package/src/tests/messagePartTypeMismatch.test.tsx +2 -2
- package/src/tests/threadMessageById.test.tsx +0 -7
- package/src/unstable/useComposerInput.test.tsx +2 -2
- package/src/unstable/useComposerInput.ts +2 -2
- package/src/unstable/useComposerInputHistory.test.tsx +3 -3
- package/src/unstable/useComposerInputHistory.ts +6 -6
- package/src/unstable/useMentionAdapter.ts +1 -1
- package/src/utils/smooth/SmoothContext.tsx +1 -1
- package/src/utils/smooth/useSmooth.test.tsx +1 -1
- package/src/utils/smooth/useSmooth.ts +8 -5
- package/dist/context/react/utils/createStateHookForRuntime.d.ts +0 -34
- package/dist/context/react/utils/createStateHookForRuntime.d.ts.map +0 -1
- package/dist/context/react/utils/createStateHookForRuntime.js +0 -21
- package/dist/context/react/utils/createStateHookForRuntime.js.map +0 -1
- package/dist/legacy-runtime/hooks/AssistantContext.d.ts +0 -74
- package/dist/legacy-runtime/hooks/AssistantContext.d.ts.map +0 -1
- package/dist/legacy-runtime/hooks/AssistantContext.js +0 -29
- package/dist/legacy-runtime/hooks/AssistantContext.js.map +0 -1
- package/dist/legacy-runtime/hooks/AttachmentContext.d.ts +0 -1007
- package/dist/legacy-runtime/hooks/AttachmentContext.d.ts.map +0 -1
- package/dist/legacy-runtime/hooks/AttachmentContext.js +0 -47
- package/dist/legacy-runtime/hooks/AttachmentContext.js.map +0 -1
- package/dist/legacy-runtime/hooks/ComposerContext.d.ts +0 -141
- package/dist/legacy-runtime/hooks/ComposerContext.d.ts.map +0 -1
- package/dist/legacy-runtime/hooks/ComposerContext.js +0 -65
- package/dist/legacy-runtime/hooks/ComposerContext.js.map +0 -1
- package/dist/legacy-runtime/hooks/MessageContext.d.ts +0 -155
- package/dist/legacy-runtime/hooks/MessageContext.d.ts.map +0 -1
- package/dist/legacy-runtime/hooks/MessageContext.js +0 -68
- package/dist/legacy-runtime/hooks/MessageContext.js.map +0 -1
- package/dist/legacy-runtime/hooks/MessagePartContext.d.ts +0 -44
- package/dist/legacy-runtime/hooks/MessagePartContext.d.ts.map +0 -1
- package/dist/legacy-runtime/hooks/MessagePartContext.js +0 -26
- package/dist/legacy-runtime/hooks/MessagePartContext.js.map +0 -1
- package/dist/legacy-runtime/hooks/ThreadContext.d.ts +0 -139
- package/dist/legacy-runtime/hooks/ThreadContext.d.ts.map +0 -1
- package/dist/legacy-runtime/hooks/ThreadContext.js +0 -84
- package/dist/legacy-runtime/hooks/ThreadContext.js.map +0 -1
- package/dist/legacy-runtime/hooks/ThreadListItemContext.d.ts +0 -44
- package/dist/legacy-runtime/hooks/ThreadListItemContext.d.ts.map +0 -1
- package/dist/legacy-runtime/hooks/ThreadListItemContext.js +0 -26
- package/dist/legacy-runtime/hooks/ThreadListItemContext.js.map +0 -1
- package/src/context/react/utils/createStateHookForRuntime.ts +0 -82
- package/src/legacy-runtime/hooks/AssistantContext.ts +0 -67
- package/src/legacy-runtime/hooks/AttachmentContext.ts +0 -99
- package/src/legacy-runtime/hooks/ComposerContext.ts +0 -131
- package/src/legacy-runtime/hooks/MessageContext.ts +0 -127
- package/src/legacy-runtime/hooks/MessagePartContext.ts +0 -32
- package/src/legacy-runtime/hooks/ThreadContext.ts +0 -120
- package/src/legacy-runtime/hooks/ThreadListItemContext.ts +0 -36
- package/src/tests/BaseComposerRuntimeCore.test.ts +0 -621
- package/src/tests/BaseSubscribable.test.ts +0 -54
- package/src/tests/DataRenderers.test.ts +0 -355
- package/src/tests/ExternalStoreThreadRuntimeCore.test.ts +0 -685
- package/src/tests/LocalThreadRuntimeCore.test.ts +0 -324
- package/src/tests/auiV0Encode.test.ts +0 -188
- package/src/tests/external-message-converter.test.ts +0 -346
- package/src/tests/shouldContinue.test.ts +0 -122
|
@@ -208,7 +208,7 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
208
208
|
|
|
209
209
|
if (!cancelOnEscape) return;
|
|
210
210
|
|
|
211
|
-
const composer = aui.composer
|
|
211
|
+
const composer = aui.composer;
|
|
212
212
|
if (composer.getState().canCancel) {
|
|
213
213
|
composer.cancel();
|
|
214
214
|
e.preventDefault();
|
|
@@ -229,7 +229,7 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
if (e.key === "Enter") {
|
|
232
|
-
const threadState = aui.thread
|
|
232
|
+
const threadState = aui.thread.getState();
|
|
233
233
|
const hasQueue = threadState.capabilities.queue;
|
|
234
234
|
|
|
235
235
|
// Steer hotkey: Cmd/Ctrl+Shift+Enter (respects submitMode="none" and canSend)
|
|
@@ -238,10 +238,10 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
238
238
|
(e.ctrlKey || e.metaKey) &&
|
|
239
239
|
hasQueue &&
|
|
240
240
|
declaredSubmitMode !== "none" &&
|
|
241
|
-
aui.composer
|
|
241
|
+
aui.composer.getState().canSend
|
|
242
242
|
) {
|
|
243
243
|
e.preventDefault();
|
|
244
|
-
aui.composer
|
|
244
|
+
aui.composer.send({ steer: true });
|
|
245
245
|
return;
|
|
246
246
|
}
|
|
247
247
|
|
|
@@ -267,18 +267,20 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
267
267
|
|
|
268
268
|
const handlePaste = async (e: ClipboardEvent<HTMLTextAreaElement>) => {
|
|
269
269
|
if (!addAttachmentOnPaste) return;
|
|
270
|
-
const threadCapabilities = aui.thread
|
|
270
|
+
const threadCapabilities = aui.thread.getState().capabilities;
|
|
271
271
|
const files = Array.from(e.clipboardData?.files || []);
|
|
272
272
|
|
|
273
273
|
if (threadCapabilities.attachments && files.length > 0) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
274
|
+
e.preventDefault();
|
|
275
|
+
await Promise.all(
|
|
276
|
+
files.map(async (file) => {
|
|
277
|
+
try {
|
|
278
|
+
await aui.composer.addAttachment(file);
|
|
279
|
+
} catch {
|
|
280
|
+
// The composer runtime emits composer.attachmentAddError before rejecting.
|
|
281
|
+
}
|
|
282
|
+
}),
|
|
283
|
+
);
|
|
282
284
|
}
|
|
283
285
|
};
|
|
284
286
|
|
|
@@ -317,7 +319,7 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
317
319
|
|
|
318
320
|
useOnScrollToBottom(() => {
|
|
319
321
|
if (
|
|
320
|
-
aui.composer
|
|
322
|
+
aui.composer.getState().type === "thread" &&
|
|
321
323
|
unstable_focusOnScrollToBottom
|
|
322
324
|
) {
|
|
323
325
|
focus();
|
|
@@ -326,7 +328,7 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
326
328
|
|
|
327
329
|
useEffect(() => {
|
|
328
330
|
if (
|
|
329
|
-
aui.composer
|
|
331
|
+
aui.composer.getState().type !== "thread" ||
|
|
330
332
|
!unstable_focusOnRunStart
|
|
331
333
|
)
|
|
332
334
|
return undefined;
|
|
@@ -336,7 +338,7 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
336
338
|
|
|
337
339
|
useEffect(() => {
|
|
338
340
|
if (
|
|
339
|
-
aui.composer
|
|
341
|
+
aui.composer.getState().type !== "thread" ||
|
|
340
342
|
!unstable_focusOnThreadSwitched
|
|
341
343
|
)
|
|
342
344
|
return undefined;
|
|
@@ -360,7 +362,7 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
360
362
|
onChange: composeEventHandlers(
|
|
361
363
|
onChange,
|
|
362
364
|
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
363
|
-
if (!aui.composer
|
|
365
|
+
if (!aui.composer.getState().isEditing) return;
|
|
364
366
|
const nativeIsComposing =
|
|
365
367
|
(e.nativeEvent as { isComposing?: boolean }).isComposing === true;
|
|
366
368
|
// recover stuck compositionRef when the browser drops compositionend
|
|
@@ -370,7 +372,7 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
370
372
|
const isComposing = nativeIsComposing || compositionRef.current;
|
|
371
373
|
// keep controlled value in sync mid-IME so react does not reset the textarea to a stale value
|
|
372
374
|
flushTapSync(() => {
|
|
373
|
-
aui.composer
|
|
375
|
+
aui.composer.setText(e.target.value);
|
|
374
376
|
});
|
|
375
377
|
if (isComposing) return;
|
|
376
378
|
const pos = e.target.selectionStart ?? e.target.value.length;
|
|
@@ -394,10 +396,10 @@ export const ComposerPrimitiveInput = forwardRef<
|
|
|
394
396
|
.onCompositionEnd,
|
|
395
397
|
(e: React.CompositionEvent<HTMLTextAreaElement>) => {
|
|
396
398
|
compositionRef.current = false;
|
|
397
|
-
if (!aui.composer
|
|
399
|
+
if (!aui.composer.getState().isEditing) return;
|
|
398
400
|
const target = e.target as HTMLTextAreaElement;
|
|
399
401
|
flushTapSync(() => {
|
|
400
|
-
aui.composer
|
|
402
|
+
aui.composer.setText(target.value);
|
|
401
403
|
});
|
|
402
404
|
const pos = target.selectionStart ?? target.value.length;
|
|
403
405
|
if (pluginRegistry) {
|
|
@@ -93,7 +93,7 @@ export const ComposerPrimitiveQuoteDismiss = forwardRef<
|
|
|
93
93
|
>(({ onClick, ...props }, forwardedRef) => {
|
|
94
94
|
const aui = useAui();
|
|
95
95
|
const handleDismiss = useCallback(() => {
|
|
96
|
-
aui.composer
|
|
96
|
+
aui.composer.setQuote(undefined);
|
|
97
97
|
}, [aui]);
|
|
98
98
|
|
|
99
99
|
return (
|
|
@@ -14,7 +14,7 @@ const useComposerStopDictation = () => {
|
|
|
14
14
|
const isDictating = useAuiState((s) => s.composer.dictation != null);
|
|
15
15
|
|
|
16
16
|
const callback = useCallback(() => {
|
|
17
|
-
aui.composer
|
|
17
|
+
aui.composer.stopDictation();
|
|
18
18
|
}, [aui]);
|
|
19
19
|
|
|
20
20
|
if (!isDictating) return null;
|
|
@@ -72,7 +72,7 @@ const useTriggerSelectionResource = ({
|
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const currentText = aui.composer
|
|
75
|
+
const currentText = aui.composer.getState().text;
|
|
76
76
|
const before = currentText.slice(0, trigger.offset);
|
|
77
77
|
const after = currentText.slice(
|
|
78
78
|
trigger.offset + triggerChar.length + trigger.query.length,
|
|
@@ -80,11 +80,9 @@ const useTriggerSelectionResource = ({
|
|
|
80
80
|
|
|
81
81
|
const insertDirective = () => {
|
|
82
82
|
const directive = behavior.formatter.serialize(item);
|
|
83
|
-
aui
|
|
84
|
-
.
|
|
85
|
-
|
|
86
|
-
before + directive + (after.startsWith(" ") ? after : ` ${after}`),
|
|
87
|
-
);
|
|
83
|
+
aui.composer.setText(
|
|
84
|
+
before + directive + (after.startsWith(" ") ? after : ` ${after}`),
|
|
85
|
+
);
|
|
88
86
|
};
|
|
89
87
|
|
|
90
88
|
if (behavior.kind === "directive") {
|
|
@@ -92,9 +90,9 @@ const useTriggerSelectionResource = ({
|
|
|
92
90
|
behavior.onInserted?.(item);
|
|
93
91
|
} else {
|
|
94
92
|
if (behavior.removeOnExecute) {
|
|
95
|
-
aui
|
|
96
|
-
.
|
|
97
|
-
|
|
93
|
+
aui.composer.setText(
|
|
94
|
+
before + (after.startsWith(" ") ? after.slice(1) : after),
|
|
95
|
+
);
|
|
98
96
|
} else {
|
|
99
97
|
// Leave directive chip in the composer as an audit trail
|
|
100
98
|
insertDirective();
|
|
@@ -230,11 +230,9 @@ const ToolUIDisplay = ({
|
|
|
230
230
|
}: {
|
|
231
231
|
Fallback: ToolCallMessagePartComponent | undefined;
|
|
232
232
|
} & ToolCallMessagePartProps) => {
|
|
233
|
-
const Render = useAuiState(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return Render;
|
|
237
|
-
});
|
|
233
|
+
const Render = useAuiState(
|
|
234
|
+
(s) => s.tools.toolUIs[props.toolName]?.[0]?.render ?? Fallback,
|
|
235
|
+
);
|
|
238
236
|
if (!Render) return null;
|
|
239
237
|
return <Render {...props} />;
|
|
240
238
|
};
|
|
@@ -292,9 +290,9 @@ const MessagePartComponent: FC<MessagePartComponentProps> = ({
|
|
|
292
290
|
|
|
293
291
|
const type = part.type;
|
|
294
292
|
if (type === "tool-call") {
|
|
295
|
-
const addResult = aui.part
|
|
296
|
-
const resume = aui.part
|
|
297
|
-
const respondToApproval = aui.part
|
|
293
|
+
const addResult = aui.part.addToolResult;
|
|
294
|
+
const resume = aui.part.resumeToolCall;
|
|
295
|
+
const respondToApproval = aui.part.respondToToolApproval;
|
|
298
296
|
if ("Override" in tools)
|
|
299
297
|
return (
|
|
300
298
|
<tools.Override
|
|
@@ -23,7 +23,7 @@ type ThreadViewportStore = NonNullable<
|
|
|
23
23
|
|
|
24
24
|
const useIsHoveringRef = () => {
|
|
25
25
|
const aui = useAui();
|
|
26
|
-
const message = useAuiState(() => aui.message
|
|
26
|
+
const message = useAuiState(() => aui.message);
|
|
27
27
|
|
|
28
28
|
const callbackRef = useCallback(
|
|
29
29
|
(el: HTMLElement) => {
|
|
@@ -34,24 +34,24 @@ const useSuggestionTrigger = ({
|
|
|
34
34
|
const resolvedSend = send ?? false;
|
|
35
35
|
|
|
36
36
|
const callback = useCallback(() => {
|
|
37
|
-
const isRunning = aui.thread
|
|
37
|
+
const isRunning = aui.thread.getState().isRunning;
|
|
38
38
|
|
|
39
39
|
if (resolvedSend && !isRunning) {
|
|
40
|
-
aui.thread
|
|
40
|
+
aui.thread.append({
|
|
41
41
|
content: [{ type: "text", text: prompt }],
|
|
42
|
-
runConfig: aui.composer
|
|
42
|
+
runConfig: aui.composer.getState().runConfig,
|
|
43
43
|
});
|
|
44
44
|
if (clearComposer) {
|
|
45
|
-
aui.composer
|
|
45
|
+
aui.composer.setText("");
|
|
46
46
|
}
|
|
47
47
|
} else {
|
|
48
48
|
if (clearComposer) {
|
|
49
|
-
aui.composer
|
|
49
|
+
aui.composer.setText(prompt);
|
|
50
50
|
} else {
|
|
51
|
-
const currentText = aui.composer
|
|
52
|
-
aui
|
|
53
|
-
.
|
|
54
|
-
|
|
51
|
+
const currentText = aui.composer.getState().text;
|
|
52
|
+
aui.composer.setText(
|
|
53
|
+
currentText.trim() ? `${currentText} ${prompt}` : prompt,
|
|
54
|
+
);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}, [aui, resolvedSend, clearComposer, prompt]);
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
// Data part rendering contract: global renderers > global fallbacks >
|
|
4
|
+
// inline `components.data` config, exercised through the real store.
|
|
5
|
+
|
|
6
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
7
|
+
import {
|
|
8
|
+
useEffect,
|
|
9
|
+
type FC,
|
|
10
|
+
type PropsWithChildren,
|
|
11
|
+
type ReactNode,
|
|
12
|
+
} from "react";
|
|
13
|
+
import { describe, expect, it } from "vitest";
|
|
14
|
+
import { useAui } from "@assistant-ui/store";
|
|
15
|
+
import { AssistantRuntimeProvider } from "../context";
|
|
16
|
+
import * as MessagePrimitive from "../primitives/message";
|
|
17
|
+
import * as ThreadPrimitive from "../primitives/thread";
|
|
18
|
+
import { useLocalRuntime } from "../legacy-runtime/runtime-cores/local/useLocalRuntime";
|
|
19
|
+
import {
|
|
20
|
+
useAssistantDataUI,
|
|
21
|
+
type ChatModelAdapter,
|
|
22
|
+
type DataMessagePartComponent,
|
|
23
|
+
type ThreadMessageLike,
|
|
24
|
+
} from "../index";
|
|
25
|
+
|
|
26
|
+
const noOpAdapter: ChatModelAdapter = {
|
|
27
|
+
async *run() {},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const dataMessages = (name: string): ThreadMessageLike[] => [
|
|
31
|
+
{
|
|
32
|
+
role: "assistant",
|
|
33
|
+
content: [{ type: "data", name, data: { value: 42 } }],
|
|
34
|
+
status: { type: "complete", reason: "stop" },
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const labeled =
|
|
39
|
+
(label: string): DataMessagePartComponent =>
|
|
40
|
+
({ name, data }) => (
|
|
41
|
+
<span data-testid={label}>
|
|
42
|
+
{name}:{(data as { value: number }).value}
|
|
43
|
+
</span>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const RuntimeProvider: FC<
|
|
47
|
+
PropsWithChildren<{ messages: ThreadMessageLike[] }>
|
|
48
|
+
> = ({ children, messages }) => {
|
|
49
|
+
const runtime = useLocalRuntime(noOpAdapter, { initialMessages: messages });
|
|
50
|
+
return (
|
|
51
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
52
|
+
{children}
|
|
53
|
+
</AssistantRuntimeProvider>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const GlobalDataUI: FC<{ name: string; render: DataMessagePartComponent }> = ({
|
|
58
|
+
name,
|
|
59
|
+
render,
|
|
60
|
+
}) => {
|
|
61
|
+
useAssistantDataUI({ name, render });
|
|
62
|
+
return null;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const GlobalFallbackDataUI: FC<{ render: DataMessagePartComponent }> = ({
|
|
66
|
+
render,
|
|
67
|
+
}) => {
|
|
68
|
+
const aui = useAui();
|
|
69
|
+
useEffect(() => aui.dataRenderers.setFallbackDataUI(render), [aui, render]);
|
|
70
|
+
return null;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const renderThread = (
|
|
74
|
+
messages: ThreadMessageLike[],
|
|
75
|
+
Message: FC,
|
|
76
|
+
extra?: ReactNode,
|
|
77
|
+
) =>
|
|
78
|
+
render(
|
|
79
|
+
<RuntimeProvider messages={messages}>
|
|
80
|
+
{extra}
|
|
81
|
+
<ThreadPrimitive.Messages components={{ Message }} />
|
|
82
|
+
</RuntimeProvider>,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
describe("data part rendering", () => {
|
|
86
|
+
it("renders a data part via the inline by_name config with its name and data", async () => {
|
|
87
|
+
const Message: FC = () => (
|
|
88
|
+
<MessagePrimitive.Parts
|
|
89
|
+
components={{ data: { by_name: { chart: labeled("inline") } } }}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
renderThread(dataMessages("chart"), Message);
|
|
94
|
+
|
|
95
|
+
await waitFor(() => {
|
|
96
|
+
expect(screen.getByTestId("inline").textContent).toBe("chart:42");
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("uses the inline Fallback for unmatched names and renders nothing without one", async () => {
|
|
101
|
+
const Message: FC = () => (
|
|
102
|
+
<div data-testid="host">
|
|
103
|
+
<MessagePrimitive.Parts
|
|
104
|
+
components={{
|
|
105
|
+
data: { by_name: { other: labeled("named") } },
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
renderThread(dataMessages("chart"), Message);
|
|
112
|
+
await waitFor(() => {
|
|
113
|
+
expect(screen.getByTestId("host").textContent).toBe("");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const MessageWithFallback: FC = () => (
|
|
117
|
+
<MessagePrimitive.Parts
|
|
118
|
+
components={{
|
|
119
|
+
data: {
|
|
120
|
+
by_name: { other: labeled("named") },
|
|
121
|
+
Fallback: labeled("inline-fallback"),
|
|
122
|
+
},
|
|
123
|
+
}}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
renderThread(dataMessages("chart"), MessageWithFallback);
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(screen.getByTestId("inline-fallback").textContent).toBe(
|
|
129
|
+
"chart:42",
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("prefers a globally registered renderer over the inline by_name config", async () => {
|
|
135
|
+
const Message: FC = () => (
|
|
136
|
+
<MessagePrimitive.Parts
|
|
137
|
+
components={{ data: { by_name: { chart: labeled("inline") } } }}
|
|
138
|
+
/>
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
renderThread(
|
|
142
|
+
dataMessages("chart"),
|
|
143
|
+
Message,
|
|
144
|
+
<GlobalDataUI name="chart" render={labeled("global")} />,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
await waitFor(() => {
|
|
148
|
+
expect(screen.getByTestId("global").textContent).toBe("chart:42");
|
|
149
|
+
});
|
|
150
|
+
expect(screen.queryByTestId("inline")).toBeNull();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("resolves global fallbacks above inline fallbacks but below named matches", async () => {
|
|
154
|
+
const Message: FC = () => (
|
|
155
|
+
<MessagePrimitive.Parts
|
|
156
|
+
components={{ data: { Fallback: labeled("inline-fallback") } }}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
renderThread(
|
|
161
|
+
dataMessages("chart"),
|
|
162
|
+
Message,
|
|
163
|
+
<GlobalFallbackDataUI render={labeled("global-fallback")} />,
|
|
164
|
+
);
|
|
165
|
+
await waitFor(() => {
|
|
166
|
+
expect(screen.getByTestId("global-fallback").textContent).toBe(
|
|
167
|
+
"chart:42",
|
|
168
|
+
);
|
|
169
|
+
});
|
|
170
|
+
expect(screen.queryByTestId("inline-fallback")).toBeNull();
|
|
171
|
+
|
|
172
|
+
renderThread(
|
|
173
|
+
dataMessages("chart"),
|
|
174
|
+
Message,
|
|
175
|
+
<>
|
|
176
|
+
<GlobalFallbackDataUI render={labeled("global-fallback-2")} />
|
|
177
|
+
<GlobalDataUI name="chart" render={labeled("global-named")} />
|
|
178
|
+
</>,
|
|
179
|
+
);
|
|
180
|
+
await waitFor(() => {
|
|
181
|
+
expect(screen.getByTestId("global-named").textContent).toBe("chart:42");
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("restores the inline renderer when the registering component unmounts", async () => {
|
|
186
|
+
const Message: FC = () => (
|
|
187
|
+
<MessagePrimitive.Parts
|
|
188
|
+
components={{ data: { by_name: { chart: labeled("inline") } } }}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const view = render(
|
|
193
|
+
<RuntimeProvider messages={dataMessages("chart")}>
|
|
194
|
+
<GlobalDataUI name="chart" render={labeled("global")} />
|
|
195
|
+
<ThreadPrimitive.Messages components={{ Message }} />
|
|
196
|
+
</RuntimeProvider>,
|
|
197
|
+
);
|
|
198
|
+
await waitFor(() => {
|
|
199
|
+
expect(screen.getByTestId("global")).toBeTruthy();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
view.rerender(
|
|
203
|
+
<RuntimeProvider messages={dataMessages("chart")}>
|
|
204
|
+
<ThreadPrimitive.Messages components={{ Message }} />
|
|
205
|
+
</RuntimeProvider>,
|
|
206
|
+
);
|
|
207
|
+
await waitFor(() => {
|
|
208
|
+
expect(screen.getByTestId("inline").textContent).toBe("chart:42");
|
|
209
|
+
});
|
|
210
|
+
expect(screen.queryByTestId("global")).toBeNull();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
@@ -67,17 +67,7 @@ const wrapInRuntimeAdapterProvider = (
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
describe("RemoteThreadListAdapter.unstable_Provider", () => {
|
|
70
|
-
it("makes
|
|
71
|
-
const capture: { adapters: CapturedAdapters } = { adapters: null };
|
|
72
|
-
const adapter = makeAdapter({
|
|
73
|
-
unstable_Provider: wrapInRuntimeAdapterProvider(dummyHistory),
|
|
74
|
-
});
|
|
75
|
-
await renderAndWaitForBinder(adapter, capture);
|
|
76
|
-
|
|
77
|
-
expect(capture.adapters?.history).toBe(dummyHistory);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("preserves modelContext from the outer runtime-core RuntimeAdapterProvider", async () => {
|
|
70
|
+
it("makes Provider context visible to the runtime hook while preserving outer modelContext", async () => {
|
|
81
71
|
const capture: { adapters: CapturedAdapters } = { adapters: null };
|
|
82
72
|
const adapter = makeAdapter({
|
|
83
73
|
unstable_Provider: wrapInRuntimeAdapterProvider(dummyHistory),
|
|
@@ -6,9 +6,9 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
6
6
|
import { useRemoteThreadListRuntime } from "@assistant-ui/core/react";
|
|
7
7
|
import { makeAdapter } from "./remote-thread-list-test-helpers";
|
|
8
8
|
import type { AssistantRuntime } from "@assistant-ui/core";
|
|
9
|
+
import { useAui } from "@assistant-ui/store";
|
|
9
10
|
import { AssistantRuntimeProvider } from "../context";
|
|
10
11
|
import { useLocalRuntime } from "../legacy-runtime/runtime-cores/local/useLocalRuntime";
|
|
11
|
-
import { useAssistantRuntime } from "../legacy-runtime/hooks/AssistantContext";
|
|
12
12
|
import type { ChatModelAdapter, RemoteThreadListAdapter } from "../index";
|
|
13
13
|
|
|
14
14
|
const noOpAdapter: ChatModelAdapter = {
|
|
@@ -34,8 +34,8 @@ const RuntimeProvider: FC<
|
|
|
34
34
|
const RuntimeCapture: FC<{
|
|
35
35
|
runtimeRef: { current: AssistantRuntime | null };
|
|
36
36
|
}> = ({ runtimeRef }) => {
|
|
37
|
-
const
|
|
38
|
-
runtimeRef.current =
|
|
37
|
+
const aui = useAui();
|
|
38
|
+
runtimeRef.current = aui.threads.__internal_getAssistantRuntime?.() ?? null;
|
|
39
39
|
return null;
|
|
40
40
|
};
|
|
41
41
|
|