@assistant-ui/core 0.3.12 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/speech.d.ts.map +1 -1
- package/dist/adapters/speech.js +9 -15
- package/dist/adapters/speech.js.map +1 -1
- package/dist/adapters/thread-history.d.ts +2 -0
- package/dist/adapters/thread-history.d.ts.map +1 -1
- package/dist/adapters/voice.d.ts.map +1 -1
- package/dist/adapters/voice.js +27 -15
- package/dist/adapters/voice.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +6 -6
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +2 -1
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/registry.js +16 -4
- package/dist/model-context/registry.js.map +1 -1
- package/dist/react/RuntimeAdapter.d.ts +8 -1
- package/dist/react/RuntimeAdapter.d.ts.map +1 -1
- package/dist/react/RuntimeAdapter.js +23 -18
- package/dist/react/RuntimeAdapter.js.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +28 -12
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/AdaptedRemoteThread.d.ts +11 -0
- package/dist/react/client/AdaptedRemoteThread.d.ts.map +1 -0
- package/dist/react/client/AdaptedRemoteThread.js +27 -0
- package/dist/react/client/AdaptedRemoteThread.js.map +1 -0
- package/dist/react/client/InMemoryThreadList.d.ts +19 -0
- package/dist/react/client/InMemoryThreadList.d.ts.map +1 -0
- package/dist/react/client/InMemoryThreadList.js +418 -0
- package/dist/react/client/InMemoryThreadList.js.map +1 -0
- package/dist/react/client/Interactables.d.ts.map +1 -1
- package/dist/react/client/Interactables.js +159 -102
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +34 -0
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -0
- package/dist/react/client/RemoteThreadList.js +826 -0
- package/dist/react/client/RemoteThreadList.js.map +1 -0
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +38 -27
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/client/interactable-model-context.d.ts.map +1 -1
- package/dist/react/client/interactable-model-context.js +5 -1
- package/dist/react/client/interactable-model-context.js.map +1 -1
- package/dist/react/index.d.ts +7 -2
- package/dist/react/index.js +5 -2
- package/dist/react/interactables-legacy/Interactables.d.ts.map +1 -1
- package/dist/react/interactables-legacy/Interactables.js +145 -110
- package/dist/react/interactables-legacy/Interactables.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarCopy.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarCopy.js +13 -18
- package/dist/react/primitive-hooks/useActionBarCopy.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarEdit.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarEdit.js +2 -4
- package/dist/react/primitive-hooks/useActionBarEdit.js.map +1 -1
- package/dist/react/primitive-hooks/useActionBarReload.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useActionBarReload.js +2 -4
- package/dist/react/primitive-hooks/useActionBarReload.js.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerNext.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerNext.js +2 -6
- package/dist/react/primitive-hooks/useBranchPickerNext.js.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerPrevious.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useBranchPickerPrevious.js +2 -6
- package/dist/react/primitive-hooks/useBranchPickerPrevious.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerCancel.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerCancel.js +2 -4
- package/dist/react/primitive-hooks/useComposerCancel.js.map +1 -1
- package/dist/react/primitive-hooks/useComposerSend.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useComposerSend.js +2 -4
- package/dist/react/primitive-hooks/useComposerSend.js.map +1 -1
- package/dist/react/primitive-hooks/useSuggestionTrigger.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useSuggestionTrigger.js +6 -2
- package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.d.ts +13 -0
- package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +22 -10
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +109 -71
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +8 -2
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +40 -13
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts +30 -0
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -0
- package/dist/react/runtimes/RemoteThreadResource.js +134 -0
- package/dist/react/runtimes/RemoteThreadResource.js.map +1 -0
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts +3 -10
- package/dist/react/runtimes/RuntimeAdapterProvider.d.ts.map +1 -1
- package/dist/react/runtimes/RuntimeAdapterProvider.js +3 -6
- package/dist/react/runtimes/RuntimeAdapterProvider.js.map +1 -1
- package/dist/react/runtimes/assistant-transport/commandQueue.d.ts +17 -0
- package/dist/react/runtimes/assistant-transport/commandQueue.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/commandQueue.js +55 -0
- package/dist/react/runtimes/assistant-transport/commandQueue.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts +11 -0
- package/dist/react/runtimes/assistant-transport/replayBoundaryStream.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js +165 -0
- package/dist/react/runtimes/assistant-transport/replayBoundaryStream.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/runManager.d.ts +15 -0
- package/dist/react/runtimes/assistant-transport/runManager.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/runManager.js +86 -0
- package/dist/react/runtimes/assistant-transport/runManager.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/types.d.ts +130 -0
- package/dist/react/runtimes/assistant-transport/types.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/types.js +0 -0
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts +14 -0
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js +296 -0
- package/dist/react/runtimes/assistant-transport/useAssistantTransportRuntime.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts +7 -0
- package/dist/react/runtimes/assistant-transport/useConvertedState.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/useConvertedState.js +25 -0
- package/dist/react/runtimes/assistant-transport/useConvertedState.js.map +1 -0
- package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts +7 -0
- package/dist/react/runtimes/assistant-transport/useLatestRef.d.ts.map +1 -0
- package/dist/react/runtimes/assistant-transport/useLatestRef.js +27 -0
- package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -0
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +39 -13
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +2 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +3 -3
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +4 -0
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +7 -0
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +22 -12
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts +16 -0
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.d.ts.map +1 -0
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js +36 -0
- package/dist/react/runtimes/cloud/useCloudThreadListRuntime.js.map +1 -0
- package/dist/react/runtimes/external-message-converter.js +14 -14
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.js +44 -28
- package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreSharedOptions.js.map +1 -1
- package/dist/react/runtimes/useLocalRuntime.js +1 -1
- package/dist/react/runtimes/useRuntimeAdapters.d.ts +9 -0
- package/dist/react/runtimes/useRuntimeAdapters.d.ts.map +1 -0
- package/dist/react/runtimes/useRuntimeAdapters.js +20 -0
- package/dist/react/runtimes/useRuntimeAdapters.js.map +1 -0
- package/dist/runtime/api/composer-runtime.d.ts +5 -0
- package/dist/runtime/api/composer-runtime.d.ts.map +1 -1
- package/dist/runtime/api/composer-runtime.js.map +1 -1
- package/dist/runtime/api/message-runtime.js +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +1 -0
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +4 -2
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +12 -2
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +13 -3
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +25 -0
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +72 -18
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +15 -0
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +34 -3
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +1 -6
- package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts +0 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js +11 -8
- package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/internal.js +5 -5
- package/dist/runtime/queue/external-thread-queue-adapter.d.ts +15 -0
- package/dist/runtime/queue/external-thread-queue-adapter.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.js +25 -11
- package/dist/runtime/queue/message-queue.js.map +1 -1
- package/dist/runtime/utils/thread-runtime-lifecycle.d.ts +8 -0
- package/dist/runtime/utils/thread-runtime-lifecycle.d.ts.map +1 -0
- package/dist/runtime/utils/thread-runtime-lifecycle.js +11 -0
- package/dist/runtime/utils/thread-runtime-lifecycle.js.map +1 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts +7 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-shared-options.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +11 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +78 -20
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/internal.d.ts +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +3 -0
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +55 -14
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +1 -0
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +3 -0
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
- package/dist/runtimes/remote-thread-list/empty-thread-core.js +3 -0
- package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +29 -1
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +1 -12
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +67 -38
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/external-thread.d.ts +7 -0
- package/dist/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +460 -369
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/runtime-adapter.d.ts.map +1 -1
- package/dist/store/clients/runtime-adapter.js +5 -2
- package/dist/store/clients/runtime-adapter.js.map +1 -1
- package/dist/store/clients/single-thread-list.d.ts.map +1 -1
- package/dist/store/clients/single-thread-list.js +31 -27
- package/dist/store/clients/single-thread-list.js.map +1 -1
- package/dist/store/clients/suggestions.d.ts +3 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/suggestions.js +65 -37
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/clients/thread-selection-events.d.ts +10 -0
- package/dist/store/clients/thread-selection-events.d.ts.map +1 -0
- package/dist/store/clients/thread-selection-events.js +40 -0
- package/dist/store/clients/thread-selection-events.js.map +1 -0
- package/dist/store/env.d.ts +5 -0
- package/dist/store/env.d.ts.map +1 -0
- package/dist/store/env.js +12 -0
- package/dist/store/env.js.map +1 -0
- package/dist/store/index.d.ts +6 -4
- package/dist/store/index.js +5 -3
- package/dist/store/internal.d.ts +4 -1
- package/dist/store/internal.js +4 -1
- package/dist/store/primitive-predicates.d.ts +19 -0
- package/dist/store/primitive-predicates.d.ts.map +1 -0
- package/dist/store/primitive-predicates.js +19 -0
- package/dist/store/primitive-predicates.js.map +1 -0
- package/dist/store/runtime-clients/attachment-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/attachment-runtime-client.js +18 -11
- package/dist/store/runtime-clients/attachment-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/handle-runtime-action.d.ts +5 -0
- package/dist/store/runtime-clients/handle-runtime-action.d.ts.map +1 -0
- package/dist/store/runtime-clients/handle-runtime-action.js +12 -0
- package/dist/store/runtime-clients/handle-runtime-action.js.map +1 -0
- package/dist/store/runtime-clients/handle-thread-list-action.d.ts +5 -0
- package/dist/store/runtime-clients/handle-thread-list-action.d.ts.map +1 -0
- package/dist/store/runtime-clients/handle-thread-list-action.js +7 -0
- package/dist/store/runtime-clients/handle-thread-list-action.js.map +1 -0
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +104 -57
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js +5 -6
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +98 -82
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/scope-registration.d.ts +2 -2
- package/dist/store/scopes/composer.d.ts +9 -4
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/suggestions.d.ts +6 -1
- package/dist/store/scopes/suggestions.d.ts.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +7 -6
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/dist/store/scopes/thread.d.ts +25 -7
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/store/scopes/threads.d.ts +17 -1
- package/dist/store/scopes/threads.d.ts.map +1 -1
- package/dist/subscribable/subscribable.d.ts +2 -1
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +23 -18
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/types/error.d.ts +15 -1
- package/dist/types/error.d.ts.map +1 -1
- package/dist/types/error.js +18 -1
- package/dist/types/error.js.map +1 -1
- package/dist/types/message.d.ts +2 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/composite-context-provider.d.ts +1 -0
- package/dist/utils/composite-context-provider.d.ts.map +1 -1
- package/dist/utils/composite-context-provider.js +25 -9
- package/dist/utils/composite-context-provider.js.map +1 -1
- package/dist/utils/notify-event-listeners.d.ts +2 -2
- package/dist/utils/notify-event-listeners.d.ts.map +1 -1
- package/dist/utils/notify-event-listeners.js +2 -2
- package/dist/utils/notify-event-listeners.js.map +1 -1
- package/package.json +7 -7
- package/src/adapters/speech.test.ts +118 -1
- package/src/adapters/speech.ts +21 -22
- package/src/adapters/thread-history.ts +2 -0
- package/src/adapters/voice.test.ts +69 -0
- package/src/adapters/voice.ts +27 -27
- package/src/index.ts +2 -0
- package/src/model-context/frame/host.test.ts +23 -0
- package/src/model-context/frame/host.ts +2 -1
- package/src/model-context/registry.test.ts +131 -0
- package/src/model-context/registry.ts +16 -6
- package/src/react/RuntimeAdapter.test.ts +2 -0
- package/src/react/RuntimeAdapter.ts +20 -8
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +34 -17
- package/src/react/client/AdaptedRemoteThread.ts +41 -0
- package/src/react/client/InMemoryThreadList.test.tsx +148 -0
- package/src/react/client/InMemoryThreadList.ts +290 -0
- package/src/react/client/Interactables.test.ts +326 -2
- package/src/react/client/Interactables.ts +227 -110
- package/src/react/client/RemoteThreadList.test.ts +1026 -0
- package/src/react/client/RemoteThreadList.ts +1067 -0
- package/src/react/client/Tools.ts +36 -29
- package/src/react/client/interactable-model-context.ts +6 -1
- package/src/react/index.ts +13 -0
- package/src/react/interactables-legacy/Interactables.test.ts +317 -0
- package/src/react/interactables-legacy/Interactables.ts +204 -128
- package/src/react/primitive-hooks/useActionBarCopy.ts +2 -7
- package/src/react/primitive-hooks/useActionBarEdit.ts +2 -1
- package/src/react/primitive-hooks/useActionBarReload.ts +2 -6
- package/src/react/primitive-hooks/useBranchPickerNext.ts +2 -7
- package/src/react/primitive-hooks/useBranchPickerPrevious.ts +2 -7
- package/src/react/primitive-hooks/useComposerCancel.ts +2 -1
- package/src/react/primitive-hooks/useComposerSend.ts +2 -5
- package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +11 -0
- package/src/react/primitive-hooks/useSuggestionTrigger.ts +4 -5
- package/src/react/primitives/message/MessageParts.tsx +0 -1
- package/src/react/primitives/thread/ThreadMessages.tsx +2 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.retry.test.tsx +116 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +1 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +57 -6
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.title.test.tsx +272 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +159 -124
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +59 -20
- package/src/react/runtimes/RemoteThreadResource.test.ts +141 -0
- package/src/react/runtimes/RemoteThreadResource.ts +231 -0
- package/src/react/runtimes/RuntimeAdapterProvider.tsx +8 -20
- package/src/react/runtimes/assistant-transport/commandQueue.ts +68 -0
- package/src/react/runtimes/assistant-transport/replayBoundaryStream.test.ts +455 -0
- package/src/react/runtimes/assistant-transport/replayBoundaryStream.ts +172 -0
- package/src/react/runtimes/assistant-transport/runManager.ts +124 -0
- package/src/react/runtimes/assistant-transport/transport-delivery.test.tsx +79 -0
- package/src/react/runtimes/assistant-transport/transport-parentid.test.tsx +97 -0
- package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +414 -0
- package/src/react/runtimes/assistant-transport/types.ts +170 -0
- package/src/react/runtimes/assistant-transport/useAssistantTransport.spec.md +141 -0
- package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.test.tsx +625 -0
- package/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.ts +481 -0
- package/src/react/runtimes/assistant-transport/useConvertedState.ts +20 -0
- package/src/react/runtimes/assistant-transport/useLatestRef.ts +9 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +131 -6
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +61 -15
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +6 -4
- package/src/react/runtimes/cloud/auiV0.ts +17 -1
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +36 -21
- package/src/react/runtimes/cloud/useCloudThreadListRuntime.test.tsx +56 -0
- package/src/react/runtimes/cloud/useCloudThreadListRuntime.ts +31 -0
- package/src/react/runtimes/external-message-converter.test.ts +143 -0
- package/src/react/runtimes/external-message-converter.ts +41 -41
- package/src/react/runtimes/remote-thread-hook-on-tap.test.ts +58 -0
- package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +83 -0
- package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +124 -0
- package/src/react/runtimes/useExternalStoreRuntime.ts +7 -0
- package/src/react/runtimes/useExternalStoreSharedOptions.ts +3 -1
- package/src/react/runtimes/useLocalRuntime.test.tsx +130 -4
- package/src/react/runtimes/useRuntimeAdapters.test.tsx +62 -0
- package/src/react/runtimes/useRuntimeAdapters.ts +28 -0
- package/src/runtime/api/composer-runtime.ts +5 -0
- package/src/runtime/api/thread-list-runtime.ts +3 -1
- package/src/runtime/api/thread-runtime.ts +28 -3
- package/src/runtime/base/base-composer-runtime-core.ts +106 -13
- package/src/runtime/base/base-thread-runtime-core.test.ts +191 -0
- package/src/runtime/base/base-thread-runtime-core.ts +47 -2
- package/src/runtime/base/default-edit-composer-runtime-core.ts +1 -15
- package/src/runtime/base/default-thread-composer-runtime-core.ts +13 -15
- package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
- package/src/runtime/queue/external-thread-queue-adapter.ts +17 -0
- package/src/runtime/queue/message-queue.ts +28 -10
- package/src/runtime/utils/thread-runtime-lifecycle.ts +18 -0
- package/src/runtimes/external-store/external-store-adapter.ts +7 -0
- package/src/runtimes/external-store/external-store-shared-options.ts +3 -1
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +4 -1
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +187 -48
- package/src/runtimes/local/local-thread-runtime-core.test.ts +373 -4
- package/src/runtimes/local/local-thread-runtime-core.ts +83 -15
- package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +4 -0
- package/src/runtimes/remote-thread-list/empty-thread-core.ts +4 -0
- package/src/runtimes/remote-thread-list/types.ts +30 -0
- package/src/runtimes/tool-invocations/EDGE_CASES.md +17 -6
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +243 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +127 -61
- package/src/store/clients/external-thread.ts +119 -16
- package/src/store/clients/model-context-client.test.ts +16 -8
- package/src/store/clients/runtime-adapter.ts +5 -2
- package/src/store/clients/single-thread-list.ts +2 -1
- package/src/store/clients/suggestions.ts +39 -13
- package/src/store/clients/thread-selection-events.ts +21 -0
- package/src/store/env.ts +11 -0
- package/src/store/index.ts +14 -1
- package/src/store/internal.ts +13 -0
- package/src/store/primitive-predicates.test.ts +184 -0
- package/src/store/primitive-predicates.ts +43 -0
- package/src/store/runtime-clients/attachment-runtime-client.test.ts +41 -0
- package/src/store/runtime-clients/attachment-runtime-client.ts +2 -1
- package/src/store/runtime-clients/handle-runtime-action.ts +11 -0
- package/src/store/runtime-clients/handle-thread-list-action.test.ts +69 -0
- package/src/store/runtime-clients/handle-thread-list-action.ts +6 -0
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +28 -35
- package/src/store/runtime-clients/thread-list-runtime-client.ts +9 -6
- package/src/store/runtime-clients/thread-runtime-client.ts +5 -0
- package/src/store/scopes/composer.ts +9 -4
- package/src/store/scopes/suggestions.ts +6 -0
- package/src/store/scopes/thread-list-item.ts +7 -6
- package/src/store/scopes/thread.ts +25 -7
- package/src/store/scopes/threads.ts +14 -0
- package/src/subscribable/subscribable.test.ts +77 -1
- package/src/subscribable/subscribable.ts +38 -23
- package/src/tests/RemoteThreadListThreadListRuntimeCore-switchToThread-unarchive.test.ts +25 -0
- package/src/tests/append-interactable-snapshots.test.ts +350 -0
- package/src/tests/auiV0Encode.test.ts +66 -0
- package/src/tests/base-composer-runtime-core-send.test.ts +156 -0
- package/src/tests/base-composer-runtime-core.test.ts +136 -1
- package/src/tests/composer-can-cancel.test.ts +101 -0
- package/src/tests/default-edit-composer-runtime-core.test.ts +0 -68
- package/src/tests/external-store-thread-list-runtime-core.test.ts +101 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +491 -1
- package/src/tests/external-store-thread-runtime-core.test.ts +124 -0
- package/src/tests/external-thread-attachments.test.tsx +214 -0
- package/src/tests/external-thread-parity.test.tsx +54 -0
- package/src/tests/external-thread-refetch.test.tsx +117 -0
- package/src/tests/external-thread-suggestions.test.tsx +59 -0
- package/src/tests/interactables-toolui-migration.test.tsx +66 -0
- package/src/tests/message-queue.test.ts +54 -0
- package/src/tests/session-reset-notification.test.ts +145 -0
- package/src/tests/thread-message-like.test.ts +39 -0
- package/src/tests/thread-switch-events.test.tsx +234 -0
- package/src/tests/tools-scope-migration.test.tsx +58 -0
- package/src/types/error.ts +24 -0
- package/src/types/message.ts +2 -0
- package/src/utils/composite-context-provider.test.ts +139 -0
- package/src/utils/composite-context-provider.ts +26 -8
- package/src/utils/notify-event-listeners.ts +10 -5
- package/src/tests/default-thread-composer-runtime-core.test.ts +0 -82
|
@@ -35,6 +35,20 @@ export type ThreadsMethods = {
|
|
|
35
35
|
__internal_getAssistantRuntime?(): AssistantRuntime;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
export type ThreadsEvents = {
|
|
39
|
+
/**
|
|
40
|
+
* The main thread selection changed. Fires once per switch with the newly
|
|
41
|
+
* selected thread and the thread that was selected before. Does not fire
|
|
42
|
+
* for the initially selected thread on mount. Runtimes that resolve a
|
|
43
|
+
* deep-linked `threadId`/`initialThreadId` after mount (such as
|
|
44
|
+
* `useRemoteThreadListRuntime`) start on a placeholder new thread, so the
|
|
45
|
+
* deep link's resolution fires this event with the placeholder as
|
|
46
|
+
* `previousThreadId`.
|
|
47
|
+
*/
|
|
48
|
+
"threads.selectionChanged": { threadId: string; previousThreadId: string };
|
|
49
|
+
};
|
|
50
|
+
|
|
38
51
|
export type ThreadsClientSchema = {
|
|
39
52
|
methods: ThreadsMethods;
|
|
53
|
+
events: ThreadsEvents;
|
|
40
54
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
2
|
import type { SubscribableWithState } from "./subscribable";
|
|
3
|
-
import { ShallowMemoizeSubject } from "./subscribable";
|
|
3
|
+
import { LazyMemoizeSubject, ShallowMemoizeSubject } from "./subscribable";
|
|
4
4
|
|
|
5
5
|
type TestState = {
|
|
6
6
|
status: string;
|
|
@@ -26,6 +26,9 @@ const createBinding = (initialState: TestState) => {
|
|
|
26
26
|
state = nextState;
|
|
27
27
|
for (const callback of subscribers) callback();
|
|
28
28
|
},
|
|
29
|
+
replace(nextState: TestState) {
|
|
30
|
+
state = nextState;
|
|
31
|
+
},
|
|
29
32
|
};
|
|
30
33
|
};
|
|
31
34
|
|
|
@@ -55,4 +58,77 @@ describe("ShallowMemoizeSubject", () => {
|
|
|
55
58
|
|
|
56
59
|
expect(subscriber).not.toHaveBeenCalled();
|
|
57
60
|
});
|
|
61
|
+
|
|
62
|
+
it("notifies later subscribers when one throws", () => {
|
|
63
|
+
const source = createBinding({ status: "empty" });
|
|
64
|
+
const subject = new ShallowMemoizeSubject(source.binding);
|
|
65
|
+
const error = new Error("subscriber failed");
|
|
66
|
+
const laterSubscriber = vi.fn();
|
|
67
|
+
subject.subscribe(() => {
|
|
68
|
+
throw error;
|
|
69
|
+
});
|
|
70
|
+
subject.subscribe(laterSubscriber);
|
|
71
|
+
|
|
72
|
+
expect(() => source.update({ status: "ready" })).toThrow(error);
|
|
73
|
+
expect(laterSubscriber).toHaveBeenCalledOnce();
|
|
74
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("reads a value that landed while nobody was subscribed", () => {
|
|
78
|
+
const source = createBinding({ status: "empty" });
|
|
79
|
+
const subject = new ShallowMemoizeSubject(source.binding);
|
|
80
|
+
expect(subject.getState()).toEqual({ status: "empty" });
|
|
81
|
+
|
|
82
|
+
source.update({ status: "ready" });
|
|
83
|
+
const subscriber = vi.fn();
|
|
84
|
+
subject.subscribe(subscriber);
|
|
85
|
+
|
|
86
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
87
|
+
expect(subscriber).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("LazyMemoizeSubject", () => {
|
|
92
|
+
it("notifies later subscribers when one throws", () => {
|
|
93
|
+
const source = createBinding({ status: "empty" });
|
|
94
|
+
const subject = new LazyMemoizeSubject(source.binding);
|
|
95
|
+
const error = new Error("subscriber failed");
|
|
96
|
+
const laterSubscriber = vi.fn();
|
|
97
|
+
subject.subscribe(() => {
|
|
98
|
+
throw error;
|
|
99
|
+
});
|
|
100
|
+
subject.subscribe(laterSubscriber);
|
|
101
|
+
|
|
102
|
+
expect(() => source.update({ status: "ready" })).toThrow(error);
|
|
103
|
+
expect(laterSubscriber).toHaveBeenCalledOnce();
|
|
104
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("reads a value replaced before connecting", () => {
|
|
108
|
+
const source = createBinding({ status: "empty" });
|
|
109
|
+
const subject = new LazyMemoizeSubject(source.binding);
|
|
110
|
+
expect(subject.getState()).toEqual({ status: "empty" });
|
|
111
|
+
|
|
112
|
+
source.replace({ status: "ready" });
|
|
113
|
+
const subscriber = vi.fn();
|
|
114
|
+
const unsubscribe = subject.subscribe(subscriber);
|
|
115
|
+
|
|
116
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
117
|
+
expect(subscriber).not.toHaveBeenCalled();
|
|
118
|
+
unsubscribe();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("resynchronizes after reconnecting", () => {
|
|
122
|
+
const source = createBinding({ status: "empty" });
|
|
123
|
+
const subject = new LazyMemoizeSubject(source.binding);
|
|
124
|
+
expect(subject.getState()).toEqual({ status: "empty" });
|
|
125
|
+
|
|
126
|
+
const unsubscribe = subject.subscribe(() => {});
|
|
127
|
+
unsubscribe();
|
|
128
|
+
source.replace({ status: "ready" });
|
|
129
|
+
const reconnect = subject.subscribe(() => {});
|
|
130
|
+
|
|
131
|
+
expect(subject.getState()).toEqual({ status: "ready" });
|
|
132
|
+
reconnect();
|
|
133
|
+
});
|
|
58
134
|
});
|
|
@@ -32,6 +32,31 @@ export type EventSubscribable<TEvent extends string> = {
|
|
|
32
32
|
>;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
export const notifySubscribers = <TArgs extends unknown[]>(
|
|
36
|
+
subscribers: Iterable<(...args: TArgs) => void>,
|
|
37
|
+
...args: TArgs
|
|
38
|
+
): void => {
|
|
39
|
+
const errors: unknown[] = [];
|
|
40
|
+
for (const callback of subscribers) {
|
|
41
|
+
try {
|
|
42
|
+
callback(...args);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
errors.push(error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (errors.length === 1) {
|
|
49
|
+
throw errors[0];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (errors.length > 1) {
|
|
53
|
+
for (const error of errors) {
|
|
54
|
+
console.error(error);
|
|
55
|
+
}
|
|
56
|
+
throw new AggregateError(errors);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
35
60
|
function shallowEqual<T extends object>(
|
|
36
61
|
objA: T | undefined,
|
|
37
62
|
objB: T | undefined,
|
|
@@ -70,25 +95,7 @@ export class BaseSubscribable {
|
|
|
70
95
|
}
|
|
71
96
|
|
|
72
97
|
protected _notifySubscribers() {
|
|
73
|
-
|
|
74
|
-
for (const callback of this._subscribers) {
|
|
75
|
-
try {
|
|
76
|
-
callback();
|
|
77
|
-
} catch (error) {
|
|
78
|
-
errors.push(error);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (errors.length > 0) {
|
|
83
|
-
if (errors.length === 1) {
|
|
84
|
-
throw errors[0];
|
|
85
|
-
} else {
|
|
86
|
-
for (const error of errors) {
|
|
87
|
-
console.error(error);
|
|
88
|
-
}
|
|
89
|
-
throw new AggregateError(errors);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
98
|
+
notifySubscribers(this._subscribers);
|
|
92
99
|
}
|
|
93
100
|
}
|
|
94
101
|
|
|
@@ -109,7 +116,7 @@ export abstract class BaseSubject {
|
|
|
109
116
|
return;
|
|
110
117
|
}
|
|
111
118
|
|
|
112
|
-
|
|
119
|
+
notifySubscribers(this._subscriptions, payload);
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
private _updateConnection() {
|
|
@@ -173,7 +180,9 @@ export class ShallowMemoizeSubject<TState extends object, TPath>
|
|
|
173
180
|
}
|
|
174
181
|
};
|
|
175
182
|
|
|
176
|
-
|
|
183
|
+
const unsubscribe = this.binding.subscribe(callback);
|
|
184
|
+
this._syncState();
|
|
185
|
+
return unsubscribe;
|
|
177
186
|
}
|
|
178
187
|
}
|
|
179
188
|
|
|
@@ -197,7 +206,11 @@ export class LazyMemoizeSubject<TState extends object, TPath>
|
|
|
197
206
|
public getState = () => {
|
|
198
207
|
if (!this.isConnected || this._previousStateDirty) {
|
|
199
208
|
const newState = this.binding.getState();
|
|
200
|
-
if (
|
|
209
|
+
if (
|
|
210
|
+
newState !== SKIP_UPDATE &&
|
|
211
|
+
(this._previousState === undefined ||
|
|
212
|
+
!shallowEqual(newState, this._previousState))
|
|
213
|
+
) {
|
|
201
214
|
this._previousState = newState;
|
|
202
215
|
}
|
|
203
216
|
this._previousStateDirty = false;
|
|
@@ -213,7 +226,9 @@ export class LazyMemoizeSubject<TState extends object, TPath>
|
|
|
213
226
|
this.notifySubscribers();
|
|
214
227
|
};
|
|
215
228
|
|
|
216
|
-
|
|
229
|
+
const unsubscribe = this.binding.subscribe(callback);
|
|
230
|
+
this._previousStateDirty = true;
|
|
231
|
+
return unsubscribe;
|
|
217
232
|
}
|
|
218
233
|
}
|
|
219
234
|
|
|
@@ -63,6 +63,31 @@ describe("RemoteThreadListThreadListRuntimeCore.switchToThread unarchive option"
|
|
|
63
63
|
expect(core.mainThreadId).toBe(core.getItemById(THREAD_ID)?.id);
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
it("restores an initialized draft's archived thread when unarchive fails", async () => {
|
|
67
|
+
const THREAD_ID = "archived-initialized-draft";
|
|
68
|
+
const error = new Error("unarchive failed");
|
|
69
|
+
const adapter = makeAdapter({
|
|
70
|
+
list: vi.fn(async () => ({ threads: [archivedThread(THREAD_ID)] })),
|
|
71
|
+
unarchive: vi.fn(async () => {
|
|
72
|
+
throw error;
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const core = createCore(adapter);
|
|
77
|
+
await core.getLoadThreadsPromise();
|
|
78
|
+
const draftId = core.newThreadId;
|
|
79
|
+
if (draftId === undefined) throw new Error("Expected seeded draft");
|
|
80
|
+
await core.initialize(draftId);
|
|
81
|
+
expect(core.newThreadId).toBeUndefined();
|
|
82
|
+
await core.switchToThread(THREAD_ID, { unarchive: false });
|
|
83
|
+
|
|
84
|
+
await expect(core.unarchive(THREAD_ID)).rejects.toBe(error);
|
|
85
|
+
expect(core.mainThreadId).not.toBe(THREAD_ID);
|
|
86
|
+
expect(core.getItemById(THREAD_ID)?.status).toBe("archived");
|
|
87
|
+
expect(core.archivedThreadIds).toContain(THREAD_ID);
|
|
88
|
+
expect(core.threadIds).not.toContain(THREAD_ID);
|
|
89
|
+
});
|
|
90
|
+
|
|
66
91
|
it("does not call unarchive when the target is already regular, regardless of option", async () => {
|
|
67
92
|
const THREAD_ID = "regular-target";
|
|
68
93
|
const adapter = makeAdapter({
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { ExternalStoreRuntimeCore } from "../runtimes/external-store/external-store-runtime-core";
|
|
3
|
+
import { LocalRuntimeCore } from "../runtimes/local/local-runtime-core";
|
|
4
|
+
import { createMessageQueue } from "../runtime/queue/message-queue";
|
|
5
|
+
import { getThreadMessageText } from "../utils/text";
|
|
6
|
+
import type { ChatModelAdapter } from "../runtime/utils/chat-model-adapter";
|
|
7
|
+
import type { AppendMessage, ThreadMessage } from "../types/message";
|
|
8
|
+
|
|
9
|
+
const live = (state: unknown) => ({
|
|
10
|
+
interactables: [{ id: "n1", name: "note", state }],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const snapshotMessage = (id: string, state: unknown) =>
|
|
14
|
+
({
|
|
15
|
+
id,
|
|
16
|
+
role: "user",
|
|
17
|
+
createdAt: new Date(),
|
|
18
|
+
content: [{ type: "text", text: "old" }],
|
|
19
|
+
attachments: [],
|
|
20
|
+
metadata: {
|
|
21
|
+
custom: { interactables: [{ id: "n1", name: "note", state }] },
|
|
22
|
+
},
|
|
23
|
+
}) as ThreadMessage;
|
|
24
|
+
|
|
25
|
+
const userMessage = (text: string, parentId: string | null): AppendMessage => ({
|
|
26
|
+
parentId,
|
|
27
|
+
sourceId: null,
|
|
28
|
+
runConfig: {},
|
|
29
|
+
role: "user",
|
|
30
|
+
content: [{ type: "text", text }],
|
|
31
|
+
attachments: [],
|
|
32
|
+
metadata: { custom: {} },
|
|
33
|
+
createdAt: new Date(),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const externalThread = (options?: {
|
|
37
|
+
messages?: ThreadMessage[];
|
|
38
|
+
composerMetadata?: Record<string, unknown>;
|
|
39
|
+
}) => {
|
|
40
|
+
const onNew = vi.fn(async () => {});
|
|
41
|
+
const onEdit = vi.fn(async () => {});
|
|
42
|
+
const core = new ExternalStoreRuntimeCore({
|
|
43
|
+
messages: options?.messages ?? [],
|
|
44
|
+
onNew,
|
|
45
|
+
onEdit,
|
|
46
|
+
});
|
|
47
|
+
if (options?.composerMetadata) {
|
|
48
|
+
core.registerModelContextProvider({
|
|
49
|
+
getModelContext: () => ({
|
|
50
|
+
unstable_composerMetadata: options.composerMetadata,
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return { thread: core.threads.getMainThreadRuntimeCore(), onNew, onEdit };
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const appendedSnapshots = (sink: ReturnType<typeof vi.fn>) =>
|
|
58
|
+
(sink.mock.calls[0]![0] as AppendMessage).metadata?.custom?.interactables;
|
|
59
|
+
|
|
60
|
+
const tailId = (messages: ThreadMessage[]) => messages.at(-1)?.id ?? null;
|
|
61
|
+
|
|
62
|
+
describe("interactable snapshots on the append seam", () => {
|
|
63
|
+
it("stamps a baseline on the first send of the thread", async () => {
|
|
64
|
+
const { thread, onNew } = externalThread({
|
|
65
|
+
composerMetadata: live({ v: 1 }),
|
|
66
|
+
});
|
|
67
|
+
await thread.append(userMessage("hello", null));
|
|
68
|
+
expect(appendedSnapshots(onNew)).toEqual([
|
|
69
|
+
{ id: "n1", name: "note", state: { v: 1 } },
|
|
70
|
+
]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("stamps nothing when the history already carries the live state", async () => {
|
|
74
|
+
const messages = [snapshotMessage("msg-1", { v: 1 })];
|
|
75
|
+
const { thread, onNew } = externalThread({
|
|
76
|
+
messages,
|
|
77
|
+
composerMetadata: live({ v: 1 }),
|
|
78
|
+
});
|
|
79
|
+
await thread.append(userMessage("hello", tailId(messages)));
|
|
80
|
+
expect(appendedSnapshots(onNew)).toBeUndefined();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("stamps the new state when it diverged from the latest snapshot", async () => {
|
|
84
|
+
const messages = [snapshotMessage("msg-1", { v: 1 })];
|
|
85
|
+
const { thread, onNew } = externalThread({
|
|
86
|
+
messages,
|
|
87
|
+
composerMetadata: live({ v: 2 }),
|
|
88
|
+
});
|
|
89
|
+
await thread.append(userMessage("hello", tailId(messages)));
|
|
90
|
+
expect(appendedSnapshots(onNew)).toEqual([
|
|
91
|
+
{ id: "n1", name: "note", state: { v: 2 } },
|
|
92
|
+
]);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("stamps a programmatic append, the path suggestions and thread.append() take", async () => {
|
|
96
|
+
const { thread, onNew } = externalThread({
|
|
97
|
+
composerMetadata: live({ tasks: [] }),
|
|
98
|
+
});
|
|
99
|
+
await thread.append(userMessage("Add 3 tasks for a grocery run", null));
|
|
100
|
+
expect(appendedSnapshots(onNew)).toEqual([
|
|
101
|
+
{ id: "n1", name: "note", state: { tasks: [] } },
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("leaves a non-user append unstamped, since no reader folds those", async () => {
|
|
106
|
+
const { thread, onNew } = externalThread({
|
|
107
|
+
composerMetadata: live({ v: 1 }),
|
|
108
|
+
});
|
|
109
|
+
await thread.append({
|
|
110
|
+
...userMessage("an assistant turn", null),
|
|
111
|
+
role: "assistant",
|
|
112
|
+
} as AppendMessage);
|
|
113
|
+
expect(appendedSnapshots(onNew)).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("re-stamps the baseline when the edited message carried the only snapshot", async () => {
|
|
117
|
+
const messages = [snapshotMessage("msg-1", { v: 1 })];
|
|
118
|
+
const { thread, onEdit } = externalThread({
|
|
119
|
+
messages,
|
|
120
|
+
composerMetadata: live({ v: 1 }),
|
|
121
|
+
});
|
|
122
|
+
// An edit branches off the edited message's parent, so the prefix it is
|
|
123
|
+
// gated against excludes the edited message and its snapshot.
|
|
124
|
+
await thread.append({ ...userMessage("new", null), sourceId: "msg-1" });
|
|
125
|
+
expect(appendedSnapshots(onEdit)).toEqual([
|
|
126
|
+
{ id: "n1", name: "note", state: { v: 1 } },
|
|
127
|
+
]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("stamps nothing when the edit's branch prefix already carries the live state", async () => {
|
|
131
|
+
const messages = [
|
|
132
|
+
snapshotMessage("parent-1", { v: 1 }),
|
|
133
|
+
snapshotMessage("msg-1", { v: 1 }),
|
|
134
|
+
];
|
|
135
|
+
const { thread, onEdit } = externalThread({
|
|
136
|
+
messages,
|
|
137
|
+
composerMetadata: live({ v: 1 }),
|
|
138
|
+
});
|
|
139
|
+
await thread.append({
|
|
140
|
+
...userMessage("new", "parent-1"),
|
|
141
|
+
sourceId: "msg-1",
|
|
142
|
+
});
|
|
143
|
+
expect(appendedSnapshots(onEdit)).toBeUndefined();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("stamps on the local runtime core too", async () => {
|
|
147
|
+
const run = vi.fn(async function* () {
|
|
148
|
+
yield { content: [{ type: "text" as const, text: "ok" }] };
|
|
149
|
+
} as unknown as ChatModelAdapter["run"]);
|
|
150
|
+
const core = new LocalRuntimeCore(
|
|
151
|
+
{ adapters: { chatModel: { run } } },
|
|
152
|
+
undefined,
|
|
153
|
+
);
|
|
154
|
+
core.registerModelContextProvider({
|
|
155
|
+
getModelContext: () => ({
|
|
156
|
+
unstable_composerMetadata: live({ v: 1 }),
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
159
|
+
const thread = core.threads.getMainThreadRuntimeCore();
|
|
160
|
+
await thread.append(userMessage("hello", null));
|
|
161
|
+
expect(thread.messages[0]!.metadata.custom?.interactables).toEqual([
|
|
162
|
+
{ id: "n1", name: "note", state: { v: 1 } },
|
|
163
|
+
]);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe("queued sends gate at dispatch, not at enqueue", () => {
|
|
168
|
+
const queuedExternalThread = () => {
|
|
169
|
+
const run = vi.fn();
|
|
170
|
+
const onNew = vi.fn(async () => {});
|
|
171
|
+
const queue = createMessageQueue({ run });
|
|
172
|
+
let composerMetadata: Record<string, unknown> = live({ v: 1 });
|
|
173
|
+
const store = (messages: ThreadMessage[]) => ({
|
|
174
|
+
messages,
|
|
175
|
+
onNew,
|
|
176
|
+
queue: queue.adapter,
|
|
177
|
+
});
|
|
178
|
+
const core = new ExternalStoreRuntimeCore(store([]));
|
|
179
|
+
core.registerModelContextProvider({
|
|
180
|
+
getModelContext: () => ({ unstable_composerMetadata: composerMetadata }),
|
|
181
|
+
});
|
|
182
|
+
return {
|
|
183
|
+
thread: core.threads.getMainThreadRuntimeCore(),
|
|
184
|
+
queue,
|
|
185
|
+
run,
|
|
186
|
+
advanceRecord: (messages: ThreadMessage[], live: unknown) => {
|
|
187
|
+
composerMetadata = live as Record<string, unknown>;
|
|
188
|
+
core.setAdapter(store(messages));
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const dispatched = (run: ReturnType<typeof vi.fn>) =>
|
|
194
|
+
(run.mock.calls[0]![0] as AppendMessage).metadata?.custom?.interactables;
|
|
195
|
+
|
|
196
|
+
it("drops the enqueue-time stamp once the run has told the model that state", async () => {
|
|
197
|
+
const t = queuedExternalThread();
|
|
198
|
+
t.queue.notifyBusy();
|
|
199
|
+
await t.thread.append(userMessage("queued", null));
|
|
200
|
+
expect(t.run).not.toHaveBeenCalled();
|
|
201
|
+
|
|
202
|
+
// the run moved the record to v:2 and the live state matches it
|
|
203
|
+
t.advanceRecord([snapshotMessage("msg-1", { v: 2 })], live({ v: 2 }));
|
|
204
|
+
t.queue.notifyIdle();
|
|
205
|
+
|
|
206
|
+
expect(t.run).toHaveBeenCalledTimes(1);
|
|
207
|
+
expect(dispatched(t.run)).toBeUndefined();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("stamps the state as of the flush when it still diverges", async () => {
|
|
211
|
+
const t = queuedExternalThread();
|
|
212
|
+
t.queue.notifyBusy();
|
|
213
|
+
await t.thread.append(userMessage("queued", null));
|
|
214
|
+
|
|
215
|
+
// the run moved the record to v:2 while the user edited on to v:3
|
|
216
|
+
t.advanceRecord([snapshotMessage("msg-1", { v: 2 })], live({ v: 3 }));
|
|
217
|
+
t.queue.notifyIdle();
|
|
218
|
+
|
|
219
|
+
expect(dispatched(t.run)).toEqual([
|
|
220
|
+
{ id: "n1", name: "note", state: { v: 3 } },
|
|
221
|
+
]);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// interrupt dispatches synchronously inside `append`, so nothing can go
|
|
225
|
+
// stale in between; what matters is that this second dispatch point stamps
|
|
226
|
+
// at all, the way advance does.
|
|
227
|
+
it("stamps on the interrupt path a mid-run steer takes", async () => {
|
|
228
|
+
const run = vi.fn();
|
|
229
|
+
const cancel = vi.fn();
|
|
230
|
+
const onNew = vi.fn(async () => {});
|
|
231
|
+
const queue = createMessageQueue({ run, cancel });
|
|
232
|
+
let composerMetadata: Record<string, unknown> = live({ v: 1 });
|
|
233
|
+
const store = (messages: ThreadMessage[]) => ({
|
|
234
|
+
messages,
|
|
235
|
+
onNew,
|
|
236
|
+
queue: queue.adapter,
|
|
237
|
+
isRunning: true,
|
|
238
|
+
});
|
|
239
|
+
const core = new ExternalStoreRuntimeCore(store([]));
|
|
240
|
+
core.registerModelContextProvider({
|
|
241
|
+
getModelContext: () => ({ unstable_composerMetadata: composerMetadata }),
|
|
242
|
+
});
|
|
243
|
+
const thread = core.threads.getMainThreadRuntimeCore();
|
|
244
|
+
|
|
245
|
+
queue.notifyBusy();
|
|
246
|
+
composerMetadata = live({ v: 2 });
|
|
247
|
+
// isRunning routes this to the steer lane, and a cancel-capable driver
|
|
248
|
+
// makes that an interrupt rather than a buffered enqueue
|
|
249
|
+
await thread.append(
|
|
250
|
+
userMessage("steered", thread.messages.at(-1)?.id ?? null),
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
expect(cancel).toHaveBeenCalled();
|
|
254
|
+
expect(dispatched(run)).toEqual([
|
|
255
|
+
{ id: "n1", name: "note", state: { v: 2 } },
|
|
256
|
+
]);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("re-points a flushed message at the tail it was gated against", async () => {
|
|
260
|
+
const t = queuedExternalThread();
|
|
261
|
+
t.queue.notifyBusy();
|
|
262
|
+
await t.thread.append(userMessage("queued", null));
|
|
263
|
+
|
|
264
|
+
t.advanceRecord([snapshotMessage("msg-1", { v: 2 })], live({ v: 3 }));
|
|
265
|
+
t.queue.notifyIdle();
|
|
266
|
+
|
|
267
|
+
// routing and gating have to name the same point, or the branch the
|
|
268
|
+
// message lands on is not the one its snapshot was computed against
|
|
269
|
+
expect((t.run.mock.calls[0]![0] as AppendMessage).parentId).toBe("msg-1");
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("leaves a hand-rolled adapter stamping at enqueue", async () => {
|
|
273
|
+
const enqueue = vi.fn();
|
|
274
|
+
const onNew = vi.fn(async () => {});
|
|
275
|
+
const core = new ExternalStoreRuntimeCore({
|
|
276
|
+
messages: [],
|
|
277
|
+
onNew,
|
|
278
|
+
// no __internal_setDispatchTransform: nothing re-gates on the way out,
|
|
279
|
+
// so the runtime has to stamp before handing the message over
|
|
280
|
+
queue: {
|
|
281
|
+
items: [],
|
|
282
|
+
steerItems: [],
|
|
283
|
+
enqueue,
|
|
284
|
+
steer: vi.fn(),
|
|
285
|
+
move: vi.fn(),
|
|
286
|
+
edit: vi.fn(),
|
|
287
|
+
remove: vi.fn(),
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
core.registerModelContextProvider({
|
|
291
|
+
getModelContext: () => ({ unstable_composerMetadata: live({ v: 1 }) }),
|
|
292
|
+
});
|
|
293
|
+
const thread = core.threads.getMainThreadRuntimeCore();
|
|
294
|
+
|
|
295
|
+
await thread.append(userMessage("queued", null));
|
|
296
|
+
expect(dispatched(enqueue)).toEqual([
|
|
297
|
+
{ id: "n1", name: "note", state: { v: 1 } },
|
|
298
|
+
]);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("gates a queued local send against the tail it flushes onto", async () => {
|
|
302
|
+
let composerMetadata: Record<string, unknown> = live({ v: 1 });
|
|
303
|
+
let releaseFirstRun!: () => void;
|
|
304
|
+
const firstRunGate = new Promise<void>((resolve) => {
|
|
305
|
+
releaseFirstRun = resolve;
|
|
306
|
+
});
|
|
307
|
+
let runs = 0;
|
|
308
|
+
const chatModel: ChatModelAdapter = {
|
|
309
|
+
run: async function* () {
|
|
310
|
+
if (runs++ === 0) await firstRunGate;
|
|
311
|
+
yield { content: [{ type: "text" as const, text: "ok" }] };
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
const core = new LocalRuntimeCore(
|
|
315
|
+
{ adapters: { chatModel }, unstable_enableMessageQueue: true },
|
|
316
|
+
undefined,
|
|
317
|
+
);
|
|
318
|
+
core.registerModelContextProvider({
|
|
319
|
+
getModelContext: () => ({ unstable_composerMetadata: composerMetadata }),
|
|
320
|
+
});
|
|
321
|
+
const thread = core.threads.getMainThreadRuntimeCore();
|
|
322
|
+
const settle = () => new Promise((resolve) => setTimeout(resolve, 20));
|
|
323
|
+
|
|
324
|
+
void thread.append(userMessage("first", null));
|
|
325
|
+
await settle();
|
|
326
|
+
|
|
327
|
+
// the first run is still open, so this one buffers with the live state at v:1
|
|
328
|
+
void thread.append(
|
|
329
|
+
userMessage("second", thread.messages.at(-1)?.id ?? null),
|
|
330
|
+
);
|
|
331
|
+
await settle();
|
|
332
|
+
expect(
|
|
333
|
+
thread.messages.some(
|
|
334
|
+
(m) => m.role === "user" && getThreadMessageText(m) === "second",
|
|
335
|
+
),
|
|
336
|
+
).toBe(false);
|
|
337
|
+
|
|
338
|
+
composerMetadata = live({ v: 2 });
|
|
339
|
+
releaseFirstRun();
|
|
340
|
+
await settle();
|
|
341
|
+
await settle();
|
|
342
|
+
|
|
343
|
+
const second = thread.messages.find(
|
|
344
|
+
(m) => m.role === "user" && getThreadMessageText(m) === "second",
|
|
345
|
+
);
|
|
346
|
+
expect(second!.metadata.custom?.interactables).toEqual([
|
|
347
|
+
{ id: "n1", name: "note", state: { v: 2 } },
|
|
348
|
+
]);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
@@ -330,6 +330,33 @@ describe("auiV0Encode", () => {
|
|
|
330
330
|
{ type: "data", name: "telemetry", data: { runs: 3 } },
|
|
331
331
|
]);
|
|
332
332
|
});
|
|
333
|
+
|
|
334
|
+
it("preserves data message parts verbatim in the core cloud encoder", () => {
|
|
335
|
+
const encoded = auiV0Encode({
|
|
336
|
+
id: "m1",
|
|
337
|
+
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
338
|
+
role: "assistant",
|
|
339
|
+
status: { type: "complete", reason: "stop" },
|
|
340
|
+
metadata: {
|
|
341
|
+
unstable_state: null,
|
|
342
|
+
unstable_annotations: [],
|
|
343
|
+
unstable_data: [],
|
|
344
|
+
steps: [],
|
|
345
|
+
custom: {},
|
|
346
|
+
},
|
|
347
|
+
content: [
|
|
348
|
+
{ type: "text", text: "planned" },
|
|
349
|
+
{ type: "data", name: "PredictState", data: { steps: ["a"] } },
|
|
350
|
+
{ type: "data", name: "PredictState", data: '{"steps":["a","b"]}' },
|
|
351
|
+
],
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
expect(encoded.content).toEqual([
|
|
355
|
+
{ type: "text", text: "planned" },
|
|
356
|
+
{ type: "data", name: "PredictState", data: { steps: ["a"] } },
|
|
357
|
+
{ type: "data", name: "PredictState", data: '{"steps":["a","b"]}' },
|
|
358
|
+
]);
|
|
359
|
+
});
|
|
333
360
|
});
|
|
334
361
|
|
|
335
362
|
describe("auiV0Decode", () => {
|
|
@@ -573,4 +600,43 @@ describe("auiV0Decode", () => {
|
|
|
573
600
|
const toolCall = message.content.find((p) => p.type === "tool-call");
|
|
574
601
|
expect(toolCall).toHaveProperty("result", false);
|
|
575
602
|
});
|
|
603
|
+
|
|
604
|
+
it("round-trips data message parts, keeping repeated names in order", () => {
|
|
605
|
+
const content = auiV0Encode({
|
|
606
|
+
id: "local",
|
|
607
|
+
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
608
|
+
role: "assistant",
|
|
609
|
+
status: { type: "complete", reason: "stop" },
|
|
610
|
+
metadata: {
|
|
611
|
+
unstable_state: null,
|
|
612
|
+
unstable_annotations: [],
|
|
613
|
+
unstable_data: [],
|
|
614
|
+
steps: [],
|
|
615
|
+
custom: {},
|
|
616
|
+
},
|
|
617
|
+
content: [
|
|
618
|
+
{ type: "text", text: "planned" },
|
|
619
|
+
{ type: "data", name: "PredictState", data: { steps: ["a"] } },
|
|
620
|
+
{ type: "data", name: "PredictState", data: '{"steps":["a","b"]}' },
|
|
621
|
+
],
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
const decoded = auiV0Decode({
|
|
625
|
+
id: "cloud",
|
|
626
|
+
parent_id: null,
|
|
627
|
+
height: 0,
|
|
628
|
+
created_at: new Date("2026-03-15T00:00:00.000Z"),
|
|
629
|
+
updated_at: new Date("2026-03-15T00:00:00.000Z"),
|
|
630
|
+
format: "aui/v0",
|
|
631
|
+
content: content as never,
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
if (decoded.message.role !== "assistant")
|
|
635
|
+
throw new Error("expected assistant");
|
|
636
|
+
expect(decoded.message.content).toEqual([
|
|
637
|
+
{ type: "text", text: "planned" },
|
|
638
|
+
{ type: "data", name: "PredictState", data: { steps: ["a"] } },
|
|
639
|
+
{ type: "data", name: "PredictState", data: '{"steps":["a","b"]}' },
|
|
640
|
+
]);
|
|
641
|
+
});
|
|
576
642
|
});
|