@assistant-ui/core 0.1.14 → 0.1.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/attachment.d.ts +6 -0
- package/dist/adapters/attachment.d.ts.map +1 -1
- package/dist/adapters/attachment.js +54 -9
- package/dist/adapters/attachment.js.map +1 -1
- package/dist/adapters/{mention.d.ts → directive-formatter.d.ts} +2 -4
- package/dist/adapters/directive-formatter.d.ts.map +1 -0
- package/dist/adapters/{mention.js → directive-formatter.js} +4 -9
- package/dist/adapters/directive-formatter.js.map +1 -0
- package/dist/adapters/index.d.ts +1 -3
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +2 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/speech.d.ts.map +1 -1
- package/dist/adapters/speech.js +1 -3
- package/dist/adapters/speech.js.map +1 -1
- package/dist/adapters/thread-history.d.ts +1 -0
- package/dist/adapters/thread-history.d.ts.map +1 -1
- package/dist/adapters/trigger.d.ts +1 -18
- package/dist/adapters/trigger.d.ts.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- 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 +1 -0
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts +1 -1
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +1 -0
- package/dist/model-context/frame/provider.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/tool.d.ts +1 -1
- package/dist/model-context/tool.d.ts.map +1 -1
- package/dist/model-context/types.d.ts +1 -1
- package/dist/model-context/types.d.ts.map +1 -1
- package/dist/model-context/types.js +0 -3
- package/dist/model-context/types.js.map +1 -1
- package/dist/react/AssistantRuntimeProvider.d.ts +1 -1
- package/dist/react/AssistantRuntimeProvider.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/DataRenderers.d.ts +1 -1
- package/dist/react/client/DataRenderers.d.ts.map +1 -1
- package/dist/react/client/DataRenderers.js +14 -0
- package/dist/react/client/DataRenderers.js.map +1 -1
- package/dist/react/client/Tools.d.ts +1 -1
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +1 -0
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/model-context/makeAssistantTool.d.ts +1 -1
- package/dist/react/model-context/makeAssistantTool.d.ts.map +1 -1
- package/dist/react/model-context/makeAssistantToolUI.d.ts +1 -1
- package/dist/react/model-context/makeAssistantToolUI.d.ts.map +1 -1
- package/dist/react/model-context/useInlineRender.d.ts +2 -2
- package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
- package/dist/react/model-context/useInlineRender.js +1 -0
- package/dist/react/model-context/useInlineRender.js.map +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -0
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.d.ts +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.js +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.d.ts +1 -1
- package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.js +1 -1
- package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.d.ts +7 -1
- package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js +60 -44
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/primitives/part/PartMessages.d.ts +1 -1
- package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.d.ts +1 -1
- package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js +2 -1
- package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.d.ts +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.js +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
- package/dist/react/providers/AttachmentByIndexProvider.d.ts +1 -1
- package/dist/react/providers/AttachmentByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts +1 -1
- package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts.map +1 -1
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts +1 -1
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/MessageByIndexProvider.d.ts +1 -1
- package/dist/react/providers/MessageByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/PartByIndexProvider.d.ts +1 -1
- package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/QueueItemByIndexProvider.d.ts +1 -1
- package/dist/react/providers/QueueItemByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/SuggestionByIndexProvider.d.ts +1 -1
- package/dist/react/providers/SuggestionByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/TextMessagePartProvider.d.ts +1 -1
- package/dist/react/providers/TextMessagePartProvider.d.ts.map +1 -1
- package/dist/react/providers/ThreadListItemByIndexProvider.d.ts +1 -1
- package/dist/react/providers/ThreadListItemByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/ThreadListItemRuntimeProvider.d.ts +1 -1
- package/dist/react/providers/ThreadListItemRuntimeProvider.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +4 -2
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +28 -6
- 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 +27 -9
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +1 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +2 -2
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +2 -2
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +4 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.js +10 -0
- package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.js +6 -0
- package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
- package/dist/react/runtimes/useToolInvocations.d.ts.map +1 -1
- package/dist/react/runtimes/useToolInvocations.js +2 -0
- package/dist/react/runtimes/useToolInvocations.js.map +1 -1
- package/dist/react/types/MessagePartComponentTypes.d.ts +1 -1
- package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
- package/dist/react/types/scopes/dataRenderers.d.ts +2 -0
- package/dist/react/types/scopes/dataRenderers.d.ts.map +1 -1
- package/dist/runtime/api/assistant-runtime.d.ts +1 -1
- package/dist/runtime/api/assistant-runtime.d.ts.map +1 -1
- package/dist/runtime/api/attachment-runtime.d.ts +0 -1
- package/dist/runtime/api/attachment-runtime.d.ts.map +1 -1
- package/dist/runtime/api/attachment-runtime.js +0 -3
- package/dist/runtime/api/attachment-runtime.js.map +1 -1
- package/dist/runtime/api/bindings.d.ts +1 -0
- package/dist/runtime/api/bindings.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.d.ts +4 -2
- package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.js.map +1 -1
- package/dist/runtime/api/message-runtime.d.ts +6 -6
- package/dist/runtime/api/message-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +4 -2
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +6 -0
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +10 -9
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +4 -3
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +22 -8
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +2 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +26 -5
- package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +2 -0
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +7 -0
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/internal.d.ts.map +1 -1
- package/dist/runtime/internal.js +1 -4
- package/dist/runtime/internal.js.map +1 -1
- package/dist/runtime/utils/auto-status.d.ts +1 -1
- package/dist/runtime/utils/auto-status.d.ts.map +1 -1
- package/dist/runtime/utils/chat-model-adapter.d.ts +1 -1
- package/dist/runtime/utils/chat-model-adapter.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.d.ts +1 -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/assistant-transport/utils.d.ts +1 -1
- package/dist/runtimes/assistant-transport/utils.d.ts.map +1 -1
- package/dist/runtimes/assistant-transport/utils.js +1 -1
- package/dist/runtimes/assistant-transport/utils.js.map +1 -1
- package/dist/runtimes/external-store/external-store-adapter.d.ts +8 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +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 +27 -25
- 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 +1 -0
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +4 -0
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts +2 -2
- package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +3 -0
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +14 -2
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/store/runtime-clients/attachment-runtime-client.d.ts +2 -2
- package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-part-runtime-client.d.ts +2 -2
- package/dist/store/runtime-clients/message-part-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts +2 -2
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js +1 -0
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +1 -0
- package/dist/store/scopes/thread-list-item.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.map +1 -1
- package/dist/subscribable/subscribable.js +1 -15
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/tests/remote-thread-list-test-helpers.d.ts +12 -0
- package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -0
- package/dist/tests/remote-thread-list-test-helpers.js +48 -0
- package/dist/tests/remote-thread-list-test-helpers.js.map +1 -0
- package/dist/types/directive.d.ts +19 -0
- package/dist/types/directive.d.ts.map +1 -0
- package/dist/types/directive.js +2 -0
- package/dist/types/directive.js.map +1 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/trigger.d.ts +2 -2
- package/dist/types/trigger.d.ts.map +1 -1
- package/dist/utils/json/is-json.d.ts +1 -1
- package/dist/utils/json/is-json.d.ts.map +1 -1
- package/package.json +11 -11
- package/src/adapters/attachment.ts +68 -16
- package/src/adapters/{mention.ts → directive-formatter.ts} +8 -20
- package/src/adapters/index.ts +2 -9
- package/src/adapters/speech.ts +1 -16
- package/src/adapters/thread-history.ts +1 -8
- package/src/adapters/trigger.ts +1 -37
- package/src/index.ts +3 -24
- package/src/model-context/frame/host.ts +6 -5
- package/src/model-context/frame/provider.ts +6 -5
- package/src/model-context/registry.ts +6 -6
- package/src/model-context/tool.ts +1 -1
- package/src/model-context/types.ts +1 -17
- package/src/react/AssistantRuntimeProvider.tsx +1 -1
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +3 -1
- package/src/react/client/DataRenderers.ts +19 -3
- package/src/react/client/Tools.ts +4 -3
- package/src/react/model-context/makeAssistantTool.ts +1 -1
- package/src/react/model-context/makeAssistantToolUI.ts +1 -1
- package/src/react/model-context/useInlineRender.ts +3 -2
- package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -0
- package/src/react/primitives/composer/ComposerAttachments.tsx +7 -1
- package/src/react/primitives/message/MessageAttachments.tsx +7 -1
- package/src/react/primitives/message/MessageParts.tsx +94 -57
- package/src/react/primitives/part/PartMessages.tsx +1 -1
- package/src/react/primitives/thread/ThreadMessages.tsx +3 -2
- package/src/react/primitives/threadList/ThreadListItems.tsx +7 -1
- package/src/react/providers/AttachmentByIndexProvider.tsx +1 -1
- package/src/react/providers/ChainOfThoughtByIndicesProvider.tsx +1 -1
- package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +1 -1
- package/src/react/providers/MessageByIndexProvider.tsx +1 -1
- package/src/react/providers/PartByIndexProvider.tsx +1 -1
- package/src/react/providers/QueueItemByIndexProvider.tsx +1 -1
- package/src/react/providers/SuggestionByIndexProvider.tsx +1 -1
- package/src/react/providers/TextMessagePartProvider.tsx +1 -1
- package/src/react/providers/ThreadListItemByIndexProvider.tsx +1 -1
- package/src/react/providers/ThreadListItemRuntimeProvider.tsx +1 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +47 -15
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +31 -17
- package/src/react/runtimes/RuntimeAdapterProvider.tsx +1 -1
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +3 -3
- package/src/react/runtimes/cloud/auiV0.ts +5 -2
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +6 -3
- package/src/react/runtimes/useLocalRuntime.ts +10 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +6 -0
- package/src/react/runtimes/useToolInvocations.ts +2 -0
- package/src/react/types/MessagePartComponentTypes.ts +1 -1
- package/src/react/types/scopes/dataRenderers.ts +2 -0
- package/src/runtime/api/assistant-runtime.ts +1 -1
- package/src/runtime/api/attachment-runtime.ts +0 -4
- package/src/runtime/api/bindings.ts +1 -0
- package/src/runtime/api/composer-runtime.ts +4 -2
- package/src/runtime/api/message-runtime.ts +8 -8
- package/src/runtime/api/thread-list-runtime.ts +14 -5
- package/src/runtime/api/thread-runtime.ts +13 -12
- package/src/runtime/base/base-composer-runtime-core.ts +37 -16
- package/src/runtime/base/base-thread-runtime-core.ts +1 -1
- package/src/runtime/base/default-edit-composer-runtime-core.ts +35 -5
- package/src/runtime/interfaces/thread-list-runtime-core.ts +2 -0
- package/src/runtime/interfaces/thread-runtime-core.ts +7 -0
- package/src/runtime/internal.ts +1 -4
- package/src/runtime/utils/auto-status.ts +1 -1
- package/src/runtime/utils/chat-model-adapter.ts +1 -1
- package/src/runtime/utils/thread-message-like.ts +4 -1
- package/src/runtimes/assistant-transport/utils.ts +5 -1
- package/src/runtimes/external-store/external-store-adapter.ts +8 -0
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +35 -29
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +4 -0
- package/src/runtimes/remote-thread-list/adapter/in-memory.ts +2 -2
- package/src/runtimes/remote-thread-list/remote-thread-state.ts +3 -0
- package/src/runtimes/remote-thread-list/types.ts +14 -2
- package/src/store/runtime-clients/attachment-runtime-client.ts +2 -2
- package/src/store/runtime-clients/composer-runtime-client.ts +2 -2
- package/src/store/runtime-clients/message-part-runtime-client.ts +2 -2
- package/src/store/runtime-clients/message-runtime-client.ts +2 -2
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +1 -1
- package/src/store/runtime-clients/thread-list-runtime-client.ts +4 -3
- package/src/store/runtime-clients/thread-runtime-client.ts +3 -3
- package/src/store/scopes/thread-list-item.ts +1 -0
- package/src/store/scopes/threads.ts +1 -0
- package/src/subscribable/subscribable.ts +1 -24
- package/src/tests/OptimisticState-list-race.test.ts +5 -9
- package/src/tests/RemoteThreadListThreadListRuntimeCore-custom-metadata.test.ts +123 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +209 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-dedupe.test.ts +139 -0
- package/src/tests/attachment.test.ts +180 -0
- package/src/tests/base-composer-runtime-core-addAttachment.test.ts +154 -0
- package/src/tests/default-edit-composer-runtime-core.test.ts +312 -0
- package/src/tests/{mention-formatter.test.ts → directive-formatter.test.ts} +26 -1
- package/src/tests/external-store-thread-list-runtime-core.test.ts +212 -0
- package/src/tests/get-thread-state-isRunning.test.ts +93 -0
- package/src/tests/remote-thread-list-isLoading.test.ts +6 -10
- package/src/tests/remote-thread-list-test-helpers.ts +70 -0
- package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +17 -1
- package/src/types/directive.ts +19 -0
- package/src/types/index.ts +1 -3
- package/src/types/message.ts +0 -12
- package/src/types/trigger.ts +2 -10
- package/src/utils/json/is-json.ts +1 -1
- package/dist/adapters/mention.d.ts.map +0 -1
- package/dist/adapters/mention.js.map +0 -1
- package/dist/types/mention.d.ts +0 -21
- package/dist/types/mention.d.ts.map +0 -1
- package/dist/types/mention.js +0 -2
- package/dist/types/mention.js.map +0 -1
- package/src/types/mention.ts +0 -39
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { DefaultEditComposerRuntimeCore } from "../runtime/base/default-edit-composer-runtime-core";
|
|
3
|
+
import type { AppendMessage, ThreadMessage } from "../types/message";
|
|
4
|
+
import type { CompleteAttachment } from "../types/attachment";
|
|
5
|
+
import type { ThreadRuntimeCore } from "../runtime/interfaces/thread-runtime-core";
|
|
6
|
+
|
|
7
|
+
const makeRuntime = () => {
|
|
8
|
+
const append = vi.fn();
|
|
9
|
+
const runtime = {
|
|
10
|
+
append,
|
|
11
|
+
composer: { runConfig: {} },
|
|
12
|
+
} as unknown as ThreadRuntimeCore & { adapters?: undefined };
|
|
13
|
+
return { runtime, append };
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const makeUserMessage = (overrides?: Partial<ThreadMessage>): ThreadMessage =>
|
|
17
|
+
({
|
|
18
|
+
id: "msg-1",
|
|
19
|
+
role: "user",
|
|
20
|
+
createdAt: new Date(),
|
|
21
|
+
content: [{ type: "text", text: "hello" }],
|
|
22
|
+
attachments: [],
|
|
23
|
+
metadata: { custom: {} },
|
|
24
|
+
...overrides,
|
|
25
|
+
}) as ThreadMessage;
|
|
26
|
+
|
|
27
|
+
const makeCompleteAttachment = (
|
|
28
|
+
id: string,
|
|
29
|
+
name = "file.pdf",
|
|
30
|
+
): CompleteAttachment => ({
|
|
31
|
+
id,
|
|
32
|
+
type: "document",
|
|
33
|
+
name,
|
|
34
|
+
contentType: "application/pdf",
|
|
35
|
+
content: [
|
|
36
|
+
{ type: "file", data: "blob", mimeType: "application/pdf", filename: name },
|
|
37
|
+
],
|
|
38
|
+
status: { type: "complete" },
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("DefaultEditComposerRuntimeCore", () => {
|
|
42
|
+
describe("construction", () => {
|
|
43
|
+
it("seeds composer text from the edited message", () => {
|
|
44
|
+
const { runtime } = makeRuntime();
|
|
45
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
46
|
+
parentId: null,
|
|
47
|
+
message: makeUserMessage({
|
|
48
|
+
content: [{ type: "text", text: "original" }],
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
expect(composer.text).toBe("original");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("seeds attachments from message.attachments", () => {
|
|
55
|
+
const { runtime } = makeRuntime();
|
|
56
|
+
const attachment = makeCompleteAttachment("att-1");
|
|
57
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
58
|
+
parentId: null,
|
|
59
|
+
message: makeUserMessage({ attachments: [attachment] }),
|
|
60
|
+
});
|
|
61
|
+
expect(composer.attachments).toEqual([attachment]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("lifts non-text content parts into attachments", () => {
|
|
65
|
+
const { runtime } = makeRuntime();
|
|
66
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
67
|
+
parentId: null,
|
|
68
|
+
message: makeUserMessage({
|
|
69
|
+
content: [
|
|
70
|
+
{ type: "text", text: "here is a file" },
|
|
71
|
+
{
|
|
72
|
+
type: "file",
|
|
73
|
+
data: "blob",
|
|
74
|
+
mimeType: "application/pdf",
|
|
75
|
+
filename: "report.pdf",
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
expect(composer.attachments).toHaveLength(1);
|
|
81
|
+
expect(composer.attachments[0]).toMatchObject({
|
|
82
|
+
type: "document",
|
|
83
|
+
name: "report.pdf",
|
|
84
|
+
contentType: "application/pdf",
|
|
85
|
+
status: { type: "complete" },
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("merges message.attachments with lifted content parts", () => {
|
|
90
|
+
const { runtime } = makeRuntime();
|
|
91
|
+
const attachment = makeCompleteAttachment("att-1", "existing.pdf");
|
|
92
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
93
|
+
parentId: null,
|
|
94
|
+
message: makeUserMessage({
|
|
95
|
+
attachments: [attachment],
|
|
96
|
+
content: [
|
|
97
|
+
{ type: "text", text: "x" },
|
|
98
|
+
{
|
|
99
|
+
type: "file",
|
|
100
|
+
data: "b",
|
|
101
|
+
mimeType: "application/pdf",
|
|
102
|
+
filename: "inline.pdf",
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
}),
|
|
106
|
+
});
|
|
107
|
+
expect(composer.attachments).toHaveLength(2);
|
|
108
|
+
expect(composer.attachments[0]).toBe(attachment);
|
|
109
|
+
expect(composer.attachments[1]).toMatchObject({ name: "inline.pdf" });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("exposes parentId and sourceId", () => {
|
|
113
|
+
const { runtime } = makeRuntime();
|
|
114
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
115
|
+
parentId: "parent-7",
|
|
116
|
+
message: makeUserMessage(),
|
|
117
|
+
});
|
|
118
|
+
expect(composer.parentId).toBe("parent-7");
|
|
119
|
+
expect(composer.sourceId).toBe("msg-1");
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe("send behavior", () => {
|
|
124
|
+
it("does not call append when nothing changed", async () => {
|
|
125
|
+
const { runtime, append } = makeRuntime();
|
|
126
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
127
|
+
parentId: "p1",
|
|
128
|
+
message: makeUserMessage({
|
|
129
|
+
content: [{ type: "text", text: "same" }],
|
|
130
|
+
}),
|
|
131
|
+
});
|
|
132
|
+
await composer.send();
|
|
133
|
+
expect(append).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("calls append when text changes", async () => {
|
|
137
|
+
const { runtime, append } = makeRuntime();
|
|
138
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
139
|
+
parentId: "p1",
|
|
140
|
+
message: makeUserMessage({
|
|
141
|
+
content: [{ type: "text", text: "old" }],
|
|
142
|
+
}),
|
|
143
|
+
});
|
|
144
|
+
composer.setText("new");
|
|
145
|
+
await composer.send();
|
|
146
|
+
expect(append).toHaveBeenCalledTimes(1);
|
|
147
|
+
const appended = append.mock.calls[0]![0] as AppendMessage;
|
|
148
|
+
expect(appended.content).toEqual([{ type: "text", text: "new" }]);
|
|
149
|
+
expect(appended.parentId).toBe("p1");
|
|
150
|
+
expect(appended.sourceId).toBe("msg-1");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("drops a removed attachment from the sent message", async () => {
|
|
154
|
+
const { runtime, append } = makeRuntime();
|
|
155
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
156
|
+
parentId: null,
|
|
157
|
+
message: makeUserMessage({
|
|
158
|
+
content: [
|
|
159
|
+
{ type: "text", text: "original" },
|
|
160
|
+
{
|
|
161
|
+
type: "file",
|
|
162
|
+
data: "blob",
|
|
163
|
+
mimeType: "application/pdf",
|
|
164
|
+
filename: "doc.pdf",
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
}),
|
|
168
|
+
});
|
|
169
|
+
expect(composer.attachments).toHaveLength(1);
|
|
170
|
+
await composer.removeAttachment(composer.attachments[0]!.id);
|
|
171
|
+
await composer.send();
|
|
172
|
+
expect(append).toHaveBeenCalledTimes(1);
|
|
173
|
+
const appended = append.mock.calls[0]![0] as AppendMessage;
|
|
174
|
+
expect(appended.attachments).toHaveLength(0);
|
|
175
|
+
expect(appended.content).toEqual([{ type: "text", text: "original" }]);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("preserves the attachment without duplicating it when only text changes", async () => {
|
|
179
|
+
const { runtime, append } = makeRuntime();
|
|
180
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
181
|
+
parentId: null,
|
|
182
|
+
message: makeUserMessage({
|
|
183
|
+
content: [
|
|
184
|
+
{ type: "text", text: "old" },
|
|
185
|
+
{
|
|
186
|
+
type: "file",
|
|
187
|
+
data: "blob",
|
|
188
|
+
mimeType: "application/pdf",
|
|
189
|
+
filename: "doc.pdf",
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
}),
|
|
193
|
+
});
|
|
194
|
+
composer.setText("new text");
|
|
195
|
+
await composer.send();
|
|
196
|
+
const appended = append.mock.calls[0]![0] as AppendMessage;
|
|
197
|
+
expect(appended.content).toEqual([{ type: "text", text: "new text" }]);
|
|
198
|
+
expect(appended.attachments).toHaveLength(1);
|
|
199
|
+
expect(appended.attachments![0]).toMatchObject({ name: "doc.pdf" });
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("forwards startRun even when text and attachments are unchanged", async () => {
|
|
203
|
+
const { runtime, append } = makeRuntime();
|
|
204
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
205
|
+
parentId: null,
|
|
206
|
+
message: makeUserMessage({
|
|
207
|
+
content: [{ type: "text", text: "same" }],
|
|
208
|
+
}),
|
|
209
|
+
});
|
|
210
|
+
await composer.send({ startRun: true });
|
|
211
|
+
expect(append).toHaveBeenCalledTimes(1);
|
|
212
|
+
const appended = append.mock.calls[0]![0] as AppendMessage;
|
|
213
|
+
expect(appended.startRun).toBe(true);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe("non-user messages", () => {
|
|
218
|
+
it("does not lift non-text parts for assistant messages", () => {
|
|
219
|
+
const { runtime } = makeRuntime();
|
|
220
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
221
|
+
parentId: null,
|
|
222
|
+
message: {
|
|
223
|
+
id: "msg-a",
|
|
224
|
+
role: "assistant",
|
|
225
|
+
createdAt: new Date(),
|
|
226
|
+
content: [
|
|
227
|
+
{ type: "text", text: "answer" },
|
|
228
|
+
{
|
|
229
|
+
type: "file",
|
|
230
|
+
data: "blob",
|
|
231
|
+
mimeType: "application/pdf",
|
|
232
|
+
filename: "doc.pdf",
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
status: { type: "complete", reason: "stop" },
|
|
236
|
+
metadata: {
|
|
237
|
+
unstable_state: null,
|
|
238
|
+
unstable_annotations: [],
|
|
239
|
+
unstable_data: [],
|
|
240
|
+
steps: [],
|
|
241
|
+
custom: {},
|
|
242
|
+
},
|
|
243
|
+
} as ThreadMessage,
|
|
244
|
+
});
|
|
245
|
+
expect(composer.attachments).toHaveLength(0);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("preserves non-text content parts of assistant messages on send", async () => {
|
|
249
|
+
const { runtime, append } = makeRuntime();
|
|
250
|
+
const fileParts = [
|
|
251
|
+
{
|
|
252
|
+
type: "file" as const,
|
|
253
|
+
data: "blob",
|
|
254
|
+
mimeType: "application/pdf",
|
|
255
|
+
filename: "doc.pdf",
|
|
256
|
+
},
|
|
257
|
+
{ type: "reasoning" as const, text: "chain of thought" },
|
|
258
|
+
];
|
|
259
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
260
|
+
parentId: null,
|
|
261
|
+
message: {
|
|
262
|
+
id: "msg-a",
|
|
263
|
+
role: "assistant",
|
|
264
|
+
createdAt: new Date(),
|
|
265
|
+
content: [{ type: "text", text: "old answer" }, ...fileParts],
|
|
266
|
+
status: { type: "complete", reason: "stop" },
|
|
267
|
+
metadata: {
|
|
268
|
+
unstable_state: null,
|
|
269
|
+
unstable_annotations: [],
|
|
270
|
+
unstable_data: [],
|
|
271
|
+
steps: [],
|
|
272
|
+
custom: {},
|
|
273
|
+
},
|
|
274
|
+
} as ThreadMessage,
|
|
275
|
+
});
|
|
276
|
+
composer.setText("new answer");
|
|
277
|
+
await composer.send();
|
|
278
|
+
expect(append).toHaveBeenCalledTimes(1);
|
|
279
|
+
const appended = append.mock.calls[0]![0] as AppendMessage;
|
|
280
|
+
expect(appended.content).toEqual([
|
|
281
|
+
{ type: "text", text: "new answer" },
|
|
282
|
+
...fileParts,
|
|
283
|
+
]);
|
|
284
|
+
expect(appended.attachments ?? []).toHaveLength(0);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe("lifecycle", () => {
|
|
289
|
+
it("invokes endEditCallback after send", async () => {
|
|
290
|
+
const endEdit = vi.fn();
|
|
291
|
+
const { runtime } = makeRuntime();
|
|
292
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, endEdit, {
|
|
293
|
+
parentId: null,
|
|
294
|
+
message: makeUserMessage(),
|
|
295
|
+
});
|
|
296
|
+
composer.setText("changed");
|
|
297
|
+
await composer.send();
|
|
298
|
+
expect(endEdit).toHaveBeenCalledTimes(1);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("invokes endEditCallback on cancel", () => {
|
|
302
|
+
const endEdit = vi.fn();
|
|
303
|
+
const { runtime } = makeRuntime();
|
|
304
|
+
const composer = new DefaultEditComposerRuntimeCore(runtime, endEdit, {
|
|
305
|
+
parentId: null,
|
|
306
|
+
message: makeUserMessage(),
|
|
307
|
+
});
|
|
308
|
+
composer.cancel();
|
|
309
|
+
expect(endEdit).toHaveBeenCalledTimes(1);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { unstable_defaultDirectiveFormatter } from "../adapters/
|
|
2
|
+
import { unstable_defaultDirectiveFormatter } from "../adapters/directive-formatter";
|
|
3
3
|
|
|
4
4
|
describe("unstable_defaultDirectiveFormatter", () => {
|
|
5
5
|
describe("serialize", () => {
|
|
@@ -109,4 +109,29 @@ describe("unstable_defaultDirectiveFormatter", () => {
|
|
|
109
109
|
]);
|
|
110
110
|
});
|
|
111
111
|
});
|
|
112
|
+
|
|
113
|
+
describe("unicode support", () => {
|
|
114
|
+
it("serializes a directive with a CJK label", () => {
|
|
115
|
+
expect(
|
|
116
|
+
unstable_defaultDirectiveFormatter.serialize({
|
|
117
|
+
id: "天气",
|
|
118
|
+
type: "tool",
|
|
119
|
+
label: "天气",
|
|
120
|
+
}),
|
|
121
|
+
).toBe(":tool[天气]");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("parses a directive with a CJK label and name attr", () => {
|
|
125
|
+
expect(
|
|
126
|
+
unstable_defaultDirectiveFormatter.parse(":tool[天气]{name=w1}"),
|
|
127
|
+
).toEqual([
|
|
128
|
+
{
|
|
129
|
+
kind: "mention",
|
|
130
|
+
type: "tool",
|
|
131
|
+
label: "天气",
|
|
132
|
+
id: "w1",
|
|
133
|
+
},
|
|
134
|
+
]);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
112
137
|
});
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { ExternalStoreThreadListRuntimeCore } from "../runtimes/external-store/external-store-thread-list-runtime-core";
|
|
3
|
+
import type { ExternalStoreThreadRuntimeCore } from "../runtimes/external-store/external-store-thread-runtime-core";
|
|
4
|
+
import type { ExternalStoreThreadListAdapter } from "../runtimes/external-store/external-store-adapter";
|
|
5
|
+
import { ThreadListRuntimeImpl } from "../runtime/api/thread-list-runtime";
|
|
6
|
+
|
|
7
|
+
const makeFactory = () =>
|
|
8
|
+
vi.fn(
|
|
9
|
+
() =>
|
|
10
|
+
({
|
|
11
|
+
subscribe: () => () => {},
|
|
12
|
+
}) as unknown as ExternalStoreThreadRuntimeCore,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const makeAdapter = (
|
|
16
|
+
overrides: Partial<ExternalStoreThreadListAdapter> = {},
|
|
17
|
+
): ExternalStoreThreadListAdapter => ({ ...overrides });
|
|
18
|
+
|
|
19
|
+
describe("ExternalStoreThreadListRuntimeCore - construction", () => {
|
|
20
|
+
it("assigns a resolvable fallback mainThreadId when adapter has no threadId", () => {
|
|
21
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
22
|
+
makeAdapter(),
|
|
23
|
+
makeFactory(),
|
|
24
|
+
);
|
|
25
|
+
expect(typeof core.mainThreadId).toBe("string");
|
|
26
|
+
expect(core.mainThreadId.length).toBeGreaterThan(0);
|
|
27
|
+
expect(core.getItemById(core.mainThreadId)).toBeDefined();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("picks up mainThreadId from adapter.threadId on construction (regression: #2577)", () => {
|
|
31
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
32
|
+
makeAdapter({ threadId: "thread-alpha" }),
|
|
33
|
+
makeFactory(),
|
|
34
|
+
);
|
|
35
|
+
expect(core.mainThreadId).toBe("thread-alpha");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("exposes threadIds from adapter.threads on construction", () => {
|
|
39
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
40
|
+
makeAdapter({
|
|
41
|
+
threadId: "thread-alpha",
|
|
42
|
+
threads: [
|
|
43
|
+
{ id: "thread-alpha", status: "regular" },
|
|
44
|
+
{ id: "thread-beta", status: "regular" },
|
|
45
|
+
],
|
|
46
|
+
}),
|
|
47
|
+
makeFactory(),
|
|
48
|
+
);
|
|
49
|
+
expect(core.threadIds).toEqual(["thread-alpha", "thread-beta"]);
|
|
50
|
+
expect(core.mainThreadId).toBe("thread-alpha");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("creates the main thread instance exactly once on construction", () => {
|
|
54
|
+
const factory = makeFactory();
|
|
55
|
+
new ExternalStoreThreadListRuntimeCore(
|
|
56
|
+
makeAdapter({ threadId: "thread-alpha" }),
|
|
57
|
+
factory,
|
|
58
|
+
);
|
|
59
|
+
expect(factory).toHaveBeenCalledTimes(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("creates the main thread instance exactly once when adapter has no threadId", () => {
|
|
63
|
+
const factory = makeFactory();
|
|
64
|
+
new ExternalStoreThreadListRuntimeCore(makeAdapter(), factory);
|
|
65
|
+
expect(factory).toHaveBeenCalledTimes(1);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("binds getMainThreadRuntimeCore() to the instance produced by the factory", () => {
|
|
69
|
+
const instance = {
|
|
70
|
+
subscribe: () => () => {},
|
|
71
|
+
} as unknown as ExternalStoreThreadRuntimeCore;
|
|
72
|
+
const factory = vi.fn(() => instance);
|
|
73
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
74
|
+
makeAdapter({ threadId: "thread-alpha" }),
|
|
75
|
+
factory,
|
|
76
|
+
);
|
|
77
|
+
expect(core.getMainThreadRuntimeCore()).toBe(instance);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("preserves the frozen threadItems default when the adapter has no threads", () => {
|
|
81
|
+
const a = new ExternalStoreThreadListRuntimeCore(
|
|
82
|
+
makeAdapter(),
|
|
83
|
+
makeFactory(),
|
|
84
|
+
);
|
|
85
|
+
const b = new ExternalStoreThreadListRuntimeCore(
|
|
86
|
+
makeAdapter(),
|
|
87
|
+
makeFactory(),
|
|
88
|
+
);
|
|
89
|
+
// Two empty-adapter constructions should share the frozen DEFAULT_THREAD_DATA
|
|
90
|
+
// singleton rather than each getting a fresh `{ ... }` clone.
|
|
91
|
+
expect(a.threadItems).toBe(b.threadItems);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("ExternalStoreThreadListRuntimeCore - __internal_setAdapter", () => {
|
|
96
|
+
it("updates mainThreadId when adapter.threadId changes", () => {
|
|
97
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
98
|
+
makeAdapter({ threadId: "thread-alpha" }),
|
|
99
|
+
makeFactory(),
|
|
100
|
+
);
|
|
101
|
+
core.__internal_setAdapter(makeAdapter({ threadId: "thread-beta" }));
|
|
102
|
+
expect(core.mainThreadId).toBe("thread-beta");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("rebuilds the main thread instance when threadId changes", () => {
|
|
106
|
+
const factory = makeFactory();
|
|
107
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
108
|
+
makeAdapter({ threadId: "thread-alpha" }),
|
|
109
|
+
factory,
|
|
110
|
+
);
|
|
111
|
+
const constructionCalls = factory.mock.calls.length;
|
|
112
|
+
core.__internal_setAdapter(makeAdapter({ threadId: "thread-beta" }));
|
|
113
|
+
expect(factory.mock.calls.length).toBe(constructionCalls + 1);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("does not rebuild the main thread when only threads array changes", () => {
|
|
117
|
+
const factory = makeFactory();
|
|
118
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
119
|
+
makeAdapter({
|
|
120
|
+
threadId: "thread-alpha",
|
|
121
|
+
threads: [{ id: "thread-alpha", status: "regular" }],
|
|
122
|
+
}),
|
|
123
|
+
factory,
|
|
124
|
+
);
|
|
125
|
+
const constructionCalls = factory.mock.calls.length;
|
|
126
|
+
core.__internal_setAdapter(
|
|
127
|
+
makeAdapter({
|
|
128
|
+
threadId: "thread-alpha",
|
|
129
|
+
threads: [
|
|
130
|
+
{ id: "thread-alpha", status: "regular" },
|
|
131
|
+
{ id: "thread-beta", status: "regular" },
|
|
132
|
+
],
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
expect(factory.mock.calls.length).toBe(constructionCalls);
|
|
136
|
+
expect(core.threadIds).toEqual(["thread-alpha", "thread-beta"]);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("notifies subscribers on threadId change", () => {
|
|
140
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
141
|
+
makeAdapter({ threadId: "thread-alpha" }),
|
|
142
|
+
makeFactory(),
|
|
143
|
+
);
|
|
144
|
+
const callback = vi.fn();
|
|
145
|
+
core.subscribe(callback);
|
|
146
|
+
core.__internal_setAdapter(makeAdapter({ threadId: "thread-beta" }));
|
|
147
|
+
expect(callback).toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("ExternalStoreThreadListRuntimeCore - isMain via ThreadListRuntimeImpl", () => {
|
|
152
|
+
// Stub to avoid constructing the full ThreadRuntimeImpl graph when we only
|
|
153
|
+
// care about ThreadListItemRuntime.getState().isMain.
|
|
154
|
+
class NoopThreadRuntime {}
|
|
155
|
+
|
|
156
|
+
const buildImpl = (adapter: ExternalStoreThreadListAdapter) => {
|
|
157
|
+
const core = new ExternalStoreThreadListRuntimeCore(adapter, makeFactory());
|
|
158
|
+
return new ThreadListRuntimeImpl(
|
|
159
|
+
core,
|
|
160
|
+
NoopThreadRuntime as unknown as Parameters<
|
|
161
|
+
typeof ThreadListRuntimeImpl
|
|
162
|
+
>[1],
|
|
163
|
+
);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
it("reports isMain=true for adapter.threadId on construction (user-visible regression: #2577)", () => {
|
|
167
|
+
const impl = buildImpl({
|
|
168
|
+
threadId: "thread-alpha",
|
|
169
|
+
threads: [
|
|
170
|
+
{ id: "thread-alpha", status: "regular" },
|
|
171
|
+
{ id: "thread-beta", status: "regular" },
|
|
172
|
+
],
|
|
173
|
+
});
|
|
174
|
+
expect(impl.getItemById("thread-alpha").getState().isMain).toBe(true);
|
|
175
|
+
expect(impl.getItemById("thread-beta").getState().isMain).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("reflects the main thread in the aggregated ThreadListState on construction", () => {
|
|
179
|
+
const impl = buildImpl({
|
|
180
|
+
threadId: "thread-alpha",
|
|
181
|
+
threads: [
|
|
182
|
+
{ id: "thread-alpha", status: "regular" },
|
|
183
|
+
{ id: "thread-beta", status: "regular" },
|
|
184
|
+
],
|
|
185
|
+
});
|
|
186
|
+
const state = impl.getState();
|
|
187
|
+
expect(state.mainThreadId).toBe("thread-alpha");
|
|
188
|
+
expect(state.threadIds).toEqual(["thread-alpha", "thread-beta"]);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe("ExternalStoreThreadListRuntimeCore - switchToThread", () => {
|
|
193
|
+
it("invokes onSwitchToThread when the target differs from mainThreadId", async () => {
|
|
194
|
+
const onSwitchToThread = vi.fn(async () => {});
|
|
195
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
196
|
+
makeAdapter({ threadId: "thread-alpha", onSwitchToThread }),
|
|
197
|
+
makeFactory(),
|
|
198
|
+
);
|
|
199
|
+
await core.switchToThread("thread-beta");
|
|
200
|
+
expect(onSwitchToThread).toHaveBeenCalledWith("thread-beta");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("early-returns without calling onSwitchToThread when target equals initial threadId (regression: #2577)", async () => {
|
|
204
|
+
const onSwitchToThread = vi.fn(async () => {});
|
|
205
|
+
const core = new ExternalStoreThreadListRuntimeCore(
|
|
206
|
+
makeAdapter({ threadId: "thread-alpha", onSwitchToThread }),
|
|
207
|
+
makeFactory(),
|
|
208
|
+
);
|
|
209
|
+
await core.switchToThread("thread-alpha");
|
|
210
|
+
expect(onSwitchToThread).not.toHaveBeenCalled();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { getThreadState } from "../runtime/api/thread-runtime";
|
|
3
|
+
import type { ThreadRuntimeCore } from "../runtime/interfaces/thread-runtime-core";
|
|
4
|
+
import type { ThreadMessage } from "../types/message";
|
|
5
|
+
import type { ThreadListItemState } from "../runtime/api/thread-list-item-runtime";
|
|
6
|
+
|
|
7
|
+
const listItem = { id: "t1" } as unknown as ThreadListItemState;
|
|
8
|
+
|
|
9
|
+
const baseRuntime = (
|
|
10
|
+
overrides: Partial<ThreadRuntimeCore>,
|
|
11
|
+
): ThreadRuntimeCore =>
|
|
12
|
+
({
|
|
13
|
+
messages: [],
|
|
14
|
+
isDisabled: false,
|
|
15
|
+
isLoading: false,
|
|
16
|
+
capabilities: {} as any,
|
|
17
|
+
state: null,
|
|
18
|
+
suggestions: [],
|
|
19
|
+
extras: undefined,
|
|
20
|
+
speech: undefined,
|
|
21
|
+
voice: undefined,
|
|
22
|
+
...overrides,
|
|
23
|
+
}) as unknown as ThreadRuntimeCore;
|
|
24
|
+
|
|
25
|
+
const userMessage: ThreadMessage = {
|
|
26
|
+
id: "u1",
|
|
27
|
+
role: "user",
|
|
28
|
+
content: [],
|
|
29
|
+
createdAt: new Date(),
|
|
30
|
+
attachments: [],
|
|
31
|
+
metadata: { custom: {} },
|
|
32
|
+
} as unknown as ThreadMessage;
|
|
33
|
+
|
|
34
|
+
const completeAssistant: ThreadMessage = {
|
|
35
|
+
id: "a1",
|
|
36
|
+
role: "assistant",
|
|
37
|
+
content: [],
|
|
38
|
+
createdAt: new Date(),
|
|
39
|
+
status: { type: "complete", reason: "stop" },
|
|
40
|
+
metadata: { unstable_state: null, custom: {}, steps: [] },
|
|
41
|
+
} as unknown as ThreadMessage;
|
|
42
|
+
|
|
43
|
+
const runningAssistant: ThreadMessage = {
|
|
44
|
+
...completeAssistant,
|
|
45
|
+
id: "a2",
|
|
46
|
+
status: { type: "running" },
|
|
47
|
+
} as unknown as ThreadMessage;
|
|
48
|
+
|
|
49
|
+
describe("getThreadState.isRunning", () => {
|
|
50
|
+
it("falls back to last-message heuristic when runtime.isRunning is undefined", () => {
|
|
51
|
+
expect(
|
|
52
|
+
getThreadState(baseRuntime({ messages: [runningAssistant] }), listItem)
|
|
53
|
+
.isRunning,
|
|
54
|
+
).toBe(true);
|
|
55
|
+
|
|
56
|
+
expect(
|
|
57
|
+
getThreadState(baseRuntime({ messages: [completeAssistant] }), listItem)
|
|
58
|
+
.isRunning,
|
|
59
|
+
).toBe(false);
|
|
60
|
+
|
|
61
|
+
expect(
|
|
62
|
+
getThreadState(baseRuntime({ messages: [userMessage] }), listItem)
|
|
63
|
+
.isRunning,
|
|
64
|
+
).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("prefers explicit runtime.isRunning=true even when last message is complete", () => {
|
|
68
|
+
expect(
|
|
69
|
+
getThreadState(
|
|
70
|
+
baseRuntime({ isRunning: true, messages: [completeAssistant] }),
|
|
71
|
+
listItem,
|
|
72
|
+
).isRunning,
|
|
73
|
+
).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("prefers explicit runtime.isRunning=true when last message is a user message", () => {
|
|
77
|
+
expect(
|
|
78
|
+
getThreadState(
|
|
79
|
+
baseRuntime({ isRunning: true, messages: [userMessage] }),
|
|
80
|
+
listItem,
|
|
81
|
+
).isRunning,
|
|
82
|
+
).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("prefers explicit runtime.isRunning=false even when last message is running", () => {
|
|
86
|
+
expect(
|
|
87
|
+
getThreadState(
|
|
88
|
+
baseRuntime({ isRunning: false, messages: [runningAssistant] }),
|
|
89
|
+
listItem,
|
|
90
|
+
).isRunning,
|
|
91
|
+
).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
});
|