@assistant-ui/core 0.3.17 → 0.3.19
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/attachment.d.ts.map +1 -1
- package/dist/adapters/attachment.js +5 -4
- package/dist/adapters/attachment.js.map +1 -1
- package/dist/adapters/speech.d.ts.map +1 -1
- package/dist/adapters/speech.js +13 -3
- package/dist/adapters/speech.js.map +1 -1
- package/dist/adapters/thread-history.d.ts +4 -0
- package/dist/adapters/thread-history.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +4 -3
- package/dist/internal.js +3 -2
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +35 -14
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts +2 -0
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +30 -7
- package/dist/model-context/frame/provider.js.map +1 -1
- package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
- package/dist/model-context/interactable-composer-metadata.js +27 -18
- package/dist/model-context/interactable-composer-metadata.js.map +1 -1
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/registry.js +3 -5
- package/dist/model-context/registry.js.map +1 -1
- package/dist/model-context/types.d.ts.map +1 -1
- package/dist/model-context/types.js +5 -4
- package/dist/model-context/types.js.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +45 -7
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/DataRenderers.d.ts.map +1 -1
- package/dist/react/client/DataRenderers.js +20 -15
- package/dist/react/client/DataRenderers.js.map +1 -1
- package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
- package/dist/react/client/InMemoryThreadList.js +62 -56
- 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 +35 -32
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +1 -0
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
- package/dist/react/client/RemoteThreadList.js +154 -143
- package/dist/react/client/RemoteThreadList.js.map +1 -1
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +18 -16
- 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 +3 -2
- package/dist/react/client/interactable-model-context.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +2 -2
- package/dist/react/interactables-legacy/Interactables.js +242 -121
- package/dist/react/interactables-legacy/Interactables.js.map +1 -1
- package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
- package/dist/react/interactables-legacy/useAssistantInteractable.js +3 -0
- package/dist/react/interactables-legacy/useAssistantInteractable.js.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +11 -9
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -1
- package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
- package/dist/react/model-context/makeAssistantTool.js +1 -1
- package/dist/react/model-context/makeAssistantTool.js.map +1 -1
- package/dist/react/model-context/useAssistantTool.d.ts +2 -2
- package/dist/react/model-context/useAssistantTool.js +1 -1
- package/dist/react/model-context/useAssistantTool.js.map +1 -1
- package/dist/react/model-context/useInteractable.d.ts.map +1 -1
- package/dist/react/model-context/useInteractable.js +4 -1
- package/dist/react/model-context/useInteractable.js.map +1 -1
- package/dist/react/model-context/useInteractableVersions.js +1 -1
- package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.js +2 -1
- package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.d.ts +11 -2
- package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.js +3 -2
- package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
- package/dist/react/primitives/part/PartMessages.d.ts +1 -0
- package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
- package/dist/react/primitives/part/PartMessages.js +1 -0
- package/dist/react/primitives/part/PartMessages.js.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js +6 -5
- package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +16 -8
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +5 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +105 -104
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts +1 -0
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.js +13 -11
- package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +5 -24
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +354 -226
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -0
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +22 -2
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +40 -15
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +62 -15
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +2 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +6 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/sdkIdentity.d.ts +6 -0
- package/dist/react/runtimes/cloud/sdkIdentity.d.ts.map +1 -0
- package/dist/react/runtimes/cloud/sdkIdentity.js +9 -0
- package/dist/react/runtimes/cloud/sdkIdentity.js.map +1 -0
- package/dist/react/runtimes/external-message-converter.d.ts +12 -2
- package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +26 -61
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.js +75 -46
- package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.js +64 -24
- package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
- package/dist/react/utils/groupParts.d.ts +6 -1
- package/dist/react/utils/groupParts.d.ts.map +1 -1
- package/dist/react/utils/groupParts.js +6 -0
- package/dist/react/utils/groupParts.js.map +1 -1
- package/dist/react/utils/useJSONEqual.d.ts +3 -1
- package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
- package/dist/react/utils/useJSONEqual.js +6 -1
- package/dist/react/utils/useJSONEqual.js.map +1 -1
- package/dist/react/utils/useJSONSchemaDependency.d.ts +7 -0
- package/dist/react/utils/useJSONSchemaDependency.d.ts.map +1 -0
- package/dist/react/utils/useJSONSchemaDependency.js +20 -0
- package/dist/react/utils/useJSONSchemaDependency.js.map +1 -0
- package/dist/runtime/api/thread-list-item-runtime.d.ts +7 -3
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.js +2 -2
- package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +3 -0
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +18 -14
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +4 -0
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +3 -6
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -0
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +62 -22
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -0
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +161 -69
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts +12 -5
- package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +4 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.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/queue/message-queue.d.ts +5 -0
- package/dist/runtime/queue/message-queue.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.js +61 -6
- package/dist/runtime/queue/message-queue.js.map +1 -1
- package/dist/runtime/utils/auto-status.d.ts +6 -2
- package/dist/runtime/utils/auto-status.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.js +12 -4
- package/dist/runtime/utils/auto-status.js.map +1 -1
- package/dist/runtime/utils/external-message-conversion.d.ts +16 -4
- package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
- package/dist/runtime/utils/external-message-conversion.js +49 -13
- package/dist/runtime/utils/external-message-conversion.js.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts +1 -0
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +18 -9
- package/dist/runtime/utils/message-repository.js.map +1 -1
- 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 +5 -3
- package/dist/runtime/utils/thread-message-like.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 +21 -27
- 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.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +8 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/internal.d.ts +3 -3
- package/dist/runtimes/internal.js +2 -2
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +4 -1
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +18 -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 +130 -42
- package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/title-generation.d.ts +49 -0
- package/dist/runtimes/remote-thread-list/title-generation.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/title-generation.js +197 -0
- package/dist/runtimes/remote-thread-list/title-generation.js.map +1 -0
- package/dist/runtimes/remote-thread-list/title.d.ts +3 -1
- package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/title.js +9 -1
- package/dist/runtimes/remote-thread-list/title.js.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +10 -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 -1
- 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 +260 -203
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/model-context-client.d.ts.map +1 -1
- package/dist/store/clients/model-context-client.js +2 -1
- package/dist/store/clients/model-context-client.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 -0
- 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 +5 -4
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/clients/thread-tasks.d.ts +13 -0
- package/dist/store/clients/thread-tasks.d.ts.map +1 -0
- package/dist/store/clients/thread-tasks.js +69 -0
- package/dist/store/clients/thread-tasks.js.map +1 -0
- package/dist/store/index.d.ts +3 -2
- package/dist/store/index.js +3 -3
- package/dist/store/primitive-predicates.d.ts.map +1 -1
- package/dist/store/primitive-predicates.js +4 -4
- package/dist/store/primitive-predicates.js.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.js +97 -61
- package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.js +221 -144
- package/dist/store/runtime-clients/message-runtime-client.js.map +1 -1
- 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 +1 -1
- 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 +54 -52
- 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 +246 -126
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/scope-registration.d.ts +2 -0
- package/dist/store/scope-registration.d.ts.map +1 -1
- package/dist/store/scopes/composer.d.ts +10 -2
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/message.d.ts +30 -1
- package/dist/store/scopes/message.d.ts.map +1 -1
- package/dist/store/scopes/task.d.ts +36 -0
- package/dist/store/scopes/task.d.ts.map +1 -0
- package/dist/store/scopes/task.js +0 -0
- package/dist/store/scopes/thread-list-item.d.ts +2 -2
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/dist/store/scopes/thread.d.ts +28 -0
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/store/scopes/threads.d.ts +1 -0
- 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 -15
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/types/attachment.d.ts +2 -1
- package/dist/types/attachment.d.ts.map +1 -1
- package/dist/types/attachment.js +2 -1
- package/dist/types/attachment.js.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/message.d.ts +8 -1
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/abortable-iterable.d.ts +19 -0
- package/dist/utils/abortable-iterable.d.ts.map +1 -0
- package/dist/utils/abortable-iterable.js +88 -0
- package/dist/utils/abortable-iterable.js.map +1 -0
- package/dist/utils/composite-context-provider.d.ts.map +1 -1
- package/dist/utils/composite-context-provider.js +20 -2
- package/dist/utils/composite-context-provider.js.map +1 -1
- package/dist/utils/getGroupStatus.d.ts +18 -2
- package/dist/utils/getGroupStatus.d.ts.map +1 -1
- package/dist/utils/getGroupStatus.js +32 -7
- package/dist/utils/getGroupStatus.js.map +1 -1
- package/dist/utils/record.d.ts +11 -0
- package/dist/utils/record.d.ts.map +1 -0
- package/dist/utils/record.js +12 -0
- package/dist/utils/record.js.map +1 -0
- package/dist/utils/wire-media.d.ts.map +1 -1
- package/dist/utils/wire-media.js +2 -2
- package/dist/utils/wire-media.js.map +1 -1
- package/package.json +11 -11
- package/src/adapters/attachment.test.ts +50 -1
- package/src/adapters/attachment.ts +7 -4
- package/src/adapters/speech.test.ts +236 -0
- package/src/adapters/speech.ts +17 -10
- package/src/adapters/thread-history.ts +3 -0
- package/src/index.ts +2 -0
- package/src/internal.ts +4 -0
- package/src/model-context/frame/host.test.ts +137 -1
- package/src/model-context/frame/host.ts +49 -16
- package/src/model-context/frame/provider.test.ts +71 -0
- package/src/model-context/frame/provider.ts +37 -7
- package/src/model-context/interactable-composer-metadata.test.ts +58 -0
- package/src/model-context/interactable-composer-metadata.ts +19 -13
- package/src/model-context/registry.test.ts +12 -0
- package/src/model-context/registry.ts +3 -2
- package/src/model-context/types.test.ts +25 -0
- package/src/model-context/types.ts +9 -4
- package/src/react/RuntimeAdapter.test.ts +34 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +244 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +104 -7
- package/src/react/client/DataRenderers.test.tsx +45 -0
- package/src/react/client/DataRenderers.ts +13 -9
- package/src/react/client/InMemoryThreadList.ts +1 -0
- package/src/react/client/Interactables.test.ts +72 -1
- package/src/react/client/Interactables.ts +22 -14
- package/src/react/client/RemoteThreadList.background.test.ts +148 -6
- package/src/react/client/RemoteThreadList.concurrent.test.tsx +42 -1
- package/src/react/client/RemoteThreadList.test.ts +386 -4
- package/src/react/client/RemoteThreadList.ts +181 -112
- package/src/react/client/Tools.ts +22 -11
- package/src/react/client/interactable-model-context.test.ts +44 -0
- package/src/react/client/interactable-model-context.ts +3 -2
- package/src/react/index.ts +5 -1
- package/src/react/interactables-legacy/Interactables.ts +16 -16
- package/src/react/interactables-legacy/useAssistantInteractable.test.tsx +132 -0
- package/src/react/interactables-legacy/useAssistantInteractable.ts +10 -1
- package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +9 -10
- package/src/react/model-context/makeAssistantTool.ts +2 -2
- package/src/react/model-context/useAssistantTool.ts +2 -2
- package/src/react/model-context/useInteractable.test.tsx +177 -0
- package/src/react/model-context/useInteractable.ts +3 -0
- package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
- package/src/react/model-context/useToolArgsStatus.ts +2 -1
- package/src/react/primitive-hooks/useActionBarCopy.test.ts +0 -1
- package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +0 -1
- package/src/react/primitives/message/MessageGroupedParts.test.tsx +96 -0
- package/src/react/primitives/message/MessageGroupedParts.tsx +15 -4
- package/src/react/primitives/part/PartMessages.test.tsx +104 -1
- package/src/react/primitives/part/PartMessages.tsx +1 -0
- package/src/react/primitives/thread/ThreadMessages.test.tsx +142 -0
- package/src/react/primitives/thread/ThreadMessages.tsx +8 -5
- package/src/react/providers/ReadonlyThreadProvider.test.tsx +56 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.destroy.test.tsx +172 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +33 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +7 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +28 -5
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.load-error.test.ts +132 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +105 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +143 -112
- package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
- package/src/react/runtimes/RemoteThreadResource.ts +19 -12
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +20 -14
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +703 -6
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +492 -402
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +77 -0
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +27 -1
- package/src/react/runtimes/cloud/auiV0.ts +160 -25
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +36 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +8 -1
- package/src/react/runtimes/cloud/sdkIdentity.ts +9 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +18 -4
- package/src/react/runtimes/external-message-converter.test.ts +136 -1
- package/src/react/runtimes/external-message-converter.ts +39 -93
- package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +41 -0
- package/src/react/runtimes/useExternalStoreRuntime.ts +10 -4
- package/src/react/runtimes/useLocalRuntime.test.tsx +20 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.load-error.test.tsx +108 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +34 -1
- package/src/react/utils/groupParts.ts +12 -1
- package/src/react/utils/useJSONEqual.ts +9 -0
- package/src/react/utils/useJSONSchemaDependency.ts +22 -0
- package/src/runtime/api/message-runtime.test.ts +75 -0
- package/src/runtime/api/thread-list-item-runtime.ts +10 -3
- package/src/runtime/api/thread-list-runtime.ts +21 -11
- package/src/runtime/api/thread-runtime.test.ts +136 -0
- package/src/runtime/api/thread-runtime.ts +10 -5
- package/src/runtime/base/base-composer-runtime-core.ts +105 -24
- package/src/runtime/base/base-thread-runtime-core.test.ts +1063 -2
- package/src/runtime/base/base-thread-runtime-core.ts +228 -87
- package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
- package/src/runtime/interfaces/thread-list-runtime-core.ts +5 -1
- package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
- package/src/runtime/queue/message-queue.ts +68 -6
- package/src/runtime/utils/auto-status.test.ts +112 -1
- package/src/runtime/utils/auto-status.ts +31 -5
- package/src/runtime/utils/external-message-conversion.test.ts +202 -0
- package/src/runtime/utils/external-message-conversion.ts +123 -32
- package/src/runtime/utils/message-repository.test.ts +49 -0
- package/src/runtime/utils/message-repository.ts +32 -20
- package/src/runtime/utils/thread-message-like.test.ts +52 -0
- package/src/runtime/utils/thread-message-like.ts +5 -1
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +18 -13
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +31 -1
- package/src/runtimes/internal.ts +1 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +21 -0
- package/src/runtimes/local/local-thread-runtime-core.ts +11 -1
- package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +128 -2
- package/src/runtimes/remote-thread-list/remote-thread-state.ts +182 -42
- package/src/runtimes/remote-thread-list/title-generation.test.ts +602 -0
- package/src/runtimes/remote-thread-list/title-generation.ts +329 -0
- package/src/runtimes/remote-thread-list/title.test.ts +62 -0
- package/src/runtimes/remote-thread-list/title.ts +13 -0
- package/src/runtimes/remote-thread-list/types.ts +10 -0
- package/src/runtimes/tool-invocations/EDGE_CASES.md +2 -6
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +133 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +10 -6
- package/src/store/clients/external-thread.ts +67 -4
- package/src/store/clients/model-context-client.ts +5 -1
- package/src/store/clients/single-thread-list.ts +1 -0
- package/src/store/clients/suggestions.test.ts +40 -0
- package/src/store/clients/suggestions.ts +13 -10
- package/src/store/clients/thread-tasks.test.ts +274 -0
- package/src/store/clients/thread-tasks.ts +138 -0
- package/src/store/index.ts +8 -0
- package/src/store/primitive-predicates.test.ts +48 -5
- package/src/store/primitive-predicates.ts +7 -2
- package/src/store/runtime-clients/composer-runtime-client.ts +42 -9
- package/src/store/runtime-clients/message-runtime-client.ts +54 -6
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +4 -2
- package/src/store/runtime-clients/thread-list-runtime-client.ts +1 -0
- package/src/store/runtime-clients/thread-runtime-client.ts +89 -11
- package/src/store/scope-registration.ts +2 -0
- package/src/store/scopes/composer.ts +16 -4
- package/src/store/scopes/message.ts +14 -0
- package/src/store/scopes/task.ts +34 -0
- package/src/store/scopes/thread-list-item.ts +5 -2
- package/src/store/scopes/thread.ts +20 -0
- package/src/store/scopes/threads.ts +1 -0
- package/src/store/thread-tasks.test.tsx +209 -0
- package/src/subscribable/subscribable.test.ts +156 -1
- package/src/subscribable/subscribable.ts +25 -15
- package/src/tests/MessageRepository.test.ts +117 -5
- package/src/tests/OptimisticState-list-race.test.ts +1 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-initialize-adapter-change.test.ts +38 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +47 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +89 -0
- package/src/tests/attachment-adapters.test.ts +14 -0
- package/src/tests/auiV0Encode.test.ts +300 -0
- package/src/tests/base-composer-runtime-core-send.test.ts +51 -0
- package/src/tests/base-composer-runtime-core.test.ts +353 -2
- package/src/tests/external-store-thread-list-runtime-core.test.ts +83 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +178 -18
- package/src/tests/external-thread-attachments.test.tsx +208 -0
- package/src/tests/external-thread-parity.test.tsx +57 -0
- package/src/tests/groupParts.test.ts +71 -0
- package/src/tests/message-queue.test.ts +253 -0
- package/src/tests/remote-thread-list-isLoading.test.ts +1 -0
- package/src/tests/remote-thread-list-reactive-threadId.test.ts +51 -0
- package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
- package/src/tests/thread-switch-events.test.tsx +78 -0
- package/src/tests/tools-scope-migration.test.tsx +28 -0
- package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +43 -0
- package/src/types/attachment.ts +4 -0
- package/src/types/index.ts +1 -0
- package/src/types/message.ts +8 -0
- package/src/utils/abortable-iterable.test.ts +328 -0
- package/src/utils/abortable-iterable.ts +104 -0
- package/src/utils/composite-context-provider.test.ts +25 -0
- package/src/utils/composite-context-provider.ts +23 -2
- package/src/utils/getGroupStatus.test.ts +70 -4
- package/src/utils/getGroupStatus.ts +35 -12
- package/src/utils/record.test.ts +48 -0
- package/src/utils/record.ts +11 -0
- package/src/utils/wire-media.test.ts +10 -0
- package/src/utils/wire-media.ts +6 -2
|
@@ -1,9 +1,94 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
convertExternalMessages,
|
|
4
|
+
createExternalMessageConversionCache,
|
|
5
|
+
} from "./external-message-converter";
|
|
3
6
|
import type { useExternalMessageConverter } from "./external-message-converter";
|
|
4
7
|
import { isErrorMessageId } from "../../utils/id";
|
|
5
8
|
|
|
6
9
|
describe("convertExternalMessages", () => {
|
|
10
|
+
it("keeps unchanged messages and rebuilds a replaced one with an opt-in cache", () => {
|
|
11
|
+
type Input = { id: string; role: "user" | "assistant"; text: string };
|
|
12
|
+
const metadata = {};
|
|
13
|
+
const cache = createExternalMessageConversionCache();
|
|
14
|
+
const callback: useExternalMessageConverter.Callback<Input> = (
|
|
15
|
+
message,
|
|
16
|
+
) => ({
|
|
17
|
+
id: message.id,
|
|
18
|
+
role: message.role,
|
|
19
|
+
content: message.text,
|
|
20
|
+
});
|
|
21
|
+
const question: Input = { id: "question", role: "user", text: "hi" };
|
|
22
|
+
const answer: Input = { id: "answer", role: "assistant", text: "hel" };
|
|
23
|
+
|
|
24
|
+
const first = convertExternalMessages(
|
|
25
|
+
[question, answer],
|
|
26
|
+
callback,
|
|
27
|
+
true,
|
|
28
|
+
metadata,
|
|
29
|
+
cache,
|
|
30
|
+
);
|
|
31
|
+
const second = convertExternalMessages(
|
|
32
|
+
[question, { ...answer, text: "hello" }],
|
|
33
|
+
callback,
|
|
34
|
+
true,
|
|
35
|
+
metadata,
|
|
36
|
+
cache,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
expect(second[0]).toBe(first[0]);
|
|
40
|
+
expect(second[1]).not.toBe(first[1]);
|
|
41
|
+
expect(second[1]?.content).toMatchObject([{ type: "text", text: "hello" }]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("invalidates cached messages when the callback or metadata changes", () => {
|
|
45
|
+
const input = { text: "nested" };
|
|
46
|
+
const cache = createExternalMessageConversionCache();
|
|
47
|
+
const withFormat =
|
|
48
|
+
(
|
|
49
|
+
format: (text: string) => string,
|
|
50
|
+
): useExternalMessageConverter.Callback<typeof input> =>
|
|
51
|
+
(message, metadata) => ({
|
|
52
|
+
id: "nested",
|
|
53
|
+
role: "assistant",
|
|
54
|
+
content: format(message.text),
|
|
55
|
+
metadata: { timing: metadata.messageTiming?.["nested"] },
|
|
56
|
+
});
|
|
57
|
+
const callback = withFormat((text) => text);
|
|
58
|
+
const uppercaseCallback = withFormat((text) => text.toUpperCase());
|
|
59
|
+
const metadata = {};
|
|
60
|
+
const timing = { streamStartTime: 1, totalChunks: 1, toolCallCount: 0 };
|
|
61
|
+
|
|
62
|
+
const first = convertExternalMessages(
|
|
63
|
+
[input],
|
|
64
|
+
callback,
|
|
65
|
+
false,
|
|
66
|
+
metadata,
|
|
67
|
+
cache,
|
|
68
|
+
);
|
|
69
|
+
const second = convertExternalMessages(
|
|
70
|
+
[input],
|
|
71
|
+
uppercaseCallback,
|
|
72
|
+
false,
|
|
73
|
+
metadata,
|
|
74
|
+
cache,
|
|
75
|
+
);
|
|
76
|
+
const third = convertExternalMessages(
|
|
77
|
+
[input],
|
|
78
|
+
uppercaseCallback,
|
|
79
|
+
false,
|
|
80
|
+
{ messageTiming: { nested: timing } },
|
|
81
|
+
cache,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(second[0]).not.toBe(first[0]);
|
|
85
|
+
expect(second[0]?.content).toMatchObject([
|
|
86
|
+
{ type: "text", text: "NESTED" },
|
|
87
|
+
]);
|
|
88
|
+
expect(third[0]).not.toBe(second[0]);
|
|
89
|
+
expect(third[0]?.metadata).toMatchObject({ timing });
|
|
90
|
+
});
|
|
91
|
+
|
|
7
92
|
describe("reasoning part merging", () => {
|
|
8
93
|
it("should merge reasoning parts with the same parentId", () => {
|
|
9
94
|
const messages = [
|
|
@@ -205,6 +290,56 @@ describe("convertExternalMessages", () => {
|
|
|
205
290
|
expect((toolCallParts[0] as any).argsText).toBe('{"query":"new"}');
|
|
206
291
|
});
|
|
207
292
|
|
|
293
|
+
it("keeps a merged tool call in its original content position", () => {
|
|
294
|
+
const messages = [
|
|
295
|
+
{
|
|
296
|
+
role: "assistant" as const,
|
|
297
|
+
content: [
|
|
298
|
+
{
|
|
299
|
+
type: "tool-call" as const,
|
|
300
|
+
toolCallId: "tc1",
|
|
301
|
+
toolName: "search",
|
|
302
|
+
args: { query: "old" },
|
|
303
|
+
},
|
|
304
|
+
{ type: "text" as const, text: "after tool" },
|
|
305
|
+
],
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
role: "assistant" as const,
|
|
309
|
+
content: [
|
|
310
|
+
{
|
|
311
|
+
type: "tool-call" as const,
|
|
312
|
+
toolCallId: "tc1",
|
|
313
|
+
toolName: "search",
|
|
314
|
+
args: { query: "new" },
|
|
315
|
+
},
|
|
316
|
+
],
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
role: "tool" as const,
|
|
320
|
+
toolCallId: "tc1",
|
|
321
|
+
result: "found",
|
|
322
|
+
},
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
const result = convertExternalMessages(
|
|
326
|
+
messages,
|
|
327
|
+
(message) => message,
|
|
328
|
+
false,
|
|
329
|
+
{},
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
expect(result[0]!.content).toMatchObject([
|
|
333
|
+
{
|
|
334
|
+
type: "tool-call",
|
|
335
|
+
toolCallId: "tc1",
|
|
336
|
+
args: { query: "new" },
|
|
337
|
+
result: "found",
|
|
338
|
+
},
|
|
339
|
+
{ type: "text", text: "after tool" },
|
|
340
|
+
]);
|
|
341
|
+
});
|
|
342
|
+
|
|
208
343
|
it("should ignore orphaned tool results without throwing", () => {
|
|
209
344
|
const messages = [
|
|
210
345
|
{
|
|
@@ -2,28 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
import { useMemo, useState } from "react";
|
|
4
4
|
import {
|
|
5
|
-
chunkExternalMessages,
|
|
6
|
-
completeExternalMessageConversion,
|
|
7
|
-
convertExternalMessageCallback,
|
|
8
|
-
convertExternalMessageChunk,
|
|
9
5
|
convertExternalMessages as convertExternalMessagesInternal,
|
|
10
|
-
|
|
6
|
+
createExternalMessageConversionCache as createExternalMessageConversionCacheInternal,
|
|
11
7
|
type ExternalMessageConverterCallback,
|
|
12
|
-
type ExternalMessageConverterCallbackResult,
|
|
13
|
-
type ExternalMessageConverterChunk,
|
|
14
8
|
type ExternalMessageConverterMessage,
|
|
15
9
|
type ExternalMessageConverterMetadata,
|
|
10
|
+
type InternalExternalMessageConversionCache,
|
|
16
11
|
type JoinStrategy,
|
|
17
12
|
} from "../../runtime/utils/external-message-conversion";
|
|
18
13
|
import { bindExternalStoreMessage } from "../../runtime/utils/external-store-message";
|
|
19
|
-
import { ThreadMessageConverter } from "../../runtimes/external-store/thread-message-converter";
|
|
20
|
-
import type { ThreadMessage } from "../../types/message";
|
|
21
|
-
|
|
22
|
-
// Generatedness is tracked by identity, not by id shape: a caller-supplied id
|
|
23
|
-
// that happens to match the generated pattern must never be rewritten.
|
|
24
|
-
const generatedFallbackMessages = new WeakSet<object>();
|
|
25
14
|
|
|
26
15
|
export type { JoinStrategy };
|
|
16
|
+
export type ExternalMessageConversionCache = {
|
|
17
|
+
readonly __brand: unique symbol;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates a cache for plain external message conversion. Pass the same cache on every call for one message list, and a source message that has not changed since the previous call converts to the same `ThreadMessage` object.
|
|
22
|
+
*
|
|
23
|
+
* Entries are keyed by source message identity and rebuilt whenever `callback` or `metadata` is a different object than on the previous call, so keep both referentially stable.
|
|
24
|
+
*/
|
|
25
|
+
export const createExternalMessageConversionCache =
|
|
26
|
+
(): ExternalMessageConversionCache =>
|
|
27
|
+
createExternalMessageConversionCacheInternal() as unknown as ExternalMessageConversionCache;
|
|
27
28
|
|
|
28
29
|
export namespace useExternalMessageConverter {
|
|
29
30
|
export type Message = ExternalMessageConverterMessage;
|
|
@@ -31,17 +32,21 @@ export namespace useExternalMessageConverter {
|
|
|
31
32
|
export type Callback<T> = ExternalMessageConverterCallback<T>;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
export const convertExternalMessages
|
|
35
|
+
export const convertExternalMessages = <T extends WeakKey>(
|
|
35
36
|
messages: T[],
|
|
36
37
|
callback: useExternalMessageConverter.Callback<T>,
|
|
37
38
|
isRunning: boolean,
|
|
38
39
|
metadata: useExternalMessageConverter.Metadata,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
cache?: ExternalMessageConversionCache,
|
|
41
|
+
) =>
|
|
42
|
+
convertExternalMessagesInternal(
|
|
43
|
+
messages,
|
|
44
|
+
callback,
|
|
45
|
+
isRunning,
|
|
46
|
+
metadata,
|
|
47
|
+
undefined,
|
|
48
|
+
cache as unknown as InternalExternalMessageConversionCache<T> | undefined,
|
|
49
|
+
);
|
|
45
50
|
|
|
46
51
|
export const useExternalMessageConverter = <T extends WeakKey>({
|
|
47
52
|
callback,
|
|
@@ -56,89 +61,30 @@ export const useExternalMessageConverter = <T extends WeakKey>({
|
|
|
56
61
|
joinStrategy?: JoinStrategy | undefined;
|
|
57
62
|
metadata?: useExternalMessageConverter.Metadata | undefined;
|
|
58
63
|
}) => {
|
|
59
|
-
// The
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// keeping correctness independent of memoization (which React treats as
|
|
64
|
-
// droppable). A "use no memo" opt-out would restore the useMemo semantics
|
|
65
|
-
// but leave cache flushing coupled to memo firing.
|
|
66
|
-
const [caches] = useState(() => ({
|
|
67
|
-
callbackCache: new WeakMap<T, CallbackCacheEntry<T>>(),
|
|
68
|
-
chunkCache: new WeakMap<
|
|
69
|
-
ExternalMessageConverterMessage,
|
|
70
|
-
ExternalMessageConverterChunk<T>
|
|
71
|
-
>(),
|
|
72
|
-
converterCache: new ThreadMessageConverter(),
|
|
73
|
-
}));
|
|
64
|
+
// The cache lives for the component lifetime: React Compiler hoists allocations without reactive dependencies out of useMemo, so entries carry the callback and metadata that produced them instead of being flushed when those change.
|
|
65
|
+
const [cache] = useState(() =>
|
|
66
|
+
createExternalMessageConversionCacheInternal<T>(),
|
|
67
|
+
);
|
|
74
68
|
|
|
75
69
|
const state = useMemo(
|
|
76
70
|
() => ({
|
|
77
71
|
metadata: metadata ?? {},
|
|
78
72
|
callback,
|
|
79
|
-
...caches,
|
|
80
73
|
}),
|
|
81
|
-
[callback, metadata
|
|
74
|
+
[callback, metadata],
|
|
82
75
|
);
|
|
83
76
|
|
|
84
77
|
return useMemo(() => {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
) {
|
|
93
|
-
result = {
|
|
94
|
-
...convertExternalMessageCallback(
|
|
95
|
-
message,
|
|
96
|
-
state.callback,
|
|
97
|
-
state.metadata,
|
|
98
|
-
),
|
|
99
|
-
metadata: state.metadata,
|
|
100
|
-
callback: state.callback,
|
|
101
|
-
};
|
|
102
|
-
state.callbackCache.set(message, result);
|
|
103
|
-
}
|
|
104
|
-
callbackResults.push(result);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const chunks = chunkExternalMessages(callbackResults, joinStrategy).map(
|
|
108
|
-
(message) => {
|
|
109
|
-
const key = message.outputs[0];
|
|
110
|
-
if (!key) return message;
|
|
111
|
-
|
|
112
|
-
const cached = state.chunkCache.get(key);
|
|
113
|
-
if (cached && shallowArrayEqual(cached.outputs, message.outputs)) {
|
|
114
|
-
return cached;
|
|
115
|
-
}
|
|
116
|
-
state.chunkCache.set(key, message);
|
|
117
|
-
return message;
|
|
118
|
-
},
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
const threadMessages = state.converterCache.convertMessages(
|
|
122
|
-
chunks,
|
|
123
|
-
(cache, message, idx) =>
|
|
124
|
-
convertExternalMessageChunk(
|
|
125
|
-
message,
|
|
126
|
-
idx,
|
|
127
|
-
chunks.length,
|
|
128
|
-
isRunning,
|
|
129
|
-
state.metadata.error,
|
|
130
|
-
{
|
|
131
|
-
message: cache,
|
|
132
|
-
generatedFallbackMessages,
|
|
133
|
-
},
|
|
134
|
-
state.metadata.cancelledMessageIds,
|
|
135
|
-
),
|
|
78
|
+
const threadMessages = convertExternalMessagesInternal(
|
|
79
|
+
messages,
|
|
80
|
+
state.callback,
|
|
81
|
+
isRunning,
|
|
82
|
+
state.metadata,
|
|
83
|
+
joinStrategy,
|
|
84
|
+
cache,
|
|
136
85
|
);
|
|
137
86
|
|
|
138
87
|
bindExternalStoreMessage(threadMessages, messages);
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
state.metadata.error,
|
|
142
|
-
);
|
|
143
|
-
}, [state, messages, isRunning, joinStrategy]);
|
|
88
|
+
return threadMessages;
|
|
89
|
+
}, [state, messages, isRunning, joinStrategy, cache]);
|
|
144
90
|
};
|
|
@@ -5,8 +5,49 @@ import { act, render } from "@testing-library/react";
|
|
|
5
5
|
import { describe, expect, it, vi } from "vitest";
|
|
6
6
|
import { useExternalStoreRuntime } from "./useExternalStoreRuntime";
|
|
7
7
|
import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
|
|
8
|
+
import type { ThreadMessage } from "../../types/message";
|
|
9
|
+
import { RuntimeAdapterProvider } from "./RuntimeAdapterProvider";
|
|
10
|
+
|
|
11
|
+
const userMessage: ThreadMessage = {
|
|
12
|
+
id: "user-1",
|
|
13
|
+
role: "user",
|
|
14
|
+
content: [{ type: "text", text: "hello" }],
|
|
15
|
+
attachments: [],
|
|
16
|
+
createdAt: new Date(0),
|
|
17
|
+
metadata: { custom: {} },
|
|
18
|
+
};
|
|
8
19
|
|
|
9
20
|
describe("useExternalStoreRuntime lifecycle", () => {
|
|
21
|
+
it("uses feedback supplied by the per-thread adapter context", () => {
|
|
22
|
+
const submit = vi.fn();
|
|
23
|
+
const capture: { runtime: AssistantRuntime | null } = { runtime: null };
|
|
24
|
+
const App = () => {
|
|
25
|
+
const runtime = useExternalStoreRuntime({
|
|
26
|
+
messages: [userMessage],
|
|
27
|
+
onNew: async () => {},
|
|
28
|
+
});
|
|
29
|
+
capture.runtime = runtime;
|
|
30
|
+
return null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
render(
|
|
34
|
+
<RuntimeAdapterProvider adapters={{ feedback: { submit } }}>
|
|
35
|
+
<App />
|
|
36
|
+
</RuntimeAdapterProvider>,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
expect(capture.runtime!.thread.getState().capabilities.feedback).toBe(true);
|
|
40
|
+
act(() => {
|
|
41
|
+
capture
|
|
42
|
+
.runtime!.thread.getMessageById("user-1")
|
|
43
|
+
.submitFeedback({ type: "positive" });
|
|
44
|
+
});
|
|
45
|
+
expect(submit).toHaveBeenCalledWith({
|
|
46
|
+
message: expect.objectContaining({ id: "user-1" }),
|
|
47
|
+
type: "positive",
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
10
51
|
it("keeps dispatching appends after StrictMode's simulated remount", async () => {
|
|
11
52
|
const onNew = vi.fn(async () => {});
|
|
12
53
|
const capture: { runtime: AssistantRuntime | null } = { runtime: null };
|
|
@@ -11,7 +11,15 @@ import { useRuntimeAdapters } from "./RuntimeAdapterProvider";
|
|
|
11
11
|
export const useExternalStoreRuntime = <T>(
|
|
12
12
|
store: ExternalStoreAdapter<T>,
|
|
13
13
|
): AssistantRuntime => {
|
|
14
|
-
const
|
|
14
|
+
const { modelContext, feedback } = useRuntimeAdapters() ?? {};
|
|
15
|
+
const adaptedStore = useMemo(() => {
|
|
16
|
+
if (!feedback || store.adapters?.feedback) return store;
|
|
17
|
+
return {
|
|
18
|
+
...store,
|
|
19
|
+
adapters: { ...store.adapters, feedback },
|
|
20
|
+
};
|
|
21
|
+
}, [feedback, store]);
|
|
22
|
+
const [runtime] = useState(() => new ExternalStoreRuntimeCore(adaptedStore));
|
|
15
23
|
|
|
16
24
|
useEffect(() => {
|
|
17
25
|
return () => {
|
|
@@ -20,11 +28,9 @@ export const useExternalStoreRuntime = <T>(
|
|
|
20
28
|
}, [runtime]);
|
|
21
29
|
|
|
22
30
|
useEffect(() => {
|
|
23
|
-
runtime.setAdapter(
|
|
31
|
+
runtime.setAdapter(adaptedStore);
|
|
24
32
|
});
|
|
25
33
|
|
|
26
|
-
const { modelContext } = useRuntimeAdapters() ?? {};
|
|
27
|
-
|
|
28
34
|
useEffect(() => {
|
|
29
35
|
if (!modelContext) return undefined;
|
|
30
36
|
return runtime.registerModelContextProvider(modelContext);
|
|
@@ -32,6 +32,26 @@ afterEach(() => {
|
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
describe("useLocalRuntime", () => {
|
|
35
|
+
it("enables feedback for Cloud threads", async () => {
|
|
36
|
+
const cloud = makeCloud();
|
|
37
|
+
let runtime: ReturnType<typeof useLocalRuntime> | null = null;
|
|
38
|
+
const App = () => {
|
|
39
|
+
runtime = useLocalRuntime(chatModel, { cloud });
|
|
40
|
+
return (
|
|
41
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
42
|
+
<div />
|
|
43
|
+
</AssistantRuntimeProvider>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
render(<App />);
|
|
48
|
+
|
|
49
|
+
await waitFor(() => {
|
|
50
|
+
expect(cloud.threads.list).toHaveBeenCalledTimes(2);
|
|
51
|
+
expect(runtime!.thread.getState().capabilities.feedback).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
35
55
|
it("surfaces the live thread after mount without user input", async () => {
|
|
36
56
|
const auiRef: { current: ReturnType<typeof useAui> | null } = {
|
|
37
57
|
current: null,
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { act, cleanup, render, waitFor } from "@testing-library/react";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
|
|
6
|
+
import { makeAdapter } from "../../tests/remote-thread-list-test-helpers";
|
|
7
|
+
import { AssistantRuntimeProvider } from "../AssistantRuntimeProvider";
|
|
8
|
+
import { useExternalStoreRuntime } from "./useExternalStoreRuntime";
|
|
9
|
+
import { useRemoteThreadListRuntime } from "./useRemoteThreadListRuntime";
|
|
10
|
+
|
|
11
|
+
const EMPTY_MESSAGES: readonly never[] = [];
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
cleanup();
|
|
15
|
+
vi.restoreAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("useRemoteThreadListRuntime load recovery", () => {
|
|
19
|
+
it("reloads once when the browser comes online after a failed load", async () => {
|
|
20
|
+
const error = new Error("offline");
|
|
21
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
22
|
+
const list = vi
|
|
23
|
+
.fn()
|
|
24
|
+
.mockRejectedValueOnce(error)
|
|
25
|
+
.mockResolvedValueOnce({ threads: [] });
|
|
26
|
+
const adapter = makeAdapter({ list });
|
|
27
|
+
const runtimeRef: { current: AssistantRuntime | null } = { current: null };
|
|
28
|
+
const useThreadRuntime = () =>
|
|
29
|
+
useExternalStoreRuntime({
|
|
30
|
+
messages: EMPTY_MESSAGES,
|
|
31
|
+
onNew: async () => {},
|
|
32
|
+
} as never);
|
|
33
|
+
|
|
34
|
+
const App = () => {
|
|
35
|
+
const runtime = useRemoteThreadListRuntime({
|
|
36
|
+
adapter,
|
|
37
|
+
runtimeHook: useThreadRuntime,
|
|
38
|
+
});
|
|
39
|
+
runtimeRef.current = runtime;
|
|
40
|
+
return (
|
|
41
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
42
|
+
{null}
|
|
43
|
+
</AssistantRuntimeProvider>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
render(<App />);
|
|
48
|
+
await waitFor(() => expect(list).toHaveBeenCalledTimes(1));
|
|
49
|
+
await waitFor(() =>
|
|
50
|
+
expect(runtimeRef.current!.threads.getState().loadError).toBe(error),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
act(() => window.dispatchEvent(new Event("online")));
|
|
54
|
+
|
|
55
|
+
await waitFor(() => expect(list).toHaveBeenCalledTimes(2));
|
|
56
|
+
await act(async () => {});
|
|
57
|
+
expect(list).toHaveBeenCalledTimes(2);
|
|
58
|
+
expect(runtimeRef.current!.threads.getState().loadError).toBeUndefined();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("reloads once when the page becomes visible after a failed load", async () => {
|
|
62
|
+
const error = new Error("offline");
|
|
63
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
64
|
+
vi.spyOn(document, "visibilityState", "get").mockReturnValue("visible");
|
|
65
|
+
const list = vi
|
|
66
|
+
.fn()
|
|
67
|
+
.mockRejectedValueOnce(error)
|
|
68
|
+
.mockResolvedValueOnce({ threads: [] });
|
|
69
|
+
const adapter = makeAdapter({ list });
|
|
70
|
+
const runtimeRef: { current: AssistantRuntime | null } = { current: null };
|
|
71
|
+
const useThreadRuntime = () =>
|
|
72
|
+
useExternalStoreRuntime({
|
|
73
|
+
messages: EMPTY_MESSAGES,
|
|
74
|
+
onNew: async () => {},
|
|
75
|
+
} as never);
|
|
76
|
+
|
|
77
|
+
const App = () => {
|
|
78
|
+
const runtime = useRemoteThreadListRuntime({
|
|
79
|
+
adapter,
|
|
80
|
+
runtimeHook: useThreadRuntime,
|
|
81
|
+
});
|
|
82
|
+
runtimeRef.current = runtime;
|
|
83
|
+
return (
|
|
84
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
85
|
+
{null}
|
|
86
|
+
</AssistantRuntimeProvider>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
render(<App />);
|
|
91
|
+
await waitFor(() => expect(list).toHaveBeenCalledTimes(1));
|
|
92
|
+
await waitFor(() =>
|
|
93
|
+
expect(runtimeRef.current!.threads.getState().loadError).toBe(error),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
act(() => document.dispatchEvent(new Event("visibilitychange")));
|
|
97
|
+
|
|
98
|
+
await waitFor(() => expect(list).toHaveBeenCalledTimes(2));
|
|
99
|
+
await waitFor(() =>
|
|
100
|
+
expect(runtimeRef.current!.threads.getState().loadError).toBeUndefined(),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
act(() => document.dispatchEvent(new Event("visibilitychange")));
|
|
104
|
+
await act(async () => {});
|
|
105
|
+
|
|
106
|
+
expect(list).toHaveBeenCalledTimes(2);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useState,
|
|
3
3
|
useEffect,
|
|
4
|
+
useInsertionEffect,
|
|
4
5
|
useMemo,
|
|
5
6
|
useRef,
|
|
6
7
|
useCallback,
|
|
@@ -39,11 +40,43 @@ const useRemoteThreadListRuntimeImpl = (
|
|
|
39
40
|
options: RemoteThreadListOptions,
|
|
40
41
|
): AssistantRuntime => {
|
|
41
42
|
const [runtime] = useState(() => new RemoteThreadListRuntimeCore(options));
|
|
43
|
+
|
|
44
|
+
// Insertion-effect cleanup runs only when React deletes the fiber, so a
|
|
45
|
+
// hidden <Activity> or a re-suspended boundary keeps the threads alive; the
|
|
46
|
+
// disposal is deferred to a microtask because it notifies subscribers and
|
|
47
|
+
// React forbids scheduling updates from an insertion effect.
|
|
48
|
+
useInsertionEffect(
|
|
49
|
+
() => () => queueMicrotask(() => runtime.threads.__internal_dispose()),
|
|
50
|
+
[runtime],
|
|
51
|
+
);
|
|
52
|
+
|
|
42
53
|
useEffect(() => {
|
|
43
54
|
runtime.threads.__internal_setOptions(options);
|
|
44
55
|
runtime.threads.__internal_load();
|
|
45
56
|
}, [runtime, options]);
|
|
46
57
|
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const reloadAfterError = () => {
|
|
64
|
+
if (runtime.threads.loadError !== undefined) {
|
|
65
|
+
void runtime.threads.reload();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const reloadAfterVisible = () => {
|
|
69
|
+
if (document.visibilityState === "visible") reloadAfterError();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
window.addEventListener("online", reloadAfterError);
|
|
73
|
+
document.addEventListener("visibilitychange", reloadAfterVisible);
|
|
74
|
+
return () => {
|
|
75
|
+
window.removeEventListener("online", reloadAfterError);
|
|
76
|
+
document.removeEventListener("visibilitychange", reloadAfterVisible);
|
|
77
|
+
};
|
|
78
|
+
}, [runtime]);
|
|
79
|
+
|
|
47
80
|
return useMemo(() => new AssistantRuntimeImpl(runtime), [runtime]);
|
|
48
81
|
};
|
|
49
82
|
|
|
@@ -76,7 +109,7 @@ export const useRemoteThreadListRuntime = (
|
|
|
76
109
|
);
|
|
77
110
|
|
|
78
111
|
const onThreadIdChange = useEffectEvent((threadId: string | undefined) => {
|
|
79
|
-
options.onThreadIdChange?.(threadId);
|
|
112
|
+
return options.onThreadIdChange?.(threadId);
|
|
80
113
|
});
|
|
81
114
|
|
|
82
115
|
const stableOptions = useMemo<RemoteThreadListOptions>(
|
|
@@ -47,8 +47,13 @@ export const GROUPBY_MEMO_KEY: unique symbol = Symbol.for(
|
|
|
47
47
|
* `display: "standalone"`). Resolving the registry-driven cases reads the
|
|
48
48
|
* {@link GroupByContext} passed to the `groupBy` function. Takes precedence
|
|
49
49
|
* over the `"tool-call"` entry.
|
|
50
|
+
*
|
|
51
|
+
* A `"tool-call:<name>"` entry matches tool calls by tool name and takes precedence over the plain `"tool-call"` entry, while `"standalone-tool-call"` still wins first.
|
|
50
52
|
*/
|
|
51
|
-
type GroupPartType =
|
|
53
|
+
type GroupPartType =
|
|
54
|
+
| PartState["type"]
|
|
55
|
+
| "standalone-tool-call"
|
|
56
|
+
| `tool-call:${string}`;
|
|
52
57
|
|
|
53
58
|
/**
|
|
54
59
|
* Build a `groupBy` from a `part.type → group-key path` lookup.
|
|
@@ -63,11 +68,14 @@ type GroupPartType = PartState["type"] | "standalone-tool-call";
|
|
|
63
68
|
* {@link GroupByContext} that `<MessagePrimitive.GroupedParts>` passes to the
|
|
64
69
|
* `groupBy` function — the helper needs nothing threaded into it.
|
|
65
70
|
*
|
|
71
|
+
* A `"tool-call:<name>"` entry matches tool calls by tool name and takes precedence over the plain `"tool-call"` entry, while `"standalone-tool-call"` still wins first.
|
|
72
|
+
*
|
|
66
73
|
* @example
|
|
67
74
|
* ```tsx
|
|
68
75
|
* <MessagePrimitive.GroupedParts
|
|
69
76
|
* groupBy={groupPartByType({
|
|
70
77
|
* reasoning: ["group-thought", "group-reasoning"],
|
|
78
|
+
* "tool-call:task": ["group-subagents"],
|
|
71
79
|
* "tool-call": ["group-thought", "group-tool"],
|
|
72
80
|
* "standalone-tool-call": [],
|
|
73
81
|
* })}
|
|
@@ -91,6 +99,9 @@ export const groupPartByType = <TKey extends `group-${string}`>(
|
|
|
91
99
|
if (isStandalone && lookup["standalone-tool-call"] !== undefined) {
|
|
92
100
|
return lookup["standalone-tool-call"]!;
|
|
93
101
|
}
|
|
102
|
+
const toolCallPath = lookup[`tool-call:${part.toolName}`];
|
|
103
|
+
if (toolCallPath !== undefined) return toolCallPath;
|
|
104
|
+
return lookup["tool-call"] ?? [];
|
|
94
105
|
}
|
|
95
106
|
return lookup[part.type] ?? [];
|
|
96
107
|
}) as ((part: PartState, context?: GroupByContext) => readonly TKey[]) & {
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { useRef } from "react";
|
|
2
|
+
import type { ReadonlyJSONValue } from "assistant-stream/utils";
|
|
2
3
|
import { isJSONValueEqual } from "../../utils/json/is-json-equal";
|
|
3
4
|
|
|
5
|
+
export function useJSONEqualValue<T extends ReadonlyJSONValue>(value: T): T {
|
|
6
|
+
const prev = useRef(value);
|
|
7
|
+
if (prev.current !== value && !isJSONValueEqual(prev.current, value)) {
|
|
8
|
+
prev.current = value;
|
|
9
|
+
}
|
|
10
|
+
return prev.current;
|
|
11
|
+
}
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
* Like `useShallow`, but with JSON deep-equality. Use when a selector derives an
|
|
6
15
|
* equal-but-fresh value on every store update — e.g. folding over
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { toJSONSchema } from "assistant-stream";
|
|
3
|
+
import type { ReadonlyJSONValue } from "assistant-stream/utils";
|
|
4
|
+
import { isJSONValue } from "../../utils/json/is-json";
|
|
5
|
+
import type { Unstable_InteractableStateSchema } from "../types/scopes/interactables";
|
|
6
|
+
import { useJSONEqualValue } from "./useJSONEqual";
|
|
7
|
+
|
|
8
|
+
export function useJSONSchemaDependency(
|
|
9
|
+
schema: Unstable_InteractableStateSchema,
|
|
10
|
+
): ReadonlyJSONValue {
|
|
11
|
+
const normalizedSchema = useMemo(() => {
|
|
12
|
+
try {
|
|
13
|
+
const jsonSchema = toJSONSchema(schema);
|
|
14
|
+
return isJSONValue(jsonSchema) ? jsonSchema : null;
|
|
15
|
+
} catch {
|
|
16
|
+
// Opaque schemas share one fallback so rebuilt instances do not churn registration.
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}, [schema]);
|
|
20
|
+
|
|
21
|
+
return useJSONEqualValue(normalizedSchema);
|
|
22
|
+
}
|