@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,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
ExternalStoreThreadRuntimeCore,
|
|
4
4
|
hasUpcomingMessage,
|
|
@@ -49,6 +49,23 @@ const createBaseAdapter = (
|
|
|
49
49
|
...overrides,
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
+
const captureUnhandledRejections = async (
|
|
53
|
+
run: () => Promise<void>,
|
|
54
|
+
): Promise<unknown[]> => {
|
|
55
|
+
const rejections: unknown[] = [];
|
|
56
|
+
const onUnhandledRejection = (reason: unknown) => {
|
|
57
|
+
rejections.push(reason);
|
|
58
|
+
};
|
|
59
|
+
process.on("unhandledRejection", onUnhandledRejection);
|
|
60
|
+
try {
|
|
61
|
+
await run();
|
|
62
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
63
|
+
} finally {
|
|
64
|
+
process.removeListener("unhandledRejection", onUnhandledRejection);
|
|
65
|
+
}
|
|
66
|
+
return rejections;
|
|
67
|
+
};
|
|
68
|
+
|
|
52
69
|
describe("ExternalStoreThreadRuntimeCore adapter contract", () => {
|
|
53
70
|
let contextProvider: ModelContextProvider;
|
|
54
71
|
|
|
@@ -56,6 +73,10 @@ describe("ExternalStoreThreadRuntimeCore adapter contract", () => {
|
|
|
56
73
|
contextProvider = createContextProvider();
|
|
57
74
|
});
|
|
58
75
|
|
|
76
|
+
afterEach(() => {
|
|
77
|
+
vi.restoreAllMocks();
|
|
78
|
+
});
|
|
79
|
+
|
|
59
80
|
it("hasUpcomingMessage is true only while running without an assistant tail", () => {
|
|
60
81
|
expect(hasUpcomingMessage(true, [createUserMessage("u1")])).toBe(true);
|
|
61
82
|
expect(hasUpcomingMessage(true, [createAssistantMessage("a1")])).toBe(
|
|
@@ -760,6 +781,175 @@ describe("ExternalStoreThreadRuntimeCore adapter contract", () => {
|
|
|
760
781
|
});
|
|
761
782
|
});
|
|
762
783
|
|
|
784
|
+
describe("tool callbacks", () => {
|
|
785
|
+
it("handles rejected automatic tool result callbacks", async () => {
|
|
786
|
+
const error = new Error("tool result failed");
|
|
787
|
+
const consoleError = vi
|
|
788
|
+
.spyOn(console, "error")
|
|
789
|
+
.mockImplementation(() => {});
|
|
790
|
+
const execute = vi.fn(async () => ({ forecast: "sunny" }));
|
|
791
|
+
let callbackCalls = 0;
|
|
792
|
+
const onAddToolResult = () => {
|
|
793
|
+
callbackCalls += 1;
|
|
794
|
+
return Promise.reject(error);
|
|
795
|
+
};
|
|
796
|
+
const core = new ExternalStoreThreadRuntimeCore(
|
|
797
|
+
{
|
|
798
|
+
getModelContext: () => ({
|
|
799
|
+
tools: {
|
|
800
|
+
weatherSearch: {
|
|
801
|
+
parameters: { type: "object", properties: {} },
|
|
802
|
+
execute,
|
|
803
|
+
},
|
|
804
|
+
},
|
|
805
|
+
}),
|
|
806
|
+
},
|
|
807
|
+
createBaseAdapter({
|
|
808
|
+
unstable_enableToolInvocations: true,
|
|
809
|
+
onAddToolResult,
|
|
810
|
+
}),
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
const rejections = await captureUnhandledRejections(async () => {
|
|
814
|
+
core.__internal_setAdapter(
|
|
815
|
+
createBaseAdapter({
|
|
816
|
+
unstable_enableToolInvocations: true,
|
|
817
|
+
isRunning: true,
|
|
818
|
+
messages: [
|
|
819
|
+
{
|
|
820
|
+
...createAssistantMessage("a1"),
|
|
821
|
+
status: { type: "requires-action", reason: "tool-calls" },
|
|
822
|
+
content: [
|
|
823
|
+
{
|
|
824
|
+
type: "tool-call",
|
|
825
|
+
toolCallId: "tc1",
|
|
826
|
+
toolName: "weatherSearch",
|
|
827
|
+
args: { city: "London" },
|
|
828
|
+
argsText: '{"city":"London"}',
|
|
829
|
+
},
|
|
830
|
+
],
|
|
831
|
+
},
|
|
832
|
+
],
|
|
833
|
+
onAddToolResult,
|
|
834
|
+
}),
|
|
835
|
+
);
|
|
836
|
+
|
|
837
|
+
await vi.waitFor(() =>
|
|
838
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
839
|
+
"[ExternalStoreThreadRuntimeCore] onAddToolResult callback rejected",
|
|
840
|
+
error,
|
|
841
|
+
),
|
|
842
|
+
);
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
expect(execute).toHaveBeenCalledOnce();
|
|
846
|
+
expect(callbackCalls).toBe(1);
|
|
847
|
+
expect(rejections).toEqual([]);
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
it("handles rejected direct tool result callbacks", async () => {
|
|
851
|
+
const error = new Error("tool result failed");
|
|
852
|
+
const consoleError = vi
|
|
853
|
+
.spyOn(console, "error")
|
|
854
|
+
.mockImplementation(() => {});
|
|
855
|
+
let callbackCalls = 0;
|
|
856
|
+
const core = new ExternalStoreThreadRuntimeCore(
|
|
857
|
+
contextProvider,
|
|
858
|
+
createBaseAdapter({
|
|
859
|
+
onAddToolResult: () => {
|
|
860
|
+
callbackCalls += 1;
|
|
861
|
+
return Promise.reject(error);
|
|
862
|
+
},
|
|
863
|
+
}),
|
|
864
|
+
);
|
|
865
|
+
|
|
866
|
+
const rejections = await captureUnhandledRejections(async () => {
|
|
867
|
+
core.addToolResult({
|
|
868
|
+
messageId: "m1",
|
|
869
|
+
toolName: "weatherSearch",
|
|
870
|
+
toolCallId: "tc1",
|
|
871
|
+
result: { forecast: "sunny" },
|
|
872
|
+
isError: false,
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
await vi.waitFor(() =>
|
|
876
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
877
|
+
"[ExternalStoreThreadRuntimeCore] onAddToolResult callback rejected",
|
|
878
|
+
error,
|
|
879
|
+
),
|
|
880
|
+
);
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
expect(callbackCalls).toBe(1);
|
|
884
|
+
expect(rejections).toEqual([]);
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
it("handles rejected onRespondToToolApproval callbacks", async () => {
|
|
888
|
+
const error = new Error("approval failed");
|
|
889
|
+
const consoleError = vi
|
|
890
|
+
.spyOn(console, "error")
|
|
891
|
+
.mockImplementation(() => {});
|
|
892
|
+
let callbackCalls = 0;
|
|
893
|
+
const core = new ExternalStoreThreadRuntimeCore(
|
|
894
|
+
contextProvider,
|
|
895
|
+
createBaseAdapter({
|
|
896
|
+
onRespondToToolApproval: () => {
|
|
897
|
+
callbackCalls += 1;
|
|
898
|
+
return Promise.reject(error);
|
|
899
|
+
},
|
|
900
|
+
}),
|
|
901
|
+
);
|
|
902
|
+
|
|
903
|
+
const rejections = await captureUnhandledRejections(async () => {
|
|
904
|
+
core.respondToToolApproval({
|
|
905
|
+
approvalId: "approval-1",
|
|
906
|
+
approved: true,
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
await vi.waitFor(() =>
|
|
910
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
911
|
+
"[ExternalStoreThreadRuntimeCore] onRespondToToolApproval callback rejected",
|
|
912
|
+
error,
|
|
913
|
+
),
|
|
914
|
+
);
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
expect(callbackCalls).toBe(1);
|
|
918
|
+
expect(rejections).toEqual([]);
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
it("handles rejected onCancel callbacks", async () => {
|
|
922
|
+
const error = new Error("cancel failed");
|
|
923
|
+
const consoleError = vi
|
|
924
|
+
.spyOn(console, "error")
|
|
925
|
+
.mockImplementation(() => {});
|
|
926
|
+
let callbackCalls = 0;
|
|
927
|
+
const core = new ExternalStoreThreadRuntimeCore(
|
|
928
|
+
contextProvider,
|
|
929
|
+
createBaseAdapter({
|
|
930
|
+
onCancel: () => {
|
|
931
|
+
callbackCalls += 1;
|
|
932
|
+
return Promise.reject(error);
|
|
933
|
+
},
|
|
934
|
+
}),
|
|
935
|
+
);
|
|
936
|
+
|
|
937
|
+
const rejections = await captureUnhandledRejections(async () => {
|
|
938
|
+
core.cancelRun();
|
|
939
|
+
|
|
940
|
+
await vi.waitFor(() =>
|
|
941
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
942
|
+
"[ExternalStoreThreadRuntimeCore] onCancel callback rejected",
|
|
943
|
+
error,
|
|
944
|
+
),
|
|
945
|
+
);
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
expect(callbackCalls).toBe(1);
|
|
949
|
+
expect(rejections).toEqual([]);
|
|
950
|
+
});
|
|
951
|
+
});
|
|
952
|
+
|
|
763
953
|
describe("messageRepository incremental sync", () => {
|
|
764
954
|
const u1 = createUserMessage("u1");
|
|
765
955
|
const a1 = createAssistantMessage("a1");
|
|
@@ -4,6 +4,7 @@ import type { ExternalStoreAdapter } from "../runtimes/external-store/external-s
|
|
|
4
4
|
import type { ModelContextProvider } from "../model-context/types";
|
|
5
5
|
import type { ThreadMessageLike } from "../runtime/utils/thread-message-like";
|
|
6
6
|
import type { AppendMessage } from "../types/message";
|
|
7
|
+
import { invalidateThreadRuntime } from "../runtime/utils/thread-runtime-lifecycle";
|
|
7
8
|
|
|
8
9
|
const mockContextProvider: ModelContextProvider = {
|
|
9
10
|
getModelContext: () => ({}),
|
|
@@ -868,6 +869,129 @@ describe("ExternalStoreThreadRuntimeCore - message queue", () => {
|
|
|
868
869
|
expect(withoutQueue.capabilities.queue).toBe(false);
|
|
869
870
|
});
|
|
870
871
|
|
|
872
|
+
it("waits for thread initialization before enqueueing into the queue adapter", async () => {
|
|
873
|
+
let resolveInitialization!: () => void;
|
|
874
|
+
const initialization = new Promise<void>((resolve) => {
|
|
875
|
+
resolveInitialization = resolve;
|
|
876
|
+
});
|
|
877
|
+
const queue = makeQueue();
|
|
878
|
+
const onNew = vi.fn(async () => {});
|
|
879
|
+
const runtime = new ExternalStoreThreadRuntimeCore(
|
|
880
|
+
mockContextProvider,
|
|
881
|
+
makeStore({ onNew, queue }),
|
|
882
|
+
);
|
|
883
|
+
runtime.__internal_setGetInitializePromise(() => initialization);
|
|
884
|
+
|
|
885
|
+
const appendPromise = runtime.append(appendMessage());
|
|
886
|
+
await Promise.resolve();
|
|
887
|
+
|
|
888
|
+
expect(queue.enqueue).not.toHaveBeenCalled();
|
|
889
|
+
|
|
890
|
+
resolveInitialization();
|
|
891
|
+
await appendPromise;
|
|
892
|
+
|
|
893
|
+
expect(queue.enqueue).toHaveBeenCalledTimes(1);
|
|
894
|
+
expect(onNew).not.toHaveBeenCalled();
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
it("does not enqueue when the thread is invalidated during initialization", async () => {
|
|
898
|
+
let resolveInitialization!: () => void;
|
|
899
|
+
const initialization = new Promise<void>((resolve) => {
|
|
900
|
+
resolveInitialization = resolve;
|
|
901
|
+
});
|
|
902
|
+
const queue = makeQueue();
|
|
903
|
+
const runtime = new ExternalStoreThreadRuntimeCore(
|
|
904
|
+
mockContextProvider,
|
|
905
|
+
makeStore({ onNew: vi.fn(), queue }),
|
|
906
|
+
);
|
|
907
|
+
runtime.__internal_setGetInitializePromise(() => initialization);
|
|
908
|
+
|
|
909
|
+
const appendPromise = runtime.append(appendMessage());
|
|
910
|
+
await Promise.resolve();
|
|
911
|
+
invalidateThreadRuntime(runtime);
|
|
912
|
+
resolveInitialization();
|
|
913
|
+
|
|
914
|
+
await appendPromise;
|
|
915
|
+
expect(queue.enqueue).not.toHaveBeenCalled();
|
|
916
|
+
expect(queue.steer).not.toHaveBeenCalled();
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
it("dispatches an append without waiting for thread initialization", async () => {
|
|
920
|
+
const initialization = new Promise<void>(() => {});
|
|
921
|
+
const getInitializePromise = vi.fn(() => initialization);
|
|
922
|
+
const onNew = vi.fn(async () => {});
|
|
923
|
+
const runtime = new ExternalStoreThreadRuntimeCore(
|
|
924
|
+
mockContextProvider,
|
|
925
|
+
makeStore({ onNew }),
|
|
926
|
+
);
|
|
927
|
+
runtime.__internal_setGetInitializePromise(getInitializePromise);
|
|
928
|
+
|
|
929
|
+
await runtime.append(appendMessage());
|
|
930
|
+
|
|
931
|
+
expect(onNew).toHaveBeenCalledTimes(1);
|
|
932
|
+
expect(getInitializePromise).toHaveBeenCalledTimes(1);
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
it("dispatches concurrent appends without waiting for initialization", async () => {
|
|
936
|
+
const initialization = new Promise<void>(() => {});
|
|
937
|
+
const onNew = vi.fn(async () => {});
|
|
938
|
+
const runtime = new ExternalStoreThreadRuntimeCore(
|
|
939
|
+
mockContextProvider,
|
|
940
|
+
makeStore({ onNew }),
|
|
941
|
+
);
|
|
942
|
+
runtime.__internal_setGetInitializePromise(() => initialization);
|
|
943
|
+
|
|
944
|
+
await Promise.all([
|
|
945
|
+
runtime.append(appendMessage()),
|
|
946
|
+
runtime.append(appendMessage()),
|
|
947
|
+
]);
|
|
948
|
+
|
|
949
|
+
expect(onNew).toHaveBeenCalledTimes(2);
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
it("does not fail the append when thread initialization rejects", async () => {
|
|
953
|
+
const initialization = Promise.reject(new Error("initialization failed"));
|
|
954
|
+
const onNew = vi.fn(async () => {});
|
|
955
|
+
const runtime = new ExternalStoreThreadRuntimeCore(
|
|
956
|
+
mockContextProvider,
|
|
957
|
+
makeStore({ onNew }),
|
|
958
|
+
);
|
|
959
|
+
runtime.__internal_setGetInitializePromise(() => initialization);
|
|
960
|
+
|
|
961
|
+
await runtime.append(appendMessage());
|
|
962
|
+
|
|
963
|
+
expect(onNew).toHaveBeenCalledTimes(1);
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
it("drops an append disposed while aborting client-side tools", async () => {
|
|
967
|
+
let resolveAbort!: () => void;
|
|
968
|
+
const abortPromise = new Promise<void>((resolve) => {
|
|
969
|
+
resolveAbort = resolve;
|
|
970
|
+
});
|
|
971
|
+
const onNew = vi.fn(async () => {});
|
|
972
|
+
const runtime = new ExternalStoreThreadRuntimeCore(
|
|
973
|
+
mockContextProvider,
|
|
974
|
+
makeStore({ onNew }),
|
|
975
|
+
);
|
|
976
|
+
runtime.__internal_setGetInitializePromise(() => Promise.resolve());
|
|
977
|
+
const abort = vi.fn(() => abortPromise);
|
|
978
|
+
(
|
|
979
|
+
runtime as unknown as { _toolInvocations: { abort: typeof abort } }
|
|
980
|
+
)._toolInvocations = {
|
|
981
|
+
abort,
|
|
982
|
+
};
|
|
983
|
+
|
|
984
|
+
const appendPromise = runtime.append(appendMessage());
|
|
985
|
+
await Promise.resolve();
|
|
986
|
+
expect(abort).toHaveBeenCalledOnce();
|
|
987
|
+
|
|
988
|
+
invalidateThreadRuntime(runtime);
|
|
989
|
+
resolveAbort();
|
|
990
|
+
|
|
991
|
+
await appendPromise;
|
|
992
|
+
expect(onNew).not.toHaveBeenCalled();
|
|
993
|
+
});
|
|
994
|
+
|
|
871
995
|
it("routes a tail append through the queue adapter instead of onNew", async () => {
|
|
872
996
|
const queue = makeQueue();
|
|
873
997
|
const onNew = vi.fn();
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { act, cleanup, render } from "@testing-library/react";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { withKey } from "@assistant-ui/tap";
|
|
6
|
+
import { useAui } from "@assistant-ui/store";
|
|
7
|
+
import { Tools } from "../react/client/Tools";
|
|
8
|
+
import { unstable_Interactables } from "../react/client/Interactables";
|
|
9
|
+
|
|
10
|
+
type AnyClient = Record<string, any>;
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
cleanup();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("interactables update-tool UI registration", () => {
|
|
17
|
+
it("migrates to a structurally replaced tools scope", async () => {
|
|
18
|
+
let aui!: AnyClient;
|
|
19
|
+
const Harness = ({ generation }: { generation: number }) => {
|
|
20
|
+
aui = useAui({
|
|
21
|
+
tools: withKey(String(generation), Tools({})),
|
|
22
|
+
unstable_interactables: unstable_Interactables({}),
|
|
23
|
+
} as never);
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
26
|
+
const view = render(<Harness generation={0} />);
|
|
27
|
+
|
|
28
|
+
const toolUIs = () =>
|
|
29
|
+
(aui.tools().getState().toolUIs ?? {}) as Record<string, unknown[]>;
|
|
30
|
+
// setToolUI lands after the tap scheduler drains its macrotask
|
|
31
|
+
await act(async () => {
|
|
32
|
+
aui.unstable_interactables.register({
|
|
33
|
+
id: "call-1",
|
|
34
|
+
name: "note",
|
|
35
|
+
description: "a note",
|
|
36
|
+
stateSchema: { type: "object", properties: {} },
|
|
37
|
+
initialState: {},
|
|
38
|
+
updateRender: () => null,
|
|
39
|
+
});
|
|
40
|
+
await vi.waitFor(() => expect(Object.keys(toolUIs())).toHaveLength(1));
|
|
41
|
+
});
|
|
42
|
+
const [toolName] = Object.keys(toolUIs());
|
|
43
|
+
const firstRegistration = toolUIs()[toolName!]![0];
|
|
44
|
+
|
|
45
|
+
// A rerender inside an outer act would not land until that act exits,
|
|
46
|
+
// so the swap happens first and only the scheduler wait is wrapped
|
|
47
|
+
view.rerender(<Harness generation={1} />);
|
|
48
|
+
|
|
49
|
+
// The remounted tools scope starts from fresh state; a registration
|
|
50
|
+
// object distinct from the pre-swap one proves the retained entry was
|
|
51
|
+
// re-applied on the replacement instance rather than read stale. It
|
|
52
|
+
// lands one scheduler macrotask after the swap, once the tap scheduler
|
|
53
|
+
// drains.
|
|
54
|
+
await act(async () => {
|
|
55
|
+
await vi.waitFor(() => {
|
|
56
|
+
const registration = toolUIs()[toolName!]?.[0];
|
|
57
|
+
expect(registration).toBeDefined();
|
|
58
|
+
expect(registration).not.toBe(firstRegistration);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Post-settle cardinality: a duplicate re-apply would leave a second
|
|
63
|
+
// registration whose disposer was dropped
|
|
64
|
+
expect(toolUIs()[toolName!]).toHaveLength(1);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -612,6 +612,34 @@ describe("createMessageQueue", () => {
|
|
|
612
612
|
expect(cb).toHaveBeenCalled();
|
|
613
613
|
});
|
|
614
614
|
|
|
615
|
+
it("isolates subscriber errors while enqueueing", () => {
|
|
616
|
+
const run = vi.fn();
|
|
617
|
+
const { adapter, subscribe } = createMessageQueue({ run });
|
|
618
|
+
const error = new Error("subscriber failed");
|
|
619
|
+
const laterSubscriber = vi.fn();
|
|
620
|
+
const consoleError = vi
|
|
621
|
+
.spyOn(console, "error")
|
|
622
|
+
.mockImplementation(() => {});
|
|
623
|
+
|
|
624
|
+
subscribe(() => {
|
|
625
|
+
throw error;
|
|
626
|
+
});
|
|
627
|
+
subscribe(laterSubscriber);
|
|
628
|
+
|
|
629
|
+
try {
|
|
630
|
+
expect(() => adapter.enqueue(msg("a"), { steer: false })).not.toThrow();
|
|
631
|
+
expect(run).toHaveBeenCalledTimes(1);
|
|
632
|
+
expect(adapter.items).toHaveLength(0);
|
|
633
|
+
expect(laterSubscriber).toHaveBeenCalledTimes(2);
|
|
634
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
635
|
+
"[assistant-ui] Message queue listener threw an error",
|
|
636
|
+
error,
|
|
637
|
+
);
|
|
638
|
+
} finally {
|
|
639
|
+
consoleError.mockRestore();
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
|
|
615
643
|
it("buffers when a run started outside the queue is marked busy", () => {
|
|
616
644
|
const run = vi.fn();
|
|
617
645
|
const { adapter, notifyBusy, notifyIdle } = createMessageQueue({ run });
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { ExternalStoreRuntimeCore } from "../runtimes/external-store/external-store-runtime-core";
|
|
3
|
+
import { LocalRuntimeCore } from "../runtimes/local/local-runtime-core";
|
|
4
|
+
import type { ChatModelAdapter } from "../runtime/utils/chat-model-adapter";
|
|
5
|
+
import type { ThreadMessage } from "../types/message";
|
|
6
|
+
|
|
7
|
+
async function waitFor(
|
|
8
|
+
predicate: () => unknown,
|
|
9
|
+
timeoutMs = 500,
|
|
10
|
+
): Promise<void> {
|
|
11
|
+
const start = Date.now();
|
|
12
|
+
while (Date.now() - start < timeoutMs) {
|
|
13
|
+
try {
|
|
14
|
+
await predicate();
|
|
15
|
+
return;
|
|
16
|
+
} catch {
|
|
17
|
+
// retry
|
|
18
|
+
}
|
|
19
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
20
|
+
}
|
|
21
|
+
await predicate();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const trailingUserMessage = {
|
|
25
|
+
id: "u1",
|
|
26
|
+
role: "user",
|
|
27
|
+
createdAt: new Date(),
|
|
28
|
+
content: [{ type: "text", text: "draft in flight" }],
|
|
29
|
+
attachments: [],
|
|
30
|
+
metadata: { custom: {} },
|
|
31
|
+
} as ThreadMessage;
|
|
32
|
+
|
|
33
|
+
const toolCallMessage = {
|
|
34
|
+
id: "a1",
|
|
35
|
+
role: "assistant",
|
|
36
|
+
createdAt: new Date(),
|
|
37
|
+
status: { type: "requires-action", reason: "tool-calls" },
|
|
38
|
+
metadata: {
|
|
39
|
+
unstable_state: null,
|
|
40
|
+
unstable_annotations: [],
|
|
41
|
+
unstable_data: [],
|
|
42
|
+
steps: [],
|
|
43
|
+
custom: {},
|
|
44
|
+
},
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "tool-call",
|
|
48
|
+
toolCallId: "tool-1",
|
|
49
|
+
toolName: "send_email",
|
|
50
|
+
args: { to: "dev@example.com" },
|
|
51
|
+
argsText: '{"to":"dev@example.com"}',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
} as unknown as ThreadMessage;
|
|
55
|
+
|
|
56
|
+
const externalThread = () => {
|
|
57
|
+
const setToolStatuses = vi.fn();
|
|
58
|
+
const setMessages = vi.fn();
|
|
59
|
+
const onCancel = vi.fn();
|
|
60
|
+
const notifyCancelled = vi.fn();
|
|
61
|
+
const store = {
|
|
62
|
+
messages: [trailingUserMessage] as ThreadMessage[],
|
|
63
|
+
onNew: vi.fn(async () => {}),
|
|
64
|
+
onCancel,
|
|
65
|
+
setMessages,
|
|
66
|
+
unstable_enableToolInvocations: true,
|
|
67
|
+
setToolStatuses,
|
|
68
|
+
queue: {
|
|
69
|
+
__internal_notifyCancelled: notifyCancelled,
|
|
70
|
+
} as never,
|
|
71
|
+
};
|
|
72
|
+
const core = new ExternalStoreRuntimeCore(store);
|
|
73
|
+
core.registerModelContextProvider({
|
|
74
|
+
getModelContext: () => ({
|
|
75
|
+
tools: {
|
|
76
|
+
send_email: {
|
|
77
|
+
parameters: { type: "object", properties: {} },
|
|
78
|
+
execute: vi.fn(() => new Promise(() => {})),
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
core,
|
|
85
|
+
store,
|
|
86
|
+
thread: core.threads.getMainThreadRuntimeCore(),
|
|
87
|
+
setToolStatuses,
|
|
88
|
+
setMessages,
|
|
89
|
+
onCancel,
|
|
90
|
+
notifyCancelled,
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const driveExecutingTool = async (
|
|
95
|
+
harness: ReturnType<typeof externalThread>,
|
|
96
|
+
) => {
|
|
97
|
+
harness.core.setAdapter({
|
|
98
|
+
...harness.store,
|
|
99
|
+
messages: [trailingUserMessage, toolCallMessage],
|
|
100
|
+
});
|
|
101
|
+
await waitFor(() => {
|
|
102
|
+
const statuses = harness.setToolStatuses.mock.lastCall?.[0] as
|
|
103
|
+
| Record<string, { type: string }>
|
|
104
|
+
| undefined;
|
|
105
|
+
expect(statuses?.["tool-1"]?.type).toBe("executing");
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
describe("unstable_notifySessionReset", () => {
|
|
110
|
+
it("clears session-scoped tool state once and parks queued work", async () => {
|
|
111
|
+
const harness = externalThread();
|
|
112
|
+
await driveExecutingTool(harness);
|
|
113
|
+
|
|
114
|
+
harness.setToolStatuses.mockClear();
|
|
115
|
+
harness.thread.unstable_notifySessionReset();
|
|
116
|
+
|
|
117
|
+
expect(harness.setToolStatuses).toHaveBeenCalledTimes(1);
|
|
118
|
+
expect(harness.setToolStatuses).toHaveBeenLastCalledWith({});
|
|
119
|
+
expect(harness.notifyCancelled).toHaveBeenCalledTimes(1);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("carries no run-cancel semantics", async () => {
|
|
123
|
+
const harness = externalThread();
|
|
124
|
+
await driveExecutingTool(harness);
|
|
125
|
+
|
|
126
|
+
harness.thread.unstable_notifySessionReset();
|
|
127
|
+
|
|
128
|
+
expect(harness.onCancel).not.toHaveBeenCalled();
|
|
129
|
+
expect(harness.setMessages).not.toHaveBeenCalled();
|
|
130
|
+
expect(harness.thread.messages.at(-1)?.id).toBe("a1");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("throws on runtimes without a backing session", () => {
|
|
134
|
+
const local = new LocalRuntimeCore(
|
|
135
|
+
{
|
|
136
|
+
adapters: { chatModel: { async *run() {} } satisfies ChatModelAdapter },
|
|
137
|
+
},
|
|
138
|
+
undefined,
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
expect(() =>
|
|
142
|
+
local.threads.getMainThreadRuntimeCore().unstable_notifySessionReset(),
|
|
143
|
+
).toThrow("Runtime does not support resetting sessions.");
|
|
144
|
+
});
|
|
145
|
+
});
|