@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
package/src/adapters/voice.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Unsubscribe } from "../types/unsubscribe";
|
|
2
|
+
import { notifyEventListeners } from "../utils/notify-event-listeners";
|
|
2
3
|
|
|
3
4
|
export namespace RealtimeVoiceAdapter {
|
|
4
5
|
export type Status =
|
|
@@ -57,22 +58,6 @@ export type VoiceSessionHelpers = {
|
|
|
57
58
|
isDisposed: () => boolean;
|
|
58
59
|
};
|
|
59
60
|
|
|
60
|
-
const notifyListeners = <T>(
|
|
61
|
-
listeners: ReadonlySet<(value: T) => void>,
|
|
62
|
-
value: T,
|
|
63
|
-
) => {
|
|
64
|
-
for (const listener of listeners) {
|
|
65
|
-
try {
|
|
66
|
-
listener(value);
|
|
67
|
-
} catch (error) {
|
|
68
|
-
console.error(
|
|
69
|
-
"[assistant-ui] Voice session listener threw an error",
|
|
70
|
-
error,
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
61
|
export function createVoiceSession(
|
|
77
62
|
options: { abortSignal?: AbortSignal },
|
|
78
63
|
setup: (helpers: VoiceSessionHelpers) => Promise<VoiceSessionControls>,
|
|
@@ -87,7 +72,17 @@ export function createVoiceSession(
|
|
|
87
72
|
let currentStatus: RealtimeVoiceAdapter.Status = { type: "starting" };
|
|
88
73
|
let isMuted = false;
|
|
89
74
|
let disposed = false;
|
|
75
|
+
let disconnected = false;
|
|
90
76
|
let controls: VoiceSessionControls | null = null;
|
|
77
|
+
const abortSignal = options.abortSignal;
|
|
78
|
+
let abortHandler: (() => void) | undefined;
|
|
79
|
+
|
|
80
|
+
const detachAbortHandler = () => {
|
|
81
|
+
if (abortHandler) {
|
|
82
|
+
abortSignal?.removeEventListener("abort", abortHandler);
|
|
83
|
+
abortHandler = undefined;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
91
86
|
|
|
92
87
|
const cleanup = () => {
|
|
93
88
|
disposed = true;
|
|
@@ -101,25 +96,25 @@ export function createVoiceSession(
|
|
|
101
96
|
setStatus: (status) => {
|
|
102
97
|
if (disposed) return;
|
|
103
98
|
currentStatus = status;
|
|
104
|
-
|
|
99
|
+
notifyEventListeners(statusCbs, status, "Voice session");
|
|
105
100
|
},
|
|
106
101
|
end: (reason, error?) => {
|
|
107
102
|
if (disposed) return;
|
|
108
103
|
currentStatus = { type: "ended", reason, error };
|
|
109
|
-
|
|
104
|
+
notifyEventListeners(statusCbs, currentStatus, "Voice session");
|
|
110
105
|
cleanup();
|
|
111
106
|
},
|
|
112
107
|
emitTranscript: (item) => {
|
|
113
108
|
if (disposed) return;
|
|
114
|
-
|
|
109
|
+
notifyEventListeners(transcriptCbs, item, "Voice session");
|
|
115
110
|
},
|
|
116
111
|
emitMode: (mode) => {
|
|
117
112
|
if (disposed) return;
|
|
118
|
-
|
|
113
|
+
notifyEventListeners(modeCbs, mode, "Voice session");
|
|
119
114
|
},
|
|
120
115
|
emitVolume: (volume) => {
|
|
121
116
|
if (disposed) return;
|
|
122
|
-
|
|
117
|
+
notifyEventListeners(volumeCbs, volume, "Voice session");
|
|
123
118
|
},
|
|
124
119
|
isDisposed: () => disposed,
|
|
125
120
|
};
|
|
@@ -132,8 +127,14 @@ export function createVoiceSession(
|
|
|
132
127
|
return isMuted;
|
|
133
128
|
},
|
|
134
129
|
disconnect: () => {
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
if (disconnected) return;
|
|
131
|
+
disconnected = true;
|
|
132
|
+
detachAbortHandler();
|
|
133
|
+
try {
|
|
134
|
+
controls?.disconnect();
|
|
135
|
+
} finally {
|
|
136
|
+
cleanup();
|
|
137
|
+
}
|
|
137
138
|
},
|
|
138
139
|
mute: () => {
|
|
139
140
|
controls?.mute();
|
|
@@ -161,10 +162,9 @@ export function createVoiceSession(
|
|
|
161
162
|
},
|
|
162
163
|
};
|
|
163
164
|
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
});
|
|
165
|
+
if (abortSignal) {
|
|
166
|
+
abortHandler = () => session.disconnect();
|
|
167
|
+
abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
const doSetup = async () => {
|
package/src/index.ts
CHANGED
|
@@ -144,4 +144,27 @@ describe("AssistantFrameHost", () => {
|
|
|
144
144
|
);
|
|
145
145
|
expect(postMessage).toHaveBeenCalledOnce();
|
|
146
146
|
});
|
|
147
|
+
|
|
148
|
+
it("isolates subscriber errors while applying context updates", () => {
|
|
149
|
+
const { dispatchMessage, host } = createHost();
|
|
150
|
+
const error = new Error("subscriber failed");
|
|
151
|
+
const laterSubscriber = vi.fn();
|
|
152
|
+
|
|
153
|
+
host.subscribe(() => {
|
|
154
|
+
throw error;
|
|
155
|
+
});
|
|
156
|
+
host.subscribe(laterSubscriber);
|
|
157
|
+
|
|
158
|
+
expect(() =>
|
|
159
|
+
dispatchMessage({
|
|
160
|
+
type: "model-context-update",
|
|
161
|
+
context: { system: "frame instructions" },
|
|
162
|
+
}),
|
|
163
|
+
).toThrow(error);
|
|
164
|
+
|
|
165
|
+
expect(host.getModelContext().system).toBe("frame instructions");
|
|
166
|
+
expect(laterSubscriber).toHaveBeenCalledOnce();
|
|
167
|
+
|
|
168
|
+
host.dispose();
|
|
169
|
+
});
|
|
147
170
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ModelContextProvider, ModelContext } from "../types";
|
|
2
2
|
import type { Unsubscribe } from "../../types/unsubscribe";
|
|
3
3
|
import type { Tool } from "assistant-stream";
|
|
4
|
+
import { notifySubscribers as notifyStateSubscribers } from "../../subscribable/subscribable";
|
|
4
5
|
import {
|
|
5
6
|
type FrameMessage,
|
|
6
7
|
FRAME_MESSAGE_CHANNEL,
|
|
@@ -207,7 +208,7 @@ export class AssistantFrameHost implements ModelContextProvider {
|
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
private notifySubscribers() {
|
|
210
|
-
this._subscribers
|
|
211
|
+
notifyStateSubscribers(this._subscribers);
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
getModelContext(): ModelContext {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { ModelContextRegistry } from "./registry";
|
|
3
|
+
|
|
4
|
+
describe("ModelContextRegistry", () => {
|
|
5
|
+
it("notifies every subscriber and rethrows when a registration subscriber throws", () => {
|
|
6
|
+
const registry = new ModelContextRegistry();
|
|
7
|
+
const error = new Error("subscriber failed");
|
|
8
|
+
const laterSubscriber = vi.fn();
|
|
9
|
+
|
|
10
|
+
registry.subscribe(() => {
|
|
11
|
+
throw error;
|
|
12
|
+
});
|
|
13
|
+
registry.subscribe(laterSubscriber);
|
|
14
|
+
|
|
15
|
+
expect(() => registry.addTool({ toolName: "search" })).toThrow(error);
|
|
16
|
+
|
|
17
|
+
expect(registry.getModelContext().tools).toHaveProperty("search");
|
|
18
|
+
expect(laterSubscriber).toHaveBeenCalledTimes(1);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("keeps a provider registered when a registration subscriber throws", () => {
|
|
22
|
+
const registry = new ModelContextRegistry();
|
|
23
|
+
const error = new Error("subscriber failed");
|
|
24
|
+
const laterSubscriber = vi.fn();
|
|
25
|
+
|
|
26
|
+
registry.subscribe(() => {
|
|
27
|
+
throw error;
|
|
28
|
+
});
|
|
29
|
+
registry.subscribe(laterSubscriber);
|
|
30
|
+
|
|
31
|
+
expect(() =>
|
|
32
|
+
registry.addProvider({
|
|
33
|
+
getModelContext: () => ({ system: "provider instructions" }),
|
|
34
|
+
}),
|
|
35
|
+
).toThrow(error);
|
|
36
|
+
|
|
37
|
+
expect(registry.getModelContext().system).toBe("provider instructions");
|
|
38
|
+
expect(laterSubscriber).toHaveBeenCalledTimes(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("notifies every subscriber and rethrows when registering instructions", () => {
|
|
42
|
+
const registry = new ModelContextRegistry();
|
|
43
|
+
const error = new Error("subscriber failed");
|
|
44
|
+
const laterSubscriber = vi.fn();
|
|
45
|
+
|
|
46
|
+
registry.subscribe(() => {
|
|
47
|
+
throw error;
|
|
48
|
+
});
|
|
49
|
+
registry.subscribe(laterSubscriber);
|
|
50
|
+
|
|
51
|
+
expect(() => registry.addInstruction("be concise")).toThrow(error);
|
|
52
|
+
|
|
53
|
+
expect(registry.getModelContext().system).toContain("be concise");
|
|
54
|
+
expect(laterSubscriber).toHaveBeenCalledTimes(1);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("rethrows the provider subscription failure when a rollback subscriber throws", () => {
|
|
58
|
+
const registry = new ModelContextRegistry();
|
|
59
|
+
const subscriptionError = new Error("subscription failed");
|
|
60
|
+
const subscriberError = new Error("subscriber failed");
|
|
61
|
+
const consoleError = vi
|
|
62
|
+
.spyOn(console, "error")
|
|
63
|
+
.mockImplementation(() => {});
|
|
64
|
+
|
|
65
|
+
registry.subscribe(() => {
|
|
66
|
+
throw subscriberError;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
expect(() =>
|
|
71
|
+
registry.addProvider({
|
|
72
|
+
getModelContext: () => ({ system: "provider instructions" }),
|
|
73
|
+
subscribe: () => {
|
|
74
|
+
throw subscriptionError;
|
|
75
|
+
},
|
|
76
|
+
}),
|
|
77
|
+
).toThrow(subscriptionError);
|
|
78
|
+
|
|
79
|
+
expect(registry.getModelContext().system).toBeUndefined();
|
|
80
|
+
expect(consoleError).toHaveBeenCalledWith(subscriberError);
|
|
81
|
+
} finally {
|
|
82
|
+
consoleError.mockRestore();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("rolls back providers that fail to subscribe", () => {
|
|
87
|
+
const registry = new ModelContextRegistry();
|
|
88
|
+
const error = new Error("subscription failed");
|
|
89
|
+
const observedSystems: Array<string | undefined> = [];
|
|
90
|
+
|
|
91
|
+
registry.subscribe(() => {
|
|
92
|
+
observedSystems.push(registry.getModelContext().system);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(() =>
|
|
96
|
+
registry.addProvider({
|
|
97
|
+
getModelContext: () => ({ system: "provider instructions" }),
|
|
98
|
+
subscribe: (callback) => {
|
|
99
|
+
callback();
|
|
100
|
+
throw error;
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
).toThrow(error);
|
|
104
|
+
|
|
105
|
+
expect(registry.getModelContext().system).toBeUndefined();
|
|
106
|
+
expect(observedSystems).toEqual(["provider instructions", undefined]);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("notifies every subscriber and rethrows on provider updates", () => {
|
|
110
|
+
const registry = new ModelContextRegistry();
|
|
111
|
+
const error = new Error("subscriber failed");
|
|
112
|
+
const laterSubscriber = vi.fn();
|
|
113
|
+
let publishUpdate = () => {};
|
|
114
|
+
|
|
115
|
+
registry.addProvider({
|
|
116
|
+
getModelContext: () => ({ system: "provider instructions" }),
|
|
117
|
+
subscribe: (callback) => {
|
|
118
|
+
publishUpdate = callback;
|
|
119
|
+
return () => {};
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
registry.subscribe(() => {
|
|
124
|
+
throw error;
|
|
125
|
+
});
|
|
126
|
+
registry.subscribe(laterSubscriber);
|
|
127
|
+
|
|
128
|
+
expect(() => publishUpdate()).toThrow(error);
|
|
129
|
+
expect(laterSubscriber).toHaveBeenCalledTimes(1);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type AssistantInstructionsConfig,
|
|
8
8
|
} from "./types";
|
|
9
9
|
import type { Unsubscribe } from "../types/unsubscribe";
|
|
10
|
+
import { notifySubscribers as notifyStateSubscribers } from "../subscribable/subscribable";
|
|
10
11
|
import type {
|
|
11
12
|
ModelContextRegistryToolHandle,
|
|
12
13
|
ModelContextRegistryInstructionHandle,
|
|
@@ -75,9 +76,7 @@ export class ModelContextRegistry implements ModelContextProvider {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
private notifySubscribers(): void {
|
|
78
|
-
|
|
79
|
-
callback();
|
|
80
|
-
}
|
|
79
|
+
notifyStateSubscribers(this._subscribers);
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
addTool<TArgs extends Record<string, unknown>, TResult>(
|
|
@@ -144,9 +143,20 @@ export class ModelContextRegistry implements ModelContextProvider {
|
|
|
144
143
|
|
|
145
144
|
this._providers.set(id, provider);
|
|
146
145
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
let unsubscribe: Unsubscribe | undefined;
|
|
147
|
+
try {
|
|
148
|
+
unsubscribe = provider.subscribe?.(() => {
|
|
149
|
+
this.notifySubscribers();
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
this._providers.delete(id);
|
|
153
|
+
try {
|
|
154
|
+
this.notifySubscribers();
|
|
155
|
+
} catch (notifyError) {
|
|
156
|
+
console.error(notifyError);
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
150
160
|
this._providerUnsubscribes.set(id, unsubscribe);
|
|
151
161
|
|
|
152
162
|
this.notifySubscribers();
|
|
@@ -54,6 +54,7 @@ describe("RuntimeAdapter via the neutral store entry", () => {
|
|
|
54
54
|
const handle = createAssistantClient(
|
|
55
55
|
AuiConfig({ threads: RuntimeAdapter(runtime) }),
|
|
56
56
|
);
|
|
57
|
+
handle.subscribe(() => {});
|
|
57
58
|
const aui = handle.getClient();
|
|
58
59
|
|
|
59
60
|
flushTapSync(() => aui.composer.setText("hello"));
|
|
@@ -75,6 +76,7 @@ describe("RuntimeAdapter via the neutral store entry", () => {
|
|
|
75
76
|
const handle = createAssistantClient(
|
|
76
77
|
AuiConfig({ threads: RuntimeAdapter(runtime) }),
|
|
77
78
|
);
|
|
79
|
+
handle.subscribe(() => {});
|
|
78
80
|
|
|
79
81
|
// Dev mode double-mounts the root (StrictMode emulation), so assert
|
|
80
82
|
// presence rather than an exact count
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
1
|
import { useResource, resource } from "@assistant-ui/tap";
|
|
2
|
+
import type { AssistantClient, ScopesConfig } from "@assistant-ui/store";
|
|
3
3
|
import type { AssistantRuntime } from "..";
|
|
4
4
|
import {
|
|
5
5
|
baseRuntimeAdapterTransformScopes,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
attachTransformScopes,
|
|
10
10
|
useAssistantClientRef,
|
|
11
|
+
useAssistantScopeEffect,
|
|
11
12
|
} from "@assistant-ui/store/client";
|
|
12
13
|
import { DataRenderers } from "./client/DataRenderers";
|
|
13
14
|
import { Tools } from "./client/Tools";
|
|
@@ -15,11 +16,12 @@ import { Tools } from "./client/Tools";
|
|
|
15
16
|
const useRuntimeAdapter = (runtime: AssistantRuntime) => {
|
|
16
17
|
const clientRef = useAssistantClientRef();
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
useAssistantScopeEffect(
|
|
20
|
+
"modelContext",
|
|
21
|
+
() =>
|
|
22
|
+
runtime.registerModelContextProvider(clientRef.current!.modelContext()),
|
|
23
|
+
[runtime],
|
|
24
|
+
);
|
|
23
25
|
|
|
24
26
|
return useResource(
|
|
25
27
|
ThreadListClient({
|
|
@@ -31,7 +33,15 @@ const useRuntimeAdapter = (runtime: AssistantRuntime) => {
|
|
|
31
33
|
|
|
32
34
|
export const RuntimeAdapter = resource(useRuntimeAdapter);
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
/**
|
|
37
|
+
* The scope defaults `RuntimeAdapter` installs when it is used as the `threads`
|
|
38
|
+
* config entry. Adapter packages that wrap a runtime in their own config entry
|
|
39
|
+
* attach this to the wrapping resource for scope parity with `RuntimeAdapter`.
|
|
40
|
+
*/
|
|
41
|
+
export const runtimeAdapterTransformScopes = (
|
|
42
|
+
scopes: ScopesConfig,
|
|
43
|
+
parent: AssistantClient,
|
|
44
|
+
): void => {
|
|
35
45
|
baseRuntimeAdapterTransformScopes(scopes, parent);
|
|
36
46
|
|
|
37
47
|
if (!scopes.tools && parent.tools.source === null) {
|
|
@@ -41,4 +51,6 @@ attachTransformScopes(useRuntimeAdapter, (scopes, parent) => {
|
|
|
41
51
|
if (!scopes.dataRenderers && parent.dataRenderers.source === null) {
|
|
42
52
|
scopes.dataRenderers = DataRenderers();
|
|
43
53
|
}
|
|
44
|
-
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
attachTransformScopes(useRuntimeAdapter, runtimeAdapterTransformScopes);
|
|
@@ -21,7 +21,10 @@ import type {
|
|
|
21
21
|
ExportedMessageRepository,
|
|
22
22
|
ExportedMessageRepositoryItem,
|
|
23
23
|
} from "../../internal";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
RuntimeAdapterProvider,
|
|
26
|
+
type RuntimeAdapters,
|
|
27
|
+
} from "../runtimes/RuntimeAdapterProvider";
|
|
25
28
|
import type { TitleGenerationAdapter } from "./TitleGenerationAdapter";
|
|
26
29
|
|
|
27
30
|
export type AsyncStorageLike = {
|
|
@@ -338,29 +341,40 @@ class AsyncStorageHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
338
341
|
}
|
|
339
342
|
}
|
|
340
343
|
|
|
344
|
+
const useLocalStorageThreadAdapters = (
|
|
345
|
+
storage: AsyncStorageLike,
|
|
346
|
+
prefix: string,
|
|
347
|
+
mutationQueue: KeyedMutationQueue,
|
|
348
|
+
): RuntimeAdapters => {
|
|
349
|
+
const aui = useAui();
|
|
350
|
+
// Not useEffectEvent: history adapter methods run during render (SSR load).
|
|
351
|
+
const auiRef = useRef(aui);
|
|
352
|
+
useEffect(() => {
|
|
353
|
+
auiRef.current = aui;
|
|
354
|
+
});
|
|
355
|
+
const [history] = useState(
|
|
356
|
+
() =>
|
|
357
|
+
new AsyncStorageHistoryAdapter(
|
|
358
|
+
storage,
|
|
359
|
+
() => auiRef.current,
|
|
360
|
+
prefix,
|
|
361
|
+
mutationQueue,
|
|
362
|
+
),
|
|
363
|
+
);
|
|
364
|
+
return useMemo(() => ({ history }), [history]);
|
|
365
|
+
};
|
|
366
|
+
|
|
341
367
|
const createHistoryProvider = (
|
|
342
368
|
storage: AsyncStorageLike,
|
|
343
369
|
prefix: string,
|
|
344
370
|
mutationQueue: KeyedMutationQueue,
|
|
345
371
|
): FC<PropsWithChildren> => {
|
|
346
372
|
const Provider: FC<PropsWithChildren> = ({ children }) => {
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
auiRef.current = aui;
|
|
352
|
-
});
|
|
353
|
-
const [history] = useState(
|
|
354
|
-
() =>
|
|
355
|
-
new AsyncStorageHistoryAdapter(
|
|
356
|
-
storage,
|
|
357
|
-
() => auiRef.current,
|
|
358
|
-
prefix,
|
|
359
|
-
mutationQueue,
|
|
360
|
-
),
|
|
373
|
+
const adapters = useLocalStorageThreadAdapters(
|
|
374
|
+
storage,
|
|
375
|
+
prefix,
|
|
376
|
+
mutationQueue,
|
|
361
377
|
);
|
|
362
|
-
const adapters = useMemo(() => ({ history }), [history]);
|
|
363
|
-
|
|
364
378
|
return (
|
|
365
379
|
<RuntimeAdapterProvider adapters={adapters}>
|
|
366
380
|
{children}
|
|
@@ -406,6 +420,9 @@ export const createLocalStorageAdapter = (
|
|
|
406
420
|
|
|
407
421
|
const adapter: RemoteThreadListAdapter = {
|
|
408
422
|
unstable_Provider: createHistoryProvider(storage, prefix, mutationQueue),
|
|
423
|
+
unstable_useAdapters: function useLocalStorageAdapters() {
|
|
424
|
+
return useLocalStorageThreadAdapters(storage, prefix, mutationQueue);
|
|
425
|
+
},
|
|
409
426
|
|
|
410
427
|
async list(): Promise<RemoteThreadListResponse> {
|
|
411
428
|
const threads = await loadThreadMetadata();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useEffect, useMemo } from "react";
|
|
2
|
+
import { resource, type ResourceElement } from "@assistant-ui/tap";
|
|
3
|
+
import { useClientResource } from "@assistant-ui/store/client";
|
|
4
|
+
import type { ClientOutput } from "@assistant-ui/store";
|
|
5
|
+
import type { RuntimeAdapters } from "../../runtimes/remote-thread-list/types";
|
|
6
|
+
import { isDevelopment } from "../../store/internal";
|
|
7
|
+
import {
|
|
8
|
+
useRuntimeAdapters,
|
|
9
|
+
useRuntimeAdaptersProvider,
|
|
10
|
+
useStableRuntimeAdapters,
|
|
11
|
+
} from "../runtimes/useRuntimeAdapters";
|
|
12
|
+
|
|
13
|
+
const useAdaptedRemoteThread = ({
|
|
14
|
+
useAdapters,
|
|
15
|
+
thread,
|
|
16
|
+
}: {
|
|
17
|
+
useAdapters: () => RuntimeAdapters | null | undefined;
|
|
18
|
+
thread: ResourceElement<ClientOutput<"thread">>;
|
|
19
|
+
}): ClientOutput<"thread"> => {
|
|
20
|
+
const parent = useRuntimeAdapters();
|
|
21
|
+
const stableAdapters = useStableRuntimeAdapters(useAdapters());
|
|
22
|
+
|
|
23
|
+
const unkeyedHistory =
|
|
24
|
+
stableAdapters?.history != null && thread.key === undefined;
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!isDevelopment || !unkeyedHistory) return;
|
|
27
|
+
console.warn(
|
|
28
|
+
"[assistant-ui] RemoteThreadList received a history adapter, but the thread factory is unkeyed. Key the thread resource by thread id (withKey) so switching threads reloads history.",
|
|
29
|
+
);
|
|
30
|
+
}, [unkeyedHistory]);
|
|
31
|
+
|
|
32
|
+
const merged = useMemo(
|
|
33
|
+
() => (stableAdapters == null ? parent : { ...parent, ...stableAdapters }),
|
|
34
|
+
[parent, stableAdapters],
|
|
35
|
+
);
|
|
36
|
+
return useRuntimeAdaptersProvider(merged, function useBoundRemoteThread() {
|
|
37
|
+
return useClientResource(thread).methods;
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const AdaptedRemoteThread = resource(useAdaptedRemoteThread);
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { act, render } from "@testing-library/react";
|
|
4
|
+
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { resource } from "@assistant-ui/tap";
|
|
6
|
+
import { AuiProvider, useAui, useAuiEvent } from "@assistant-ui/store";
|
|
7
|
+
import { InMemoryThreadList } from "./InMemoryThreadList";
|
|
8
|
+
|
|
9
|
+
const stubComposer = { getState: () => ({}) };
|
|
10
|
+
const stubSuggestions = { getState: () => ({ suggestions: [] }) };
|
|
11
|
+
const useStubThread = (_props: { threadId: string }) => ({
|
|
12
|
+
getState: () => ({ isRunning: false }),
|
|
13
|
+
composer: () => stubComposer,
|
|
14
|
+
suggestions: () => stubSuggestions,
|
|
15
|
+
});
|
|
16
|
+
const StubThread = resource(useStubThread);
|
|
17
|
+
|
|
18
|
+
const setup = () => {
|
|
19
|
+
const selectionChanged = vi.fn();
|
|
20
|
+
let aui!: ReturnType<typeof useAui>;
|
|
21
|
+
const Consumer = () => {
|
|
22
|
+
useAuiEvent("threads.selectionChanged" as never, selectionChanged as never);
|
|
23
|
+
return null;
|
|
24
|
+
};
|
|
25
|
+
const Harness = () => {
|
|
26
|
+
aui = useAui({
|
|
27
|
+
threads: InMemoryThreadList({
|
|
28
|
+
thread: (threadId) => StubThread({ threadId }) as never,
|
|
29
|
+
}),
|
|
30
|
+
} as never);
|
|
31
|
+
return (
|
|
32
|
+
<AuiProvider value={aui}>
|
|
33
|
+
<Consumer />
|
|
34
|
+
</AuiProvider>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
render(<Harness />);
|
|
38
|
+
return { getAui: () => aui, selectionChanged };
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
describe("InMemoryThreadList selection events", () => {
|
|
42
|
+
it("does not emit for the initially selected thread on mount", async () => {
|
|
43
|
+
const { selectionChanged } = setup();
|
|
44
|
+
await act(async () => {});
|
|
45
|
+
expect(selectionChanged).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("emits on switchToNewThread and on switching back", async () => {
|
|
49
|
+
const { getAui, selectionChanged } = setup();
|
|
50
|
+
await act(async () => {});
|
|
51
|
+
|
|
52
|
+
await act(async () => {
|
|
53
|
+
getAui().threads.switchToNewThread();
|
|
54
|
+
});
|
|
55
|
+
await act(async () => {});
|
|
56
|
+
|
|
57
|
+
const newThreadId = getAui().threads.getState().mainThreadId;
|
|
58
|
+
expect(newThreadId).not.toBe("main");
|
|
59
|
+
expect(selectionChanged).toHaveBeenCalledExactlyOnceWith({
|
|
60
|
+
threadId: newThreadId,
|
|
61
|
+
previousThreadId: "main",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await act(async () => {
|
|
65
|
+
getAui().threads.switchToThread("main");
|
|
66
|
+
});
|
|
67
|
+
await act(async () => {});
|
|
68
|
+
|
|
69
|
+
expect(selectionChanged).toHaveBeenCalledTimes(2);
|
|
70
|
+
expect(selectionChanged).toHaveBeenLastCalledWith({
|
|
71
|
+
threadId: "main",
|
|
72
|
+
previousThreadId: newThreadId,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("emits when deleting the selected thread falls back to another", async () => {
|
|
77
|
+
const { getAui, selectionChanged } = setup();
|
|
78
|
+
await act(async () => {});
|
|
79
|
+
|
|
80
|
+
await act(async () => {
|
|
81
|
+
getAui().threads.switchToNewThread();
|
|
82
|
+
});
|
|
83
|
+
await act(async () => {});
|
|
84
|
+
|
|
85
|
+
const newThreadId = getAui().threads.getState().mainThreadId;
|
|
86
|
+
selectionChanged.mockClear();
|
|
87
|
+
|
|
88
|
+
await act(async () => {
|
|
89
|
+
getAui().threads.item({ id: newThreadId }).delete();
|
|
90
|
+
});
|
|
91
|
+
await act(async () => {});
|
|
92
|
+
|
|
93
|
+
expect(getAui().threads.getState().mainThreadId).toBe("main");
|
|
94
|
+
expect(selectionChanged).toHaveBeenCalledExactlyOnceWith({
|
|
95
|
+
threadId: "main",
|
|
96
|
+
previousThreadId: newThreadId,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("InMemoryThreadList delete", () => {
|
|
102
|
+
it("notifies onDelete with the removed thread id", async () => {
|
|
103
|
+
const onDelete = vi.fn();
|
|
104
|
+
let aui!: ReturnType<typeof useAui>;
|
|
105
|
+
const Harness = () => {
|
|
106
|
+
aui = useAui({
|
|
107
|
+
threads: InMemoryThreadList({
|
|
108
|
+
thread: (threadId) => StubThread({ threadId }) as never,
|
|
109
|
+
onDelete,
|
|
110
|
+
}),
|
|
111
|
+
} as never);
|
|
112
|
+
return <AuiProvider value={aui}>{null}</AuiProvider>;
|
|
113
|
+
};
|
|
114
|
+
render(<Harness />);
|
|
115
|
+
await act(async () => {});
|
|
116
|
+
|
|
117
|
+
await act(async () => {
|
|
118
|
+
aui.threads.switchToNewThread();
|
|
119
|
+
});
|
|
120
|
+
const doomed = aui.threads.getState().mainThreadId;
|
|
121
|
+
await act(async () => {
|
|
122
|
+
aui.threads.item({ id: doomed }).delete();
|
|
123
|
+
});
|
|
124
|
+
expect(onDelete).toHaveBeenCalledExactlyOnceWith(doomed);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("starts a fresh thread when the last one is deleted", async () => {
|
|
128
|
+
let aui!: ReturnType<typeof useAui>;
|
|
129
|
+
const Harness = () => {
|
|
130
|
+
aui = useAui({
|
|
131
|
+
threads: InMemoryThreadList({
|
|
132
|
+
thread: (threadId) => StubThread({ threadId }) as never,
|
|
133
|
+
}),
|
|
134
|
+
} as never);
|
|
135
|
+
return <AuiProvider value={aui}>{null}</AuiProvider>;
|
|
136
|
+
};
|
|
137
|
+
render(<Harness />);
|
|
138
|
+
await act(async () => {});
|
|
139
|
+
|
|
140
|
+
await act(async () => {
|
|
141
|
+
aui.threads.item({ id: "main" }).delete();
|
|
142
|
+
});
|
|
143
|
+
const state = aui.threads.getState();
|
|
144
|
+
expect(state.threadIds).toHaveLength(1);
|
|
145
|
+
expect(state.mainThreadId).toBe(state.threadIds[0]);
|
|
146
|
+
expect(state.mainThreadId).not.toBe("main");
|
|
147
|
+
});
|
|
148
|
+
});
|