@assistant-ui/core 0.3.12 → 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 +3 -3
- package/dist/index.js +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/client/interactable-model-context.d.ts.map +1 -1
- package/dist/react/client/interactable-model-context.js +5 -1
- package/dist/react/client/interactable-model-context.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 +13 -3
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +25 -0
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +72 -18
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +15 -0
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +34 -3
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +1 -6
- package/dist/runtime/base/default-edit-composer-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 +11 -8
- 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/external-thread-queue-adapter.d.ts +15 -0
- package/dist/runtime/queue/external-thread-queue-adapter.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.js +25 -11
- 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-adapter.d.ts +7 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- 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 +11 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +78 -20
- 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 +55 -14
- 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/external-thread.d.ts +7 -0
- package/dist/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +460 -369
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/runtime-adapter.d.ts.map +1 -1
- package/dist/store/clients/runtime-adapter.js +5 -2
- package/dist/store/clients/runtime-adapter.js.map +1 -1
- package/dist/store/clients/single-thread-list.d.ts.map +1 -1
- package/dist/store/clients/single-thread-list.js +31 -27
- package/dist/store/clients/single-thread-list.js.map +1 -1
- package/dist/store/clients/suggestions.d.ts +3 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/suggestions.js +65 -37
- 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 +6 -4
- package/dist/store/index.js +5 -3
- 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 +104 -57
- 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/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +98 -82
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/scope-registration.d.ts +2 -2
- package/dist/store/scopes/composer.d.ts +9 -4
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/suggestions.d.ts +6 -1
- package/dist/store/scopes/suggestions.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 +25 -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/types/error.d.ts +15 -1
- package/dist/types/error.d.ts.map +1 -1
- package/dist/types/error.js +18 -1
- package/dist/types/error.js.map +1 -1
- package/dist/types/message.d.ts +2 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.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 +2 -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/client/interactable-model-context.ts +6 -1
- 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 +124 -0
- 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 +28 -3
- package/src/runtime/base/base-composer-runtime-core.ts +106 -13
- package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
- package/src/runtime/base/base-thread-runtime-core.ts +47 -2
- package/src/runtime/base/default-edit-composer-runtime-core.ts +1 -15
- package/src/runtime/base/default-thread-composer-runtime-core.ts +13 -15
- package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
- package/src/runtime/queue/external-thread-queue-adapter.ts +17 -0
- package/src/runtime/queue/message-queue.ts +28 -10
- package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
- package/src/runtimes/external-store/external-store-adapter.ts +7 -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 +187 -48
- package/src/runtimes/local/local-thread-runtime-core.test.ts +373 -4
- package/src/runtimes/local/local-thread-runtime-core.ts +83 -15
- 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/external-thread.ts +119 -16
- package/src/store/clients/model-context-client.test.ts +16 -8
- package/src/store/clients/runtime-adapter.ts +5 -2
- package/src/store/clients/single-thread-list.ts +2 -1
- package/src/store/clients/suggestions.ts +39 -13
- 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 +28 -35
- package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
- package/src/store/runtime-clients/thread-runtime-client.ts +5 -0
- package/src/store/scopes/composer.ts +9 -4
- package/src/store/scopes/suggestions.ts +6 -0
- package/src/store/scopes/thread-list-item.ts +7 -6
- package/src/store/scopes/thread.ts +25 -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/append-interactable-snapshots.test.ts +350 -0
- package/src/tests/auiV0Encode.test.ts +66 -0
- package/src/tests/base-composer-runtime-core-send.test.ts +156 -0
- package/src/tests/base-composer-runtime-core.test.ts +136 -1
- package/src/tests/composer-can-cancel.test.ts +101 -0
- package/src/tests/default-edit-composer-runtime-core.test.ts +0 -68
- package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +491 -1
- package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
- package/src/tests/external-thread-attachments.test.tsx +214 -0
- package/src/tests/external-thread-parity.test.tsx +54 -0
- package/src/tests/external-thread-refetch.test.tsx +117 -0
- package/src/tests/external-thread-suggestions.test.tsx +59 -0
- package/src/tests/interactables-toolui-migration.test.tsx +66 -0
- package/src/tests/message-queue.test.ts +54 -0
- package/src/tests/session-reset-notification.test.ts +145 -0
- package/src/tests/thread-message-like.test.ts +39 -0
- package/src/tests/thread-switch-events.test.tsx +234 -0
- package/src/tests/tools-scope-migration.test.tsx +58 -0
- package/src/types/error.ts +24 -0
- package/src/types/message.ts +2 -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/tests/default-thread-composer-runtime-core.test.ts +0 -82
|
@@ -8,6 +8,8 @@ import type {
|
|
|
8
8
|
import type { AppendMessage } from "../../types/message";
|
|
9
9
|
import type { LocalRuntimeOptionsBase } from "./local-runtime-options";
|
|
10
10
|
import type { ExportedMessageRepositoryItem } from "../../runtime/utils/message-repository";
|
|
11
|
+
import type { ThreadSuggestion } from "../../runtime/interfaces/thread-runtime-core";
|
|
12
|
+
import { isMessageNotSentError } from "../../types/error";
|
|
11
13
|
|
|
12
14
|
const flush = () => new Promise((resolve) => setTimeout(resolve, 10));
|
|
13
15
|
|
|
@@ -143,6 +145,180 @@ describe("LocalThreadRuntimeCore events", () => {
|
|
|
143
145
|
});
|
|
144
146
|
});
|
|
145
147
|
|
|
148
|
+
describe("LocalThreadRuntimeCore history persistence", () => {
|
|
149
|
+
it("surfaces failed user persistence without abandoning the run", async () => {
|
|
150
|
+
const persistenceError = new Error("history unavailable");
|
|
151
|
+
const run = vi.fn(async () => ({
|
|
152
|
+
content: [{ type: "text" as const, text: "done" }],
|
|
153
|
+
}));
|
|
154
|
+
const append = vi.fn(async (item: ExportedMessageRepositoryItem) => {
|
|
155
|
+
if (item.message.role === "user") throw persistenceError;
|
|
156
|
+
});
|
|
157
|
+
const thread = createThread(
|
|
158
|
+
{ run },
|
|
159
|
+
{
|
|
160
|
+
history: {
|
|
161
|
+
async load() {
|
|
162
|
+
return { messages: [] };
|
|
163
|
+
},
|
|
164
|
+
append,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
await expect(thread.append(userMessage("hello"))).rejects.toBe(
|
|
170
|
+
persistenceError,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
expect(append).toHaveBeenCalledTimes(2);
|
|
174
|
+
expect(run).toHaveBeenCalledOnce();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("surfaces failed persistence for messages that do not start a run", async () => {
|
|
178
|
+
const persistenceError = new Error("history unavailable");
|
|
179
|
+
const run = vi.fn();
|
|
180
|
+
const thread = createThread(
|
|
181
|
+
{ run },
|
|
182
|
+
{
|
|
183
|
+
history: {
|
|
184
|
+
async load() {
|
|
185
|
+
return { messages: [] };
|
|
186
|
+
},
|
|
187
|
+
async append() {
|
|
188
|
+
throw persistenceError;
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
await expect(
|
|
195
|
+
thread.append({ ...userMessage("hello"), startRun: false }),
|
|
196
|
+
).rejects.toBe(persistenceError);
|
|
197
|
+
|
|
198
|
+
expect(run).not.toHaveBeenCalled();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("handles failed persistence before notifying no-run subscribers", async () => {
|
|
202
|
+
const persistenceError = new Error("history unavailable");
|
|
203
|
+
const listenerError = new Error("listener unavailable");
|
|
204
|
+
const thread = createThread(
|
|
205
|
+
{ run: vi.fn() },
|
|
206
|
+
{
|
|
207
|
+
history: {
|
|
208
|
+
async load() {
|
|
209
|
+
return { messages: [] };
|
|
210
|
+
},
|
|
211
|
+
async append() {
|
|
212
|
+
throw persistenceError;
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
);
|
|
217
|
+
thread.subscribe(() => {
|
|
218
|
+
throw listenerError;
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
await expect(
|
|
222
|
+
thread.append({ ...userMessage("hello"), startRun: false }),
|
|
223
|
+
).rejects.toBe(listenerError);
|
|
224
|
+
await flush();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe("LocalThreadRuntimeCore - detach", () => {
|
|
229
|
+
it("drops a pending append when detached", async () => {
|
|
230
|
+
let resolveInitialization!: () => void;
|
|
231
|
+
const initialization = new Promise<void>((resolve) => {
|
|
232
|
+
resolveInitialization = resolve;
|
|
233
|
+
});
|
|
234
|
+
const run = vi.fn(async () => ({
|
|
235
|
+
content: [{ type: "text" as const, text: "done" }],
|
|
236
|
+
}));
|
|
237
|
+
const thread = createThread({ run });
|
|
238
|
+
thread.__internal_setGetInitializePromise(() => initialization);
|
|
239
|
+
|
|
240
|
+
const appendPromise = thread.append(userMessage("hello"));
|
|
241
|
+
await Promise.resolve();
|
|
242
|
+
thread.detach();
|
|
243
|
+
resolveInitialization();
|
|
244
|
+
|
|
245
|
+
await appendPromise;
|
|
246
|
+
expect(run).not.toHaveBeenCalled();
|
|
247
|
+
expect(thread.messages).toEqual([]);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe("LocalThreadRuntimeCore optimistic append", () => {
|
|
252
|
+
it("paints the appended message before initialization resolves", async () => {
|
|
253
|
+
let resolveInitialization!: () => void;
|
|
254
|
+
const initialization = new Promise<void>((resolve) => {
|
|
255
|
+
resolveInitialization = resolve;
|
|
256
|
+
});
|
|
257
|
+
const run = vi.fn(async () => ({
|
|
258
|
+
content: [{ type: "text" as const, text: "done" }],
|
|
259
|
+
}));
|
|
260
|
+
const thread = createThread({ run });
|
|
261
|
+
thread.__internal_setGetInitializePromise(() => initialization);
|
|
262
|
+
const onUpdate = vi.fn();
|
|
263
|
+
thread.subscribe(onUpdate);
|
|
264
|
+
|
|
265
|
+
const appendPromise = thread.append(userMessage("hello"));
|
|
266
|
+
await Promise.resolve();
|
|
267
|
+
|
|
268
|
+
expect(thread.messages).toHaveLength(1);
|
|
269
|
+
expect(thread.messages[0]?.role).toBe("user");
|
|
270
|
+
expect(onUpdate).toHaveBeenCalled();
|
|
271
|
+
expect(run).not.toHaveBeenCalled();
|
|
272
|
+
|
|
273
|
+
resolveInitialization();
|
|
274
|
+
await appendPromise;
|
|
275
|
+
expect(run).toHaveBeenCalledTimes(1);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("silently drops a detached append even when initialization rejects", async () => {
|
|
279
|
+
let rejectInitialization!: (error: unknown) => void;
|
|
280
|
+
const initialization = new Promise<void>((_, reject) => {
|
|
281
|
+
rejectInitialization = reject;
|
|
282
|
+
});
|
|
283
|
+
const run = vi.fn(async () => ({
|
|
284
|
+
content: [{ type: "text" as const, text: "done" }],
|
|
285
|
+
}));
|
|
286
|
+
const thread = createThread({ run });
|
|
287
|
+
thread.__internal_setGetInitializePromise(() => initialization);
|
|
288
|
+
|
|
289
|
+
const appendPromise = thread.append(userMessage("hello"));
|
|
290
|
+
await Promise.resolve();
|
|
291
|
+
thread.detach();
|
|
292
|
+
rejectInitialization(new Error("initialization failed"));
|
|
293
|
+
|
|
294
|
+
await expect(appendPromise).resolves.toBeUndefined();
|
|
295
|
+
expect(thread.messages).toEqual([]);
|
|
296
|
+
expect(run).not.toHaveBeenCalled();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("rolls the optimistic message back when initialization rejects", async () => {
|
|
300
|
+
const initializationError = new Error("initialization failed");
|
|
301
|
+
const run = vi.fn(async () => ({
|
|
302
|
+
content: [{ type: "text" as const, text: "done" }],
|
|
303
|
+
}));
|
|
304
|
+
const thread = createThread({ run });
|
|
305
|
+
thread.__internal_setGetInitializePromise(() =>
|
|
306
|
+
Promise.reject(initializationError),
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const error = await thread.append(userMessage("hello")).then(
|
|
310
|
+
() => {
|
|
311
|
+
throw new Error("expected the append to reject");
|
|
312
|
+
},
|
|
313
|
+
(e: unknown) => e,
|
|
314
|
+
);
|
|
315
|
+
expect(isMessageNotSentError(error)).toBe(true);
|
|
316
|
+
expect((error as Error).cause).toBe(initializationError);
|
|
317
|
+
expect(thread.messages).toEqual([]);
|
|
318
|
+
expect(run).not.toHaveBeenCalled();
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
146
322
|
describe("LocalThreadRuntimeCore human-in-the-loop tools", () => {
|
|
147
323
|
it("pauses on requires-action while a listed tool call has no result", async () => {
|
|
148
324
|
const { thread, runs } = createApprovalThread(toolCallResult("send_email"));
|
|
@@ -603,6 +779,48 @@ describe("LocalThreadRuntimeCore cancellation", () => {
|
|
|
603
779
|
});
|
|
604
780
|
|
|
605
781
|
describe("LocalThreadRuntimeCore suggestions", () => {
|
|
782
|
+
it("ignores suggestion generation from a superseded run", async () => {
|
|
783
|
+
let releaseFirst!: () => void;
|
|
784
|
+
let releaseSecond!: () => void;
|
|
785
|
+
const firstGate = new Promise<void>((resolve) => {
|
|
786
|
+
releaseFirst = resolve;
|
|
787
|
+
});
|
|
788
|
+
const secondGate = new Promise<void>((resolve) => {
|
|
789
|
+
releaseSecond = resolve;
|
|
790
|
+
});
|
|
791
|
+
let runCount = 0;
|
|
792
|
+
const generate = vi.fn().mockResolvedValue([{ prompt: "follow up" }]);
|
|
793
|
+
const thread = createThread(
|
|
794
|
+
{
|
|
795
|
+
async run() {
|
|
796
|
+
runCount += 1;
|
|
797
|
+
await (runCount === 1 ? firstGate : secondGate);
|
|
798
|
+
return { content: [{ type: "text", text: "done" }] };
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
{ suggestion: { generate } },
|
|
802
|
+
);
|
|
803
|
+
|
|
804
|
+
const firstAppend = thread.append(userMessage("first"));
|
|
805
|
+
await flush();
|
|
806
|
+
const secondAppend = thread.append(userMessage("second"));
|
|
807
|
+
await flush();
|
|
808
|
+
|
|
809
|
+
releaseFirst();
|
|
810
|
+
await firstAppend;
|
|
811
|
+
await flush();
|
|
812
|
+
|
|
813
|
+
expect(generate).not.toHaveBeenCalled();
|
|
814
|
+
expect(thread.suggestions).toEqual([]);
|
|
815
|
+
|
|
816
|
+
releaseSecond();
|
|
817
|
+
await secondAppend;
|
|
818
|
+
await flush();
|
|
819
|
+
|
|
820
|
+
expect(generate).toHaveBeenCalledOnce();
|
|
821
|
+
expect(thread.suggestions).toEqual([{ prompt: "follow up" }]);
|
|
822
|
+
});
|
|
823
|
+
|
|
606
824
|
it("cancelRun aborts pending suggestion generation", async () => {
|
|
607
825
|
const generate = vi.fn().mockImplementation(
|
|
608
826
|
({ signal }: { signal?: AbortSignal }) =>
|
|
@@ -656,8 +874,8 @@ describe("LocalThreadRuntimeCore suggestions", () => {
|
|
|
656
874
|
});
|
|
657
875
|
|
|
658
876
|
it("resolves append before suggestion generation completes", async () => {
|
|
659
|
-
let resolveSuggestions!: (value: readonly
|
|
660
|
-
const suggestionsDeferred = new Promise<readonly
|
|
877
|
+
let resolveSuggestions!: (value: readonly ThreadSuggestion[]) => void;
|
|
878
|
+
const suggestionsDeferred = new Promise<readonly ThreadSuggestion[]>(
|
|
661
879
|
(resolve) => {
|
|
662
880
|
resolveSuggestions = resolve;
|
|
663
881
|
},
|
|
@@ -681,9 +899,15 @@ describe("LocalThreadRuntimeCore suggestions", () => {
|
|
|
681
899
|
expect(generate).toHaveBeenCalledTimes(1);
|
|
682
900
|
expect(thread.suggestions).toEqual([]);
|
|
683
901
|
|
|
684
|
-
resolveSuggestions([
|
|
902
|
+
resolveSuggestions([
|
|
903
|
+
{ title: "Weather", label: "in SF", prompt: "What's the weather?" },
|
|
904
|
+
{ prompt: "follow up" },
|
|
905
|
+
]);
|
|
685
906
|
await new Promise((r) => setTimeout(r, 0));
|
|
686
|
-
expect(thread.suggestions).toEqual([
|
|
907
|
+
expect(thread.suggestions).toEqual([
|
|
908
|
+
{ title: "Weather", label: "in SF", prompt: "What's the weather?" },
|
|
909
|
+
{ prompt: "follow up" },
|
|
910
|
+
]);
|
|
687
911
|
});
|
|
688
912
|
});
|
|
689
913
|
|
|
@@ -1313,4 +1537,149 @@ describe("LocalThreadRuntimeCore runs", () => {
|
|
|
1313
1537
|
expect(thread.capabilities.attachments).toBe(false);
|
|
1314
1538
|
expect(thread.capabilities.feedback).toBe(false);
|
|
1315
1539
|
});
|
|
1540
|
+
|
|
1541
|
+
it("loads history when the adapter arrives after the first load", async () => {
|
|
1542
|
+
const adapter: ChatModelAdapter = {
|
|
1543
|
+
run: async () => ({ content: [] }),
|
|
1544
|
+
};
|
|
1545
|
+
const thread = createPlainThread(adapter);
|
|
1546
|
+
const load = vi.fn(async () => ({
|
|
1547
|
+
headId: "restored",
|
|
1548
|
+
messages: [
|
|
1549
|
+
{
|
|
1550
|
+
parentId: null,
|
|
1551
|
+
message: {
|
|
1552
|
+
id: "restored",
|
|
1553
|
+
role: "user" as const,
|
|
1554
|
+
content: [{ type: "text" as const, text: "hello" }],
|
|
1555
|
+
createdAt: new Date(0),
|
|
1556
|
+
metadata: { custom: {} },
|
|
1557
|
+
},
|
|
1558
|
+
},
|
|
1559
|
+
],
|
|
1560
|
+
}));
|
|
1561
|
+
|
|
1562
|
+
thread.__internal_load();
|
|
1563
|
+
expect(load).not.toHaveBeenCalled();
|
|
1564
|
+
expect(thread.messages).toHaveLength(0);
|
|
1565
|
+
|
|
1566
|
+
thread.__internal_setOptions({
|
|
1567
|
+
adapters: {
|
|
1568
|
+
chatModel: adapter,
|
|
1569
|
+
history: { load, append: async () => {} },
|
|
1570
|
+
},
|
|
1571
|
+
});
|
|
1572
|
+
await flush();
|
|
1573
|
+
|
|
1574
|
+
expect(load).toHaveBeenCalledOnce();
|
|
1575
|
+
expect(thread.messages.map((message) => message.id)).toEqual(["restored"]);
|
|
1576
|
+
});
|
|
1577
|
+
|
|
1578
|
+
it("does not load late history over a thread that already has messages", async () => {
|
|
1579
|
+
const adapter: ChatModelAdapter = {
|
|
1580
|
+
run: async () => ({ content: [] }),
|
|
1581
|
+
};
|
|
1582
|
+
const thread = createPlainThread(adapter);
|
|
1583
|
+
const load = vi.fn(async () => ({
|
|
1584
|
+
headId: "restored",
|
|
1585
|
+
messages: [
|
|
1586
|
+
{
|
|
1587
|
+
parentId: null,
|
|
1588
|
+
message: {
|
|
1589
|
+
id: "restored",
|
|
1590
|
+
role: "user" as const,
|
|
1591
|
+
content: [{ type: "text" as const, text: "hello" }],
|
|
1592
|
+
createdAt: new Date(0),
|
|
1593
|
+
metadata: { custom: {} },
|
|
1594
|
+
},
|
|
1595
|
+
},
|
|
1596
|
+
],
|
|
1597
|
+
}));
|
|
1598
|
+
|
|
1599
|
+
thread.__internal_load();
|
|
1600
|
+
await thread.append({ ...userMessage("typed"), startRun: false });
|
|
1601
|
+
expect(thread.messages).toHaveLength(1);
|
|
1602
|
+
|
|
1603
|
+
thread.__internal_setOptions({
|
|
1604
|
+
adapters: {
|
|
1605
|
+
chatModel: adapter,
|
|
1606
|
+
history: { load, append: async () => {} },
|
|
1607
|
+
},
|
|
1608
|
+
});
|
|
1609
|
+
await flush();
|
|
1610
|
+
|
|
1611
|
+
expect(load).not.toHaveBeenCalled();
|
|
1612
|
+
expect(thread.messages.map((message) => message.content)).toEqual([
|
|
1613
|
+
[{ type: "text", text: "typed" }],
|
|
1614
|
+
]);
|
|
1615
|
+
});
|
|
1616
|
+
|
|
1617
|
+
it("logs a rejected late history load", async () => {
|
|
1618
|
+
const adapter: ChatModelAdapter = {
|
|
1619
|
+
run: async () => ({ content: [] }),
|
|
1620
|
+
};
|
|
1621
|
+
const thread = createPlainThread(adapter);
|
|
1622
|
+
const error = new Error("history unavailable");
|
|
1623
|
+
const consoleError = vi
|
|
1624
|
+
.spyOn(console, "error")
|
|
1625
|
+
.mockImplementation(() => {});
|
|
1626
|
+
|
|
1627
|
+
thread.__internal_load();
|
|
1628
|
+
thread.__internal_setOptions({
|
|
1629
|
+
adapters: {
|
|
1630
|
+
chatModel: adapter,
|
|
1631
|
+
history: {
|
|
1632
|
+
load: async () => {
|
|
1633
|
+
throw error;
|
|
1634
|
+
},
|
|
1635
|
+
append: async () => {},
|
|
1636
|
+
},
|
|
1637
|
+
},
|
|
1638
|
+
});
|
|
1639
|
+
await flush();
|
|
1640
|
+
|
|
1641
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
1642
|
+
"[assistant-ui] local thread history load failed:",
|
|
1643
|
+
error,
|
|
1644
|
+
);
|
|
1645
|
+
});
|
|
1646
|
+
});
|
|
1647
|
+
|
|
1648
|
+
describe("LocalRuntimeCore composer.canCancel", () => {
|
|
1649
|
+
it("is true after append when the thread was created with initial messages", async () => {
|
|
1650
|
+
const core = new LocalRuntimeCore(
|
|
1651
|
+
{
|
|
1652
|
+
adapters: {
|
|
1653
|
+
chatModel: {
|
|
1654
|
+
async *run({ abortSignal }) {
|
|
1655
|
+
await new Promise<void>((resolve) => {
|
|
1656
|
+
if (abortSignal.aborted) {
|
|
1657
|
+
resolve();
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
abortSignal.addEventListener("abort", () => resolve(), {
|
|
1661
|
+
once: true,
|
|
1662
|
+
});
|
|
1663
|
+
});
|
|
1664
|
+
},
|
|
1665
|
+
},
|
|
1666
|
+
},
|
|
1667
|
+
},
|
|
1668
|
+
[
|
|
1669
|
+
{
|
|
1670
|
+
role: "assistant",
|
|
1671
|
+
content: [{ type: "text", text: "Hello" }],
|
|
1672
|
+
status: { type: "complete", reason: "stop" },
|
|
1673
|
+
},
|
|
1674
|
+
],
|
|
1675
|
+
);
|
|
1676
|
+
const thread = core.threads.getMainThreadRuntimeCore();
|
|
1677
|
+
expect(thread.composer.canCancel).toBe(false);
|
|
1678
|
+
|
|
1679
|
+
void thread.append(userMessage("Run"));
|
|
1680
|
+
await flush();
|
|
1681
|
+
|
|
1682
|
+
expect(thread.composer.canCancel).toBe(true);
|
|
1683
|
+
thread.cancelRun();
|
|
1684
|
+
});
|
|
1316
1685
|
});
|
|
@@ -22,7 +22,7 @@ import type {
|
|
|
22
22
|
ThreadAssistantMessage,
|
|
23
23
|
} from "../../types/message";
|
|
24
24
|
import type { RunConfig } from "../../types/message";
|
|
25
|
-
import { toAssistantError } from "../../types/error";
|
|
25
|
+
import { MessageNotSentError, toAssistantError } from "../../types/error";
|
|
26
26
|
import type { ModelContextProvider } from "../../model-context/types";
|
|
27
27
|
import {
|
|
28
28
|
createMessageQueue,
|
|
@@ -33,6 +33,11 @@ import {
|
|
|
33
33
|
EMPTY_QUEUE_ITEMS,
|
|
34
34
|
type QueueItemState,
|
|
35
35
|
} from "../../store/scopes/queue-item";
|
|
36
|
+
import {
|
|
37
|
+
captureThreadRuntimeGeneration,
|
|
38
|
+
invalidateThreadRuntime,
|
|
39
|
+
isThreadRuntimeGenerationCurrent,
|
|
40
|
+
} from "../../runtime/utils/thread-runtime-lifecycle";
|
|
36
41
|
|
|
37
42
|
class AbortError extends Error {
|
|
38
43
|
override name = "AbortError";
|
|
@@ -162,6 +167,7 @@ export class LocalThreadRuntimeCore
|
|
|
162
167
|
public __internal_setOptions(options: LocalRuntimeOptionsBase) {
|
|
163
168
|
if (this._options === options) return;
|
|
164
169
|
|
|
170
|
+
const previousHistory = this._options?.adapters.history;
|
|
165
171
|
this._options = options;
|
|
166
172
|
|
|
167
173
|
let hasUpdates = false;
|
|
@@ -234,13 +240,31 @@ export class LocalThreadRuntimeCore
|
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
if (hasUpdates) this._notifySubscribers();
|
|
243
|
+
|
|
244
|
+
if (
|
|
245
|
+
this._loadRequested &&
|
|
246
|
+
!this._loadPromise &&
|
|
247
|
+
!previousHistory &&
|
|
248
|
+
options.adapters.history &&
|
|
249
|
+
this.messages.length === 0
|
|
250
|
+
) {
|
|
251
|
+
void this.__internal_load().catch((error: unknown) => {
|
|
252
|
+
console.error(
|
|
253
|
+
"[assistant-ui] local thread history load failed:",
|
|
254
|
+
error,
|
|
255
|
+
);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
237
258
|
}
|
|
238
259
|
|
|
239
260
|
private _loadPromise: Promise<void> | undefined;
|
|
261
|
+
private _loadRequested = false;
|
|
240
262
|
public __internal_load() {
|
|
263
|
+
this._loadRequested = true;
|
|
241
264
|
if (this._loadPromise) return this._loadPromise;
|
|
265
|
+
if (!this.adapters.history) return Promise.resolve();
|
|
242
266
|
|
|
243
|
-
const promise = this.adapters.history
|
|
267
|
+
const promise = this.adapters.history.load();
|
|
244
268
|
|
|
245
269
|
this._isLoading = true;
|
|
246
270
|
this._notifySubscribers();
|
|
@@ -312,35 +336,72 @@ export class LocalThreadRuntimeCore
|
|
|
312
336
|
this._queue?.adapter.remove(queueItemId);
|
|
313
337
|
}
|
|
314
338
|
|
|
315
|
-
private
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
await initPromise;
|
|
339
|
+
private _rollbackAppend(messageId: string) {
|
|
340
|
+
try {
|
|
341
|
+
this.repository.deleteMessage(messageId);
|
|
342
|
+
} catch {
|
|
343
|
+
return;
|
|
321
344
|
}
|
|
345
|
+
this._notifySubscribers();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
private async _runAppend(rawMessage: AppendMessage): Promise<void> {
|
|
349
|
+
// Stamped here rather than in `append` so a queued message is gated after
|
|
350
|
+
// the flush re-pointed its parentId at the current tail.
|
|
351
|
+
const generation = captureThreadRuntimeGeneration(this);
|
|
352
|
+
const message = this.enrichAppendMetadata(rawMessage);
|
|
353
|
+
this.ensureInitialized();
|
|
322
354
|
|
|
323
355
|
const newMessage = fromThreadMessageLike(message, generateId(), {
|
|
324
356
|
type: "complete",
|
|
325
357
|
reason: "unknown",
|
|
326
358
|
});
|
|
327
359
|
this.repository.addOrUpdateMessage(message.parentId, newMessage);
|
|
328
|
-
this.
|
|
360
|
+
this._notifySubscribers();
|
|
361
|
+
|
|
362
|
+
// Initialization only gates the history write and the run; the message
|
|
363
|
+
// is already on screen. A failed barrier rolls the optimistic message
|
|
364
|
+
// back and rejects as an unsent message so the composer restores the
|
|
365
|
+
// draft; a thread invalidated mid-wait rolls back silently.
|
|
366
|
+
try {
|
|
367
|
+
const initPromise = this._getInitializePromise?.();
|
|
368
|
+
if (initPromise) {
|
|
369
|
+
await initPromise;
|
|
370
|
+
}
|
|
371
|
+
} catch (error) {
|
|
372
|
+
this._rollbackAppend(newMessage.id);
|
|
373
|
+
if (!isThreadRuntimeGenerationCurrent(this, generation)) return;
|
|
374
|
+
const notSent = new MessageNotSentError();
|
|
375
|
+
notSent.cause = error;
|
|
376
|
+
throw notSent;
|
|
377
|
+
}
|
|
378
|
+
if (!isThreadRuntimeGenerationCurrent(this, generation)) {
|
|
379
|
+
this._rollbackAppend(newMessage.id);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const historyWrite = this._options.adapters.history?.append({
|
|
329
383
|
parentId: message.parentId,
|
|
330
384
|
message: newMessage,
|
|
331
385
|
...(message.runConfig !== undefined && { runConfig: message.runConfig }),
|
|
332
386
|
});
|
|
387
|
+
void historyWrite?.catch(() => {});
|
|
333
388
|
|
|
334
389
|
const startRun = message.startRun ?? message.role === "user";
|
|
335
390
|
if (startRun) {
|
|
336
|
-
await
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
391
|
+
const [runResult, historyResult] = await Promise.allSettled([
|
|
392
|
+
this.startRun({
|
|
393
|
+
parentId: newMessage.id,
|
|
394
|
+
sourceId: message.sourceId,
|
|
395
|
+
runConfig: message.runConfig ?? {},
|
|
396
|
+
}),
|
|
397
|
+
historyWrite,
|
|
398
|
+
]);
|
|
399
|
+
if (runResult.status === "rejected") throw runResult.reason;
|
|
400
|
+
if (historyResult.status === "rejected") throw historyResult.reason;
|
|
341
401
|
} else {
|
|
342
402
|
this.repository.resetHead(newMessage.id);
|
|
343
403
|
this._notifySubscribers();
|
|
404
|
+
await historyWrite;
|
|
344
405
|
}
|
|
345
406
|
}
|
|
346
407
|
|
|
@@ -377,6 +438,10 @@ export class LocalThreadRuntimeCore
|
|
|
377
438
|
throw new Error("Runtime does not support importing external states.");
|
|
378
439
|
}
|
|
379
440
|
|
|
441
|
+
public unstable_notifySessionReset(): void {
|
|
442
|
+
throw new Error("Runtime does not support resetting sessions.");
|
|
443
|
+
}
|
|
444
|
+
|
|
380
445
|
public async startRun(
|
|
381
446
|
{ parentId, runConfig }: StartRunConfig,
|
|
382
447
|
runCallback?: ChatModelAdapter["run"],
|
|
@@ -421,6 +486,7 @@ export class LocalThreadRuntimeCore
|
|
|
421
486
|
this._activeRun = run;
|
|
422
487
|
this._runGeneration++;
|
|
423
488
|
|
|
489
|
+
let active = false;
|
|
424
490
|
try {
|
|
425
491
|
// mark busy for runs not started through the queue (regenerate, resume)
|
|
426
492
|
this._queue?.notifyBusy();
|
|
@@ -444,7 +510,7 @@ export class LocalThreadRuntimeCore
|
|
|
444
510
|
// the settle belongs to this run only while it is still the active run
|
|
445
511
|
// or was cancelled (the engine expects a cancelled run's settle); a run
|
|
446
512
|
// superseded by a newer one stays silent
|
|
447
|
-
|
|
513
|
+
active = this._activeRun === run;
|
|
448
514
|
if (active) this._activeRun = null;
|
|
449
515
|
if (active || run.cancelled) {
|
|
450
516
|
queueMicrotask(() => this._queue?.notifyIdle());
|
|
@@ -452,6 +518,7 @@ export class LocalThreadRuntimeCore
|
|
|
452
518
|
}
|
|
453
519
|
|
|
454
520
|
if (
|
|
521
|
+
active &&
|
|
455
522
|
this.adapters.suggestion &&
|
|
456
523
|
message.status?.type !== "requires-action"
|
|
457
524
|
) {
|
|
@@ -671,6 +738,7 @@ export class LocalThreadRuntimeCore
|
|
|
671
738
|
}
|
|
672
739
|
|
|
673
740
|
public detach() {
|
|
741
|
+
invalidateThreadRuntime(this);
|
|
674
742
|
// drop the queue so pending items cannot dispatch on a detached thread
|
|
675
743
|
this._queue = null;
|
|
676
744
|
const error = new AbortError(true);
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ThreadMessage } from "../../types/message";
|
|
2
2
|
import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
|
|
3
3
|
import type { AssistantStream } from "assistant-stream";
|
|
4
|
+
import type { ThreadHistoryAdapter } from "../../adapters/thread-history";
|
|
5
|
+
import type { AttachmentAdapter } from "../../adapters/attachment";
|
|
6
|
+
import type { ModelContextProvider } from "../../model-context/types";
|
|
4
7
|
|
|
5
8
|
/* oxlint-disable typescript/no-explicit-any -- structural stand-in for ComponentType without depending on react types */
|
|
6
9
|
type RemoteThreadListProviderProps = { children?: any };
|
|
@@ -33,6 +36,12 @@ export type RemoteThreadListPageOptions = {
|
|
|
33
36
|
after?: string | undefined;
|
|
34
37
|
};
|
|
35
38
|
|
|
39
|
+
export type RuntimeAdapters = {
|
|
40
|
+
modelContext?: ModelContextProvider | undefined;
|
|
41
|
+
history?: ThreadHistoryAdapter | undefined;
|
|
42
|
+
attachments?: AttachmentAdapter | undefined;
|
|
43
|
+
};
|
|
44
|
+
|
|
36
45
|
export type RemoteThreadListAdapter = {
|
|
37
46
|
list(params?: RemoteThreadListPageOptions): Promise<RemoteThreadListResponse>;
|
|
38
47
|
|
|
@@ -56,12 +65,33 @@ export type RemoteThreadListAdapter = {
|
|
|
56
65
|
* inject per-thread context such as a history or attachments adapter (see
|
|
57
66
|
* `useCloudThreadListAdapter` for the canonical shape).
|
|
58
67
|
*
|
|
68
|
+
* `useRemoteThreadListRuntime` renders this component when present. If it
|
|
69
|
+
* is omitted, that host synthesizes a `RuntimeAdapterProvider` from
|
|
70
|
+
* `unstable_useAdapters`. The `RemoteThreadList` store entry ignores it;
|
|
71
|
+
* expose `unstable_useAdapters` for that host.
|
|
72
|
+
*
|
|
59
73
|
* The Provider must render `children` on its first commit; deferring them
|
|
60
74
|
* behind a loading state, a Suspense boundary, or a `useEffect`-gated render
|
|
61
75
|
* is unsupported and leaves thread context unavailable to downstream
|
|
62
76
|
* consumers. Load data inside an always-mounted child instead.
|
|
63
77
|
*/
|
|
64
78
|
unstable_Provider?: RemoteThreadListProviderComponent | undefined;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Hook the `RemoteThreadList` store entry calls once for the main-thread
|
|
82
|
+
* slot, then provides to the `thread` factory. This is not mounted per
|
|
83
|
+
* listed thread. `useRemoteThreadListRuntime` also calls it when
|
|
84
|
+
* `unstable_Provider` is omitted. Resolve `threadListItem` lazily on each
|
|
85
|
+
* adapter call; do not capture it at hook mount. The hook must keep a
|
|
86
|
+
* stable hook count across adapter swaps; a different count throws.
|
|
87
|
+
* Memoize the returned object.
|
|
88
|
+
*
|
|
89
|
+
* Per-thread history also requires the `thread` factory to be keyed by
|
|
90
|
+
* thread id (`withKey(id, thread(...))`). History loaders such as
|
|
91
|
+
* `useExternalHistory` run once per mount; an unkeyed factory keeps one
|
|
92
|
+
* instance across switches and the next thread's messages never load.
|
|
93
|
+
*/
|
|
94
|
+
unstable_useAdapters?: (() => RuntimeAdapters | null | undefined) | undefined;
|
|
65
95
|
};
|
|
66
96
|
|
|
67
97
|
export type RemoteThreadListOptions = {
|