@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
|
@@ -35,6 +35,7 @@ const useLocalThreadRuntime = (
|
|
|
35
35
|
const [runtime] = useState(() => new LocalRuntimeCore(opt, initialMessages));
|
|
36
36
|
|
|
37
37
|
const threadIdRef = useRef<string | undefined>(undefined);
|
|
38
|
+
const historyLoadPromiseRef = useRef<Promise<void> | undefined>(undefined);
|
|
38
39
|
threadIdRef.current = useAuiState((s) => s.threadListItem.remoteId);
|
|
39
40
|
|
|
40
41
|
useEffect(() => {
|
|
@@ -51,9 +52,20 @@ const useLocalThreadRuntime = (
|
|
|
51
52
|
|
|
52
53
|
useEffect(() => {
|
|
53
54
|
runtime.threads.getMainThreadRuntimeCore().__internal_setOptions(opt);
|
|
54
|
-
runtime.threads.getMainThreadRuntimeCore().__internal_load();
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const loadPromise = runtime.threads
|
|
59
|
+
.getMainThreadRuntimeCore()
|
|
60
|
+
.__internal_load();
|
|
61
|
+
if (historyLoadPromiseRef.current === loadPromise) return;
|
|
62
|
+
|
|
63
|
+
historyLoadPromiseRef.current = loadPromise;
|
|
64
|
+
void loadPromise.catch((error: unknown) => {
|
|
65
|
+
console.error("[assistant-ui] local thread history load failed:", error);
|
|
66
|
+
});
|
|
67
|
+
}, [runtime]);
|
|
68
|
+
|
|
57
69
|
useEffect(() => {
|
|
58
70
|
if (!modelContext) return undefined;
|
|
59
71
|
return runtime.registerModelContextProvider(modelContext);
|
|
@@ -31,7 +31,10 @@ export class AssistantRuntimeImpl implements AssistantRuntime {
|
|
|
31
31
|
|
|
32
32
|
public readonly _thread: ThreadRuntime;
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
private readonly _core: AssistantRuntimeCore;
|
|
35
|
+
|
|
36
|
+
constructor(_core: AssistantRuntimeCore) {
|
|
37
|
+
this._core = _core;
|
|
35
38
|
this.threads = new ThreadListRuntimeImpl(_core.threads);
|
|
36
39
|
this._thread = this.threads.main;
|
|
37
40
|
|
|
@@ -49,7 +49,10 @@ export abstract class AttachmentRuntimeImpl<
|
|
|
49
49
|
|
|
50
50
|
public abstract get source(): Source;
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
private _core: AttachmentSnapshotBinding<Source>;
|
|
53
|
+
|
|
54
|
+
constructor(_core: AttachmentSnapshotBinding<Source>) {
|
|
55
|
+
this._core = _core;
|
|
53
56
|
this.__internal_bindMethods();
|
|
54
57
|
}
|
|
55
58
|
|
|
@@ -73,11 +76,14 @@ export abstract class AttachmentRuntimeImpl<
|
|
|
73
76
|
abstract class ComposerAttachmentRuntime<
|
|
74
77
|
Source extends "thread-composer" | "edit-composer",
|
|
75
78
|
> extends AttachmentRuntimeImpl<Source> {
|
|
79
|
+
private _composerApi: ComposerRuntimeCoreBinding;
|
|
80
|
+
|
|
76
81
|
constructor(
|
|
77
82
|
core: AttachmentSnapshotBinding<Source>,
|
|
78
|
-
|
|
83
|
+
_composerApi: ComposerRuntimeCoreBinding,
|
|
79
84
|
) {
|
|
80
85
|
super(core);
|
|
86
|
+
this._composerApi = _composerApi;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
89
|
public remove() {
|
|
@@ -251,7 +251,11 @@ export abstract class ComposerRuntimeImpl implements ComposerRuntime {
|
|
|
251
251
|
|
|
252
252
|
public abstract get type(): "edit" | "thread";
|
|
253
253
|
|
|
254
|
-
|
|
254
|
+
protected _core: ComposerRuntimeCoreBinding;
|
|
255
|
+
|
|
256
|
+
constructor(_core: ComposerRuntimeCoreBinding) {
|
|
257
|
+
this._core = _core;
|
|
258
|
+
}
|
|
255
259
|
|
|
256
260
|
protected __internal_bindMethods() {
|
|
257
261
|
this.setText = this.setText.bind(this);
|
|
@@ -483,10 +487,9 @@ export class EditComposerRuntimeImpl
|
|
|
483
487
|
}
|
|
484
488
|
|
|
485
489
|
private _getState;
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
) {
|
|
490
|
+
private _beginEdit: () => void;
|
|
491
|
+
|
|
492
|
+
constructor(core: EditComposerRuntimeCoreBinding, _beginEdit: () => void) {
|
|
490
493
|
const stateBinding = new LazyMemoizeSubject({
|
|
491
494
|
path: core.path,
|
|
492
495
|
getState: () => getEditComposerState(core.getState()),
|
|
@@ -498,6 +501,7 @@ export class EditComposerRuntimeImpl
|
|
|
498
501
|
getState: () => core.getState(),
|
|
499
502
|
subscribe: (callback) => stateBinding.subscribe(callback),
|
|
500
503
|
});
|
|
504
|
+
this._beginEdit = _beginEdit;
|
|
501
505
|
|
|
502
506
|
this._getState = stateBinding.getState.bind(stateBinding);
|
|
503
507
|
|
|
@@ -40,11 +40,18 @@ export class MessagePartRuntimeImpl implements MessagePartRuntime {
|
|
|
40
40
|
return this.contentBinding.path;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
private contentBinding: MessagePartSnapshotBinding;
|
|
44
|
+
private messageApi: MessageStateBinding | undefined;
|
|
45
|
+
private threadApi: ThreadRuntimeCoreBinding | undefined;
|
|
46
|
+
|
|
43
47
|
constructor(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
contentBinding: MessagePartSnapshotBinding,
|
|
49
|
+
messageApi?: MessageStateBinding,
|
|
50
|
+
threadApi?: ThreadRuntimeCoreBinding,
|
|
47
51
|
) {
|
|
52
|
+
this.contentBinding = contentBinding;
|
|
53
|
+
this.messageApi = messageApi;
|
|
54
|
+
this.threadApi = threadApi;
|
|
48
55
|
this.__internal_bindMethods();
|
|
49
56
|
}
|
|
50
57
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import type { CompleteAttachment } from "../../types/attachment";
|
|
3
|
+
import type { ThreadRuntimeCoreBinding } from "./thread-runtime";
|
|
4
|
+
import {
|
|
5
|
+
MessageRuntimeImpl,
|
|
6
|
+
type MessageState,
|
|
7
|
+
type MessageStateBinding,
|
|
8
|
+
} from "./message-runtime";
|
|
9
|
+
|
|
10
|
+
const messagePath = {
|
|
11
|
+
ref: "threads.main.messages[0]",
|
|
12
|
+
threadSelector: { type: "main" as const },
|
|
13
|
+
messageSelector: { type: "index" as const, index: 0 },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const attachment: CompleteAttachment = {
|
|
17
|
+
id: "attachment-1",
|
|
18
|
+
type: "file",
|
|
19
|
+
name: "notes.txt",
|
|
20
|
+
contentType: "text/plain",
|
|
21
|
+
content: [{ type: "text", text: "notes" }],
|
|
22
|
+
status: { type: "complete" },
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const message: MessageState = {
|
|
26
|
+
id: "message-1",
|
|
27
|
+
role: "assistant",
|
|
28
|
+
createdAt: new Date(0),
|
|
29
|
+
content: [
|
|
30
|
+
{ type: "text", text: "Hello" },
|
|
31
|
+
{
|
|
32
|
+
type: "tool-call",
|
|
33
|
+
toolCallId: "call-1",
|
|
34
|
+
toolName: "weather",
|
|
35
|
+
args: {},
|
|
36
|
+
argsText: "{}",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
attachments: [attachment],
|
|
40
|
+
status: { type: "complete", reason: "stop" },
|
|
41
|
+
metadata: {
|
|
42
|
+
unstable_state: null,
|
|
43
|
+
unstable_annotations: [],
|
|
44
|
+
unstable_data: [],
|
|
45
|
+
steps: [],
|
|
46
|
+
custom: {},
|
|
47
|
+
},
|
|
48
|
+
parentId: null,
|
|
49
|
+
index: 0,
|
|
50
|
+
isLast: true,
|
|
51
|
+
branchNumber: 1,
|
|
52
|
+
branchCount: 1,
|
|
53
|
+
speech: undefined,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const messageBinding: MessageStateBinding = {
|
|
57
|
+
path: messagePath,
|
|
58
|
+
getState: () => message,
|
|
59
|
+
subscribe: () => () => {},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const threadBinding = {
|
|
63
|
+
subscribe: () => () => {},
|
|
64
|
+
} as unknown as ThreadRuntimeCoreBinding;
|
|
65
|
+
|
|
66
|
+
describe("MessageRuntimeImpl paths", () => {
|
|
67
|
+
it("appends nested selectors to the message path", () => {
|
|
68
|
+
const runtime = new MessageRuntimeImpl(messageBinding, threadBinding);
|
|
69
|
+
|
|
70
|
+
expect(runtime.composer.path.ref).toBe("threads.main.messages[0].composer");
|
|
71
|
+
expect(runtime.getMessagePartByIndex(0).path.ref).toBe(
|
|
72
|
+
"threads.main.messages[0].content[0]",
|
|
73
|
+
);
|
|
74
|
+
expect(runtime.getMessagePartByToolCallId("call-1").path.ref).toBe(
|
|
75
|
+
'threads.main.messages[0].content[toolCallId="call-1"]',
|
|
76
|
+
);
|
|
77
|
+
expect(runtime.getAttachmentByIndex(0).path.ref).toBe(
|
|
78
|
+
"threads.main.messages[0].attachments[0]",
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -134,15 +134,20 @@ export class MessageRuntimeImpl implements MessageRuntime {
|
|
|
134
134
|
return this._core.path;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
private _core: MessageStateBinding;
|
|
138
|
+
private _threadBinding: ThreadRuntimeCoreBinding;
|
|
139
|
+
|
|
137
140
|
constructor(
|
|
138
|
-
|
|
139
|
-
|
|
141
|
+
_core: MessageStateBinding,
|
|
142
|
+
_threadBinding: ThreadRuntimeCoreBinding,
|
|
140
143
|
) {
|
|
144
|
+
this._core = _core;
|
|
145
|
+
this._threadBinding = _threadBinding;
|
|
141
146
|
this.composer = new EditComposerRuntimeImpl(
|
|
142
147
|
new NestedSubscriptionSubject({
|
|
143
148
|
path: {
|
|
144
149
|
...this.path,
|
|
145
|
-
ref: `${this.path.ref}
|
|
150
|
+
ref: `${this.path.ref}.composer`,
|
|
146
151
|
composerSource: "edit",
|
|
147
152
|
},
|
|
148
153
|
getState: this._getEditComposerRuntimeCore,
|
|
@@ -269,7 +274,7 @@ export class MessageRuntimeImpl implements MessageRuntime {
|
|
|
269
274
|
new ShallowMemoizeSubject({
|
|
270
275
|
path: {
|
|
271
276
|
...this.path,
|
|
272
|
-
ref: `${this.path.ref}
|
|
277
|
+
ref: `${this.path.ref}.content[${idx}]`,
|
|
273
278
|
messagePartSelector: { type: "index", index: idx },
|
|
274
279
|
},
|
|
275
280
|
getState: () => {
|
|
@@ -287,9 +292,7 @@ export class MessageRuntimeImpl implements MessageRuntime {
|
|
|
287
292
|
new ShallowMemoizeSubject({
|
|
288
293
|
path: {
|
|
289
294
|
...this.path,
|
|
290
|
-
ref:
|
|
291
|
-
this.path.ref +
|
|
292
|
-
`${this.path.ref}.content[toolCallId=${JSON.stringify(toolCallId)}]`,
|
|
295
|
+
ref: `${this.path.ref}.content[toolCallId=${JSON.stringify(toolCallId)}]`,
|
|
293
296
|
messagePartSelector: { type: "toolCallId", toolCallId },
|
|
294
297
|
},
|
|
295
298
|
getState: () => {
|
|
@@ -313,7 +316,7 @@ export class MessageRuntimeImpl implements MessageRuntime {
|
|
|
313
316
|
new ShallowMemoizeSubject({
|
|
314
317
|
path: {
|
|
315
318
|
...this.path,
|
|
316
|
-
ref: `${this.path.ref}
|
|
319
|
+
ref: `${this.path.ref}.attachments[${idx}]`,
|
|
317
320
|
attachmentSource: "message",
|
|
318
321
|
attachmentSelector: { type: "index", index: idx },
|
|
319
322
|
},
|
|
@@ -2,6 +2,7 @@ import type { Unsubscribe } from "../../types/unsubscribe";
|
|
|
2
2
|
import type { SubscribableWithState } from "../../subscribable/subscribable";
|
|
3
3
|
import type { ThreadListItemRuntimePath } from "./paths";
|
|
4
4
|
import type { ThreadListRuntimeCoreBinding } from "./thread-list-runtime";
|
|
5
|
+
import { notifyEventListeners } from "../../utils/notify-event-listeners";
|
|
5
6
|
|
|
6
7
|
export type ThreadListItemEventPayload = {
|
|
7
8
|
/**
|
|
@@ -65,10 +66,15 @@ export class ThreadListItemRuntimeImpl implements ThreadListItemRuntime {
|
|
|
65
66
|
return this._core.path;
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
private _core: ThreadListItemStateBinding;
|
|
70
|
+
private _threadListBinding: ThreadListRuntimeCoreBinding;
|
|
71
|
+
|
|
68
72
|
constructor(
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
_core: ThreadListItemStateBinding,
|
|
74
|
+
_threadListBinding: ThreadListRuntimeCoreBinding,
|
|
71
75
|
) {
|
|
76
|
+
this._core = _core;
|
|
77
|
+
this._threadListBinding = _threadListBinding;
|
|
72
78
|
this.__internal_bindMethods();
|
|
73
79
|
}
|
|
74
80
|
|
|
@@ -162,7 +168,11 @@ export class ThreadListItemRuntimeImpl implements ThreadListItemRuntime {
|
|
|
162
168
|
|
|
163
169
|
if (event === "switchedTo" && !newIsMain) return;
|
|
164
170
|
if (event === "switchedAway" && newIsMain) return;
|
|
165
|
-
(
|
|
171
|
+
notifyEventListeners(
|
|
172
|
+
[callback as (payload?: unknown) => void],
|
|
173
|
+
{},
|
|
174
|
+
`Thread list item "${event}"`,
|
|
175
|
+
);
|
|
166
176
|
});
|
|
167
177
|
}
|
|
168
178
|
|
|
@@ -98,13 +98,21 @@ export type ThreadListRuntimeCoreBinding = ThreadListRuntimeCore;
|
|
|
98
98
|
|
|
99
99
|
export class ThreadListRuntimeImpl implements ThreadListRuntime {
|
|
100
100
|
private _getState;
|
|
101
|
+
private _core: ThreadListRuntimeCoreBinding;
|
|
102
|
+
private _runtimeFactory: new (
|
|
103
|
+
binding: ThreadRuntimeCoreBinding,
|
|
104
|
+
threadListItemBinding: ThreadListItemRuntimeBinding,
|
|
105
|
+
) => ThreadRuntime;
|
|
106
|
+
|
|
101
107
|
constructor(
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
_core: ThreadListRuntimeCoreBinding,
|
|
109
|
+
_runtimeFactory: new (
|
|
104
110
|
binding: ThreadRuntimeCoreBinding,
|
|
105
111
|
threadListItemBinding: ThreadListItemRuntimeBinding,
|
|
106
112
|
) => ThreadRuntime = ThreadRuntimeImpl,
|
|
107
113
|
) {
|
|
114
|
+
this._core = _core;
|
|
115
|
+
this._runtimeFactory = _runtimeFactory;
|
|
108
116
|
const stateBinding = new LazyMemoizeSubject({
|
|
109
117
|
path: {},
|
|
110
118
|
getState: () => getThreadListState(_core),
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
isCreateAttachment,
|
|
3
|
+
type Attachment,
|
|
4
|
+
type CompleteAttachment,
|
|
5
|
+
type CreateAttachment,
|
|
6
|
+
type PendingAttachment,
|
|
6
7
|
} from "../../types/attachment";
|
|
7
8
|
import type { MessageRole, AppendMessage } from "../../types/message";
|
|
8
9
|
import type { QuoteInfo } from "../../types/quote";
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
type QueueItemState,
|
|
29
30
|
} from "../../store/scopes/queue-item";
|
|
30
31
|
import { generateId } from "../../utils/id";
|
|
32
|
+
import { notifyEventListeners } from "../../utils/notify-event-listeners";
|
|
31
33
|
|
|
32
34
|
const isAttachmentComplete = (a: Attachment): a is CompleteAttachment =>
|
|
33
35
|
a.status.type === "complete";
|
|
@@ -133,6 +135,10 @@ export abstract class BaseComposerRuntimeCore
|
|
|
133
135
|
this._notifySubscribers();
|
|
134
136
|
}
|
|
135
137
|
|
|
138
|
+
protected _isSending = false;
|
|
139
|
+
private _removedDuringSend = new Set<string>();
|
|
140
|
+
private _sendGeneration = 0;
|
|
141
|
+
|
|
136
142
|
private _emptyTextAndAttachments() {
|
|
137
143
|
this._attachments = [];
|
|
138
144
|
this._text = "";
|
|
@@ -148,6 +154,14 @@ export abstract class BaseComposerRuntimeCore
|
|
|
148
154
|
}
|
|
149
155
|
|
|
150
156
|
public async reset() {
|
|
157
|
+
// A send whose adapter never settles must not brick the composer; reset is
|
|
158
|
+
// the escape hatch that releases the in-flight lock. Bumping the generation
|
|
159
|
+
// invalidates that send entirely so a late-settling upload can neither
|
|
160
|
+
// append the discarded draft nor touch a newer send's lock.
|
|
161
|
+
this._sendGeneration++;
|
|
162
|
+
this._isSending = false;
|
|
163
|
+
this._removedDuringSend.clear();
|
|
164
|
+
|
|
151
165
|
if (
|
|
152
166
|
this._attachments.length === 0 &&
|
|
153
167
|
this._text === "" &&
|
|
@@ -175,7 +189,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
175
189
|
}
|
|
176
190
|
|
|
177
191
|
public async send(options?: SendOptions) {
|
|
178
|
-
if (!this.canSend) return;
|
|
192
|
+
if (!this.canSend || this._isSending) return;
|
|
179
193
|
|
|
180
194
|
if (this._dictationSession) {
|
|
181
195
|
this._dictationSession.cancel();
|
|
@@ -183,47 +197,75 @@ export abstract class BaseComposerRuntimeCore
|
|
|
183
197
|
}
|
|
184
198
|
|
|
185
199
|
const adapter = this.getAttachmentAdapter();
|
|
186
|
-
const attachments
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const result = await adapter.send(a);
|
|
193
|
-
return result as CompleteAttachment;
|
|
194
|
-
}),
|
|
195
|
-
)
|
|
196
|
-
: [];
|
|
200
|
+
const attachmentTasks = this.attachments.map(async (a) => {
|
|
201
|
+
if (isAttachmentComplete(a)) return a;
|
|
202
|
+
if (!adapter) throw new Error("Attachments are not supported");
|
|
203
|
+
const result = await adapter.send(a);
|
|
204
|
+
return result as CompleteAttachment;
|
|
205
|
+
});
|
|
197
206
|
|
|
198
207
|
const originalAttachments = this.attachments;
|
|
199
208
|
const text = this.text;
|
|
200
209
|
const quote = this._quote;
|
|
201
210
|
this._quote = undefined;
|
|
202
|
-
this.
|
|
211
|
+
this._text = "";
|
|
212
|
+
this._isSending = true;
|
|
213
|
+
const generation = ++this._sendGeneration;
|
|
214
|
+
this._notifySubscribers();
|
|
203
215
|
|
|
204
|
-
let resolvedAttachments:
|
|
216
|
+
let resolvedAttachments: CompleteAttachment[];
|
|
205
217
|
try {
|
|
206
|
-
resolvedAttachments = await
|
|
218
|
+
resolvedAttachments = await Promise.all(attachmentTasks);
|
|
207
219
|
} catch (e) {
|
|
208
|
-
if (
|
|
209
|
-
this.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
220
|
+
if (generation === this._sendGeneration) {
|
|
221
|
+
if (!this.text.trim() && this._quote === undefined) {
|
|
222
|
+
this._text = text;
|
|
223
|
+
this._quote = quote;
|
|
224
|
+
this._notifySubscribers();
|
|
225
|
+
}
|
|
226
|
+
// Promise.all rejects on the first failure, but sibling uploads from
|
|
227
|
+
// this batch keep running; the send rejects immediately while the
|
|
228
|
+
// retry lock is held until they settle, or a retry could re-send
|
|
229
|
+
// attachments that are still in flight.
|
|
230
|
+
void Promise.allSettled(attachmentTasks).then(() => {
|
|
231
|
+
if (generation !== this._sendGeneration) return;
|
|
232
|
+
this._removedDuringSend.clear();
|
|
233
|
+
this._isSending = false;
|
|
234
|
+
this._notifySubscribers();
|
|
235
|
+
});
|
|
213
236
|
}
|
|
214
237
|
throw e;
|
|
215
238
|
}
|
|
216
239
|
|
|
240
|
+
// A reset during the upload discarded this send's draft; the settled
|
|
241
|
+
// uploads must not append it or touch the lock a newer send may own.
|
|
242
|
+
if (generation !== this._sendGeneration) return;
|
|
243
|
+
|
|
244
|
+
// Drop by id, not wholesale: the user may have added or removed chips while
|
|
245
|
+
// the upload was in flight.
|
|
246
|
+
const sentIds = new Set(originalAttachments.map((a) => a.id));
|
|
247
|
+
this._attachments = this._attachments.filter((a) => !sentIds.has(a.id));
|
|
248
|
+
this._isSending = false;
|
|
249
|
+
this._notifySubscribers();
|
|
250
|
+
|
|
251
|
+
// An attachment removed mid-upload can't be cancelled, but it can still be
|
|
252
|
+
// dropped from the outgoing message instead of silently being sent anyway.
|
|
253
|
+
const finalAttachments = resolvedAttachments.filter(
|
|
254
|
+
(a) => !this._removedDuringSend.has(a.id),
|
|
255
|
+
);
|
|
256
|
+
this._removedDuringSend.clear();
|
|
257
|
+
|
|
217
258
|
const message: Omit<AppendMessage, "parentId" | "sourceId"> = {
|
|
218
259
|
createdAt: new Date(),
|
|
219
260
|
role: this.role,
|
|
220
261
|
content: text ? [{ type: "text", text }] : [],
|
|
221
|
-
attachments:
|
|
262
|
+
attachments: finalAttachments,
|
|
222
263
|
runConfig: this.runConfig,
|
|
223
264
|
metadata: { custom: { ...(quote ? { quote } : {}) } },
|
|
224
265
|
};
|
|
225
266
|
|
|
226
|
-
this.handleSend(message, options);
|
|
267
|
+
const sendTask = this.handleSend(message, options);
|
|
268
|
+
if (sendTask) void sendTask.catch(() => {});
|
|
227
269
|
this._notifyEventSubscribers("send", {});
|
|
228
270
|
}
|
|
229
271
|
|
|
@@ -241,11 +283,11 @@ export abstract class BaseComposerRuntimeCore
|
|
|
241
283
|
protected abstract handleSend(
|
|
242
284
|
message: Omit<AppendMessage, "parentId" | "sourceId">,
|
|
243
285
|
options?: SendOptions,
|
|
244
|
-
): void
|
|
286
|
+
): void | Promise<void>;
|
|
245
287
|
protected abstract handleCancel(): void;
|
|
246
288
|
|
|
247
289
|
async addAttachment(fileOrAttachment: File | CreateAttachment) {
|
|
248
|
-
if (
|
|
290
|
+
if (isCreateAttachment(fileOrAttachment)) {
|
|
249
291
|
const adapter = this.getAttachmentAdapter();
|
|
250
292
|
if (
|
|
251
293
|
adapter &&
|
|
@@ -392,12 +434,16 @@ export abstract class BaseComposerRuntimeCore
|
|
|
392
434
|
if (index === -1) throw new Error("Attachment not found");
|
|
393
435
|
const attachment = this._attachments[index]!;
|
|
394
436
|
|
|
437
|
+
// A send in flight may already be uploading this attachment; the upload
|
|
438
|
+
// can't be cancelled, so mark it to be dropped from the outgoing message
|
|
439
|
+
// before any await gives the upload a chance to settle first.
|
|
440
|
+
if (this._isSending) this._removedDuringSend.add(attachmentId);
|
|
441
|
+
|
|
395
442
|
if (!isAttachmentComplete(attachment)) {
|
|
396
443
|
const adapter = this.getAttachmentAdapter();
|
|
397
444
|
if (!adapter) throw new Error("Attachments are not supported");
|
|
398
445
|
await adapter.remove(attachment);
|
|
399
446
|
}
|
|
400
|
-
|
|
401
447
|
this._attachments = this._attachments.filter((a) => a.id !== attachmentId);
|
|
402
448
|
this._notifySubscribers();
|
|
403
449
|
}
|
|
@@ -563,7 +609,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
563
609
|
const subscribers = this._eventSubscribers.get(event);
|
|
564
610
|
if (!subscribers) return;
|
|
565
611
|
|
|
566
|
-
|
|
612
|
+
notifyEventListeners(subscribers, payload, `Composer runtime "${event}"`);
|
|
567
613
|
}
|
|
568
614
|
|
|
569
615
|
public unstable_on<E extends ComposerRuntimeEventType>(
|
|
@@ -34,6 +34,7 @@ import type { FeedbackAdapter } from "../../adapters/feedback";
|
|
|
34
34
|
import type { AttachmentAdapter } from "../../adapters/attachment";
|
|
35
35
|
import type { RealtimeVoiceAdapter } from "../../adapters/voice";
|
|
36
36
|
import type { ThreadMessageLike } from "../utils/thread-message-like";
|
|
37
|
+
import { notifyEventListeners } from "../../utils/notify-event-listeners";
|
|
37
38
|
|
|
38
39
|
type BaseThreadAdapters = {
|
|
39
40
|
speech?: SpeechSynthesisAdapter | undefined;
|
|
@@ -112,7 +113,11 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
|
|
|
112
113
|
|
|
113
114
|
public readonly composer = new DefaultThreadComposerRuntimeCore(this);
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
private readonly _contextProvider: ModelContextProvider;
|
|
117
|
+
|
|
118
|
+
constructor(_contextProvider: ModelContextProvider) {
|
|
119
|
+
this._contextProvider = _contextProvider;
|
|
120
|
+
}
|
|
116
121
|
|
|
117
122
|
public getModelContext() {
|
|
118
123
|
return this._contextProvider.getModelContext();
|
|
@@ -182,7 +187,7 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
|
|
|
182
187
|
const subscribers = this._eventSubscribers.get(event);
|
|
183
188
|
if (!subscribers) return;
|
|
184
189
|
|
|
185
|
-
|
|
190
|
+
notifyEventListeners(subscribers, payload, `Thread runtime "${event}"`);
|
|
186
191
|
}
|
|
187
192
|
|
|
188
193
|
public subscribe(callback: () => void): Unsubscribe {
|
|
@@ -15,7 +15,7 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
public get canSend() {
|
|
18
|
-
return !this.isEmpty;
|
|
18
|
+
return !this.isEmpty && !this._isSending;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
protected getAttachmentAdapter() {
|
|
@@ -31,8 +31,18 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
31
31
|
private _nonTextPassthrough: readonly ThreadMessage["content"][number][];
|
|
32
32
|
private _parentId: string | null;
|
|
33
33
|
private _sourceId: string | null;
|
|
34
|
+
private runtime: ThreadRuntimeCore & {
|
|
35
|
+
adapters?:
|
|
36
|
+
| {
|
|
37
|
+
attachments?: AttachmentAdapter | undefined;
|
|
38
|
+
dictation?: DictationAdapter | undefined;
|
|
39
|
+
}
|
|
40
|
+
| undefined;
|
|
41
|
+
};
|
|
42
|
+
private endEditCallback: () => void;
|
|
43
|
+
|
|
34
44
|
constructor(
|
|
35
|
-
|
|
45
|
+
runtime: ThreadRuntimeCore & {
|
|
36
46
|
adapters?:
|
|
37
47
|
| {
|
|
38
48
|
attachments?: AttachmentAdapter | undefined;
|
|
@@ -40,10 +50,12 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
40
50
|
}
|
|
41
51
|
| undefined;
|
|
42
52
|
},
|
|
43
|
-
|
|
53
|
+
endEditCallback: () => void,
|
|
44
54
|
{ parentId, message }: { parentId: string | null; message: ThreadMessage },
|
|
45
55
|
) {
|
|
46
56
|
super();
|
|
57
|
+
this.runtime = runtime;
|
|
58
|
+
this.endEditCallback = endEditCallback;
|
|
47
59
|
this._parentId = parentId;
|
|
48
60
|
this._sourceId = message.id;
|
|
49
61
|
this._previousText = getThreadMessageText(message);
|
|
@@ -80,6 +92,7 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
80
92
|
message: Omit<AppendMessage, "parentId" | "sourceId">,
|
|
81
93
|
options?: SendOptions,
|
|
82
94
|
) {
|
|
95
|
+
let appendTask: void | Promise<void> = undefined;
|
|
83
96
|
const text = getThreadMessageText(message as AppendMessage);
|
|
84
97
|
const attachmentsChanged = !attachmentsEqual(
|
|
85
98
|
message.attachments ?? [],
|
|
@@ -114,7 +127,7 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
114
127
|
message,
|
|
115
128
|
composerMetadata,
|
|
116
129
|
);
|
|
117
|
-
this.runtime.append({
|
|
130
|
+
appendTask = this.runtime.append({
|
|
118
131
|
...enriched,
|
|
119
132
|
content,
|
|
120
133
|
parentId: this._parentId,
|
|
@@ -124,6 +137,7 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
124
137
|
}
|
|
125
138
|
|
|
126
139
|
this.handleCancel();
|
|
140
|
+
return appendTask;
|
|
127
141
|
}
|
|
128
142
|
|
|
129
143
|
public handleCancel() {
|
|
@@ -23,7 +23,7 @@ export class DefaultThreadComposerRuntimeCore
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
public get canSend() {
|
|
26
|
-
return !this.isEmpty && !this.runtime.isSendDisabled;
|
|
26
|
+
return !this.isEmpty && !this.runtime.isSendDisabled && !this._isSending;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
public override get queue(): readonly QueueItemState[] {
|
|
@@ -46,8 +46,17 @@ export class DefaultThreadComposerRuntimeCore
|
|
|
46
46
|
return this.runtime.adapters?.dictation;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
private runtime: Omit<ThreadRuntimeCore, "composer"> & {
|
|
50
|
+
adapters?:
|
|
51
|
+
| {
|
|
52
|
+
attachments?: AttachmentAdapter | undefined;
|
|
53
|
+
dictation?: DictationAdapter | undefined;
|
|
54
|
+
}
|
|
55
|
+
| undefined;
|
|
56
|
+
};
|
|
57
|
+
|
|
49
58
|
constructor(
|
|
50
|
-
|
|
59
|
+
runtime: Omit<ThreadRuntimeCore, "composer"> & {
|
|
51
60
|
adapters?:
|
|
52
61
|
| {
|
|
53
62
|
attachments?: AttachmentAdapter | undefined;
|
|
@@ -57,6 +66,7 @@ export class DefaultThreadComposerRuntimeCore
|
|
|
57
66
|
},
|
|
58
67
|
) {
|
|
59
68
|
super();
|
|
69
|
+
this.runtime = runtime;
|
|
60
70
|
this.connect();
|
|
61
71
|
}
|
|
62
72
|
|
|
@@ -94,7 +104,7 @@ export class DefaultThreadComposerRuntimeCore
|
|
|
94
104
|
);
|
|
95
105
|
const enriched = this.enrichWithComposerMetadata(message, composerMetadata);
|
|
96
106
|
|
|
97
|
-
this.runtime.append({
|
|
107
|
+
return this.runtime.append({
|
|
98
108
|
...(enriched as AppendMessage),
|
|
99
109
|
parentId: this.runtime.messages.at(-1)?.id ?? null,
|
|
100
110
|
sourceId: null,
|