@assistant-ui/core 0.2.20 → 0.2.22
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 +2 -2
- package/dist/adapters/attachment.d.ts.map +1 -1
- package/dist/adapters/attachment.js +14 -7
- package/dist/adapters/attachment.js.map +1 -1
- package/dist/adapters/directive-formatter.d.ts +0 -1
- package/dist/adapters/directive-formatter.d.ts.map +1 -1
- package/dist/adapters/feedback.d.ts +0 -1
- package/dist/adapters/feedback.d.ts.map +1 -1
- package/dist/adapters/index.d.ts +2 -2
- package/dist/adapters/index.js +2 -1
- package/dist/adapters/speech.d.ts +0 -1
- package/dist/adapters/speech.d.ts.map +1 -1
- package/dist/adapters/speech.js +9 -2
- package/dist/adapters/speech.js.map +1 -1
- package/dist/adapters/suggestion.d.ts +16 -2
- package/dist/adapters/suggestion.d.ts.map +1 -1
- package/dist/adapters/suggestion.js +36 -0
- package/dist/adapters/suggestion.js.map +1 -0
- package/dist/adapters/thread-history.d.ts +2 -2
- package/dist/adapters/thread-history.d.ts.map +1 -1
- package/dist/adapters/trigger.d.ts +5 -3
- package/dist/adapters/trigger.d.ts.map +1 -1
- package/dist/adapters/voice.d.ts +0 -1
- package/dist/adapters/voice.d.ts.map +1 -1
- package/dist/adapters/voice.js +13 -5
- package/dist/adapters/voice.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/duplicate-detection.d.ts.map +1 -1
- package/dist/internal.d.ts +9 -1
- package/dist/internal.js +8 -2
- 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 +5 -0
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts +0 -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/frame/types.d.ts.map +1 -1
- package/dist/model-context/interactable-composer-metadata.d.ts +4 -2
- package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
- package/dist/model-context/interactable-composer-metadata.js.map +1 -1
- package/dist/model-context/registry-handles.d.ts +0 -1
- package/dist/model-context/registry-handles.d.ts.map +1 -1
- package/dist/model-context/registry.d.ts +0 -1
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/tool.d.ts +23 -9
- package/dist/model-context/tool.d.ts.map +1 -1
- package/dist/model-context/tool.js +0 -25
- package/dist/model-context/tool.js.map +1 -1
- package/dist/model-context/types.d.ts +0 -1
- package/dist/model-context/types.d.ts.map +1 -1
- package/dist/react/AssistantProvider.d.ts +0 -1
- package/dist/react/AssistantProvider.d.ts.map +1 -1
- package/dist/react/AssistantProvider.js.map +1 -1
- package/dist/react/AssistantRuntimeProvider.d.ts +1 -6
- package/dist/react/AssistantRuntimeProvider.d.ts.map +1 -1
- package/dist/react/RuntimeAdapter.d.ts +1 -0
- package/dist/react/RuntimeAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts +13 -2
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +196 -54
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/adapters/TitleGenerationAdapter.d.ts +0 -1
- package/dist/react/adapters/TitleGenerationAdapter.d.ts.map +1 -1
- package/dist/react/client/DataRenderers.d.ts +0 -1
- package/dist/react/client/DataRenderers.d.ts.map +1 -1
- package/dist/react/client/Interactables.d.ts +0 -1
- package/dist/react/client/Interactables.d.ts.map +1 -1
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/Tools.d.ts +3 -2
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/interactable-model-context.d.ts +0 -1
- package/dist/react/client/interactable-model-context.d.ts.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/interactables-legacy/Interactables.d.ts +0 -1
- package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
- package/dist/react/interactables-legacy/interactable-model-context.d.ts +0 -1
- package/dist/react/interactables-legacy/interactable-model-context.d.ts.map +1 -1
- package/dist/react/interactables-legacy/scopes.d.ts +4 -2
- package/dist/react/interactables-legacy/scopes.d.ts.map +1 -1
- package/dist/react/interactables-legacy/useAssistantInteractable.d.ts +0 -1
- package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
- package/dist/react/interactables-legacy/useInteractableState.d.ts.map +1 -1
- package/dist/react/model-context/define-mcp-toolkit.d.ts +19 -4
- package/dist/react/model-context/define-mcp-toolkit.d.ts.map +1 -1
- package/dist/react/model-context/define-mcp-toolkit.js +17 -5
- package/dist/react/model-context/define-mcp-toolkit.js.map +1 -1
- package/dist/react/model-context/define-toolkit.d.ts +1 -2
- package/dist/react/model-context/define-toolkit.d.ts.map +1 -1
- package/dist/react/model-context/external-tool.d.ts.map +1 -1
- package/dist/react/model-context/human-tool.d.ts.map +1 -1
- package/dist/react/model-context/interactableTool.d.ts +2 -2
- package/dist/react/model-context/interactableTool.d.ts.map +1 -1
- package/dist/react/model-context/makeAssistantDataUI.d.ts +2 -2
- package/dist/react/model-context/makeAssistantDataUI.d.ts.map +1 -1
- package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
- package/dist/react/model-context/makeAssistantTool.d.ts.map +1 -1
- package/dist/react/model-context/makeAssistantToolUI.d.ts +2 -2
- package/dist/react/model-context/makeAssistantToolUI.d.ts.map +1 -1
- package/dist/react/model-context/provider-tool.d.ts +0 -1
- package/dist/react/model-context/provider-tool.d.ts.map +1 -1
- package/dist/react/model-context/stub-tool.d.ts.map +1 -1
- package/dist/react/model-context/toolbox.d.ts +5 -5
- package/dist/react/model-context/toolbox.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantContext.d.ts +1 -0
- package/dist/react/model-context/useAssistantContext.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantDataUI.d.ts +3 -2
- package/dist/react/model-context/useAssistantDataUI.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantInstructions.d.ts +1 -0
- package/dist/react/model-context/useAssistantInstructions.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantTool.d.ts +4 -2
- package/dist/react/model-context/useAssistantTool.d.ts.map +1 -1
- package/dist/react/model-context/useAssistantToolUI.d.ts +3 -2
- package/dist/react/model-context/useAssistantToolUI.d.ts.map +1 -1
- package/dist/react/model-context/useAuiToolOverrides.d.ts +0 -1
- package/dist/react/model-context/useAuiToolOverrides.d.ts.map +1 -1
- package/dist/react/model-context/useInlineRender.d.ts +0 -1
- package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
- package/dist/react/model-context/useInteractable.d.ts +7 -4
- package/dist/react/model-context/useInteractable.d.ts.map +1 -1
- package/dist/react/model-context/useInteractable.js.map +1 -1
- package/dist/react/model-context/useInteractableState.d.ts.map +1 -1
- package/dist/react/model-context/useInteractableVersions.d.ts +0 -1
- package/dist/react/model-context/useInteractableVersions.d.ts.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.d.ts +3 -1
- package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarCopy.d.ts +1 -4
- package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarCopy.js +13 -13
- package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarFeedback.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarSpeak.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarStopSpeaking.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerAddAttachment.d.ts +0 -1
- package/dist/react/primitive-hooks/useComposerAddAttachment.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerDictate.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerSend.d.ts +0 -1
- package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useEditComposerCancel.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useEditComposerSend.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useMessageBranching.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useMessageError.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useMessageError.js +5 -1
- package/dist/react/primitive-hooks/useMessageError.js.map +1 -1
- package/dist/react/primitive-hooks/useMessageReload.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts +1 -5
- package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadIsEmpty.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadIsRunning.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemArchive.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemDelete.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemTrigger.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListItemUnarchive.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListNew.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadMessageIds.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadMessages.d.ts +0 -1
- package/dist/react/primitive-hooks/useThreadMessages.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useVoice.d.ts +0 -1
- package/dist/react/primitive-hooks/useVoice.d.ts.map +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts +7 -4
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js +1 -1
- package/dist/react/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.d.ts +4 -3
- package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
- package/dist/react/primitives/composer/ComposerIf.d.ts +4 -3
- package/dist/react/primitives/composer/ComposerIf.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.d.ts +2 -2
- package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
- package/dist/react/primitives/generativeUI/GenerativeUI.d.ts +2 -2
- package/dist/react/primitives/generativeUI/GenerativeUI.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.d.ts +4 -3
- package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.d.ts +1 -6
- package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.d.ts +44 -25
- package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js +48 -37
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/primitives/message/MessageQuote.d.ts +2 -2
- package/dist/react/primitives/message/MessageQuote.d.ts.map +1 -1
- package/dist/react/primitives/messagePart/MessagePartInProgress.d.ts +0 -1
- package/dist/react/primitives/messagePart/MessagePartInProgress.d.ts.map +1 -1
- package/dist/react/primitives/part/PartMessages.d.ts +2 -2
- package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
- package/dist/react/primitives/part/PartMessages.js.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.d.ts +35 -17
- package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/react/primitives/thread/ThreadSuggestions.d.ts +6 -4
- package/dist/react/primitives/thread/ThreadSuggestions.d.ts.map +1 -1
- package/dist/react/primitives/thread/ThreadSuggestions.js.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.d.ts +4 -3
- package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
- package/dist/react/primitives/threadListItem/ThreadListItemTitle.d.ts +0 -1
- package/dist/react/primitives/threadListItem/ThreadListItemTitle.d.ts.map +1 -1
- package/dist/react/providers/AttachmentByIndexProvider.d.ts +0 -1
- package/dist/react/providers/AttachmentByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts +0 -1
- package/dist/react/providers/ChainOfThoughtByIndicesProvider.d.ts.map +1 -1
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts +0 -1
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js +18 -30
- package/dist/react/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -1
- package/dist/react/providers/MessageByIdProvider.d.ts +0 -1
- package/dist/react/providers/MessageByIdProvider.d.ts.map +1 -1
- package/dist/react/providers/MessageByIndexProvider.d.ts +0 -1
- package/dist/react/providers/MessageByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/PartByIndexProvider.d.ts +0 -1
- package/dist/react/providers/PartByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/PartByIndexProvider.js +18 -30
- package/dist/react/providers/PartByIndexProvider.js.map +1 -1
- package/dist/react/providers/QueueItemByIndexProvider.d.ts +0 -1
- package/dist/react/providers/QueueItemByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/ReadonlyThreadProvider.d.ts +0 -1
- package/dist/react/providers/ReadonlyThreadProvider.d.ts.map +1 -1
- package/dist/react/providers/SuggestionByIndexProvider.d.ts +0 -1
- package/dist/react/providers/SuggestionByIndexProvider.d.ts.map +1 -1
- package/dist/react/providers/TextMessagePartProvider.d.ts +0 -1
- package/dist/react/providers/TextMessagePartProvider.d.ts.map +1 -1
- package/dist/react/providers/ThreadListItemByIndexProvider.d.ts +0 -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 +2 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +2 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +12 -3
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +70 -27
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +0 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +0 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -4
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +8 -4
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +12 -2
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +30 -1
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts +0 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/createMessageConverter.d.ts +1 -7
- package/dist/react/runtimes/createMessageConverter.d.ts.map +1 -1
- package/dist/react/runtimes/createRuntimeExtras.d.ts +0 -1
- package/dist/react/runtimes/createRuntimeExtras.d.ts.map +1 -1
- package/dist/react/runtimes/external-message-converter.d.ts +1 -8
- package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +43 -45
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.d.ts +0 -1
- package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useExternalStoreSharedOptions.d.ts +0 -1
- package/dist/react/runtimes/useExternalStoreSharedOptions.d.ts.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.d.ts +3 -5
- package/dist/react/runtimes/useLocalRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.js +9 -1
- package/dist/react/runtimes/useLocalRuntime.js.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts +0 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useStreamingTiming.d.ts +0 -1
- package/dist/react/runtimes/useStreamingTiming.d.ts.map +1 -1
- package/dist/react/types/MessagePartComponentTypes.d.ts +6 -3
- package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
- package/dist/react/types/scopes/dataRenderers.d.ts +1 -1
- package/dist/react/types/scopes/dataRenderers.d.ts.map +1 -1
- package/dist/react/types/scopes/interactables.d.ts +4 -2
- package/dist/react/types/scopes/interactables.d.ts.map +1 -1
- package/dist/react/types/scopes/tools.d.ts +5 -3
- package/dist/react/types/scopes/tools.d.ts.map +1 -1
- package/dist/react/types/store-augmentation.d.ts +1 -2
- package/dist/react/types/store-augmentation.d.ts.map +1 -1
- package/dist/react/utils/getMessageQuote.d.ts +0 -1
- package/dist/react/utils/getMessageQuote.d.ts.map +1 -1
- package/dist/react/utils/groupParts.d.ts +2 -2
- package/dist/react/utils/groupParts.d.ts.map +1 -1
- package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
- package/dist/runtime/api/assistant-runtime.d.ts +0 -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/bindings.d.ts +0 -1
- package/dist/runtime/api/bindings.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.d.ts +6 -4
- package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.d.ts +0 -1
- package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-runtime.d.ts +6 -16
- package/dist/runtime/api/message-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-runtime.js +5 -5
- package/dist/runtime/api/message-runtime.js.map +1 -1
- package/dist/runtime/api/paths.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts +0 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.js +2 -1
- package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +0 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +3 -1
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/base/base-assistant-runtime-core.d.ts +0 -1
- package/dist/runtime/base/base-assistant-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +4 -2
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +51 -10
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -4
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +3 -2
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +1 -5
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +4 -2
- package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +1 -0
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js +2 -2
- package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
- package/dist/runtime/branch/external-thread-branch-adapter.d.ts.map +1 -1
- package/dist/runtime/interfaces/assistant-runtime-core.d.ts +0 -1
- package/dist/runtime/interfaces/assistant-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts +2 -2
- package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +0 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +2 -2
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/queue/external-thread-queue-adapter.d.ts +0 -1
- package/dist/runtime/queue/external-thread-queue-adapter.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.d.ts +6 -4
- package/dist/runtime/queue/message-queue.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.js +1 -1
- package/dist/runtime/utils/auto-status.d.ts +0 -1
- package/dist/runtime/utils/auto-status.d.ts.map +1 -1
- package/dist/runtime/utils/chat-model-adapter.d.ts +0 -1
- package/dist/runtime/utils/chat-model-adapter.d.ts.map +1 -1
- package/dist/runtime/utils/external-store-message.d.ts +0 -1
- package/dist/runtime/utils/external-store-message.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts +1 -5
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +3 -1
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtime/utils/resolveToolApprovalResponse.d.ts +0 -1
- package/dist/runtime/utils/resolveToolApprovalResponse.d.ts.map +1 -1
- package/dist/runtime/utils/streaming-timing.d.ts +5 -3
- package/dist/runtime/utils/streaming-timing.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.d.ts +2 -2
- package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.js +4 -1
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/runtimes/assistant-transport/utils.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-adapter.d.ts +2 -2
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-runtime-core.d.ts +0 -1
- package/dist/runtimes/external-store/external-store-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-shared-options.d.ts +0 -1
- package/dist/runtimes/external-store/external-store-shared-options.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +0 -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-runtime-core.d.ts +2 -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 +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/thread-message-converter.d.ts +0 -1
- package/dist/runtimes/external-store/thread-message-converter.d.ts.map +1 -1
- package/dist/runtimes/local/local-runtime-core.d.ts +0 -1
- package/dist/runtimes/local/local-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-runtime-options.d.ts +0 -1
- package/dist/runtimes/local/local-runtime-options.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-list-runtime-core.d.ts +0 -1
- package/dist/runtimes/local/local-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +5 -21
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +29 -17
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/local/should-continue.d.ts +0 -1
- package/dist/runtimes/local/should-continue.d.ts.map +1 -1
- package/dist/runtimes/local/should-continue.js +2 -2
- package/dist/runtimes/local/should-continue.js.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +0 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts +1 -2
- package/dist/runtimes/remote-thread-list/adapter/in-memory.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/adapter/in-memory.js +5 -3
- package/dist/runtimes/remote-thread-list/adapter/in-memory.js.map +1 -1
- package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts +0 -1
- package/dist/runtimes/remote-thread-list/empty-thread-core.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/optimistic-state.d.ts +10 -8
- package/dist/runtimes/remote-thread-list/optimistic-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/optimistic-state.js +22 -9
- package/dist/runtimes/remote-thread-list/optimistic-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +0 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +1 -2
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +2 -2
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +1 -2
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/chain-of-thought-client.d.ts +0 -1
- package/dist/store/clients/chain-of-thought-client.d.ts.map +1 -1
- package/dist/store/clients/model-context-client.d.ts +0 -1
- package/dist/store/clients/model-context-client.d.ts.map +1 -1
- package/dist/store/clients/no-op-composer-client.d.ts +0 -1
- package/dist/store/clients/no-op-composer-client.d.ts.map +1 -1
- package/dist/store/clients/runtime-adapter.d.ts +0 -1
- package/dist/store/clients/runtime-adapter.d.ts.map +1 -1
- package/dist/store/clients/suggestions.d.ts +0 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/thread-message-client.d.ts +0 -1
- package/dist/store/clients/thread-message-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/attachment-runtime-client.d.ts +0 -1
- package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts +0 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/liveRef.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-part-runtime-client.d.ts +0 -1
- package/dist/store/runtime-clients/message-part-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts +0 -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 +0 -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 +0 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts +0 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/useSubscribable.d.ts +0 -1
- package/dist/store/runtime-clients/useSubscribable.d.ts.map +1 -1
- package/dist/store/scope-registration.d.ts +1 -2
- package/dist/store/scope-registration.d.ts.map +1 -1
- package/dist/store/scopes/attachment.d.ts +0 -1
- package/dist/store/scopes/attachment.d.ts.map +1 -1
- package/dist/store/scopes/chain-of-thought.d.ts +0 -1
- package/dist/store/scopes/chain-of-thought.d.ts.map +1 -1
- package/dist/store/scopes/composer.d.ts +0 -1
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/message.d.ts +6 -4
- package/dist/store/scopes/message.d.ts.map +1 -1
- package/dist/store/scopes/model-context.d.ts +0 -1
- package/dist/store/scopes/model-context.d.ts.map +1 -1
- package/dist/store/scopes/part.d.ts +0 -1
- package/dist/store/scopes/part.d.ts.map +1 -1
- package/dist/store/scopes/queue-item.d.ts.map +1 -1
- package/dist/store/scopes/suggestion.d.ts.map +1 -1
- package/dist/store/scopes/suggestions.d.ts +0 -1
- package/dist/store/scopes/suggestions.d.ts.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +0 -1
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/dist/store/scopes/thread.d.ts +4 -3
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/store/scopes/threads.d.ts +0 -1
- package/dist/store/scopes/threads.d.ts.map +1 -1
- package/dist/subscribable/subscribable.d.ts +1 -2
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +11 -3
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/tests/remote-thread-list-test-helpers.d.ts +2 -2
- package/dist/tests/remote-thread-list-test-helpers.d.ts.map +1 -1
- package/dist/tests/remote-thread-list-test-helpers.js +5 -2
- package/dist/tests/remote-thread-list-test-helpers.js.map +1 -1
- package/dist/types/attachment.d.ts +3 -2
- package/dist/types/attachment.d.ts.map +1 -1
- package/dist/types/attachment.js +6 -0
- package/dist/types/attachment.js.map +1 -0
- package/dist/types/directive.d.ts +3 -2
- package/dist/types/directive.d.ts.map +1 -1
- package/dist/types/error.d.ts +15 -0
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/error.js +46 -0
- package/dist/types/error.js.map +1 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/message.d.ts +71 -33
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/dist/types/quote.d.ts.map +1 -1
- package/dist/types/trigger.d.ts +0 -1
- package/dist/types/trigger.d.ts.map +1 -1
- package/dist/types/unsubscribe.d.ts.map +1 -1
- package/dist/utils/composite-context-provider.d.ts +1 -0
- package/dist/utils/composite-context-provider.d.ts.map +1 -1
- package/dist/utils/data-url.d.ts +9 -0
- package/dist/utils/data-url.d.ts.map +1 -0
- package/dist/utils/data-url.js +14 -0
- package/dist/utils/data-url.js.map +1 -0
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/json/is-json-equal.d.ts.map +1 -1
- package/dist/utils/json/is-json.d.ts +0 -1
- package/dist/utils/json/is-json.d.ts.map +1 -1
- package/dist/utils/json/is-json.js +1 -1
- package/dist/utils/json/is-json.js.map +1 -1
- package/dist/utils/json/stable-stringify-tool-args.d.ts +7 -0
- package/dist/utils/json/stable-stringify-tool-args.d.ts.map +1 -0
- package/dist/utils/json/stable-stringify-tool-args.js +32 -0
- package/dist/utils/json/stable-stringify-tool-args.js.map +1 -0
- package/dist/utils/notify-event-listeners.d.ts +6 -0
- package/dist/utils/notify-event-listeners.d.ts.map +1 -0
- package/dist/utils/notify-event-listeners.js +16 -0
- package/dist/utils/notify-event-listeners.js.map +1 -0
- package/dist/utils/text.d.ts +0 -1
- package/dist/utils/text.d.ts.map +1 -1
- package/package.json +14 -10
- package/src/adapters/attachment.test.ts +107 -0
- package/src/adapters/attachment.ts +20 -10
- package/src/adapters/index.ts +6 -1
- package/src/adapters/speech.test.ts +88 -0
- package/src/adapters/speech.ts +17 -2
- package/src/adapters/suggestion.test.ts +187 -0
- package/src/adapters/suggestion.ts +75 -1
- package/src/adapters/voice.test.ts +130 -0
- package/src/adapters/voice.ts +26 -6
- package/src/index.ts +15 -1
- package/src/internal.ts +21 -0
- package/src/model-context/frame/host.test.ts +100 -0
- package/src/model-context/frame/host.ts +10 -0
- package/src/model-context/frame/provider.test.ts +83 -0
- package/src/model-context/frame/provider.ts +1 -0
- package/src/model-context/tool.test.ts +110 -0
- package/src/model-context/tool.ts +31 -9
- package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +304 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +307 -60
- package/src/react/index.ts +2 -0
- package/src/react/model-context/define-mcp-toolkit.ts +39 -6
- package/src/react/model-context/define-toolkit.test.ts +107 -0
- package/src/react/primitive-hooks/useActionBarCopy.test.ts +79 -0
- package/src/react/primitive-hooks/useActionBarCopy.ts +4 -3
- package/src/react/primitive-hooks/useMessageError.test.ts +64 -0
- package/src/react/primitive-hooks/useMessageError.ts +19 -6
- package/src/react/primitives/chainOfThought/ChainOfThoughtParts.tsx +1 -3
- package/src/react/primitives/message/MessageParts.tsx +48 -35
- package/src/react/providers/ChainOfThoughtPartByIndexProvider.tsx +19 -2
- package/src/react/providers/PartByIndexProvider.tsx +16 -2
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +18 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +4 -1
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +96 -26
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +69 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +1 -1
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +127 -0
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +15 -4
- package/src/react/runtimes/cloud/auiV0.ts +71 -2
- package/src/react/runtimes/external-message-converter.test.tsx +123 -0
- package/src/react/runtimes/external-message-converter.ts +36 -11
- package/src/react/runtimes/useLocalRuntime.test.tsx +56 -0
- package/src/react/runtimes/useLocalRuntime.ts +13 -1
- package/src/runtime/api/message-runtime.test.ts +81 -0
- package/src/runtime/api/message-runtime.ts +4 -6
- package/src/runtime/api/thread-list-item-runtime.ts +6 -1
- package/src/runtime/base/base-composer-runtime-core.ts +95 -30
- package/src/runtime/base/base-thread-runtime-core.ts +2 -1
- package/src/runtime/base/default-edit-composer-runtime-core.ts +4 -2
- package/src/runtime/base/default-thread-composer-runtime-core.ts +2 -2
- package/src/runtime/utils/message-repository.ts +8 -3
- package/src/runtime/utils/thread-message-like.ts +3 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +276 -3
- package/src/runtimes/local/local-thread-runtime-core.ts +29 -25
- package/src/runtimes/local/should-continue.ts +5 -2
- package/src/runtimes/remote-thread-list/adapter/in-memory.test.ts +14 -0
- package/src/runtimes/remote-thread-list/adapter/in-memory.ts +13 -5
- package/src/runtimes/remote-thread-list/optimistic-state.test.ts +63 -0
- package/src/runtimes/remote-thread-list/optimistic-state.ts +49 -17
- package/src/runtimes/remote-thread-list/types.ts +1 -1
- package/src/runtimes/tool-invocations/EDGE_CASES.md +13 -19
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +127 -6
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +4 -2
- package/src/subscribable/subscribable.test.ts +58 -0
- package/src/subscribable/subscribable.ts +13 -3
- package/src/tests/MessageRepository.test.ts +26 -0
- package/src/tests/OptimisticState-list-race.test.ts +33 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-errors.test.ts +42 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-order.test.ts +223 -0
- package/src/tests/attachment-adapters.test.ts +14 -2
- package/src/tests/auiV0Encode.test.ts +134 -1
- package/src/tests/base-composer-runtime-core-addAttachment.test.ts +123 -5
- package/src/tests/base-composer-runtime-core-send.test.ts +573 -0
- package/src/tests/default-edit-composer-runtime-core.test.ts +43 -5
- package/src/tests/event-subscription-listener-errors.test.ts +205 -0
- package/src/tests/remote-thread-list-test-helpers.ts +14 -7
- package/src/tests/thread-message-like.test.ts +97 -0
- package/src/types/attachment.ts +6 -0
- package/src/types/error.test.ts +122 -0
- package/src/types/error.ts +74 -0
- package/src/types/index.ts +1 -0
- package/src/types/message.ts +12 -3
- package/src/utils/data-url.test.ts +50 -0
- package/src/utils/data-url.ts +9 -0
- package/src/utils/json/is-json-equal.test.ts +84 -0
- package/src/utils/json/is-json.test.ts +123 -0
- package/src/utils/json/is-json.ts +1 -1
- package/src/utils/json/stable-stringify-tool-args.test.ts +105 -0
- package/src/utils/json/stable-stringify-tool-args.ts +70 -0
- package/src/utils/notify-event-listeners.ts +30 -0
|
@@ -41,6 +41,15 @@ Subsequent snapshots that *are* prefixes of the new (regressed) snapshot
|
|
|
41
41
|
also won't be appended, because `entry.argsText` still points at the
|
|
42
42
|
pre-regression value used for delta calculation.
|
|
43
43
|
|
|
44
|
+
The args stream closes only when the controller's *streamed* content
|
|
45
|
+
(`entry.argsText`) is complete, not when a later snapshot is. A divergent
|
|
46
|
+
snapshot can be complete while the controller still holds an incomplete
|
|
47
|
+
stale prefix; closing on the snapshot would parse that stale prefix and
|
|
48
|
+
auto-submit a bogus parse-error result (resuming the host graph and
|
|
49
|
+
abandoning a pending interrupt). Gating the close on the streamed content
|
|
50
|
+
leaves the stream open until the prefix itself completes, so no stale
|
|
51
|
+
parse runs and no error result is fabricated from divergent args.
|
|
52
|
+
|
|
44
53
|
### A.3. Args complete then equivalent-JSON key reorder
|
|
45
54
|
Both old and new `argsText` parse to equivalent JSON values (e.g. keys
|
|
46
55
|
reordered by the backend). The tracker updates its tracked `argsText`
|
|
@@ -53,9 +62,10 @@ existing `streamCall` keeps its original args view.
|
|
|
53
62
|
|
|
54
63
|
### A.5. First resolution (`result` becomes defined)
|
|
55
64
|
The tracker calls `setResponse` on the active controller and closes it.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
The backend result is emitted before the args stream closes, so a stale
|
|
66
|
+
args parse failure cannot replace it. `reader.response.get()` resolves.
|
|
67
|
+
If the tool also had a frontend `execute`, the executor is short-circuited
|
|
68
|
+
via `_skipExecuteStreamIds`. Single fire.
|
|
59
69
|
|
|
60
70
|
### A.6. Previously-resolved tool's `result` is replaced
|
|
61
71
|
Silently ignored — `entry.hasResult` short-circuits both the
|
|
@@ -167,22 +177,6 @@ keep the tracker dead with a visible error to avoid restart loops.
|
|
|
167
177
|
|
|
168
178
|
## Known limitations
|
|
169
179
|
|
|
170
|
-
### Result delivery after args regression (A.2 + A.5 in the same snapshot)
|
|
171
|
-
When a snapshot has both a regressed `argsText` *and* a backend result
|
|
172
|
-
on the same tool call, `activeController.setResponse(result)` closes
|
|
173
|
-
`argsText` before enqueueing the result chunk. The args-text-finish
|
|
174
|
-
chunk reaches `ToolExecutionStream` first, attempts to parse the
|
|
175
|
-
(stale) accumulated argsText, fails, and emits a parse-error result
|
|
176
|
-
that beats the backend result to the reader's response promise.
|
|
177
|
-
|
|
178
|
-
The tracker's `entry.hasResult` short-circuit *does* suppress both
|
|
179
|
-
result chunks at the `onResult` callback level (no double-fire), but
|
|
180
|
-
the reader's `response.get()` already resolved with the parse error.
|
|
181
|
-
|
|
182
|
-
Fixable upstream in `ToolCallStreamControllerImpl.setResponse` by
|
|
183
|
-
enqueueing the result chunk before closing argsText. Tracked separately;
|
|
184
|
-
out of scope for the tracker layer.
|
|
185
|
-
|
|
186
180
|
### Host callback throws
|
|
187
181
|
`onResult` and `onStatusesChange` are invoked through wrappers that
|
|
188
182
|
catch and log. The tracker continues to function; the host's bad
|
|
@@ -152,6 +152,131 @@ describe("ToolInvocationTracker", () => {
|
|
|
152
152
|
}
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
+
it("does not auto-submit a parse-error result when divergent argsText closes without a backend result (#5130)", async () => {
|
|
156
|
+
// Mirrors the #5098 production shape: a human-in-the-loop tool whose
|
|
157
|
+
// argsText diverges mid-stream and never re-converges, with no backend
|
|
158
|
+
// result at close time. The args stream must not close on the divergent
|
|
159
|
+
// snapshot (which holds a stale prefix the execution path would parse),
|
|
160
|
+
// so no bogus parse-error result is auto-submitted to resume the host
|
|
161
|
+
// graph and abandon the pending interrupt.
|
|
162
|
+
const execute = vi.fn(async () => ({ forecast: "ok" }));
|
|
163
|
+
const streamCall = vi.fn((_reader, { human }) => {
|
|
164
|
+
// Request human input immediately — sets up the pending interrupt.
|
|
165
|
+
void human({ request: "approve" });
|
|
166
|
+
});
|
|
167
|
+
const getTools = () => ({
|
|
168
|
+
weatherSearch: {
|
|
169
|
+
parameters: { type: "object", properties: {} },
|
|
170
|
+
execute,
|
|
171
|
+
streamCall,
|
|
172
|
+
} satisfies Tool,
|
|
173
|
+
});
|
|
174
|
+
const onResult = vi.fn();
|
|
175
|
+
let statuses: Record<string, ToolExecutionStatus> = {};
|
|
176
|
+
const onStatusesChange = (s: ReadonlyMap<string, ToolExecutionStatus>) => {
|
|
177
|
+
statuses = Object.fromEntries(s);
|
|
178
|
+
};
|
|
179
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const tracker = new ToolInvocationTracker(getTools, {
|
|
183
|
+
onResult,
|
|
184
|
+
onStatusesChange,
|
|
185
|
+
});
|
|
186
|
+
tracker.setState(createState([]));
|
|
187
|
+
|
|
188
|
+
tracker.setState(
|
|
189
|
+
createState([
|
|
190
|
+
createAssistantMessage('{"query":"London","longitude":0', {
|
|
191
|
+
query: "London",
|
|
192
|
+
longitude: 0,
|
|
193
|
+
}),
|
|
194
|
+
]),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
// The pending interrupt is set up via streamCall → human().
|
|
198
|
+
await waitFor(() => {
|
|
199
|
+
expect(statuses["tool-1"]?.type).toBe("interrupt");
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Divergent regression (not a prefix of the streamed text).
|
|
203
|
+
tracker.setState(
|
|
204
|
+
createState([
|
|
205
|
+
createAssistantMessage('{"query":"London","longitude":-0.125', {
|
|
206
|
+
query: "London",
|
|
207
|
+
longitude: -0.125,
|
|
208
|
+
}),
|
|
209
|
+
]),
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Complete valid JSON, divergent from the streamed prefix, no backend
|
|
213
|
+
// result. Previously this closed the args stream on the snapshot's
|
|
214
|
+
// completeness, parsed the stale prefix, and auto-submitted an error.
|
|
215
|
+
tracker.setState(
|
|
216
|
+
createState([
|
|
217
|
+
createAssistantMessage(
|
|
218
|
+
'{"query":"London","longitude":-0.125,"latitude":51.5072}',
|
|
219
|
+
{ query: "London", longitude: -0.125, latitude: 51.5072 },
|
|
220
|
+
),
|
|
221
|
+
]),
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
for (let i = 0; i < 5; i++) {
|
|
225
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// No bogus parse-error result is auto-submitted, so the host graph is
|
|
229
|
+
// not resumed with a fake tool failure and the pending interrupt is
|
|
230
|
+
// preserved.
|
|
231
|
+
expect(onResult).not.toHaveBeenCalled();
|
|
232
|
+
// The frontend execute never ran: the stale prefix was never parsed.
|
|
233
|
+
expect(execute).not.toHaveBeenCalled();
|
|
234
|
+
} finally {
|
|
235
|
+
warnSpy.mockRestore();
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("does not auto-submit a parse-error result for a non-executable tool whose divergent argsText closes (#5130)", async () => {
|
|
240
|
+
// Same close-gating mismatch as the executable case, but for a tool with
|
|
241
|
+
// no frontend execute. Closing on the divergent complete snapshot would
|
|
242
|
+
// still parse the incomplete stale prefix and fabricate a parse-error
|
|
243
|
+
// result, so the close must gate on the controller's streamed content.
|
|
244
|
+
const getTools = () => ({
|
|
245
|
+
weatherSearch: {
|
|
246
|
+
parameters: { type: "object", properties: {} },
|
|
247
|
+
} satisfies Tool,
|
|
248
|
+
});
|
|
249
|
+
const onResult = vi.fn();
|
|
250
|
+
const onStatusesChange = () => {};
|
|
251
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const tracker = new ToolInvocationTracker(getTools, {
|
|
255
|
+
onResult,
|
|
256
|
+
onStatusesChange,
|
|
257
|
+
});
|
|
258
|
+
tracker.setState(createState([]));
|
|
259
|
+
|
|
260
|
+
// Incomplete prefix while the run is still streaming.
|
|
261
|
+
tracker.setState(
|
|
262
|
+
createState([createAssistantMessage('{"a":1', { a: 1 })], true),
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
// Run settles and the snapshot regresses to a complete divergent text.
|
|
266
|
+
tracker.setState(
|
|
267
|
+
createState([createAssistantMessage('{"a":2}', { a: 2 })], false),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
for (let i = 0; i < 5; i++) {
|
|
271
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
expect(onResult).not.toHaveBeenCalled();
|
|
275
|
+
} finally {
|
|
276
|
+
warnSpy.mockRestore();
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
155
280
|
it("clears executing status under the logical toolCallId when reset() lands while execute is pending", async () => {
|
|
156
281
|
// Tests the F.1 lifecycle: reset() aborts in-flight execute() invocations
|
|
157
282
|
// and clears their executing status. The status key is the logical
|
|
@@ -948,12 +1073,8 @@ describe("ToolInvocationTracker", () => {
|
|
|
948
1073
|
// result replacement) and verifying streamCall fires exactly once.
|
|
949
1074
|
//
|
|
950
1075
|
// The pathological mid-stream regression case (A.2) is covered by
|
|
951
|
-
// the
|
|
952
|
-
//
|
|
953
|
-
// assistant-stream's `ToolCallStreamController.setResponse` ordering
|
|
954
|
-
// (parse-failure result reaches the reader before the backend
|
|
955
|
-
// result); that's tracked separately and out of scope for the
|
|
956
|
-
// tracker-level contract.
|
|
1076
|
+
// the assistant-stream ordering regression test in
|
|
1077
|
+
// packages/assistant-stream/src/core/modules/tool-call.test.ts.
|
|
957
1078
|
const streamCall = vi.fn();
|
|
958
1079
|
const execute = vi.fn(async () => ({ forecast: "ok" }));
|
|
959
1080
|
const getTools = () => ({
|
|
@@ -687,14 +687,16 @@ export class ToolInvocationTracker {
|
|
|
687
687
|
}
|
|
688
688
|
|
|
689
689
|
if (!entry.argsComplete && entry.controller) {
|
|
690
|
+
// ToolExecutionStream parses the streamed prefix on close, so the close
|
|
691
|
+
// gates on the streamed content; a divergent snapshot (A.2) can be
|
|
692
|
+
// complete while the controller still holds an incomplete stale prefix.
|
|
690
693
|
const shouldClose = this._shouldCloseArgsStream({
|
|
691
694
|
toolName: content.toolName,
|
|
692
|
-
argsText:
|
|
695
|
+
argsText: entry.argsText,
|
|
693
696
|
hasResult,
|
|
694
697
|
});
|
|
695
698
|
if (shouldClose) {
|
|
696
699
|
entry.controller.argsText.close();
|
|
697
|
-
entry.argsText = content.argsText;
|
|
698
700
|
entry.argsComplete = true;
|
|
699
701
|
}
|
|
700
702
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import type { SubscribableWithState } from "./subscribable";
|
|
3
|
+
import { ShallowMemoizeSubject } from "./subscribable";
|
|
4
|
+
|
|
5
|
+
type TestState = {
|
|
6
|
+
status: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const createBinding = (initialState: TestState) => {
|
|
11
|
+
let state = initialState;
|
|
12
|
+
const subscribers = new Set<() => void>();
|
|
13
|
+
|
|
14
|
+
const binding: SubscribableWithState<TestState, null> = {
|
|
15
|
+
path: null,
|
|
16
|
+
getState: () => state,
|
|
17
|
+
subscribe: (callback) => {
|
|
18
|
+
subscribers.add(callback);
|
|
19
|
+
return () => subscribers.delete(callback);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
binding,
|
|
25
|
+
update(nextState: TestState) {
|
|
26
|
+
state = nextState;
|
|
27
|
+
for (const callback of subscribers) callback();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
describe("ShallowMemoizeSubject", () => {
|
|
33
|
+
it("notifies subscribers when a state key is removed", () => {
|
|
34
|
+
const source = createBinding({
|
|
35
|
+
status: "running",
|
|
36
|
+
error: "Connection failed",
|
|
37
|
+
});
|
|
38
|
+
const subject = new ShallowMemoizeSubject(source.binding);
|
|
39
|
+
const subscriber = vi.fn();
|
|
40
|
+
subject.subscribe(subscriber);
|
|
41
|
+
|
|
42
|
+
source.update({ status: "running" });
|
|
43
|
+
|
|
44
|
+
expect(subscriber).toHaveBeenCalledOnce();
|
|
45
|
+
expect(subject.getState()).toEqual({ status: "running" });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("does not notify subscribers for a shallow-equal state", () => {
|
|
49
|
+
const source = createBinding({ status: "running" });
|
|
50
|
+
const subject = new ShallowMemoizeSubject(source.binding);
|
|
51
|
+
const subscriber = vi.fn();
|
|
52
|
+
subject.subscribe(subscriber);
|
|
53
|
+
|
|
54
|
+
source.update({ status: "running" });
|
|
55
|
+
|
|
56
|
+
expect(subscriber).not.toHaveBeenCalled();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Unsubscribe } from "../types/unsubscribe";
|
|
2
|
+
import { notifyEventListeners } from "../utils/notify-event-listeners";
|
|
2
3
|
|
|
3
4
|
export const SKIP_UPDATE = Symbol("skip-update");
|
|
4
5
|
export type SKIP_UPDATE = typeof SKIP_UPDATE;
|
|
@@ -39,7 +40,10 @@ function shallowEqual<T extends object>(
|
|
|
39
40
|
if (objA === undefined) return false;
|
|
40
41
|
if (objB === undefined) return false;
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
const keysA = Object.keys(objA);
|
|
44
|
+
if (keysA.length !== Object.keys(objB).length) return false;
|
|
45
|
+
|
|
46
|
+
for (const key of keysA) {
|
|
43
47
|
const valueA = objA[key as keyof T];
|
|
44
48
|
const valueB = objB[key as keyof T];
|
|
45
49
|
if (!Object.is(valueA, valueB)) return false;
|
|
@@ -99,7 +103,12 @@ export abstract class BaseSubject {
|
|
|
99
103
|
|
|
100
104
|
protected abstract _connect(): Unsubscribe;
|
|
101
105
|
|
|
102
|
-
protected notifySubscribers(payload?: unknown) {
|
|
106
|
+
protected notifySubscribers(payload?: unknown, errorContext?: string) {
|
|
107
|
+
if (errorContext) {
|
|
108
|
+
notifyEventListeners(this._subscriptions, payload, errorContext);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
103
112
|
for (const callback of this._subscriptions) callback(payload);
|
|
104
113
|
}
|
|
105
114
|
|
|
@@ -273,8 +282,9 @@ export class EventSubscriptionSubject<
|
|
|
273
282
|
}
|
|
274
283
|
|
|
275
284
|
protected _connect(): Unsubscribe {
|
|
285
|
+
const errorContext = `Runtime event "${this.config.event}"`;
|
|
276
286
|
const callback = (payload?: unknown) => {
|
|
277
|
-
this.notifySubscribers(payload);
|
|
287
|
+
this.notifySubscribers(payload, errorContext);
|
|
278
288
|
};
|
|
279
289
|
|
|
280
290
|
let lastState = this.config.binding.getState();
|
|
@@ -309,6 +309,32 @@ describe("MessageRepository", () => {
|
|
|
309
309
|
expect(exported.headId).toBe("u");
|
|
310
310
|
});
|
|
311
311
|
|
|
312
|
+
it("re-parents children of a skipped optimistic message in export()", () => {
|
|
313
|
+
repository.addOrUpdateMessage(null, createTestMessage({ id: "u1" }));
|
|
314
|
+
repository.addOrUpdateMessage("u1", optimistic({ id: "a1" }));
|
|
315
|
+
repository.addOrUpdateMessage(
|
|
316
|
+
"a1",
|
|
317
|
+
createTestMessage({ id: "u2", role: "user" }),
|
|
318
|
+
);
|
|
319
|
+
repository.addOrUpdateMessage("u2", createTestMessage({ id: "a2" }));
|
|
320
|
+
repository.resetHead("a2");
|
|
321
|
+
|
|
322
|
+
const exported = repository.export();
|
|
323
|
+
const byId = new Map(exported.messages.map((m) => [m.message.id, m]));
|
|
324
|
+
|
|
325
|
+
expect([...byId.keys()].sort()).toEqual(["a2", "u1", "u2"]);
|
|
326
|
+
expect(byId.get("u2")?.parentId).toBe("u1");
|
|
327
|
+
expect(byId.get("a2")?.parentId).toBe("u2");
|
|
328
|
+
|
|
329
|
+
const restored = new MessageRepository();
|
|
330
|
+
restored.import(exported);
|
|
331
|
+
expect(restored.getMessages().map((m) => m.id)).toEqual([
|
|
332
|
+
"u1",
|
|
333
|
+
"u2",
|
|
334
|
+
"a2",
|
|
335
|
+
]);
|
|
336
|
+
});
|
|
337
|
+
|
|
312
338
|
it("round-trips through export/import without resurrecting the placeholder", () => {
|
|
313
339
|
const parent = createTestMessage({ id: "u" });
|
|
314
340
|
const real = createTestMessage({ id: "a" });
|
|
@@ -79,6 +79,39 @@ const applyListResult = (
|
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
describe("list + delete race condition", () => {
|
|
82
|
+
it("stale list() does not re-add a thread deleted before list started", async () => {
|
|
83
|
+
const state = new OptimisticState<RemoteThreadState>(
|
|
84
|
+
applyListResult(EMPTY_STATE, {
|
|
85
|
+
threads: [{ remoteId: "thread-A", status: "regular", title: "A" }],
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
88
|
+
const deleteDeferred = deferred<void>();
|
|
89
|
+
const listDeferred = deferred<ListResult>();
|
|
90
|
+
|
|
91
|
+
const deletePromise = state.optimisticUpdate({
|
|
92
|
+
execute: () => deleteDeferred.promise,
|
|
93
|
+
optimistic: (s) => updateStatusReducer(s, "thread-A", "deleted"),
|
|
94
|
+
});
|
|
95
|
+
const listPromise = state.optimisticUpdate({
|
|
96
|
+
execute: () => listDeferred.promise,
|
|
97
|
+
loading: (s) => ({ ...s, isLoading: true }),
|
|
98
|
+
then: applyListResult,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
deleteDeferred.resolve();
|
|
102
|
+
await deletePromise;
|
|
103
|
+
|
|
104
|
+
listDeferred.resolve({
|
|
105
|
+
threads: [{ remoteId: "thread-A", status: "regular", title: "A" }],
|
|
106
|
+
});
|
|
107
|
+
await listPromise;
|
|
108
|
+
|
|
109
|
+
expect(state.value.threadIds).not.toContain("thread-A");
|
|
110
|
+
expect(
|
|
111
|
+
state.value.threadData[createThreadMappingId("thread-A")],
|
|
112
|
+
).toBeUndefined();
|
|
113
|
+
});
|
|
114
|
+
|
|
82
115
|
it("stale list() does not re-add a thread deleted while list was in flight", async () => {
|
|
83
116
|
const state = new OptimisticState<RemoteThreadState>(EMPTY_STATE);
|
|
84
117
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { createCore, makeAdapter } from "./remote-thread-list-test-helpers";
|
|
3
|
+
import { InMemoryThreadListAdapter } from "../runtimes/remote-thread-list/adapter/in-memory";
|
|
4
|
+
|
|
5
|
+
describe("RemoteThreadListThreadListRuntimeCore errors", () => {
|
|
6
|
+
it("includes the requested thread id when a thread is missing", () => {
|
|
7
|
+
const core = createCore(makeAdapter());
|
|
8
|
+
|
|
9
|
+
expect(() => core.rename("missing-thread", "New title")).toThrow(
|
|
10
|
+
'Thread "missing-thread" not found while renaming it.',
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("includes the requested thread id and status when an operation is invalid", async () => {
|
|
15
|
+
const adapter = makeAdapter({
|
|
16
|
+
list: vi.fn(async () => ({
|
|
17
|
+
threads: [
|
|
18
|
+
{
|
|
19
|
+
status: "archived" as const,
|
|
20
|
+
remoteId: "archived-thread",
|
|
21
|
+
externalId: "archived-thread",
|
|
22
|
+
title: "Archived",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
})),
|
|
26
|
+
});
|
|
27
|
+
const core = createCore(adapter);
|
|
28
|
+
await core.getLoadThreadsPromise();
|
|
29
|
+
|
|
30
|
+
await expect(core.archive("archived-thread")).rejects.toThrow(
|
|
31
|
+
'Thread "archived-thread" has status "archived", so it cannot be archived.',
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("includes the requested thread id when the in-memory adapter cannot fetch it", async () => {
|
|
36
|
+
const adapter = new InMemoryThreadListAdapter();
|
|
37
|
+
|
|
38
|
+
await expect(adapter.fetch("missing-thread")).rejects.toThrow(
|
|
39
|
+
'Thread "missing-thread" not found in in-memory thread list.',
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import type { RemoteThreadMetadata } from "../runtimes/remote-thread-list/types";
|
|
3
|
+
import {
|
|
4
|
+
createCore,
|
|
5
|
+
deferred,
|
|
6
|
+
makeAdapter,
|
|
7
|
+
setStartThreadRuntime,
|
|
8
|
+
} from "./remote-thread-list-test-helpers";
|
|
9
|
+
|
|
10
|
+
const thread = (id: string): RemoteThreadMetadata => ({
|
|
11
|
+
status: "regular",
|
|
12
|
+
remoteId: id,
|
|
13
|
+
externalId: id,
|
|
14
|
+
title: id,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe("RemoteThreadListThreadListRuntimeCore.switchToThread order", () => {
|
|
18
|
+
it("preserves the latest switch when an earlier fetch resolves last", async () => {
|
|
19
|
+
const fetchB = deferred<RemoteThreadMetadata>();
|
|
20
|
+
const fetchC = deferred<RemoteThreadMetadata>();
|
|
21
|
+
const adapter = makeAdapter({
|
|
22
|
+
fetch: vi.fn((id: string) =>
|
|
23
|
+
id === "thread-b" ? fetchB.promise : fetchC.promise,
|
|
24
|
+
),
|
|
25
|
+
});
|
|
26
|
+
const core = createCore(adapter);
|
|
27
|
+
|
|
28
|
+
const switchToB = core.switchToThread("thread-b");
|
|
29
|
+
const switchToC = core.switchToThread("thread-c");
|
|
30
|
+
|
|
31
|
+
fetchC.resolve(thread("thread-c"));
|
|
32
|
+
await switchToC;
|
|
33
|
+
fetchB.resolve(thread("thread-b"));
|
|
34
|
+
await switchToB;
|
|
35
|
+
|
|
36
|
+
expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("preserves the latest switch when an earlier runtime starts last", async () => {
|
|
40
|
+
const runtimeB = deferred<unknown>();
|
|
41
|
+
const runtimeC = deferred<unknown>();
|
|
42
|
+
const adapter = makeAdapter({
|
|
43
|
+
list: vi.fn(async () => ({
|
|
44
|
+
threads: [thread("thread-b"), thread("thread-c")],
|
|
45
|
+
})),
|
|
46
|
+
});
|
|
47
|
+
const core = createCore(adapter);
|
|
48
|
+
await core.getLoadThreadsPromise();
|
|
49
|
+
|
|
50
|
+
setStartThreadRuntime(core, (id) =>
|
|
51
|
+
id === core.getItemById("thread-b")?.id
|
|
52
|
+
? runtimeB.promise
|
|
53
|
+
: runtimeC.promise,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const switchToB = core.switchToThread("thread-b");
|
|
57
|
+
const switchToC = core.switchToThread("thread-c");
|
|
58
|
+
|
|
59
|
+
runtimeC.resolve({});
|
|
60
|
+
await switchToC;
|
|
61
|
+
runtimeB.resolve({});
|
|
62
|
+
await switchToB;
|
|
63
|
+
|
|
64
|
+
expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("invalidates an earlier switch while a new thread request is pending", async () => {
|
|
68
|
+
const initializeThread = deferred<{
|
|
69
|
+
remoteId: string;
|
|
70
|
+
externalId: string;
|
|
71
|
+
}>();
|
|
72
|
+
const runtimeB = deferred<unknown>();
|
|
73
|
+
const adapter = makeAdapter({
|
|
74
|
+
initialize: vi.fn(() => initializeThread.promise),
|
|
75
|
+
list: vi.fn(async () => ({ threads: [thread("thread-b")] })),
|
|
76
|
+
});
|
|
77
|
+
const core = createCore(adapter);
|
|
78
|
+
await core.getLoadThreadsPromise();
|
|
79
|
+
|
|
80
|
+
const initialNewThreadId = core.newThreadId;
|
|
81
|
+
if (!initialNewThreadId) throw new Error("Expected an initial new thread");
|
|
82
|
+
|
|
83
|
+
const threadBId = core.getItemById("thread-b")?.id;
|
|
84
|
+
setStartThreadRuntime(core, (id) =>
|
|
85
|
+
id === threadBId ? runtimeB.promise : Promise.resolve({}),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const initialize = core.initialize(initialNewThreadId);
|
|
89
|
+
const switchToB = core.switchToThread("thread-b");
|
|
90
|
+
const switchToNewThread = core.switchToNewThread();
|
|
91
|
+
|
|
92
|
+
runtimeB.resolve({});
|
|
93
|
+
await switchToB;
|
|
94
|
+
|
|
95
|
+
expect(core.mainThreadId).not.toBe(threadBId);
|
|
96
|
+
|
|
97
|
+
initializeThread.resolve({
|
|
98
|
+
remoteId: "initialized-thread",
|
|
99
|
+
externalId: "initialized-thread",
|
|
100
|
+
});
|
|
101
|
+
await initialize;
|
|
102
|
+
await switchToNewThread;
|
|
103
|
+
|
|
104
|
+
expect(core.mainThreadId).toBe(core.getItemById(core.newThreadId!)?.id);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("does not let a pending new thread request override a later switch", async () => {
|
|
108
|
+
const initializeThread = deferred<{
|
|
109
|
+
remoteId: string;
|
|
110
|
+
externalId: string;
|
|
111
|
+
}>();
|
|
112
|
+
const adapter = makeAdapter({
|
|
113
|
+
initialize: vi.fn(() => initializeThread.promise),
|
|
114
|
+
list: vi.fn(async () => ({ threads: [thread("thread-c")] })),
|
|
115
|
+
});
|
|
116
|
+
const core = createCore(adapter);
|
|
117
|
+
await core.getLoadThreadsPromise();
|
|
118
|
+
|
|
119
|
+
const initialNewThreadId = core.newThreadId;
|
|
120
|
+
if (!initialNewThreadId) throw new Error("Expected an initial new thread");
|
|
121
|
+
|
|
122
|
+
const initialize = core.initialize(initialNewThreadId);
|
|
123
|
+
const switchToNewThread = core.switchToNewThread();
|
|
124
|
+
await core.switchToThread("thread-c");
|
|
125
|
+
|
|
126
|
+
initializeThread.resolve({
|
|
127
|
+
remoteId: "initialized-thread",
|
|
128
|
+
externalId: "initialized-thread",
|
|
129
|
+
});
|
|
130
|
+
await initialize;
|
|
131
|
+
await switchToNewThread;
|
|
132
|
+
|
|
133
|
+
expect(core.mainThreadId).toBe(core.getItemById("thread-c")?.id);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("keeps mutations waiting when a newer switch fails", async () => {
|
|
137
|
+
const fetchB = deferred<RemoteThreadMetadata>();
|
|
138
|
+
const newThreadRuntime = deferred<unknown>();
|
|
139
|
+
const adapter = makeAdapter({
|
|
140
|
+
fetch: vi.fn(() => fetchB.promise),
|
|
141
|
+
list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
|
|
142
|
+
});
|
|
143
|
+
const core = createCore(adapter);
|
|
144
|
+
await core.getLoadThreadsPromise();
|
|
145
|
+
await core.switchToThread("thread-a");
|
|
146
|
+
|
|
147
|
+
const threadAId = core.getItemById("thread-a")?.id;
|
|
148
|
+
const newThreadId = core.newThreadId;
|
|
149
|
+
if (!newThreadId) throw new Error("Expected an initial new thread");
|
|
150
|
+
|
|
151
|
+
setStartThreadRuntime(core, (id) =>
|
|
152
|
+
id === core.getItemById(newThreadId)?.id
|
|
153
|
+
? newThreadRuntime.promise
|
|
154
|
+
: Promise.resolve({}),
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const deleteA = core.delete("thread-a");
|
|
158
|
+
const switchToB = core.switchToThread("thread-b");
|
|
159
|
+
const switchToBResult = expect(switchToB).rejects.toThrow("fetch failed");
|
|
160
|
+
|
|
161
|
+
newThreadRuntime.resolve({});
|
|
162
|
+
fetchB.reject(new Error("fetch failed"));
|
|
163
|
+
|
|
164
|
+
await switchToBResult;
|
|
165
|
+
await deleteA;
|
|
166
|
+
|
|
167
|
+
expect(core.mainThreadId).not.toBe(threadAId);
|
|
168
|
+
expect(core.mainThreadId).toBe(core.getItemById(core.newThreadId!)?.id);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("lets a newer successful switch move the mutation target away", async () => {
|
|
172
|
+
const fetchB = deferred<RemoteThreadMetadata>();
|
|
173
|
+
const newThreadRuntime = deferred<unknown>();
|
|
174
|
+
const adapter = makeAdapter({
|
|
175
|
+
fetch: vi.fn(() => fetchB.promise),
|
|
176
|
+
list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
|
|
177
|
+
});
|
|
178
|
+
const core = createCore(adapter);
|
|
179
|
+
await core.getLoadThreadsPromise();
|
|
180
|
+
await core.switchToThread("thread-a");
|
|
181
|
+
|
|
182
|
+
const newThreadId = core.newThreadId;
|
|
183
|
+
if (!newThreadId) throw new Error("Expected an initial new thread");
|
|
184
|
+
|
|
185
|
+
setStartThreadRuntime(core, (id) =>
|
|
186
|
+
id === core.getItemById(newThreadId)?.id
|
|
187
|
+
? newThreadRuntime.promise
|
|
188
|
+
: Promise.resolve({}),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const deleteA = core.delete("thread-a");
|
|
192
|
+
const switchToB = core.switchToThread("thread-b");
|
|
193
|
+
|
|
194
|
+
newThreadRuntime.resolve({});
|
|
195
|
+
fetchB.resolve(thread("thread-b"));
|
|
196
|
+
|
|
197
|
+
await switchToB;
|
|
198
|
+
await deleteA;
|
|
199
|
+
|
|
200
|
+
expect(core.mainThreadId).toBe(core.getItemById("thread-b")?.id);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("does not let a mutation cancel an existing pending switch", async () => {
|
|
204
|
+
const fetchB = deferred<RemoteThreadMetadata>();
|
|
205
|
+
const adapter = makeAdapter({
|
|
206
|
+
fetch: vi.fn(() => fetchB.promise),
|
|
207
|
+
list: vi.fn(async () => ({ threads: [thread("thread-a")] })),
|
|
208
|
+
});
|
|
209
|
+
const core = createCore(adapter);
|
|
210
|
+
await core.getLoadThreadsPromise();
|
|
211
|
+
await core.switchToThread("thread-a");
|
|
212
|
+
|
|
213
|
+
const switchToB = core.switchToThread("thread-b");
|
|
214
|
+
const deleteA = core.delete("thread-a");
|
|
215
|
+
|
|
216
|
+
fetchB.resolve(thread("thread-b"));
|
|
217
|
+
|
|
218
|
+
await switchToB;
|
|
219
|
+
await deleteA;
|
|
220
|
+
|
|
221
|
+
expect(core.mainThreadId).toBe(core.getItemById("thread-b")?.id);
|
|
222
|
+
});
|
|
223
|
+
});
|