@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
|
@@ -2,15 +2,20 @@ import {
|
|
|
2
2
|
useCallback,
|
|
3
3
|
useEffect,
|
|
4
4
|
useMemo,
|
|
5
|
+
useRef,
|
|
5
6
|
useState,
|
|
6
7
|
useSyncExternalStore,
|
|
7
8
|
} from "react";
|
|
8
|
-
import { resource, withKey } from "@assistant-ui/tap";
|
|
9
|
+
import { resource, withKey, type ResourceElement } from "@assistant-ui/tap";
|
|
9
10
|
import type { ClientOutput } from "@assistant-ui/store";
|
|
10
11
|
import {
|
|
11
12
|
attachTransformScopes,
|
|
13
|
+
Derived,
|
|
14
|
+
useAssistantContextProvider,
|
|
15
|
+
useAssistantContextValue,
|
|
12
16
|
useClientLookup,
|
|
13
17
|
useClientResource,
|
|
18
|
+
useConfiguredAui,
|
|
14
19
|
} from "@assistant-ui/store/client";
|
|
15
20
|
import { isDevelopment, useThreadSelectionEvents } from "../../store/internal";
|
|
16
21
|
import { OptimisticState } from "../../runtimes/remote-thread-list/optimistic-state";
|
|
@@ -40,6 +45,7 @@ import {
|
|
|
40
45
|
type InMemoryThreadListProps,
|
|
41
46
|
} from "./InMemoryThreadList";
|
|
42
47
|
import { AdaptedRemoteThread } from "./AdaptedRemoteThread";
|
|
48
|
+
import { isTitleSourceMessage } from "../../runtimes/remote-thread-list/title";
|
|
43
49
|
|
|
44
50
|
const RESOLVED_PROMISE = Promise.resolve();
|
|
45
51
|
|
|
@@ -62,6 +68,18 @@ export type RemoteThreadListProps = {
|
|
|
62
68
|
onSwitchToThread?: ((threadId: string) => void) | undefined;
|
|
63
69
|
onSwitchToNewThread?: (() => void) | undefined;
|
|
64
70
|
onDelete?: ((threadId: string) => void) | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Keeps every thread the session switched to mounted, so a run continues
|
|
73
|
+
* after the user switches away, per-item `isRunning` reflects background
|
|
74
|
+
* runs, and a freshly initialized thread generates its title automatically.
|
|
75
|
+
* A body unmounts on delete, detach, or an adapter replacement (`reload()`
|
|
76
|
+
* after swapping the adapter); visited threads otherwise stay mounted for
|
|
77
|
+
* the client's lifetime. Each body reads its own thread through the ambient
|
|
78
|
+
* `threadListItem` scope, and `unstable_useAdapters` runs once per mounted
|
|
79
|
+
* body. Off (the default), only the visible thread is mounted and a switch
|
|
80
|
+
* unmounts it. The mode is fixed at mount.
|
|
81
|
+
*/
|
|
82
|
+
backgroundThreads?: boolean | undefined;
|
|
65
83
|
};
|
|
66
84
|
|
|
67
85
|
const threadNotFoundError = (threadIdOrRemoteId: string, action: string) =>
|
|
@@ -202,9 +220,96 @@ const isSameThread = (
|
|
|
202
220
|
return data !== undefined && itemMatchesId(data, listState, right);
|
|
203
221
|
};
|
|
204
222
|
|
|
223
|
+
const useRemoteThreadBody = ({
|
|
224
|
+
id,
|
|
225
|
+
status,
|
|
226
|
+
remoteId,
|
|
227
|
+
item,
|
|
228
|
+
thread,
|
|
229
|
+
}: {
|
|
230
|
+
id: string;
|
|
231
|
+
status: RemoteThreadData["status"];
|
|
232
|
+
remoteId: string | undefined;
|
|
233
|
+
item: (isRunning: boolean) => ResourceElement<ClientOutput<"threadListItem">>;
|
|
234
|
+
thread: ResourceElement<ClientOutput<"thread">>;
|
|
235
|
+
}): ClientOutput<"thread"> => {
|
|
236
|
+
const parent = useAssistantContextValue();
|
|
237
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
238
|
+
// The item client is mounted inside the body and served to the subtree
|
|
239
|
+
// through a Derived scope, which keeps the graft on the derived-only (no
|
|
240
|
+
// nested client host) path; resolving `parent.threads` here instead would
|
|
241
|
+
// read the threads scope during its own construction.
|
|
242
|
+
const itemHandle = useClientResource(item(isRunning));
|
|
243
|
+
const { client } = useConfiguredAui(parent, {
|
|
244
|
+
threadListItem: Derived({
|
|
245
|
+
source: "threads",
|
|
246
|
+
query: { type: "id", id },
|
|
247
|
+
get: () => itemHandle.methods,
|
|
248
|
+
}),
|
|
249
|
+
});
|
|
250
|
+
// Auto-title arms only for a thread born "new" in this body's lifetime;
|
|
251
|
+
// threads loaded or fetched from the adapter already carry their title. The
|
|
252
|
+
// settled (non-optimistic) initialize is what writes remoteId, so its
|
|
253
|
+
// arrival is the initialization signal.
|
|
254
|
+
const bornNewRef = useRef(status === "new");
|
|
255
|
+
const titleFiredRef = useRef(false);
|
|
256
|
+
return useAssistantContextProvider(client, function useBoundRemoteBody() {
|
|
257
|
+
const body = useClientResource(thread);
|
|
258
|
+
const bodyRunning = body.state.isRunning === true;
|
|
259
|
+
useEffect(() => {
|
|
260
|
+
setIsRunning(bodyRunning);
|
|
261
|
+
}, [bodyRunning]);
|
|
262
|
+
const armed =
|
|
263
|
+
bornNewRef.current && !titleFiredRef.current && remoteId !== undefined;
|
|
264
|
+
const hasTitleSource =
|
|
265
|
+
armed &&
|
|
266
|
+
(
|
|
267
|
+
body.state.messages as readonly {
|
|
268
|
+
status?: { type: string } | undefined;
|
|
269
|
+
}[]
|
|
270
|
+
).some(isTitleSourceMessage);
|
|
271
|
+
useEffect(() => {
|
|
272
|
+
if (!hasTitleSource || titleFiredRef.current) return;
|
|
273
|
+
titleFiredRef.current = true;
|
|
274
|
+
client.threadListItem.generateTitle();
|
|
275
|
+
}, [hasTitleSource]);
|
|
276
|
+
return body.methods;
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const RemoteThreadBody = resource(useRemoteThreadBody);
|
|
281
|
+
|
|
282
|
+
// `thread("main")` keeps one identity across switches, like the single
|
|
283
|
+
// useClientResource slot it replaced: consumers (the ambient `thread` scope,
|
|
284
|
+
// captured clients) hold the facade while it delegates to whichever body is
|
|
285
|
+
// currently main. Publishing the target during commit keeps abandoned
|
|
286
|
+
// concurrent renders from changing the facade observed by committed consumers.
|
|
287
|
+
const useMainThreadFacade = (
|
|
288
|
+
current: ClientOutput<"thread">,
|
|
289
|
+
): ClientOutput<"thread"> => {
|
|
290
|
+
const currentRef = useRef(current);
|
|
291
|
+
useEffect(() => {
|
|
292
|
+
currentRef.current = current;
|
|
293
|
+
}, [current]);
|
|
294
|
+
const [facade] = useState(
|
|
295
|
+
() =>
|
|
296
|
+
new Proxy({} as ClientOutput<"thread">, {
|
|
297
|
+
get: (_, prop) =>
|
|
298
|
+
(currentRef.current as unknown as Record<PropertyKey, unknown>)[prop],
|
|
299
|
+
has: (_, prop) => prop in (currentRef.current as object),
|
|
300
|
+
ownKeys: () => Reflect.ownKeys(currentRef.current as object),
|
|
301
|
+
getOwnPropertyDescriptor: (_, prop) =>
|
|
302
|
+
Reflect.getOwnPropertyDescriptor(currentRef.current as object, prop),
|
|
303
|
+
}),
|
|
304
|
+
);
|
|
305
|
+
return facade;
|
|
306
|
+
};
|
|
307
|
+
|
|
205
308
|
const useRemoteThreadListView = ({
|
|
206
309
|
listState,
|
|
207
310
|
mainThreadId,
|
|
311
|
+
startedIds,
|
|
312
|
+
backgroundThreads,
|
|
208
313
|
threadFactory,
|
|
209
314
|
useAdapters,
|
|
210
315
|
onSwitchTo,
|
|
@@ -219,6 +324,8 @@ const useRemoteThreadListView = ({
|
|
|
219
324
|
}: {
|
|
220
325
|
listState: RemoteThreadState;
|
|
221
326
|
mainThreadId: string;
|
|
327
|
+
startedIds: readonly string[];
|
|
328
|
+
backgroundThreads: boolean;
|
|
222
329
|
threadFactory: RemoteThreadListProps["thread"];
|
|
223
330
|
useAdapters: RemoteThreadListAdapter["unstable_useAdapters"];
|
|
224
331
|
onSwitchTo: (
|
|
@@ -243,17 +350,102 @@ const useRemoteThreadListView = ({
|
|
|
243
350
|
}>;
|
|
244
351
|
onDetach: (threadId: string) => Promise<void>;
|
|
245
352
|
}) => {
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
353
|
+
const bodyIds = useMemo(() => {
|
|
354
|
+
if (!backgroundThreads) return [mainThreadId];
|
|
355
|
+
const seen = new Set<string>();
|
|
356
|
+
const seenRemoteIds = new Set<string>();
|
|
357
|
+
const ids: string[] = [];
|
|
358
|
+
for (const id of startedIds) {
|
|
359
|
+
const data = getThreadData(listState, id);
|
|
360
|
+
if (!data || seen.has(data.id)) continue;
|
|
361
|
+
if (data.remoteId !== undefined && seenRemoteIds.has(data.remoteId)) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
seen.add(data.id);
|
|
365
|
+
if (data.remoteId !== undefined) seenRemoteIds.add(data.remoteId);
|
|
366
|
+
ids.push(data.id);
|
|
367
|
+
}
|
|
368
|
+
return ids;
|
|
369
|
+
}, [backgroundThreads, listState, mainThreadId, startedIds]);
|
|
370
|
+
|
|
371
|
+
const itemElementFor = (data: RemoteThreadData, isRunning: boolean) =>
|
|
372
|
+
ThreadListItemClient({
|
|
373
|
+
data,
|
|
374
|
+
isRunning,
|
|
375
|
+
onSwitchTo: (options) =>
|
|
376
|
+
handleThreadListAction("switch", () => onSwitchTo(data.id, options)),
|
|
377
|
+
onRename: (title) =>
|
|
378
|
+
handleThreadListAction("rename", () => onRename(data.id, title)),
|
|
379
|
+
onUpdateCustom: (custom) =>
|
|
380
|
+
handleThreadListAction("update custom metadata", () =>
|
|
381
|
+
onUpdateCustom(data.id, custom),
|
|
382
|
+
),
|
|
383
|
+
onArchive: () =>
|
|
384
|
+
handleThreadListAction("archive", () => onArchive(data.id)),
|
|
385
|
+
onUnarchive: () =>
|
|
386
|
+
handleThreadListAction("unarchive", () => onUnarchive(data.id)),
|
|
387
|
+
onDelete: () => handleThreadListAction("delete", () => onDelete(data.id)),
|
|
388
|
+
onGenerateTitle: () =>
|
|
389
|
+
handleThreadListAction("generate title", () =>
|
|
390
|
+
onGenerateTitle(
|
|
391
|
+
data.id,
|
|
392
|
+
(backgroundThreads
|
|
393
|
+
? bodyStateOf(data.id)?.messages
|
|
394
|
+
: mainThreadClient.state.messages) as
|
|
395
|
+
| readonly ThreadMessage[]
|
|
396
|
+
| undefined,
|
|
397
|
+
),
|
|
398
|
+
),
|
|
399
|
+
onInitialize: () => onInitialize(data.id),
|
|
400
|
+
onDetach: () => handleThreadListAction("detach", () => onDetach(data.id)),
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const bodies = useClientLookup(
|
|
404
|
+
bodyIds.map((id) => {
|
|
405
|
+
const made = threadFactory(id);
|
|
406
|
+
// Background bodies never change occupant, so an unkeyed factory
|
|
407
|
+
// element is keyed by the mapping id here; per-body history loads
|
|
408
|
+
// without requiring the factory to key itself.
|
|
409
|
+
const thread =
|
|
410
|
+
backgroundThreads && made.key === undefined ? withKey(id, made) : made;
|
|
411
|
+
const wrapped =
|
|
412
|
+
useAdapters === undefined
|
|
413
|
+
? thread
|
|
414
|
+
: AdaptedRemoteThread({
|
|
415
|
+
useAdapters,
|
|
416
|
+
thread,
|
|
417
|
+
});
|
|
418
|
+
const data = getThreadData(listState, id);
|
|
419
|
+
const element =
|
|
420
|
+
backgroundThreads && data !== undefined
|
|
421
|
+
? RemoteThreadBody({
|
|
422
|
+
id,
|
|
423
|
+
status: data.status,
|
|
424
|
+
remoteId: data.remoteId,
|
|
425
|
+
item: (isRunning) => itemElementFor(data, isRunning),
|
|
426
|
+
thread: wrapped,
|
|
427
|
+
})
|
|
428
|
+
: wrapped;
|
|
429
|
+
return withKey(backgroundThreads ? id : (made.key ?? "main"), element);
|
|
430
|
+
}),
|
|
256
431
|
);
|
|
432
|
+
// A reload can remap a local thread id to its remote identity while the
|
|
433
|
+
// body stays keyed by the original mapping id, so lookups fall back to
|
|
434
|
+
// remote-identity matching.
|
|
435
|
+
const bodyIndexOf = (id: string) => {
|
|
436
|
+
const direct = bodyIds.indexOf(id);
|
|
437
|
+
if (direct !== -1) return direct;
|
|
438
|
+
return bodyIds.findIndex((bodyId) => isSameThread(listState, bodyId, id));
|
|
439
|
+
};
|
|
440
|
+
const bodyStateOf = (id: string) => {
|
|
441
|
+
const index = bodyIndexOf(id);
|
|
442
|
+
return index === -1 ? undefined : bodies.state[index];
|
|
443
|
+
};
|
|
444
|
+
const mainIndex = bodyIndexOf(mainThreadId);
|
|
445
|
+
const mainThreadClient = {
|
|
446
|
+
state: bodies.state[mainIndex]!,
|
|
447
|
+
methods: useMainThreadFacade(bodies.get({ index: mainIndex })),
|
|
448
|
+
};
|
|
257
449
|
const itemOrder = useMemo(
|
|
258
450
|
() => collectItemOrder(listState, mainThreadId),
|
|
259
451
|
[listState, mainThreadId],
|
|
@@ -262,40 +454,13 @@ const useRemoteThreadListView = ({
|
|
|
262
454
|
itemOrder.map((data) =>
|
|
263
455
|
withKey(
|
|
264
456
|
data.id,
|
|
265
|
-
|
|
457
|
+
itemElementFor(
|
|
266
458
|
data,
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
onSwitchTo(data.id, options),
|
|
273
|
-
),
|
|
274
|
-
onRename: (title) =>
|
|
275
|
-
handleThreadListAction("rename", () => onRename(data.id, title)),
|
|
276
|
-
onUpdateCustom: (custom) =>
|
|
277
|
-
handleThreadListAction("update custom metadata", () =>
|
|
278
|
-
onUpdateCustom(data.id, custom),
|
|
279
|
-
),
|
|
280
|
-
onArchive: () =>
|
|
281
|
-
handleThreadListAction("archive", () => onArchive(data.id)),
|
|
282
|
-
onUnarchive: () =>
|
|
283
|
-
handleThreadListAction("unarchive", () => onUnarchive(data.id)),
|
|
284
|
-
onDelete: () =>
|
|
285
|
-
handleThreadListAction("delete", () => onDelete(data.id)),
|
|
286
|
-
onGenerateTitle: () =>
|
|
287
|
-
handleThreadListAction("generate title", () =>
|
|
288
|
-
onGenerateTitle(
|
|
289
|
-
data.id,
|
|
290
|
-
mainThreadClient.state.messages as
|
|
291
|
-
| readonly ThreadMessage[]
|
|
292
|
-
| undefined,
|
|
293
|
-
),
|
|
294
|
-
),
|
|
295
|
-
onInitialize: () => onInitialize(data.id),
|
|
296
|
-
onDetach: () =>
|
|
297
|
-
handleThreadListAction("detach", () => onDetach(data.id)),
|
|
298
|
-
}),
|
|
459
|
+
backgroundThreads
|
|
460
|
+
? (bodyStateOf(data.id)?.isRunning ?? false)
|
|
461
|
+
: itemMatchesId(data, listState, mainThreadId) &&
|
|
462
|
+
mainThreadClient.state.isRunning,
|
|
463
|
+
),
|
|
299
464
|
),
|
|
300
465
|
),
|
|
301
466
|
);
|
|
@@ -340,9 +505,6 @@ const useRemoteThreadList = (
|
|
|
340
505
|
};
|
|
341
506
|
});
|
|
342
507
|
|
|
343
|
-
// Config updates can invoke `reload()` in the same turn as the re-render, before the effect below runs.
|
|
344
|
-
session.adapter = adapter;
|
|
345
|
-
|
|
346
508
|
const listState = useSyncExternalStore(
|
|
347
509
|
(onStoreChange) => store.subscribe(onStoreChange),
|
|
348
510
|
() => store.value,
|
|
@@ -350,15 +512,21 @@ const useRemoteThreadList = (
|
|
|
350
512
|
);
|
|
351
513
|
|
|
352
514
|
const [mainThreadId, setMainThreadId] = useState(initialMainId);
|
|
515
|
+
const [startedIds, setStartedIds] = useState<readonly string[]>([
|
|
516
|
+
initialMainId,
|
|
517
|
+
]);
|
|
518
|
+
const [backgroundThreads] = useState(props.backgroundThreads === true);
|
|
353
519
|
const assignMainThreadId = useCallback(
|
|
354
520
|
(id: string) => {
|
|
355
521
|
session.mainThreadId = id;
|
|
356
522
|
setMainThreadId(id);
|
|
523
|
+
setStartedIds((prev) => (prev.includes(id) ? prev : [...prev, id]));
|
|
357
524
|
},
|
|
358
525
|
[session],
|
|
359
526
|
);
|
|
360
527
|
useThreadSelectionEvents(mainThreadId);
|
|
361
528
|
useEffect(() => {
|
|
529
|
+
// Publishing after commit keeps imperative actions on the adapter the committed tree renders with; an abandoned render must not reach them.
|
|
362
530
|
session.adapter = adapter;
|
|
363
531
|
session.mainThreadId = mainThreadId;
|
|
364
532
|
session.onThreadIdChange = onThreadIdChange;
|
|
@@ -390,15 +558,18 @@ const useRemoteThreadList = (
|
|
|
390
558
|
session.loadPromise = store
|
|
391
559
|
.optimisticUpdate({
|
|
392
560
|
execute: () => adapter.list(),
|
|
393
|
-
loading: (state) =>
|
|
561
|
+
loading: (state) => {
|
|
562
|
+
if (generation !== session.loadGeneration) return state;
|
|
563
|
+
return { ...state, isLoading: true };
|
|
564
|
+
},
|
|
394
565
|
then: (state, page) => {
|
|
395
566
|
if (generation !== session.loadGeneration) return state;
|
|
396
567
|
session.adapterAtLoad = adapter;
|
|
397
568
|
const fresh = classifyThreads(page.threads, {
|
|
398
569
|
threadIds: [],
|
|
399
570
|
archivedThreadIds: [],
|
|
400
|
-
threadIdMap: {},
|
|
401
|
-
threadData: {},
|
|
571
|
+
threadIdMap: { ...state.threadIdMap },
|
|
572
|
+
threadData: { ...state.threadData },
|
|
402
573
|
});
|
|
403
574
|
const merged = {
|
|
404
575
|
...state,
|
|
@@ -406,14 +577,8 @@ const useRemoteThreadList = (
|
|
|
406
577
|
cursor: normalizeCursor(page.nextCursor),
|
|
407
578
|
threadIds: fresh.threadIds,
|
|
408
579
|
archivedThreadIds: fresh.archivedThreadIds,
|
|
409
|
-
threadIdMap:
|
|
410
|
-
|
|
411
|
-
...fresh.threadIdMap,
|
|
412
|
-
},
|
|
413
|
-
threadData: {
|
|
414
|
-
...state.threadData,
|
|
415
|
-
...fresh.threadData,
|
|
416
|
-
},
|
|
580
|
+
threadIdMap: fresh.threadIdMap,
|
|
581
|
+
threadData: fresh.threadData,
|
|
417
582
|
};
|
|
418
583
|
return preserveMidLoadTransitions(merged, state, statusAtRequest);
|
|
419
584
|
},
|
|
@@ -444,6 +609,7 @@ const useRemoteThreadList = (
|
|
|
444
609
|
const seeded = seedNewThread(EMPTY_LIST);
|
|
445
610
|
store.reset({ ...seeded.state, isLoading: true });
|
|
446
611
|
assignMainThreadId(seeded.id);
|
|
612
|
+
setStartedIds([seeded.id]);
|
|
447
613
|
notifyRemoteId(undefined, true);
|
|
448
614
|
} else {
|
|
449
615
|
store.update({
|
|
@@ -486,7 +652,10 @@ const useRemoteThreadList = (
|
|
|
486
652
|
const task = store
|
|
487
653
|
.optimisticUpdate({
|
|
488
654
|
execute: () => currentAdapter.list({ after: cursor }),
|
|
489
|
-
loading: (state) =>
|
|
655
|
+
loading: (state) => {
|
|
656
|
+
if (generation !== session.loadGeneration) return state;
|
|
657
|
+
return { ...state, isLoadingMore: true };
|
|
658
|
+
},
|
|
490
659
|
then: (state, page) => {
|
|
491
660
|
if (generation !== session.loadGeneration) return state;
|
|
492
661
|
const appended = classifyThreads(page.threads, {
|
|
@@ -604,22 +773,30 @@ const useRemoteThreadList = (
|
|
|
604
773
|
throw threadNotFoundError(threadIdOrRemoteId, "switching to it");
|
|
605
774
|
}
|
|
606
775
|
if (isSameThread(store.value, data.id, session.mainThreadId)) return;
|
|
607
|
-
|
|
608
|
-
|
|
776
|
+
|
|
777
|
+
const targetId = data.id;
|
|
778
|
+
let current: RemoteThreadData | undefined = data;
|
|
779
|
+
|
|
780
|
+
if (current.status === "archived" && options?.unarchive !== false) {
|
|
609
781
|
const { remoteId } = await current.initializeTask;
|
|
610
782
|
if (generation !== session.switchGeneration) return;
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
783
|
+
current = getThreadData(store.value, targetId);
|
|
784
|
+
if (current?.id !== targetId) return;
|
|
785
|
+
if (current.status === "archived") {
|
|
786
|
+
await store.optimisticUpdate({
|
|
787
|
+
execute: () => session.adapter.unarchive(remoteId),
|
|
788
|
+
optimistic: (state) =>
|
|
789
|
+
updateStatusReducer(state, targetId, "regular"),
|
|
790
|
+
});
|
|
791
|
+
if (generation !== session.switchGeneration) return;
|
|
792
|
+
current = getThreadData(store.value, targetId);
|
|
793
|
+
if (current?.id !== targetId) return;
|
|
794
|
+
}
|
|
618
795
|
}
|
|
619
796
|
if (generation !== session.switchGeneration) return;
|
|
620
|
-
assignMainThreadId(
|
|
621
|
-
notifyRemoteId(
|
|
622
|
-
session.onSwitchToThread?.(
|
|
797
|
+
assignMainThreadId(current.id);
|
|
798
|
+
notifyRemoteId(current.remoteId, emitThreadIdChange);
|
|
799
|
+
session.onSwitchToThread?.(current.id);
|
|
623
800
|
}),
|
|
624
801
|
[assignMainThreadId, notifyRemoteId, session, startSwitch, store],
|
|
625
802
|
);
|
|
@@ -728,21 +905,36 @@ const useRemoteThreadList = (
|
|
|
728
905
|
const data = getThreadData(state, threadId);
|
|
729
906
|
if (!data) return state;
|
|
730
907
|
const mappingId = createThreadMappingId(threadId);
|
|
908
|
+
// A list() response that landed while this initialize was in flight
|
|
909
|
+
// could not know the remote id yet, so it may have minted its own
|
|
910
|
+
// slot for it; that slot collapses into this one.
|
|
911
|
+
const listedMappingId = state.threadIdMap[remoteId];
|
|
912
|
+
const orphan =
|
|
913
|
+
listedMappingId !== undefined && listedMappingId !== mappingId
|
|
914
|
+
? state.threadData[listedMappingId]
|
|
915
|
+
: undefined;
|
|
916
|
+
|
|
917
|
+
const threadData = { ...state.threadData };
|
|
918
|
+
if (orphan !== undefined) delete threadData[listedMappingId!];
|
|
919
|
+
threadData[mappingId] = {
|
|
920
|
+
...data,
|
|
921
|
+
initializeTask: Promise.resolve({ remoteId, externalId }),
|
|
922
|
+
remoteId,
|
|
923
|
+
externalId,
|
|
924
|
+
} as RemoteThreadData;
|
|
925
|
+
|
|
926
|
+
const rewire = (ids: readonly string[]) =>
|
|
927
|
+
orphan === undefined ? ids : ids.filter((id) => id !== orphan.id);
|
|
928
|
+
|
|
731
929
|
return {
|
|
732
930
|
...state,
|
|
931
|
+
threadIds: rewire(state.threadIds),
|
|
932
|
+
archivedThreadIds: rewire(state.archivedThreadIds),
|
|
733
933
|
threadIdMap: {
|
|
734
934
|
...state.threadIdMap,
|
|
735
935
|
[remoteId]: mappingId,
|
|
736
936
|
},
|
|
737
|
-
threadData
|
|
738
|
-
...state.threadData,
|
|
739
|
-
[mappingId]: {
|
|
740
|
-
...data,
|
|
741
|
-
initializeTask: Promise.resolve({ remoteId, externalId }),
|
|
742
|
-
remoteId,
|
|
743
|
-
externalId,
|
|
744
|
-
},
|
|
745
|
-
},
|
|
937
|
+
threadData,
|
|
746
938
|
};
|
|
747
939
|
},
|
|
748
940
|
});
|
|
@@ -945,7 +1137,12 @@ const useRemoteThreadList = (
|
|
|
945
1137
|
}
|
|
946
1138
|
const { remoteId } = await data.initializeTask;
|
|
947
1139
|
requireAdapterGeneration(adapterGeneration);
|
|
948
|
-
if (
|
|
1140
|
+
if (
|
|
1141
|
+
!backgroundThreads &&
|
|
1142
|
+
!isSameThread(store.value, data.id, session.mainThreadId)
|
|
1143
|
+
) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
949
1146
|
if (!messages) return;
|
|
950
1147
|
const stream = await currentAdapter.generateTitle(remoteId, messages);
|
|
951
1148
|
requireAdapterGeneration(adapterGeneration);
|
|
@@ -970,13 +1167,23 @@ const useRemoteThreadList = (
|
|
|
970
1167
|
});
|
|
971
1168
|
});
|
|
972
1169
|
},
|
|
973
|
-
[requireAdapterGeneration, session, store],
|
|
1170
|
+
[backgroundThreads, requireAdapterGeneration, session, store],
|
|
1171
|
+
);
|
|
1172
|
+
|
|
1173
|
+
const detach = useCallback(
|
|
1174
|
+
async (threadId: string) => {
|
|
1175
|
+
await ensureNotMain(threadId);
|
|
1176
|
+
setStartedIds((prev) => prev.filter((id) => id !== threadId));
|
|
1177
|
+
},
|
|
1178
|
+
[ensureNotMain],
|
|
974
1179
|
);
|
|
975
1180
|
|
|
976
1181
|
const { mainThreadClient, itemOrder, threadListItems } =
|
|
977
1182
|
useRemoteThreadListView({
|
|
978
1183
|
listState,
|
|
979
1184
|
mainThreadId,
|
|
1185
|
+
startedIds,
|
|
1186
|
+
backgroundThreads,
|
|
980
1187
|
threadFactory,
|
|
981
1188
|
useAdapters: adapter.unstable_useAdapters,
|
|
982
1189
|
onSwitchTo: (id, options) => switchToThread(id, options),
|
|
@@ -987,7 +1194,7 @@ const useRemoteThreadList = (
|
|
|
987
1194
|
onDelete: (id) => deleteThread(id),
|
|
988
1195
|
onGenerateTitle: (id, messages) => generateTitle(id, messages),
|
|
989
1196
|
onInitialize: async (id) => toInitializeResult(await initialize(id)),
|
|
990
|
-
onDetach: (id) =>
|
|
1197
|
+
onDetach: (id) => detach(id),
|
|
991
1198
|
});
|
|
992
1199
|
|
|
993
1200
|
const mainRemoteId = getThreadData(listState, mainThreadId)?.remoteId;
|
|
@@ -1098,6 +1305,9 @@ const useRemoteThreadList = (
|
|
|
1098
1305
|
* and attachments come from `unstable_useAdapters`. `useRemoteThreadListRuntime`
|
|
1099
1306
|
* uses the same hook when `unstable_Provider` is omitted. Key the factory
|
|
1100
1307
|
* with `withKey` so history reloads when the visible thread changes.
|
|
1308
|
+
* With `backgroundThreads`, every visited thread stays mounted: runs continue
|
|
1309
|
+
* across switches, per-item `isRunning` is live, and freshly initialized
|
|
1310
|
+
* threads title themselves.
|
|
1101
1311
|
*/
|
|
1102
1312
|
export const RemoteThreadList = resource(useRemoteThreadList);
|
|
1103
1313
|
|
|
@@ -16,6 +16,7 @@ import type { Tool } from "assistant-stream";
|
|
|
16
16
|
import {
|
|
17
17
|
isStandaloneToolDisplay,
|
|
18
18
|
makeToolCallTextComponent,
|
|
19
|
+
type ToolCallText,
|
|
19
20
|
type Toolkit,
|
|
20
21
|
} from "../model-context/toolbox";
|
|
21
22
|
import type { ToolCallMessagePartComponent } from "../types/MessagePartComponentTypes";
|
|
@@ -59,12 +60,16 @@ const useTools = ({
|
|
|
59
60
|
(
|
|
60
61
|
toolName: string,
|
|
61
62
|
render: ToolCallMessagePartComponent,
|
|
62
|
-
options?: {
|
|
63
|
+
options?: {
|
|
64
|
+
standalone?: boolean;
|
|
65
|
+
renderText?: ToolCallText<any, any> | undefined;
|
|
66
|
+
},
|
|
63
67
|
) => {
|
|
64
68
|
// One registration object per call; identity is the removal key, so
|
|
65
69
|
// the per-name list stays correctly ref-counted across re-registers.
|
|
66
70
|
const registration = {
|
|
67
71
|
render,
|
|
72
|
+
renderText: options?.renderText,
|
|
68
73
|
standalone: options?.standalone ?? false,
|
|
69
74
|
};
|
|
70
75
|
|
|
@@ -105,6 +110,7 @@ const useTools = ({
|
|
|
105
110
|
unsubscribes.push(
|
|
106
111
|
setToolUI(toolName, render, {
|
|
107
112
|
standalone: isStandaloneToolDisplay(tool),
|
|
113
|
+
renderText: toolRenderText,
|
|
108
114
|
}),
|
|
109
115
|
);
|
|
110
116
|
}
|
package/src/react/index.ts
CHANGED
|
@@ -235,6 +235,10 @@ export { RemoteThreadListHookInstanceManager } from "./runtimes/RemoteThreadList
|
|
|
235
235
|
export { RemoteThreadListThreadListRuntimeCore } from "./runtimes/RemoteThreadListThreadListRuntimeCore";
|
|
236
236
|
export { useRemoteThreadListRuntime } from "./runtimes/useRemoteThreadListRuntime";
|
|
237
237
|
export { useCloudThreadListAdapter } from "./runtimes/cloud/useCloudThreadListAdapter";
|
|
238
|
+
export {
|
|
239
|
+
createCloudThreadListAdapter,
|
|
240
|
+
type CloudThreadListAdapterOptions,
|
|
241
|
+
} from "./runtimes/cloud/createCloudThreadListAdapter";
|
|
238
242
|
export { useCloudThreadListRuntime } from "./runtimes/cloud/useCloudThreadListRuntime";
|
|
239
243
|
export {
|
|
240
244
|
useAssistantTransportRuntime,
|