@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,6 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
2
|
import type { SubscribableWithState } from "./subscribable";
|
|
3
|
-
import { ShallowMemoizeSubject } from "./subscribable";
|
|
3
|
+
import { LazyMemoizeSubject, ShallowMemoizeSubject } from "./subscribable";
|
|
4
4
|
|
|
5
5
|
type TestState = {
|
|
6
6
|
status: string;
|
|
@@ -26,6 +26,9 @@ const createBinding = (initialState: TestState) => {
|
|
|
26
26
|
state = nextState;
|
|
27
27
|
for (const callback of subscribers) callback();
|
|
28
28
|
},
|
|
29
|
+
replace(nextState: TestState) {
|
|
30
|
+
state = nextState;
|
|
31
|
+
},
|
|
29
32
|
};
|
|
30
33
|
};
|
|
31
34
|
|
|
@@ -55,4 +58,77 @@ describe("ShallowMemoizeSubject", () => {
|
|
|
55
58
|
|
|
56
59
|
expect(subscriber).not.toHaveBeenCalled();
|
|
57
60
|
});
|
|
61
|
+
|
|
62
|
+
it("notifies later subscribers when one throws", () => {
|
|
63
|
+
const source = createBinding({ status: "empty" });
|
|
64
|
+
const subject = new ShallowMemoizeSubject(source.binding);
|
|
65
|
+
const error = new Error("subscriber failed");
|
|
66
|
+
const laterSubscriber = vi.fn();
|
|
67
|
+
subject.subscribe(() => {
|
|
68
|
+
throw error;
|
|
69
|
+
});
|
|
70
|
+
subject.subscribe(laterSubscriber);
|
|
71
|
+
|
|
72
|
+
expect(() => source.update({ status: "ready" })).toThrow(error);
|
|
73
|
+
expect(laterSubscriber).toHaveBeenCalledOnce();
|
|
74
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("reads a value that landed while nobody was subscribed", () => {
|
|
78
|
+
const source = createBinding({ status: "empty" });
|
|
79
|
+
const subject = new ShallowMemoizeSubject(source.binding);
|
|
80
|
+
expect(subject.getState()).toEqual({ status: "empty" });
|
|
81
|
+
|
|
82
|
+
source.update({ status: "ready" });
|
|
83
|
+
const subscriber = vi.fn();
|
|
84
|
+
subject.subscribe(subscriber);
|
|
85
|
+
|
|
86
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
87
|
+
expect(subscriber).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("LazyMemoizeSubject", () => {
|
|
92
|
+
it("notifies later subscribers when one throws", () => {
|
|
93
|
+
const source = createBinding({ status: "empty" });
|
|
94
|
+
const subject = new LazyMemoizeSubject(source.binding);
|
|
95
|
+
const error = new Error("subscriber failed");
|
|
96
|
+
const laterSubscriber = vi.fn();
|
|
97
|
+
subject.subscribe(() => {
|
|
98
|
+
throw error;
|
|
99
|
+
});
|
|
100
|
+
subject.subscribe(laterSubscriber);
|
|
101
|
+
|
|
102
|
+
expect(() => source.update({ status: "ready" })).toThrow(error);
|
|
103
|
+
expect(laterSubscriber).toHaveBeenCalledOnce();
|
|
104
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("reads a value replaced before connecting", () => {
|
|
108
|
+
const source = createBinding({ status: "empty" });
|
|
109
|
+
const subject = new LazyMemoizeSubject(source.binding);
|
|
110
|
+
expect(subject.getState()).toEqual({ status: "empty" });
|
|
111
|
+
|
|
112
|
+
source.replace({ status: "ready" });
|
|
113
|
+
const subscriber = vi.fn();
|
|
114
|
+
const unsubscribe = subject.subscribe(subscriber);
|
|
115
|
+
|
|
116
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
117
|
+
expect(subscriber).not.toHaveBeenCalled();
|
|
118
|
+
unsubscribe();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("resynchronizes after reconnecting", () => {
|
|
122
|
+
const source = createBinding({ status: "empty" });
|
|
123
|
+
const subject = new LazyMemoizeSubject(source.binding);
|
|
124
|
+
expect(subject.getState()).toEqual({ status: "empty" });
|
|
125
|
+
|
|
126
|
+
const unsubscribe = subject.subscribe(() => {});
|
|
127
|
+
unsubscribe();
|
|
128
|
+
source.replace({ status: "ready" });
|
|
129
|
+
const reconnect = subject.subscribe(() => {});
|
|
130
|
+
|
|
131
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
132
|
+
reconnect();
|
|
133
|
+
});
|
|
58
134
|
});
|
|
@@ -32,6 +32,31 @@ export type EventSubscribable<TEvent extends string> = {
|
|
|
32
32
|
>;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
export const notifySubscribers = <TArgs extends unknown[]>(
|
|
36
|
+
subscribers: Iterable<(...args: TArgs) => void>,
|
|
37
|
+
...args: TArgs
|
|
38
|
+
): void => {
|
|
39
|
+
const errors: unknown[] = [];
|
|
40
|
+
for (const callback of subscribers) {
|
|
41
|
+
try {
|
|
42
|
+
callback(...args);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
errors.push(error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (errors.length === 1) {
|
|
49
|
+
throw errors[0];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (errors.length > 1) {
|
|
53
|
+
for (const error of errors) {
|
|
54
|
+
console.error(error);
|
|
55
|
+
}
|
|
56
|
+
throw new AggregateError(errors);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
35
60
|
function shallowEqual<T extends object>(
|
|
36
61
|
objA: T | undefined,
|
|
37
62
|
objB: T | undefined,
|
|
@@ -70,25 +95,7 @@ export class BaseSubscribable {
|
|
|
70
95
|
}
|
|
71
96
|
|
|
72
97
|
protected _notifySubscribers() {
|
|
73
|
-
|
|
74
|
-
for (const callback of this._subscribers) {
|
|
75
|
-
try {
|
|
76
|
-
callback();
|
|
77
|
-
} catch (error) {
|
|
78
|
-
errors.push(error);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (errors.length > 0) {
|
|
83
|
-
if (errors.length === 1) {
|
|
84
|
-
throw errors[0];
|
|
85
|
-
} else {
|
|
86
|
-
for (const error of errors) {
|
|
87
|
-
console.error(error);
|
|
88
|
-
}
|
|
89
|
-
throw new AggregateError(errors);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
98
|
+
notifySubscribers(this._subscribers);
|
|
92
99
|
}
|
|
93
100
|
}
|
|
94
101
|
|
|
@@ -109,7 +116,7 @@ export abstract class BaseSubject {
|
|
|
109
116
|
return;
|
|
110
117
|
}
|
|
111
118
|
|
|
112
|
-
|
|
119
|
+
notifySubscribers(this._subscriptions, payload);
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
private _updateConnection() {
|
|
@@ -173,7 +180,9 @@ export class ShallowMemoizeSubject<TState extends object, TPath>
|
|
|
173
180
|
}
|
|
174
181
|
};
|
|
175
182
|
|
|
176
|
-
|
|
183
|
+
const unsubscribe = this.binding.subscribe(callback);
|
|
184
|
+
this._syncState();
|
|
185
|
+
return unsubscribe;
|
|
177
186
|
}
|
|
178
187
|
}
|
|
179
188
|
|
|
@@ -197,7 +206,11 @@ export class LazyMemoizeSubject<TState extends object, TPath>
|
|
|
197
206
|
public getState = () => {
|
|
198
207
|
if (!this.isConnected || this._previousStateDirty) {
|
|
199
208
|
const newState = this.binding.getState();
|
|
200
|
-
if (
|
|
209
|
+
if (
|
|
210
|
+
newState !== SKIP_UPDATE &&
|
|
211
|
+
(this._previousState === undefined ||
|
|
212
|
+
!shallowEqual(newState, this._previousState))
|
|
213
|
+
) {
|
|
201
214
|
this._previousState = newState;
|
|
202
215
|
}
|
|
203
216
|
this._previousStateDirty = false;
|
|
@@ -213,7 +226,9 @@ export class LazyMemoizeSubject<TState extends object, TPath>
|
|
|
213
226
|
this.notifySubscribers();
|
|
214
227
|
};
|
|
215
228
|
|
|
216
|
-
|
|
229
|
+
const unsubscribe = this.binding.subscribe(callback);
|
|
230
|
+
this._previousStateDirty = true;
|
|
231
|
+
return unsubscribe;
|
|
217
232
|
}
|
|
218
233
|
}
|
|
219
234
|
|
|
@@ -63,6 +63,31 @@ describe("RemoteThreadListThreadListRuntimeCore.switchToThread unarchive option"
|
|
|
63
63
|
expect(core.mainThreadId).toBe(core.getItemById(THREAD_ID)?.id);
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
it("restores an initialized draft's archived thread when unarchive fails", async () => {
|
|
67
|
+
const THREAD_ID = "archived-initialized-draft";
|
|
68
|
+
const error = new Error("unarchive failed");
|
|
69
|
+
const adapter = makeAdapter({
|
|
70
|
+
list: vi.fn(async () => ({ threads: [archivedThread(THREAD_ID)] })),
|
|
71
|
+
unarchive: vi.fn(async () => {
|
|
72
|
+
throw error;
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const core = createCore(adapter);
|
|
77
|
+
await core.getLoadThreadsPromise();
|
|
78
|
+
const draftId = core.newThreadId;
|
|
79
|
+
if (draftId === undefined) throw new Error("Expected seeded draft");
|
|
80
|
+
await core.initialize(draftId);
|
|
81
|
+
expect(core.newThreadId).toBeUndefined();
|
|
82
|
+
await core.switchToThread(THREAD_ID, { unarchive: false });
|
|
83
|
+
|
|
84
|
+
await expect(core.unarchive(THREAD_ID)).rejects.toBe(error);
|
|
85
|
+
expect(core.mainThreadId).not.toBe(THREAD_ID);
|
|
86
|
+
expect(core.getItemById(THREAD_ID)?.status).toBe("archived");
|
|
87
|
+
expect(core.archivedThreadIds).toContain(THREAD_ID);
|
|
88
|
+
expect(core.threadIds).not.toContain(THREAD_ID);
|
|
89
|
+
});
|
|
90
|
+
|
|
66
91
|
it("does not call unarchive when the target is already regular, regardless of option", async () => {
|
|
67
92
|
const THREAD_ID = "regular-target";
|
|
68
93
|
const adapter = makeAdapter({
|
|
@@ -330,6 +330,33 @@ describe("auiV0Encode", () => {
|
|
|
330
330
|
{ type: "data", name: "telemetry", data: { runs: 3 } },
|
|
331
331
|
]);
|
|
332
332
|
});
|
|
333
|
+
|
|
334
|
+
it("preserves data message parts verbatim in the core cloud encoder", () => {
|
|
335
|
+
const encoded = auiV0Encode({
|
|
336
|
+
id: "m1",
|
|
337
|
+
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
338
|
+
role: "assistant",
|
|
339
|
+
status: { type: "complete", reason: "stop" },
|
|
340
|
+
metadata: {
|
|
341
|
+
unstable_state: null,
|
|
342
|
+
unstable_annotations: [],
|
|
343
|
+
unstable_data: [],
|
|
344
|
+
steps: [],
|
|
345
|
+
custom: {},
|
|
346
|
+
},
|
|
347
|
+
content: [
|
|
348
|
+
{ type: "text", text: "planned" },
|
|
349
|
+
{ type: "data", name: "PredictState", data: { steps: ["a"] } },
|
|
350
|
+
{ type: "data", name: "PredictState", data: '{"steps":["a","b"]}' },
|
|
351
|
+
],
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
expect(encoded.content).toEqual([
|
|
355
|
+
{ type: "text", text: "planned" },
|
|
356
|
+
{ type: "data", name: "PredictState", data: { steps: ["a"] } },
|
|
357
|
+
{ type: "data", name: "PredictState", data: '{"steps":["a","b"]}' },
|
|
358
|
+
]);
|
|
359
|
+
});
|
|
333
360
|
});
|
|
334
361
|
|
|
335
362
|
describe("auiV0Decode", () => {
|
|
@@ -573,4 +600,43 @@ describe("auiV0Decode", () => {
|
|
|
573
600
|
const toolCall = message.content.find((p) => p.type === "tool-call");
|
|
574
601
|
expect(toolCall).toHaveProperty("result", false);
|
|
575
602
|
});
|
|
603
|
+
|
|
604
|
+
it("round-trips data message parts, keeping repeated names in order", () => {
|
|
605
|
+
const content = auiV0Encode({
|
|
606
|
+
id: "local",
|
|
607
|
+
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
608
|
+
role: "assistant",
|
|
609
|
+
status: { type: "complete", reason: "stop" },
|
|
610
|
+
metadata: {
|
|
611
|
+
unstable_state: null,
|
|
612
|
+
unstable_annotations: [],
|
|
613
|
+
unstable_data: [],
|
|
614
|
+
steps: [],
|
|
615
|
+
custom: {},
|
|
616
|
+
},
|
|
617
|
+
content: [
|
|
618
|
+
{ type: "text", text: "planned" },
|
|
619
|
+
{ type: "data", name: "PredictState", data: { steps: ["a"] } },
|
|
620
|
+
{ type: "data", name: "PredictState", data: '{"steps":["a","b"]}' },
|
|
621
|
+
],
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
const decoded = auiV0Decode({
|
|
625
|
+
id: "cloud",
|
|
626
|
+
parent_id: null,
|
|
627
|
+
height: 0,
|
|
628
|
+
created_at: new Date("2026-03-15T00:00:00.000Z"),
|
|
629
|
+
updated_at: new Date("2026-03-15T00:00:00.000Z"),
|
|
630
|
+
format: "aui/v0",
|
|
631
|
+
content: content as never,
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
if (decoded.message.role !== "assistant")
|
|
635
|
+
throw new Error("expected assistant");
|
|
636
|
+
expect(decoded.message.content).toEqual([
|
|
637
|
+
{ type: "text", text: "planned" },
|
|
638
|
+
{ type: "data", name: "PredictState", data: { steps: ["a"] } },
|
|
639
|
+
{ type: "data", name: "PredictState", data: '{"steps":["a","b"]}' },
|
|
640
|
+
]);
|
|
641
|
+
});
|
|
576
642
|
});
|
|
@@ -158,6 +158,36 @@ describe("BaseComposerRuntimeCore.send restore-on-failure", () => {
|
|
|
158
158
|
expect(append).toHaveBeenCalledTimes(1);
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
+
it("snapshots role and run config before uploading attachments", async () => {
|
|
162
|
+
let resolveSend!: () => void;
|
|
163
|
+
const adapter = makeAdapter({
|
|
164
|
+
send: (a) =>
|
|
165
|
+
new Promise((resolve) => {
|
|
166
|
+
resolveSend = () =>
|
|
167
|
+
resolve({ ...a, status: { type: "complete" }, content: [] });
|
|
168
|
+
}),
|
|
169
|
+
});
|
|
170
|
+
const { composer, append } = makeComposer(adapter);
|
|
171
|
+
|
|
172
|
+
composer.setText("hello");
|
|
173
|
+
composer.setRole("assistant");
|
|
174
|
+
composer.setRunConfig({ custom: { modelName: "model-a" } });
|
|
175
|
+
await composer.addAttachment(textFile());
|
|
176
|
+
|
|
177
|
+
const sendPromise = composer.send();
|
|
178
|
+
composer.setRole("system");
|
|
179
|
+
composer.setRunConfig({ custom: { modelName: "model-b" } });
|
|
180
|
+
resolveSend();
|
|
181
|
+
await sendPromise;
|
|
182
|
+
|
|
183
|
+
expect(append).toHaveBeenCalledWith(
|
|
184
|
+
expect.objectContaining({
|
|
185
|
+
role: "assistant",
|
|
186
|
+
runConfig: { custom: { modelName: "model-a" } },
|
|
187
|
+
}),
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
161
191
|
it("keeps an attachment added while the upload was in flight", async () => {
|
|
162
192
|
let resolveSend!: () => void;
|
|
163
193
|
const adapter = makeAdapter({
|
|
@@ -186,6 +186,34 @@ describe("BaseComposerRuntimeCore", () => {
|
|
|
186
186
|
expect(composer.attachmentAccept).toBe("image/*");
|
|
187
187
|
});
|
|
188
188
|
|
|
189
|
+
it("handles rejected dictation shutdowns", async () => {
|
|
190
|
+
const session: DictationAdapter.Session = {
|
|
191
|
+
status: { type: "running" },
|
|
192
|
+
stop: vi.fn().mockRejectedValue(new Error("shutdown failed")),
|
|
193
|
+
cancel: vi.fn(),
|
|
194
|
+
onSpeechStart: vi.fn(() => () => {}),
|
|
195
|
+
onSpeechEnd: vi.fn(() => () => {}),
|
|
196
|
+
onSpeech: vi.fn(() => () => {}),
|
|
197
|
+
};
|
|
198
|
+
const unhandledRejection = vi.fn();
|
|
199
|
+
composer.setDictationAdapter({ listen: () => session });
|
|
200
|
+
process.on("unhandledRejection", unhandledRejection);
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
composer.startDictation();
|
|
204
|
+
expect(composer.dictation).toBeDefined();
|
|
205
|
+
|
|
206
|
+
composer.stopDictation();
|
|
207
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
208
|
+
|
|
209
|
+
expect(session.stop).toHaveBeenCalledOnce();
|
|
210
|
+
expect(composer.dictation).toBeUndefined();
|
|
211
|
+
expect(unhandledRejection).not.toHaveBeenCalled();
|
|
212
|
+
} finally {
|
|
213
|
+
process.off("unhandledRejection", unhandledRejection);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
189
217
|
describe("CreateAttachment (external source)", () => {
|
|
190
218
|
const makeCreateAttachment = (
|
|
191
219
|
overrides?: Partial<CreateAttachment>,
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { DefaultThreadComposerRuntimeCore } from "../runtime/base/default-thread-composer-runtime-core";
|
|
3
|
+
import type { ThreadRuntimeCore } from "../runtime/interfaces/thread-runtime-core";
|
|
4
|
+
import type { ThreadMessage } from "../types/message";
|
|
5
|
+
|
|
6
|
+
type ThreadRuntimeStub = Omit<ThreadRuntimeCore, "composer"> & {
|
|
7
|
+
notify: () => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const makeRuntimeStub = (
|
|
11
|
+
overrides: Partial<ThreadRuntimeCore> = {},
|
|
12
|
+
): ThreadRuntimeStub => {
|
|
13
|
+
const subscribers = new Set<() => void>();
|
|
14
|
+
return {
|
|
15
|
+
append: vi.fn(),
|
|
16
|
+
cancelRun: vi.fn(),
|
|
17
|
+
getModelContext: () => ({}),
|
|
18
|
+
subscribe: (cb: () => void) => {
|
|
19
|
+
subscribers.add(cb);
|
|
20
|
+
return () => subscribers.delete(cb);
|
|
21
|
+
},
|
|
22
|
+
capabilities: { cancel: true },
|
|
23
|
+
messages: [],
|
|
24
|
+
isDisabled: false,
|
|
25
|
+
isSendDisabled: false,
|
|
26
|
+
isLoading: false,
|
|
27
|
+
composer: { runConfig: {} },
|
|
28
|
+
notify: () => {
|
|
29
|
+
for (const cb of subscribers) cb();
|
|
30
|
+
},
|
|
31
|
+
...overrides,
|
|
32
|
+
} as unknown as ThreadRuntimeStub;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const runningAssistant = {
|
|
36
|
+
id: "a1",
|
|
37
|
+
role: "assistant",
|
|
38
|
+
status: { type: "running" },
|
|
39
|
+
} as ThreadMessage;
|
|
40
|
+
|
|
41
|
+
describe("DefaultThreadComposerRuntimeCore.canCancel", () => {
|
|
42
|
+
it("is false when the runtime is idle even if cancel is supported", () => {
|
|
43
|
+
const composer = new DefaultThreadComposerRuntimeCore(makeRuntimeStub());
|
|
44
|
+
expect(composer.canCancel).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("is false when cancel is not a capability", () => {
|
|
48
|
+
const composer = new DefaultThreadComposerRuntimeCore(
|
|
49
|
+
makeRuntimeStub({
|
|
50
|
+
capabilities: { cancel: false },
|
|
51
|
+
isRunning: true,
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
expect(composer.canCancel).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("is true while the runtime reports isRunning", () => {
|
|
58
|
+
const composer = new DefaultThreadComposerRuntimeCore(
|
|
59
|
+
makeRuntimeStub({ isRunning: true }),
|
|
60
|
+
);
|
|
61
|
+
expect(composer.canCancel).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("is true while the trailing assistant message is running", () => {
|
|
65
|
+
const composer = new DefaultThreadComposerRuntimeCore(
|
|
66
|
+
makeRuntimeStub({ messages: [runningAssistant] }),
|
|
67
|
+
);
|
|
68
|
+
expect(composer.canCancel).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("stays false after a runtime notify while idle", () => {
|
|
72
|
+
const stub = makeRuntimeStub();
|
|
73
|
+
const composer = new DefaultThreadComposerRuntimeCore(stub);
|
|
74
|
+
stub.notify();
|
|
75
|
+
expect(composer.canCancel).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("notifies subscribers when a run starts", () => {
|
|
79
|
+
const stub = makeRuntimeStub();
|
|
80
|
+
const composer = new DefaultThreadComposerRuntimeCore(stub);
|
|
81
|
+
const onChange = vi.fn();
|
|
82
|
+
composer.subscribe(onChange);
|
|
83
|
+
|
|
84
|
+
(stub as { isRunning?: boolean }).isRunning = true;
|
|
85
|
+
stub.notify();
|
|
86
|
+
|
|
87
|
+
expect(onChange).toHaveBeenCalled();
|
|
88
|
+
expect(composer.canCancel).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("returns to false when the run ends", () => {
|
|
92
|
+
const stub = makeRuntimeStub({ isRunning: true });
|
|
93
|
+
const composer = new DefaultThreadComposerRuntimeCore(stub);
|
|
94
|
+
expect(composer.canCancel).toBe(true);
|
|
95
|
+
|
|
96
|
+
(stub as { isRunning?: boolean }).isRunning = false;
|
|
97
|
+
stub.notify();
|
|
98
|
+
|
|
99
|
+
expect(composer.canCancel).toBe(false);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
2
|
import { ExternalStoreThreadListRuntimeCore } from "../runtimes/external-store/external-store-thread-list-runtime-core";
|
|
3
3
|
import type { ExternalStoreThreadRuntimeCore } from "../runtimes/external-store/external-store-thread-runtime-core";
|
|
4
|
+
import { ExternalStoreThreadRuntimeCore as ExternalStoreThreadRuntimeCoreImpl } from "../runtimes/external-store/external-store-thread-runtime-core";
|
|
4
5
|
import type { ExternalStoreThreadListAdapter } from "../runtimes/external-store/external-store-adapter";
|
|
6
|
+
import type { ExternalStoreAdapter } from "../runtimes/external-store/external-store-adapter";
|
|
7
|
+
import type { ModelContextProvider } from "../model-context/types";
|
|
5
8
|
import { ThreadListRuntimeImpl } from "../runtime/api/thread-list-runtime";
|
|
6
9
|
|
|
7
10
|
const makeFactory = (overrides: Record<string, unknown> = {}) =>
|
|
@@ -18,6 +21,21 @@ const makeAdapter = (
|
|
|
18
21
|
overrides: Partial<ExternalStoreThreadListAdapter> = {},
|
|
19
22
|
): ExternalStoreThreadListAdapter => ({ ...overrides });
|
|
20
23
|
|
|
24
|
+
const mockContextProvider: ModelContextProvider = {
|
|
25
|
+
getModelContext: () => ({}),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const appendMessage = () => ({
|
|
29
|
+
parentId: null,
|
|
30
|
+
sourceId: null,
|
|
31
|
+
runConfig: {},
|
|
32
|
+
role: "user" as const,
|
|
33
|
+
content: [{ type: "text" as const, text: "hello" }],
|
|
34
|
+
attachments: [],
|
|
35
|
+
metadata: { custom: {} },
|
|
36
|
+
createdAt: new Date(0),
|
|
37
|
+
});
|
|
38
|
+
|
|
21
39
|
describe("ExternalStoreThreadListRuntimeCore - construction", () => {
|
|
22
40
|
it("assigns a resolvable fallback mainThreadId when adapter has no threadId", () => {
|
|
23
41
|
const core = new ExternalStoreThreadListRuntimeCore(
|
|
@@ -149,6 +167,26 @@ describe("ExternalStoreThreadListRuntimeCore - __internal_setAdapter", () => {
|
|
|
149
167
|
expect(callback).toHaveBeenCalled();
|
|
150
168
|
});
|
|
151
169
|
|
|
170
|
+
it("notifies later subscribers when an earlier subscriber throws", () => {
|
|
171
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
172
|
+
makeAdapter({ threadId: "thread-alpha" }),
|
|
173
|
+
makeFactory(),
|
|
174
|
+
);
|
|
175
|
+
const error = new Error("subscriber failed");
|
|
176
|
+
const laterSubscriber = vi.fn();
|
|
177
|
+
|
|
178
|
+
core.subscribe(() => {
|
|
179
|
+
throw error;
|
|
180
|
+
});
|
|
181
|
+
core.subscribe(laterSubscriber);
|
|
182
|
+
|
|
183
|
+
expect(() =>
|
|
184
|
+
core.__internal_setAdapter(makeAdapter({ threadId: "thread-beta" })),
|
|
185
|
+
).toThrow(error);
|
|
186
|
+
expect(core.mainThreadId).toBe("thread-beta");
|
|
187
|
+
expect(laterSubscriber).toHaveBeenCalledOnce();
|
|
188
|
+
});
|
|
189
|
+
|
|
152
190
|
it("synthesizes mainThreadId entry after a switch to a threadId not in the threads list", () => {
|
|
153
191
|
const core = new ExternalStoreThreadListRuntimeCore(
|
|
154
192
|
makeAdapter({ threadId: "thread-alpha" }),
|
|
@@ -175,6 +213,69 @@ describe("ExternalStoreThreadListRuntimeCore - __internal_setAdapter", () => {
|
|
|
175
213
|
"thread-gamma",
|
|
176
214
|
]);
|
|
177
215
|
});
|
|
216
|
+
|
|
217
|
+
it("dispatches an append before a thread switch", async () => {
|
|
218
|
+
let resolveInitialization!: () => void;
|
|
219
|
+
const initialization = new Promise<void>((resolve) => {
|
|
220
|
+
resolveInitialization = resolve;
|
|
221
|
+
});
|
|
222
|
+
const onNew = vi.fn(async () => {});
|
|
223
|
+
const firstRuntime = new ExternalStoreThreadRuntimeCoreImpl(
|
|
224
|
+
mockContextProvider,
|
|
225
|
+
{ messages: [], onNew } as ExternalStoreAdapter,
|
|
226
|
+
);
|
|
227
|
+
firstRuntime.__internal_setGetInitializePromise(() => initialization);
|
|
228
|
+
const secondRuntime = new ExternalStoreThreadRuntimeCoreImpl(
|
|
229
|
+
mockContextProvider,
|
|
230
|
+
{ messages: [], onNew: vi.fn() } as ExternalStoreAdapter,
|
|
231
|
+
);
|
|
232
|
+
const factory = vi
|
|
233
|
+
.fn()
|
|
234
|
+
.mockReturnValueOnce(firstRuntime)
|
|
235
|
+
.mockReturnValueOnce(secondRuntime);
|
|
236
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
237
|
+
makeAdapter({ threadId: "thread-alpha" }),
|
|
238
|
+
factory,
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const appendPromise = firstRuntime.append(appendMessage());
|
|
242
|
+
await Promise.resolve();
|
|
243
|
+
|
|
244
|
+
expect(onNew).toHaveBeenCalledTimes(1);
|
|
245
|
+
|
|
246
|
+
core.__internal_setAdapter(makeAdapter({ threadId: "thread-beta" }));
|
|
247
|
+
resolveInitialization();
|
|
248
|
+
|
|
249
|
+
await appendPromise;
|
|
250
|
+
expect(onNew).toHaveBeenCalledTimes(1);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
describe("ExternalStoreThreadListRuntimeCore - detach", () => {
|
|
255
|
+
it("leaves the main thread's pending append alone when an item detaches", async () => {
|
|
256
|
+
let resolveInitialization!: () => void;
|
|
257
|
+
const initialization = new Promise<void>((resolve) => {
|
|
258
|
+
resolveInitialization = resolve;
|
|
259
|
+
});
|
|
260
|
+
const onNew = vi.fn(async () => {});
|
|
261
|
+
const runtime = new ExternalStoreThreadRuntimeCoreImpl(
|
|
262
|
+
mockContextProvider,
|
|
263
|
+
{ messages: [], onNew } as ExternalStoreAdapter,
|
|
264
|
+
);
|
|
265
|
+
runtime.__internal_setGetInitializePromise(() => initialization);
|
|
266
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
267
|
+
makeAdapter(),
|
|
268
|
+
vi.fn(() => runtime),
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const appendPromise = runtime.append(appendMessage());
|
|
272
|
+
await Promise.resolve();
|
|
273
|
+
await core.detach();
|
|
274
|
+
resolveInitialization();
|
|
275
|
+
|
|
276
|
+
await appendPromise;
|
|
277
|
+
expect(onNew).toHaveBeenCalledTimes(1);
|
|
278
|
+
});
|
|
178
279
|
});
|
|
179
280
|
|
|
180
281
|
describe("ExternalStoreThreadListRuntimeCore - isMain via ThreadListRuntimeImpl", () => {
|