@assistant-ui/core 0.3.16 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/attachment.d.ts.map +1 -1
- package/dist/adapters/attachment.js +5 -4
- package/dist/adapters/attachment.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +4 -2
- package/dist/internal.js +4 -2
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +10 -4
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts +5 -0
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +101 -28
- package/dist/model-context/frame/provider.js.map +1 -1
- package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
- package/dist/model-context/interactable-composer-metadata.js +16 -9
- package/dist/model-context/interactable-composer-metadata.js.map +1 -1
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/registry.js +3 -5
- package/dist/model-context/registry.js.map +1 -1
- package/dist/model-context/tool-call-text.d.ts +26 -0
- package/dist/model-context/tool-call-text.d.ts.map +1 -0
- package/dist/model-context/tool-call-text.js +18 -0
- package/dist/model-context/tool-call-text.js.map +1 -0
- package/dist/model-context/types.d.ts.map +1 -1
- package/dist/model-context/types.js +5 -4
- package/dist/model-context/types.js.map +1 -1
- package/dist/react/RuntimeAdapter.js +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/AdaptedRemoteThread.js +1 -1
- package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
- package/dist/react/client/InMemoryThreadList.js +63 -57
- package/dist/react/client/InMemoryThreadList.js.map +1 -1
- package/dist/react/client/Interactables.d.ts.map +1 -1
- package/dist/react/client/Interactables.js +25 -28
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +16 -0
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
- package/dist/react/client/RemoteThreadList.js +354 -242
- package/dist/react/client/RemoteThreadList.js.map +1 -1
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +24 -18
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +2 -1
- package/dist/react/interactables-legacy/Interactables.js +246 -125
- package/dist/react/interactables-legacy/Interactables.js.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +11 -9
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -1
- package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
- package/dist/react/model-context/makeAssistantTool.js +1 -1
- package/dist/react/model-context/makeAssistantTool.js.map +1 -1
- package/dist/react/model-context/toolbox.d.ts +2 -14
- package/dist/react/model-context/toolbox.d.ts.map +1 -1
- package/dist/react/model-context/toolbox.js +1 -13
- package/dist/react/model-context/toolbox.js.map +1 -1
- package/dist/react/model-context/useAssistantContext.js +37 -7
- package/dist/react/model-context/useAssistantContext.js.map +1 -1
- package/dist/react/model-context/useAssistantTool.d.ts +2 -2
- package/dist/react/model-context/useAssistantTool.js +1 -1
- package/dist/react/model-context/useAssistantTool.js.map +1 -1
- package/dist/react/model-context/useAuiToolOverrides.js +31 -5
- package/dist/react/model-context/useAuiToolOverrides.js.map +1 -1
- package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
- package/dist/react/model-context/useInlineRender.js +10 -36
- package/dist/react/model-context/useInlineRender.js.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.js +2 -1
- package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
- package/dist/react/primitive-hooks/useMessageError.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useMessageError.js +2 -8
- package/dist/react/primitive-hooks/useMessageError.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.js +2 -4
- package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.js +4 -3
- package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.js +4 -3
- package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.js +7 -6
- package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.js +2 -2
- package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.js +3 -3
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.js +5 -4
- package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +6 -4
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +59 -29
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +11 -6
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +160 -143
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts +2 -6
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.js +15 -13
- package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
- package/dist/react/runtimes/assistant-transport/useLatestRef.js +2 -2
- package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +4 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +424 -52
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +5 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +29 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +160 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -0
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts +1 -9
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +16 -153
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +1 -1
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.js +75 -46
- package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.js +77 -29
- package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
- package/dist/react/types/MessagePartComponentTypes.d.ts +7 -3
- package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
- package/dist/react/types/scopes/tools.d.ts +2 -0
- package/dist/react/types/scopes/tools.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.d.ts +2 -2
- package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.js +1 -1
- package/dist/runtime/api/message-part-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts +7 -3
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.js +2 -2
- package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +12 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +23 -14
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +5 -1
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +1 -1
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +16 -12
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -2
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +8 -7
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts +12 -5
- package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +18 -3
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +15 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.d.ts +1 -1
- package/dist/runtime/utils/auto-status.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.js +6 -2
- package/dist/runtime/utils/auto-status.js.map +1 -1
- package/dist/runtime/utils/external-message-conversion.d.ts +3 -2
- package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
- package/dist/runtime/utils/external-message-conversion.js +5 -4
- package/dist/runtime/utils/external-message-conversion.js.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts +1 -0
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +15 -6
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtime/utils/resolveToolApprovalResponse.d.ts +6 -3
- package/dist/runtime/utils/resolveToolApprovalResponse.d.ts.map +1 -1
- package/dist/runtime/utils/resolveToolApprovalResponse.js +12 -3
- package/dist/runtime/utils/resolveToolApprovalResponse.js.map +1 -1
- package/dist/runtime/utils/thread-message-like.d.ts +2 -10
- package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.js +1 -1
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/runtime/utils/tool-call-tree.d.ts +39 -0
- package/dist/runtime/utils/tool-call-tree.d.ts.map +1 -0
- package/dist/runtime/utils/tool-call-tree.js +85 -0
- package/dist/runtime/utils/tool-call-tree.js.map +1 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts +29 -2
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +21 -27
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +2 -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 +34 -28
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -1
- package/dist/runtimes/internal.d.ts +2 -2
- package/dist/runtimes/internal.js +2 -2
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +3 -1
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +18 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.js +148 -43
- package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/title-generation.d.ts +49 -0
- package/dist/runtimes/remote-thread-list/title-generation.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/title-generation.js +197 -0
- package/dist/runtimes/remote-thread-list/title-generation.js.map +1 -0
- package/dist/runtimes/remote-thread-list/title.d.ts +11 -0
- package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/title.js +14 -0
- package/dist/runtimes/remote-thread-list/title.js.map +1 -0
- package/dist/runtimes/remote-thread-list/types.d.ts +16 -5
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +31 -8
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +97 -60
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/external-thread.d.ts +1 -1
- package/dist/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +30 -7
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/model-context-client.d.ts.map +1 -1
- package/dist/store/clients/model-context-client.js +2 -1
- package/dist/store/clients/model-context-client.js.map +1 -1
- package/dist/store/clients/single-thread-list.d.ts.map +1 -1
- package/dist/store/clients/single-thread-list.js +2 -1
- package/dist/store/clients/single-thread-list.js.map +1 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/suggestions.js +19 -6
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/clients/thread-message-client.js +1 -1
- package/dist/store/clients/thread-selection-events.js +1 -1
- package/dist/store/index.d.ts +2 -1
- package/dist/store/index.js +2 -1
- package/dist/store/internal.d.ts +2 -2
- package/dist/store/internal.js +2 -2
- package/dist/store/primitive-predicates.d.ts +4 -1
- package/dist/store/primitive-predicates.d.ts.map +1 -1
- package/dist/store/primitive-predicates.js +9 -1
- package/dist/store/primitive-predicates.js.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.js +98 -62
- package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.js +221 -144
- package/dist/store/runtime-clients/message-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +2 -2
- 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 +128 -107
- 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 +194 -122
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/useSubscribable.d.ts +3 -1
- package/dist/store/runtime-clients/useSubscribable.d.ts.map +1 -1
- package/dist/store/runtime-clients/useSubscribable.js +1 -1
- package/dist/store/runtime-clients/useSubscribable.js.map +1 -1
- package/dist/store/scopes/composer.d.ts +10 -2
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/message.d.ts +30 -1
- package/dist/store/scopes/message.d.ts.map +1 -1
- package/dist/store/scopes/part.d.ts +6 -3
- package/dist/store/scopes/part.d.ts.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +2 -2
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/dist/store/scopes/thread.d.ts +8 -0
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/store/scopes/threads.d.ts +1 -0
- package/dist/store/scopes/threads.d.ts.map +1 -1
- package/dist/subscribable/subscribable.d.ts +8 -1
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +24 -16
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/types/attachment.d.ts +2 -1
- package/dist/types/attachment.d.ts.map +1 -1
- package/dist/types/attachment.js +2 -1
- package/dist/types/attachment.js.map +1 -1
- package/dist/types/message.d.ts +40 -1
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js +7 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/abortable-iterable.d.ts +19 -0
- package/dist/utils/abortable-iterable.d.ts.map +1 -0
- package/dist/utils/abortable-iterable.js +72 -0
- package/dist/utils/abortable-iterable.js.map +1 -0
- package/dist/utils/composite-context-provider.d.ts.map +1 -1
- package/dist/utils/composite-context-provider.js +20 -2
- package/dist/utils/composite-context-provider.js.map +1 -1
- package/dist/utils/record.d.ts +11 -0
- package/dist/utils/record.d.ts.map +1 -0
- package/dist/utils/record.js +12 -0
- package/dist/utils/record.js.map +1 -0
- package/package.json +12 -17
- package/src/adapters/attachment.test.ts +50 -1
- package/src/adapters/attachment.ts +7 -4
- package/src/index.ts +7 -1
- package/src/internal.ts +12 -0
- package/src/model-context/frame/host.test.ts +24 -0
- package/src/model-context/frame/host.ts +10 -4
- package/src/model-context/frame/provider.test.ts +288 -1
- package/src/model-context/frame/provider.ts +148 -30
- package/src/model-context/interactable-composer-metadata.test.ts +28 -0
- package/src/model-context/interactable-composer-metadata.ts +9 -3
- package/src/model-context/registry.test.ts +12 -0
- package/src/model-context/registry.ts +3 -2
- package/src/model-context/tool-call-text.test.ts +67 -0
- package/src/model-context/tool-call-text.ts +67 -0
- package/src/model-context/types.test.ts +25 -0
- package/src/model-context/types.ts +9 -4
- package/src/react/AssistantRuntimeProvider.test.tsx +66 -2
- package/src/react/RuntimeAdapter.test.ts +34 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +1 -3
- package/src/react/client/InMemoryThreadList.ts +1 -0
- package/src/react/client/Interactables.test.ts +28 -0
- package/src/react/client/Interactables.ts +15 -13
- package/src/react/client/RemoteThreadList.background.test.ts +526 -0
- package/src/react/client/RemoteThreadList.concurrent.test.tsx +315 -0
- package/src/react/client/RemoteThreadList.test.ts +617 -3
- package/src/react/client/RemoteThreadList.ts +433 -167
- package/src/react/client/Tools.ts +29 -12
- package/src/react/index.ts +4 -0
- package/src/react/interactables-legacy/Interactables.ts +16 -16
- package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +9 -10
- package/src/react/model-context/makeAssistantTool.ts +2 -2
- package/src/react/model-context/modelContextHooks.test.tsx +131 -0
- package/src/react/model-context/toolbox.test.ts +9 -9
- package/src/react/model-context/toolbox.ts +9 -36
- package/src/react/model-context/useAssistantContext.ts +4 -2
- package/src/react/model-context/useAssistantTool.ts +2 -2
- package/src/react/model-context/useAuiToolOverrides.ts +4 -2
- package/src/react/model-context/useInlineRender.test.tsx +48 -0
- package/src/react/model-context/useInlineRender.ts +14 -10
- package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
- package/src/react/model-context/useToolArgsStatus.ts +2 -1
- package/src/react/primitive-hooks/useMessageError.ts +2 -19
- package/src/react/primitive-hooks/useThreadListLoadMore.ts +2 -3
- package/src/react/primitives/composer/ComposerAttachments.test.tsx +76 -0
- package/src/react/primitives/composer/ComposerAttachments.tsx +9 -4
- package/src/react/primitives/composer/ComposerQueue.test.tsx +72 -0
- package/src/react/primitives/composer/ComposerQueue.tsx +7 -4
- package/src/react/primitives/message/MessageAttachments.test.tsx +107 -37
- package/src/react/primitives/message/MessageAttachments.tsx +10 -7
- package/src/react/primitives/message/MessageGroupedParts.tsx +2 -2
- package/src/react/primitives/message/MessageParts.tsx +3 -3
- package/src/react/primitives/threadList/ThreadListItems.test.tsx +99 -0
- package/src/react/primitives/threadList/ThreadListItems.tsx +8 -5
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.destroy.test.tsx +172 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +127 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +7 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +99 -35
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.load-error.test.ts +132 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +274 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +223 -152
- package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
- package/src/react/runtimes/RemoteThreadResource.ts +20 -16
- package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +51 -2
- package/src/react/runtimes/assistant-transport/useLatestRef.ts +2 -2
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +45 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +546 -5
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +546 -103
- package/src/react/runtimes/cloud/auiV0.ts +5 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +103 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +237 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +90 -1
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +33 -238
- package/src/react/runtimes/external-message-converter.ts +1 -0
- package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +41 -0
- package/src/react/runtimes/useExternalStoreRuntime.ts +10 -4
- package/src/react/runtimes/useLocalRuntime.test.tsx +20 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.concurrent.test.tsx +216 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.load-error.test.tsx +108 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +57 -6
- package/src/react/types/MessagePartComponentTypes.ts +7 -3
- package/src/react/types/scopes/tools.ts +2 -0
- package/src/runtime/api/message-part-runtime.ts +3 -3
- package/src/runtime/api/message-runtime.test.ts +75 -0
- package/src/runtime/api/thread-list-item-runtime.ts +10 -3
- package/src/runtime/api/thread-list-runtime.ts +46 -12
- package/src/runtime/api/thread-runtime.test.ts +78 -0
- package/src/runtime/api/thread-runtime.ts +8 -1
- package/src/runtime/base/base-composer-runtime-core.ts +36 -8
- package/src/runtime/base/base-thread-runtime-core.test.ts +149 -4
- package/src/runtime/base/base-thread-runtime-core.ts +16 -8
- package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
- package/src/runtime/interfaces/thread-list-runtime-core.ts +25 -2
- package/src/runtime/interfaces/thread-runtime-core.ts +17 -1
- package/src/runtime/utils/auto-status.test.ts +57 -0
- package/src/runtime/utils/auto-status.ts +13 -1
- package/src/runtime/utils/external-message-conversion.test.ts +165 -0
- package/src/runtime/utils/external-message-conversion.ts +18 -2
- package/src/runtime/utils/message-repository.ts +29 -17
- package/src/runtime/utils/resolveToolApprovalResponse.test.ts +73 -0
- package/src/runtime/utils/resolveToolApprovalResponse.ts +27 -6
- package/src/runtime/utils/thread-message-like.ts +3 -11
- package/src/runtime/utils/tool-call-tree.test.ts +191 -0
- package/src/runtime/utils/tool-call-tree.ts +97 -0
- package/src/runtimes/external-store/external-store-adapter.ts +38 -2
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +18 -13
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +56 -33
- package/src/runtimes/inert/InertThreadRuntimeCore.ts +1 -1
- package/src/runtimes/internal.ts +1 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +29 -3
- package/src/runtimes/local/local-thread-runtime-core.ts +5 -1
- package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +238 -0
- package/src/runtimes/remote-thread-list/remote-thread-state.ts +223 -44
- package/src/runtimes/remote-thread-list/title-generation.test.ts +602 -0
- package/src/runtimes/remote-thread-list/title-generation.ts +329 -0
- package/src/runtimes/remote-thread-list/title.test.ts +62 -0
- package/src/runtimes/remote-thread-list/title.ts +16 -0
- package/src/runtimes/remote-thread-list/types.ts +16 -5
- package/src/runtimes/tool-invocations/EDGE_CASES.md +110 -5
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +750 -136
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +144 -91
- package/src/store/clients/external-thread.ts +62 -11
- package/src/store/clients/model-context-client.ts +5 -1
- package/src/store/clients/single-thread-list.ts +1 -0
- package/src/store/clients/suggestions.test.ts +195 -1
- package/src/store/clients/suggestions.ts +45 -34
- package/src/store/index.ts +4 -0
- package/src/store/internal.ts +2 -0
- package/src/store/primitive-predicates.ts +35 -0
- package/src/store/runtime-clients/composer-runtime-client.ts +42 -9
- package/src/store/runtime-clients/message-runtime-client.ts +54 -6
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +4 -2
- package/src/store/runtime-clients/thread-list-runtime-client.ts +17 -2
- package/src/store/runtime-clients/thread-runtime-client.ts +58 -10
- package/src/store/runtime-clients/useSubscribable.ts +8 -2
- package/src/store/scopes/composer.ts +16 -4
- package/src/store/scopes/message.ts +14 -0
- package/src/store/scopes/part.ts +6 -3
- package/src/store/scopes/thread-list-item.ts +5 -2
- package/src/store/scopes/thread.ts +4 -0
- package/src/store/scopes/threads.ts +1 -0
- package/src/subscribable/subscribable.test.ts +50 -0
- package/src/subscribable/subscribable.ts +33 -21
- package/src/tests/MessageRepository.test.ts +116 -0
- package/src/tests/OptimisticState-list-race.test.ts +1 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-initialize-adapter-change.test.ts +38 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +158 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +78 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +52 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +89 -0
- package/src/tests/attachment-adapters.test.ts +14 -0
- package/src/tests/base-composer-runtime-core.test.ts +39 -0
- package/src/tests/external-store-optimistic-id.test.ts +79 -0
- package/src/tests/external-store-repository-instance.test.ts +166 -0
- package/src/tests/external-store-thread-list-runtime-core.test.ts +83 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +49 -34
- package/src/tests/external-thread-attachments.test.tsx +224 -1
- package/src/tests/external-thread-parity.test.tsx +23 -0
- package/src/tests/remote-thread-list-adapter-switch.test.ts +66 -1
- package/src/tests/remote-thread-list-isLoading.test.ts +1 -0
- package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
- package/src/tests/thread-switch-events.test.tsx +475 -2
- package/src/tests/tools-scope-migration.test.tsx +28 -0
- package/src/types/attachment.ts +4 -0
- package/src/types/message.ts +50 -2
- package/src/utils/abortable-iterable.test.ts +213 -0
- package/src/utils/abortable-iterable.ts +93 -0
- package/src/utils/composite-context-provider.test.ts +25 -0
- package/src/utils/composite-context-provider.ts +23 -2
- package/src/utils/record.test.ts +48 -0
- package/src/utils/record.ts +11 -0
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
useMemo,
|
|
7
7
|
} from "react";
|
|
8
8
|
import { RenderChildrenWithAccessor, useAuiState } from "@assistant-ui/store";
|
|
9
|
+
import { useShallowSelector } from "@assistant-ui/store/internal";
|
|
9
10
|
import type { ThreadListItemState } from "../../../store/scopes/thread-list-item";
|
|
10
11
|
import { ThreadListItemByIndexProvider } from "../../providers/ThreadListItemByIndexProvider";
|
|
11
12
|
|
|
@@ -64,15 +65,17 @@ const ThreadListPrimitiveItemsInner: FC<{
|
|
|
64
65
|
archived: boolean;
|
|
65
66
|
children: (value: { threadListItem: ThreadListItemState }) => ReactNode;
|
|
66
67
|
}> = ({ archived, children }) => {
|
|
67
|
-
const
|
|
68
|
-
|
|
68
|
+
const threadIds = useAuiState(
|
|
69
|
+
useShallowSelector((s) =>
|
|
70
|
+
archived ? s.threads.archivedThreadIds : s.threads.threadIds,
|
|
71
|
+
),
|
|
69
72
|
);
|
|
70
73
|
|
|
71
74
|
return useMemo(
|
|
72
75
|
() =>
|
|
73
|
-
|
|
76
|
+
threadIds.map((threadId, index) => (
|
|
74
77
|
<ThreadListItemByIndexProvider
|
|
75
|
-
key={
|
|
78
|
+
key={threadId}
|
|
76
79
|
index={index}
|
|
77
80
|
archived={archived}
|
|
78
81
|
>
|
|
@@ -91,7 +94,7 @@ const ThreadListPrimitiveItemsInner: FC<{
|
|
|
91
94
|
</RenderChildrenWithAccessor>
|
|
92
95
|
</ThreadListItemByIndexProvider>
|
|
93
96
|
)),
|
|
94
|
-
[
|
|
97
|
+
[threadIds, archived, children],
|
|
95
98
|
);
|
|
96
99
|
};
|
|
97
100
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import type { ThreadListRuntimeCore } from "../../runtime/interfaces/thread-list-runtime-core";
|
|
3
|
+
import type { ThreadRuntimeCore } from "../../runtime/interfaces/thread-runtime-core";
|
|
4
|
+
import { RemoteThreadListHookInstanceManager } from "./RemoteThreadListHookInstanceManager";
|
|
5
|
+
|
|
6
|
+
const makeManager = () =>
|
|
7
|
+
new RemoteThreadListHookInstanceManager(
|
|
8
|
+
() => ({}) as never,
|
|
9
|
+
{} as ThreadListRuntimeCore,
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
// No AdapterSink attaches a runtime here, so the start and restart promises
|
|
13
|
+
// stay pending or reject on stop; neither is what these tests are about.
|
|
14
|
+
const start = (manager: RemoteThreadListHookInstanceManager, id: string) => {
|
|
15
|
+
manager.startThreadRuntime(id).catch(() => {});
|
|
16
|
+
};
|
|
17
|
+
const restart = (manager: RemoteThreadListHookInstanceManager, id: string) => {
|
|
18
|
+
manager.__internal_restartThreadRuntime(id).catch(() => {});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const publishedSignal = (
|
|
22
|
+
manager: RemoteThreadListHookInstanceManager,
|
|
23
|
+
id: string,
|
|
24
|
+
) => {
|
|
25
|
+
const { hostStore } = manager as unknown as {
|
|
26
|
+
hostStore: {
|
|
27
|
+
getState: () => {
|
|
28
|
+
threads: readonly { id: string; destroySignal: AbortSignal }[];
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
return hostStore.getState().threads.find((thread) => thread.id === id)
|
|
33
|
+
?.destroySignal;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
describe("RemoteThreadListHookInstanceManager destroy signal", () => {
|
|
37
|
+
it("publishes a live signal for each started thread", () => {
|
|
38
|
+
const manager = makeManager();
|
|
39
|
+
start(manager, "thread-1");
|
|
40
|
+
|
|
41
|
+
expect(publishedSignal(manager, "thread-1")?.aborted).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("aborts the thread's signal when its runtime stops", () => {
|
|
45
|
+
const manager = makeManager();
|
|
46
|
+
start(manager, "thread-1");
|
|
47
|
+
const signal = publishedSignal(manager, "thread-1")!;
|
|
48
|
+
|
|
49
|
+
manager.stopThreadRuntime("thread-1");
|
|
50
|
+
|
|
51
|
+
expect(signal.aborted).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("leaves sibling threads untouched when one stops", () => {
|
|
55
|
+
const manager = makeManager();
|
|
56
|
+
start(manager, "thread-1");
|
|
57
|
+
start(manager, "thread-2");
|
|
58
|
+
const sibling = publishedSignal(manager, "thread-2")!;
|
|
59
|
+
|
|
60
|
+
manager.stopThreadRuntime("thread-1");
|
|
61
|
+
|
|
62
|
+
expect(sibling.aborted).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("hands the next generation a fresh signal on restart", () => {
|
|
66
|
+
const manager = makeManager();
|
|
67
|
+
start(manager, "thread-1");
|
|
68
|
+
const first = publishedSignal(manager, "thread-1")!;
|
|
69
|
+
|
|
70
|
+
restart(manager, "thread-1");
|
|
71
|
+
const second = publishedSignal(manager, "thread-1")!;
|
|
72
|
+
|
|
73
|
+
expect(first.aborted).toBe(true);
|
|
74
|
+
expect(second).not.toBe(first);
|
|
75
|
+
expect(second.aborted).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("aborts every thread when the manager is disposed", () => {
|
|
79
|
+
const manager = makeManager();
|
|
80
|
+
start(manager, "thread-1");
|
|
81
|
+
start(manager, "thread-2");
|
|
82
|
+
const signals = [
|
|
83
|
+
publishedSignal(manager, "thread-1")!,
|
|
84
|
+
publishedSignal(manager, "thread-2")!,
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
manager.__internal_dispose();
|
|
88
|
+
|
|
89
|
+
expect(signals.map((signal) => signal.aborted)).toEqual([true, true]);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const makeRunningRuntime = () => {
|
|
94
|
+
const subscribers = new Set<() => void>();
|
|
95
|
+
const eventListeners = new Map<string, Set<() => void>>();
|
|
96
|
+
const runtime = {
|
|
97
|
+
isRunning: true,
|
|
98
|
+
messages: [],
|
|
99
|
+
subscribe: (callback: () => void) => {
|
|
100
|
+
subscribers.add(callback);
|
|
101
|
+
return () => subscribers.delete(callback);
|
|
102
|
+
},
|
|
103
|
+
unstable_on: (event: string, callback: () => void) => {
|
|
104
|
+
let listeners = eventListeners.get(event);
|
|
105
|
+
if (!listeners) {
|
|
106
|
+
listeners = new Set();
|
|
107
|
+
eventListeners.set(event, listeners);
|
|
108
|
+
}
|
|
109
|
+
listeners.add(callback);
|
|
110
|
+
return () => listeners.delete(callback);
|
|
111
|
+
},
|
|
112
|
+
} as unknown as ThreadRuntimeCore & { isRunning: boolean };
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
runtime,
|
|
116
|
+
// what a stopOnClientDestroy consumer does when the destroy signal fires
|
|
117
|
+
stop: () => {
|
|
118
|
+
runtime.isRunning = false;
|
|
119
|
+
for (const callback of eventListeners.get("runEnd") ?? []) callback();
|
|
120
|
+
for (const callback of subscribers) callback();
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const publish = (
|
|
126
|
+
manager: RemoteThreadListHookInstanceManager,
|
|
127
|
+
threadId: string,
|
|
128
|
+
runtime: ThreadRuntimeCore,
|
|
129
|
+
) => {
|
|
130
|
+
const internals = manager as unknown as {
|
|
131
|
+
instances: Map<string, { generation: number }>;
|
|
132
|
+
_publishThreadRuntime: (
|
|
133
|
+
threadId: string,
|
|
134
|
+
runtime: ThreadRuntimeCore,
|
|
135
|
+
generation: number,
|
|
136
|
+
) => void;
|
|
137
|
+
};
|
|
138
|
+
internals._publishThreadRuntime(
|
|
139
|
+
threadId,
|
|
140
|
+
runtime,
|
|
141
|
+
internals.instances.get(threadId)!.generation,
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
describe("RemoteThreadListHookInstanceManager restart teardown", () => {
|
|
146
|
+
it("keeps the outgoing generation's terminal events off the thread's subscribers", () => {
|
|
147
|
+
const manager = makeManager();
|
|
148
|
+
start(manager, "thread-1");
|
|
149
|
+
const { runtime, stop } = makeRunningRuntime();
|
|
150
|
+
publish(manager, "thread-1", runtime);
|
|
151
|
+
|
|
152
|
+
const signal = publishedSignal(manager, "thread-1")!;
|
|
153
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
154
|
+
|
|
155
|
+
const events: string[] = [];
|
|
156
|
+
manager.__internal_subscribeThreadEvents((event) =>
|
|
157
|
+
events.push(event.type),
|
|
158
|
+
);
|
|
159
|
+
const runningChanges: boolean[] = [];
|
|
160
|
+
manager.__internal_subscribeRunningChanged(() =>
|
|
161
|
+
runningChanges.push(manager.__internal_isThreadRunning("thread-1")),
|
|
162
|
+
);
|
|
163
|
+
expect(manager.__internal_isThreadRunning("thread-1")).toBe(true);
|
|
164
|
+
|
|
165
|
+
restart(manager, "thread-1");
|
|
166
|
+
|
|
167
|
+
expect(signal.aborted).toBe(true);
|
|
168
|
+
expect(events).toEqual([]);
|
|
169
|
+
expect(runningChanges).toEqual([]);
|
|
170
|
+
expect(manager.__internal_isThreadRunning("thread-1")).toBe(true);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
@@ -5,9 +5,12 @@ import type { ThreadMessage } from "../../types/message";
|
|
|
5
5
|
import { RemoteThreadListHookInstanceManager } from "./RemoteThreadListHookInstanceManager";
|
|
6
6
|
|
|
7
7
|
const makeRuntime = (
|
|
8
|
-
initial: Partial<Pick<ThreadRuntimeCore, "isRunning" | "messages">>
|
|
8
|
+
initial: Partial<Pick<ThreadRuntimeCore, "isRunning" | "messages">> & {
|
|
9
|
+
initialized?: boolean;
|
|
10
|
+
} = {},
|
|
9
11
|
) => {
|
|
10
12
|
const subscribers = new Set<() => void>();
|
|
13
|
+
const eventListeners = new Map<string, Set<() => void>>();
|
|
11
14
|
const runtime = {
|
|
12
15
|
isRunning: initial.isRunning,
|
|
13
16
|
messages: initial.messages ?? [],
|
|
@@ -15,6 +18,23 @@ const makeRuntime = (
|
|
|
15
18
|
subscribers.add(callback);
|
|
16
19
|
return () => subscribers.delete(callback);
|
|
17
20
|
},
|
|
21
|
+
unstable_on: (event: string, callback: () => void) => {
|
|
22
|
+
let listeners = eventListeners.get(event);
|
|
23
|
+
if (!listeners) {
|
|
24
|
+
listeners = new Set();
|
|
25
|
+
eventListeners.set(event, listeners);
|
|
26
|
+
}
|
|
27
|
+
listeners.add(callback);
|
|
28
|
+
// mirrors the real core: initialize latches, so a subscriber that
|
|
29
|
+
// attaches after initialization gets a deferred replay
|
|
30
|
+
if (event === "initialize" && initial.initialized) {
|
|
31
|
+
const latched = listeners;
|
|
32
|
+
queueMicrotask(() => {
|
|
33
|
+
if (latched.has(callback)) callback();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return () => listeners.delete(callback);
|
|
37
|
+
},
|
|
18
38
|
} as unknown as ThreadRuntimeCore & {
|
|
19
39
|
isRunning: boolean | undefined;
|
|
20
40
|
messages: readonly ThreadMessage[];
|
|
@@ -23,6 +43,14 @@ const makeRuntime = (
|
|
|
23
43
|
return {
|
|
24
44
|
runtime,
|
|
25
45
|
subscriberCount: () => subscribers.size,
|
|
46
|
+
eventListenerCount: () =>
|
|
47
|
+
[...eventListeners.values()].reduce(
|
|
48
|
+
(total, listeners) => total + listeners.size,
|
|
49
|
+
0,
|
|
50
|
+
),
|
|
51
|
+
emit: (event: string) => {
|
|
52
|
+
for (const callback of eventListeners.get(event) ?? []) callback();
|
|
53
|
+
},
|
|
26
54
|
setRunning: (isRunning: boolean | undefined) => {
|
|
27
55
|
runtime.isRunning = isRunning;
|
|
28
56
|
for (const callback of subscribers) callback();
|
|
@@ -127,6 +155,39 @@ describe("RemoteThreadListHookInstanceManager run tracking", () => {
|
|
|
127
155
|
expect(onChange).toHaveBeenCalledTimes(2);
|
|
128
156
|
});
|
|
129
157
|
|
|
158
|
+
it("notifies every running subscriber when one throws", () => {
|
|
159
|
+
const manager = makeManager();
|
|
160
|
+
start(manager, "thread-1");
|
|
161
|
+
const thread = makeRuntime({ isRunning: false });
|
|
162
|
+
publish(manager, "thread-1", thread.runtime);
|
|
163
|
+
const error = new Error("listener failed");
|
|
164
|
+
manager.__internal_subscribeRunningChanged(() => {
|
|
165
|
+
throw error;
|
|
166
|
+
});
|
|
167
|
+
const laterSubscriber = vi.fn();
|
|
168
|
+
manager.__internal_subscribeRunningChanged(laterSubscriber);
|
|
169
|
+
|
|
170
|
+
expect(() => thread.setRunning(true)).toThrow(error);
|
|
171
|
+
expect(laterSubscriber).toHaveBeenCalledOnce();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("notifies every replacement subscriber when one throws", () => {
|
|
175
|
+
const manager = makeManager();
|
|
176
|
+
start(manager, "thread-1");
|
|
177
|
+
publish(manager, "thread-1", makeRuntime().runtime);
|
|
178
|
+
const error = new Error("listener failed");
|
|
179
|
+
manager.__internal_subscribeRuntimeReplaced(() => {
|
|
180
|
+
throw error;
|
|
181
|
+
});
|
|
182
|
+
const laterSubscriber = vi.fn();
|
|
183
|
+
manager.__internal_subscribeRuntimeReplaced(laterSubscriber);
|
|
184
|
+
|
|
185
|
+
expect(() => publish(manager, "thread-1", makeRuntime().runtime)).toThrow(
|
|
186
|
+
error,
|
|
187
|
+
);
|
|
188
|
+
expect(laterSubscriber).toHaveBeenCalledOnce();
|
|
189
|
+
});
|
|
190
|
+
|
|
130
191
|
it("moves tracking to the runtime a restart publishes", () => {
|
|
131
192
|
const manager = makeManager();
|
|
132
193
|
start(manager, "thread-1");
|
|
@@ -152,6 +213,71 @@ describe("RemoteThreadListHookInstanceManager run tracking", () => {
|
|
|
152
213
|
manager.stopThreadRuntime("thread-1");
|
|
153
214
|
|
|
154
215
|
expect(thread.subscriberCount()).toBe(0);
|
|
216
|
+
expect(thread.eventListenerCount()).toBe(0);
|
|
155
217
|
expect(manager.__internal_isThreadRunning("thread-1")).toBe(false);
|
|
156
218
|
});
|
|
219
|
+
|
|
220
|
+
it("forwards every lifecycle event from every tracked thread with its thread id", () => {
|
|
221
|
+
const manager = makeManager();
|
|
222
|
+
const events: unknown[] = [];
|
|
223
|
+
manager.__internal_subscribeThreadEvents((event) => events.push(event));
|
|
224
|
+
|
|
225
|
+
start(manager, "thread-1");
|
|
226
|
+
start(manager, "thread-2");
|
|
227
|
+
const first = makeRuntime();
|
|
228
|
+
const second = makeRuntime();
|
|
229
|
+
publish(manager, "thread-1", first.runtime);
|
|
230
|
+
publish(manager, "thread-2", second.runtime);
|
|
231
|
+
|
|
232
|
+
second.emit("runStart");
|
|
233
|
+
first.emit("runEnd");
|
|
234
|
+
first.emit("initialize");
|
|
235
|
+
second.emit("modelContextUpdate");
|
|
236
|
+
|
|
237
|
+
expect(events).toEqual([
|
|
238
|
+
{ threadId: "thread-2", type: "runStart" },
|
|
239
|
+
{ threadId: "thread-1", type: "runEnd" },
|
|
240
|
+
{ threadId: "thread-1", type: "initialize" },
|
|
241
|
+
{ threadId: "thread-2", type: "modelContextUpdate" },
|
|
242
|
+
]);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("replays a latched initialize from the surviving runtime after a restart", async () => {
|
|
246
|
+
const manager = makeManager();
|
|
247
|
+
const events: unknown[] = [];
|
|
248
|
+
manager.__internal_subscribeThreadEvents((event) => events.push(event));
|
|
249
|
+
|
|
250
|
+
start(manager, "thread-1");
|
|
251
|
+
const before = makeRuntime({ initialized: true });
|
|
252
|
+
publish(manager, "thread-1", before.runtime);
|
|
253
|
+
const after = makeRuntime({ initialized: true });
|
|
254
|
+
publish(manager, "thread-1", after.runtime);
|
|
255
|
+
await new Promise<void>((resolve) => queueMicrotask(resolve));
|
|
256
|
+
|
|
257
|
+
expect(before.eventListenerCount()).toBe(0);
|
|
258
|
+
expect(events).toEqual([{ threadId: "thread-1", type: "initialize" }]);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("stops forwarding lifecycle events from a runtime a restart replaced", () => {
|
|
262
|
+
const manager = makeManager();
|
|
263
|
+
const events: unknown[] = [];
|
|
264
|
+
manager.__internal_subscribeThreadEvents((event) => events.push(event));
|
|
265
|
+
|
|
266
|
+
start(manager, "thread-1");
|
|
267
|
+
const before = makeRuntime();
|
|
268
|
+
publish(manager, "thread-1", before.runtime);
|
|
269
|
+
const after = makeRuntime();
|
|
270
|
+
publish(manager, "thread-1", after.runtime);
|
|
271
|
+
|
|
272
|
+
before.emit("runEnd");
|
|
273
|
+
before.emit("initialize");
|
|
274
|
+
after.emit("runEnd");
|
|
275
|
+
after.emit("modelContextUpdate");
|
|
276
|
+
|
|
277
|
+
expect(before.eventListenerCount()).toBe(0);
|
|
278
|
+
expect(events).toEqual([
|
|
279
|
+
{ threadId: "thread-1", type: "runEnd" },
|
|
280
|
+
{ threadId: "thread-1", type: "modelContextUpdate" },
|
|
281
|
+
]);
|
|
282
|
+
});
|
|
157
283
|
});
|
|
@@ -37,13 +37,19 @@ describe("RemoteThreadListHookInstanceManager", () => {
|
|
|
37
37
|
const internals = manager as unknown as {
|
|
38
38
|
instances: Map<
|
|
39
39
|
string,
|
|
40
|
-
{
|
|
40
|
+
{
|
|
41
|
+
runtime: typeof runtime;
|
|
42
|
+
generation: number;
|
|
43
|
+
isRunning: boolean;
|
|
44
|
+
destroy: AbortController;
|
|
45
|
+
}
|
|
41
46
|
>;
|
|
42
47
|
};
|
|
43
48
|
internals.instances.set("thread-1", {
|
|
44
49
|
runtime,
|
|
45
50
|
generation: 0,
|
|
46
51
|
isRunning: false,
|
|
52
|
+
destroy: new AbortController(),
|
|
47
53
|
});
|
|
48
54
|
|
|
49
55
|
const appendPromise = runtime.append({
|
|
@@ -10,17 +10,28 @@ import {
|
|
|
10
10
|
type ComponentType,
|
|
11
11
|
Fragment,
|
|
12
12
|
} from "react";
|
|
13
|
-
import { create } from "zustand";
|
|
14
13
|
import { useResources, withKey } from "@assistant-ui/tap";
|
|
15
14
|
import type { AssistantClient } from "@assistant-ui/store";
|
|
16
15
|
import { ThreadListItemRuntimeProvider } from "../providers/ThreadListItemRuntimeProvider";
|
|
17
|
-
import type {
|
|
18
|
-
|
|
16
|
+
import type {
|
|
17
|
+
ThreadRuntimeCore,
|
|
18
|
+
ThreadRuntimeEventType,
|
|
19
|
+
} from "../../runtime/interfaces/thread-runtime-core";
|
|
20
|
+
import type {
|
|
21
|
+
ThreadListRuntimeCore,
|
|
22
|
+
ThreadListRuntimeEvent,
|
|
23
|
+
} from "../../runtime/interfaces/thread-list-runtime-core";
|
|
19
24
|
import type { Unsubscribe } from "../../types/unsubscribe";
|
|
20
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
BaseSubscribable,
|
|
27
|
+
notifySubscribers,
|
|
28
|
+
WritableSubscribable,
|
|
29
|
+
} from "../../subscribable/subscribable";
|
|
30
|
+
import { useSubscribable } from "../../store/runtime-clients/useSubscribable";
|
|
21
31
|
import { getThreadRuntimeCoreIsRunning } from "../../runtime/api/thread-runtime";
|
|
22
32
|
import { ThreadListRuntimeImpl } from "../../runtime/api/thread-list-runtime";
|
|
23
33
|
import { invalidateThreadRuntime } from "../../runtime/utils/thread-runtime-lifecycle";
|
|
34
|
+
import { notifyEventListeners } from "../../utils/notify-event-listeners";
|
|
24
35
|
import {
|
|
25
36
|
useRuntimeAdapters,
|
|
26
37
|
type RuntimeAdapters,
|
|
@@ -30,12 +41,22 @@ import {
|
|
|
30
41
|
type RemoteThreadListHook,
|
|
31
42
|
} from "./RemoteThreadResource";
|
|
32
43
|
|
|
44
|
+
const THREAD_EVENTS = [
|
|
45
|
+
"runStart",
|
|
46
|
+
"runEnd",
|
|
47
|
+
"initialize",
|
|
48
|
+
"modelContextUpdate",
|
|
49
|
+
] as const satisfies readonly ThreadRuntimeEventType[];
|
|
50
|
+
|
|
33
51
|
type RemoteThreadListHookInstance = {
|
|
34
52
|
runtime?: ThreadRuntimeCore | undefined;
|
|
35
53
|
publishedGeneration?: number | undefined;
|
|
36
54
|
generation: number;
|
|
37
55
|
isRunning: boolean;
|
|
38
56
|
unsubscribeRunning?: Unsubscribe | undefined;
|
|
57
|
+
// Permanent teardown of the thread's runtime, aborted when the thread is
|
|
58
|
+
// stopped or its runtime restarted. A soft unmount leaves it armed.
|
|
59
|
+
destroy: AbortController;
|
|
39
60
|
};
|
|
40
61
|
|
|
41
62
|
type AdapterSnapshot = {
|
|
@@ -44,7 +65,11 @@ type AdapterSnapshot = {
|
|
|
44
65
|
};
|
|
45
66
|
|
|
46
67
|
type HostSnapshot = {
|
|
47
|
-
threads: readonly {
|
|
68
|
+
threads: readonly {
|
|
69
|
+
id: string;
|
|
70
|
+
generation: number;
|
|
71
|
+
destroySignal: AbortSignal;
|
|
72
|
+
}[];
|
|
48
73
|
hookEpoch: number;
|
|
49
74
|
};
|
|
50
75
|
|
|
@@ -59,14 +84,14 @@ const ProviderRenderDetector: FC<{
|
|
|
59
84
|
|
|
60
85
|
export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
61
86
|
private runtimeHook: RemoteThreadListHook;
|
|
62
|
-
private readonly adapterStore =
|
|
87
|
+
private readonly adapterStore = new WritableSubscribable<AdapterSnapshot>({
|
|
63
88
|
defaultAdapters: null,
|
|
64
89
|
threadAdapters: new Map(),
|
|
65
|
-
})
|
|
66
|
-
private readonly hostStore =
|
|
90
|
+
});
|
|
91
|
+
private readonly hostStore = new WritableSubscribable<HostSnapshot>({
|
|
67
92
|
threads: [],
|
|
68
93
|
hookEpoch: 0,
|
|
69
|
-
})
|
|
94
|
+
});
|
|
70
95
|
private readonly pendingThreadAdapters = new Map<
|
|
71
96
|
string,
|
|
72
97
|
RuntimeAdapters | null
|
|
@@ -112,6 +137,7 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
112
137
|
this.instances.set(threadId, {
|
|
113
138
|
generation,
|
|
114
139
|
isRunning: false,
|
|
140
|
+
destroy: new AbortController(),
|
|
115
141
|
});
|
|
116
142
|
this._syncHostThreads();
|
|
117
143
|
}
|
|
@@ -124,6 +150,14 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
124
150
|
if (!instance) return this.startThreadRuntime(threadId);
|
|
125
151
|
|
|
126
152
|
if (instance.runtime) invalidateThreadRuntime(instance.runtime);
|
|
153
|
+
// Detach before aborting, as stopThreadRuntime does: the abort runs the
|
|
154
|
+
// destroy listeners synchronously, and a listener that stops the outgoing
|
|
155
|
+
// runtime would otherwise emit that generation's terminal events through
|
|
156
|
+
// the subscription the next generation is about to reuse.
|
|
157
|
+
instance.unsubscribeRunning?.();
|
|
158
|
+
instance.unsubscribeRunning = undefined;
|
|
159
|
+
instance.destroy.abort();
|
|
160
|
+
instance.destroy = new AbortController();
|
|
127
161
|
instance.generation = this.nextGeneration++;
|
|
128
162
|
this._syncHostThreads();
|
|
129
163
|
this._notifySubscribers();
|
|
@@ -148,6 +182,17 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
148
182
|
return () => this.runningSubscribers.delete(callback);
|
|
149
183
|
}
|
|
150
184
|
|
|
185
|
+
private threadEventSubscribers = new Set<
|
|
186
|
+
(event: ThreadListRuntimeEvent) => void
|
|
187
|
+
>();
|
|
188
|
+
|
|
189
|
+
public __internal_subscribeThreadEvents(
|
|
190
|
+
callback: (event: ThreadListRuntimeEvent) => void,
|
|
191
|
+
): Unsubscribe {
|
|
192
|
+
this.threadEventSubscribers.add(callback);
|
|
193
|
+
return () => this.threadEventSubscribers.delete(callback);
|
|
194
|
+
}
|
|
195
|
+
|
|
151
196
|
private _publish = (
|
|
152
197
|
threadId: string,
|
|
153
198
|
runtime: ThreadRuntimeCore,
|
|
@@ -170,11 +215,11 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
170
215
|
instance.runtime = runtime;
|
|
171
216
|
instance.publishedGeneration = generation;
|
|
172
217
|
if (previousRuntime !== runtime) {
|
|
173
|
-
this._trackRunning(instance);
|
|
218
|
+
this._trackRunning(threadId, instance);
|
|
174
219
|
}
|
|
175
220
|
this._notifySubscribers();
|
|
176
221
|
if (previousRuntime !== undefined && previousRuntime !== runtime) {
|
|
177
|
-
|
|
222
|
+
notifySubscribers(this.replacedSubscribers);
|
|
178
223
|
}
|
|
179
224
|
}
|
|
180
225
|
|
|
@@ -187,7 +232,10 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
187
232
|
return () => this.replacedSubscribers.delete(callback);
|
|
188
233
|
}
|
|
189
234
|
|
|
190
|
-
private _trackRunning(
|
|
235
|
+
private _trackRunning(
|
|
236
|
+
threadId: string,
|
|
237
|
+
instance: RemoteThreadListHookInstance,
|
|
238
|
+
) {
|
|
191
239
|
instance.unsubscribeRunning?.();
|
|
192
240
|
|
|
193
241
|
const runtime = instance.runtime;
|
|
@@ -198,9 +246,23 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
198
246
|
}
|
|
199
247
|
|
|
200
248
|
this._setRunning(instance, getThreadRuntimeCoreIsRunning(runtime));
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
249
|
+
const unsubscribers = [
|
|
250
|
+
runtime.subscribe(() => {
|
|
251
|
+
this._setRunning(instance, getThreadRuntimeCoreIsRunning(runtime));
|
|
252
|
+
}),
|
|
253
|
+
...THREAD_EVENTS.map((type) =>
|
|
254
|
+
runtime.unstable_on(type, () => {
|
|
255
|
+
notifyEventListeners(
|
|
256
|
+
this.threadEventSubscribers,
|
|
257
|
+
{ threadId, type },
|
|
258
|
+
`Thread event "${type}"`,
|
|
259
|
+
);
|
|
260
|
+
}),
|
|
261
|
+
),
|
|
262
|
+
];
|
|
263
|
+
instance.unsubscribeRunning = () => {
|
|
264
|
+
for (const unsubscribe of unsubscribers) unsubscribe();
|
|
265
|
+
};
|
|
204
266
|
}
|
|
205
267
|
|
|
206
268
|
private _setRunning(
|
|
@@ -209,13 +271,14 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
209
271
|
) {
|
|
210
272
|
if (instance.isRunning === isRunning) return;
|
|
211
273
|
instance.isRunning = isRunning;
|
|
212
|
-
|
|
274
|
+
notifySubscribers(this.runningSubscribers);
|
|
213
275
|
}
|
|
214
276
|
|
|
215
277
|
public stopThreadRuntime(threadId: string) {
|
|
216
278
|
const instance = this.instances.get(threadId);
|
|
217
279
|
if (instance?.runtime) invalidateThreadRuntime(instance.runtime);
|
|
218
280
|
instance?.unsubscribeRunning?.();
|
|
281
|
+
instance?.destroy.abort();
|
|
219
282
|
this.instances.delete(threadId);
|
|
220
283
|
this.pendingThreadAdapters.delete(threadId);
|
|
221
284
|
this._syncHostThreads();
|
|
@@ -225,16 +288,14 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
225
288
|
public setRuntimeHook(newRuntimeHook: RemoteThreadListHook) {
|
|
226
289
|
if (this.runtimeHook === newRuntimeHook) return;
|
|
227
290
|
this.runtimeHook = newRuntimeHook;
|
|
228
|
-
this.hostStore.
|
|
229
|
-
|
|
230
|
-
true,
|
|
231
|
-
);
|
|
291
|
+
const host = this.hostStore.getState();
|
|
292
|
+
this.hostStore.setState({ ...host, hookEpoch: host.hookEpoch + 1 });
|
|
232
293
|
}
|
|
233
294
|
|
|
234
295
|
public __internal_setDefaultAdapters(adapters: RuntimeAdapters | null) {
|
|
235
296
|
const current = this.adapterStore.getState();
|
|
236
297
|
if (current.defaultAdapters === adapters) return;
|
|
237
|
-
this.adapterStore.setState({ ...current, defaultAdapters: adapters }
|
|
298
|
+
this.adapterStore.setState({ ...current, defaultAdapters: adapters });
|
|
238
299
|
}
|
|
239
300
|
|
|
240
301
|
public __internal_setThreadAdapters(
|
|
@@ -245,7 +306,7 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
245
306
|
const next = new Map(current.threadAdapters);
|
|
246
307
|
if (adapters === null) next.delete(threadId);
|
|
247
308
|
else next.set(threadId, adapters);
|
|
248
|
-
this.adapterStore.setState({ ...current, threadAdapters: next }
|
|
309
|
+
this.adapterStore.setState({ ...current, threadAdapters: next });
|
|
249
310
|
}
|
|
250
311
|
|
|
251
312
|
public __internal_dispose() {
|
|
@@ -255,23 +316,25 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
255
316
|
}
|
|
256
317
|
|
|
257
318
|
private _syncHostThreads() {
|
|
258
|
-
this.hostStore.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
319
|
+
const host = this.hostStore.getState();
|
|
320
|
+
this.hostStore.setState({
|
|
321
|
+
...host,
|
|
322
|
+
threads: Array.from(this.instances.entries()).map(
|
|
323
|
+
([id, { generation, destroy }]) => ({
|
|
324
|
+
id,
|
|
325
|
+
generation,
|
|
326
|
+
destroySignal: destroy.signal,
|
|
327
|
+
}),
|
|
328
|
+
),
|
|
329
|
+
});
|
|
267
330
|
}
|
|
268
331
|
|
|
269
332
|
public __internal_useHost(parentClient: AssistantClient) {
|
|
270
|
-
const { threads, hookEpoch } = this.hostStore
|
|
271
|
-
const adapters = this.adapterStore
|
|
333
|
+
const { threads, hookEpoch } = useSubscribable(this.hostStore);
|
|
334
|
+
const adapters = useSubscribable(this.adapterStore);
|
|
272
335
|
const runtimeHook = this.runtimeHook;
|
|
273
336
|
return useResources(
|
|
274
|
-
threads.map(({ id, generation }) => {
|
|
337
|
+
threads.map(({ id, generation, destroySignal }) => {
|
|
275
338
|
const threadAdapters = this.pendingThreadAdapters.has(id)
|
|
276
339
|
? this.pendingThreadAdapters.get(id)!
|
|
277
340
|
: (adapters.threadAdapters.get(id) ?? adapters.defaultAdapters);
|
|
@@ -285,6 +348,7 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
285
348
|
parentClient,
|
|
286
349
|
adapters: threadAdapters,
|
|
287
350
|
publish: this._publish,
|
|
351
|
+
destroySignal,
|
|
288
352
|
}),
|
|
289
353
|
);
|
|
290
354
|
}),
|
|
@@ -294,7 +358,7 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
294
358
|
public __internal_RenderThreadRuntimes: FC<{
|
|
295
359
|
provider: ComponentType<PropsWithChildren>;
|
|
296
360
|
}> = ({ provider }) => {
|
|
297
|
-
this.hostStore
|
|
361
|
+
useSubscribable(this.hostStore);
|
|
298
362
|
|
|
299
363
|
return Array.from(this.instances.entries()).map(
|
|
300
364
|
([threadId, { generation }]) => (
|