@assistant-ui/core 0.3.16 → 0.3.17
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/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +2 -1
- package/dist/internal.js +2 -1
- package/dist/model-context/frame/provider.d.ts +3 -0
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +71 -21
- package/dist/model-context/frame/provider.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/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.js +1 -1
- package/dist/react/client/Interactables.js +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +15 -0
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
- package/dist/react/client/RemoteThreadList.js +240 -138
- 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 +6 -2
- 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 +4 -4
- package/dist/react/interactables-legacy/Interactables.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/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/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 +44 -22
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +6 -5
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +79 -62
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts +1 -6
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.js +3 -3
- 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.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +23 -18
- 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 +159 -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/useRemoteThreadListRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.js +14 -6
- 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-runtime.d.ts +9 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +5 -0
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +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 +2 -2
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +14 -2
- 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 +4 -3
- package/dist/runtime/utils/external-message-conversion.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.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-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/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 +1 -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 +30 -13
- package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/title.d.ts +9 -0
- package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/title.js +6 -0
- package/dist/runtimes/remote-thread-list/title.js.map +1 -0
- package/dist/runtimes/remote-thread-list/types.d.ts +6 -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 +11 -4
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/single-thread-list.js +1 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/suggestions.js +18 -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.js +1 -1
- package/dist/store/runtime-clients/message-runtime-client.js +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +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 +124 -105
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +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/part.d.ts +6 -3
- package/dist/store/scopes/part.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/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/package.json +12 -17
- package/src/index.ts +6 -1
- package/src/internal.ts +8 -0
- package/src/model-context/frame/provider.test.ts +217 -1
- package/src/model-context/frame/provider.ts +111 -23
- package/src/model-context/tool-call-text.test.ts +67 -0
- package/src/model-context/tool-call-text.ts +67 -0
- package/src/react/AssistantRuntimeProvider.test.tsx +66 -2
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +1 -3
- package/src/react/client/RemoteThreadList.background.test.ts +384 -0
- package/src/react/client/RemoteThreadList.concurrent.test.tsx +274 -0
- package/src/react/client/RemoteThreadList.test.ts +273 -1
- package/src/react/client/RemoteThreadList.ts +293 -83
- package/src/react/client/Tools.ts +7 -1
- package/src/react/index.ts +4 -0
- 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/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/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.running.test.tsx +94 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +72 -31
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +169 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +114 -68
- package/src/react/runtimes/RemoteThreadResource.ts +1 -4
- 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 +65 -1
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +42 -35
- package/src/react/runtimes/cloud/auiV0.ts +5 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +88 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +236 -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/useRemoteThreadListRuntime.concurrent.test.tsx +216 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +24 -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/thread-list-runtime.ts +25 -1
- package/src/runtime/base/base-thread-runtime-core.test.ts +94 -3
- package/src/runtime/base/base-thread-runtime-core.ts +10 -4
- package/src/runtime/interfaces/thread-list-runtime-core.ts +20 -1
- 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 +97 -0
- package/src/runtime/utils/external-message-conversion.ts +17 -1
- 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 +2 -10
- 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-runtime-core.ts +56 -33
- package/src/runtimes/inert/InertThreadRuntimeCore.ts +1 -1
- 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 +112 -0
- package/src/runtimes/remote-thread-list/remote-thread-state.ts +55 -16
- package/src/runtimes/remote-thread-list/title.ts +3 -0
- package/src/runtimes/remote-thread-list/types.ts +6 -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 +14 -8
- package/src/store/clients/suggestions.test.ts +155 -1
- package/src/store/clients/suggestions.ts +42 -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/thread-list-runtime-client.ts +16 -2
- package/src/store/runtime-clients/useSubscribable.ts +8 -2
- package/src/store/scopes/part.ts +6 -3
- package/src/subscribable/subscribable.test.ts +50 -0
- package/src/subscribable/subscribable.ts +33 -21
- package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +111 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +78 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +52 -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-runtime-core-adapter.test.ts +22 -16
- package/src/tests/external-thread-attachments.test.tsx +85 -1
- package/src/tests/remote-thread-list-adapter-switch.test.ts +66 -1
- package/src/tests/thread-switch-events.test.tsx +397 -2
- package/src/types/message.ts +50 -2
|
@@ -10,17 +10,27 @@ 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
|
+
WritableSubscribable,
|
|
28
|
+
} from "../../subscribable/subscribable";
|
|
29
|
+
import { useSubscribable } from "../../store/runtime-clients/useSubscribable";
|
|
21
30
|
import { getThreadRuntimeCoreIsRunning } from "../../runtime/api/thread-runtime";
|
|
22
31
|
import { ThreadListRuntimeImpl } from "../../runtime/api/thread-list-runtime";
|
|
23
32
|
import { invalidateThreadRuntime } from "../../runtime/utils/thread-runtime-lifecycle";
|
|
33
|
+
import { notifyEventListeners } from "../../utils/notify-event-listeners";
|
|
24
34
|
import {
|
|
25
35
|
useRuntimeAdapters,
|
|
26
36
|
type RuntimeAdapters,
|
|
@@ -30,6 +40,13 @@ import {
|
|
|
30
40
|
type RemoteThreadListHook,
|
|
31
41
|
} from "./RemoteThreadResource";
|
|
32
42
|
|
|
43
|
+
const THREAD_EVENTS = [
|
|
44
|
+
"runStart",
|
|
45
|
+
"runEnd",
|
|
46
|
+
"initialize",
|
|
47
|
+
"modelContextUpdate",
|
|
48
|
+
] as const satisfies readonly ThreadRuntimeEventType[];
|
|
49
|
+
|
|
33
50
|
type RemoteThreadListHookInstance = {
|
|
34
51
|
runtime?: ThreadRuntimeCore | undefined;
|
|
35
52
|
publishedGeneration?: number | undefined;
|
|
@@ -59,14 +76,14 @@ const ProviderRenderDetector: FC<{
|
|
|
59
76
|
|
|
60
77
|
export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
61
78
|
private runtimeHook: RemoteThreadListHook;
|
|
62
|
-
private readonly adapterStore =
|
|
79
|
+
private readonly adapterStore = new WritableSubscribable<AdapterSnapshot>({
|
|
63
80
|
defaultAdapters: null,
|
|
64
81
|
threadAdapters: new Map(),
|
|
65
|
-
})
|
|
66
|
-
private readonly hostStore =
|
|
82
|
+
});
|
|
83
|
+
private readonly hostStore = new WritableSubscribable<HostSnapshot>({
|
|
67
84
|
threads: [],
|
|
68
85
|
hookEpoch: 0,
|
|
69
|
-
})
|
|
86
|
+
});
|
|
70
87
|
private readonly pendingThreadAdapters = new Map<
|
|
71
88
|
string,
|
|
72
89
|
RuntimeAdapters | null
|
|
@@ -148,6 +165,17 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
148
165
|
return () => this.runningSubscribers.delete(callback);
|
|
149
166
|
}
|
|
150
167
|
|
|
168
|
+
private threadEventSubscribers = new Set<
|
|
169
|
+
(event: ThreadListRuntimeEvent) => void
|
|
170
|
+
>();
|
|
171
|
+
|
|
172
|
+
public __internal_subscribeThreadEvents(
|
|
173
|
+
callback: (event: ThreadListRuntimeEvent) => void,
|
|
174
|
+
): Unsubscribe {
|
|
175
|
+
this.threadEventSubscribers.add(callback);
|
|
176
|
+
return () => this.threadEventSubscribers.delete(callback);
|
|
177
|
+
}
|
|
178
|
+
|
|
151
179
|
private _publish = (
|
|
152
180
|
threadId: string,
|
|
153
181
|
runtime: ThreadRuntimeCore,
|
|
@@ -170,7 +198,7 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
170
198
|
instance.runtime = runtime;
|
|
171
199
|
instance.publishedGeneration = generation;
|
|
172
200
|
if (previousRuntime !== runtime) {
|
|
173
|
-
this._trackRunning(instance);
|
|
201
|
+
this._trackRunning(threadId, instance);
|
|
174
202
|
}
|
|
175
203
|
this._notifySubscribers();
|
|
176
204
|
if (previousRuntime !== undefined && previousRuntime !== runtime) {
|
|
@@ -187,7 +215,10 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
187
215
|
return () => this.replacedSubscribers.delete(callback);
|
|
188
216
|
}
|
|
189
217
|
|
|
190
|
-
private _trackRunning(
|
|
218
|
+
private _trackRunning(
|
|
219
|
+
threadId: string,
|
|
220
|
+
instance: RemoteThreadListHookInstance,
|
|
221
|
+
) {
|
|
191
222
|
instance.unsubscribeRunning?.();
|
|
192
223
|
|
|
193
224
|
const runtime = instance.runtime;
|
|
@@ -198,9 +229,23 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
198
229
|
}
|
|
199
230
|
|
|
200
231
|
this._setRunning(instance, getThreadRuntimeCoreIsRunning(runtime));
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
232
|
+
const unsubscribers = [
|
|
233
|
+
runtime.subscribe(() => {
|
|
234
|
+
this._setRunning(instance, getThreadRuntimeCoreIsRunning(runtime));
|
|
235
|
+
}),
|
|
236
|
+
...THREAD_EVENTS.map((type) =>
|
|
237
|
+
runtime.unstable_on(type, () => {
|
|
238
|
+
notifyEventListeners(
|
|
239
|
+
this.threadEventSubscribers,
|
|
240
|
+
{ threadId, type },
|
|
241
|
+
`Thread event "${type}"`,
|
|
242
|
+
);
|
|
243
|
+
}),
|
|
244
|
+
),
|
|
245
|
+
];
|
|
246
|
+
instance.unsubscribeRunning = () => {
|
|
247
|
+
for (const unsubscribe of unsubscribers) unsubscribe();
|
|
248
|
+
};
|
|
204
249
|
}
|
|
205
250
|
|
|
206
251
|
private _setRunning(
|
|
@@ -225,16 +270,14 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
225
270
|
public setRuntimeHook(newRuntimeHook: RemoteThreadListHook) {
|
|
226
271
|
if (this.runtimeHook === newRuntimeHook) return;
|
|
227
272
|
this.runtimeHook = newRuntimeHook;
|
|
228
|
-
this.hostStore.
|
|
229
|
-
|
|
230
|
-
true,
|
|
231
|
-
);
|
|
273
|
+
const host = this.hostStore.getState();
|
|
274
|
+
this.hostStore.setState({ ...host, hookEpoch: host.hookEpoch + 1 });
|
|
232
275
|
}
|
|
233
276
|
|
|
234
277
|
public __internal_setDefaultAdapters(adapters: RuntimeAdapters | null) {
|
|
235
278
|
const current = this.adapterStore.getState();
|
|
236
279
|
if (current.defaultAdapters === adapters) return;
|
|
237
|
-
this.adapterStore.setState({ ...current, defaultAdapters: adapters }
|
|
280
|
+
this.adapterStore.setState({ ...current, defaultAdapters: adapters });
|
|
238
281
|
}
|
|
239
282
|
|
|
240
283
|
public __internal_setThreadAdapters(
|
|
@@ -245,7 +288,7 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
245
288
|
const next = new Map(current.threadAdapters);
|
|
246
289
|
if (adapters === null) next.delete(threadId);
|
|
247
290
|
else next.set(threadId, adapters);
|
|
248
|
-
this.adapterStore.setState({ ...current, threadAdapters: next }
|
|
291
|
+
this.adapterStore.setState({ ...current, threadAdapters: next });
|
|
249
292
|
}
|
|
250
293
|
|
|
251
294
|
public __internal_dispose() {
|
|
@@ -255,20 +298,18 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
255
298
|
}
|
|
256
299
|
|
|
257
300
|
private _syncHostThreads() {
|
|
258
|
-
this.hostStore.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
true,
|
|
266
|
-
);
|
|
301
|
+
const host = this.hostStore.getState();
|
|
302
|
+
this.hostStore.setState({
|
|
303
|
+
...host,
|
|
304
|
+
threads: Array.from(this.instances.entries()).map(
|
|
305
|
+
([id, { generation }]) => ({ id, generation }),
|
|
306
|
+
),
|
|
307
|
+
});
|
|
267
308
|
}
|
|
268
309
|
|
|
269
310
|
public __internal_useHost(parentClient: AssistantClient) {
|
|
270
|
-
const { threads, hookEpoch } = this.hostStore
|
|
271
|
-
const adapters = this.adapterStore
|
|
311
|
+
const { threads, hookEpoch } = useSubscribable(this.hostStore);
|
|
312
|
+
const adapters = useSubscribable(this.adapterStore);
|
|
272
313
|
const runtimeHook = this.runtimeHook;
|
|
273
314
|
return useResources(
|
|
274
315
|
threads.map(({ id, generation }) => {
|
|
@@ -294,7 +335,7 @@ export class RemoteThreadListHookInstanceManager extends BaseSubscribable {
|
|
|
294
335
|
public __internal_RenderThreadRuntimes: FC<{
|
|
295
336
|
provider: ComponentType<PropsWithChildren>;
|
|
296
337
|
}> = ({ provider }) => {
|
|
297
|
-
this.hostStore
|
|
338
|
+
useSubscribable(this.hostStore);
|
|
298
339
|
|
|
299
340
|
return Array.from(this.instances.entries()).map(
|
|
300
341
|
([threadId, { generation }]) => (
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { RemoteThreadListThreadListRuntimeCore } from "./RemoteThreadListThreadListRuntimeCore";
|
|
3
|
+
import {
|
|
4
|
+
contextProvider,
|
|
5
|
+
createCore,
|
|
6
|
+
deferred,
|
|
7
|
+
makeAdapter,
|
|
8
|
+
} from "../../tests/remote-thread-list-test-helpers";
|
|
9
|
+
|
|
10
|
+
describe("RemoteThreadListThreadListRuntimeCore switch/delete ordering", () => {
|
|
11
|
+
it("rejects when a thread is deleted before its runtime attaches", async () => {
|
|
12
|
+
const adapter = makeAdapter({
|
|
13
|
+
list: vi.fn(async () => ({
|
|
14
|
+
threads: [
|
|
15
|
+
{
|
|
16
|
+
status: "archived" as const,
|
|
17
|
+
remoteId: "thread-b",
|
|
18
|
+
externalId: "thread-b",
|
|
19
|
+
title: "Thread B",
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
})),
|
|
23
|
+
});
|
|
24
|
+
const core = new RemoteThreadListThreadListRuntimeCore(
|
|
25
|
+
{ adapter, runtimeHook: () => ({}) as never },
|
|
26
|
+
contextProvider,
|
|
27
|
+
);
|
|
28
|
+
await core.getLoadThreadsPromise();
|
|
29
|
+
const initialMainThreadId = core.mainThreadId;
|
|
30
|
+
|
|
31
|
+
const switchToB = core.switchToThread("thread-b");
|
|
32
|
+
const rejection = expect(switchToB).rejects.toThrow(
|
|
33
|
+
"Thread was deleted before runtime was started",
|
|
34
|
+
);
|
|
35
|
+
await core.delete("thread-b");
|
|
36
|
+
await rejection;
|
|
37
|
+
|
|
38
|
+
expect(adapter.unarchive).not.toHaveBeenCalled();
|
|
39
|
+
expect(core.getItemById("thread-b")).toBeUndefined();
|
|
40
|
+
expect(core.mainThreadId).toBe(initialMainThreadId);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("does not select a thread deleted while its switch is unarchiving", async () => {
|
|
44
|
+
const unarchive = deferred<void>();
|
|
45
|
+
const adapter = makeAdapter({
|
|
46
|
+
list: vi.fn(async () => ({
|
|
47
|
+
threads: [
|
|
48
|
+
{
|
|
49
|
+
status: "archived" as const,
|
|
50
|
+
remoteId: "thread-b",
|
|
51
|
+
externalId: "thread-b",
|
|
52
|
+
title: "Thread B",
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
})),
|
|
56
|
+
unarchive: vi.fn(() => unarchive.promise),
|
|
57
|
+
});
|
|
58
|
+
const core = createCore(adapter);
|
|
59
|
+
await core.getLoadThreadsPromise();
|
|
60
|
+
const initialMainThreadId = core.mainThreadId;
|
|
61
|
+
|
|
62
|
+
const switchToB = core.switchToThread("thread-b");
|
|
63
|
+
await vi.waitFor(() => {
|
|
64
|
+
expect(adapter.unarchive).toHaveBeenCalledWith("thread-b");
|
|
65
|
+
});
|
|
66
|
+
await core.delete("thread-b");
|
|
67
|
+
|
|
68
|
+
unarchive.resolve();
|
|
69
|
+
await switchToB;
|
|
70
|
+
|
|
71
|
+
expect(core.getItemById("thread-b")).toBeUndefined();
|
|
72
|
+
expect(core.mainThreadId).toBe(initialMainThreadId);
|
|
73
|
+
expect(core.getItemById(core.mainThreadId!)).toBeDefined();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("does not start unarchive after initialization when the target was deleted", async () => {
|
|
77
|
+
const initialization = deferred<{
|
|
78
|
+
remoteId: string;
|
|
79
|
+
externalId: string | undefined;
|
|
80
|
+
}>();
|
|
81
|
+
const adapter = makeAdapter({
|
|
82
|
+
list: vi.fn(async () => ({
|
|
83
|
+
threads: [
|
|
84
|
+
{
|
|
85
|
+
status: "archived" as const,
|
|
86
|
+
remoteId: "thread-b",
|
|
87
|
+
externalId: "thread-b",
|
|
88
|
+
title: "Thread B",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
})),
|
|
92
|
+
});
|
|
93
|
+
const core = createCore(adapter);
|
|
94
|
+
await core.getLoadThreadsPromise();
|
|
95
|
+
const target = core.getItemById("thread-b")!;
|
|
96
|
+
(
|
|
97
|
+
target as {
|
|
98
|
+
initializeTask: Promise<{
|
|
99
|
+
remoteId: string;
|
|
100
|
+
externalId: string | undefined;
|
|
101
|
+
}>;
|
|
102
|
+
}
|
|
103
|
+
).initializeTask = initialization.promise;
|
|
104
|
+
const initialMainThreadId = core.mainThreadId;
|
|
105
|
+
|
|
106
|
+
const switchToB = core.switchToThread("thread-b");
|
|
107
|
+
const deleteB = core.delete("thread-b");
|
|
108
|
+
await vi.waitFor(() => {
|
|
109
|
+
expect(core.getItemById("thread-b")).toBeUndefined();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
initialization.resolve({
|
|
113
|
+
remoteId: "thread-b",
|
|
114
|
+
externalId: "thread-b",
|
|
115
|
+
});
|
|
116
|
+
await Promise.all([switchToB, deleteB]);
|
|
117
|
+
|
|
118
|
+
expect(adapter.unarchive).not.toHaveBeenCalled();
|
|
119
|
+
expect(core.mainThreadId).toBe(initialMainThreadId);
|
|
120
|
+
expect(core.getItemById(core.mainThreadId!)).toBeDefined();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("does not unarchive again when the target became regular during initialization", async () => {
|
|
124
|
+
const initialization = deferred<{
|
|
125
|
+
remoteId: string;
|
|
126
|
+
externalId: string | undefined;
|
|
127
|
+
}>();
|
|
128
|
+
const adapter = makeAdapter({
|
|
129
|
+
list: vi.fn(async () => ({
|
|
130
|
+
threads: [
|
|
131
|
+
{
|
|
132
|
+
status: "archived" as const,
|
|
133
|
+
remoteId: "thread-b",
|
|
134
|
+
externalId: "thread-b",
|
|
135
|
+
title: "Thread B",
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
})),
|
|
139
|
+
});
|
|
140
|
+
const core = createCore(adapter);
|
|
141
|
+
await core.getLoadThreadsPromise();
|
|
142
|
+
const target = core.getItemById("thread-b")!;
|
|
143
|
+
(
|
|
144
|
+
target as {
|
|
145
|
+
initializeTask: Promise<{
|
|
146
|
+
remoteId: string;
|
|
147
|
+
externalId: string | undefined;
|
|
148
|
+
}>;
|
|
149
|
+
}
|
|
150
|
+
).initializeTask = initialization.promise;
|
|
151
|
+
|
|
152
|
+
const switchToB = core.switchToThread("thread-b");
|
|
153
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
154
|
+
const unarchiveB = core.unarchive("thread-b");
|
|
155
|
+
await vi.waitFor(() => {
|
|
156
|
+
expect(core.getItemById("thread-b")?.status).toBe("regular");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
initialization.resolve({
|
|
160
|
+
remoteId: "thread-b",
|
|
161
|
+
externalId: "thread-b",
|
|
162
|
+
});
|
|
163
|
+
await Promise.all([switchToB, unarchiveB]);
|
|
164
|
+
|
|
165
|
+
expect(adapter.unarchive).toHaveBeenCalledTimes(1);
|
|
166
|
+
expect(adapter.unarchive).toHaveBeenCalledWith("thread-b");
|
|
167
|
+
expect(core.mainThreadId).toBe("thread-b");
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
ThreadListRuntimeCore,
|
|
3
|
+
ThreadListRuntimeEvent,
|
|
4
|
+
} from "../../runtime/interfaces/thread-list-runtime-core";
|
|
5
|
+
import {
|
|
6
|
+
BaseSubscribable,
|
|
7
|
+
WritableSubscribable,
|
|
8
|
+
} from "../../subscribable/subscribable";
|
|
9
|
+
import { useSubscribable } from "../../store/runtime-clients/useSubscribable";
|
|
3
10
|
import { OptimisticState } from "../../runtimes/remote-thread-list/optimistic-state";
|
|
4
11
|
import { EMPTY_THREAD_CORE } from "../../runtimes/remote-thread-list/empty-thread-core";
|
|
5
12
|
import type {
|
|
13
|
+
ClassifyAccumulator,
|
|
6
14
|
RemoteThreadData,
|
|
7
15
|
RemoteThreadState,
|
|
8
16
|
} from "../../runtimes/remote-thread-list/remote-thread-state";
|
|
@@ -24,7 +32,7 @@ import type {
|
|
|
24
32
|
} from "../../runtimes/remote-thread-list/types";
|
|
25
33
|
import { ThreadListAdapterChangedError } from "../../runtimes/remote-thread-list/adapter-changed";
|
|
26
34
|
import { RemoteThreadListHookInstanceManager } from "./RemoteThreadListHookInstanceManager";
|
|
27
|
-
import { isTitleSourceMessage } from "
|
|
35
|
+
import { isTitleSourceMessage } from "../../runtimes/remote-thread-list/title";
|
|
28
36
|
import {
|
|
29
37
|
type ComponentType,
|
|
30
38
|
type FC,
|
|
@@ -34,7 +42,6 @@ import {
|
|
|
34
42
|
useId,
|
|
35
43
|
} from "react";
|
|
36
44
|
import { useAui } from "@assistant-ui/store";
|
|
37
|
-
import { create } from "zustand";
|
|
38
45
|
import { AssistantMessageStream } from "assistant-stream";
|
|
39
46
|
import type { ModelContextProvider } from "../../model-context/types";
|
|
40
47
|
import { RuntimeAdapterProvider } from "./RuntimeAdapterProvider";
|
|
@@ -126,6 +133,7 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
126
133
|
.optimisticUpdate({
|
|
127
134
|
execute: () => this._options.adapter.list(),
|
|
128
135
|
loading: (state) => {
|
|
136
|
+
if (generation !== this._loadGeneration) return state;
|
|
129
137
|
return {
|
|
130
138
|
...state,
|
|
131
139
|
isLoading: true,
|
|
@@ -147,8 +155,8 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
147
155
|
const fresh = classifyThreads(l.threads, {
|
|
148
156
|
threadIds: [],
|
|
149
157
|
archivedThreadIds: [],
|
|
150
|
-
threadIdMap: {},
|
|
151
|
-
threadData: {},
|
|
158
|
+
threadIdMap: { ...state.threadIdMap },
|
|
159
|
+
threadData: { ...state.threadData },
|
|
152
160
|
});
|
|
153
161
|
const merged = {
|
|
154
162
|
...state,
|
|
@@ -156,8 +164,8 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
156
164
|
cursor: normalizeCursor(l.nextCursor),
|
|
157
165
|
threadIds: fresh.threadIds,
|
|
158
166
|
archivedThreadIds: fresh.archivedThreadIds,
|
|
159
|
-
threadIdMap:
|
|
160
|
-
threadData:
|
|
167
|
+
threadIdMap: fresh.threadIdMap,
|
|
168
|
+
threadData: fresh.threadData,
|
|
161
169
|
};
|
|
162
170
|
return preserveMidLoadTransitions(merged, state, statusAtRequest);
|
|
163
171
|
},
|
|
@@ -206,7 +214,10 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
206
214
|
const dedup = this._state
|
|
207
215
|
.optimisticUpdate({
|
|
208
216
|
execute: () => adapter.list({ after: cursor }),
|
|
209
|
-
loading: (state) =>
|
|
217
|
+
loading: (state) => {
|
|
218
|
+
if (generation !== this._loadGeneration) return state;
|
|
219
|
+
return { ...state, isLoadingMore: true };
|
|
220
|
+
},
|
|
210
221
|
then: (state, l) => {
|
|
211
222
|
if (generation !== this._loadGeneration) return state;
|
|
212
223
|
if (adapter !== this._options.adapter) return state;
|
|
@@ -267,15 +278,15 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
267
278
|
// synchronous notify would re-enter store consumers mid-render.
|
|
268
279
|
queueMicrotask(() => this._notifySubscribers());
|
|
269
280
|
});
|
|
270
|
-
this.
|
|
271
|
-
|
|
272
|
-
|
|
281
|
+
this.providerStore = new WritableSubscribable(
|
|
282
|
+
this.resolveProvider(options.adapter),
|
|
283
|
+
);
|
|
273
284
|
this.__internal_setOptions(options);
|
|
274
285
|
this.switchToNewThread();
|
|
275
286
|
}
|
|
276
287
|
|
|
277
288
|
private _initialThreadLoaded = false;
|
|
278
|
-
private
|
|
289
|
+
private providerStore;
|
|
279
290
|
|
|
280
291
|
public __internal_setOptions(options: RemoteThreadListOptions) {
|
|
281
292
|
if (this._options === options) return;
|
|
@@ -289,10 +300,7 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
289
300
|
|
|
290
301
|
this._options = options;
|
|
291
302
|
|
|
292
|
-
|
|
293
|
-
if (Provider !== this.useProvider.getState().Provider) {
|
|
294
|
-
this.useProvider.setState({ Provider }, true);
|
|
295
|
-
}
|
|
303
|
+
this.providerStore.setState(this.resolveProvider(options.adapter));
|
|
296
304
|
|
|
297
305
|
this._hookManager.setRuntimeHook(options.runtimeHook);
|
|
298
306
|
|
|
@@ -337,24 +345,11 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
337
345
|
threads: readonly RemoteThreadMetadata[],
|
|
338
346
|
cursor: string | undefined,
|
|
339
347
|
): RemoteThreadState {
|
|
340
|
-
const
|
|
341
|
-
threadIds: [],
|
|
342
|
-
archivedThreadIds: [],
|
|
343
|
-
threadIdMap: {},
|
|
344
|
-
threadData: {},
|
|
345
|
-
});
|
|
346
|
-
const threadIdMap = { ...fresh.threadIdMap };
|
|
347
|
-
const threadData = { ...fresh.threadData };
|
|
348
|
-
const threadIds = [...fresh.threadIds];
|
|
349
|
-
const archivedThreadIds = [...fresh.archivedThreadIds];
|
|
350
|
-
|
|
348
|
+
const carried: RemoteThreadData[] = [];
|
|
351
349
|
if (state.newThreadId) {
|
|
352
350
|
const mappingId = state.threadIdMap[state.newThreadId];
|
|
353
351
|
const draft = mappingId ? state.threadData[mappingId] : undefined;
|
|
354
|
-
if (draft?.status === "new")
|
|
355
|
-
threadIdMap[state.newThreadId] = mappingId!;
|
|
356
|
-
threadData[mappingId!] = draft;
|
|
357
|
-
}
|
|
352
|
+
if (draft?.status === "new") carried.push(draft);
|
|
358
353
|
}
|
|
359
354
|
|
|
360
355
|
const stale = this._staleThreadIdsOnReplace;
|
|
@@ -362,26 +357,44 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
362
357
|
for (const item of Object.values(state.threadData)) {
|
|
363
358
|
if (stale.has(item.id)) continue;
|
|
364
359
|
if (item.status !== "new" && item.remoteId === undefined) continue;
|
|
365
|
-
|
|
366
|
-
if (threadData[mappingId]) continue;
|
|
367
|
-
threadIdMap[item.id] = mappingId;
|
|
368
|
-
if (item.remoteId !== undefined) {
|
|
369
|
-
threadIdMap[item.remoteId] = mappingId;
|
|
370
|
-
}
|
|
371
|
-
threadData[mappingId] = item;
|
|
372
|
-
if (item.remoteId === undefined) continue;
|
|
373
|
-
if (item.status === "regular" && !threadIds.includes(item.remoteId)) {
|
|
374
|
-
threadIds.push(item.remoteId);
|
|
375
|
-
} else if (
|
|
376
|
-
item.status === "archived" &&
|
|
377
|
-
!archivedThreadIds.includes(item.remoteId)
|
|
378
|
-
) {
|
|
379
|
-
archivedThreadIds.push(item.remoteId);
|
|
380
|
-
}
|
|
360
|
+
carried.push(item);
|
|
381
361
|
}
|
|
382
362
|
}
|
|
383
363
|
this._staleThreadIdsOnReplace = undefined;
|
|
384
364
|
|
|
365
|
+
const seed: ClassifyAccumulator = {
|
|
366
|
+
threadIds: [],
|
|
367
|
+
archivedThreadIds: [],
|
|
368
|
+
threadIdMap: {},
|
|
369
|
+
threadData: {},
|
|
370
|
+
};
|
|
371
|
+
for (const item of carried) {
|
|
372
|
+
const mappingId = createThreadMappingId(item.id);
|
|
373
|
+
if (seed.threadData[mappingId]) continue;
|
|
374
|
+
seed.threadIdMap[item.id] = mappingId;
|
|
375
|
+
if (item.remoteId !== undefined) {
|
|
376
|
+
seed.threadIdMap[item.remoteId] = mappingId;
|
|
377
|
+
}
|
|
378
|
+
seed.threadData[mappingId] = item;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const { threadIds, archivedThreadIds, threadIdMap, threadData } =
|
|
382
|
+
classifyThreads(threads, seed);
|
|
383
|
+
|
|
384
|
+
for (const item of carried) {
|
|
385
|
+
if (item.remoteId === undefined) continue;
|
|
386
|
+
const current = threadData[createThreadMappingId(item.id)];
|
|
387
|
+
if (current === undefined) continue;
|
|
388
|
+
if (current.status === "regular" && !threadIds.includes(current.id)) {
|
|
389
|
+
threadIds.push(current.id);
|
|
390
|
+
} else if (
|
|
391
|
+
current.status === "archived" &&
|
|
392
|
+
!archivedThreadIds.includes(current.id)
|
|
393
|
+
) {
|
|
394
|
+
archivedThreadIds.push(current.id);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
385
398
|
let nextState: RemoteThreadState = {
|
|
386
399
|
...state,
|
|
387
400
|
isLoading: false,
|
|
@@ -555,6 +568,12 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
555
568
|
return this._hookManager.__internal_isThreadRunning(data.id);
|
|
556
569
|
}
|
|
557
570
|
|
|
571
|
+
public unstable_subscribeThreadEvents(
|
|
572
|
+
callback: (event: ThreadListRuntimeEvent) => void,
|
|
573
|
+
) {
|
|
574
|
+
return this._hookManager.__internal_subscribeThreadEvents(callback);
|
|
575
|
+
}
|
|
576
|
+
|
|
558
577
|
public getItemById(threadIdOrRemoteId: string) {
|
|
559
578
|
return getThreadData(this._state.value, threadIdOrRemoteId);
|
|
560
579
|
}
|
|
@@ -629,9 +648,8 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
629
648
|
// A concurrent `list()` may already have placed this thread; keep that
|
|
630
649
|
// position and only merge metadata. A genuinely absent thread stays
|
|
631
650
|
// appended: it may live on an unloaded page, and a prepend would pin it
|
|
632
|
-
// above newer threads permanently
|
|
633
|
-
//
|
|
634
|
-
// duplication or a wrong-status entry from `list()`.
|
|
651
|
+
// above newer threads permanently. Filtering both arrays first still
|
|
652
|
+
// prevents duplication or a wrong-status entry from `list()`.
|
|
635
653
|
const remoteId = remoteMetadata.remoteId;
|
|
636
654
|
const wasInTarget =
|
|
637
655
|
remoteMetadata.status === "regular"
|
|
@@ -684,11 +702,22 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
684
702
|
|
|
685
703
|
if (generation !== this._switchGeneration) return;
|
|
686
704
|
|
|
687
|
-
|
|
688
|
-
|
|
705
|
+
let current = this.getItemById(data.id);
|
|
706
|
+
if (current?.id !== data.id) return;
|
|
707
|
+
|
|
708
|
+
if (current.status === "archived" && options?.unarchive !== false) {
|
|
709
|
+
await current.initializeTask;
|
|
689
710
|
if (generation !== this._switchGeneration) return;
|
|
711
|
+
current = this.getItemById(data.id);
|
|
712
|
+
if (current?.id !== data.id) return;
|
|
713
|
+
if (current.status === "archived") {
|
|
714
|
+
await this.unarchive(current.id);
|
|
715
|
+
if (generation !== this._switchGeneration) return;
|
|
716
|
+
current = this.getItemById(data.id);
|
|
717
|
+
if (current?.id !== data.id) return;
|
|
718
|
+
}
|
|
690
719
|
}
|
|
691
|
-
this._mainThreadId =
|
|
720
|
+
this._mainThreadId = current.id;
|
|
692
721
|
|
|
693
722
|
this._notifySubscribers();
|
|
694
723
|
this._notifyThreadIdChange(emitThreadIdChange);
|
|
@@ -776,21 +805,36 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
776
805
|
if (!data) return state;
|
|
777
806
|
|
|
778
807
|
const mappingId = createThreadMappingId(threadId);
|
|
808
|
+
// A list() response that landed while this initialize was in flight
|
|
809
|
+
// could not know the remote id yet, so it may have minted its own slot
|
|
810
|
+
// for it; that slot collapses into this one.
|
|
811
|
+
const listedMappingId = state.threadIdMap[remoteId];
|
|
812
|
+
const orphan =
|
|
813
|
+
listedMappingId !== undefined && listedMappingId !== mappingId
|
|
814
|
+
? state.threadData[listedMappingId]
|
|
815
|
+
: undefined;
|
|
816
|
+
|
|
817
|
+
const threadData = { ...state.threadData };
|
|
818
|
+
if (orphan !== undefined) delete threadData[listedMappingId!];
|
|
819
|
+
threadData[mappingId] = {
|
|
820
|
+
...data,
|
|
821
|
+
initializeTask: Promise.resolve({ remoteId, externalId }),
|
|
822
|
+
remoteId,
|
|
823
|
+
externalId,
|
|
824
|
+
} as RemoteThreadData;
|
|
825
|
+
|
|
826
|
+
const rewire = (ids: readonly string[]) =>
|
|
827
|
+
orphan === undefined ? ids : ids.filter((id) => id !== orphan.id);
|
|
828
|
+
|
|
779
829
|
return {
|
|
780
830
|
...state,
|
|
831
|
+
threadIds: rewire(state.threadIds),
|
|
832
|
+
archivedThreadIds: rewire(state.archivedThreadIds),
|
|
781
833
|
threadIdMap: {
|
|
782
834
|
...state.threadIdMap,
|
|
783
835
|
[remoteId]: mappingId,
|
|
784
836
|
},
|
|
785
|
-
threadData
|
|
786
|
-
...state.threadData,
|
|
787
|
-
[mappingId]: {
|
|
788
|
-
...data,
|
|
789
|
-
initializeTask: Promise.resolve({ remoteId, externalId }),
|
|
790
|
-
remoteId,
|
|
791
|
-
externalId,
|
|
792
|
-
},
|
|
793
|
-
},
|
|
837
|
+
threadData,
|
|
794
838
|
};
|
|
795
839
|
},
|
|
796
840
|
});
|
|
@@ -1049,19 +1093,21 @@ export class RemoteThreadListThreadListRuntimeCore
|
|
|
1049
1093
|
this._hookManager.stopThreadRuntime(data.id);
|
|
1050
1094
|
}
|
|
1051
1095
|
|
|
1052
|
-
private
|
|
1096
|
+
private boundIdsStore = new WritableSubscribable<readonly string[]>([]);
|
|
1053
1097
|
|
|
1054
1098
|
public __internal_RenderComponent: FC = () => {
|
|
1055
1099
|
const id = useId();
|
|
1056
1100
|
useEffect(() => {
|
|
1057
|
-
this.
|
|
1101
|
+
this.boundIdsStore.setState([...this.boundIdsStore.getState(), id]);
|
|
1058
1102
|
return () => {
|
|
1059
|
-
this.
|
|
1103
|
+
this.boundIdsStore.setState(
|
|
1104
|
+
this.boundIdsStore.getState().filter((i) => i !== id),
|
|
1105
|
+
);
|
|
1060
1106
|
};
|
|
1061
1107
|
}, [id]);
|
|
1062
1108
|
|
|
1063
|
-
const boundIds = this.
|
|
1064
|
-
const
|
|
1109
|
+
const boundIds = useSubscribable(this.boundIdsStore);
|
|
1110
|
+
const Provider = useSubscribable(this.providerStore);
|
|
1065
1111
|
const aui = useAui();
|
|
1066
1112
|
const enabled = boundIds.length === 0 || boundIds[0] === id;
|
|
1067
1113
|
|