@assistant-ui/core 0.3.16 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/attachment.d.ts.map +1 -1
- package/dist/adapters/attachment.js +5 -4
- package/dist/adapters/attachment.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +4 -2
- package/dist/internal.js +4 -2
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +10 -4
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts +5 -0
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +101 -28
- package/dist/model-context/frame/provider.js.map +1 -1
- package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
- package/dist/model-context/interactable-composer-metadata.js +16 -9
- package/dist/model-context/interactable-composer-metadata.js.map +1 -1
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/registry.js +3 -5
- package/dist/model-context/registry.js.map +1 -1
- package/dist/model-context/tool-call-text.d.ts +26 -0
- package/dist/model-context/tool-call-text.d.ts.map +1 -0
- package/dist/model-context/tool-call-text.js +18 -0
- package/dist/model-context/tool-call-text.js.map +1 -0
- package/dist/model-context/types.d.ts.map +1 -1
- package/dist/model-context/types.js +5 -4
- package/dist/model-context/types.js.map +1 -1
- package/dist/react/RuntimeAdapter.js +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/AdaptedRemoteThread.js +1 -1
- package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
- package/dist/react/client/InMemoryThreadList.js +63 -57
- package/dist/react/client/InMemoryThreadList.js.map +1 -1
- package/dist/react/client/Interactables.d.ts.map +1 -1
- package/dist/react/client/Interactables.js +25 -28
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +16 -0
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
- package/dist/react/client/RemoteThreadList.js +354 -242
- package/dist/react/client/RemoteThreadList.js.map +1 -1
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +24 -18
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +2 -1
- package/dist/react/interactables-legacy/Interactables.js +246 -125
- package/dist/react/interactables-legacy/Interactables.js.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +11 -9
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -1
- package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
- package/dist/react/model-context/makeAssistantTool.js +1 -1
- package/dist/react/model-context/makeAssistantTool.js.map +1 -1
- package/dist/react/model-context/toolbox.d.ts +2 -14
- package/dist/react/model-context/toolbox.d.ts.map +1 -1
- package/dist/react/model-context/toolbox.js +1 -13
- package/dist/react/model-context/toolbox.js.map +1 -1
- package/dist/react/model-context/useAssistantContext.js +37 -7
- package/dist/react/model-context/useAssistantContext.js.map +1 -1
- package/dist/react/model-context/useAssistantTool.d.ts +2 -2
- package/dist/react/model-context/useAssistantTool.js +1 -1
- package/dist/react/model-context/useAssistantTool.js.map +1 -1
- package/dist/react/model-context/useAuiToolOverrides.js +31 -5
- package/dist/react/model-context/useAuiToolOverrides.js.map +1 -1
- package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
- package/dist/react/model-context/useInlineRender.js +10 -36
- package/dist/react/model-context/useInlineRender.js.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.js +2 -1
- package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
- package/dist/react/primitive-hooks/useMessageError.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useMessageError.js +2 -8
- package/dist/react/primitive-hooks/useMessageError.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.js +2 -4
- package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.js +4 -3
- package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.js +4 -3
- package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.js +7 -6
- package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.js +2 -2
- package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.js +3 -3
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.js +5 -4
- package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +6 -4
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +59 -29
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +11 -6
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +160 -143
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts +2 -6
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.js +15 -13
- package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
- package/dist/react/runtimes/assistant-transport/useLatestRef.js +2 -2
- package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +4 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +424 -52
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +5 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +29 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +160 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -0
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts +1 -9
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +16 -153
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +1 -1
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.js +75 -46
- package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.js +77 -29
- package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
- package/dist/react/types/MessagePartComponentTypes.d.ts +7 -3
- package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
- package/dist/react/types/scopes/tools.d.ts +2 -0
- package/dist/react/types/scopes/tools.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.d.ts +2 -2
- package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.js +1 -1
- package/dist/runtime/api/message-part-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts +7 -3
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.js +2 -2
- package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +12 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +23 -14
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +5 -1
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +1 -1
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +16 -12
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -2
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +8 -7
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts +12 -5
- package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +18 -3
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +15 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.d.ts +1 -1
- package/dist/runtime/utils/auto-status.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.js +6 -2
- package/dist/runtime/utils/auto-status.js.map +1 -1
- package/dist/runtime/utils/external-message-conversion.d.ts +3 -2
- package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
- package/dist/runtime/utils/external-message-conversion.js +5 -4
- package/dist/runtime/utils/external-message-conversion.js.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts +1 -0
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +15 -6
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtime/utils/resolveToolApprovalResponse.d.ts +6 -3
- package/dist/runtime/utils/resolveToolApprovalResponse.d.ts.map +1 -1
- package/dist/runtime/utils/resolveToolApprovalResponse.js +12 -3
- package/dist/runtime/utils/resolveToolApprovalResponse.js.map +1 -1
- package/dist/runtime/utils/thread-message-like.d.ts +2 -10
- package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.js +1 -1
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/runtime/utils/tool-call-tree.d.ts +39 -0
- package/dist/runtime/utils/tool-call-tree.d.ts.map +1 -0
- package/dist/runtime/utils/tool-call-tree.js +85 -0
- package/dist/runtime/utils/tool-call-tree.js.map +1 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts +29 -2
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +21 -27
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +2 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +34 -28
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -1
- package/dist/runtimes/internal.d.ts +2 -2
- package/dist/runtimes/internal.js +2 -2
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +3 -1
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +18 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.js +148 -43
- package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/title-generation.d.ts +49 -0
- package/dist/runtimes/remote-thread-list/title-generation.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/title-generation.js +197 -0
- package/dist/runtimes/remote-thread-list/title-generation.js.map +1 -0
- package/dist/runtimes/remote-thread-list/title.d.ts +11 -0
- package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/title.js +14 -0
- package/dist/runtimes/remote-thread-list/title.js.map +1 -0
- package/dist/runtimes/remote-thread-list/types.d.ts +16 -5
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +31 -8
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +97 -60
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/external-thread.d.ts +1 -1
- package/dist/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +30 -7
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/model-context-client.d.ts.map +1 -1
- package/dist/store/clients/model-context-client.js +2 -1
- package/dist/store/clients/model-context-client.js.map +1 -1
- package/dist/store/clients/single-thread-list.d.ts.map +1 -1
- package/dist/store/clients/single-thread-list.js +2 -1
- package/dist/store/clients/single-thread-list.js.map +1 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/suggestions.js +19 -6
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/clients/thread-message-client.js +1 -1
- package/dist/store/clients/thread-selection-events.js +1 -1
- package/dist/store/index.d.ts +2 -1
- package/dist/store/index.js +2 -1
- package/dist/store/internal.d.ts +2 -2
- package/dist/store/internal.js +2 -2
- package/dist/store/primitive-predicates.d.ts +4 -1
- package/dist/store/primitive-predicates.d.ts.map +1 -1
- package/dist/store/primitive-predicates.js +9 -1
- package/dist/store/primitive-predicates.js.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.js +98 -62
- package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.js +221 -144
- package/dist/store/runtime-clients/message-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +2 -2
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js +128 -107
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +194 -122
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/useSubscribable.d.ts +3 -1
- package/dist/store/runtime-clients/useSubscribable.d.ts.map +1 -1
- package/dist/store/runtime-clients/useSubscribable.js +1 -1
- package/dist/store/runtime-clients/useSubscribable.js.map +1 -1
- package/dist/store/scopes/composer.d.ts +10 -2
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/message.d.ts +30 -1
- package/dist/store/scopes/message.d.ts.map +1 -1
- package/dist/store/scopes/part.d.ts +6 -3
- package/dist/store/scopes/part.d.ts.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +2 -2
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/dist/store/scopes/thread.d.ts +8 -0
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/store/scopes/threads.d.ts +1 -0
- package/dist/store/scopes/threads.d.ts.map +1 -1
- package/dist/subscribable/subscribable.d.ts +8 -1
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +24 -16
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/types/attachment.d.ts +2 -1
- package/dist/types/attachment.d.ts.map +1 -1
- package/dist/types/attachment.js +2 -1
- package/dist/types/attachment.js.map +1 -1
- package/dist/types/message.d.ts +40 -1
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js +7 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/abortable-iterable.d.ts +19 -0
- package/dist/utils/abortable-iterable.d.ts.map +1 -0
- package/dist/utils/abortable-iterable.js +72 -0
- package/dist/utils/abortable-iterable.js.map +1 -0
- package/dist/utils/composite-context-provider.d.ts.map +1 -1
- package/dist/utils/composite-context-provider.js +20 -2
- package/dist/utils/composite-context-provider.js.map +1 -1
- package/dist/utils/record.d.ts +11 -0
- package/dist/utils/record.d.ts.map +1 -0
- package/dist/utils/record.js +12 -0
- package/dist/utils/record.js.map +1 -0
- package/package.json +12 -17
- package/src/adapters/attachment.test.ts +50 -1
- package/src/adapters/attachment.ts +7 -4
- package/src/index.ts +7 -1
- package/src/internal.ts +12 -0
- package/src/model-context/frame/host.test.ts +24 -0
- package/src/model-context/frame/host.ts +10 -4
- package/src/model-context/frame/provider.test.ts +288 -1
- package/src/model-context/frame/provider.ts +148 -30
- package/src/model-context/interactable-composer-metadata.test.ts +28 -0
- package/src/model-context/interactable-composer-metadata.ts +9 -3
- package/src/model-context/registry.test.ts +12 -0
- package/src/model-context/registry.ts +3 -2
- package/src/model-context/tool-call-text.test.ts +67 -0
- package/src/model-context/tool-call-text.ts +67 -0
- package/src/model-context/types.test.ts +25 -0
- package/src/model-context/types.ts +9 -4
- package/src/react/AssistantRuntimeProvider.test.tsx +66 -2
- package/src/react/RuntimeAdapter.test.ts +34 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +1 -3
- package/src/react/client/InMemoryThreadList.ts +1 -0
- package/src/react/client/Interactables.test.ts +28 -0
- package/src/react/client/Interactables.ts +15 -13
- package/src/react/client/RemoteThreadList.background.test.ts +526 -0
- package/src/react/client/RemoteThreadList.concurrent.test.tsx +315 -0
- package/src/react/client/RemoteThreadList.test.ts +617 -3
- package/src/react/client/RemoteThreadList.ts +433 -167
- package/src/react/client/Tools.ts +29 -12
- package/src/react/index.ts +4 -0
- package/src/react/interactables-legacy/Interactables.ts +16 -16
- package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +9 -10
- package/src/react/model-context/makeAssistantTool.ts +2 -2
- package/src/react/model-context/modelContextHooks.test.tsx +131 -0
- package/src/react/model-context/toolbox.test.ts +9 -9
- package/src/react/model-context/toolbox.ts +9 -36
- package/src/react/model-context/useAssistantContext.ts +4 -2
- package/src/react/model-context/useAssistantTool.ts +2 -2
- package/src/react/model-context/useAuiToolOverrides.ts +4 -2
- package/src/react/model-context/useInlineRender.test.tsx +48 -0
- package/src/react/model-context/useInlineRender.ts +14 -10
- package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
- package/src/react/model-context/useToolArgsStatus.ts +2 -1
- package/src/react/primitive-hooks/useMessageError.ts +2 -19
- package/src/react/primitive-hooks/useThreadListLoadMore.ts +2 -3
- package/src/react/primitives/composer/ComposerAttachments.test.tsx +76 -0
- package/src/react/primitives/composer/ComposerAttachments.tsx +9 -4
- package/src/react/primitives/composer/ComposerQueue.test.tsx +72 -0
- package/src/react/primitives/composer/ComposerQueue.tsx +7 -4
- package/src/react/primitives/message/MessageAttachments.test.tsx +107 -37
- package/src/react/primitives/message/MessageAttachments.tsx +10 -7
- package/src/react/primitives/message/MessageGroupedParts.tsx +2 -2
- package/src/react/primitives/message/MessageParts.tsx +3 -3
- package/src/react/primitives/threadList/ThreadListItems.test.tsx +99 -0
- package/src/react/primitives/threadList/ThreadListItems.tsx +8 -5
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.destroy.test.tsx +172 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +127 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +7 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +99 -35
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.load-error.test.ts +132 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +274 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +223 -152
- package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
- package/src/react/runtimes/RemoteThreadResource.ts +20 -16
- package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +51 -2
- package/src/react/runtimes/assistant-transport/useLatestRef.ts +2 -2
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +45 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +546 -5
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +546 -103
- package/src/react/runtimes/cloud/auiV0.ts +5 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +103 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +237 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +90 -1
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +33 -238
- package/src/react/runtimes/external-message-converter.ts +1 -0
- package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +41 -0
- package/src/react/runtimes/useExternalStoreRuntime.ts +10 -4
- package/src/react/runtimes/useLocalRuntime.test.tsx +20 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.concurrent.test.tsx +216 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.load-error.test.tsx +108 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +57 -6
- package/src/react/types/MessagePartComponentTypes.ts +7 -3
- package/src/react/types/scopes/tools.ts +2 -0
- package/src/runtime/api/message-part-runtime.ts +3 -3
- package/src/runtime/api/message-runtime.test.ts +75 -0
- package/src/runtime/api/thread-list-item-runtime.ts +10 -3
- package/src/runtime/api/thread-list-runtime.ts +46 -12
- package/src/runtime/api/thread-runtime.test.ts +78 -0
- package/src/runtime/api/thread-runtime.ts +8 -1
- package/src/runtime/base/base-composer-runtime-core.ts +36 -8
- package/src/runtime/base/base-thread-runtime-core.test.ts +149 -4
- package/src/runtime/base/base-thread-runtime-core.ts +16 -8
- package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
- package/src/runtime/interfaces/thread-list-runtime-core.ts +25 -2
- package/src/runtime/interfaces/thread-runtime-core.ts +17 -1
- package/src/runtime/utils/auto-status.test.ts +57 -0
- package/src/runtime/utils/auto-status.ts +13 -1
- package/src/runtime/utils/external-message-conversion.test.ts +165 -0
- package/src/runtime/utils/external-message-conversion.ts +18 -2
- package/src/runtime/utils/message-repository.ts +29 -17
- package/src/runtime/utils/resolveToolApprovalResponse.test.ts +73 -0
- package/src/runtime/utils/resolveToolApprovalResponse.ts +27 -6
- package/src/runtime/utils/thread-message-like.ts +3 -11
- package/src/runtime/utils/tool-call-tree.test.ts +191 -0
- package/src/runtime/utils/tool-call-tree.ts +97 -0
- package/src/runtimes/external-store/external-store-adapter.ts +38 -2
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +18 -13
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +56 -33
- package/src/runtimes/inert/InertThreadRuntimeCore.ts +1 -1
- package/src/runtimes/internal.ts +1 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +29 -3
- package/src/runtimes/local/local-thread-runtime-core.ts +5 -1
- package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +238 -0
- package/src/runtimes/remote-thread-list/remote-thread-state.ts +223 -44
- package/src/runtimes/remote-thread-list/title-generation.test.ts +602 -0
- package/src/runtimes/remote-thread-list/title-generation.ts +329 -0
- package/src/runtimes/remote-thread-list/title.test.ts +62 -0
- package/src/runtimes/remote-thread-list/title.ts +16 -0
- package/src/runtimes/remote-thread-list/types.ts +16 -5
- package/src/runtimes/tool-invocations/EDGE_CASES.md +110 -5
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +750 -136
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +144 -91
- package/src/store/clients/external-thread.ts +62 -11
- package/src/store/clients/model-context-client.ts +5 -1
- package/src/store/clients/single-thread-list.ts +1 -0
- package/src/store/clients/suggestions.test.ts +195 -1
- package/src/store/clients/suggestions.ts +45 -34
- package/src/store/index.ts +4 -0
- package/src/store/internal.ts +2 -0
- package/src/store/primitive-predicates.ts +35 -0
- package/src/store/runtime-clients/composer-runtime-client.ts +42 -9
- package/src/store/runtime-clients/message-runtime-client.ts +54 -6
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +4 -2
- package/src/store/runtime-clients/thread-list-runtime-client.ts +17 -2
- package/src/store/runtime-clients/thread-runtime-client.ts +58 -10
- package/src/store/runtime-clients/useSubscribable.ts +8 -2
- package/src/store/scopes/composer.ts +16 -4
- package/src/store/scopes/message.ts +14 -0
- package/src/store/scopes/part.ts +6 -3
- package/src/store/scopes/thread-list-item.ts +5 -2
- package/src/store/scopes/thread.ts +4 -0
- package/src/store/scopes/threads.ts +1 -0
- package/src/subscribable/subscribable.test.ts +50 -0
- package/src/subscribable/subscribable.ts +33 -21
- package/src/tests/MessageRepository.test.ts +116 -0
- package/src/tests/OptimisticState-list-race.test.ts +1 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-initialize-adapter-change.test.ts +38 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +158 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +78 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +52 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +89 -0
- package/src/tests/attachment-adapters.test.ts +14 -0
- package/src/tests/base-composer-runtime-core.test.ts +39 -0
- package/src/tests/external-store-optimistic-id.test.ts +79 -0
- package/src/tests/external-store-repository-instance.test.ts +166 -0
- package/src/tests/external-store-thread-list-runtime-core.test.ts +83 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +49 -34
- package/src/tests/external-thread-attachments.test.tsx +224 -1
- package/src/tests/external-thread-parity.test.tsx +23 -0
- package/src/tests/remote-thread-list-adapter-switch.test.ts +66 -1
- package/src/tests/remote-thread-list-isLoading.test.ts +1 -0
- package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
- package/src/tests/thread-switch-events.test.tsx +475 -2
- package/src/tests/tools-scope-migration.test.tsx +28 -0
- package/src/types/attachment.ts +4 -0
- package/src/types/message.ts +50 -2
- package/src/utils/abortable-iterable.test.ts +213 -0
- package/src/utils/abortable-iterable.ts +93 -0
- package/src/utils/composite-context-provider.test.ts +25 -0
- package/src/utils/composite-context-provider.ts +23 -2
- package/src/utils/record.test.ts +48 -0
- package/src/utils/record.ts +11 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
export type ThreadTitleClaim = {
|
|
2
|
+
readonly title: string;
|
|
3
|
+
readonly order: number;
|
|
4
|
+
readonly settled: Promise<boolean>;
|
|
5
|
+
readonly settle: (renamed: boolean) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type ThreadTitleGeneration = {
|
|
9
|
+
readonly automatic: boolean;
|
|
10
|
+
readonly order: number;
|
|
11
|
+
claim: ThreadTitleClaim | null;
|
|
12
|
+
beforeGenerationClaims: readonly ThreadTitleClaim[];
|
|
13
|
+
superseded: boolean;
|
|
14
|
+
readonly persisted: Promise<string | undefined>;
|
|
15
|
+
readonly settlePersisted: (title: string | undefined) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ThreadTitleState = {
|
|
19
|
+
generations: Set<ThreadTitleGeneration>;
|
|
20
|
+
pendingClaim: ThreadTitleClaim | null;
|
|
21
|
+
inFlightClaims: Set<ThreadTitleClaim>;
|
|
22
|
+
manualTitle: string | undefined;
|
|
23
|
+
latestExplicit: ThreadTitleGeneration | null;
|
|
24
|
+
nextOrder: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type ThreadTitleGenerationRun = {
|
|
28
|
+
states: Map<string, ThreadTitleState>;
|
|
29
|
+
threadId: string;
|
|
30
|
+
automatic: boolean;
|
|
31
|
+
generate: (
|
|
32
|
+
onTitle: (title: string | undefined) => Promise<void>,
|
|
33
|
+
) => Promise<void>;
|
|
34
|
+
rename: (title: string) => Promise<void>;
|
|
35
|
+
applyTitle: (title: string | undefined) => Promise<void>;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function getThreadTitleState(
|
|
39
|
+
states: Map<string, ThreadTitleState>,
|
|
40
|
+
threadId: string,
|
|
41
|
+
): ThreadTitleState {
|
|
42
|
+
let state = states.get(threadId);
|
|
43
|
+
if (state === undefined) {
|
|
44
|
+
state = {
|
|
45
|
+
generations: new Set(),
|
|
46
|
+
pendingClaim: null,
|
|
47
|
+
inFlightClaims: new Set(),
|
|
48
|
+
manualTitle: undefined,
|
|
49
|
+
latestExplicit: null,
|
|
50
|
+
nextOrder: 0,
|
|
51
|
+
};
|
|
52
|
+
states.set(threadId, state);
|
|
53
|
+
}
|
|
54
|
+
return state;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function pruneThreadTitleState(
|
|
58
|
+
states: Map<string, ThreadTitleState>,
|
|
59
|
+
threadId: string,
|
|
60
|
+
state: ThreadTitleState,
|
|
61
|
+
): void {
|
|
62
|
+
if (
|
|
63
|
+
state.generations.size === 0 &&
|
|
64
|
+
state.pendingClaim === null &&
|
|
65
|
+
state.inFlightClaims.size === 0 &&
|
|
66
|
+
state.manualTitle === undefined &&
|
|
67
|
+
states.get(threadId) === state
|
|
68
|
+
) {
|
|
69
|
+
states.delete(threadId);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isCurrentGeneration(
|
|
74
|
+
state: ThreadTitleState,
|
|
75
|
+
generation: ThreadTitleGeneration,
|
|
76
|
+
): boolean {
|
|
77
|
+
return (
|
|
78
|
+
!generation.superseded &&
|
|
79
|
+
(state.latestExplicit?.order ?? 0) <= generation.order
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isCurrentClaim(
|
|
84
|
+
state: ThreadTitleState,
|
|
85
|
+
claim: ThreadTitleClaim,
|
|
86
|
+
): boolean {
|
|
87
|
+
return (state.latestExplicit?.order ?? 0) < claim.order;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function startThreadTitleRename(
|
|
91
|
+
states: Map<string, ThreadTitleState>,
|
|
92
|
+
threadId: string,
|
|
93
|
+
title: string,
|
|
94
|
+
): ThreadTitleClaim {
|
|
95
|
+
const state = getThreadTitleState(states, threadId);
|
|
96
|
+
let settle!: (renamed: boolean) => void;
|
|
97
|
+
const settled = new Promise<boolean>((resolve) => {
|
|
98
|
+
settle = resolve;
|
|
99
|
+
});
|
|
100
|
+
const claim: ThreadTitleClaim = {
|
|
101
|
+
title,
|
|
102
|
+
order: ++state.nextOrder,
|
|
103
|
+
settled,
|
|
104
|
+
settle,
|
|
105
|
+
};
|
|
106
|
+
state.pendingClaim = claim;
|
|
107
|
+
state.inFlightClaims.add(claim);
|
|
108
|
+
for (const generation of state.generations) {
|
|
109
|
+
if (generation.order < claim.order) generation.claim = claim;
|
|
110
|
+
}
|
|
111
|
+
return claim;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function finishThreadTitleRename(
|
|
115
|
+
states: Map<string, ThreadTitleState>,
|
|
116
|
+
threadId: string,
|
|
117
|
+
claim: ThreadTitleClaim,
|
|
118
|
+
renamed: boolean,
|
|
119
|
+
): void {
|
|
120
|
+
claim.settle(renamed);
|
|
121
|
+
const state = states.get(threadId);
|
|
122
|
+
if (state === undefined) return;
|
|
123
|
+
state.inFlightClaims.delete(claim);
|
|
124
|
+
if (state.pendingClaim === claim) {
|
|
125
|
+
state.pendingClaim = null;
|
|
126
|
+
if (renamed) {
|
|
127
|
+
state.manualTitle = claim.title;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
pruneThreadTitleState(states, threadId, state);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function takeManualTitle(
|
|
134
|
+
states: Map<string, ThreadTitleState>,
|
|
135
|
+
threadId: string,
|
|
136
|
+
state: ThreadTitleState,
|
|
137
|
+
): string | undefined {
|
|
138
|
+
const retained = state.manualTitle;
|
|
139
|
+
if (retained === undefined) return undefined;
|
|
140
|
+
state.manualTitle = undefined;
|
|
141
|
+
pruneThreadTitleState(states, threadId, state);
|
|
142
|
+
return retained;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function clearThreadTitleState(
|
|
146
|
+
states: Map<string, ThreadTitleState>,
|
|
147
|
+
threadId: string,
|
|
148
|
+
): void {
|
|
149
|
+
states.delete(threadId);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function startThreadTitleGeneration(
|
|
153
|
+
states: Map<string, ThreadTitleState>,
|
|
154
|
+
threadId: string,
|
|
155
|
+
automatic: boolean,
|
|
156
|
+
): ThreadTitleGeneration | null {
|
|
157
|
+
const state = getThreadTitleState(states, threadId);
|
|
158
|
+
if (
|
|
159
|
+
automatic &&
|
|
160
|
+
state.pendingClaim === null &&
|
|
161
|
+
takeManualTitle(states, threadId, state) !== undefined
|
|
162
|
+
) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let settlePersisted!: (title: string | undefined) => void;
|
|
167
|
+
const persisted = new Promise<string | undefined>((resolve) => {
|
|
168
|
+
settlePersisted = resolve;
|
|
169
|
+
});
|
|
170
|
+
const generation: ThreadTitleGeneration = {
|
|
171
|
+
automatic,
|
|
172
|
+
order: ++state.nextOrder,
|
|
173
|
+
claim: automatic ? state.pendingClaim : null,
|
|
174
|
+
beforeGenerationClaims: automatic ? [] : [...state.inFlightClaims],
|
|
175
|
+
superseded: false,
|
|
176
|
+
persisted,
|
|
177
|
+
settlePersisted,
|
|
178
|
+
};
|
|
179
|
+
if (!automatic) {
|
|
180
|
+
state.pendingClaim = null;
|
|
181
|
+
state.manualTitle = undefined;
|
|
182
|
+
state.latestExplicit = generation;
|
|
183
|
+
for (const active of state.generations) {
|
|
184
|
+
if (active.automatic) active.superseded = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
state.generations.add(generation);
|
|
188
|
+
return generation;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Runs one title generation under the per-thread rename claims and generation
|
|
193
|
+
* ordering, so the title that wins locally is also the title left on the
|
|
194
|
+
* server.
|
|
195
|
+
*
|
|
196
|
+
* A generated run persists the title itself, and the adapter exposes no
|
|
197
|
+
* compare-and-set, so the run that loses reasserts the winner through `rename`
|
|
198
|
+
* only after `generate` has resolved. Reasserting mid-stream would race the
|
|
199
|
+
* run's own write and lose the winning title on the server.
|
|
200
|
+
*/
|
|
201
|
+
export async function runThreadTitleGeneration({
|
|
202
|
+
states,
|
|
203
|
+
threadId,
|
|
204
|
+
automatic,
|
|
205
|
+
generate,
|
|
206
|
+
rename,
|
|
207
|
+
applyTitle,
|
|
208
|
+
}: ThreadTitleGenerationRun): Promise<void> {
|
|
209
|
+
const state = getThreadTitleState(states, threadId);
|
|
210
|
+
const generation = startThreadTitleGeneration(states, threadId, automatic);
|
|
211
|
+
if (generation === null) return;
|
|
212
|
+
|
|
213
|
+
let persistedTitle: string | undefined;
|
|
214
|
+
let persistedOrder = generation.order;
|
|
215
|
+
|
|
216
|
+
const settleClaim = async (claim: ThreadTitleClaim) => {
|
|
217
|
+
const renamed = await claim.settled;
|
|
218
|
+
if (generation.claim !== claim) return undefined;
|
|
219
|
+
if (!renamed) {
|
|
220
|
+
generation.claim = null;
|
|
221
|
+
if (state.pendingClaim === claim) state.pendingClaim = null;
|
|
222
|
+
}
|
|
223
|
+
return renamed;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const retainManualTitle = () =>
|
|
227
|
+
automatic && takeManualTitle(states, threadId, state) !== undefined;
|
|
228
|
+
|
|
229
|
+
// `generate` resolves only once the run has persisted its title, so a run
|
|
230
|
+
// that lost the ordering race while it streamed has already overwritten the
|
|
231
|
+
// winner. It waits for the winning generation to persist its own title and
|
|
232
|
+
// writes that title back.
|
|
233
|
+
const repairLostRace = async () => {
|
|
234
|
+
if (persistedTitle === undefined) return;
|
|
235
|
+
while (true) {
|
|
236
|
+
const claim = generation.claim;
|
|
237
|
+
if (
|
|
238
|
+
claim !== null &&
|
|
239
|
+
claim.order > persistedOrder &&
|
|
240
|
+
isCurrentClaim(state, claim)
|
|
241
|
+
) {
|
|
242
|
+
const renamed = await settleClaim(claim);
|
|
243
|
+
if (renamed === true) {
|
|
244
|
+
persistedTitle = claim.title;
|
|
245
|
+
persistedOrder = claim.order;
|
|
246
|
+
await rename(claim.title);
|
|
247
|
+
}
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const winner = state.latestExplicit;
|
|
251
|
+
if (winner === null || winner.order <= persistedOrder) return;
|
|
252
|
+
const title = await winner.persisted;
|
|
253
|
+
if (state.latestExplicit !== winner) continue;
|
|
254
|
+
persistedOrder = winner.order;
|
|
255
|
+
if (title === undefined || title === persistedTitle) return;
|
|
256
|
+
persistedTitle = title;
|
|
257
|
+
await rename(title);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const runGeneration = async () => {
|
|
262
|
+
// An explicit generation waits for every earlier rename because any of
|
|
263
|
+
// those server writes may settle last.
|
|
264
|
+
if (generation.beforeGenerationClaims.length > 0) {
|
|
265
|
+
await Promise.all(
|
|
266
|
+
generation.beforeGenerationClaims.map((claim) => claim.settled),
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
if (generation.claim !== null) {
|
|
270
|
+
const renamed = await settleClaim(generation.claim);
|
|
271
|
+
if (renamed === true) {
|
|
272
|
+
generation.superseded = true;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (renamed === false && retainManualTitle()) return;
|
|
276
|
+
}
|
|
277
|
+
if (!isCurrentGeneration(state, generation)) return;
|
|
278
|
+
|
|
279
|
+
let sawTitle = false;
|
|
280
|
+
let lastTitle: string | undefined;
|
|
281
|
+
await generate(async (title) => {
|
|
282
|
+
sawTitle = true;
|
|
283
|
+
lastTitle = title;
|
|
284
|
+
if (title !== undefined) persistedTitle = title;
|
|
285
|
+
const claim = generation.claim;
|
|
286
|
+
if (claim !== null) {
|
|
287
|
+
const renamed = await settleClaim(claim);
|
|
288
|
+
if (renamed !== false) return;
|
|
289
|
+
if (retainManualTitle()) {
|
|
290
|
+
generation.superseded = true;
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (isCurrentGeneration(state, generation)) await applyTitle(lastTitle);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
while (true) {
|
|
298
|
+
const claim = generation.claim;
|
|
299
|
+
if (claim === null) return;
|
|
300
|
+
const renamed = await settleClaim(claim);
|
|
301
|
+
if (renamed === undefined) continue;
|
|
302
|
+
if (renamed === false) {
|
|
303
|
+
if (retainManualTitle()) return;
|
|
304
|
+
if (sawTitle && isCurrentGeneration(state, generation)) {
|
|
305
|
+
await applyTitle(lastTitle);
|
|
306
|
+
}
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (!isCurrentClaim(state, claim)) return;
|
|
310
|
+
await rename(claim.title);
|
|
311
|
+
persistedTitle = claim.title;
|
|
312
|
+
persistedOrder = claim.order;
|
|
313
|
+
if (generation.claim !== claim) continue;
|
|
314
|
+
if (!isCurrentGeneration(state, generation)) return;
|
|
315
|
+
await applyTitle(claim.title);
|
|
316
|
+
generation.superseded = true;
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
await runGeneration();
|
|
323
|
+
await repairLostRace();
|
|
324
|
+
} finally {
|
|
325
|
+
generation.settlePersisted(persistedTitle);
|
|
326
|
+
state.generations.delete(generation);
|
|
327
|
+
pruneThreadTitleState(states, threadId, state);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { applyTitleStream } from "./title";
|
|
3
|
+
|
|
4
|
+
const createTextStream = (text: string) =>
|
|
5
|
+
new ReadableStream({
|
|
6
|
+
start(controller) {
|
|
7
|
+
controller.enqueue({
|
|
8
|
+
type: "part-start",
|
|
9
|
+
path: [0],
|
|
10
|
+
part: { type: "text" },
|
|
11
|
+
});
|
|
12
|
+
controller.enqueue({
|
|
13
|
+
type: "text-delta",
|
|
14
|
+
path: [0],
|
|
15
|
+
textDelta: text,
|
|
16
|
+
});
|
|
17
|
+
controller.enqueue({ type: "part-finish", path: [0] });
|
|
18
|
+
controller.close();
|
|
19
|
+
},
|
|
20
|
+
}) as never;
|
|
21
|
+
|
|
22
|
+
describe("applyTitleStream", () => {
|
|
23
|
+
it("ignores an empty stream", async () => {
|
|
24
|
+
const titles: (string | undefined)[] = [];
|
|
25
|
+
|
|
26
|
+
await applyTitleStream(
|
|
27
|
+
new ReadableStream({
|
|
28
|
+
start(controller) {
|
|
29
|
+
controller.close();
|
|
30
|
+
},
|
|
31
|
+
}) as never,
|
|
32
|
+
async (title) => {
|
|
33
|
+
titles.push(title);
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
expect(titles).toEqual([]);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("ignores whitespace-only titles", async () => {
|
|
41
|
+
const titles: (string | undefined)[] = [];
|
|
42
|
+
|
|
43
|
+
await applyTitleStream(createTextStream(" "), async (title) => {
|
|
44
|
+
titles.push(title);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(titles).toEqual([]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("forwards titles containing text unchanged", async () => {
|
|
51
|
+
const titles: (string | undefined)[] = [];
|
|
52
|
+
|
|
53
|
+
await applyTitleStream(
|
|
54
|
+
createTextStream(" Generated title "),
|
|
55
|
+
async (title) => {
|
|
56
|
+
titles.push(title);
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(titles).toContain(" Generated title ");
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AssistantMessageStream } from "assistant-stream";
|
|
2
|
+
|
|
3
|
+
export const isTitleSourceMessage = (message: {
|
|
4
|
+
status?: { type: string } | undefined;
|
|
5
|
+
}) => message.status?.type !== "running";
|
|
6
|
+
|
|
7
|
+
export const applyTitleStream = async (
|
|
8
|
+
stream: Parameters<typeof AssistantMessageStream.fromAssistantStream>[0],
|
|
9
|
+
onTitle: (title: string | undefined) => Promise<void>,
|
|
10
|
+
) => {
|
|
11
|
+
const messageStream = AssistantMessageStream.fromAssistantStream(stream);
|
|
12
|
+
for await (const result of messageStream) {
|
|
13
|
+
const title = result.parts.filter((part) => part.type === "text")[0]?.text;
|
|
14
|
+
if (title?.trim()) await onTitle(title);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -3,6 +3,7 @@ import type { AssistantRuntime } from "../../runtime/api/assistant-runtime";
|
|
|
3
3
|
import type { AssistantStream } from "assistant-stream";
|
|
4
4
|
import type { ThreadHistoryAdapter } from "../../adapters/thread-history";
|
|
5
5
|
import type { AttachmentAdapter } from "../../adapters/attachment";
|
|
6
|
+
import type { FeedbackAdapter } from "../../adapters/feedback";
|
|
6
7
|
import type { ModelContextProvider } from "../../model-context/types";
|
|
7
8
|
|
|
8
9
|
/* oxlint-disable typescript/no-explicit-any -- structural stand-in for ComponentType without depending on react types */
|
|
@@ -40,6 +41,7 @@ export type RuntimeAdapters = {
|
|
|
40
41
|
modelContext?: ModelContextProvider | undefined;
|
|
41
42
|
history?: ThreadHistoryAdapter | undefined;
|
|
42
43
|
attachments?: AttachmentAdapter | undefined;
|
|
44
|
+
feedback?: FeedbackAdapter | undefined;
|
|
43
45
|
};
|
|
44
46
|
|
|
45
47
|
export type RemoteThreadListAdapter = {
|
|
@@ -54,6 +56,14 @@ export type RemoteThreadListAdapter = {
|
|
|
54
56
|
unarchive(remoteId: string): Promise<void>;
|
|
55
57
|
delete(remoteId: string): Promise<void>;
|
|
56
58
|
initialize(threadId: string): Promise<RemoteThreadInitializeResponse>;
|
|
59
|
+
/**
|
|
60
|
+
* Generates a title for the thread and streams it back.
|
|
61
|
+
*
|
|
62
|
+
* When the generation persists the title itself, the returned stream must
|
|
63
|
+
* not complete before that write has landed. Concurrent generations are
|
|
64
|
+
* ordered by stream completion, and a run whose write outlives its stream
|
|
65
|
+
* can overwrite a newer title.
|
|
66
|
+
*/
|
|
57
67
|
generateTitle(
|
|
58
68
|
remoteId: string,
|
|
59
69
|
unstable_messages: readonly ThreadMessage[],
|
|
@@ -78,11 +88,12 @@ export type RemoteThreadListAdapter = {
|
|
|
78
88
|
unstable_Provider?: RemoteThreadListProviderComponent | undefined;
|
|
79
89
|
|
|
80
90
|
/**
|
|
81
|
-
* Hook the `RemoteThreadList` store entry calls once
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
91
|
+
* Hook the `RemoteThreadList` store entry calls once per mounted thread
|
|
92
|
+
* body (the main-thread slot by default; every started thread with
|
|
93
|
+
* `backgroundThreads`), then provides to the `thread` factory. This is not
|
|
94
|
+
* mounted per listed thread. `useRemoteThreadListRuntime` also calls it
|
|
95
|
+
* when `unstable_Provider` is omitted. Resolve `threadListItem` lazily on
|
|
96
|
+
* each adapter call; do not capture it at hook mount. The hook must keep a
|
|
86
97
|
* stable hook count across adapter swaps; a different count throws.
|
|
87
98
|
* Memoize the returned object.
|
|
88
99
|
*
|
|
@@ -11,8 +11,9 @@ observe via `setState(snapshot)` and what the current behavior is.
|
|
|
11
11
|
> result is replaced, result is cleared, key order shuffles — the tracker
|
|
12
12
|
> never invokes the host's tool callback a second time.
|
|
13
13
|
>
|
|
14
|
-
> `reset()` starts a new execution boundary
|
|
15
|
-
>
|
|
14
|
+
> `reset()` starts a new execution boundary, and so does the single
|
|
15
|
+
> pipeline restart after a stream failure (F.4). A reused `toolCallId` in
|
|
16
|
+
> the next boundary gets a new execution identity and may fire once there.
|
|
16
17
|
|
|
17
18
|
This guarantees host-side side effects (the typical reason `streamCall` /
|
|
18
19
|
`execute` exists at all) can't double-run. The cost: post-completion
|
|
@@ -92,8 +93,102 @@ in-flight `execute` resolves, the execute runs to completion (its side
|
|
|
92
93
|
effects happen) but its result chunk is dropped: `onResult` never fires,
|
|
93
94
|
and the `executing` status, plus any `human()` interrupt the execution
|
|
94
95
|
parked, stays up until the promise settles. Only a gate that lands after
|
|
95
|
-
the result chunk has already been emitted is fully too late
|
|
96
|
-
|
|
96
|
+
the result chunk has already been emitted is fully too late.
|
|
97
|
+
|
|
98
|
+
A call the adapter reports as client-owned reaches that window while the
|
|
99
|
+
run is still open; a call whose ownership is unknown reaches it when the
|
|
100
|
+
run settles before the gate arrives (A.10). Either way the client was
|
|
101
|
+
meant to run it, so nothing but the gate's arrival says otherwise and the
|
|
102
|
+
gate is late by construction.
|
|
103
|
+
|
|
104
|
+
### A.9. Adapter reports the tool call as provider-owned
|
|
105
|
+
The entry is marked `skipExecute` at creation, exactly like a call
|
|
106
|
+
observed with a `result`. `unstable_isClientToolCall` is read once, when
|
|
107
|
+
the call is first observed live, and never re-read: ownership is fixed
|
|
108
|
+
when the provider emits the call, so a later snapshot cannot revoke it
|
|
109
|
+
and drop the result of an execute already in flight. `streamCall` still
|
|
110
|
+
fires once, as under A.8; only the wrapped `execute` and its result
|
|
111
|
+
chunk are withheld.
|
|
112
|
+
|
|
113
|
+
Outside production, a provider-owned call whose name resolves to a tool
|
|
114
|
+
with an `execute` logs a `console.warn`. The two together are a
|
|
115
|
+
misconfiguration: the provider answers the call, so the registered
|
|
116
|
+
`execute` would never run and the skip is otherwise silent.
|
|
117
|
+
|
|
118
|
+
The predicate is also what licenses running a frontend tool before the
|
|
119
|
+
provider's run ends, so an adapter that supplies it keeps the overlap
|
|
120
|
+
between a client tool's work and the run tail (A.10).
|
|
121
|
+
|
|
122
|
+
### A.10. Args complete while the provider's run is still open
|
|
123
|
+
Closing the args stream hands the call to the client executor, so it may
|
|
124
|
+
only happen once the provider can no longer speak about that call. A
|
|
125
|
+
provider may still answer the call (A.5) or gate it (A.8) one or more
|
|
126
|
+
snapshots after its arguments complete, and a protocol can carry the
|
|
127
|
+
outcome no earlier: AG-UI projects an interrupt only from `RUN_FINISHED`.
|
|
128
|
+
The run ending is the only universal signal, so a call whose ownership is
|
|
129
|
+
unknown closes when the snapshot's `isRunning` goes false.
|
|
130
|
+
|
|
131
|
+
`ExternalStoreThreadRuntimeCore` feeds the tracker
|
|
132
|
+
`store.isRunning || _hasExecutingTools(store)`, so that condition also covers
|
|
133
|
+
a client tool mid-`execute`. That defers an unknown-ownership sibling only
|
|
134
|
+
while a client-owned call is actually executing, which no shipped adapter
|
|
135
|
+
produces: every entry pending in a snapshot closes in the same
|
|
136
|
+
`_processMessages` pass, an adapter that supplies the predicate classifies
|
|
137
|
+
every call, and an execution parked on `human()` reports `interrupt` rather
|
|
138
|
+
than `executing`, which `_hasExecutingTools` does not count.
|
|
139
|
+
|
|
140
|
+
That holds even when `execute` opens with `await human()`. The stream
|
|
141
|
+
fires `onExecutionStart` only after `execute` returns, because until then
|
|
142
|
+
it cannot tell a frontend tool from one without an `execute`, so by the
|
|
143
|
+
time the callback runs the body has already parked its resolver and set
|
|
144
|
+
`interrupt`. `_onExecutionStart` still registers the execution for
|
|
145
|
+
`_onExecutionEnd` but leaves the status alone when this execution's own
|
|
146
|
+
request is pending. The check is keyed on the request's execution id,
|
|
147
|
+
not on the status map: a pipeline restart (F.4) clears `_executing` but
|
|
148
|
+
keeps the status map, and a stale `interrupt` must not stop the fresh
|
|
149
|
+
execution from reporting `executing` (#6763).
|
|
150
|
+
|
|
151
|
+
A call the adapter reports as client-owned (A.9) closes as soon as its
|
|
152
|
+
arguments parse, because the adapter has already said the provider will
|
|
153
|
+
not answer it. Ownership says who answers a call, not whether it is
|
|
154
|
+
gated, so a gate on such a call is still late and A.8 governs it
|
|
155
|
+
(#6677).
|
|
156
|
+
|
|
157
|
+
### A.11. The turn is discarded while a call waits on the run
|
|
158
|
+
`abort({ discardPending: true })` records every active entry that has
|
|
159
|
+
neither closed its args stream nor holds a result in
|
|
160
|
+
`_discardedToolCallIds`, and marks it `skipExecute`.
|
|
161
|
+
|
|
162
|
+
The abort signal alone does not cover these. A call waiting on the run to
|
|
163
|
+
settle (A.10) has not reached the executor, so there is nothing to signal,
|
|
164
|
+
and `abort()` installs a fresh `AbortController` before the settled
|
|
165
|
+
snapshot arrives; without the record, cancelling a run would be what
|
|
166
|
+
starts the call it was meant to stop.
|
|
167
|
+
|
|
168
|
+
`discardPending` is the caller's claim that the turn is over, not that it
|
|
169
|
+
is being interrupted, so only the three callers that end it pass it: a new
|
|
170
|
+
turn starting, a reload, and `cancelRun`. `deleteMessage` does not: its
|
|
171
|
+
`setMessages` fallback aborts while the provider run continues, and
|
|
172
|
+
discarding there would strand that run's remaining calls result-less,
|
|
173
|
+
while its `onDelete` path never aborts at all. `reset()` is unaffected
|
|
174
|
+
either way: it clears `_entries` and the recorded ids before aborting,
|
|
175
|
+
because it opens a new execution boundary.
|
|
176
|
+
|
|
177
|
+
An id is forgotten once a live snapshot observes the call with a result,
|
|
178
|
+
which bounds the set to the open calls of a discarded turn. That is all
|
|
179
|
+
it does: an id re-emitted inside the same execution boundary keeps its
|
|
180
|
+
existing entry, so A.4 and A.7 govern it rather than this set, and a new
|
|
181
|
+
boundary clears the set outright. The residual is a call that is
|
|
182
|
+
discarded, answered, and then loses its result (A.7) across a pipeline
|
|
183
|
+
restart; it is left to A.7 rather than pinned here, because holding the
|
|
184
|
+
id past the answer would trade a five-step chain for a set that grows for
|
|
185
|
+
the life of the tracker.
|
|
186
|
+
|
|
187
|
+
The record lives on the tracker rather than the entry because it is the one
|
|
188
|
+
reason to skip that no later snapshot carries: an `approval` is re-read at
|
|
189
|
+
each snapshot and provider ownership is recomputed, while a rebuilt entry
|
|
190
|
+
would otherwise come back clean. That is what lets F.4 drop a waiting entry
|
|
191
|
+
without a special case.
|
|
97
192
|
|
|
98
193
|
## B. Tool call disappears from snapshot
|
|
99
194
|
|
|
@@ -193,7 +288,17 @@ The `.pipeTo(...).catch(...)` handler logs and flips `_pipelineDead`.
|
|
|
193
288
|
The next `setState` call recreates the pipeline once per tracker
|
|
194
289
|
lifetime: existing active entries are *demoted to restored* (so the
|
|
195
290
|
rebuilt pipeline does not re-fire `streamCall` for them) and the
|
|
196
|
-
snapshot is processed against the fresh pipeline.
|
|
291
|
+
snapshot is processed against the fresh pipeline. An active entry that
|
|
292
|
+
neither closed its args stream nor holds a result is dropped instead of
|
|
293
|
+
demoted: a restored entry is promoted only when its signature changes,
|
|
294
|
+
and a call waiting on the run to settle (A.10) already holds its final
|
|
295
|
+
args, so demoting it would strand it unexecuted.
|
|
296
|
+
|
|
297
|
+
Starting it over re-fires `streamCall`, which the restart path already
|
|
298
|
+
does for any demoted entry whose signature later changes. The rebuilt
|
|
299
|
+
pipeline holds no part for the call, so nothing can reach the executor
|
|
300
|
+
without adding one; a restart is an execution boundary in the same sense
|
|
301
|
+
`reset()` is. Repeated failures
|
|
197
302
|
keep the tracker dead with a visible error to avoid restart loops.
|
|
198
303
|
|
|
199
304
|
### F.5. Reset followed by same-id reuse
|