@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-composer-runtime-core.js","names":["isCreateAttachment","Attachment","CompleteAttachment","CreateAttachment","PendingAttachment","MessageRole","AppendMessage","isMessageNotSentError","QuoteInfo","Unsubscribe","RunConfig","BaseSubscribable","AttachmentAdapter","fileMatchesAccept","AttachmentAddErrorReason","ComposerRuntimeCore","ComposerRuntimeEventCallback","ComposerRuntimeEventPayload","ComposerRuntimeEventType","DictationState","SendOptions","DictationAdapter","QueuePlacement","EMPTY_QUEUE_ITEMS","QueueItemState","generateId","notifyEventListeners","AttachmentAddOperations","drainAttachmentAdd","isAttachmentComplete","a","status","type","BaseComposerRuntimeCore","isEditing","getAttachmentAdapter","getDictationAdapter","enrichWithComposerMetadata","metadata","custom","Record","message","T","composerMetadata","attachmentAccept","accept","_attachments","attachments","setAttachments","value","_notifySubscribers","canCancel","canSend","isEmpty","text","trim","length","_text","_role","role","_runConfig","runConfig","_quote","undefined","quote","setQuote","setText","_rebaseDictation","_dictation","_dictationBaseText","_currentInterimText","inputDisabled","setRole","setRunConfig","_isSending","_removedDuringSend","Set","_sendGeneration","_attachmentAddOperations","_cancelAttachmentAdd","attachmentId","cancel","_cancelAllAttachmentAdds","cancelAll","_emptyTextAndAttachments","_onClearAttachments","adapter","pending","filter","Promise","all","map","remove","reset","clear","Object","keys","task","clearAttachments","send","options","_dictationSession","_cleanupDictation","attachmentTasks","Error","result","originalAttachments","generation","resolvedAttachments","e","allSettled","then","sentIds","id","has","finalAttachments","Omit","createdAt","Date","content","draft","sendTask","handleSend","error","_restoreUnsentDraft","catch","_notifyEventSubscribers","restoreDraft","retractDraft","attachmentsUntouched","handleCancel","queue","moveQueueItem","_queueItemId","_placement","removeQueueItem","addAttachment","fileOrAttachment","File","name","contentType","err","_safeEmitAttachmentAddError","operation","start","upsertAttachment","idx","findIndex","attachment","slice","lastAttachment","add","file","isCancelled","reason","String","finish","subscriberError","console","removeAttachment","index","candidate","Session","_dictationUnsubscribes","_dictationSessionIdCounter","_activeDictationSessionId","_isCleaningDictation","dictation","_isActiveSession","sessionId","session","startDictation","unsub","oldSession","stop","disableInputDuringDictation","listen","unsubSpeech","onSpeech","isFinal","needsSeparator","endsWith","transcript","separator","_","rest","push","unsubStart","onSpeechStart","unsubEnd","onSpeechEnd","statusInterval","setInterval","clearInterval","stopDictation","cleanup","isStaleSession","_eventSubscribers","Map","payload","event","E","subscribers","get","unstable_on","callback","wrapped","set","delete"],"sources":["../../../src/runtime/base/base-composer-runtime-core.ts"],"sourcesContent":["import {\n isCreateAttachment,\n type Attachment,\n type CompleteAttachment,\n type CreateAttachment,\n type PendingAttachment,\n} from \"../../types/attachment\";\nimport type { MessageRole, AppendMessage } from \"../../types/message\";\nimport { isMessageNotSentError } from \"../../types/error\";\nimport type { QuoteInfo } from \"../../types/quote\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { RunConfig } from \"../../types/message\";\nimport { BaseSubscribable } from \"../../subscribable/subscribable\";\nimport {\n type AttachmentAdapter,\n fileMatchesAccept,\n} from \"../../adapters/attachment\";\nimport type {\n AttachmentAddErrorReason,\n ComposerRuntimeCore,\n ComposerRuntimeEventCallback,\n ComposerRuntimeEventPayload,\n ComposerRuntimeEventType,\n DictationState,\n SendOptions,\n} from \"../interfaces/composer-runtime-core\";\nimport type { DictationAdapter } from \"../../adapters/speech\";\nimport type { QueuePlacement } from \"../queue/external-thread-queue-adapter\";\nimport { EMPTY_QUEUE_ITEMS, type QueueItemState } from \"../queue/queue-item\";\nimport { generateId } from \"../../utils/id\";\nimport { notifyEventListeners } from \"../../utils/notify-event-listeners\";\nimport {\n AttachmentAddOperations,\n drainAttachmentAdd,\n} from \"../utils/attachment-add-operations\";\n\nconst isAttachmentComplete = (a: Attachment): a is CompleteAttachment =>\n a.status.type === \"complete\";\n\nexport abstract class BaseComposerRuntimeCore\n extends BaseSubscribable\n implements ComposerRuntimeCore\n{\n public readonly isEditing = true;\n\n protected abstract getAttachmentAdapter(): AttachmentAdapter | undefined;\n protected abstract getDictationAdapter(): DictationAdapter | undefined;\n\n protected enrichWithComposerMetadata<\n T extends { metadata?: { custom?: Record<string, unknown> } },\n >(message: T, composerMetadata: Record<string, unknown> | undefined): T {\n if (!composerMetadata) return message;\n return {\n ...message,\n metadata: {\n ...message.metadata,\n custom: { ...message.metadata?.custom, ...composerMetadata },\n },\n } as T;\n }\n\n public get attachmentAccept(): string {\n return this.getAttachmentAdapter()?.accept ?? \"*\";\n }\n\n private _attachments: readonly Attachment[] = [];\n public get attachments() {\n return this._attachments;\n }\n\n protected setAttachments(value: readonly Attachment[]) {\n this._attachments = value;\n this._notifySubscribers();\n }\n\n public abstract get canCancel(): boolean;\n public abstract get canSend(): boolean;\n\n public get isEmpty() {\n return !this.text.trim() && !this.attachments.length;\n }\n\n private _text = \"\";\n\n get text() {\n return this._text;\n }\n\n private _role: MessageRole = \"user\";\n\n get role() {\n return this._role;\n }\n\n private _runConfig: RunConfig = {};\n\n get runConfig() {\n return this._runConfig;\n }\n\n private _quote: QuoteInfo | undefined = undefined;\n\n get quote() {\n return this._quote;\n }\n\n public setQuote(quote: QuoteInfo | undefined) {\n if (this._quote === quote) return;\n\n this._quote = quote;\n this._notifySubscribers();\n }\n\n public setText(value: string) {\n if (this._text === value) return;\n\n this._text = value;\n this._rebaseDictation(value);\n this._notifySubscribers();\n }\n\n // A live dictation session appends to the text it last saw, so any write\n // that bypasses `setText` has to move that baseline or the next transcript\n // overwrites what was just written.\n private _rebaseDictation(value: string) {\n if (!this._dictation) return;\n\n this._dictationBaseText = value;\n this._currentInterimText = \"\";\n const { status, inputDisabled } = this._dictation;\n this._dictation = inputDisabled ? { status, inputDisabled } : { status };\n }\n\n public setRole(role: MessageRole) {\n if (this._role === role) return;\n\n this._role = role;\n this._notifySubscribers();\n }\n\n public setRunConfig(runConfig: RunConfig) {\n if (this._runConfig === runConfig) return;\n\n this._runConfig = runConfig;\n this._notifySubscribers();\n }\n\n protected _isSending = false;\n private _removedDuringSend = new Set<string>();\n private _sendGeneration = 0;\n private _attachmentAddOperations = new AttachmentAddOperations();\n\n private _cancelAttachmentAdd(attachmentId: string) {\n this._attachmentAddOperations.cancel(attachmentId);\n }\n\n private _cancelAllAttachmentAdds() {\n this._attachmentAddOperations.cancelAll();\n }\n\n private _emptyTextAndAttachments() {\n this._attachments = [];\n this._text = \"\";\n this._notifySubscribers();\n }\n\n private async _onClearAttachments() {\n const adapter = this.getAttachmentAdapter();\n if (adapter) {\n const pending = this._attachments.filter((a) => !isAttachmentComplete(a));\n await Promise.all(pending.map((a) => adapter.remove(a)));\n }\n }\n\n public async reset() {\n this._cancelAllAttachmentAdds();\n\n // A send whose adapter never settles must not brick the composer; reset is\n // the escape hatch that releases the in-flight lock. Bumping the generation\n // invalidates that send entirely so a late-settling upload can neither\n // append the discarded draft nor touch a newer send's lock.\n this._sendGeneration++;\n this._isSending = false;\n this._removedDuringSend.clear();\n\n if (\n this._attachments.length === 0 &&\n this._text === \"\" &&\n this._role === \"user\" &&\n Object.keys(this._runConfig).length === 0 &&\n this._quote === undefined\n ) {\n return;\n }\n\n this._role = \"user\";\n this._runConfig = {};\n this._quote = undefined;\n\n const task = this._onClearAttachments();\n this._emptyTextAndAttachments();\n await task;\n }\n\n public async clearAttachments() {\n this._cancelAllAttachmentAdds();\n const task = this._onClearAttachments();\n this.setAttachments([]);\n\n await task;\n }\n\n public async send(options?: SendOptions) {\n if (!this.canSend || this._isSending) return;\n\n if (this._dictationSession) {\n this._dictationSession.cancel();\n this._cleanupDictation();\n }\n\n const adapter = this.getAttachmentAdapter();\n const attachmentTasks = this.attachments.map(async (a) => {\n if (isAttachmentComplete(a)) return a;\n if (!adapter) throw new Error(\"Attachments are not supported\");\n const result = await adapter.send(a);\n return result as CompleteAttachment;\n });\n\n const originalAttachments = this.attachments;\n const text = this.text;\n const quote = this._quote;\n const role = this.role;\n const runConfig = this.runConfig;\n this._quote = undefined;\n this._text = \"\";\n this._isSending = true;\n const generation = ++this._sendGeneration;\n this._notifySubscribers();\n\n let resolvedAttachments: CompleteAttachment[];\n try {\n resolvedAttachments = await Promise.all(attachmentTasks);\n } catch (e) {\n if (generation === this._sendGeneration) {\n if (!this.text.trim() && this._quote === undefined) {\n this._text = text;\n this._rebaseDictation(text);\n this._quote = quote;\n this._notifySubscribers();\n }\n // Promise.all rejects on the first failure, but sibling uploads from\n // this batch keep running; the send rejects immediately while the\n // retry lock is held until they settle, or a retry could re-send\n // attachments that are still in flight.\n void Promise.allSettled(attachmentTasks).then(() => {\n if (generation !== this._sendGeneration) return;\n this._removedDuringSend.clear();\n this._isSending = false;\n this._notifySubscribers();\n });\n }\n throw e;\n }\n\n // A reset during the upload discarded this send's draft; the settled\n // uploads must not append it or touch the lock a newer send may own.\n if (generation !== this._sendGeneration) return;\n\n // Drop by id, not wholesale: the user may have added or removed chips while\n // the upload was in flight.\n const sentIds = new Set(originalAttachments.map((a) => a.id));\n this._attachments = this._attachments.filter((a) => !sentIds.has(a.id));\n this._isSending = false;\n this._notifySubscribers();\n\n // An attachment removed mid-upload can't be cancelled, but it can still be\n // dropped from the outgoing message instead of silently being sent anyway.\n const finalAttachments = resolvedAttachments.filter(\n (a) => !this._removedDuringSend.has(a.id),\n );\n this._removedDuringSend.clear();\n\n const message: Omit<AppendMessage, \"parentId\" | \"sourceId\"> = {\n createdAt: new Date(),\n role,\n content: text ? [{ type: \"text\", text }] : [],\n attachments: finalAttachments,\n runConfig,\n metadata: { custom: { ...(quote ? { quote } : {}) } },\n };\n\n const draft = { text, quote, attachments: finalAttachments };\n let sendTask: void | Promise<void>;\n try {\n sendTask = this.handleSend(message, options);\n } catch (error) {\n this._restoreUnsentDraft(error, generation, draft);\n throw error;\n }\n if (sendTask)\n void sendTask.catch((error) => {\n this._restoreUnsentDraft(error, generation, draft);\n });\n this._notifyEventSubscribers(\"send\", {});\n }\n\n /**\n * Take a message back into the composer when it has nowhere else to live:\n * a send the runtime never dispatched, or a message a cancelled run is\n * removing from the thread. Reports whether the composer accepted it, so a\n * caller that is also removing the message can keep it instead of dropping\n * it. Refused, and left untouched, while the composer holds anything of its\n * own.\n */\n public restoreDraft(draft: {\n text: string;\n quote?: QuoteInfo | undefined;\n attachments?: readonly Attachment[] | undefined;\n }): boolean {\n if (\n this._text.trim() ||\n this._quote !== undefined ||\n this._attachments.length > 0\n )\n return false;\n\n this._text = draft.text;\n this._rebaseDictation(draft.text);\n this._quote = draft.quote;\n this._attachments = draft.attachments ?? [];\n this._notifySubscribers();\n return true;\n }\n\n /**\n * Inverse of `restoreDraft`: clears the composer while it still holds\n * exactly the given draft. A draft the user has edited since is left\n * untouched.\n */\n public retractDraft(draft: {\n text: string;\n quote?: QuoteInfo | undefined;\n attachments?: readonly Attachment[] | undefined;\n }): void {\n const attachmentsUntouched =\n draft.attachments !== undefined\n ? this._attachments === draft.attachments\n : this._attachments.length === 0;\n if (\n this._text !== draft.text ||\n this._quote !== draft.quote ||\n !attachmentsUntouched\n )\n return;\n\n this._text = \"\";\n this._rebaseDictation(\"\");\n this._quote = undefined;\n this._attachments = [];\n this._notifySubscribers();\n }\n\n // The generation check is what a reset and a later send use to invalidate a\n // draft, so of several queued drafts only the most recent one is still\n // restorable.\n private _restoreUnsentDraft(\n error: unknown,\n generation: number,\n draft: {\n text: string;\n quote: QuoteInfo | undefined;\n attachments: readonly CompleteAttachment[];\n },\n ) {\n if (!isMessageNotSentError(error)) return;\n if (generation !== this._sendGeneration) return;\n this.restoreDraft(draft);\n }\n\n public cancel() {\n this.handleCancel();\n }\n\n public get queue(): readonly QueueItemState[] {\n return EMPTY_QUEUE_ITEMS;\n }\n\n public moveQueueItem(\n _queueItemId: string,\n _placement: QueuePlacement,\n ): void {}\n public removeQueueItem(_queueItemId: string): void {}\n\n protected abstract handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n options?: SendOptions,\n ): void | Promise<void>;\n protected abstract handleCancel(): void;\n\n async addAttachment(fileOrAttachment: File | CreateAttachment) {\n if (isCreateAttachment(fileOrAttachment)) {\n const adapter = this.getAttachmentAdapter();\n if (\n adapter &&\n !fileMatchesAccept(\n {\n name: fileOrAttachment.name,\n type: fileOrAttachment.contentType ?? \"\",\n },\n adapter.accept,\n )\n ) {\n const message = `File type ${fileOrAttachment.contentType || \"unknown\"} is not accepted. Accepted types: ${adapter.accept}`;\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\n \"not-accepted\",\n message,\n undefined,\n err,\n );\n throw err;\n }\n\n const a: CompleteAttachment = {\n id: fileOrAttachment.id ?? generateId(),\n type: fileOrAttachment.type ?? \"document\",\n name: fileOrAttachment.name,\n contentType: fileOrAttachment.contentType,\n content: fileOrAttachment.content,\n status: { type: \"complete\" },\n };\n this._attachments = [...this._attachments, a];\n this._notifySubscribers();\n this._notifyEventSubscribers(\"attachmentAdd\", {});\n return;\n }\n\n const adapter = this.getAttachmentAdapter();\n if (!adapter) {\n const message = \"Attachments are not supported\";\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\"no-adapter\", message, undefined, err);\n throw err;\n }\n\n if (\n !fileMatchesAccept(\n { name: fileOrAttachment.name, type: fileOrAttachment.type },\n adapter.accept,\n )\n ) {\n const message = `File type ${fileOrAttachment.type || \"unknown\"} is not accepted. Accepted types: ${adapter.accept}`;\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\"not-accepted\", message, undefined, err);\n throw err;\n }\n\n const operation = this._attachmentAddOperations.start();\n const upsertAttachment = (a: PendingAttachment) => {\n if (!this._attachmentAddOperations.accept(operation, a.id)) return false;\n\n const idx = this._attachments.findIndex(\n (attachment) => attachment.id === a.id,\n );\n if (idx !== -1)\n this._attachments = [\n ...this._attachments.slice(0, idx),\n a,\n ...this._attachments.slice(idx + 1),\n ];\n else {\n this._attachments = [...this._attachments, a];\n }\n\n this._notifySubscribers();\n return true;\n };\n let lastAttachment: PendingAttachment | undefined;\n try {\n await drainAttachmentAdd(\n adapter.add({ file: fileOrAttachment }),\n (attachment) => {\n lastAttachment = attachment;\n return upsertAttachment(attachment);\n },\n );\n } catch (e) {\n if (this._attachmentAddOperations.isCancelled(operation)) return;\n if (lastAttachment) {\n upsertAttachment({\n ...lastAttachment,\n status: {\n type: \"incomplete\",\n reason: \"error\",\n message: e instanceof Error ? e.message : String(e),\n },\n });\n }\n this._safeEmitAttachmentAddError(\n \"adapter-error\",\n e instanceof Error ? e.message : String(e),\n lastAttachment?.id,\n e instanceof Error ? e : undefined,\n );\n throw e;\n } finally {\n this._attachmentAddOperations.finish(operation);\n }\n\n if (this._attachmentAddOperations.isCancelled(operation)) return;\n if (\n lastAttachment?.status.type === \"incomplete\" &&\n lastAttachment.status.reason === \"error\"\n ) {\n this._safeEmitAttachmentAddError(\n \"adapter-error\",\n lastAttachment.status.message ??\n \"Attachment upload did not complete successfully.\",\n lastAttachment.id,\n );\n } else {\n this._notifyEventSubscribers(\"attachmentAdd\", {});\n }\n }\n\n private _safeEmitAttachmentAddError(\n reason: AttachmentAddErrorReason,\n message: string,\n attachmentId?: string,\n error?: Error,\n ) {\n try {\n this._notifyEventSubscribers(\"attachmentAddError\", {\n reason,\n message,\n ...(attachmentId !== undefined && { attachmentId }),\n ...(error !== undefined && { error }),\n });\n } catch (subscriberError) {\n console.error(\n \"[assistant-ui] attachmentAddError subscriber threw:\",\n subscriberError,\n );\n }\n }\n\n async removeAttachment(attachmentId: string) {\n const index = this._attachments.findIndex((a) => a.id === attachmentId);\n if (index === -1) throw new Error(\"Attachment not found\");\n const attachment = this._attachments[index]!;\n\n this._cancelAttachmentAdd(attachmentId);\n\n // A send in flight may already be uploading this attachment; the upload\n // can't be cancelled, so mark it to be dropped from the outgoing message\n // before any await gives the upload a chance to settle first.\n if (this._isSending) this._removedDuringSend.add(attachmentId);\n\n if (!isAttachmentComplete(attachment)) {\n const adapter = this.getAttachmentAdapter();\n if (!adapter) throw new Error(\"Attachments are not supported\");\n try {\n await adapter.remove(attachment);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this._attachments = this._attachments.map((candidate) =>\n candidate.id === attachmentId && !isAttachmentComplete(candidate)\n ? {\n ...candidate,\n status: { type: \"incomplete\", reason: \"error\", message },\n }\n : candidate,\n );\n this._notifySubscribers();\n throw error;\n }\n }\n this._attachments = this._attachments.filter((a) => a.id !== attachmentId);\n this._notifySubscribers();\n }\n\n private _dictation: DictationState | undefined;\n private _dictationSession: DictationAdapter.Session | undefined;\n private _dictationUnsubscribes: Unsubscribe[] = [];\n private _dictationBaseText = \"\";\n private _currentInterimText = \"\";\n private _dictationSessionIdCounter = 0;\n private _activeDictationSessionId: number | undefined;\n private _isCleaningDictation = false;\n\n public get dictation(): DictationState | undefined {\n return this._dictation;\n }\n\n private _isActiveSession(\n sessionId: number,\n session: DictationAdapter.Session,\n ): boolean {\n return (\n this._activeDictationSessionId === sessionId &&\n this._dictationSession === session\n );\n }\n\n public startDictation(): void {\n const adapter = this.getDictationAdapter();\n if (!adapter) {\n throw new Error(\"Dictation adapter not configured\");\n }\n\n if (this._dictationSession) {\n for (const unsub of this._dictationUnsubscribes) {\n unsub();\n }\n this._dictationUnsubscribes = [];\n const oldSession = this._dictationSession;\n oldSession.stop().catch(() => {});\n this._dictationSession = undefined;\n }\n\n const inputDisabled = adapter.disableInputDuringDictation ?? false;\n\n this._dictationBaseText = this._text;\n this._currentInterimText = \"\";\n\n const session = adapter.listen();\n this._dictationSession = session;\n const sessionId = ++this._dictationSessionIdCounter;\n this._activeDictationSessionId = sessionId;\n this._dictation = { status: session.status, inputDisabled };\n this._notifySubscribers();\n\n const unsubSpeech = session.onSpeech((result) => {\n if (!this._isActiveSession(sessionId, session)) return;\n const isFinal = result.isFinal !== false;\n\n const needsSeparator =\n this._dictationBaseText &&\n !this._dictationBaseText.endsWith(\" \") &&\n result.transcript;\n const separator = needsSeparator ? \" \" : \"\";\n\n if (isFinal) {\n this._dictationBaseText =\n this._dictationBaseText + separator + result.transcript;\n this._currentInterimText = \"\";\n this._text = this._dictationBaseText;\n\n if (this._dictation) {\n const { transcript: _, ...rest } = this._dictation;\n this._dictation = rest;\n }\n this._notifySubscribers();\n } else {\n this._currentInterimText = separator + result.transcript;\n this._text = this._dictationBaseText + this._currentInterimText;\n\n if (this._dictation) {\n this._dictation = {\n ...this._dictation,\n transcript: result.transcript,\n };\n }\n this._notifySubscribers();\n }\n });\n this._dictationUnsubscribes.push(unsubSpeech);\n\n const unsubStart = session.onSpeechStart(() => {\n if (!this._isActiveSession(sessionId, session)) return;\n\n this._dictation = {\n status: { type: \"running\" },\n inputDisabled,\n ...(this._dictation?.transcript && {\n transcript: this._dictation.transcript,\n }),\n };\n this._notifySubscribers();\n });\n this._dictationUnsubscribes.push(unsubStart);\n\n const unsubEnd = session.onSpeechEnd(() => {\n this._cleanupDictation({ sessionId });\n });\n this._dictationUnsubscribes.push(unsubEnd);\n\n const statusInterval = setInterval(() => {\n if (!this._isActiveSession(sessionId, session)) return;\n\n if (session.status.type === \"ended\") {\n this._cleanupDictation({ sessionId });\n }\n }, 100);\n this._dictationUnsubscribes.push(() => clearInterval(statusInterval));\n }\n\n public stopDictation(): void {\n if (!this._dictationSession) return;\n\n const session = this._dictationSession;\n const sessionId = this._activeDictationSessionId;\n const cleanup = () => this._cleanupDictation({ sessionId });\n void session.stop().then(cleanup, cleanup);\n }\n\n private _cleanupDictation(options?: { sessionId: number | undefined }): void {\n const isStaleSession =\n options?.sessionId !== undefined &&\n options.sessionId !== this._activeDictationSessionId;\n if (isStaleSession || this._isCleaningDictation) return;\n\n this._isCleaningDictation = true;\n try {\n for (const unsub of this._dictationUnsubscribes) {\n unsub();\n }\n this._dictationUnsubscribes = [];\n this._dictationSession = undefined;\n this._activeDictationSessionId = undefined;\n this._dictation = undefined;\n this._dictationBaseText = \"\";\n this._currentInterimText = \"\";\n this._notifySubscribers();\n } finally {\n this._isCleaningDictation = false;\n }\n }\n\n private _eventSubscribers = new Map<\n ComposerRuntimeEventType,\n Set<(payload?: unknown) => void>\n >();\n\n protected _notifyEventSubscribers<E extends ComposerRuntimeEventType>(\n event: E,\n payload: ComposerRuntimeEventPayload[E],\n ) {\n const subscribers = this._eventSubscribers.get(event);\n if (!subscribers) return;\n\n notifyEventListeners(subscribers, payload, `Composer runtime \"${event}\"`);\n }\n\n public unstable_on<E extends ComposerRuntimeEventType>(\n event: E,\n callback: ComposerRuntimeEventCallback<E>,\n ) {\n const wrapped = callback as (payload?: unknown) => void;\n let subscribers = this._eventSubscribers.get(event);\n if (!subscribers) {\n subscribers = new Set();\n this._eventSubscribers.set(event, subscribers);\n }\n subscribers.add(wrapped);\n\n return () => {\n this._eventSubscribers.get(event)?.delete(wrapped);\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base-composer-runtime-core.js","names":["isAttachmentComplete","isCreateAttachment","Attachment","CompleteAttachment","CreateAttachment","PendingAttachment","MessageRole","AppendMessage","isMessageNotSentError","QuoteInfo","Unsubscribe","RunConfig","BaseSubscribable","AttachmentAdapter","fileMatchesAccept","AttachmentAddErrorReason","ComposerRuntimeCore","ComposerRuntimeEventCallback","ComposerRuntimeEventPayload","ComposerRuntimeEventType","DictationState","SendOptions","DictationAdapter","QueuePlacement","EMPTY_QUEUE_ITEMS","QueueItemState","generateId","notifyEventListeners","AttachmentAddOperations","drainAttachmentAdd","BaseComposerRuntimeCore","isEditing","getAttachmentAdapter","getDictationAdapter","enrichWithComposerMetadata","metadata","custom","Record","message","T","composerMetadata","attachmentAccept","accept","_attachments","attachments","setAttachments","value","_notifySubscribers","canCancel","canSend","isEmpty","text","trim","length","_text","_role","role","_runConfig","runConfig","_quote","undefined","quote","setQuote","setText","_rebaseDictation","_dictation","_dictationBaseText","_currentInterimText","status","inputDisabled","setRole","setRunConfig","_isSending","_removedDuringSend","Set","_sendGeneration","_attachmentAddOperations","_cancelAttachmentAdd","attachmentId","cancel","_cancelAllAttachmentAdds","cancelAll","_emptyTextAndAttachments","_onClearAttachments","adapter","pending","filter","a","Promise","all","map","remove","reset","clear","Object","keys","task","clearAttachments","attachment","add","id","send","options","_dictationSession","error","console","_cleanupDictation","attachmentTasks","Error","result","originalAttachments","generation","resolvedAttachments","e","allSettled","then","sentIds","has","finalAttachments","Omit","createdAt","Date","content","type","draft","sendTask","handleSend","_restoreUnsentDraft","catch","_notifyEventSubscribers","chars","restoreDraft","retractDraft","attachmentsUntouched","handleCancel","queue","moveQueueItem","_queueItemId","_placement","removeQueueItem","addAttachment","fileOrAttachment","File","name","contentType","err","_safeEmitAttachmentAddError","operation","start","upsertAttachment","idx","findIndex","slice","lastAttachment","file","isCancelled","reason","String","finish","subscriberError","removeAttachment","index","candidate","Session","_dictationUnsubscribes","_dictationSessionIdCounter","_activeDictationSessionId","_isCleaningDictation","dictation","_isActiveSession","sessionId","session","startDictation","isReplacing","oldSession","notify","_stopDictationSession","disableInputDuringDictation","listen","notifyError","unsubSpeech","onSpeech","isFinal","needsSeparator","endsWith","transcript","separator","_","rest","push","unsubStart","onSpeechStart","unsubEnd","onSpeechEnd","statusInterval","setInterval","clearInterval","stopDictation","cleanup","onSettled","stop","isStaleSession","runCleanup","unsubscribes","unsubscribe","_eventSubscribers","Map","payload","event","E","subscribers","get","unstable_on","callback","wrapped","set","delete"],"sources":["../../../src/runtime/base/base-composer-runtime-core.ts"],"sourcesContent":["import {\n isAttachmentComplete,\n isCreateAttachment,\n type Attachment,\n type CompleteAttachment,\n type CreateAttachment,\n type PendingAttachment,\n} from \"../../types/attachment\";\nimport type { MessageRole, AppendMessage } from \"../../types/message\";\nimport { isMessageNotSentError } from \"../../types/error\";\nimport type { QuoteInfo } from \"../../types/quote\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { RunConfig } from \"../../types/message\";\nimport { BaseSubscribable } from \"../../subscribable/subscribable\";\nimport {\n type AttachmentAdapter,\n fileMatchesAccept,\n} from \"../../adapters/attachment\";\nimport type {\n AttachmentAddErrorReason,\n ComposerRuntimeCore,\n ComposerRuntimeEventCallback,\n ComposerRuntimeEventPayload,\n ComposerRuntimeEventType,\n DictationState,\n SendOptions,\n} from \"../interfaces/composer-runtime-core\";\nimport type { DictationAdapter } from \"../../adapters/speech\";\nimport type { QueuePlacement } from \"../queue/external-thread-queue-adapter\";\nimport { EMPTY_QUEUE_ITEMS, type QueueItemState } from \"../queue/queue-item\";\nimport { generateId } from \"../../utils/id\";\nimport { notifyEventListeners } from \"../../utils/notify-event-listeners\";\nimport {\n AttachmentAddOperations,\n drainAttachmentAdd,\n} from \"../utils/attachment-add-operations\";\n\nexport abstract class BaseComposerRuntimeCore\n extends BaseSubscribable\n implements ComposerRuntimeCore\n{\n public readonly isEditing = true;\n\n protected abstract getAttachmentAdapter(): AttachmentAdapter | undefined;\n protected abstract getDictationAdapter(): DictationAdapter | undefined;\n\n protected enrichWithComposerMetadata<\n T extends { metadata?: { custom?: Record<string, unknown> } },\n >(message: T, composerMetadata: Record<string, unknown> | undefined): T {\n if (!composerMetadata) return message;\n return {\n ...message,\n metadata: {\n ...message.metadata,\n custom: { ...message.metadata?.custom, ...composerMetadata },\n },\n } as T;\n }\n\n public get attachmentAccept(): string {\n return this.getAttachmentAdapter()?.accept ?? \"*\";\n }\n\n private _attachments: readonly Attachment[] = [];\n public get attachments() {\n return this._attachments;\n }\n\n protected setAttachments(value: readonly Attachment[]) {\n this._attachments = value;\n this._notifySubscribers();\n }\n\n public abstract get canCancel(): boolean;\n public abstract get canSend(): boolean;\n\n public get isEmpty() {\n return !this.text.trim() && !this.attachments.length;\n }\n\n private _text = \"\";\n\n get text() {\n return this._text;\n }\n\n private _role: MessageRole = \"user\";\n\n get role() {\n return this._role;\n }\n\n private _runConfig: RunConfig = {};\n\n get runConfig() {\n return this._runConfig;\n }\n\n private _quote: QuoteInfo | undefined = undefined;\n\n get quote() {\n return this._quote;\n }\n\n public setQuote(quote: QuoteInfo | undefined) {\n if (this._quote === quote) return;\n\n this._quote = quote;\n this._notifySubscribers();\n }\n\n public setText(value: string) {\n if (this._text === value) return;\n\n this._text = value;\n this._rebaseDictation(value);\n this._notifySubscribers();\n }\n\n // A live dictation session appends to the text it last saw, so any write\n // that bypasses `setText` has to move that baseline or the next transcript\n // overwrites what was just written.\n private _rebaseDictation(value: string) {\n if (!this._dictation) return;\n\n this._dictationBaseText = value;\n this._currentInterimText = \"\";\n const { status, inputDisabled } = this._dictation;\n this._dictation = inputDisabled ? { status, inputDisabled } : { status };\n }\n\n public setRole(role: MessageRole) {\n if (this._role === role) return;\n\n this._role = role;\n this._notifySubscribers();\n }\n\n public setRunConfig(runConfig: RunConfig) {\n if (this._runConfig === runConfig) return;\n\n this._runConfig = runConfig;\n this._notifySubscribers();\n }\n\n protected _isSending = false;\n private _removedDuringSend = new Set<string>();\n private _sendGeneration = 0;\n private _attachmentAddOperations = new AttachmentAddOperations();\n\n private _cancelAttachmentAdd(attachmentId: string) {\n this._attachmentAddOperations.cancel(attachmentId);\n }\n\n private _cancelAllAttachmentAdds() {\n this._attachmentAddOperations.cancelAll();\n }\n\n private _emptyTextAndAttachments() {\n this._attachments = [];\n this._text = \"\";\n this._rebaseDictation(\"\");\n this._notifySubscribers();\n }\n\n private async _onClearAttachments() {\n const adapter = this.getAttachmentAdapter();\n if (adapter) {\n const pending = this._attachments.filter((a) => !isAttachmentComplete(a));\n await Promise.all(pending.map(async (a) => adapter.remove(a)));\n }\n }\n\n public async reset() {\n this._cancelAllAttachmentAdds();\n\n // A send whose adapter never settles must not brick the composer; reset is\n // the escape hatch that releases the in-flight lock. Bumping the generation\n // invalidates that send entirely so a late-settling upload can neither\n // append the discarded draft nor touch a newer send's lock.\n this._sendGeneration++;\n this._isSending = false;\n this._removedDuringSend.clear();\n\n if (\n this._attachments.length === 0 &&\n this._text === \"\" &&\n this._role === \"user\" &&\n Object.keys(this._runConfig).length === 0 &&\n this._quote === undefined\n ) {\n return;\n }\n\n this._role = \"user\";\n this._runConfig = {};\n this._quote = undefined;\n\n const task = this._onClearAttachments();\n this._emptyTextAndAttachments();\n await task;\n }\n\n public async clearAttachments() {\n this._cancelAllAttachmentAdds();\n if (this._isSending) {\n for (const attachment of this._attachments)\n this._removedDuringSend.add(attachment.id);\n }\n const task = this._onClearAttachments();\n this.setAttachments([]);\n\n await task;\n }\n\n public async send(options?: SendOptions) {\n if (!this.canSend || this._isSending) return;\n\n if (this._dictationSession) {\n try {\n this._dictationSession.cancel();\n } catch (error) {\n console.error(\"[assistant-ui] Dictation session cancel threw\", error);\n } finally {\n this._cleanupDictation();\n }\n }\n\n const adapter = this.getAttachmentAdapter();\n const attachmentTasks = this.attachments.map(async (a) => {\n if (isAttachmentComplete(a)) return a;\n if (!adapter) throw new Error(\"Attachments are not supported\");\n const result = await adapter.send(a);\n return result as CompleteAttachment;\n });\n\n const originalAttachments = this.attachments;\n const text = this.text;\n const quote = this._quote;\n const role = this.role;\n const runConfig = this.runConfig;\n this._quote = undefined;\n this._text = \"\";\n this._isSending = true;\n const generation = ++this._sendGeneration;\n this._notifySubscribers();\n\n let resolvedAttachments: CompleteAttachment[];\n try {\n resolvedAttachments = await Promise.all(attachmentTasks);\n } catch (e) {\n if (generation === this._sendGeneration) {\n if (!this.text.trim() && this._quote === undefined) {\n this._text = text;\n this._rebaseDictation(text);\n this._quote = quote;\n this._notifySubscribers();\n }\n // Promise.all rejects on the first failure, but sibling uploads from\n // this batch keep running; the send rejects immediately while the\n // retry lock is held until they settle, or a retry could re-send\n // attachments that are still in flight.\n void Promise.allSettled(attachmentTasks).then(() => {\n if (generation !== this._sendGeneration) return;\n this._removedDuringSend.clear();\n this._isSending = false;\n this._notifySubscribers();\n });\n }\n throw e;\n }\n\n // A reset during the upload discarded this send's draft; the settled\n // uploads must not append it or touch the lock a newer send may own.\n if (generation !== this._sendGeneration) return;\n\n // Drop by id, not wholesale: the user may have added or removed chips while\n // the upload was in flight.\n const sentIds = new Set(originalAttachments.map((a) => a.id));\n this._attachments = this._attachments.filter((a) => !sentIds.has(a.id));\n this._isSending = false;\n this._notifySubscribers();\n\n // An attachment removed mid-upload can't be cancelled, but it can still be\n // dropped from the outgoing message instead of silently being sent anyway.\n const finalAttachments = resolvedAttachments.filter(\n (a) => !this._removedDuringSend.has(a.id),\n );\n this._removedDuringSend.clear();\n\n const message: Omit<AppendMessage, \"parentId\" | \"sourceId\"> = {\n createdAt: new Date(),\n role,\n content: text ? [{ type: \"text\", text }] : [],\n attachments: finalAttachments,\n runConfig,\n metadata: { custom: { ...(quote ? { quote } : {}) } },\n };\n\n const draft = { text, quote, attachments: finalAttachments };\n let sendTask: void | Promise<void>;\n try {\n sendTask = this.handleSend(message, options);\n } catch (error) {\n this._restoreUnsentDraft(error, generation, draft);\n throw error;\n }\n if (sendTask)\n void sendTask.catch((error) => {\n this._restoreUnsentDraft(error, generation, draft);\n });\n this._notifyEventSubscribers(\"send\", {\n chars: text.length,\n attachments: finalAttachments.length,\n });\n }\n\n /**\n * Take a message back into the composer when it has nowhere else to live:\n * a send the runtime never dispatched, or a message a cancelled run is\n * removing from the thread. Reports whether the composer accepted it, so a\n * caller that is also removing the message can keep it instead of dropping\n * it. Refused, and left untouched, while the composer holds anything of its\n * own.\n */\n public restoreDraft(draft: {\n text: string;\n quote?: QuoteInfo | undefined;\n attachments?: readonly Attachment[] | undefined;\n }): boolean {\n if (\n this._text.trim() ||\n this._quote !== undefined ||\n this._attachments.length > 0\n )\n return false;\n\n this._text = draft.text;\n this._rebaseDictation(draft.text);\n this._quote = draft.quote;\n this._attachments = draft.attachments ?? [];\n this._notifySubscribers();\n return true;\n }\n\n /**\n * Inverse of `restoreDraft`: clears the composer while it still holds\n * exactly the given draft. A draft the user has edited since is left\n * untouched.\n */\n public retractDraft(draft: {\n text: string;\n quote?: QuoteInfo | undefined;\n attachments?: readonly Attachment[] | undefined;\n }): void {\n const attachmentsUntouched =\n draft.attachments !== undefined\n ? this._attachments === draft.attachments\n : this._attachments.length === 0;\n if (\n this._text !== draft.text ||\n this._quote !== draft.quote ||\n !attachmentsUntouched\n )\n return;\n\n this._text = \"\";\n this._rebaseDictation(\"\");\n this._quote = undefined;\n this._attachments = [];\n this._notifySubscribers();\n }\n\n // The generation check is what a reset and a later send use to invalidate a\n // draft, so of several queued drafts only the most recent one is still\n // restorable.\n private _restoreUnsentDraft(\n error: unknown,\n generation: number,\n draft: {\n text: string;\n quote: QuoteInfo | undefined;\n attachments: readonly CompleteAttachment[];\n },\n ) {\n if (!isMessageNotSentError(error)) return;\n if (generation !== this._sendGeneration) return;\n this.restoreDraft(draft);\n }\n\n public cancel() {\n this.handleCancel();\n }\n\n public get queue(): readonly QueueItemState[] {\n return EMPTY_QUEUE_ITEMS;\n }\n\n public moveQueueItem(\n _queueItemId: string,\n _placement: QueuePlacement,\n ): void {}\n public removeQueueItem(_queueItemId: string): void {}\n\n protected abstract handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n options?: SendOptions,\n ): void | Promise<void>;\n protected abstract handleCancel(): void;\n\n async addAttachment(fileOrAttachment: File | CreateAttachment) {\n if (isCreateAttachment(fileOrAttachment)) {\n const adapter = this.getAttachmentAdapter();\n if (\n adapter &&\n !fileMatchesAccept(\n {\n name: fileOrAttachment.name,\n type: fileOrAttachment.contentType ?? \"\",\n },\n adapter.accept,\n )\n ) {\n const message = `File type ${fileOrAttachment.contentType || \"unknown\"} is not accepted. Accepted types: ${adapter.accept}`;\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\n \"not-accepted\",\n message,\n undefined,\n err,\n fileOrAttachment.contentType,\n );\n throw err;\n }\n\n const a: CompleteAttachment = {\n id: fileOrAttachment.id ?? generateId(),\n type: fileOrAttachment.type ?? \"document\",\n name: fileOrAttachment.name,\n contentType: fileOrAttachment.contentType,\n content: fileOrAttachment.content,\n status: { type: \"complete\" },\n };\n this._attachments = [...this._attachments, a];\n this._notifySubscribers();\n this._notifyEventSubscribers(\"attachmentAdd\", {\n ...(a.contentType ? { contentType: a.contentType } : undefined),\n });\n return;\n }\n\n const adapter = this.getAttachmentAdapter();\n if (!adapter) {\n const message = \"Attachments are not supported\";\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\n \"no-adapter\",\n message,\n undefined,\n err,\n fileOrAttachment.type,\n );\n throw err;\n }\n\n if (\n !fileMatchesAccept(\n { name: fileOrAttachment.name, type: fileOrAttachment.type },\n adapter.accept,\n )\n ) {\n const message = `File type ${fileOrAttachment.type || \"unknown\"} is not accepted. Accepted types: ${adapter.accept}`;\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\n \"not-accepted\",\n message,\n undefined,\n err,\n fileOrAttachment.type,\n );\n throw err;\n }\n\n const operation = this._attachmentAddOperations.start();\n const upsertAttachment = (a: PendingAttachment) => {\n if (!this._attachmentAddOperations.accept(operation, a.id)) return false;\n\n const idx = this._attachments.findIndex(\n (attachment) => attachment.id === a.id,\n );\n if (idx !== -1)\n this._attachments = [\n ...this._attachments.slice(0, idx),\n a,\n ...this._attachments.slice(idx + 1),\n ];\n else {\n this._attachments = [...this._attachments, a];\n }\n\n this._notifySubscribers();\n return true;\n };\n let lastAttachment: PendingAttachment | undefined;\n try {\n await drainAttachmentAdd(\n adapter.add({ file: fileOrAttachment }),\n (attachment) => {\n lastAttachment = attachment;\n return upsertAttachment(attachment);\n },\n );\n } catch (e) {\n if (this._attachmentAddOperations.isCancelled(operation)) return;\n if (lastAttachment) {\n upsertAttachment({\n ...lastAttachment,\n status: {\n type: \"incomplete\",\n reason: \"error\",\n message: e instanceof Error ? e.message : String(e),\n },\n });\n }\n this._safeEmitAttachmentAddError(\n \"adapter-error\",\n e instanceof Error ? e.message : String(e),\n lastAttachment?.id,\n e instanceof Error ? e : undefined,\n lastAttachment?.contentType || fileOrAttachment.type,\n );\n throw e;\n } finally {\n this._attachmentAddOperations.finish(operation);\n }\n\n if (this._attachmentAddOperations.isCancelled(operation)) return;\n if (\n lastAttachment?.status.type === \"incomplete\" &&\n lastAttachment.status.reason === \"error\"\n ) {\n this._safeEmitAttachmentAddError(\n \"adapter-error\",\n lastAttachment.status.message ??\n \"Attachment upload did not complete successfully.\",\n lastAttachment.id,\n undefined,\n lastAttachment.contentType || fileOrAttachment.type,\n );\n } else {\n this._notifyEventSubscribers(\"attachmentAdd\", {\n ...(lastAttachment?.contentType\n ? { contentType: lastAttachment.contentType }\n : fileOrAttachment.type\n ? { contentType: fileOrAttachment.type }\n : undefined),\n });\n }\n }\n\n private _safeEmitAttachmentAddError(\n reason: AttachmentAddErrorReason,\n message: string,\n attachmentId?: string,\n error?: Error,\n contentType?: string,\n ) {\n try {\n this._notifyEventSubscribers(\"attachmentAddError\", {\n reason,\n message,\n ...(attachmentId !== undefined && { attachmentId }),\n ...(error !== undefined && { error }),\n ...(contentType ? { contentType } : undefined),\n });\n } catch (subscriberError) {\n console.error(\n \"[assistant-ui] attachmentAddError subscriber threw:\",\n subscriberError,\n );\n }\n }\n\n async removeAttachment(attachmentId: string) {\n const index = this._attachments.findIndex((a) => a.id === attachmentId);\n if (index === -1) throw new Error(\"Attachment not found\");\n const attachment = this._attachments[index]!;\n\n this._cancelAttachmentAdd(attachmentId);\n\n // A send in flight may already be uploading this attachment; the upload\n // can't be cancelled, so mark it to be dropped from the outgoing message\n // before any await gives the upload a chance to settle first.\n if (this._isSending) this._removedDuringSend.add(attachmentId);\n\n if (!isAttachmentComplete(attachment)) {\n const adapter = this.getAttachmentAdapter();\n if (!adapter) throw new Error(\"Attachments are not supported\");\n try {\n await adapter.remove(attachment);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this._attachments = this._attachments.map((candidate) =>\n candidate.id === attachmentId && !isAttachmentComplete(candidate)\n ? {\n ...candidate,\n status: { type: \"incomplete\", reason: \"error\", message },\n }\n : candidate,\n );\n this._notifySubscribers();\n throw error;\n }\n }\n this._attachments = this._attachments.filter((a) => a.id !== attachmentId);\n this._notifySubscribers();\n }\n\n private _dictation: DictationState | undefined;\n private _dictationSession: DictationAdapter.Session | undefined;\n private _dictationUnsubscribes: Unsubscribe[] = [];\n private _dictationBaseText = \"\";\n private _currentInterimText = \"\";\n private _dictationSessionIdCounter = 0;\n private _activeDictationSessionId: number | undefined;\n private _isCleaningDictation = false;\n\n public get dictation(): DictationState | undefined {\n return this._dictation;\n }\n\n private _isActiveSession(\n sessionId: number,\n session: DictationAdapter.Session,\n ): boolean {\n return (\n this._activeDictationSessionId === sessionId &&\n this._dictationSession === session\n );\n }\n\n public startDictation(): void {\n const adapter = this.getDictationAdapter();\n if (!adapter) {\n throw new Error(\"Dictation adapter not configured\");\n }\n\n const isReplacing = this._dictationSession !== undefined;\n if (this._dictationSession) {\n const oldSession = this._dictationSession;\n this._cleanupDictation({ notify: false });\n this._stopDictationSession(oldSession);\n }\n\n const inputDisabled = adapter.disableInputDuringDictation ?? false;\n\n this._dictationBaseText = this._text;\n this._currentInterimText = \"\";\n\n let session: DictationAdapter.Session;\n try {\n session = adapter.listen();\n } catch (error) {\n if (isReplacing) {\n try {\n this._notifySubscribers();\n } catch (notifyError) {\n console.error(\n \"[assistant-ui] Dictation replacement rollback notification threw\",\n notifyError,\n );\n }\n }\n throw error;\n }\n this._dictationSession = session;\n const sessionId = ++this._dictationSessionIdCounter;\n this._activeDictationSessionId = sessionId;\n this._dictation = { status: session.status, inputDisabled };\n this._notifySubscribers();\n\n const unsubSpeech = session.onSpeech((result) => {\n if (!this._isActiveSession(sessionId, session)) return;\n const isFinal = result.isFinal !== false;\n\n const needsSeparator =\n this._dictationBaseText &&\n !this._dictationBaseText.endsWith(\" \") &&\n result.transcript;\n const separator = needsSeparator ? \" \" : \"\";\n\n if (isFinal) {\n this._dictationBaseText =\n this._dictationBaseText + separator + result.transcript;\n this._currentInterimText = \"\";\n this._text = this._dictationBaseText;\n\n if (this._dictation) {\n const { transcript: _, ...rest } = this._dictation;\n this._dictation = rest;\n }\n this._notifySubscribers();\n } else {\n this._currentInterimText = separator + result.transcript;\n this._text = this._dictationBaseText + this._currentInterimText;\n\n if (this._dictation) {\n this._dictation = {\n ...this._dictation,\n transcript: result.transcript,\n };\n }\n this._notifySubscribers();\n }\n });\n this._dictationUnsubscribes.push(unsubSpeech);\n\n const unsubStart = session.onSpeechStart(() => {\n if (!this._isActiveSession(sessionId, session)) return;\n\n this._dictation = {\n status: { type: \"running\" },\n inputDisabled,\n ...(this._dictation?.transcript && {\n transcript: this._dictation.transcript,\n }),\n };\n this._notifySubscribers();\n });\n this._dictationUnsubscribes.push(unsubStart);\n\n const unsubEnd = session.onSpeechEnd(() => {\n this._cleanupDictation({ sessionId });\n });\n this._dictationUnsubscribes.push(unsubEnd);\n\n const statusInterval = setInterval(() => {\n if (!this._isActiveSession(sessionId, session)) return;\n\n if (session.status.type === \"ended\") {\n this._cleanupDictation({ sessionId });\n }\n }, 100);\n this._dictationUnsubscribes.push(() => clearInterval(statusInterval));\n }\n\n public stopDictation(): void {\n if (!this._dictationSession) return;\n\n const session = this._dictationSession;\n const sessionId = this._activeDictationSessionId;\n const cleanup = () => this._cleanupDictation({ sessionId });\n this._stopDictationSession(session, cleanup);\n }\n\n private _stopDictationSession(\n session: DictationAdapter.Session,\n onSettled: () => void = () => {},\n ): void {\n let task: Promise<void>;\n try {\n task = session.stop();\n } catch (error) {\n console.error(\"[assistant-ui] Dictation session stop threw\", error);\n onSettled();\n return;\n }\n\n void task.then(onSettled, (error) => {\n console.error(\"[assistant-ui] Dictation session stop rejected\", error);\n onSettled();\n });\n }\n\n private _cleanupDictation(options?: {\n sessionId?: number | undefined;\n notify?: boolean | undefined;\n }): void {\n const isStaleSession =\n options?.sessionId !== undefined &&\n options.sessionId !== this._activeDictationSessionId;\n if (isStaleSession || this._isCleaningDictation) return;\n\n this._isCleaningDictation = true;\n const runCleanup = (cleanup: () => void) => {\n try {\n cleanup();\n } catch (error) {\n console.error(\"[assistant-ui] Dictation cleanup threw\", error);\n }\n };\n\n try {\n const unsubscribes = this._dictationUnsubscribes;\n this._dictationUnsubscribes = [];\n this._dictationSession = undefined;\n this._activeDictationSessionId = undefined;\n this._dictation = undefined;\n this._dictationBaseText = \"\";\n this._currentInterimText = \"\";\n\n for (const unsubscribe of unsubscribes) runCleanup(unsubscribe);\n if (options?.notify !== false) {\n runCleanup(() => this._notifySubscribers());\n }\n } finally {\n this._isCleaningDictation = false;\n }\n }\n\n private _eventSubscribers = new Map<\n ComposerRuntimeEventType,\n Set<(payload?: unknown) => void>\n >();\n\n protected _notifyEventSubscribers<E extends ComposerRuntimeEventType>(\n event: E,\n payload: ComposerRuntimeEventPayload[E],\n ) {\n const subscribers = this._eventSubscribers.get(event);\n if (!subscribers) return;\n\n notifyEventListeners(subscribers, payload, `Composer runtime \"${event}\"`);\n }\n\n public unstable_on<E extends ComposerRuntimeEventType>(\n event: E,\n callback: ComposerRuntimeEventCallback<E>,\n ) {\n const wrapped = callback as (payload?: unknown) => void;\n let subscribers = this._eventSubscribers.get(event);\n if (!subscribers) {\n subscribers = new Set();\n this._eventSubscribers.set(event, subscribers);\n }\n subscribers.add(wrapped);\n\n return () => {\n this._eventSubscribers.get(event)?.delete(wrapped);\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -69,6 +69,7 @@ declare abstract class BaseThreadRuntimeCore extends BaseSubscribable implements
|
|
|
69
69
|
protected enrichAppendMetadata(message: AppendMessage, anchorId?: string | null): AppendMessage;
|
|
70
70
|
private _editComposers;
|
|
71
71
|
getEditComposer(messageId: string): DefaultEditComposerRuntimeCore | undefined;
|
|
72
|
+
protected _isVoiceMessage(messageId: string | null): boolean;
|
|
72
73
|
beginEdit(messageId: string): void;
|
|
73
74
|
getMessageById(messageId: string): {
|
|
74
75
|
parentId: string | null;
|
|
@@ -78,6 +79,7 @@ declare abstract class BaseThreadRuntimeCore extends BaseSubscribable implements
|
|
|
78
79
|
getBranches(messageId: string): string[];
|
|
79
80
|
switchToBranch(branchId: string): void;
|
|
80
81
|
_notifyEventSubscribers<E extends ThreadRuntimeEventType>(event: E, payload: ThreadRuntimeEventPayload[E]): void;
|
|
82
|
+
protected _notifyToolApprovalAnswered(messageId: string, toolCallId: string, toolName: string, approved: boolean): void;
|
|
81
83
|
submitFeedback({ messageId, type }: SubmitFeedbackOptions): void;
|
|
82
84
|
private _stopSpeaking;
|
|
83
85
|
speech: SpeechState | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-thread-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/base-thread-runtime-core.ts"],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"base-thread-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/base-thread-runtime-core.ts"],"mappings":";;;;;;;;;;;;;;;KA2CK;EACH,SAAS;EACT,WAAW;EACX,cAAc;EACd,QAAQ;;uBAGY,8BACZ,4BACG;UAEH;YAEE,YAAU;eACA,YAAY;eACZ;eACA;eACA;eACA,wBAAwB;eACxB;eAEA,gBAAgB;WACpB,OAAO,SAAS;WAChB,cAAc,2BAA2B;WACzC,SAAS,QAAQ;WACjB,UAAU,QAAQ;WAClB,cAAc,SAAS;WACvB,eAAe,SAAS;WACxB,sBACd,SAAS,+BACR;WACa;WACA;WACA,oBAAoB;WACpB;YAEN,gBAAgB;YAChB;UACF;UACA;UACA;YAEE;YAKA,6BAA6B;MAI5B,qBAAqB;MAgBrB,sEAAK,sDAAA;WAWA,UAAQ;mBAEP;EAEL,YAAA,kBAAkB;EAKvB,mBALuB;;;;;;;;;;;;;;YAsBpB,qBACR,SAAS,eACT,2BACC;UAmBK;EACD,gBAAgB,oBAAiB;YAG9B,gBAAgB;EAMnB,UAAU;EAkBV,eAAe;;;;;EAsBf,YAAY;EAOZ,eAAe;EAKf,wBAAwB,UAAU,wBACvC,OAAO,GACP,SAAS,0BAA0B;YAQ3B,4BACR,mBACA,oBACA,kBACA;EAUK,iBAAiB,WAAW,QAAQ;UAkCnC;EACD,QAAQ;EAER,MAAM;EA2EN;UAKC;UACA;EACD,OAAO;UAEN;UACA;EAED;EAEA,uBAAwB,yBAAuB;EAK/C;UA+GC;UAEA;UAiEA;EAaD;EA8BA;EAUA;YAUG;EAOH,UAAM;EAIN,OAAO,MAAM;EAOb,MAAM,2BAA2B;UAIhC;EAKD,YAAY,UAAU,wBAC3B,OAAO,GACP,UAAU,2BAA2B,KAAE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { gateInteractableComposerMetadata } from "../../model-context/interactable-composer-metadata.js";
|
|
2
2
|
import { notifyEventListeners } from "../../utils/notify-event-listeners.js";
|
|
3
|
-
import { BaseSubscribable } from "../../subscribable/subscribable.js";
|
|
3
|
+
import { BaseSubscribable, notifySubscribers } from "../../subscribable/subscribable.js";
|
|
4
4
|
import { generateId } from "../../utils/id.js";
|
|
5
5
|
import { getThreadMessageText } from "../../utils/text.js";
|
|
6
6
|
import { ExportedMessageRepository, MessageRepository } from "../utils/message-repository.js";
|
|
@@ -80,7 +80,11 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
80
80
|
getEditComposer(messageId) {
|
|
81
81
|
return this._editComposers.get(messageId);
|
|
82
82
|
}
|
|
83
|
+
_isVoiceMessage(messageId) {
|
|
84
|
+
return messageId !== null && this._voiceMessages.some((m) => m.id === messageId);
|
|
85
|
+
}
|
|
83
86
|
beginEdit(messageId) {
|
|
87
|
+
if (this._isVoiceMessage(messageId)) throw new Error("Voice transcript messages cannot be edited");
|
|
84
88
|
if (this._editComposers.has(messageId)) throw new Error("Edit already in progress");
|
|
85
89
|
this._editComposers.set(messageId, new DefaultEditComposerRuntimeCore(this, () => this._editComposers.delete(messageId), this.repository.getMessage(messageId)));
|
|
86
90
|
this._notifySubscribers();
|
|
@@ -112,10 +116,20 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
112
116
|
if (!subscribers) return;
|
|
113
117
|
notifyEventListeners(subscribers, payload, `Thread runtime "${event}"`);
|
|
114
118
|
}
|
|
119
|
+
_notifyToolApprovalAnswered(messageId, toolCallId, toolName, approved) {
|
|
120
|
+
this._notifyEventSubscribers("toolApprovalAnswered", {
|
|
121
|
+
messageId,
|
|
122
|
+
toolCallId,
|
|
123
|
+
toolName,
|
|
124
|
+
approved
|
|
125
|
+
});
|
|
126
|
+
}
|
|
115
127
|
submitFeedback({ messageId, type }) {
|
|
116
128
|
const adapter = this.adapters?.feedback;
|
|
117
129
|
if (!adapter) throw new Error("Feedback adapter not configured");
|
|
118
|
-
const
|
|
130
|
+
const entry = this.getMessageById(messageId);
|
|
131
|
+
if (!entry) throw new Error(`Message not found: ${messageId}`);
|
|
132
|
+
const { message, parentId } = entry;
|
|
119
133
|
adapter.submit({
|
|
120
134
|
message,
|
|
121
135
|
type
|
|
@@ -128,7 +142,13 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
128
142
|
submittedFeedback: { type }
|
|
129
143
|
}
|
|
130
144
|
};
|
|
131
|
-
this.
|
|
145
|
+
const voiceIdx = this._voiceMessages.findIndex((voiceMessage) => voiceMessage.id === messageId);
|
|
146
|
+
if (voiceIdx === -1) this.repository.addOrUpdateMessage(parentId, updatedMessage);
|
|
147
|
+
else {
|
|
148
|
+
this._voiceMessages[voiceIdx] = updatedMessage;
|
|
149
|
+
if (this._currentAssistantMsg === message) this._currentAssistantMsg = updatedMessage;
|
|
150
|
+
this._markVoiceMessagesDirty();
|
|
151
|
+
}
|
|
132
152
|
}
|
|
133
153
|
this._notifySubscribers();
|
|
134
154
|
}
|
|
@@ -137,35 +157,69 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
137
157
|
speak(messageId) {
|
|
138
158
|
const adapter = this.adapters?.speech;
|
|
139
159
|
if (!adapter) throw new Error("Speech adapter not configured");
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
this._stopSpeaking = () => {
|
|
159
|
-
utterance.cancel();
|
|
160
|
-
unsub();
|
|
161
|
-
this.speech = void 0;
|
|
160
|
+
const entry = this.getMessageById(messageId);
|
|
161
|
+
if (!entry) throw new Error(`Message not found: ${messageId}`);
|
|
162
|
+
const { message } = entry;
|
|
163
|
+
const previousStop = this._stopSpeaking;
|
|
164
|
+
let utterance;
|
|
165
|
+
try {
|
|
166
|
+
previousStop?.();
|
|
167
|
+
utterance = adapter.speak(getThreadMessageText(message));
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (previousStop && !this._stopSpeaking) try {
|
|
170
|
+
this._notifySubscribers();
|
|
171
|
+
} catch (notificationError) {
|
|
172
|
+
console.error("[assistant-ui] Speech rollback notification threw", notificationError);
|
|
173
|
+
}
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
let unsub;
|
|
177
|
+
const clear = () => {
|
|
162
178
|
this._stopSpeaking = void 0;
|
|
179
|
+
this.speech = void 0;
|
|
180
|
+
const cleanup = unsub;
|
|
181
|
+
unsub = void 0;
|
|
182
|
+
cleanup?.();
|
|
163
183
|
};
|
|
184
|
+
const stop = () => {
|
|
185
|
+
if (this._stopSpeaking !== stop) return;
|
|
186
|
+
try {
|
|
187
|
+
clear();
|
|
188
|
+
} finally {
|
|
189
|
+
utterance.cancel();
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
const update = () => {
|
|
193
|
+
if (this._stopSpeaking !== stop) return;
|
|
194
|
+
if (utterance.status.type === "ended") notifySubscribers([clear, () => this._notifySubscribers()]);
|
|
195
|
+
else {
|
|
196
|
+
this.speech = {
|
|
197
|
+
messageId,
|
|
198
|
+
status: utterance.status
|
|
199
|
+
};
|
|
200
|
+
this._notifySubscribers();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
this._stopSpeaking = stop;
|
|
204
|
+
try {
|
|
205
|
+
unsub = utterance.subscribe(update);
|
|
206
|
+
if (this._stopSpeaking !== stop) {
|
|
207
|
+
unsub();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
update();
|
|
211
|
+
} catch (error) {
|
|
212
|
+
if (this._stopSpeaking === stop) try {
|
|
213
|
+
notifySubscribers([stop, () => this._notifySubscribers()]);
|
|
214
|
+
} catch (cleanupError) {
|
|
215
|
+
console.error("[assistant-ui] Speech rollback cleanup threw", cleanupError);
|
|
216
|
+
}
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
164
219
|
}
|
|
165
220
|
stopSpeaking() {
|
|
166
221
|
if (!this._stopSpeaking) throw new Error("No message is being spoken");
|
|
167
|
-
this._stopSpeaking();
|
|
168
|
-
this._notifySubscribers();
|
|
222
|
+
notifySubscribers([this._stopSpeaking, () => this._notifySubscribers()]);
|
|
169
223
|
}
|
|
170
224
|
_voiceSession;
|
|
171
225
|
_voiceUnsubs = [];
|
|
@@ -180,48 +234,76 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
180
234
|
connectVoice() {
|
|
181
235
|
const adapter = this.adapters?.voice;
|
|
182
236
|
if (!adapter) throw new Error("Voice adapter not configured");
|
|
183
|
-
|
|
237
|
+
try {
|
|
238
|
+
this.disconnectVoice();
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error("[assistant-ui] Voice cleanup threw before reconnect", error);
|
|
241
|
+
}
|
|
184
242
|
const session = adapter.connect({});
|
|
185
243
|
this._voiceSession = session;
|
|
186
244
|
const unsubs = [];
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
245
|
+
this._voiceUnsubs = unsubs;
|
|
246
|
+
const finishDetachedSetup = () => {
|
|
247
|
+
if (this._voiceSession === session && this._voiceUnsubs === unsubs) return false;
|
|
248
|
+
try {
|
|
249
|
+
notifySubscribers(unsubs.splice(0));
|
|
250
|
+
} catch (error) {
|
|
251
|
+
console.error("[assistant-ui] Detached voice setup cleanup threw", error);
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
192
254
|
};
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
this._finishVoiceAssistantMessage();
|
|
198
|
-
this._voiceSession = void 0;
|
|
199
|
-
this.voice = void 0;
|
|
200
|
-
} else this.voice = {
|
|
201
|
-
status,
|
|
255
|
+
try {
|
|
256
|
+
let currentMode = "listening";
|
|
257
|
+
this.voice = {
|
|
258
|
+
status: session.status,
|
|
202
259
|
isMuted: session.isMuted,
|
|
203
260
|
mode: currentMode
|
|
204
261
|
};
|
|
262
|
+
this._voiceVolume = 0;
|
|
205
263
|
this._notifySubscribers();
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
264
|
+
if (finishDetachedSetup()) return;
|
|
265
|
+
unsubs.push(session.onStatusChange((status) => {
|
|
266
|
+
if (status.type === "ended") {
|
|
267
|
+
this._finishVoiceAssistantMessage();
|
|
268
|
+
this._voiceSession = void 0;
|
|
269
|
+
this.voice = void 0;
|
|
270
|
+
} else this.voice = {
|
|
271
|
+
status,
|
|
272
|
+
isMuted: session.isMuted,
|
|
273
|
+
mode: currentMode
|
|
213
274
|
};
|
|
214
275
|
this._notifySubscribers();
|
|
276
|
+
}));
|
|
277
|
+
if (finishDetachedSetup()) return;
|
|
278
|
+
unsubs.push(session.onModeChange((mode) => {
|
|
279
|
+
currentMode = mode;
|
|
280
|
+
if (this.voice) {
|
|
281
|
+
this.voice = {
|
|
282
|
+
...this.voice,
|
|
283
|
+
mode
|
|
284
|
+
};
|
|
285
|
+
this._notifySubscribers();
|
|
286
|
+
}
|
|
287
|
+
}));
|
|
288
|
+
if (finishDetachedSetup()) return;
|
|
289
|
+
unsubs.push(session.onVolumeChange((volume) => {
|
|
290
|
+
this._voiceVolume = volume;
|
|
291
|
+
notifyEventListeners(this._voiceVolumeSubscribers, void 0, "Voice volume");
|
|
292
|
+
}));
|
|
293
|
+
if (finishDetachedSetup()) return;
|
|
294
|
+
unsubs.push(session.onTranscript((transcript) => {
|
|
295
|
+
this._handleVoiceTranscript(transcript);
|
|
296
|
+
}));
|
|
297
|
+
finishDetachedSetup();
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (this._voiceSession === session && this._voiceUnsubs === unsubs) try {
|
|
300
|
+
this.disconnectVoice();
|
|
301
|
+
} catch (cleanupError) {
|
|
302
|
+
console.error("[assistant-ui] Voice rollback cleanup threw", cleanupError);
|
|
215
303
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
notifyEventListeners(this._voiceVolumeSubscribers, void 0, "Voice volume");
|
|
220
|
-
}));
|
|
221
|
-
unsubs.push(session.onTranscript((transcript) => {
|
|
222
|
-
this._handleVoiceTranscript(transcript);
|
|
223
|
-
}));
|
|
224
|
-
this._voiceUnsubs = unsubs;
|
|
304
|
+
else finishDetachedSetup();
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
225
307
|
}
|
|
226
308
|
_currentAssistantMsg = null;
|
|
227
309
|
_handleVoiceTranscript(transcript) {
|
|
@@ -237,7 +319,10 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
237
319
|
type: "text",
|
|
238
320
|
text: transcript.text
|
|
239
321
|
}],
|
|
240
|
-
metadata: {
|
|
322
|
+
metadata: {
|
|
323
|
+
modality: "voice",
|
|
324
|
+
custom: {}
|
|
325
|
+
},
|
|
241
326
|
createdAt: /* @__PURE__ */ new Date(),
|
|
242
327
|
status: {
|
|
243
328
|
type: "complete",
|
|
@@ -249,6 +334,10 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
249
334
|
this._notifySubscribers();
|
|
250
335
|
}
|
|
251
336
|
} else {
|
|
337
|
+
const status = transcript.isFinal ? {
|
|
338
|
+
type: "complete",
|
|
339
|
+
reason: "stop"
|
|
340
|
+
} : { type: "running" };
|
|
252
341
|
if (!this._currentAssistantMsg) {
|
|
253
342
|
this._currentAssistantMsg = {
|
|
254
343
|
id: generateId(),
|
|
@@ -262,9 +351,10 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
262
351
|
unstable_annotations: [],
|
|
263
352
|
unstable_data: [],
|
|
264
353
|
steps: [],
|
|
354
|
+
modality: "voice",
|
|
265
355
|
custom: {}
|
|
266
356
|
},
|
|
267
|
-
status
|
|
357
|
+
status,
|
|
268
358
|
createdAt: /* @__PURE__ */ new Date()
|
|
269
359
|
};
|
|
270
360
|
this._voiceMessages.push(this._currentAssistantMsg);
|
|
@@ -277,10 +367,7 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
277
367
|
type: "text",
|
|
278
368
|
text: transcript.text
|
|
279
369
|
}],
|
|
280
|
-
|
|
281
|
-
type: "complete",
|
|
282
|
-
reason: "stop"
|
|
283
|
-
} } : {}
|
|
370
|
+
status
|
|
284
371
|
};
|
|
285
372
|
this._voiceMessages[idx] = updated;
|
|
286
373
|
this._currentAssistantMsg = updated;
|
|
@@ -306,18 +393,23 @@ var BaseThreadRuntimeCore = class extends BaseSubscribable {
|
|
|
306
393
|
}
|
|
307
394
|
}
|
|
308
395
|
disconnectVoice() {
|
|
309
|
-
this._finishVoiceAssistantMessage();
|
|
310
396
|
this._currentAssistantMsg = null;
|
|
311
|
-
|
|
397
|
+
const unsubs = this._voiceUnsubs.splice(0);
|
|
312
398
|
this._voiceUnsubs = [];
|
|
313
|
-
this._voiceSession
|
|
399
|
+
const session = this._voiceSession;
|
|
314
400
|
this._voiceSession = void 0;
|
|
315
401
|
this.voice = void 0;
|
|
316
402
|
this._voiceVolume = 0;
|
|
317
|
-
|
|
403
|
+
const stopSpeaking = this.speech && this._isVoiceMessage(this.speech.messageId) ? this._stopSpeaking : void 0;
|
|
318
404
|
this._voiceMessages = [];
|
|
319
405
|
this._markVoiceMessagesDirty();
|
|
320
|
-
|
|
406
|
+
notifySubscribers([
|
|
407
|
+
...unsubs,
|
|
408
|
+
...stopSpeaking ? [stopSpeaking] : [],
|
|
409
|
+
...session ? [() => session.disconnect()] : [],
|
|
410
|
+
() => notifyEventListeners(this._voiceVolumeSubscribers, void 0, "Voice volume"),
|
|
411
|
+
() => this._notifySubscribers()
|
|
412
|
+
]);
|
|
321
413
|
}
|
|
322
414
|
muteVoice() {
|
|
323
415
|
if (!this._voiceSession) throw new Error("No active voice session");
|