@assistant-ui/core 0.3.13 → 0.3.14
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/speech.d.ts.map +1 -1
- package/dist/adapters/speech.js +9 -15
- package/dist/adapters/speech.js.map +1 -1
- package/dist/adapters/thread-history.d.ts +2 -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 +27 -15
- package/dist/adapters/voice.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +6 -6
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +2 -1
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/registry.js +16 -4
- package/dist/model-context/registry.js.map +1 -1
- package/dist/react/RuntimeAdapter.d.ts +8 -1
- package/dist/react/RuntimeAdapter.d.ts.map +1 -1
- package/dist/react/RuntimeAdapter.js +23 -18
- package/dist/react/RuntimeAdapter.js.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
- package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
- package/dist/react/client/AdaptedRemoteThread.js +27 -0
- package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
- package/dist/react/client/InMemoryThreadList.d.ts +19 -0
- package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
- package/dist/react/client/InMemoryThreadList.js +418 -0
- package/dist/react/client/InMemoryThreadList.js.map +1 -0
- package/dist/react/client/Interactables.d.ts.map +1 -1
- package/dist/react/client/Interactables.js +159 -102
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +34 -0
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
- package/dist/react/client/RemoteThreadList.js +826 -0
- package/dist/react/client/RemoteThreadList.js.map +1 -0
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +38 -27
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/index.d.ts +7 -2
- package/dist/react/index.js +5 -2
- package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
- package/dist/react/interactables-legacy/Interactables.js +145 -110
- package/dist/react/interactables-legacy/Interactables.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarCopy.js +13 -18
- package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
- package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
- package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
- package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
- package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
- package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerSend.js +2 -4
- package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
- package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
- package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.d.ts +13 -0
- package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +22 -10
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +109 -71
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +8 -2
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +40 -13
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
- package/dist/react/runtimes/RemoteThreadResource.js +134 -0
- package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
- package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
- package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
- package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
- package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
- package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
- package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
- package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
- package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
- package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/types.js +0 -0
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
- package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
- package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
- package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
- package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +7 -0
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +22 -12
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
- package/dist/react/runtimes/external-message-converter.js +14 -14
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
- package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.js +1 -1
- package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
- package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
- package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
- package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
- package/dist/runtime/api/composer-runtime.d.ts +5 -0
- package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.js.map +1 -1
- package/dist/runtime/api/message-runtime.js +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +4 -2
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +12 -2
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +8 -2
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +8 -7
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +1 -0
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +3 -3
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -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 +10 -4
- package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/internal.js +5 -5
- package/dist/runtime/queue/message-queue.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.js +2 -1
- package/dist/runtime/queue/message-queue.js.map +1 -1
- package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
- package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
- package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
- package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
- package/dist/runtimes/external-store/external-store-shared-options.js.map +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 +4 -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 +8 -0
- 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 +35 -13
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/internal.d.ts +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 +53 -13
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +1 -0
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +3 -0
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
- package/dist/runtimes/remote-thread-list/empty-thread-core.js +3 -0
- package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +29 -1
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/suggestions.js +2 -2
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/clients/thread-selection-events.d.ts +10 -0
- package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
- package/dist/store/clients/thread-selection-events.js +40 -0
- package/dist/store/clients/thread-selection-events.js.map +1 -0
- package/dist/store/env.d.ts +5 -0
- package/dist/store/env.d.ts.map +1 -0
- package/dist/store/env.js +12 -0
- package/dist/store/env.js.map +1 -0
- package/dist/store/index.d.ts +5 -3
- package/dist/store/index.js +4 -2
- package/dist/store/internal.d.ts +4 -1
- package/dist/store/internal.js +4 -1
- package/dist/store/primitive-predicates.d.ts +19 -0
- package/dist/store/primitive-predicates.d.ts.map +1 -0
- package/dist/store/primitive-predicates.js +19 -0
- package/dist/store/primitive-predicates.js.map +1 -0
- package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
- package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
- package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
- package/dist/store/runtime-clients/handle-runtime-action.js +12 -0
- package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
- package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
- package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
- package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
- package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +62 -29
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js.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 +5 -6
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/scopes/composer.d.ts +9 -4
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +7 -6
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/dist/store/scopes/thread.d.ts +8 -7
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/store/scopes/threads.d.ts +17 -1
- package/dist/store/scopes/threads.d.ts.map +1 -1
- package/dist/subscribable/subscribable.d.ts +2 -1
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +23 -18
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/utils/composite-context-provider.d.ts +1 -0
- package/dist/utils/composite-context-provider.d.ts.map +1 -1
- package/dist/utils/composite-context-provider.js +25 -9
- package/dist/utils/composite-context-provider.js.map +1 -1
- package/dist/utils/notify-event-listeners.d.ts +2 -2
- package/dist/utils/notify-event-listeners.d.ts.map +1 -1
- package/dist/utils/notify-event-listeners.js +2 -2
- package/dist/utils/notify-event-listeners.js.map +1 -1
- package/package.json +7 -7
- package/src/adapters/speech.test.ts +118 -1
- package/src/adapters/speech.ts +21 -22
- package/src/adapters/thread-history.ts +2 -0
- package/src/adapters/voice.test.ts +69 -0
- package/src/adapters/voice.ts +27 -27
- package/src/index.ts +1 -0
- package/src/model-context/frame/host.test.ts +23 -0
- package/src/model-context/frame/host.ts +2 -1
- package/src/model-context/registry.test.ts +131 -0
- package/src/model-context/registry.ts +16 -6
- package/src/react/RuntimeAdapter.test.ts +2 -0
- package/src/react/RuntimeAdapter.ts +20 -8
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
- package/src/react/client/AdaptedRemoteThread.ts +41 -0
- package/src/react/client/InMemoryThreadList.test.tsx +148 -0
- package/src/react/client/InMemoryThreadList.ts +290 -0
- package/src/react/client/Interactables.test.ts +326 -2
- package/src/react/client/Interactables.ts +227 -110
- package/src/react/client/RemoteThreadList.test.ts +1026 -0
- package/src/react/client/RemoteThreadList.ts +1067 -0
- package/src/react/client/Tools.ts +36 -29
- package/src/react/index.ts +13 -0
- package/src/react/interactables-legacy/Interactables.test.ts +317 -0
- package/src/react/interactables-legacy/Interactables.ts +204 -128
- package/src/react/primitive-hooks/useActionBarCopy.ts +2 -7
- package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
- package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
- package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
- package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
- package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
- package/src/react/primitive-hooks/useComposerSend.ts +2 -5
- package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
- package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
- package/src/react/primitives/message/MessageParts.tsx +0 -1
- package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +159 -124
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +59 -20
- package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
- package/src/react/runtimes/RemoteThreadResource.ts +231 -0
- package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
- package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
- package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
- package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
- package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
- package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
- package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
- package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
- package/src/react/runtimes/assistant-transport/types.ts +170 -0
- package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
- package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +625 -0
- package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +481 -0
- package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
- package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
- package/src/react/runtimes/cloud/auiV0.ts +17 -1
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +36 -21
- package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
- package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
- package/src/react/runtimes/external-message-converter.test.ts +143 -0
- package/src/react/runtimes/external-message-converter.ts +41 -41
- package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
- package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
- package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +13 -3
- package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
- package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
- package/src/react/runtimes/useLocalRuntime.test.tsx +130 -4
- package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
- package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
- package/src/runtime/api/composer-runtime.ts +5 -0
- package/src/runtime/api/thread-list-runtime.ts +3 -1
- package/src/runtime/api/thread-runtime.ts +20 -2
- package/src/runtime/base/base-composer-runtime-core.ts +6 -5
- package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
- package/src/runtime/base/base-thread-runtime-core.ts +11 -2
- package/src/runtime/base/default-thread-composer-runtime-core.ts +12 -4
- package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
- package/src/runtime/queue/message-queue.ts +2 -1
- package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
- package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
- 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 +99 -34
- package/src/runtimes/local/local-thread-runtime-core.test.ts +373 -4
- package/src/runtimes/local/local-thread-runtime-core.ts +79 -14
- package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +4 -0
- package/src/runtimes/remote-thread-list/empty-thread-core.ts +4 -0
- package/src/runtimes/remote-thread-list/types.ts +30 -0
- package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
- package/src/store/clients/model-context-client.test.ts +16 -8
- package/src/store/clients/suggestions.ts +2 -2
- package/src/store/clients/thread-selection-events.ts +21 -0
- package/src/store/env.ts +11 -0
- package/src/store/index.ts +14 -1
- package/src/store/internal.ts +13 -0
- package/src/store/primitive-predicates.test.ts +184 -0
- package/src/store/primitive-predicates.ts +43 -0
- package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
- package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
- package/src/store/runtime-clients/handle-runtime-action.ts +11 -0
- package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
- package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +15 -7
- package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
- package/src/store/scopes/composer.ts +9 -4
- package/src/store/scopes/thread-list-item.ts +7 -6
- package/src/store/scopes/thread.ts +8 -7
- package/src/store/scopes/threads.ts +14 -0
- package/src/subscribable/subscribable.test.ts +77 -1
- package/src/subscribable/subscribable.ts +38 -23
- package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
- package/src/tests/auiV0Encode.test.ts +66 -0
- package/src/tests/base-composer-runtime-core-send.test.ts +30 -0
- package/src/tests/base-composer-runtime-core.test.ts +28 -0
- package/src/tests/composer-can-cancel.test.ts +101 -0
- package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +191 -1
- package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
- package/src/tests/interactables-toolui-migration.test.tsx +66 -0
- package/src/tests/message-queue.test.ts +28 -0
- package/src/tests/session-reset-notification.test.ts +145 -0
- package/src/tests/thread-switch-events.test.tsx +99 -1
- package/src/tests/tools-scope-migration.test.tsx +58 -0
- package/src/utils/composite-context-provider.test.ts +139 -0
- package/src/utils/composite-context-provider.ts +26 -8
- package/src/utils/notify-event-listeners.ts +10 -5
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { notifyEventListeners } from "../utils/notify-event-listeners.js";
|
|
2
2
|
//#region src/subscribable/subscribable.ts
|
|
3
3
|
const SKIP_UPDATE = Symbol("skip-update");
|
|
4
|
+
const notifySubscribers = (subscribers, ...args) => {
|
|
5
|
+
const errors = [];
|
|
6
|
+
for (const callback of subscribers) try {
|
|
7
|
+
callback(...args);
|
|
8
|
+
} catch (error) {
|
|
9
|
+
errors.push(error);
|
|
10
|
+
}
|
|
11
|
+
if (errors.length === 1) throw errors[0];
|
|
12
|
+
if (errors.length > 1) {
|
|
13
|
+
for (const error of errors) console.error(error);
|
|
14
|
+
throw new AggregateError(errors);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
4
17
|
function shallowEqual(objA, objB) {
|
|
5
18
|
if (objA === void 0 && objB === void 0) return true;
|
|
6
19
|
if (objA === void 0) return false;
|
|
@@ -29,19 +42,7 @@ var BaseSubscribable = class {
|
|
|
29
42
|
});
|
|
30
43
|
}
|
|
31
44
|
_notifySubscribers() {
|
|
32
|
-
|
|
33
|
-
for (const callback of this._subscribers) try {
|
|
34
|
-
callback();
|
|
35
|
-
} catch (error) {
|
|
36
|
-
errors.push(error);
|
|
37
|
-
}
|
|
38
|
-
if (errors.length > 0) {
|
|
39
|
-
if (errors.length === 1) throw errors[0];
|
|
40
|
-
else {
|
|
41
|
-
for (const error of errors) console.error(error);
|
|
42
|
-
throw new AggregateError(errors);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
+
notifySubscribers(this._subscribers);
|
|
45
46
|
}
|
|
46
47
|
};
|
|
47
48
|
var BaseSubject = class {
|
|
@@ -55,7 +56,7 @@ var BaseSubject = class {
|
|
|
55
56
|
notifyEventListeners(this._subscriptions, payload, errorContext);
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
+
notifySubscribers(this._subscriptions, payload);
|
|
59
60
|
}
|
|
60
61
|
_updateConnection() {
|
|
61
62
|
if (this._subscriptions.size > 0) {
|
|
@@ -103,7 +104,9 @@ var ShallowMemoizeSubject = class extends BaseSubject {
|
|
|
103
104
|
const callback = () => {
|
|
104
105
|
if (this._syncState()) this.notifySubscribers();
|
|
105
106
|
};
|
|
106
|
-
|
|
107
|
+
const unsubscribe = this.binding.subscribe(callback);
|
|
108
|
+
this._syncState();
|
|
109
|
+
return unsubscribe;
|
|
107
110
|
}
|
|
108
111
|
};
|
|
109
112
|
var LazyMemoizeSubject = class extends BaseSubject {
|
|
@@ -120,7 +123,7 @@ var LazyMemoizeSubject = class extends BaseSubject {
|
|
|
120
123
|
getState = () => {
|
|
121
124
|
if (!this.isConnected || this._previousStateDirty) {
|
|
122
125
|
const newState = this.binding.getState();
|
|
123
|
-
if (newState !== SKIP_UPDATE) this._previousState = newState;
|
|
126
|
+
if (newState !== SKIP_UPDATE && (this._previousState === void 0 || !shallowEqual(newState, this._previousState))) this._previousState = newState;
|
|
124
127
|
this._previousStateDirty = false;
|
|
125
128
|
}
|
|
126
129
|
if (this._previousState === void 0) throw new Error("Entry not available in the store");
|
|
@@ -131,7 +134,9 @@ var LazyMemoizeSubject = class extends BaseSubject {
|
|
|
131
134
|
this._previousStateDirty = true;
|
|
132
135
|
this.notifySubscribers();
|
|
133
136
|
};
|
|
134
|
-
|
|
137
|
+
const unsubscribe = this.binding.subscribe(callback);
|
|
138
|
+
this._previousStateDirty = true;
|
|
139
|
+
return unsubscribe;
|
|
135
140
|
}
|
|
136
141
|
};
|
|
137
142
|
var NestedSubscriptionSubject = class extends BaseSubject {
|
|
@@ -204,6 +209,6 @@ var EventSubscriptionSubject = class extends BaseSubject {
|
|
|
204
209
|
}
|
|
205
210
|
};
|
|
206
211
|
//#endregion
|
|
207
|
-
export { BaseSubject, BaseSubscribable, EventSubscriptionSubject, LazyMemoizeSubject, NestedSubscriptionSubject, SKIP_UPDATE, ShallowMemoizeSubject };
|
|
212
|
+
export { BaseSubject, BaseSubscribable, EventSubscriptionSubject, LazyMemoizeSubject, NestedSubscriptionSubject, SKIP_UPDATE, ShallowMemoizeSubject, notifySubscribers };
|
|
208
213
|
|
|
209
214
|
//# sourceMappingURL=subscribable.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscribable.js","names":["Unsubscribe","notifyEventListeners","SKIP_UPDATE","Symbol","Subscribable","subscribe","callback","SubscribableWithState","path","TPath","getState","TState","NestedSubscribable","EventSubscribable","event","TEvent","binding","unstable_on","payload","shallowEqual","objA","T","objB","undefined","keysA","Object","keys","length","key","valueA","valueB","is","BaseSubscribable","_subscribers","Set","add","delete","waitForUpdate","Promise","resolve","unsubscribe","_notifySubscribers","errors","error","push","console","AggregateError","BaseSubject","_subscriptions","_connection","isConnected","_connect","notifySubscribers","errorContext","_updateConnection","size","ShallowMemoizeSubject","constructor","state","Error","_previousState","_syncState","LazyMemoizeSubject","_previousStateDirty","newState","NestedSubscriptionSubject","outerSubscribe","lastState","innerUnsubscribe","onRuntimeUpdate","outerUnsubscribe","EventSubscriptionSubject","config"],"sources":["../../src/subscribable/subscribable.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\nimport { notifyEventListeners } from \"../utils/notify-event-listeners\";\n\nexport const SKIP_UPDATE = Symbol(\"skip-update\");\nexport type SKIP_UPDATE = typeof SKIP_UPDATE;\n\nexport type Subscribable = {\n subscribe: (callback: () => void) => Unsubscribe;\n};\n\nexport type SubscribableWithState<TState, TPath> = Subscribable & {\n path: TPath;\n getState: () => TState;\n};\n\nexport type NestedSubscribable<\n TState extends Subscribable | undefined,\n TPath,\n> = SubscribableWithState<TState, TPath>;\n\nexport type EventSubscribable<TEvent extends string> = {\n event: TEvent;\n binding: SubscribableWithState<\n | {\n unstable_on: (\n event: TEvent,\n callback: (payload?: unknown) => void,\n ) => Unsubscribe;\n }\n | undefined,\n unknown\n >;\n};\n\nfunction shallowEqual<T extends object>(\n objA: T | undefined,\n objB: T | undefined,\n) {\n if (objA === undefined && objB === undefined) return true;\n if (objA === undefined) return false;\n if (objB === undefined) return false;\n\n const keysA = Object.keys(objA);\n if (keysA.length !== Object.keys(objB).length) return false;\n\n for (const key of keysA) {\n const valueA = objA[key as keyof T];\n const valueB = objB[key as keyof T];\n if (!Object.is(valueA, valueB)) return false;\n }\n\n return true;\n}\n\nexport class BaseSubscribable {\n private _subscribers = new Set<() => void>();\n\n public subscribe(callback: () => void): Unsubscribe {\n this._subscribers.add(callback);\n return () => this._subscribers.delete(callback);\n }\n\n public waitForUpdate() {\n return new Promise<void>((resolve) => {\n const unsubscribe = this.subscribe(() => {\n unsubscribe();\n resolve();\n });\n });\n }\n\n protected _notifySubscribers() {\n const errors = [];\n for (const callback of this._subscribers) {\n try {\n callback();\n } catch (error) {\n errors.push(error);\n }\n }\n\n if (errors.length > 0) {\n if (errors.length === 1) {\n throw errors[0];\n } else {\n for (const error of errors) {\n console.error(error);\n }\n throw new AggregateError(errors);\n }\n }\n }\n}\n\n// lazy connect/disconnect: only opens upstream subscription while it has subscribers\nexport abstract class BaseSubject {\n private _subscriptions = new Set<(payload?: unknown) => void>();\n private _connection: Unsubscribe | undefined;\n\n protected get isConnected() {\n return !!this._connection;\n }\n\n protected abstract _connect(): Unsubscribe;\n\n protected notifySubscribers(payload?: unknown, errorContext?: string) {\n if (errorContext) {\n notifyEventListeners(this._subscriptions, payload, errorContext);\n return;\n }\n\n for (const callback of this._subscriptions) callback(payload);\n }\n\n private _updateConnection() {\n if (this._subscriptions.size > 0) {\n if (this._connection) return;\n this._connection = this._connect();\n } else {\n this._connection?.();\n this._connection = undefined;\n }\n }\n\n public subscribe(callback: (payload?: unknown) => void) {\n this._subscriptions.add(callback);\n this._updateConnection();\n\n return () => {\n this._subscriptions.delete(callback);\n this._updateConnection();\n };\n }\n}\n\nexport class ShallowMemoizeSubject<TState extends object, TPath>\n extends BaseSubject\n implements SubscribableWithState<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n private binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>;\n\n constructor(binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>) {\n super();\n this.binding = binding;\n const state = binding.getState();\n if (state === SKIP_UPDATE)\n throw new Error(\"Entry not available in the store\");\n this._previousState = state;\n }\n\n private _previousState: TState;\n public getState = () => {\n if (!this.isConnected) this._syncState();\n return this._previousState;\n };\n\n private _syncState() {\n const state = this.binding.getState();\n if (state === SKIP_UPDATE) return false;\n if (shallowEqual(state, this._previousState)) return false;\n this._previousState = state;\n return true;\n }\n\n protected _connect() {\n const callback = () => {\n if (this._syncState()) {\n this.notifySubscribers();\n }\n };\n\n return this.binding.subscribe(callback);\n }\n}\n\nexport class LazyMemoizeSubject<TState extends object, TPath>\n extends BaseSubject\n implements SubscribableWithState<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n private binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>;\n\n constructor(binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>) {\n super();\n this.binding = binding;\n }\n\n private _previousStateDirty = true;\n private _previousState: TState | undefined;\n public getState = () => {\n if (!this.isConnected || this._previousStateDirty) {\n const newState = this.binding.getState();\n if (newState !== SKIP_UPDATE) {\n this._previousState = newState;\n }\n this._previousStateDirty = false;\n }\n if (this._previousState === undefined)\n throw new Error(\"Entry not available in the store\");\n return this._previousState;\n };\n\n protected _connect() {\n const callback = () => {\n this._previousStateDirty = true;\n this.notifySubscribers();\n };\n\n return this.binding.subscribe(callback);\n }\n}\n\nexport class NestedSubscriptionSubject<\n TState extends Subscribable | undefined,\n TPath,\n>\n extends BaseSubject\n implements\n SubscribableWithState<TState, TPath>,\n NestedSubscribable<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n private binding: NestedSubscribable<TState, TPath>;\n\n constructor(binding: NestedSubscribable<TState, TPath>) {\n super();\n this.binding = binding;\n }\n\n public getState() {\n return this.binding.getState();\n }\n\n public outerSubscribe(callback: () => void) {\n return this.binding.subscribe(callback);\n }\n\n protected _connect(): Unsubscribe {\n const callback = () => {\n this.notifySubscribers();\n };\n\n let lastState = this.binding.getState();\n let innerUnsubscribe = lastState?.subscribe(callback);\n const onRuntimeUpdate = () => {\n const newState = this.binding.getState();\n if (newState === lastState) return;\n lastState = newState;\n\n innerUnsubscribe?.();\n innerUnsubscribe = newState?.subscribe(callback);\n\n callback();\n };\n\n const outerUnsubscribe = this.outerSubscribe(onRuntimeUpdate);\n return () => {\n outerUnsubscribe?.();\n innerUnsubscribe?.();\n };\n }\n}\n\nexport class EventSubscriptionSubject<\n TEvent extends string,\n> extends BaseSubject {\n private config: EventSubscribable<TEvent>;\n\n constructor(config: EventSubscribable<TEvent>) {\n super();\n this.config = config;\n }\n\n public getState() {\n return this.config.binding.getState();\n }\n\n public outerSubscribe(callback: () => void) {\n return this.config.binding.subscribe(callback);\n }\n\n protected _connect(): Unsubscribe {\n const errorContext = `Runtime event \"${this.config.event}\"`;\n const callback = (payload?: unknown) => {\n this.notifySubscribers(payload, errorContext);\n };\n\n let lastState = this.config.binding.getState();\n let innerUnsubscribe = lastState?.unstable_on(this.config.event, callback);\n const onRuntimeUpdate = () => {\n const newState = this.config.binding.getState();\n if (newState === lastState) return;\n lastState = newState;\n\n innerUnsubscribe?.();\n innerUnsubscribe = newState?.unstable_on(this.config.event, callback);\n };\n\n const outerUnsubscribe = this.outerSubscribe(onRuntimeUpdate);\n return () => {\n outerUnsubscribe?.();\n innerUnsubscribe?.();\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"subscribable.js","names":["Unsubscribe","notifyEventListeners","SKIP_UPDATE","Symbol","Subscribable","subscribe","callback","SubscribableWithState","path","TPath","getState","TState","NestedSubscribable","EventSubscribable","event","TEvent","binding","unstable_on","payload","notifySubscribers","subscribers","Iterable","args","TArgs","errors","error","push","length","console","AggregateError","shallowEqual","objA","T","objB","undefined","keysA","Object","keys","key","valueA","valueB","is","BaseSubscribable","_subscribers","Set","add","delete","waitForUpdate","Promise","resolve","unsubscribe","_notifySubscribers","BaseSubject","_subscriptions","_connection","isConnected","_connect","errorContext","_updateConnection","size","ShallowMemoizeSubject","constructor","state","Error","_previousState","_syncState","LazyMemoizeSubject","_previousStateDirty","newState","NestedSubscriptionSubject","outerSubscribe","lastState","innerUnsubscribe","onRuntimeUpdate","outerUnsubscribe","EventSubscriptionSubject","config"],"sources":["../../src/subscribable/subscribable.ts"],"sourcesContent":["import type { Unsubscribe } from \"../types/unsubscribe\";\nimport { notifyEventListeners } from \"../utils/notify-event-listeners\";\n\nexport const SKIP_UPDATE = Symbol(\"skip-update\");\nexport type SKIP_UPDATE = typeof SKIP_UPDATE;\n\nexport type Subscribable = {\n subscribe: (callback: () => void) => Unsubscribe;\n};\n\nexport type SubscribableWithState<TState, TPath> = Subscribable & {\n path: TPath;\n getState: () => TState;\n};\n\nexport type NestedSubscribable<\n TState extends Subscribable | undefined,\n TPath,\n> = SubscribableWithState<TState, TPath>;\n\nexport type EventSubscribable<TEvent extends string> = {\n event: TEvent;\n binding: SubscribableWithState<\n | {\n unstable_on: (\n event: TEvent,\n callback: (payload?: unknown) => void,\n ) => Unsubscribe;\n }\n | undefined,\n unknown\n >;\n};\n\nexport const notifySubscribers = <TArgs extends unknown[]>(\n subscribers: Iterable<(...args: TArgs) => void>,\n ...args: TArgs\n): void => {\n const errors: unknown[] = [];\n for (const callback of subscribers) {\n try {\n callback(...args);\n } catch (error) {\n errors.push(error);\n }\n }\n\n if (errors.length === 1) {\n throw errors[0];\n }\n\n if (errors.length > 1) {\n for (const error of errors) {\n console.error(error);\n }\n throw new AggregateError(errors);\n }\n};\n\nfunction shallowEqual<T extends object>(\n objA: T | undefined,\n objB: T | undefined,\n) {\n if (objA === undefined && objB === undefined) return true;\n if (objA === undefined) return false;\n if (objB === undefined) return false;\n\n const keysA = Object.keys(objA);\n if (keysA.length !== Object.keys(objB).length) return false;\n\n for (const key of keysA) {\n const valueA = objA[key as keyof T];\n const valueB = objB[key as keyof T];\n if (!Object.is(valueA, valueB)) return false;\n }\n\n return true;\n}\n\nexport class BaseSubscribable {\n private _subscribers = new Set<() => void>();\n\n public subscribe(callback: () => void): Unsubscribe {\n this._subscribers.add(callback);\n return () => this._subscribers.delete(callback);\n }\n\n public waitForUpdate() {\n return new Promise<void>((resolve) => {\n const unsubscribe = this.subscribe(() => {\n unsubscribe();\n resolve();\n });\n });\n }\n\n protected _notifySubscribers() {\n notifySubscribers(this._subscribers);\n }\n}\n\n// lazy connect/disconnect: only opens upstream subscription while it has subscribers\nexport abstract class BaseSubject {\n private _subscriptions = new Set<(payload?: unknown) => void>();\n private _connection: Unsubscribe | undefined;\n\n protected get isConnected() {\n return !!this._connection;\n }\n\n protected abstract _connect(): Unsubscribe;\n\n protected notifySubscribers(payload?: unknown, errorContext?: string) {\n if (errorContext) {\n notifyEventListeners(this._subscriptions, payload, errorContext);\n return;\n }\n\n notifySubscribers(this._subscriptions, payload);\n }\n\n private _updateConnection() {\n if (this._subscriptions.size > 0) {\n if (this._connection) return;\n this._connection = this._connect();\n } else {\n this._connection?.();\n this._connection = undefined;\n }\n }\n\n public subscribe(callback: (payload?: unknown) => void) {\n this._subscriptions.add(callback);\n this._updateConnection();\n\n return () => {\n this._subscriptions.delete(callback);\n this._updateConnection();\n };\n }\n}\n\nexport class ShallowMemoizeSubject<TState extends object, TPath>\n extends BaseSubject\n implements SubscribableWithState<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n private binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>;\n\n constructor(binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>) {\n super();\n this.binding = binding;\n const state = binding.getState();\n if (state === SKIP_UPDATE)\n throw new Error(\"Entry not available in the store\");\n this._previousState = state;\n }\n\n private _previousState: TState;\n public getState = () => {\n if (!this.isConnected) this._syncState();\n return this._previousState;\n };\n\n private _syncState() {\n const state = this.binding.getState();\n if (state === SKIP_UPDATE) return false;\n if (shallowEqual(state, this._previousState)) return false;\n this._previousState = state;\n return true;\n }\n\n protected _connect() {\n const callback = () => {\n if (this._syncState()) {\n this.notifySubscribers();\n }\n };\n\n const unsubscribe = this.binding.subscribe(callback);\n this._syncState();\n return unsubscribe;\n }\n}\n\nexport class LazyMemoizeSubject<TState extends object, TPath>\n extends BaseSubject\n implements SubscribableWithState<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n private binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>;\n\n constructor(binding: SubscribableWithState<TState | SKIP_UPDATE, TPath>) {\n super();\n this.binding = binding;\n }\n\n private _previousStateDirty = true;\n private _previousState: TState | undefined;\n public getState = () => {\n if (!this.isConnected || this._previousStateDirty) {\n const newState = this.binding.getState();\n if (\n newState !== SKIP_UPDATE &&\n (this._previousState === undefined ||\n !shallowEqual(newState, this._previousState))\n ) {\n this._previousState = newState;\n }\n this._previousStateDirty = false;\n }\n if (this._previousState === undefined)\n throw new Error(\"Entry not available in the store\");\n return this._previousState;\n };\n\n protected _connect() {\n const callback = () => {\n this._previousStateDirty = true;\n this.notifySubscribers();\n };\n\n const unsubscribe = this.binding.subscribe(callback);\n this._previousStateDirty = true;\n return unsubscribe;\n }\n}\n\nexport class NestedSubscriptionSubject<\n TState extends Subscribable | undefined,\n TPath,\n>\n extends BaseSubject\n implements\n SubscribableWithState<TState, TPath>,\n NestedSubscribable<TState, TPath>\n{\n public get path() {\n return this.binding.path;\n }\n\n private binding: NestedSubscribable<TState, TPath>;\n\n constructor(binding: NestedSubscribable<TState, TPath>) {\n super();\n this.binding = binding;\n }\n\n public getState() {\n return this.binding.getState();\n }\n\n public outerSubscribe(callback: () => void) {\n return this.binding.subscribe(callback);\n }\n\n protected _connect(): Unsubscribe {\n const callback = () => {\n this.notifySubscribers();\n };\n\n let lastState = this.binding.getState();\n let innerUnsubscribe = lastState?.subscribe(callback);\n const onRuntimeUpdate = () => {\n const newState = this.binding.getState();\n if (newState === lastState) return;\n lastState = newState;\n\n innerUnsubscribe?.();\n innerUnsubscribe = newState?.subscribe(callback);\n\n callback();\n };\n\n const outerUnsubscribe = this.outerSubscribe(onRuntimeUpdate);\n return () => {\n outerUnsubscribe?.();\n innerUnsubscribe?.();\n };\n }\n}\n\nexport class EventSubscriptionSubject<\n TEvent extends string,\n> extends BaseSubject {\n private config: EventSubscribable<TEvent>;\n\n constructor(config: EventSubscribable<TEvent>) {\n super();\n this.config = config;\n }\n\n public getState() {\n return this.config.binding.getState();\n }\n\n public outerSubscribe(callback: () => void) {\n return this.config.binding.subscribe(callback);\n }\n\n protected _connect(): Unsubscribe {\n const errorContext = `Runtime event \"${this.config.event}\"`;\n const callback = (payload?: unknown) => {\n this.notifySubscribers(payload, errorContext);\n };\n\n let lastState = this.config.binding.getState();\n let innerUnsubscribe = lastState?.unstable_on(this.config.event, callback);\n const onRuntimeUpdate = () => {\n const newState = this.config.binding.getState();\n if (newState === lastState) return;\n lastState = newState;\n\n innerUnsubscribe?.();\n innerUnsubscribe = newState?.unstable_on(this.config.event, callback);\n };\n\n const outerUnsubscribe = this.outerSubscribe(onRuntimeUpdate);\n return () => {\n outerUnsubscribe?.();\n innerUnsubscribe?.();\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import "../index.js";
|
|
|
3
3
|
//#region src/utils/composite-context-provider.d.ts
|
|
4
4
|
declare class CompositeContextProvider implements ModelContextProvider {
|
|
5
5
|
private _providers;
|
|
6
|
+
private _providerUnsubscribes;
|
|
6
7
|
getModelContext(): ModelContext;
|
|
7
8
|
registerModelContextProvider(provider: ModelContextProvider): () => void;
|
|
8
9
|
private _subscribers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composite-context-provider.d.ts","names":[],"sources":["../../src/utils/composite-context-provider.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"composite-context-provider.d.ts","names":[],"sources":["../../src/utils/composite-context-provider.ts"],"mappings":";;;cAOa,oCAAoC;UACvC;UACA;EAER,mBAJW;EAQX,6BAA6B,UAAU;UA4B/B;EAER;EAIA,UAAU"}
|
|
@@ -1,25 +1,41 @@
|
|
|
1
1
|
import { mergeModelContexts } from "../model-context/types.js";
|
|
2
|
+
import { notifySubscribers } from "../subscribable/subscribable.js";
|
|
2
3
|
//#region src/utils/composite-context-provider.ts
|
|
3
4
|
var CompositeContextProvider = class {
|
|
4
|
-
_providers = /* @__PURE__ */ new
|
|
5
|
+
_providers = /* @__PURE__ */ new Map();
|
|
6
|
+
_providerUnsubscribes = /* @__PURE__ */ new Map();
|
|
5
7
|
getModelContext() {
|
|
6
|
-
return mergeModelContexts(this._providers);
|
|
8
|
+
return mergeModelContexts(new Set(this._providers.values()));
|
|
7
9
|
}
|
|
8
10
|
registerModelContextProvider(provider) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const id = Symbol();
|
|
12
|
+
this._providers.set(id, provider);
|
|
13
|
+
let unsubscribe;
|
|
14
|
+
try {
|
|
15
|
+
unsubscribe = provider.subscribe?.(() => {
|
|
16
|
+
this.notifySubscribers();
|
|
17
|
+
});
|
|
18
|
+
} catch (error) {
|
|
19
|
+
this._providers.delete(id);
|
|
20
|
+
try {
|
|
21
|
+
this.notifySubscribers();
|
|
22
|
+
} catch (notifyError) {
|
|
23
|
+
console.error(notifyError);
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
this._providerUnsubscribes.set(id, unsubscribe);
|
|
13
28
|
this.notifySubscribers();
|
|
14
29
|
return () => {
|
|
15
|
-
this._providers.delete(
|
|
16
|
-
|
|
30
|
+
this._providers.delete(id);
|
|
31
|
+
this._providerUnsubscribes.get(id)?.();
|
|
32
|
+
this._providerUnsubscribes.delete(id);
|
|
17
33
|
this.notifySubscribers();
|
|
18
34
|
};
|
|
19
35
|
}
|
|
20
36
|
_subscribers = /* @__PURE__ */ new Set();
|
|
21
37
|
notifySubscribers() {
|
|
22
|
-
|
|
38
|
+
notifySubscribers(this._subscribers);
|
|
23
39
|
}
|
|
24
40
|
subscribe(callback) {
|
|
25
41
|
this._subscribers.add(callback);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composite-context-provider.js","names":["ModelContextProvider","mergeModelContexts","CompositeContextProvider","_providers","
|
|
1
|
+
{"version":3,"file":"composite-context-provider.js","names":["ModelContextProvider","mergeModelContexts","notifySubscribers","notifyStateSubscribers","Unsubscribe","CompositeContextProvider","_providers","Map","_providerUnsubscribes","getModelContext","Set","values","registerModelContextProvider","provider","id","Symbol","set","unsubscribe","subscribe","error","delete","notifyError","console","get","_subscribers","callback","add"],"sources":["../../src/utils/composite-context-provider.ts"],"sourcesContent":["import {\n type ModelContextProvider,\n mergeModelContexts,\n} from \"../model-context/types\";\nimport { notifySubscribers as notifyStateSubscribers } from \"../subscribable/subscribable\";\nimport type { Unsubscribe } from \"../types/unsubscribe\";\n\nexport class CompositeContextProvider implements ModelContextProvider {\n private _providers = new Map<symbol, ModelContextProvider>();\n private _providerUnsubscribes = new Map<symbol, Unsubscribe | undefined>();\n\n getModelContext() {\n return mergeModelContexts(new Set(this._providers.values()));\n }\n\n registerModelContextProvider(provider: ModelContextProvider) {\n const id = Symbol();\n this._providers.set(id, provider);\n let unsubscribe: Unsubscribe | undefined;\n try {\n unsubscribe = provider.subscribe?.(() => {\n this.notifySubscribers();\n });\n } catch (error) {\n this._providers.delete(id);\n try {\n this.notifySubscribers();\n } catch (notifyError) {\n console.error(notifyError);\n }\n throw error;\n }\n this._providerUnsubscribes.set(id, unsubscribe);\n this.notifySubscribers();\n return () => {\n this._providers.delete(id);\n const unsubscribe = this._providerUnsubscribes.get(id);\n unsubscribe?.();\n this._providerUnsubscribes.delete(id);\n this.notifySubscribers();\n };\n }\n\n private _subscribers = new Set<() => void>();\n\n notifySubscribers() {\n notifyStateSubscribers(this._subscribers);\n }\n\n subscribe(callback: () => void) {\n this._subscribers.add(callback);\n return () => {\n this._subscribers.delete(callback);\n };\n }\n}\n"],"mappings":";;;AAOA,IAAaK,2BAAb,MAAsE;CACpE,6BAAqB,IAAIE,IAAkC;CAC3D,wCAAgC,IAAIA,IAAqC;CAEzEE,kBAAkB;EAChB,OAAOR,mBAAmB,IAAIS,IAAI,KAAKJ,WAAWK,OAAO,CAAC,CAAC;CAC7D;CAEAC,6BAA6BC,UAAgC;EAC3D,MAAMC,KAAKC,OAAO;EAClB,KAAKT,WAAWU,IAAIF,IAAID,QAAQ;EAChC,IAAII;EACJ,IAAI;GACFA,cAAcJ,SAASK,kBAAkB;IACvC,KAAKhB,kBAAkB;GACzB,CAAC;EACH,SAASiB,OAAO;GACd,KAAKb,WAAWc,OAAON,EAAE;GACzB,IAAI;IACF,KAAKZ,kBAAkB;GACzB,SAASmB,aAAa;IACpBC,QAAQH,MAAME,WAAW;GAC3B;GACA,MAAMF;EACR;EACA,KAAKX,sBAAsBQ,IAAIF,IAAIG,WAAW;EAC9C,KAAKf,kBAAkB;EACvB,aAAa;GACX,KAAKI,WAAWc,OAAON,EAAE;GAEzBG,KADyBT,sBAAsBe,IAAIT,EACnDG,CAAW,GAAG;GACd,KAAKT,sBAAsBY,OAAON,EAAE;GACpC,KAAKZ,kBAAkB;EACzB;CACF;CAEA,+BAAuB,IAAIQ,IAAgB;CAE3CR,oBAAoB;EAClBC,kBAAuB,KAAKqB,YAAY;CAC1C;CAEAN,UAAUO,UAAsB;EAC9B,KAAKD,aAAaE,IAAID,QAAQ;EAC9B,aAAa;GACX,KAAKD,aAAaJ,OAAOK,QAAQ;EACnC;CACF;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/utils/notify-event-listeners.d.ts
|
|
2
|
-
type EventListener = (payload
|
|
3
|
-
declare const notifyEventListeners: (listeners: Iterable<EventListener
|
|
2
|
+
type EventListener<T> = (payload: T) => unknown;
|
|
3
|
+
declare const notifyEventListeners: <T>(listeners: Iterable<EventListener<T>>, payloadOrFactory: T | (() => T), errorContext: string) => void;
|
|
4
4
|
//#endregion
|
|
5
5
|
export { notifyEventListeners };
|
|
6
6
|
//# sourceMappingURL=notify-event-listeners.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notify-event-listeners.d.ts","names":[],"sources":["../../src/utils/notify-event-listeners.ts"],"mappings":";KAAK,
|
|
1
|
+
{"version":3,"file":"notify-event-listeners.d.ts","names":[],"sources":["../../src/utils/notify-event-listeners.ts"],"mappings":";KAAK,cAAc,MAAM,SAAS;cAGrB,uBAAwB,GACnC,WAAW,SAAS,cAAc,KAClC,kBAAkB,WAAW,IAC7B"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
//#region src/utils/notify-event-listeners.ts
|
|
2
|
-
const notifyEventListeners = (listeners,
|
|
2
|
+
const notifyEventListeners = (listeners, payloadOrFactory, errorContext) => {
|
|
3
3
|
const reportError = (error) => {
|
|
4
4
|
console.error(`[assistant-ui] ${errorContext} listener threw an error`, error);
|
|
5
5
|
};
|
|
6
6
|
for (const listener of listeners) try {
|
|
7
|
-
const result = listener(
|
|
7
|
+
const result = listener(typeof payloadOrFactory === "function" ? payloadOrFactory() : payloadOrFactory);
|
|
8
8
|
if (result !== null && (typeof result === "object" || typeof result === "function") && "then" in result && typeof result.then === "function") Promise.resolve(result).catch(reportError);
|
|
9
9
|
} catch (error) {
|
|
10
10
|
reportError(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notify-event-listeners.js","names":["EventListener","payload","notifyEventListeners","listeners","Iterable","errorContext","reportError","error","console","listener","result","then","Promise","resolve","catch"],"sources":["../../src/utils/notify-event-listeners.ts"],"sourcesContent":["type EventListener = (payload
|
|
1
|
+
{"version":3,"file":"notify-event-listeners.js","names":["EventListener","payload","T","notifyEventListeners","listeners","Iterable","payloadOrFactory","errorContext","reportError","error","console","listener","result","then","Promise","resolve","catch"],"sources":["../../src/utils/notify-event-listeners.ts"],"sourcesContent":["type EventListener<T> = (payload: T) => unknown;\n\n// A function payload is indistinguishable from a factory and gets invoked; wrap a function-typed payload in a factory.\nexport const notifyEventListeners = <T>(\n listeners: Iterable<EventListener<T>>,\n payloadOrFactory: T | (() => T),\n errorContext: string,\n) => {\n const reportError = (error: unknown) => {\n console.error(\n `[assistant-ui] ${errorContext} listener threw an error`,\n error,\n );\n };\n\n for (const listener of listeners) {\n try {\n const result = listener(\n typeof payloadOrFactory === \"function\"\n ? (payloadOrFactory as () => T)()\n : payloadOrFactory,\n );\n if (\n result !== null &&\n (typeof result === \"object\" || typeof result === \"function\") &&\n \"then\" in result &&\n typeof result.then === \"function\"\n ) {\n void Promise.resolve(result).catch(reportError);\n }\n } catch (error) {\n reportError(error);\n }\n }\n};\n"],"mappings":";AAGA,MAAaG,wBACXC,WACAE,kBACAC,iBACG;CACH,MAAMC,eAAeC,UAAmB;EACtCC,QAAQD,MACN,kBAAkBF,aAAY,2BAC9BE,KACF;CACF;CAEA,KAAK,MAAME,YAAYP,WACrB,IAAI;EACF,MAAMQ,SAASD,SACb,OAAOL,qBAAqB,aACvBA,iBAA6B,IAC9BA,gBACN;EACA,IACEM,WAAW,SACV,OAAOA,WAAW,YAAY,OAAOA,WAAW,eACjD,UAAUA,UACV,OAAOA,OAAOC,SAAS,YAEvB,QAAaE,QAAQH,MAAM,CAAC,CAACI,MAAMR,WAAW;CAElD,SAASC,OAAO;EACdD,YAAYC,KAAK;CACnB;AAEJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"description": "Framework-agnostic core runtime for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"assistant",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
],
|
|
60
60
|
"sideEffects": false,
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"assistant-stream": "^0.3.
|
|
62
|
+
"assistant-stream": "^0.3.38",
|
|
63
63
|
"nanoid": "^6.0.1"
|
|
64
64
|
},
|
|
65
65
|
"optionalDevDependencies": {
|
|
@@ -95,11 +95,11 @@
|
|
|
95
95
|
"react-dom": "^19.2.8",
|
|
96
96
|
"vitest": "^4.1.10",
|
|
97
97
|
"zustand": "^5.0.14",
|
|
98
|
-
"@assistant-ui/
|
|
99
|
-
"@assistant-ui/
|
|
100
|
-
"assistant-
|
|
101
|
-
"@assistant-ui/
|
|
102
|
-
"
|
|
98
|
+
"@assistant-ui/store": "0.3.10",
|
|
99
|
+
"@assistant-ui/tap": "0.9.13",
|
|
100
|
+
"@assistant-ui/vite": "0.0.14",
|
|
101
|
+
"@assistant-ui/x-buildutils": "0.0.23",
|
|
102
|
+
"assistant-cloud": "0.1.41"
|
|
103
103
|
},
|
|
104
104
|
"publishConfig": {
|
|
105
105
|
"access": "public",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { WebSpeechSynthesisAdapter } from "./speech";
|
|
2
|
+
import { WebSpeechDictationAdapter, WebSpeechSynthesisAdapter } from "./speech";
|
|
3
3
|
|
|
4
4
|
afterEach(() => {
|
|
5
5
|
vi.restoreAllMocks();
|
|
@@ -86,3 +86,120 @@ describe("WebSpeechSynthesisAdapter", () => {
|
|
|
86
86
|
);
|
|
87
87
|
});
|
|
88
88
|
});
|
|
89
|
+
|
|
90
|
+
describe("WebSpeechDictationAdapter", () => {
|
|
91
|
+
const stubSpeechRecognition = () => {
|
|
92
|
+
const listeners = new Map<string, EventListener>();
|
|
93
|
+
class MockSpeechRecognition {
|
|
94
|
+
lang = "";
|
|
95
|
+
continuous = false;
|
|
96
|
+
interimResults = false;
|
|
97
|
+
|
|
98
|
+
addEventListener(type: string, listener: EventListener) {
|
|
99
|
+
listeners.set(type, listener);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
start() {}
|
|
103
|
+
stop() {}
|
|
104
|
+
abort() {}
|
|
105
|
+
}
|
|
106
|
+
vi.stubGlobal("window", {
|
|
107
|
+
SpeechRecognition: MockSpeechRecognition,
|
|
108
|
+
});
|
|
109
|
+
return listeners;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
it("continues notifying dictation listeners when one throws", () => {
|
|
113
|
+
const listeners = stubSpeechRecognition();
|
|
114
|
+
const listenerError = new Error("listener failed");
|
|
115
|
+
const consoleError = vi
|
|
116
|
+
.spyOn(console, "error")
|
|
117
|
+
.mockImplementation(() => {});
|
|
118
|
+
const session = new WebSpeechDictationAdapter().listen();
|
|
119
|
+
const laterStartListener = vi.fn();
|
|
120
|
+
const laterSpeechListener = vi.fn();
|
|
121
|
+
const laterEndListener = vi.fn();
|
|
122
|
+
|
|
123
|
+
session.onSpeechStart(() => {
|
|
124
|
+
throw listenerError;
|
|
125
|
+
});
|
|
126
|
+
session.onSpeechStart(laterStartListener);
|
|
127
|
+
session.onSpeech(() => {
|
|
128
|
+
throw listenerError;
|
|
129
|
+
});
|
|
130
|
+
session.onSpeech(laterSpeechListener);
|
|
131
|
+
session.onSpeechEnd(() => {
|
|
132
|
+
throw listenerError;
|
|
133
|
+
});
|
|
134
|
+
session.onSpeechEnd(laterEndListener);
|
|
135
|
+
|
|
136
|
+
const event = {
|
|
137
|
+
resultIndex: 0,
|
|
138
|
+
results: [
|
|
139
|
+
{
|
|
140
|
+
0: { transcript: "Hello" },
|
|
141
|
+
isFinal: true,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
} as unknown as Event;
|
|
145
|
+
|
|
146
|
+
expect(() =>
|
|
147
|
+
listeners.get("speechstart")?.(new Event("speechstart")),
|
|
148
|
+
).not.toThrow();
|
|
149
|
+
expect(() => listeners.get("result")?.(event)).not.toThrow();
|
|
150
|
+
expect(() => listeners.get("end")?.(new Event("end"))).not.toThrow();
|
|
151
|
+
|
|
152
|
+
expect(laterStartListener).toHaveBeenCalledOnce();
|
|
153
|
+
expect(laterSpeechListener).toHaveBeenCalledWith({
|
|
154
|
+
transcript: "Hello",
|
|
155
|
+
isFinal: true,
|
|
156
|
+
});
|
|
157
|
+
expect(laterEndListener).toHaveBeenCalledWith({
|
|
158
|
+
transcript: "Hello",
|
|
159
|
+
});
|
|
160
|
+
expect(consoleError).toHaveBeenCalledTimes(3);
|
|
161
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
162
|
+
"[assistant-ui] Dictation listener threw an error",
|
|
163
|
+
listenerError,
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("isolates async failures and payload mutations", async () => {
|
|
168
|
+
const listeners = stubSpeechRecognition();
|
|
169
|
+
const listenerError = new Error("async listener failed");
|
|
170
|
+
const consoleError = vi
|
|
171
|
+
.spyOn(console, "error")
|
|
172
|
+
.mockImplementation(() => {});
|
|
173
|
+
const session = new WebSpeechDictationAdapter().listen();
|
|
174
|
+
const laterListener = vi.fn();
|
|
175
|
+
|
|
176
|
+
session.onSpeech(async (result) => {
|
|
177
|
+
result.transcript = "Changed";
|
|
178
|
+
result.isFinal = false;
|
|
179
|
+
throw listenerError;
|
|
180
|
+
});
|
|
181
|
+
session.onSpeech(laterListener);
|
|
182
|
+
|
|
183
|
+
const event = {
|
|
184
|
+
resultIndex: 0,
|
|
185
|
+
results: [
|
|
186
|
+
{
|
|
187
|
+
0: { transcript: "Hello" },
|
|
188
|
+
isFinal: true,
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
} as unknown as Event;
|
|
192
|
+
|
|
193
|
+
expect(() => listeners.get("result")?.(event)).not.toThrow();
|
|
194
|
+
expect(laterListener).toHaveBeenCalledWith({
|
|
195
|
+
transcript: "Hello",
|
|
196
|
+
isFinal: true,
|
|
197
|
+
});
|
|
198
|
+
await vi.waitFor(() => {
|
|
199
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
200
|
+
"[assistant-ui] Dictation listener threw an error",
|
|
201
|
+
listenerError,
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|
package/src/adapters/speech.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Unsubscribe } from "../types/unsubscribe";
|
|
2
|
+
import { notifyEventListeners } from "../utils/notify-event-listeners";
|
|
2
3
|
|
|
3
4
|
export namespace SpeechSynthesisAdapter {
|
|
4
5
|
export type Status =
|
|
@@ -22,21 +23,6 @@ export type SpeechSynthesisAdapter = {
|
|
|
22
23
|
speak: (text: string) => SpeechSynthesisAdapter.Utterance;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
const notifySpeechSynthesisListeners = (
|
|
26
|
-
listeners: Iterable<() => void>,
|
|
27
|
-
): void => {
|
|
28
|
-
for (const listener of listeners) {
|
|
29
|
-
try {
|
|
30
|
-
listener();
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error(
|
|
33
|
-
"[assistant-ui] Speech synthesis listener threw an error",
|
|
34
|
-
error,
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
26
|
export namespace DictationAdapter {
|
|
41
27
|
export type Status =
|
|
42
28
|
| {
|
|
@@ -79,7 +65,7 @@ export class WebSpeechSynthesisAdapter implements SpeechSynthesisAdapter {
|
|
|
79
65
|
if (res.status.type === "ended") return;
|
|
80
66
|
|
|
81
67
|
res.status = { type: "ended", reason, error };
|
|
82
|
-
|
|
68
|
+
notifyEventListeners(subscribers, undefined, "Speech synthesis");
|
|
83
69
|
};
|
|
84
70
|
|
|
85
71
|
utterance.addEventListener("end", () => handleEnd("finished"));
|
|
@@ -97,7 +83,9 @@ export class WebSpeechSynthesisAdapter implements SpeechSynthesisAdapter {
|
|
|
97
83
|
if (res.status.type === "ended") {
|
|
98
84
|
let cancelled = false;
|
|
99
85
|
queueMicrotask(() => {
|
|
100
|
-
if (!cancelled)
|
|
86
|
+
if (!cancelled) {
|
|
87
|
+
notifyEventListeners([callback], undefined, "Speech synthesis");
|
|
88
|
+
}
|
|
101
89
|
});
|
|
102
90
|
return () => {
|
|
103
91
|
cancelled = true;
|
|
@@ -270,7 +258,7 @@ export class WebSpeechDictationAdapter implements DictationAdapter {
|
|
|
270
258
|
};
|
|
271
259
|
|
|
272
260
|
recognition.addEventListener("speechstart", () => {
|
|
273
|
-
|
|
261
|
+
notifyEventListeners(speechStartCallbacks, undefined, "Dictation");
|
|
274
262
|
});
|
|
275
263
|
|
|
276
264
|
recognition.addEventListener("start", () => {
|
|
@@ -292,9 +280,17 @@ export class WebSpeechDictationAdapter implements DictationAdapter {
|
|
|
292
280
|
|
|
293
281
|
if (result.isFinal) {
|
|
294
282
|
finalTranscript += transcript;
|
|
295
|
-
|
|
283
|
+
notifyEventListeners(
|
|
284
|
+
speechCallbacks,
|
|
285
|
+
() => ({ transcript, isFinal: true }),
|
|
286
|
+
"Dictation",
|
|
287
|
+
);
|
|
296
288
|
} else {
|
|
297
|
-
|
|
289
|
+
notifyEventListeners(
|
|
290
|
+
speechCallbacks,
|
|
291
|
+
() => ({ transcript, isFinal: false }),
|
|
292
|
+
"Dictation",
|
|
293
|
+
);
|
|
298
294
|
}
|
|
299
295
|
}
|
|
300
296
|
});
|
|
@@ -309,8 +305,11 @@ export class WebSpeechDictationAdapter implements DictationAdapter {
|
|
|
309
305
|
updateStatus({ type: "ended", reason: "stopped" });
|
|
310
306
|
}
|
|
311
307
|
if (finalTranscript) {
|
|
312
|
-
|
|
313
|
-
|
|
308
|
+
notifyEventListeners(
|
|
309
|
+
speechEndCallbacks,
|
|
310
|
+
() => ({ transcript: finalTranscript }),
|
|
311
|
+
"Dictation",
|
|
312
|
+
);
|
|
314
313
|
finalTranscript = "";
|
|
315
314
|
}
|
|
316
315
|
});
|
|
@@ -39,6 +39,8 @@ export interface MessageFormatAdapter<
|
|
|
39
39
|
|
|
40
40
|
export type GenericThreadHistoryAdapter<TMessage> = {
|
|
41
41
|
load(): Promise<MessageFormatRepository<TMessage>>;
|
|
42
|
+
/** Snapshot the current thread so later writes survive a switch. */
|
|
43
|
+
pin?(): void;
|
|
42
44
|
append(item: MessageFormatItem<TMessage>): Promise<void>;
|
|
43
45
|
update?(
|
|
44
46
|
item: MessageFormatItem<TMessage>,
|
|
@@ -73,6 +73,75 @@ describe("createVoiceSession", () => {
|
|
|
73
73
|
expect(controls.mute).not.toHaveBeenCalled();
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
it("removes the abort listener after disconnecting", async () => {
|
|
77
|
+
const abortController = new AbortController();
|
|
78
|
+
const controls = {
|
|
79
|
+
disconnect: vi.fn(),
|
|
80
|
+
mute: vi.fn(),
|
|
81
|
+
unmute: vi.fn(),
|
|
82
|
+
};
|
|
83
|
+
const session = createVoiceSession(
|
|
84
|
+
{ abortSignal: abortController.signal },
|
|
85
|
+
async () => controls,
|
|
86
|
+
);
|
|
87
|
+
await Promise.resolve();
|
|
88
|
+
|
|
89
|
+
session.disconnect();
|
|
90
|
+
session.disconnect();
|
|
91
|
+
abortController.abort();
|
|
92
|
+
|
|
93
|
+
expect(controls.disconnect).toHaveBeenCalledOnce();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("keeps abort teardown available after the session ends", async () => {
|
|
97
|
+
const abortController = new AbortController();
|
|
98
|
+
const controls = {
|
|
99
|
+
disconnect: vi.fn(),
|
|
100
|
+
mute: vi.fn(),
|
|
101
|
+
unmute: vi.fn(),
|
|
102
|
+
};
|
|
103
|
+
let helpers: VoiceSessionHelpers | undefined;
|
|
104
|
+
createVoiceSession(
|
|
105
|
+
{ abortSignal: abortController.signal },
|
|
106
|
+
async (sessionHelpers) => {
|
|
107
|
+
helpers = sessionHelpers;
|
|
108
|
+
return controls;
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
await Promise.resolve();
|
|
112
|
+
if (!helpers) throw new Error("Voice session setup did not start");
|
|
113
|
+
|
|
114
|
+
helpers.end("error");
|
|
115
|
+
abortController.abort();
|
|
116
|
+
|
|
117
|
+
expect(controls.disconnect).toHaveBeenCalledOnce();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("cleans up when the adapter disconnect throws", async () => {
|
|
121
|
+
const disconnectError = new Error("disconnect failed");
|
|
122
|
+
let helpers: VoiceSessionHelpers | undefined;
|
|
123
|
+
const session = createVoiceSession({}, async (sessionHelpers) => {
|
|
124
|
+
helpers = sessionHelpers;
|
|
125
|
+
return {
|
|
126
|
+
disconnect: () => {
|
|
127
|
+
throw disconnectError;
|
|
128
|
+
},
|
|
129
|
+
mute: vi.fn(),
|
|
130
|
+
unmute: vi.fn(),
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
await Promise.resolve();
|
|
134
|
+
if (!helpers) throw new Error("Voice session setup did not start");
|
|
135
|
+
const transcriptListener = vi.fn();
|
|
136
|
+
session.onTranscript(transcriptListener);
|
|
137
|
+
|
|
138
|
+
expect(() => session.disconnect()).toThrow(disconnectError);
|
|
139
|
+
expect(helpers.isDisposed()).toBe(true);
|
|
140
|
+
|
|
141
|
+
helpers.emitTranscript({ role: "assistant", text: "stale" });
|
|
142
|
+
expect(transcriptListener).not.toHaveBeenCalled();
|
|
143
|
+
});
|
|
144
|
+
|
|
76
145
|
it("continues notifying listeners when one throws", () => {
|
|
77
146
|
const listenerError = new Error("listener failed");
|
|
78
147
|
const consoleError = vi
|