@assistant-ui/core 0.2.21 → 0.2.23
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/adapters/attachment.d.ts.map +1 -1
- package/dist/adapters/speech.d.ts.map +1 -1
- package/dist/adapters/speech.js +9 -2
- package/dist/adapters/speech.js.map +1 -1
- package/dist/adapters/thread-history.d.ts +8 -0
- package/dist/adapters/thread-history.d.ts.map +1 -1
- package/dist/adapters/voice.d.ts.map +1 -1
- package/dist/adapters/voice.js +13 -5
- package/dist/adapters/voice.js.map +1 -1
- package/dist/internal.d.ts +5 -2
- package/dist/internal.js +5 -2
- package/dist/model-context/frame/host.d.ts +1 -0
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +41 -21
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +1 -0
- package/dist/model-context/frame/provider.js.map +1 -1
- package/dist/model-context/interactable-composer-metadata.js.map +1 -1
- package/dist/model-context/types.d.ts.map +1 -1
- package/dist/model-context/types.js +13 -4
- package/dist/model-context/types.js.map +1 -1
- package/dist/react/AssistantProvider.js.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +78 -50
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/interactable-model-context.d.ts.map +1 -1
- package/dist/react/client/interactable-model-context.js +1 -0
- package/dist/react/client/interactable-model-context.js.map +1 -1
- package/dist/react/interactables-legacy/useInteractableState.js +1 -0
- package/dist/react/interactables-legacy/useInteractableState.js.map +1 -1
- package/dist/react/model-context/useInteractable.js.map +1 -1
- package/dist/react/model-context/useInteractableState.js +1 -0
- package/dist/react/model-context/useInteractableState.js.map +1 -1
- package/dist/react/model-context/useInteractableVersions.js +1 -0
- package/dist/react/model-context/useInteractableVersions.js.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.js +1 -0
- package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarCopy.js +14 -13
- package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarEdit.js +1 -0
- package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarFeedback.js +1 -0
- package/dist/react/primitive-hooks/useActionBarFeedback.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarReload.js +1 -0
- package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarSpeak.js +1 -0
- package/dist/react/primitive-hooks/useActionBarSpeak.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarStopSpeaking.js +1 -0
- package/dist/react/primitive-hooks/useActionBarStopSpeaking.js.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerNext.js +1 -0
- package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerPrevious.js +1 -0
- package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerAddAttachment.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerAddAttachment.js +1 -0
- package/dist/react/primitive-hooks/useComposerAddAttachment.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerCancel.js +1 -0
- package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerDictate.js +1 -0
- package/dist/react/primitive-hooks/useComposerDictate.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerSend.js +1 -0
- package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
- package/dist/react/primitive-hooks/useEditComposerCancel.js +1 -0
- package/dist/react/primitive-hooks/useEditComposerCancel.js.map +1 -1
- package/dist/react/primitive-hooks/useEditComposerSend.js +1 -0
- package/dist/react/primitive-hooks/useEditComposerSend.js.map +1 -1
- package/dist/react/primitive-hooks/useMessageBranching.js +1 -0
- package/dist/react/primitive-hooks/useMessageBranching.js.map +1 -1
- package/dist/react/primitive-hooks/useMessageReload.js +1 -0
- package/dist/react/primitive-hooks/useMessageReload.js.map +1 -1
- package/dist/react/primitive-hooks/useSuggestionTrigger.js +1 -0
- package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemArchive.js +1 -0
- package/dist/react/primitive-hooks/useThreadListItemArchive.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemDelete.js +1 -0
- package/dist/react/primitive-hooks/useThreadListItemDelete.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemTrigger.js +1 -0
- package/dist/react/primitive-hooks/useThreadListItemTrigger.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemUnarchive.js +1 -0
- package/dist/react/primitive-hooks/useThreadListItemUnarchive.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.js +1 -0
- package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListNew.js +1 -0
- package/dist/react/primitive-hooks/useThreadListNew.js.map +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
- package/dist/react/primitives/generativeUI/GenerativeUI.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.d.ts +2 -1
- package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js +46 -36
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/primitives/part/PartMessages.js.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/react/primitives/thread/ThreadSuggestions.js.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js +18 -30
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -1
- package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/PartByIndexProvider.js +18 -30
- package/dist/react/providers/PartByIndexProvider.js.map +1 -1
- package/dist/react/providers/TextMessagePartProvider.js +1 -0
- package/dist/react/providers/TextMessagePartProvider.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +1 -0
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +9 -2
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +55 -12
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +31 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +12 -2
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -2
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +12 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +2 -1
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +75 -73
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +2 -2
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreSharedOptions.js +1 -0
- package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.js +9 -1
- package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
- package/dist/runtime/api/assistant-runtime.d.ts +1 -1
- package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
- package/dist/runtime/api/assistant-runtime.js +1 -1
- package/dist/runtime/api/assistant-runtime.js.map +1 -1
- package/dist/runtime/api/attachment-runtime.d.ts +1 -1
- package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
- package/dist/runtime/api/attachment-runtime.js +1 -1
- package/dist/runtime/api/attachment-runtime.js.map +1 -1
- package/dist/runtime/api/composer-runtime.d.ts +2 -2
- package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.js +2 -2
- package/dist/runtime/api/composer-runtime.js.map +1 -1
- package/dist/runtime/api/message-part-runtime.d.ts +4 -4
- package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.js +3 -3
- package/dist/runtime/api/message-part-runtime.js.map +1 -1
- package/dist/runtime/api/message-runtime.d.ts +1 -1
- package/dist/runtime/api/message-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-runtime.js +6 -6
- package/dist/runtime/api/message-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.js +4 -3
- package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +1 -1
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +4 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +41 -14
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +3 -2
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +2 -2
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +6 -4
- package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js +3 -3
- package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +4 -2
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtime/utils/thread-message-like.js +4 -1
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/runtimes/external-store/external-store-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +12 -0
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/internal.d.ts +2 -1
- package/dist/runtimes/internal.js +2 -1
- package/dist/runtimes/local/local-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +49 -15
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +4 -4
- package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/optimistic-state.js +22 -9
- package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +32 -27
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +3 -2
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/chain-of-thought-client.d.ts.map +1 -1
- package/dist/store/clients/no-op-composer-client.d.ts.map +1 -1
- package/dist/store/clients/no-op-composer-client.js +1 -0
- package/dist/store/clients/no-op-composer-client.js.map +1 -1
- package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-part-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -0
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +17 -15
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/scopes/thread.d.ts +1 -0
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/subscribable/subscribable.d.ts +4 -4
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +14 -6
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/tests/remote-thread-list-test-helpers.d.ts +2 -1
- package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
- package/dist/tests/remote-thread-list-test-helpers.js +5 -2
- package/dist/tests/remote-thread-list-test-helpers.js.map +1 -1
- package/dist/types/attachment.d.ts +2 -1
- package/dist/types/attachment.d.ts.map +1 -1
- package/dist/types/attachment.js +6 -0
- package/dist/types/attachment.js.map +1 -0
- package/dist/types/message.d.ts +1 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/data-url.d.ts +9 -0
- package/dist/utils/data-url.d.ts.map +1 -0
- package/dist/utils/data-url.js +14 -0
- package/dist/utils/data-url.js.map +1 -0
- package/dist/utils/notify-event-listeners.d.ts +6 -0
- package/dist/utils/notify-event-listeners.d.ts.map +1 -0
- package/dist/utils/notify-event-listeners.js +16 -0
- package/dist/utils/notify-event-listeners.js.map +1 -0
- package/package.json +10 -9
- package/src/adapters/speech.test.ts +88 -0
- package/src/adapters/speech.ts +17 -2
- package/src/adapters/thread-history.ts +8 -0
- package/src/adapters/voice.test.ts +130 -0
- package/src/adapters/voice.ts +26 -6
- package/src/internal.ts +6 -1
- package/src/model-context/frame/host.test.ts +147 -0
- package/src/model-context/frame/host.ts +56 -19
- package/src/model-context/frame/provider.test.ts +83 -0
- package/src/model-context/frame/provider.ts +1 -0
- package/src/model-context/types.ts +16 -6
- package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +82 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +108 -58
- package/src/react/primitive-hooks/useActionBarCopy.test.ts +79 -0
- package/src/react/primitive-hooks/useActionBarCopy.ts +4 -3
- package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -3
- package/src/react/primitives/message/MessageParts.tsx +48 -35
- package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +19 -2
- package/src/react/providers/PartByIndexProvider.tsx +16 -2
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +18 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +1 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +68 -13
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +34 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +69 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +27 -6
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +16 -0
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +7 -2
- package/src/react/runtimes/cloud/auiV0.ts +14 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +90 -88
- package/src/react/runtimes/external-message-converter.test.ts +346 -0
- package/src/react/runtimes/external-message-converter.test.tsx +21 -0
- package/src/react/runtimes/external-message-converter.ts +2 -2
- package/src/react/runtimes/useLocalRuntime.test.tsx +99 -0
- package/src/react/runtimes/useLocalRuntime.ts +13 -1
- package/src/runtime/api/assistant-runtime.ts +4 -1
- package/src/runtime/api/attachment-runtime.ts +8 -2
- package/src/runtime/api/composer-runtime.ts +9 -5
- package/src/runtime/api/message-part-runtime.ts +10 -3
- package/src/runtime/api/message-runtime.test.ts +81 -0
- package/src/runtime/api/message-runtime.ts +11 -8
- package/src/runtime/api/thread-list-item-runtime.ts +13 -3
- package/src/runtime/api/thread-list-runtime.ts +10 -2
- package/src/runtime/base/base-composer-runtime-core.ts +77 -31
- package/src/runtime/base/base-thread-runtime-core.ts +7 -2
- package/src/runtime/base/default-edit-composer-runtime-core.ts +18 -4
- package/src/runtime/base/default-thread-composer-runtime-core.ts +13 -3
- package/src/runtime/utils/message-repository.ts +19 -13
- package/src/runtime/utils/thread-message-like.ts +1 -0
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +15 -0
- package/src/runtimes/internal.ts +3 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +746 -1
- package/src/runtimes/local/local-thread-runtime-core.ts +89 -23
- package/src/runtimes/local/should-continue.test.ts +122 -0
- package/src/runtimes/remote-thread-list/optimistic-state.test.ts +63 -0
- package/src/runtimes/remote-thread-list/optimistic-state.ts +49 -17
- package/src/runtimes/remote-thread-list/types.ts +1 -1
- package/src/runtimes/tool-invocations/EDGE_CASES.md +13 -19
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +128 -8
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +42 -34
- package/src/store/clients/model-context-client.test.ts +21 -1
- package/src/store/runtime-clients/thread-runtime-client.ts +2 -1
- package/src/store/scopes/thread.ts +1 -0
- package/src/subscribable/subscribable.test.ts +58 -0
- package/src/subscribable/subscribable.ts +29 -11
- package/src/tests/MessageRepository.test.ts +12 -0
- package/src/tests/OptimisticState-list-race.test.ts +33 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-order.test.ts +223 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-position.test.ts +121 -0
- package/src/tests/auiV0Encode.test.ts +74 -0
- package/src/tests/base-composer-runtime-core-addAttachment.test.ts +44 -0
- package/src/tests/base-composer-runtime-core-send.test.ts +433 -5
- package/src/tests/base-composer-runtime-core.test.ts +422 -0
- package/src/tests/default-edit-composer-runtime-core.test.ts +43 -5
- package/src/tests/event-subscription-listener-errors.test.ts +205 -0
- package/src/tests/external-store-thread-list-runtime-core.test.ts +6 -6
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +575 -0
- package/src/tests/external-store-thread-runtime-core.test.ts +55 -1
- package/src/tests/remote-thread-list-test-helpers.ts +14 -7
- package/src/tests/thread-message-like.test.ts +57 -0
- package/src/types/attachment.ts +5 -0
- package/src/types/message.ts +1 -0
- package/src/utils/data-url.test.ts +50 -0
- package/src/utils/data-url.ts +9 -0
- package/src/utils/notify-event-listeners.ts +30 -0
- package/src/tests/OptimisticState-delete-crash.test.ts +0 -208
|
@@ -18,6 +18,19 @@ export const contextProvider: ModelContextProvider = {
|
|
|
18
18
|
subscribe: () => () => {},
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
export function setStartThreadRuntime(
|
|
22
|
+
core: RemoteThreadListThreadListRuntimeCore,
|
|
23
|
+
startThreadRuntime: (id: string) => Promise<unknown>,
|
|
24
|
+
) {
|
|
25
|
+
(
|
|
26
|
+
core as unknown as {
|
|
27
|
+
_hookManager: {
|
|
28
|
+
startThreadRuntime: (id: string) => Promise<unknown>;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
)._hookManager.startThreadRuntime = startThreadRuntime;
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
export function makeAdapter(
|
|
22
35
|
overrides: Partial<RemoteThreadListAdapter> = {},
|
|
23
36
|
): RemoteThreadListAdapter {
|
|
@@ -60,12 +73,6 @@ export function createCore(
|
|
|
60
73
|
);
|
|
61
74
|
// `startThreadRuntime` blocks until a React component attaches a runtime;
|
|
62
75
|
// stub it so non-React unit tests don't hang.
|
|
63
|
-
(
|
|
64
|
-
core as unknown as {
|
|
65
|
-
_hookManager: {
|
|
66
|
-
startThreadRuntime: (id: string) => Promise<unknown>;
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
)._hookManager.startThreadRuntime = async () => ({});
|
|
76
|
+
setStartThreadRuntime(core, async () => ({}));
|
|
70
77
|
return core;
|
|
71
78
|
}
|
|
@@ -200,4 +200,61 @@ describe("fromThreadMessageLike", () => {
|
|
|
200
200
|
});
|
|
201
201
|
});
|
|
202
202
|
});
|
|
203
|
+
|
|
204
|
+
describe("metadata.isOptimistic", () => {
|
|
205
|
+
it("preserves isOptimistic on user messages", () => {
|
|
206
|
+
const result = fromThreadMessageLike(
|
|
207
|
+
{
|
|
208
|
+
role: "user",
|
|
209
|
+
content: [{ type: "text", text: "hello" }],
|
|
210
|
+
metadata: { isOptimistic: true },
|
|
211
|
+
},
|
|
212
|
+
fallbackId,
|
|
213
|
+
fallbackStatus,
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
expect(result.metadata.isOptimistic).toBe(true);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("preserves isOptimistic on assistant messages", () => {
|
|
220
|
+
const result = fromThreadMessageLike(
|
|
221
|
+
{
|
|
222
|
+
role: "assistant",
|
|
223
|
+
content: [{ type: "text", text: "hello" }],
|
|
224
|
+
metadata: { isOptimistic: true },
|
|
225
|
+
},
|
|
226
|
+
fallbackId,
|
|
227
|
+
fallbackStatus,
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
expect(result.metadata.isOptimistic).toBe(true);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("omits isOptimistic when false", () => {
|
|
234
|
+
const result = fromThreadMessageLike(
|
|
235
|
+
{
|
|
236
|
+
role: "user",
|
|
237
|
+
content: [{ type: "text", text: "hello" }],
|
|
238
|
+
metadata: { isOptimistic: false },
|
|
239
|
+
},
|
|
240
|
+
fallbackId,
|
|
241
|
+
fallbackStatus,
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
expect(result.metadata).not.toHaveProperty("isOptimistic");
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("omits isOptimistic when not set", () => {
|
|
248
|
+
const result = fromThreadMessageLike(
|
|
249
|
+
{
|
|
250
|
+
role: "user",
|
|
251
|
+
content: [{ type: "text", text: "hello" }],
|
|
252
|
+
},
|
|
253
|
+
fallbackId,
|
|
254
|
+
fallbackStatus,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
expect(result.metadata).not.toHaveProperty("isOptimistic");
|
|
258
|
+
});
|
|
259
|
+
});
|
|
203
260
|
});
|
package/src/types/attachment.ts
CHANGED
|
@@ -52,3 +52,8 @@ export type CreateAttachment = {
|
|
|
52
52
|
contentType?: string;
|
|
53
53
|
content: ThreadUserMessagePart[];
|
|
54
54
|
};
|
|
55
|
+
|
|
56
|
+
export const isCreateAttachment = (
|
|
57
|
+
attachment: File | CreateAttachment,
|
|
58
|
+
): attachment is CreateAttachment =>
|
|
59
|
+
"content" in attachment && !("lastModified" in attachment);
|
package/src/types/message.ts
CHANGED
|
@@ -349,6 +349,7 @@ export type ThreadUserMessage = MessageCommonProps & {
|
|
|
349
349
|
readonly steps?: undefined;
|
|
350
350
|
readonly submittedFeedback?: undefined;
|
|
351
351
|
readonly timing?: undefined;
|
|
352
|
+
readonly isOptimistic?: boolean;
|
|
352
353
|
readonly custom: Record<string, unknown>;
|
|
353
354
|
};
|
|
354
355
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { httpUrlPattern, parseDataUrl } from "./data-url";
|
|
3
|
+
|
|
4
|
+
describe("parseDataUrl", () => {
|
|
5
|
+
it("parses a base64 data URL", () => {
|
|
6
|
+
expect(parseDataUrl("data:image/png;base64,aGVsbG8=")).toEqual({
|
|
7
|
+
mimeType: "image/png",
|
|
8
|
+
data: "aGVsbG8=",
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("parses a data URL with extra parameters", () => {
|
|
13
|
+
expect(parseDataUrl("data:text/plain;charset=utf-8;base64,aGk=")).toEqual({
|
|
14
|
+
mimeType: "text/plain",
|
|
15
|
+
data: "aGk=",
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("returns null for non-base64 data URLs", () => {
|
|
20
|
+
expect(parseDataUrl("data:text/plain,hello")).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("returns null for data URLs with an empty payload", () => {
|
|
24
|
+
expect(parseDataUrl("data:image/png;base64,")).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("returns null for plain strings", () => {
|
|
28
|
+
expect(parseDataUrl("aGVsbG8=")).toBeNull();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("returns null for http URLs", () => {
|
|
32
|
+
expect(parseDataUrl("https://example.com/a.png")).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("httpUrlPattern", () => {
|
|
37
|
+
it.each(["http://example.com", "https://example.com", "HTTPS://EXAMPLE.COM"])(
|
|
38
|
+
"matches %s",
|
|
39
|
+
(value) => {
|
|
40
|
+
expect(httpUrlPattern.test(value)).toBe(true);
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
it.each(["ftp://example.com", "data:image/png;base64,aGk=", "/relative"])(
|
|
45
|
+
"does not match %s",
|
|
46
|
+
(value) => {
|
|
47
|
+
expect(httpUrlPattern.test(value)).toBe(false);
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const httpUrlPattern = /^https?:\/\//i;
|
|
2
|
+
|
|
3
|
+
export function parseDataUrl(
|
|
4
|
+
value: string,
|
|
5
|
+
): { mimeType: string; data: string } | null {
|
|
6
|
+
const match = value.match(/^data:([^;,]+)(?:;[^;,]+)*;base64,(.+)$/);
|
|
7
|
+
if (!match) return null;
|
|
8
|
+
return { mimeType: match[1]!, data: match[2]! };
|
|
9
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type EventListener = (payload?: unknown) => void;
|
|
2
|
+
|
|
3
|
+
export const notifyEventListeners = (
|
|
4
|
+
listeners: Iterable<EventListener>,
|
|
5
|
+
payload: unknown,
|
|
6
|
+
errorContext: string,
|
|
7
|
+
) => {
|
|
8
|
+
const reportError = (error: unknown) => {
|
|
9
|
+
console.error(
|
|
10
|
+
`[assistant-ui] ${errorContext} listener threw an error`,
|
|
11
|
+
error,
|
|
12
|
+
);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
for (const listener of listeners) {
|
|
16
|
+
try {
|
|
17
|
+
const result = listener(payload) as unknown;
|
|
18
|
+
if (
|
|
19
|
+
result !== null &&
|
|
20
|
+
(typeof result === "object" || typeof result === "function") &&
|
|
21
|
+
"then" in result &&
|
|
22
|
+
typeof result.then === "function"
|
|
23
|
+
) {
|
|
24
|
+
void Promise.resolve(result).catch(reportError);
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
reportError(error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { OptimisticState } from "../runtimes/remote-thread-list/optimistic-state";
|
|
3
|
-
import {
|
|
4
|
-
type RemoteThreadState,
|
|
5
|
-
createThreadMappingId,
|
|
6
|
-
updateStatusReducer,
|
|
7
|
-
getThreadData,
|
|
8
|
-
} from "../runtimes/remote-thread-list/remote-thread-state";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* This test reproduces the crash from issue #3346:
|
|
12
|
-
* "Entry not available in the store" when deleting the active thread.
|
|
13
|
-
*
|
|
14
|
-
* Root cause: optimisticUpdate's `optimistic` callback runs synchronously
|
|
15
|
-
* and removes the thread from threadData, but mainThreadId still points to
|
|
16
|
-
* the deleted thread. Subscribers that fire during _notifySubscribers() see
|
|
17
|
-
* this inconsistent state and crash.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
const createThreadState = (
|
|
21
|
-
threadId: string,
|
|
22
|
-
status: "regular" | "archived" = "regular",
|
|
23
|
-
): RemoteThreadState => {
|
|
24
|
-
const mappingId = createThreadMappingId(threadId);
|
|
25
|
-
return {
|
|
26
|
-
isLoading: false,
|
|
27
|
-
isLoadingMore: false,
|
|
28
|
-
cursor: undefined,
|
|
29
|
-
newThreadId: undefined,
|
|
30
|
-
threadIds: status === "regular" ? [threadId] : [],
|
|
31
|
-
archivedThreadIds: status === "archived" ? [threadId] : [],
|
|
32
|
-
threadIdMap: { [threadId]: mappingId },
|
|
33
|
-
threadData: {
|
|
34
|
-
[mappingId]: {
|
|
35
|
-
id: threadId,
|
|
36
|
-
remoteId: threadId,
|
|
37
|
-
externalId: undefined,
|
|
38
|
-
status,
|
|
39
|
-
title: undefined,
|
|
40
|
-
initializeTask: Promise.resolve({
|
|
41
|
-
remoteId: threadId,
|
|
42
|
-
externalId: undefined,
|
|
43
|
-
}),
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
describe("OptimisticState delete crash (#3346)", () => {
|
|
50
|
-
it("optimistic callback runs synchronously before execute completes", async () => {
|
|
51
|
-
const state = new OptimisticState(createThreadState("thread-1"));
|
|
52
|
-
const events: string[] = [];
|
|
53
|
-
|
|
54
|
-
state.subscribe(() => {
|
|
55
|
-
events.push("subscriber-notified");
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const executeStarted = vi.fn();
|
|
59
|
-
const executeCompleted = vi.fn();
|
|
60
|
-
|
|
61
|
-
const promise = state.optimisticUpdate({
|
|
62
|
-
execute: async () => {
|
|
63
|
-
executeStarted();
|
|
64
|
-
// simulate async work like _ensureThreadIsNotMain
|
|
65
|
-
await Promise.resolve();
|
|
66
|
-
executeCompleted();
|
|
67
|
-
},
|
|
68
|
-
optimistic: (s) => {
|
|
69
|
-
events.push("optimistic-ran");
|
|
70
|
-
return updateStatusReducer(s, "thread-1", "deleted");
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// After calling optimisticUpdate but before awaiting:
|
|
75
|
-
// - optimistic callback has already run (synchronous)
|
|
76
|
-
// - execute has started but not completed (async)
|
|
77
|
-
expect(events).toEqual(["optimistic-ran", "subscriber-notified"]);
|
|
78
|
-
expect(executeStarted).toHaveBeenCalled();
|
|
79
|
-
expect(executeCompleted).not.toHaveBeenCalled();
|
|
80
|
-
|
|
81
|
-
// Thread data is already gone from the optimistic value
|
|
82
|
-
expect(getThreadData(state.value, "thread-1")).toBeUndefined();
|
|
83
|
-
|
|
84
|
-
await promise;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("BUG SCENARIO: subscriber sees deleted thread data while mainThreadId still references it", async () => {
|
|
88
|
-
const state = new OptimisticState(createThreadState("thread-1"));
|
|
89
|
-
|
|
90
|
-
// Simulate what happens in the real code:
|
|
91
|
-
// mainThreadId is external state that _ensureThreadIsNotMain would update
|
|
92
|
-
let mainThreadId = "thread-1";
|
|
93
|
-
let subscriberSawInconsistentState = false;
|
|
94
|
-
|
|
95
|
-
state.subscribe(() => {
|
|
96
|
-
// This fires synchronously during optimisticUpdate.
|
|
97
|
-
// In the real code, React components would re-render here and try to
|
|
98
|
-
// access the main thread's data.
|
|
99
|
-
const threadData = getThreadData(state.value, mainThreadId);
|
|
100
|
-
if (threadData === undefined && mainThreadId === "thread-1") {
|
|
101
|
-
// mainThreadId points to a deleted thread — this is the crash condition
|
|
102
|
-
subscriberSawInconsistentState = true;
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// OLD CODE: _ensureThreadIsNotMain inside execute
|
|
107
|
-
// The optimistic callback deletes thread data BEFORE execute can update mainThreadId
|
|
108
|
-
const promise = state.optimisticUpdate({
|
|
109
|
-
execute: async () => {
|
|
110
|
-
// In old code, _ensureThreadIsNotMain was here.
|
|
111
|
-
// It would switch mainThreadId, but this runs AFTER optimistic callback
|
|
112
|
-
await Promise.resolve();
|
|
113
|
-
mainThreadId = "thread-2"; // too late — subscriber already fired
|
|
114
|
-
},
|
|
115
|
-
optimistic: (s) => {
|
|
116
|
-
return updateStatusReducer(s, "thread-1", "deleted");
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// The subscriber saw inconsistent state — mainThreadId points to deleted thread
|
|
121
|
-
expect(subscriberSawInconsistentState).toBe(true);
|
|
122
|
-
|
|
123
|
-
await promise;
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("FIX: switching mainThreadId before optimisticUpdate prevents inconsistency", async () => {
|
|
127
|
-
const state = new OptimisticState(createThreadState("thread-1"));
|
|
128
|
-
|
|
129
|
-
let mainThreadId = "thread-1";
|
|
130
|
-
let subscriberSawInconsistentState = false;
|
|
131
|
-
|
|
132
|
-
state.subscribe(() => {
|
|
133
|
-
const threadData = getThreadData(state.value, mainThreadId);
|
|
134
|
-
if (threadData === undefined) {
|
|
135
|
-
subscriberSawInconsistentState = true;
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// FIX: _ensureThreadIsNotMain runs BEFORE optimisticUpdate.
|
|
140
|
-
// switchToNewThread() both creates the new thread in state AND updates mainThreadId.
|
|
141
|
-
const newThreadId = "thread-2";
|
|
142
|
-
const mappingId = createThreadMappingId(newThreadId);
|
|
143
|
-
const currentState = state.value;
|
|
144
|
-
state.update({
|
|
145
|
-
...currentState,
|
|
146
|
-
newThreadId: newThreadId,
|
|
147
|
-
threadIdMap: {
|
|
148
|
-
...currentState.threadIdMap,
|
|
149
|
-
[newThreadId]: mappingId,
|
|
150
|
-
},
|
|
151
|
-
threadData: {
|
|
152
|
-
...currentState.threadData,
|
|
153
|
-
[mappingId]: {
|
|
154
|
-
status: "new" as const,
|
|
155
|
-
id: newThreadId,
|
|
156
|
-
remoteId: undefined,
|
|
157
|
-
externalId: undefined,
|
|
158
|
-
title: undefined,
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
mainThreadId = newThreadId;
|
|
163
|
-
|
|
164
|
-
// Reset flag — the state.update above triggered the subscriber
|
|
165
|
-
subscriberSawInconsistentState = false;
|
|
166
|
-
|
|
167
|
-
const promise = state.optimisticUpdate({
|
|
168
|
-
execute: async () => {
|
|
169
|
-
// _ensureThreadIsNotMain no longer here
|
|
170
|
-
return undefined;
|
|
171
|
-
},
|
|
172
|
-
optimistic: (s) => {
|
|
173
|
-
return updateStatusReducer(s, "thread-1", "deleted");
|
|
174
|
-
},
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// mainThreadId was already switched to thread-2 which exists in state
|
|
178
|
-
// — subscriber sees consistent state, no crash
|
|
179
|
-
expect(subscriberSawInconsistentState).toBe(false);
|
|
180
|
-
|
|
181
|
-
await promise;
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("archive does NOT remove threadData (no crash even without fix)", async () => {
|
|
185
|
-
const state = new OptimisticState(createThreadState("thread-1"));
|
|
186
|
-
|
|
187
|
-
let threadDataMissingDuringNotify = false;
|
|
188
|
-
|
|
189
|
-
state.subscribe(() => {
|
|
190
|
-
const threadData = getThreadData(state.value, "thread-1");
|
|
191
|
-
if (threadData === undefined) {
|
|
192
|
-
threadDataMissingDuringNotify = true;
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
await state.optimisticUpdate({
|
|
197
|
-
execute: async () => undefined,
|
|
198
|
-
optimistic: (s) => {
|
|
199
|
-
return updateStatusReducer(s, "thread-1", "archived");
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// Archive keeps threadData — no SKIP_UPDATE, no crash
|
|
204
|
-
expect(threadDataMissingDuringNotify).toBe(false);
|
|
205
|
-
expect(getThreadData(state.value, "thread-1")).toBeDefined();
|
|
206
|
-
expect(getThreadData(state.value, "thread-1")?.status).toBe("archived");
|
|
207
|
-
});
|
|
208
|
-
});
|