@assistant-ui/core 0.3.17 → 0.3.19
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/adapters/speech.d.ts.map +1 -1
- package/dist/adapters/speech.js +13 -3
- package/dist/adapters/speech.js.map +1 -1
- package/dist/adapters/thread-history.d.ts +4 -0
- package/dist/adapters/thread-history.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +4 -3
- package/dist/internal.js +3 -2
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +35 -14
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts +2 -0
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +30 -7
- 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 +27 -18
- 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/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/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +45 -7
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/DataRenderers.d.ts.map +1 -1
- package/dist/react/client/DataRenderers.js +20 -15
- package/dist/react/client/DataRenderers.js.map +1 -1
- package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
- package/dist/react/client/InMemoryThreadList.js +62 -56
- 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 +35 -32
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +1 -0
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
- package/dist/react/client/RemoteThreadList.js +154 -143
- 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 +18 -16
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/client/interactable-model-context.d.ts.map +1 -1
- package/dist/react/client/interactable-model-context.js +3 -2
- package/dist/react/client/interactable-model-context.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +2 -2
- package/dist/react/interactables-legacy/Interactables.js +242 -121
- package/dist/react/interactables-legacy/Interactables.js.map +1 -1
- package/dist/react/interactables-legacy/useAssistantInteractable.d.ts.map +1 -1
- package/dist/react/interactables-legacy/useAssistantInteractable.js +3 -0
- package/dist/react/interactables-legacy/useAssistantInteractable.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/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/useInteractable.d.ts.map +1 -1
- package/dist/react/model-context/useInteractable.js +4 -1
- package/dist/react/model-context/useInteractable.js.map +1 -1
- package/dist/react/model-context/useInteractableVersions.js +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/primitives/message/MessageGroupedParts.d.ts +11 -2
- package/dist/react/primitives/message/MessageGroupedParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.js +3 -2
- package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
- package/dist/react/primitives/part/PartMessages.d.ts +1 -0
- package/dist/react/primitives/part/PartMessages.d.ts.map +1 -1
- package/dist/react/primitives/part/PartMessages.js +1 -0
- package/dist/react/primitives/part/PartMessages.js.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/react/primitives/thread/ThreadMessages.js +6 -5
- package/dist/react/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +16 -8
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +5 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +105 -104
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts +1 -0
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.js +13 -11
- package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +5 -24
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +354 -226
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts +1 -0
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js +22 -2
- package/dist/react/runtimes/cloud/CloudFileAttachmentAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +40 -15
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +62 -15
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +2 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +6 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/sdkIdentity.d.ts +6 -0
- package/dist/react/runtimes/cloud/sdkIdentity.d.ts.map +1 -0
- package/dist/react/runtimes/cloud/sdkIdentity.js +9 -0
- package/dist/react/runtimes/cloud/sdkIdentity.js.map +1 -0
- package/dist/react/runtimes/external-message-converter.d.ts +12 -2
- package/dist/react/runtimes/external-message-converter.d.ts.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +26 -61
- 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 +64 -24
- package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
- package/dist/react/utils/groupParts.d.ts +6 -1
- package/dist/react/utils/groupParts.d.ts.map +1 -1
- package/dist/react/utils/groupParts.js +6 -0
- package/dist/react/utils/groupParts.js.map +1 -1
- package/dist/react/utils/useJSONEqual.d.ts +3 -1
- package/dist/react/utils/useJSONEqual.d.ts.map +1 -1
- package/dist/react/utils/useJSONEqual.js +6 -1
- package/dist/react/utils/useJSONEqual.js.map +1 -1
- package/dist/react/utils/useJSONSchemaDependency.d.ts +7 -0
- package/dist/react/utils/useJSONSchemaDependency.d.ts.map +1 -0
- package/dist/react/utils/useJSONSchemaDependency.js +20 -0
- package/dist/react/utils/useJSONSchemaDependency.js.map +1 -0
- 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 +3 -0
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +18 -14
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +4 -0
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +3 -6
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -0
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +62 -22
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -0
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +161 -69
- 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 +4 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +6 -0
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.d.ts +5 -0
- package/dist/runtime/queue/message-queue.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.js +61 -6
- package/dist/runtime/queue/message-queue.js.map +1 -1
- package/dist/runtime/utils/auto-status.d.ts +6 -2
- package/dist/runtime/utils/auto-status.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.js +12 -4
- package/dist/runtime/utils/auto-status.js.map +1 -1
- package/dist/runtime/utils/external-message-conversion.d.ts +16 -4
- package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
- package/dist/runtime/utils/external-message-conversion.js +49 -13
- 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 +18 -9
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtime/utils/thread-message-like.d.ts +2 -1
- package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.js +5 -3
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +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.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +8 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/internal.d.ts +3 -3
- 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 +4 -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 +130 -42
- 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 +3 -1
- package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/title.js +9 -1
- package/dist/runtimes/remote-thread-list/title.js.map +1 -1
- package/dist/runtimes/remote-thread-list/types.d.ts +10 -0
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +2 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +260 -203
- 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 +1 -0
- 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 +5 -4
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/clients/thread-tasks.d.ts +13 -0
- package/dist/store/clients/thread-tasks.d.ts.map +1 -0
- package/dist/store/clients/thread-tasks.js +69 -0
- package/dist/store/clients/thread-tasks.js.map +1 -0
- package/dist/store/index.d.ts +3 -2
- package/dist/store/index.js +3 -3
- package/dist/store/primitive-predicates.d.ts.map +1 -1
- package/dist/store/primitive-predicates.js +4 -4
- 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 +97 -61
- 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 +1 -1
- 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 +54 -52
- 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 +246 -126
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/scope-registration.d.ts +2 -0
- package/dist/store/scope-registration.d.ts.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/task.d.ts +36 -0
- package/dist/store/scopes/task.d.ts.map +1 -0
- package/dist/store/scopes/task.js +0 -0
- 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 +28 -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 +2 -1
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +23 -15
- 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/index.d.ts +2 -2
- package/dist/types/message.d.ts +8 -1
- package/dist/types/message.d.ts.map +1 -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 +88 -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/getGroupStatus.d.ts +18 -2
- package/dist/utils/getGroupStatus.d.ts.map +1 -1
- package/dist/utils/getGroupStatus.js +32 -7
- package/dist/utils/getGroupStatus.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/dist/utils/wire-media.d.ts.map +1 -1
- package/dist/utils/wire-media.js +2 -2
- package/dist/utils/wire-media.js.map +1 -1
- package/package.json +11 -11
- package/src/adapters/attachment.test.ts +50 -1
- package/src/adapters/attachment.ts +7 -4
- package/src/adapters/speech.test.ts +236 -0
- package/src/adapters/speech.ts +17 -10
- package/src/adapters/thread-history.ts +3 -0
- package/src/index.ts +2 -0
- package/src/internal.ts +4 -0
- package/src/model-context/frame/host.test.ts +137 -1
- package/src/model-context/frame/host.ts +49 -16
- package/src/model-context/frame/provider.test.ts +71 -0
- package/src/model-context/frame/provider.ts +37 -7
- package/src/model-context/interactable-composer-metadata.test.ts +58 -0
- package/src/model-context/interactable-composer-metadata.ts +19 -13
- package/src/model-context/registry.test.ts +12 -0
- package/src/model-context/registry.ts +3 -2
- package/src/model-context/types.test.ts +25 -0
- package/src/model-context/types.ts +9 -4
- package/src/react/RuntimeAdapter.test.ts +34 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.test.ts +244 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +104 -7
- package/src/react/client/DataRenderers.test.tsx +45 -0
- package/src/react/client/DataRenderers.ts +13 -9
- package/src/react/client/InMemoryThreadList.ts +1 -0
- package/src/react/client/Interactables.test.ts +72 -1
- package/src/react/client/Interactables.ts +22 -14
- package/src/react/client/RemoteThreadList.background.test.ts +148 -6
- package/src/react/client/RemoteThreadList.concurrent.test.tsx +42 -1
- package/src/react/client/RemoteThreadList.test.ts +386 -4
- package/src/react/client/RemoteThreadList.ts +181 -112
- package/src/react/client/Tools.ts +22 -11
- package/src/react/client/interactable-model-context.test.ts +44 -0
- package/src/react/client/interactable-model-context.ts +3 -2
- package/src/react/index.ts +5 -1
- package/src/react/interactables-legacy/Interactables.ts +16 -16
- package/src/react/interactables-legacy/useAssistantInteractable.test.tsx +132 -0
- package/src/react/interactables-legacy/useAssistantInteractable.ts +10 -1
- package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +9 -10
- package/src/react/model-context/makeAssistantTool.ts +2 -2
- package/src/react/model-context/useAssistantTool.ts +2 -2
- package/src/react/model-context/useInteractable.test.tsx +177 -0
- package/src/react/model-context/useInteractable.ts +3 -0
- package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
- package/src/react/model-context/useToolArgsStatus.ts +2 -1
- package/src/react/primitive-hooks/useActionBarCopy.test.ts +0 -1
- package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +0 -1
- package/src/react/primitives/message/MessageGroupedParts.test.tsx +96 -0
- package/src/react/primitives/message/MessageGroupedParts.tsx +15 -4
- package/src/react/primitives/part/PartMessages.test.tsx +104 -1
- package/src/react/primitives/part/PartMessages.tsx +1 -0
- package/src/react/primitives/thread/ThreadMessages.test.tsx +142 -0
- package/src/react/primitives/thread/ThreadMessages.tsx +8 -5
- package/src/react/providers/ReadonlyThreadProvider.test.tsx +56 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.destroy.test.tsx +172 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +33 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +7 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +28 -5
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.load-error.test.ts +132 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +105 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +143 -112
- package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
- package/src/react/runtimes/RemoteThreadResource.ts +19 -12
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +20 -14
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +703 -6
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +492 -402
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.test.ts +77 -0
- package/src/react/runtimes/cloud/CloudFileAttachmentAdapter.ts +27 -1
- package/src/react/runtimes/cloud/auiV0.ts +160 -25
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +36 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +8 -1
- package/src/react/runtimes/cloud/sdkIdentity.ts +9 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +18 -4
- package/src/react/runtimes/external-message-converter.test.ts +136 -1
- package/src/react/runtimes/external-message-converter.ts +39 -93
- 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.load-error.test.tsx +108 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +34 -1
- package/src/react/utils/groupParts.ts +12 -1
- package/src/react/utils/useJSONEqual.ts +9 -0
- package/src/react/utils/useJSONSchemaDependency.ts +22 -0
- 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 +21 -11
- package/src/runtime/api/thread-runtime.test.ts +136 -0
- package/src/runtime/api/thread-runtime.ts +10 -5
- package/src/runtime/base/base-composer-runtime-core.ts +105 -24
- package/src/runtime/base/base-thread-runtime-core.test.ts +1063 -2
- package/src/runtime/base/base-thread-runtime-core.ts +228 -87
- package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
- package/src/runtime/interfaces/thread-list-runtime-core.ts +5 -1
- package/src/runtime/interfaces/thread-runtime-core.ts +6 -0
- package/src/runtime/queue/message-queue.ts +68 -6
- package/src/runtime/utils/auto-status.test.ts +112 -1
- package/src/runtime/utils/auto-status.ts +31 -5
- package/src/runtime/utils/external-message-conversion.test.ts +202 -0
- package/src/runtime/utils/external-message-conversion.ts +123 -32
- package/src/runtime/utils/message-repository.test.ts +49 -0
- package/src/runtime/utils/message-repository.ts +32 -20
- package/src/runtime/utils/thread-message-like.test.ts +52 -0
- package/src/runtime/utils/thread-message-like.ts +5 -1
- 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 +31 -1
- package/src/runtimes/internal.ts +1 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +21 -0
- package/src/runtimes/local/local-thread-runtime-core.ts +11 -1
- package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +128 -2
- package/src/runtimes/remote-thread-list/remote-thread-state.ts +182 -42
- 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 +13 -0
- package/src/runtimes/remote-thread-list/types.ts +10 -0
- package/src/runtimes/tool-invocations/EDGE_CASES.md +2 -6
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +133 -0
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +10 -6
- package/src/store/clients/external-thread.ts +67 -4
- 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 +40 -0
- package/src/store/clients/suggestions.ts +13 -10
- package/src/store/clients/thread-tasks.test.ts +274 -0
- package/src/store/clients/thread-tasks.ts +138 -0
- package/src/store/index.ts +8 -0
- package/src/store/primitive-predicates.test.ts +48 -5
- package/src/store/primitive-predicates.ts +7 -2
- 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 +1 -0
- package/src/store/runtime-clients/thread-runtime-client.ts +89 -11
- package/src/store/scope-registration.ts +2 -0
- package/src/store/scopes/composer.ts +16 -4
- package/src/store/scopes/message.ts +14 -0
- package/src/store/scopes/task.ts +34 -0
- package/src/store/scopes/thread-list-item.ts +5 -2
- package/src/store/scopes/thread.ts +20 -0
- package/src/store/scopes/threads.ts +1 -0
- package/src/store/thread-tasks.test.tsx +209 -0
- package/src/subscribable/subscribable.test.ts +156 -1
- package/src/subscribable/subscribable.ts +25 -15
- package/src/tests/MessageRepository.test.ts +117 -5
- 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 +47 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +89 -0
- package/src/tests/attachment-adapters.test.ts +14 -0
- package/src/tests/auiV0Encode.test.ts +300 -0
- package/src/tests/base-composer-runtime-core-send.test.ts +51 -0
- package/src/tests/base-composer-runtime-core.test.ts +353 -2
- package/src/tests/external-store-thread-list-runtime-core.test.ts +83 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +178 -18
- package/src/tests/external-thread-attachments.test.tsx +208 -0
- package/src/tests/external-thread-parity.test.tsx +57 -0
- package/src/tests/groupParts.test.ts +71 -0
- package/src/tests/message-queue.test.ts +253 -0
- package/src/tests/remote-thread-list-isLoading.test.ts +1 -0
- package/src/tests/remote-thread-list-reactive-threadId.test.ts +51 -0
- package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
- package/src/tests/thread-switch-events.test.tsx +78 -0
- package/src/tests/tools-scope-migration.test.tsx +28 -0
- package/src/tests/useRemoteThreadListRuntime-controlled.test.tsx +43 -0
- package/src/types/attachment.ts +4 -0
- package/src/types/index.ts +1 -0
- package/src/types/message.ts +8 -0
- package/src/utils/abortable-iterable.test.ts +328 -0
- package/src/utils/abortable-iterable.ts +104 -0
- package/src/utils/composite-context-provider.test.ts +25 -0
- package/src/utils/composite-context-provider.ts +23 -2
- package/src/utils/getGroupStatus.test.ts +70 -4
- package/src/utils/getGroupStatus.ts +35 -12
- package/src/utils/record.test.ts +48 -0
- package/src/utils/record.ts +11 -0
- package/src/utils/wire-media.test.ts +10 -0
- package/src/utils/wire-media.ts +6 -2
|
@@ -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
|
+
});
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
import { AssistantMessageStream } from "assistant-stream";
|
|
2
|
+
|
|
1
3
|
export const isTitleSourceMessage = (message: {
|
|
2
4
|
status?: { type: string } | undefined;
|
|
3
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[],
|
|
@@ -72,9 +72,7 @@ If the tool also had a frontend `execute`, the executor is short-circuited
|
|
|
72
72
|
via the entry's per-execution skip marker. Single fire.
|
|
73
73
|
|
|
74
74
|
### A.6. Previously-resolved tool's `result` is replaced
|
|
75
|
-
Silently ignored
|
|
76
|
-
re-`setResponse` path and the downstream result-chunk handler. The host
|
|
77
|
-
sees only the first result.
|
|
75
|
+
Silently ignored. A restored entry with a result remains historical even when a live snapshot reserializes its `argsText` or replaces its result. For active entries, `entry.hasResult` short-circuits both the re-`setResponse` path and the downstream result-chunk handler. The host sees only the first result.
|
|
78
76
|
|
|
79
77
|
### A.7. Previously-resolved tool loses its `result` (back to undefined)
|
|
80
78
|
Silently ignored. The entry stays in the resolved phase internally.
|
|
@@ -213,9 +211,7 @@ Silently kept as restored. Recursion into `content.messages` still
|
|
|
213
211
|
happens so any nested live tool calls are processed.
|
|
214
212
|
|
|
215
213
|
### C.3. Restored entry observed in a live snapshot, signature changed
|
|
216
|
-
|
|
217
|
-
`_startActiveEntry`. This is PR #4057's promotion path. `streamCall`
|
|
218
|
-
fires once — its first and only fire for this `toolCallId`.
|
|
214
|
+
A restored entry with a result remains historical regardless of later `argsText` or result changes. An unresolved restored entry is promoted only when a result lands or its `argsText` changes. Complete `argsText` values that parse to equivalent JSON are unchanged. Promotion deletes the restored entry and starts a new active entry via `_startActiveEntry`. `streamCall` fires once, its first and only fire for this `toolCallId`.
|
|
219
215
|
|
|
220
216
|
### C.4. `isLoading` transitions `true → false` while messages are stable
|
|
221
217
|
The next `setState` call sees `isLoading === false` and processes
|
|
@@ -1465,6 +1465,139 @@ describe("ToolInvocationTracker", () => {
|
|
|
1465
1465
|
expect(onResult).not.toHaveBeenCalled();
|
|
1466
1466
|
});
|
|
1467
1467
|
|
|
1468
|
+
it("keeps a resolved restored tool call historical when its snapshot is reserialized", async () => {
|
|
1469
|
+
const execute = vi.fn(async () => ({ forecast: "ok" }));
|
|
1470
|
+
const streamCall = vi.fn();
|
|
1471
|
+
const getTools = () => ({
|
|
1472
|
+
weatherSearch: {
|
|
1473
|
+
parameters: { type: "object", properties: {} },
|
|
1474
|
+
execute,
|
|
1475
|
+
streamCall,
|
|
1476
|
+
} satisfies Tool,
|
|
1477
|
+
});
|
|
1478
|
+
const onResult = vi.fn();
|
|
1479
|
+
const tracker = new ToolInvocationTracker(getTools, {
|
|
1480
|
+
onResult,
|
|
1481
|
+
onStatusesChange: () => {},
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1484
|
+
tracker.setState(
|
|
1485
|
+
createState([
|
|
1486
|
+
createAssistantMessage(
|
|
1487
|
+
'{"query":"London","page":1}',
|
|
1488
|
+
{ query: "London", page: 1 },
|
|
1489
|
+
{ result: { source: "history", revision: 1 } },
|
|
1490
|
+
),
|
|
1491
|
+
]),
|
|
1492
|
+
);
|
|
1493
|
+
|
|
1494
|
+
tracker.setState(
|
|
1495
|
+
createState([
|
|
1496
|
+
createAssistantMessage(
|
|
1497
|
+
'{ "page": 1, "query": "London" }',
|
|
1498
|
+
{ query: "London", page: 1 },
|
|
1499
|
+
{ result: { source: "history", revision: 2 } },
|
|
1500
|
+
),
|
|
1501
|
+
]),
|
|
1502
|
+
);
|
|
1503
|
+
|
|
1504
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
1505
|
+
|
|
1506
|
+
expect(streamCall).not.toHaveBeenCalled();
|
|
1507
|
+
expect(execute).not.toHaveBeenCalled();
|
|
1508
|
+
expect(onResult).not.toHaveBeenCalled();
|
|
1509
|
+
});
|
|
1510
|
+
|
|
1511
|
+
it("promotes unresolved restored tool calls only for real args changes or a landed result", async () => {
|
|
1512
|
+
const equivalentStreamCall = vi.fn();
|
|
1513
|
+
const growingStreamCall = vi.fn();
|
|
1514
|
+
const resolvedStreamCall = vi.fn();
|
|
1515
|
+
const getTools = () => ({
|
|
1516
|
+
equivalentTool: {
|
|
1517
|
+
parameters: { type: "object", properties: {} },
|
|
1518
|
+
streamCall: equivalentStreamCall,
|
|
1519
|
+
} satisfies Tool,
|
|
1520
|
+
growingTool: {
|
|
1521
|
+
parameters: { type: "object", properties: {} },
|
|
1522
|
+
streamCall: growingStreamCall,
|
|
1523
|
+
} satisfies Tool,
|
|
1524
|
+
resolvedTool: {
|
|
1525
|
+
parameters: { type: "object", properties: {} },
|
|
1526
|
+
streamCall: resolvedStreamCall,
|
|
1527
|
+
} satisfies Tool,
|
|
1528
|
+
});
|
|
1529
|
+
const tracker = new ToolInvocationTracker(getTools, {
|
|
1530
|
+
onResult: vi.fn(),
|
|
1531
|
+
onStatusesChange: () => {},
|
|
1532
|
+
});
|
|
1533
|
+
|
|
1534
|
+
tracker.setState(
|
|
1535
|
+
createState([
|
|
1536
|
+
createAssistantMessage(
|
|
1537
|
+
'{"a":1,"b":2}',
|
|
1538
|
+
{ a: 1, b: 2 },
|
|
1539
|
+
{
|
|
1540
|
+
toolCallId: "equivalent",
|
|
1541
|
+
toolName: "equivalentTool",
|
|
1542
|
+
},
|
|
1543
|
+
),
|
|
1544
|
+
createAssistantMessage(
|
|
1545
|
+
'{"query":"Lon',
|
|
1546
|
+
{ query: "Lon" },
|
|
1547
|
+
{
|
|
1548
|
+
toolCallId: "growing",
|
|
1549
|
+
toolName: "growingTool",
|
|
1550
|
+
},
|
|
1551
|
+
),
|
|
1552
|
+
createAssistantMessage(
|
|
1553
|
+
'{"city":"London"}',
|
|
1554
|
+
{ city: "London" },
|
|
1555
|
+
{
|
|
1556
|
+
toolCallId: "resolved",
|
|
1557
|
+
toolName: "resolvedTool",
|
|
1558
|
+
},
|
|
1559
|
+
),
|
|
1560
|
+
]),
|
|
1561
|
+
);
|
|
1562
|
+
|
|
1563
|
+
tracker.setState(
|
|
1564
|
+
createState([
|
|
1565
|
+
createAssistantMessage(
|
|
1566
|
+
'{ "b": 2, "a": 1 }',
|
|
1567
|
+
{ a: 1, b: 2 },
|
|
1568
|
+
{
|
|
1569
|
+
toolCallId: "equivalent",
|
|
1570
|
+
toolName: "equivalentTool",
|
|
1571
|
+
},
|
|
1572
|
+
),
|
|
1573
|
+
createAssistantMessage(
|
|
1574
|
+
'{"query":"London"}',
|
|
1575
|
+
{ query: "London" },
|
|
1576
|
+
{
|
|
1577
|
+
toolCallId: "growing",
|
|
1578
|
+
toolName: "growingTool",
|
|
1579
|
+
},
|
|
1580
|
+
),
|
|
1581
|
+
createAssistantMessage(
|
|
1582
|
+
'{"city":"London"}',
|
|
1583
|
+
{ city: "London" },
|
|
1584
|
+
{
|
|
1585
|
+
toolCallId: "resolved",
|
|
1586
|
+
toolName: "resolvedTool",
|
|
1587
|
+
result: { source: "history" },
|
|
1588
|
+
},
|
|
1589
|
+
),
|
|
1590
|
+
]),
|
|
1591
|
+
);
|
|
1592
|
+
|
|
1593
|
+
await waitFor(() => {
|
|
1594
|
+
expect(growingStreamCall).toHaveBeenCalledTimes(1);
|
|
1595
|
+
expect(resolvedStreamCall).toHaveBeenCalledTimes(1);
|
|
1596
|
+
});
|
|
1597
|
+
|
|
1598
|
+
expect(equivalentStreamCall).not.toHaveBeenCalled();
|
|
1599
|
+
});
|
|
1600
|
+
|
|
1468
1601
|
it("promotes an in-progress tool call from the initial snapshot when it changes", async () => {
|
|
1469
1602
|
const execute = vi.fn(async () => ({ forecast: "ok" }));
|
|
1470
1603
|
const streamCall = vi.fn();
|
|
@@ -825,12 +825,16 @@ export class ToolInvocationTracker {
|
|
|
825
825
|
this._discardedToolCallIds.delete(content.toolCallId);
|
|
826
826
|
|
|
827
827
|
if (entry && !entry.controller) {
|
|
828
|
-
//
|
|
829
|
-
|
|
830
|
-
const
|
|
831
|
-
content.argsText !== entry.argsText
|
|
832
|
-
(
|
|
833
|
-
|
|
828
|
+
// A restored entry with a result remains historical.
|
|
829
|
+
if (entry.hasResult) continue;
|
|
830
|
+
const argsChanged =
|
|
831
|
+
content.argsText !== entry.argsText &&
|
|
832
|
+
!(
|
|
833
|
+
isArgsTextComplete(entry.argsText) &&
|
|
834
|
+
isArgsTextComplete(content.argsText) &&
|
|
835
|
+
isEquivalentCompleteArgsText(entry.argsText, content.argsText)
|
|
836
|
+
);
|
|
837
|
+
if (!argsChanged && content.result === undefined) continue;
|
|
834
838
|
this._entries.delete(content.toolCallId);
|
|
835
839
|
entry = undefined;
|
|
836
840
|
}
|