@assistant-ui/core 0.3.14 → 0.3.16
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/voice.js +11 -0
- package/dist/adapters/voice.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +8 -2
- package/dist/internal.js +9 -3
- package/dist/model-context/frame/host.d.ts +1 -1
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +20 -5
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts +6 -0
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +126 -16
- package/dist/model-context/frame/provider.js.map +1 -1
- package/dist/model-context/frame/types.d.ts +4 -1
- package/dist/model-context/frame/types.d.ts.map +1 -1
- package/dist/model-context/frame/types.js.map +1 -1
- package/dist/model-context/interactable-composer-metadata.d.ts +1 -1
- package/dist/model-context/interactable-composer-metadata.js +1 -1
- package/dist/model-context/interactable-composer-metadata.js.map +1 -1
- package/dist/model-context/registry.d.ts +2 -2
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/registry.js +9 -28
- package/dist/model-context/registry.js.map +1 -1
- package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
- package/dist/react/client/InMemoryThreadList.js +24 -20
- package/dist/react/client/InMemoryThreadList.js.map +1 -1
- package/dist/react/client/Interactables.d.ts.map +1 -1
- package/dist/react/client/Interactables.js +59 -177
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +1 -1
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
- package/dist/react/client/RemoteThreadList.js +117 -78
- package/dist/react/client/RemoteThreadList.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
- package/dist/react/interactables-legacy/Interactables.js +56 -174
- package/dist/react/interactables-legacy/Interactables.js.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts +24 -0
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -0
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +138 -0
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -0
- package/dist/react/primitive-hooks/useActionBarCopy.js +7 -1
- package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts +3 -0
- package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadIsEmpty.js +3 -0
- package/dist/react/primitive-hooks/useThreadIsEmpty.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadIsRunning.d.ts +3 -0
- package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadIsRunning.js +3 -0
- package/dist/react/primitive-hooks/useThreadIsRunning.js.map +1 -1
- package/dist/react/primitives/composer/ComposerIf.js.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.d.ts +2 -1
- package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +3 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +6 -0
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +7 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +174 -64
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.js +2 -0
- package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
- package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -1
- package/dist/react/runtimes/assistant-transport/runManager.js +2 -12
- package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -1
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +1 -1
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +3 -10
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +20 -67
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.d.ts +12 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.d.ts.map +1 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js +10 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.js.map +1 -0
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +38 -5
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -1
- package/dist/react/runtimes/createMessageConverter.d.ts +2 -1
- package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
- package/dist/react/runtimes/external-message-converter.d.ts +6 -25
- package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +33 -233
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/runtime/api/composer-runtime.d.ts +1 -1
- package/dist/runtime/api/composer-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +1 -2
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +14 -29
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -4
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +3 -9
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -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 +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +1 -1
- package/dist/runtime/internal.d.ts +2 -1
- package/dist/runtime/internal.js +2 -1
- package/dist/runtime/queue/external-thread-queue-adapter.d.ts +1 -1
- package/dist/runtime/queue/message-queue.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.js +1 -1
- package/dist/runtime/queue/message-queue.js.map +1 -1
- package/dist/runtime/queue/queue-item.d.ts +12 -0
- package/dist/runtime/queue/queue-item.d.ts.map +1 -0
- package/dist/runtime/queue/queue-item.js +6 -0
- package/dist/runtime/queue/queue-item.js.map +1 -0
- package/dist/runtime/utils/abortable-thread-load.d.ts +15 -0
- package/dist/runtime/utils/abortable-thread-load.d.ts.map +1 -0
- package/dist/runtime/utils/abortable-thread-load.js +35 -0
- package/dist/runtime/utils/abortable-thread-load.js.map +1 -0
- package/dist/runtime/utils/attachment-add-operations.d.ts +18 -0
- package/dist/runtime/utils/attachment-add-operations.d.ts.map +1 -0
- package/dist/runtime/utils/attachment-add-operations.js +43 -0
- package/dist/runtime/utils/attachment-add-operations.js.map +1 -0
- package/dist/runtime/utils/auto-status.d.ts +6 -1
- package/dist/runtime/utils/auto-status.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.js +7 -1
- package/dist/runtime/utils/auto-status.js.map +1 -1
- package/dist/runtime/utils/external-message-conversion.d.ts +47 -0
- package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -0
- package/dist/runtime/utils/external-message-conversion.js +221 -0
- package/dist/runtime/utils/external-message-conversion.js.map +1 -0
- package/dist/runtime/utils/external-store-message.d.ts +2 -1
- package/dist/runtime/utils/external-store-message.d.ts.map +1 -1
- package/dist/runtime/utils/external-store-message.js +2 -1
- package/dist/runtime/utils/external-store-message.js.map +1 -1
- package/dist/runtime/utils/message-repository-session.d.ts +30 -0
- package/dist/runtime/utils/message-repository-session.d.ts.map +1 -0
- package/dist/runtime/utils/message-repository-session.js +130 -0
- package/dist/runtime/utils/message-repository-session.js.map +1 -0
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +30 -22
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtime/utils/pending-tool-calls.d.ts +20 -0
- package/dist/runtime/utils/pending-tool-calls.d.ts.map +1 -0
- package/dist/runtime/utils/pending-tool-calls.js +22 -0
- package/dist/runtime/utils/pending-tool-calls.js.map +1 -0
- package/dist/runtime/utils/thread-message-like.d.ts +2 -1
- package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +2 -5
- 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 +3 -10
- 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 +19 -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 +124 -20
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +102 -0
- package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -0
- package/dist/runtimes/inert/InertThreadRuntimeCore.js +156 -0
- package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -0
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +45 -8
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +12 -60
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +10 -145
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
- package/dist/runtimes/remote-thread-list/adapter-changed.d.ts +9 -0
- package/dist/runtimes/remote-thread-list/adapter-changed.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/adapter-changed.js +13 -0
- package/dist/runtimes/remote-thread-list/adapter-changed.js.map +1 -0
- package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/empty-thread-core.js +16 -155
- package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +2 -0
- package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/optimistic-state.js +11 -0
- package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +12 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.js +77 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +3 -0
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -0
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +75 -100
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/single-thread-list.d.ts.map +1 -1
- package/dist/store/clients/single-thread-list.js +1 -1
- package/dist/store/clients/single-thread-list.js.map +1 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/suggestions.js +16 -7
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/index.d.ts +4 -2
- package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -1
- package/dist/store/runtime-clients/handle-runtime-action.js +2 -0
- package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -1
- package/dist/store/scope-registration.d.ts +1 -1
- package/dist/store/scopes/composer.d.ts +2 -1
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/message.d.ts +1 -1
- package/dist/store/scopes/queue-item.d.ts +2 -9
- package/dist/store/scopes/queue-item.d.ts.map +1 -1
- package/dist/store/scopes/queue-item.js +0 -6
- package/dist/types/message.d.ts +8 -4
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/data-url.d.ts +14 -1
- package/dist/utils/data-url.d.ts.map +1 -1
- package/dist/utils/data-url.js +13 -1
- package/dist/utils/data-url.js.map +1 -1
- package/dist/utils/invoke-user-callback.d.ts +5 -0
- package/dist/utils/invoke-user-callback.d.ts.map +1 -0
- package/dist/utils/invoke-user-callback.js +19 -0
- package/dist/utils/invoke-user-callback.js.map +1 -0
- package/dist/utils/normalizePartStatus.js.map +1 -1
- package/dist/utils/silent-runtime-action.d.ts +6 -0
- package/dist/utils/silent-runtime-action.d.ts.map +1 -0
- package/dist/utils/silent-runtime-action.js +7 -0
- package/dist/utils/silent-runtime-action.js.map +1 -0
- package/package.json +10 -10
- package/src/adapters/voice.test.ts +66 -1
- package/src/adapters/voice.ts +8 -0
- package/src/internal.ts +13 -0
- package/src/model-context/frame/host.test.ts +152 -9
- package/src/model-context/frame/host.ts +23 -5
- package/src/model-context/frame/provider.test.ts +601 -19
- package/src/model-context/frame/provider.ts +158 -20
- package/src/model-context/frame/types.ts +5 -0
- package/src/model-context/interactable-composer-metadata.ts +1 -1
- package/src/model-context/registry.test.ts +44 -0
- package/src/model-context/registry.ts +13 -35
- package/src/react/client/InMemoryThreadList.test.tsx +49 -0
- package/src/react/client/InMemoryThreadList.ts +7 -1
- package/src/react/client/Interactables.ts +19 -178
- package/src/react/client/RemoteThreadList.test.ts +292 -0
- package/src/react/client/RemoteThreadList.ts +119 -82
- package/src/react/interactables-legacy/Interactables.ts +20 -177
- package/src/react/interactables-shared/useInteractablePersistenceQueue.test.tsx +161 -0
- package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +206 -0
- package/src/react/primitive-hooks/useActionBarCopy.test.ts +15 -0
- package/src/react/primitive-hooks/useActionBarCopy.ts +13 -3
- package/src/react/primitive-hooks/useThreadIsEmpty.ts +3 -0
- package/src/react/primitive-hooks/useThreadIsRunning.ts +3 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +12 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.republish.test.ts +87 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +251 -76
- package/src/react/runtimes/RemoteThreadResource.ts +2 -0
- package/src/react/runtimes/assistant-transport/runManager.ts +4 -17
- package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +58 -0
- package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +3 -1
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +92 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +40 -141
- package/src/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.test.ts +37 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapterCreateFallback.ts +18 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +98 -3
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +68 -6
- package/src/react/runtimes/external-message-converter.test.ts +0 -14
- package/src/react/runtimes/external-message-converter.test.tsx +77 -0
- package/src/react/runtimes/external-message-converter.ts +58 -481
- package/src/react/runtimes/useLocalRuntime.test.tsx +5 -5
- package/src/runtime/api/composer-runtime.ts +1 -1
- package/src/runtime/api/message-runtime.test.ts +28 -1
- package/src/runtime/base/base-composer-runtime-core.ts +20 -40
- package/src/runtime/base/base-thread-runtime-core.test.ts +16 -0
- package/src/runtime/base/base-thread-runtime-core.ts +6 -11
- package/src/runtime/base/default-thread-composer-runtime-core.ts +1 -4
- package/src/runtime/interfaces/composer-runtime-core.ts +1 -1
- package/src/runtime/interfaces/thread-runtime-core.ts +1 -1
- package/src/runtime/internal.ts +5 -0
- package/src/runtime/queue/external-thread-queue-adapter.ts +1 -1
- package/src/runtime/queue/message-queue.ts +1 -4
- package/src/runtime/queue/queue-item.ts +10 -0
- package/src/runtime/utils/abortable-thread-load.test.ts +87 -0
- package/src/runtime/utils/abortable-thread-load.ts +53 -0
- package/src/runtime/utils/attachment-add-operations.ts +59 -0
- package/src/runtime/utils/auto-status.ts +33 -0
- package/src/runtime/utils/external-message-conversion.test.ts +113 -0
- package/src/runtime/utils/external-message-conversion.ts +494 -0
- package/src/runtime/utils/external-store-message.ts +2 -0
- package/src/runtime/utils/message-repository-session.test.ts +195 -0
- package/src/runtime/utils/message-repository-session.ts +176 -0
- package/src/runtime/utils/message-repository.ts +33 -22
- package/src/runtime/utils/pending-tool-calls.test.ts +57 -0
- package/src/runtime/utils/pending-tool-calls.ts +35 -0
- package/src/runtime/utils/thread-message-like.ts +2 -0
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +6 -14
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +179 -28
- package/src/runtimes/inert/InertThreadRuntimeCore.test.ts +253 -0
- package/src/runtimes/inert/InertThreadRuntimeCore.ts +232 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +491 -1
- package/src/runtimes/local/local-thread-runtime-core.ts +86 -11
- package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +17 -209
- package/src/runtimes/remote-thread-list/adapter-changed.ts +10 -0
- package/src/runtimes/remote-thread-list/empty-thread-core.ts +28 -221
- package/src/runtimes/remote-thread-list/optimistic-state.test.ts +18 -0
- package/src/runtimes/remote-thread-list/optimistic-state.ts +13 -0
- package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +37 -0
- package/src/runtimes/remote-thread-list/remote-thread-state.ts +123 -0
- package/src/runtimes/remote-thread-list/types.ts +4 -0
- package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +140 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +3 -0
- package/src/store/clients/external-thread.ts +17 -62
- package/src/store/clients/single-thread-list.ts +4 -1
- package/src/store/clients/suggestions.test.ts +31 -0
- package/src/store/clients/suggestions.ts +18 -19
- package/src/store/runtime-clients/handle-runtime-action.test.ts +40 -0
- package/src/store/runtime-clients/handle-runtime-action.ts +3 -0
- package/src/store/scopes/message.ts +1 -1
- package/src/store/scopes/queue-item.ts +2 -9
- package/src/tests/MessageRepository.test.ts +125 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +2 -2
- package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +194 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +8 -6
- package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +158 -0
- package/src/tests/empty-thread-core.test.ts +6 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +184 -0
- package/src/tests/external-store-thread-runtime-core.test.ts +642 -0
- package/src/tests/external-thread-attachments.test.tsx +173 -0
- package/src/tests/external-thread-isEmpty.test.tsx +100 -0
- package/src/tests/remote-thread-list-adapter-switch.test.ts +383 -0
- package/src/tests/single-thread-list-item.test.tsx +47 -0
- package/src/tests/thread-message-like.test.ts +39 -1
- package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +67 -0
- package/src/types/message.ts +9 -4
- package/src/utils/data-url.test.ts +52 -1
- package/src/utils/data-url.ts +21 -0
- package/src/utils/invoke-user-callback.test.ts +82 -0
- package/src/utils/invoke-user-callback.ts +31 -0
- package/src/utils/normalizePartStatus.ts +1 -1
- package/src/utils/silent-runtime-action.ts +6 -0
- package/dist/store/scopes/queue-item.js.map +0 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ThreadListRuntimeCore } from "../../runtime/interfaces/thread-list-runtime-core";
|
|
2
|
-
import { generateId } from "../../utils/id";
|
|
3
2
|
import { BaseSubscribable } from "../../subscribable/subscribable";
|
|
4
3
|
import { OptimisticState } from "../../runtimes/remote-thread-list/optimistic-state";
|
|
5
4
|
import { EMPTY_THREAD_CORE } from "../../runtimes/remote-thread-list/empty-thread-core";
|
|
@@ -9,15 +8,21 @@ import type {
|
|
|
9
8
|
} from "../../runtimes/remote-thread-list/remote-thread-state";
|
|
10
9
|
import {
|
|
11
10
|
classifyThreads,
|
|
11
|
+
createEmptyRemoteThreadState,
|
|
12
12
|
createThreadMappingId,
|
|
13
13
|
getThreadData,
|
|
14
14
|
normalizeCursor,
|
|
15
15
|
updateStatusReducer,
|
|
16
|
+
preserveMidLoadTransitions,
|
|
17
|
+
seedNewThread,
|
|
18
|
+
statusSnapshot,
|
|
16
19
|
} from "../../runtimes/remote-thread-list/remote-thread-state";
|
|
17
20
|
import type {
|
|
18
21
|
RemoteThreadListAdapter,
|
|
19
22
|
RemoteThreadListOptions,
|
|
23
|
+
RemoteThreadMetadata,
|
|
20
24
|
} from "../../runtimes/remote-thread-list/types";
|
|
25
|
+
import { ThreadListAdapterChangedError } from "../../runtimes/remote-thread-list/adapter-changed";
|
|
21
26
|
import { RemoteThreadListHookInstanceManager } from "./RemoteThreadListHookInstanceManager";
|
|
22
27
|
import { isTitleSourceMessage } from "./RemoteThreadResource";
|
|
23
28
|
import {
|
|
@@ -47,6 +52,8 @@ const threadStatusError = (
|
|
|
47
52
|
`Thread "${threadIdOrRemoteId}" has status "${status}", so it cannot ${action}.`,
|
|
48
53
|
);
|
|
49
54
|
|
|
55
|
+
const EMPTY_REMOTE_STATE = createEmptyRemoteThreadState();
|
|
56
|
+
|
|
50
57
|
export class RemoteThreadListThreadListRuntimeCore
|
|
51
58
|
extends BaseSubscribable
|
|
52
59
|
implements ThreadListRuntimeCore
|
|
@@ -58,20 +65,16 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
58
65
|
private _loadThreadsPromise: Promise<void> | undefined;
|
|
59
66
|
private _loadMorePromise: Promise<void> | undefined;
|
|
60
67
|
private _loadGeneration = 0;
|
|
68
|
+
private _adapterGeneration = 0;
|
|
69
|
+
private _replaceListOnNextLoad = false;
|
|
70
|
+
private _staleThreadIdsOnReplace: ReadonlySet<string> | undefined;
|
|
61
71
|
private _switchGeneration = 0;
|
|
62
72
|
private _switchTask: Promise<void> | undefined;
|
|
63
73
|
|
|
64
74
|
private _mainThreadId!: string;
|
|
65
|
-
private readonly _state = new OptimisticState<RemoteThreadState>(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
cursor: undefined,
|
|
69
|
-
newThreadId: undefined,
|
|
70
|
-
threadIds: [],
|
|
71
|
-
archivedThreadIds: [],
|
|
72
|
-
threadIdMap: {},
|
|
73
|
-
threadData: {},
|
|
74
|
-
});
|
|
75
|
+
private readonly _state = new OptimisticState<RemoteThreadState>(
|
|
76
|
+
EMPTY_REMOTE_STATE,
|
|
77
|
+
);
|
|
75
78
|
|
|
76
79
|
private readonly _useAdaptersProvider: FC<PropsWithChildren> = ({
|
|
77
80
|
children,
|
|
@@ -117,6 +120,8 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
117
120
|
// TODO this needs to be cached in case this promise is loaded during suspense
|
|
118
121
|
if (!this._loadThreadsPromise) {
|
|
119
122
|
const generation = this._loadGeneration;
|
|
123
|
+
let replacedList = false;
|
|
124
|
+
const statusAtRequest = statusSnapshot(this._state.baseValue);
|
|
120
125
|
this._loadThreadsPromise = this._state
|
|
121
126
|
.optimisticUpdate({
|
|
122
127
|
execute: () => this._options.adapter.list(),
|
|
@@ -128,40 +133,59 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
128
133
|
},
|
|
129
134
|
then: (state, l) => {
|
|
130
135
|
if (generation !== this._loadGeneration) return state;
|
|
136
|
+
const replaceList = this._replaceListOnNextLoad;
|
|
137
|
+
if (replaceList) {
|
|
138
|
+
this._replaceListOnNextLoad = false;
|
|
139
|
+
replacedList = true;
|
|
140
|
+
return this._replaceWithThreads(
|
|
141
|
+
state,
|
|
142
|
+
l.threads,
|
|
143
|
+
normalizeCursor(l.nextCursor),
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
131
147
|
const fresh = classifyThreads(l.threads, {
|
|
132
148
|
threadIds: [],
|
|
133
149
|
archivedThreadIds: [],
|
|
134
150
|
threadIdMap: {},
|
|
135
151
|
threadData: {},
|
|
136
152
|
});
|
|
137
|
-
|
|
138
|
-
return {
|
|
153
|
+
const merged = {
|
|
139
154
|
...state,
|
|
140
155
|
isLoading: false,
|
|
141
156
|
cursor: normalizeCursor(l.nextCursor),
|
|
142
157
|
threadIds: fresh.threadIds,
|
|
143
158
|
archivedThreadIds: fresh.archivedThreadIds,
|
|
144
|
-
threadIdMap: {
|
|
145
|
-
|
|
146
|
-
...fresh.threadIdMap,
|
|
147
|
-
},
|
|
148
|
-
threadData: {
|
|
149
|
-
...state.threadData,
|
|
150
|
-
...fresh.threadData,
|
|
151
|
-
},
|
|
159
|
+
threadIdMap: { ...state.threadIdMap, ...fresh.threadIdMap },
|
|
160
|
+
threadData: { ...state.threadData, ...fresh.threadData },
|
|
152
161
|
};
|
|
162
|
+
return preserveMidLoadTransitions(merged, state, statusAtRequest);
|
|
153
163
|
},
|
|
154
164
|
})
|
|
155
165
|
.catch((error: unknown) => {
|
|
156
166
|
if (generation !== this._loadGeneration) return;
|
|
157
167
|
console.error("[assistant-ui] thread list load failed:", error);
|
|
158
168
|
this._loadThreadsPromise = undefined;
|
|
159
|
-
this.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
169
|
+
if (!this._replaceListOnNextLoad) {
|
|
170
|
+
this._state.update({
|
|
171
|
+
...this._state.baseValue,
|
|
172
|
+
isLoading: false,
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
this._replaceListOnNextLoad = false;
|
|
177
|
+
replacedList = true;
|
|
178
|
+
this._state.update(
|
|
179
|
+
this._replaceWithThreads(this._state.baseValue, [], undefined),
|
|
180
|
+
);
|
|
163
181
|
})
|
|
164
|
-
.then(() => {
|
|
182
|
+
.then(() => {
|
|
183
|
+
if (!replacedList) return;
|
|
184
|
+
const threadId = this._options.threadId;
|
|
185
|
+
if (threadId === undefined) return;
|
|
186
|
+
if (this.getItemById(threadId)?.id === this._mainThreadId) return;
|
|
187
|
+
this._switchToThreadFromProp(threadId).catch(() => {});
|
|
188
|
+
});
|
|
165
189
|
}
|
|
166
190
|
|
|
167
191
|
return this._loadThreadsPromise;
|
|
@@ -206,6 +230,7 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
206
230
|
},
|
|
207
231
|
})
|
|
208
232
|
.catch((error: unknown) => {
|
|
233
|
+
if (generation !== this._loadGeneration) return;
|
|
209
234
|
console.error("[assistant-ui] thread list loadMore failed:", error);
|
|
210
235
|
})
|
|
211
236
|
.then(() => {
|
|
@@ -237,6 +262,11 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
237
262
|
this._hookManager.__internal_subscribeRunningChanged(() =>
|
|
238
263
|
this._notifySubscribers(),
|
|
239
264
|
);
|
|
265
|
+
this._hookManager.__internal_subscribeRuntimeReplaced(() => {
|
|
266
|
+
// A republish can land during the thread resource's render, where a
|
|
267
|
+
// synchronous notify would re-enter store consumers mid-render.
|
|
268
|
+
queueMicrotask(() => this._notifySubscribers());
|
|
269
|
+
});
|
|
240
270
|
this.useProvider = create(() => ({
|
|
241
271
|
Provider: this.resolveProvider(options.adapter),
|
|
242
272
|
}));
|
|
@@ -268,8 +298,17 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
268
298
|
|
|
269
299
|
if (adapterChanged) {
|
|
270
300
|
this._loadGeneration++;
|
|
301
|
+
this._adapterGeneration++;
|
|
302
|
+
this._switchGeneration++;
|
|
303
|
+
this._switchTask = undefined;
|
|
271
304
|
this._loadThreadsPromise = undefined;
|
|
272
305
|
this._loadMorePromise = undefined;
|
|
306
|
+
this._replaceListOnNextLoad = true;
|
|
307
|
+
this._staleThreadIdsOnReplace = new Set(
|
|
308
|
+
Object.values(this._state.baseValue.threadData)
|
|
309
|
+
.filter((item) => item.status !== "new")
|
|
310
|
+
.map((item) => item.id),
|
|
311
|
+
);
|
|
273
312
|
this._state.update({
|
|
274
313
|
...this._state.baseValue,
|
|
275
314
|
cursor: undefined,
|
|
@@ -281,6 +320,115 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
281
320
|
}
|
|
282
321
|
}
|
|
283
322
|
|
|
323
|
+
private _requireAdapterGeneration(generation: number) {
|
|
324
|
+
if (generation !== this._adapterGeneration) {
|
|
325
|
+
throw new ThreadListAdapterChangedError();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private _requireAdapterSettled() {
|
|
330
|
+
if (this._replaceListOnNextLoad) {
|
|
331
|
+
throw new ThreadListAdapterChangedError();
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private _replaceWithThreads(
|
|
336
|
+
state: RemoteThreadState,
|
|
337
|
+
threads: readonly RemoteThreadMetadata[],
|
|
338
|
+
cursor: string | undefined,
|
|
339
|
+
): RemoteThreadState {
|
|
340
|
+
const fresh = classifyThreads(threads, {
|
|
341
|
+
threadIds: [],
|
|
342
|
+
archivedThreadIds: [],
|
|
343
|
+
threadIdMap: {},
|
|
344
|
+
threadData: {},
|
|
345
|
+
});
|
|
346
|
+
const threadIdMap = { ...fresh.threadIdMap };
|
|
347
|
+
const threadData = { ...fresh.threadData };
|
|
348
|
+
const threadIds = [...fresh.threadIds];
|
|
349
|
+
const archivedThreadIds = [...fresh.archivedThreadIds];
|
|
350
|
+
|
|
351
|
+
if (state.newThreadId) {
|
|
352
|
+
const mappingId = state.threadIdMap[state.newThreadId];
|
|
353
|
+
const draft = mappingId ? state.threadData[mappingId] : undefined;
|
|
354
|
+
if (draft?.status === "new") {
|
|
355
|
+
threadIdMap[state.newThreadId] = mappingId!;
|
|
356
|
+
threadData[mappingId!] = draft;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const stale = this._staleThreadIdsOnReplace;
|
|
361
|
+
if (stale) {
|
|
362
|
+
for (const item of Object.values(state.threadData)) {
|
|
363
|
+
if (stale.has(item.id)) continue;
|
|
364
|
+
if (item.status !== "new" && item.remoteId === undefined) continue;
|
|
365
|
+
const mappingId = createThreadMappingId(item.id);
|
|
366
|
+
if (threadData[mappingId]) continue;
|
|
367
|
+
threadIdMap[item.id] = mappingId;
|
|
368
|
+
if (item.remoteId !== undefined) {
|
|
369
|
+
threadIdMap[item.remoteId] = mappingId;
|
|
370
|
+
}
|
|
371
|
+
threadData[mappingId] = item;
|
|
372
|
+
if (item.remoteId === undefined) continue;
|
|
373
|
+
if (item.status === "regular" && !threadIds.includes(item.remoteId)) {
|
|
374
|
+
threadIds.push(item.remoteId);
|
|
375
|
+
} else if (
|
|
376
|
+
item.status === "archived" &&
|
|
377
|
+
!archivedThreadIds.includes(item.remoteId)
|
|
378
|
+
) {
|
|
379
|
+
archivedThreadIds.push(item.remoteId);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
this._staleThreadIdsOnReplace = undefined;
|
|
384
|
+
|
|
385
|
+
let nextState: RemoteThreadState = {
|
|
386
|
+
...state,
|
|
387
|
+
isLoading: false,
|
|
388
|
+
cursor,
|
|
389
|
+
threadIds,
|
|
390
|
+
archivedThreadIds,
|
|
391
|
+
threadIdMap,
|
|
392
|
+
threadData,
|
|
393
|
+
newThreadId:
|
|
394
|
+
state.newThreadId !== undefined &&
|
|
395
|
+
threadIdMap[state.newThreadId] === undefined
|
|
396
|
+
? undefined
|
|
397
|
+
: state.newThreadId,
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
if (getThreadData(nextState, this._mainThreadId) === undefined) {
|
|
401
|
+
const preservedDraft = nextState.newThreadId;
|
|
402
|
+
if (preservedDraft !== undefined) {
|
|
403
|
+
this._mainThreadId = preservedDraft;
|
|
404
|
+
} else {
|
|
405
|
+
const seeded = seedNewThread(nextState);
|
|
406
|
+
this._mainThreadId = seeded.id;
|
|
407
|
+
nextState = seeded.state;
|
|
408
|
+
}
|
|
409
|
+
if (this._options.threadId === undefined) {
|
|
410
|
+
this._notifyThreadIdChange();
|
|
411
|
+
} else {
|
|
412
|
+
this._lastNotifiedThreadId = undefined;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const nextIds = new Set(
|
|
417
|
+
Object.values(nextState.threadData).map((item) => item.id),
|
|
418
|
+
);
|
|
419
|
+
for (const item of Object.values(state.threadData)) {
|
|
420
|
+
if (!nextIds.has(item.id)) {
|
|
421
|
+
this._hookManager.stopThreadRuntime(item.id);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
void this._hookManager.startThreadRuntime(this._mainThreadId).then(
|
|
425
|
+
() => this._notifySubscribers(),
|
|
426
|
+
() => undefined,
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
return nextState;
|
|
430
|
+
}
|
|
431
|
+
|
|
284
432
|
public __internal_load() {
|
|
285
433
|
this.getLoadThreadsPromise(); // begin loading on initial bind
|
|
286
434
|
if (this._initialThreadLoaded) return;
|
|
@@ -440,6 +588,12 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
440
588
|
generation: number,
|
|
441
589
|
emitThreadIdChange: boolean,
|
|
442
590
|
): Promise<void> {
|
|
591
|
+
if (
|
|
592
|
+
this._replaceListOnNextLoad &&
|
|
593
|
+
threadIdOrRemoteId !== this._state.value.newThreadId
|
|
594
|
+
) {
|
|
595
|
+
throw new ThreadListAdapterChangedError();
|
|
596
|
+
}
|
|
443
597
|
let data = this.getItemById(threadIdOrRemoteId);
|
|
444
598
|
|
|
445
599
|
if (!data) {
|
|
@@ -573,48 +727,32 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
573
727
|
const state = this._state.baseValue;
|
|
574
728
|
let id: string | undefined = this._state.value.newThreadId;
|
|
575
729
|
if (id === undefined) {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
const mappingId = createThreadMappingId(id);
|
|
581
|
-
this._state.update({
|
|
582
|
-
...state,
|
|
583
|
-
newThreadId: id,
|
|
584
|
-
threadIdMap: {
|
|
585
|
-
...state.threadIdMap,
|
|
586
|
-
[id]: mappingId,
|
|
587
|
-
},
|
|
588
|
-
threadData: {
|
|
589
|
-
...state.threadData,
|
|
590
|
-
[mappingId]: {
|
|
591
|
-
status: "new",
|
|
592
|
-
id,
|
|
593
|
-
remoteId: undefined,
|
|
594
|
-
externalId: undefined,
|
|
595
|
-
title: undefined,
|
|
596
|
-
custom: undefined,
|
|
597
|
-
} satisfies RemoteThreadData,
|
|
598
|
-
},
|
|
599
|
-
});
|
|
730
|
+
const next = seedNewThread(state);
|
|
731
|
+
id = next.id;
|
|
732
|
+
this._state.update(next.state);
|
|
600
733
|
}
|
|
601
734
|
|
|
602
735
|
return this._switchToThread(id, undefined, generation, emitThreadIdChange);
|
|
603
736
|
}
|
|
604
737
|
|
|
605
738
|
public initialize = async (threadId: string) => {
|
|
739
|
+
const adapter = this._options.adapter;
|
|
740
|
+
const adapterGeneration = this._adapterGeneration;
|
|
606
741
|
if (this._state.value.newThreadId !== threadId) {
|
|
742
|
+
this._requireAdapterSettled();
|
|
607
743
|
const data = this.getItemById(threadId);
|
|
608
744
|
if (!data) throw threadNotFoundError(threadId, "initializing it");
|
|
609
745
|
if (data.status === "new")
|
|
610
746
|
throw threadStatusError(threadId, data.status, "be initialized here");
|
|
611
747
|
const { remoteId, externalId } = await data.initializeTask;
|
|
748
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
612
749
|
return { remoteId, externalId };
|
|
613
750
|
}
|
|
614
751
|
|
|
615
752
|
const { remoteId, externalId } = await this._state.optimisticUpdate({
|
|
616
753
|
execute: () => {
|
|
617
|
-
|
|
754
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
755
|
+
return adapter.initialize(threadId);
|
|
618
756
|
},
|
|
619
757
|
optimistic: (state) => {
|
|
620
758
|
return updateStatusReducer(state, threadId, "regular");
|
|
@@ -633,6 +771,7 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
633
771
|
};
|
|
634
772
|
},
|
|
635
773
|
then: (state, { remoteId, externalId }) => {
|
|
774
|
+
if (adapterGeneration !== this._adapterGeneration) return state;
|
|
636
775
|
const data = getThreadData(state, threadId);
|
|
637
776
|
if (!data) return state;
|
|
638
777
|
|
|
@@ -655,16 +794,21 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
655
794
|
};
|
|
656
795
|
},
|
|
657
796
|
});
|
|
797
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
658
798
|
return { remoteId, externalId };
|
|
659
799
|
};
|
|
660
800
|
|
|
661
801
|
public generateTitle = async (threadId: string) => {
|
|
802
|
+
this._requireAdapterSettled();
|
|
803
|
+
const adapter = this._options.adapter;
|
|
804
|
+
const adapterGeneration = this._adapterGeneration;
|
|
662
805
|
const data = this.getItemById(threadId);
|
|
663
806
|
if (!data) throw threadNotFoundError(threadId, "generating its title");
|
|
664
807
|
if (data.status === "new")
|
|
665
808
|
throw threadStatusError(threadId, data.status, "generate a title");
|
|
666
809
|
|
|
667
810
|
const { remoteId } = await data.initializeTask;
|
|
811
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
668
812
|
|
|
669
813
|
const runtimeCore = this._hookManager.getThreadRuntimeCore(data.id);
|
|
670
814
|
if (!runtimeCore) return; // thread is no longer running
|
|
@@ -673,30 +817,39 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
673
817
|
// would make the payload race-dependent; the title reads settled
|
|
674
818
|
// messages only, matching the trigger's readiness gate.
|
|
675
819
|
const messages = runtimeCore.messages.filter(isTitleSourceMessage);
|
|
676
|
-
const stream = await
|
|
677
|
-
remoteId,
|
|
678
|
-
messages,
|
|
679
|
-
);
|
|
820
|
+
const stream = await adapter.generateTitle(remoteId, messages);
|
|
680
821
|
const messageStream = AssistantMessageStream.fromAssistantStream(stream);
|
|
681
822
|
for await (const result of messageStream) {
|
|
823
|
+
if (adapterGeneration !== this._adapterGeneration) return;
|
|
682
824
|
const newTitle = result.parts.filter((c) => c.type === "text")[0]?.text;
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
825
|
+
await this._state.optimisticUpdate({
|
|
826
|
+
execute: async () => {},
|
|
827
|
+
optimistic: (state) => {
|
|
828
|
+
if (adapterGeneration !== this._adapterGeneration) return state;
|
|
829
|
+
const currentData = getThreadData(state, data.id);
|
|
830
|
+
if (!currentData) return state;
|
|
831
|
+
return {
|
|
832
|
+
...state,
|
|
833
|
+
threadData: {
|
|
834
|
+
...state.threadData,
|
|
835
|
+
[currentData.id]: {
|
|
836
|
+
...currentData,
|
|
837
|
+
title: newTitle,
|
|
838
|
+
},
|
|
839
|
+
},
|
|
840
|
+
};
|
|
694
841
|
},
|
|
695
842
|
});
|
|
696
843
|
}
|
|
697
844
|
};
|
|
698
845
|
|
|
699
|
-
public rename(
|
|
846
|
+
public async rename(
|
|
847
|
+
threadIdOrRemoteId: string,
|
|
848
|
+
newTitle: string,
|
|
849
|
+
): Promise<void> {
|
|
850
|
+
this._requireAdapterSettled();
|
|
851
|
+
const adapter = this._options.adapter;
|
|
852
|
+
const adapterGeneration = this._adapterGeneration;
|
|
700
853
|
const data = this.getItemById(threadIdOrRemoteId);
|
|
701
854
|
if (!data) throw threadNotFoundError(threadIdOrRemoteId, "renaming it");
|
|
702
855
|
if (data.status === "new")
|
|
@@ -705,7 +858,8 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
705
858
|
return this._state.optimisticUpdate({
|
|
706
859
|
execute: async () => {
|
|
707
860
|
const { remoteId } = await data.initializeTask;
|
|
708
|
-
|
|
861
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
862
|
+
return adapter.rename(remoteId, newTitle);
|
|
709
863
|
},
|
|
710
864
|
optimistic: (state) => {
|
|
711
865
|
const data = getThreadData(state, threadIdOrRemoteId);
|
|
@@ -725,10 +879,13 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
725
879
|
});
|
|
726
880
|
}
|
|
727
881
|
|
|
728
|
-
public updateCustom(
|
|
882
|
+
public async updateCustom(
|
|
729
883
|
threadIdOrRemoteId: string,
|
|
730
884
|
custom: Record<string, unknown> | undefined,
|
|
731
885
|
): Promise<void> {
|
|
886
|
+
this._requireAdapterSettled();
|
|
887
|
+
const adapter = this._options.adapter;
|
|
888
|
+
const adapterGeneration = this._adapterGeneration;
|
|
732
889
|
const data = this.getItemById(threadIdOrRemoteId);
|
|
733
890
|
if (!data)
|
|
734
891
|
throw threadNotFoundError(
|
|
@@ -742,7 +899,7 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
742
899
|
"update custom metadata",
|
|
743
900
|
);
|
|
744
901
|
|
|
745
|
-
if (!
|
|
902
|
+
if (!adapter.updateCustom) {
|
|
746
903
|
throw new Error(
|
|
747
904
|
"Remote thread list adapter does not support updating custom metadata",
|
|
748
905
|
);
|
|
@@ -751,7 +908,7 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
751
908
|
return this._state.optimisticUpdate({
|
|
752
909
|
execute: async () => {
|
|
753
910
|
const { remoteId } = await data.initializeTask;
|
|
754
|
-
|
|
911
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
755
912
|
if (!adapter.updateCustom) {
|
|
756
913
|
throw new Error(
|
|
757
914
|
"Remote thread list adapter does not support updating custom metadata",
|
|
@@ -800,17 +957,22 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
800
957
|
}
|
|
801
958
|
|
|
802
959
|
public async archive(threadIdOrRemoteId: string) {
|
|
960
|
+
this._requireAdapterSettled();
|
|
961
|
+
const adapter = this._options.adapter;
|
|
962
|
+
const adapterGeneration = this._adapterGeneration;
|
|
803
963
|
const data = this.getItemById(threadIdOrRemoteId);
|
|
804
964
|
if (!data) throw threadNotFoundError(threadIdOrRemoteId, "archiving it");
|
|
805
965
|
if (data.status !== "regular")
|
|
806
966
|
throw threadStatusError(threadIdOrRemoteId, data.status, "be archived");
|
|
807
967
|
|
|
808
968
|
await this._ensureThreadIsNotMain(data.id);
|
|
969
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
809
970
|
|
|
810
971
|
return this._state.optimisticUpdate({
|
|
811
972
|
execute: async () => {
|
|
812
973
|
const { remoteId } = await data.initializeTask;
|
|
813
|
-
|
|
974
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
975
|
+
return adapter.archive(remoteId);
|
|
814
976
|
},
|
|
815
977
|
optimistic: (state) => {
|
|
816
978
|
return updateStatusReducer(state, data.id, "archived");
|
|
@@ -818,7 +980,10 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
818
980
|
});
|
|
819
981
|
}
|
|
820
982
|
|
|
821
|
-
public unarchive(threadIdOrRemoteId: string): Promise<void> {
|
|
983
|
+
public async unarchive(threadIdOrRemoteId: string): Promise<void> {
|
|
984
|
+
this._requireAdapterSettled();
|
|
985
|
+
const adapter = this._options.adapter;
|
|
986
|
+
const adapterGeneration = this._adapterGeneration;
|
|
822
987
|
const data = this.getItemById(threadIdOrRemoteId);
|
|
823
988
|
if (!data) throw threadNotFoundError(threadIdOrRemoteId, "unarchiving it");
|
|
824
989
|
if (data.status !== "archived")
|
|
@@ -828,9 +993,12 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
828
993
|
execute: async () => {
|
|
829
994
|
try {
|
|
830
995
|
const { remoteId } = await data.initializeTask;
|
|
831
|
-
|
|
996
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
997
|
+
return await adapter.unarchive(remoteId);
|
|
832
998
|
} catch (error) {
|
|
833
|
-
|
|
999
|
+
if (adapterGeneration === this._adapterGeneration) {
|
|
1000
|
+
await this._ensureThreadIsNotMain(data.id);
|
|
1001
|
+
}
|
|
834
1002
|
throw error;
|
|
835
1003
|
}
|
|
836
1004
|
},
|
|
@@ -841,18 +1009,23 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
841
1009
|
}
|
|
842
1010
|
|
|
843
1011
|
public async delete(threadIdOrRemoteId: string) {
|
|
1012
|
+
this._requireAdapterSettled();
|
|
1013
|
+
const adapter = this._options.adapter;
|
|
1014
|
+
const adapterGeneration = this._adapterGeneration;
|
|
844
1015
|
const data = this.getItemById(threadIdOrRemoteId);
|
|
845
1016
|
if (!data) throw threadNotFoundError(threadIdOrRemoteId, "deleting it");
|
|
846
1017
|
if (data.status !== "regular" && data.status !== "archived")
|
|
847
1018
|
throw threadStatusError(threadIdOrRemoteId, data.status, "be deleted");
|
|
848
1019
|
|
|
849
1020
|
await this._ensureThreadIsNotMain(data.id);
|
|
1021
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
850
1022
|
this._hookManager.stopThreadRuntime(data.id);
|
|
851
1023
|
|
|
852
1024
|
return this._state.optimisticUpdate({
|
|
853
1025
|
execute: async () => {
|
|
854
1026
|
const { remoteId } = await data.initializeTask;
|
|
855
|
-
|
|
1027
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
1028
|
+
return await adapter.delete(remoteId);
|
|
856
1029
|
},
|
|
857
1030
|
optimistic: (state) => {
|
|
858
1031
|
return updateStatusReducer(state, data.id, "deleted");
|
|
@@ -865,12 +1038,14 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
865
1038
|
}
|
|
866
1039
|
|
|
867
1040
|
public async detach(threadIdOrRemoteId: string): Promise<void> {
|
|
1041
|
+
const adapterGeneration = this._adapterGeneration;
|
|
868
1042
|
const data = this.getItemById(threadIdOrRemoteId);
|
|
869
1043
|
if (!data) throw threadNotFoundError(threadIdOrRemoteId, "detaching it");
|
|
870
1044
|
if (data.status !== "regular" && data.status !== "archived")
|
|
871
1045
|
throw threadStatusError(threadIdOrRemoteId, data.status, "be detached");
|
|
872
1046
|
|
|
873
1047
|
await this._ensureThreadIsNotMain(data.id);
|
|
1048
|
+
this._requireAdapterGeneration(adapterGeneration);
|
|
874
1049
|
this._hookManager.stopThreadRuntime(data.id);
|
|
875
1050
|
}
|
|
876
1051
|
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
useRuntimeAdaptersProvider,
|
|
22
22
|
type RuntimeAdapters,
|
|
23
23
|
} from "./RuntimeAdapterProvider";
|
|
24
|
+
import { isSilentRuntimeAction } from "../../utils/silent-runtime-action";
|
|
24
25
|
|
|
25
26
|
export type RemoteThreadListHook = () => AssistantRuntime;
|
|
26
27
|
|
|
@@ -48,6 +49,7 @@ export const subscribeToTitleGeneration = (
|
|
|
48
49
|
) => {
|
|
49
50
|
const generate = () =>
|
|
50
51
|
void itemRuntime.generateTitle().catch((error: unknown) => {
|
|
52
|
+
if (isSilentRuntimeAction(error)) return;
|
|
51
53
|
console.error("[assistant-ui] Thread title generation failed", error);
|
|
52
54
|
});
|
|
53
55
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { invokeUserCallback } from "../../../utils/invoke-user-callback";
|
|
2
3
|
import { useLatestRef } from "./useLatestRef";
|
|
3
4
|
|
|
4
5
|
export type RunManager = Readonly<{
|
|
@@ -11,25 +12,11 @@ const disposeReason = Symbol("assistant-transport-dispose");
|
|
|
11
12
|
|
|
12
13
|
type LifecycleCallbackName = "onCancel" | "onError" | "onFinish";
|
|
13
14
|
|
|
14
|
-
const
|
|
15
|
-
console.error(
|
|
16
|
-
`[assistant-ui] Assistant transport ${name} callback threw an error`,
|
|
17
|
-
error,
|
|
18
|
-
);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const invokeCallback = async (
|
|
15
|
+
const invokeCallback = (
|
|
22
16
|
name: LifecycleCallbackName,
|
|
23
17
|
callback: (() => unknown) | undefined,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
await callback?.();
|
|
27
|
-
} catch (error) {
|
|
28
|
-
try {
|
|
29
|
-
reportCallbackError(name, error);
|
|
30
|
-
} catch {}
|
|
31
|
-
}
|
|
32
|
-
};
|
|
18
|
+
) =>
|
|
19
|
+
invokeUserCallback("assistant-ui", `Assistant transport ${name}`, callback);
|
|
33
20
|
|
|
34
21
|
export function useRunManager(config: {
|
|
35
22
|
onRun: (signal: AbortSignal) => Promise<void>;
|