@assistant-ui/core 0.3.16 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/attachment.d.ts.map +1 -1
- package/dist/adapters/attachment.js +5 -4
- package/dist/adapters/attachment.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +4 -2
- package/dist/internal.js +4 -2
- package/dist/model-context/frame/host.d.ts.map +1 -1
- package/dist/model-context/frame/host.js +10 -4
- package/dist/model-context/frame/host.js.map +1 -1
- package/dist/model-context/frame/provider.d.ts +5 -0
- package/dist/model-context/frame/provider.d.ts.map +1 -1
- package/dist/model-context/frame/provider.js +101 -28
- package/dist/model-context/frame/provider.js.map +1 -1
- package/dist/model-context/interactable-composer-metadata.d.ts.map +1 -1
- package/dist/model-context/interactable-composer-metadata.js +16 -9
- package/dist/model-context/interactable-composer-metadata.js.map +1 -1
- package/dist/model-context/registry.d.ts.map +1 -1
- package/dist/model-context/registry.js +3 -5
- package/dist/model-context/registry.js.map +1 -1
- package/dist/model-context/tool-call-text.d.ts +26 -0
- package/dist/model-context/tool-call-text.d.ts.map +1 -0
- package/dist/model-context/tool-call-text.js +18 -0
- package/dist/model-context/tool-call-text.js.map +1 -0
- package/dist/model-context/types.d.ts.map +1 -1
- package/dist/model-context/types.js +5 -4
- package/dist/model-context/types.js.map +1 -1
- package/dist/react/RuntimeAdapter.js +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.d.ts.map +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js +1 -1
- package/dist/react/adapters/LocalStorageThreadListAdapter.js.map +1 -1
- package/dist/react/client/AdaptedRemoteThread.js +1 -1
- package/dist/react/client/InMemoryThreadList.d.ts.map +1 -1
- package/dist/react/client/InMemoryThreadList.js +63 -57
- package/dist/react/client/InMemoryThreadList.js.map +1 -1
- package/dist/react/client/Interactables.d.ts.map +1 -1
- package/dist/react/client/Interactables.js +25 -28
- package/dist/react/client/Interactables.js.map +1 -1
- package/dist/react/client/RemoteThreadList.d.ts +16 -0
- package/dist/react/client/RemoteThreadList.d.ts.map +1 -1
- package/dist/react/client/RemoteThreadList.js +354 -242
- package/dist/react/client/RemoteThreadList.js.map +1 -1
- package/dist/react/client/Tools.d.ts.map +1 -1
- package/dist/react/client/Tools.js +24 -18
- package/dist/react/client/Tools.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +2 -1
- package/dist/react/interactables-legacy/Interactables.js +246 -125
- package/dist/react/interactables-legacy/Interactables.js.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.d.ts.map +1 -1
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js +11 -9
- package/dist/react/interactables-shared/useInteractablePersistenceQueue.js.map +1 -1
- package/dist/react/model-context/makeAssistantTool.d.ts +2 -2
- package/dist/react/model-context/makeAssistantTool.js +1 -1
- package/dist/react/model-context/makeAssistantTool.js.map +1 -1
- package/dist/react/model-context/toolbox.d.ts +2 -14
- package/dist/react/model-context/toolbox.d.ts.map +1 -1
- package/dist/react/model-context/toolbox.js +1 -13
- package/dist/react/model-context/toolbox.js.map +1 -1
- package/dist/react/model-context/useAssistantContext.js +37 -7
- package/dist/react/model-context/useAssistantContext.js.map +1 -1
- package/dist/react/model-context/useAssistantTool.d.ts +2 -2
- package/dist/react/model-context/useAssistantTool.js +1 -1
- package/dist/react/model-context/useAssistantTool.js.map +1 -1
- package/dist/react/model-context/useAuiToolOverrides.js +31 -5
- package/dist/react/model-context/useAuiToolOverrides.js.map +1 -1
- package/dist/react/model-context/useInlineRender.d.ts.map +1 -1
- package/dist/react/model-context/useInlineRender.js +10 -36
- package/dist/react/model-context/useInlineRender.js.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.d.ts.map +1 -1
- package/dist/react/model-context/useToolArgsStatus.js +2 -1
- package/dist/react/model-context/useToolArgsStatus.js.map +1 -1
- package/dist/react/primitive-hooks/useMessageError.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useMessageError.js +2 -8
- package/dist/react/primitive-hooks/useMessageError.js.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.d.ts.map +1 -1
- package/dist/react/primitive-hooks/useThreadListLoadMore.js +2 -4
- package/dist/react/primitive-hooks/useThreadListLoadMore.js.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerAttachments.js +4 -3
- package/dist/react/primitives/composer/ComposerAttachments.js.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.d.ts.map +1 -1
- package/dist/react/primitives/composer/ComposerQueue.js +4 -3
- package/dist/react/primitives/composer/ComposerQueue.js.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageAttachments.js +7 -6
- package/dist/react/primitives/message/MessageAttachments.js.map +1 -1
- package/dist/react/primitives/message/MessageGroupedParts.js +2 -2
- package/dist/react/primitives/message/MessageGroupedParts.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.js +3 -3
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/react/primitives/threadList/ThreadListItems.js +5 -4
- package/dist/react/primitives/threadList/ThreadListItems.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +6 -4
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +59 -29
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +11 -6
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +160 -143
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.d.ts +2 -6
- package/dist/react/runtimes/RemoteThreadResource.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadResource.js +15 -13
- package/dist/react/runtimes/RemoteThreadResource.js.map +1 -1
- package/dist/react/runtimes/assistant-transport/useLatestRef.js +2 -2
- package/dist/react/runtimes/assistant-transport/useLatestRef.js.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts +4 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +424 -52
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +5 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts +29 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +160 -0
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js.map +1 -0
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts +1 -9
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js +16 -153
- package/dist/react/runtimes/cloud/useCloudThreadListAdapter.js.map +1 -1
- package/dist/react/runtimes/external-message-converter.js +1 -1
- package/dist/react/runtimes/external-message-converter.js.map +1 -1
- package/dist/react/runtimes/useExternalStoreRuntime.js +75 -46
- package/dist/react/runtimes/useExternalStoreRuntime.js.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -1
- package/dist/react/runtimes/useRemoteThreadListRuntime.js +77 -29
- package/dist/react/runtimes/useRemoteThreadListRuntime.js.map +1 -1
- package/dist/react/types/MessagePartComponentTypes.d.ts +7 -3
- package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
- package/dist/react/types/scopes/tools.d.ts +2 -0
- package/dist/react/types/scopes/tools.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.d.ts +2 -2
- package/dist/runtime/api/message-part-runtime.d.ts.map +1 -1
- package/dist/runtime/api/message-part-runtime.js +1 -1
- package/dist/runtime/api/message-part-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.d.ts +7 -3
- package/dist/runtime/api/thread-list-item-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-item-runtime.js +2 -2
- package/dist/runtime/api/thread-list-item-runtime.js.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +12 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +23 -14
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +5 -1
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +1 -1
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +16 -12
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +2 -2
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +8 -7
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/composer-runtime-core.d.ts +12 -5
- package/dist/runtime/interfaces/composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +18 -3
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +15 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.d.ts +1 -1
- package/dist/runtime/utils/auto-status.d.ts.map +1 -1
- package/dist/runtime/utils/auto-status.js +6 -2
- package/dist/runtime/utils/auto-status.js.map +1 -1
- package/dist/runtime/utils/external-message-conversion.d.ts +3 -2
- package/dist/runtime/utils/external-message-conversion.d.ts.map +1 -1
- package/dist/runtime/utils/external-message-conversion.js +5 -4
- package/dist/runtime/utils/external-message-conversion.js.map +1 -1
- package/dist/runtime/utils/message-repository.d.ts +1 -0
- package/dist/runtime/utils/message-repository.d.ts.map +1 -1
- package/dist/runtime/utils/message-repository.js +15 -6
- package/dist/runtime/utils/message-repository.js.map +1 -1
- package/dist/runtime/utils/resolveToolApprovalResponse.d.ts +6 -3
- package/dist/runtime/utils/resolveToolApprovalResponse.d.ts.map +1 -1
- package/dist/runtime/utils/resolveToolApprovalResponse.js +12 -3
- package/dist/runtime/utils/resolveToolApprovalResponse.js.map +1 -1
- package/dist/runtime/utils/thread-message-like.d.ts +2 -10
- package/dist/runtime/utils/thread-message-like.d.ts.map +1 -1
- package/dist/runtime/utils/thread-message-like.js +1 -1
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/runtime/utils/tool-call-tree.d.ts +39 -0
- package/dist/runtime/utils/tool-call-tree.d.ts.map +1 -0
- package/dist/runtime/utils/tool-call-tree.js +85 -0
- package/dist/runtime/utils/tool-call-tree.js.map +1 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts +29 -2
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +21 -27
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +2 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +34 -28
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/inert/InertThreadRuntimeCore.js.map +1 -1
- package/dist/runtimes/internal.d.ts +2 -2
- package/dist/runtimes/internal.js +2 -2
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +3 -1
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts +18 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.d.ts.map +1 -1
- package/dist/runtimes/remote-thread-list/remote-thread-state.js +148 -43
- package/dist/runtimes/remote-thread-list/remote-thread-state.js.map +1 -1
- package/dist/runtimes/remote-thread-list/title-generation.d.ts +49 -0
- package/dist/runtimes/remote-thread-list/title-generation.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/title-generation.js +197 -0
- package/dist/runtimes/remote-thread-list/title-generation.js.map +1 -0
- package/dist/runtimes/remote-thread-list/title.d.ts +11 -0
- package/dist/runtimes/remote-thread-list/title.d.ts.map +1 -0
- package/dist/runtimes/remote-thread-list/title.js +14 -0
- package/dist/runtimes/remote-thread-list/title.js.map +1 -0
- package/dist/runtimes/remote-thread-list/types.d.ts +16 -5
- package/dist/runtimes/remote-thread-list/types.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts +31 -8
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.d.ts.map +1 -1
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js +97 -60
- package/dist/runtimes/tool-invocations/ToolInvocationTracker.js.map +1 -1
- package/dist/store/clients/external-thread.d.ts +1 -1
- package/dist/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +30 -7
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/model-context-client.d.ts.map +1 -1
- package/dist/store/clients/model-context-client.js +2 -1
- package/dist/store/clients/model-context-client.js.map +1 -1
- package/dist/store/clients/single-thread-list.d.ts.map +1 -1
- package/dist/store/clients/single-thread-list.js +2 -1
- package/dist/store/clients/single-thread-list.js.map +1 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/suggestions.js +19 -6
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/clients/thread-message-client.js +1 -1
- package/dist/store/clients/thread-selection-events.js +1 -1
- package/dist/store/index.d.ts +2 -1
- package/dist/store/index.js +2 -1
- package/dist/store/internal.d.ts +2 -2
- package/dist/store/internal.js +2 -2
- package/dist/store/primitive-predicates.d.ts +4 -1
- package/dist/store/primitive-predicates.d.ts.map +1 -1
- package/dist/store/primitive-predicates.js +9 -1
- package/dist/store/primitive-predicates.js.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/composer-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/composer-runtime-client.js +98 -62
- package/dist/store/runtime-clients/composer-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/message-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/message-runtime-client.js +221 -144
- package/dist/store/runtime-clients/message-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +2 -2
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js +128 -107
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +194 -122
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/useSubscribable.d.ts +3 -1
- package/dist/store/runtime-clients/useSubscribable.d.ts.map +1 -1
- package/dist/store/runtime-clients/useSubscribable.js +1 -1
- package/dist/store/runtime-clients/useSubscribable.js.map +1 -1
- package/dist/store/scopes/composer.d.ts +10 -2
- package/dist/store/scopes/composer.d.ts.map +1 -1
- package/dist/store/scopes/message.d.ts +30 -1
- package/dist/store/scopes/message.d.ts.map +1 -1
- package/dist/store/scopes/part.d.ts +6 -3
- package/dist/store/scopes/part.d.ts.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +2 -2
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/dist/store/scopes/thread.d.ts +8 -0
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/store/scopes/threads.d.ts +1 -0
- package/dist/store/scopes/threads.d.ts.map +1 -1
- package/dist/subscribable/subscribable.d.ts +8 -1
- package/dist/subscribable/subscribable.d.ts.map +1 -1
- package/dist/subscribable/subscribable.js +24 -16
- package/dist/subscribable/subscribable.js.map +1 -1
- package/dist/types/attachment.d.ts +2 -1
- package/dist/types/attachment.d.ts.map +1 -1
- package/dist/types/attachment.js +2 -1
- package/dist/types/attachment.js.map +1 -1
- package/dist/types/message.d.ts +40 -1
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js +7 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/abortable-iterable.d.ts +19 -0
- package/dist/utils/abortable-iterable.d.ts.map +1 -0
- package/dist/utils/abortable-iterable.js +72 -0
- package/dist/utils/abortable-iterable.js.map +1 -0
- package/dist/utils/composite-context-provider.d.ts.map +1 -1
- package/dist/utils/composite-context-provider.js +20 -2
- package/dist/utils/composite-context-provider.js.map +1 -1
- package/dist/utils/record.d.ts +11 -0
- package/dist/utils/record.d.ts.map +1 -0
- package/dist/utils/record.js +12 -0
- package/dist/utils/record.js.map +1 -0
- package/package.json +12 -17
- package/src/adapters/attachment.test.ts +50 -1
- package/src/adapters/attachment.ts +7 -4
- package/src/index.ts +7 -1
- package/src/internal.ts +12 -0
- package/src/model-context/frame/host.test.ts +24 -0
- package/src/model-context/frame/host.ts +10 -4
- package/src/model-context/frame/provider.test.ts +288 -1
- package/src/model-context/frame/provider.ts +148 -30
- package/src/model-context/interactable-composer-metadata.test.ts +28 -0
- package/src/model-context/interactable-composer-metadata.ts +9 -3
- package/src/model-context/registry.test.ts +12 -0
- package/src/model-context/registry.ts +3 -2
- package/src/model-context/tool-call-text.test.ts +67 -0
- package/src/model-context/tool-call-text.ts +67 -0
- package/src/model-context/types.test.ts +25 -0
- package/src/model-context/types.ts +9 -4
- package/src/react/AssistantRuntimeProvider.test.tsx +66 -2
- package/src/react/RuntimeAdapter.test.ts +34 -0
- package/src/react/adapters/LocalStorageThreadListAdapter.tsx +1 -3
- package/src/react/client/InMemoryThreadList.ts +1 -0
- package/src/react/client/Interactables.test.ts +28 -0
- package/src/react/client/Interactables.ts +15 -13
- package/src/react/client/RemoteThreadList.background.test.ts +526 -0
- package/src/react/client/RemoteThreadList.concurrent.test.tsx +315 -0
- package/src/react/client/RemoteThreadList.test.ts +617 -3
- package/src/react/client/RemoteThreadList.ts +433 -167
- package/src/react/client/Tools.ts +29 -12
- package/src/react/index.ts +4 -0
- package/src/react/interactables-legacy/Interactables.ts +16 -16
- package/src/react/interactables-shared/useInteractablePersistenceQueue.ts +9 -10
- package/src/react/model-context/makeAssistantTool.ts +2 -2
- package/src/react/model-context/modelContextHooks.test.tsx +131 -0
- package/src/react/model-context/toolbox.test.ts +9 -9
- package/src/react/model-context/toolbox.ts +9 -36
- package/src/react/model-context/useAssistantContext.ts +4 -2
- package/src/react/model-context/useAssistantTool.ts +2 -2
- package/src/react/model-context/useAuiToolOverrides.ts +4 -2
- package/src/react/model-context/useInlineRender.test.tsx +48 -0
- package/src/react/model-context/useInlineRender.ts +14 -10
- package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
- package/src/react/model-context/useToolArgsStatus.ts +2 -1
- package/src/react/primitive-hooks/useMessageError.ts +2 -19
- package/src/react/primitive-hooks/useThreadListLoadMore.ts +2 -3
- package/src/react/primitives/composer/ComposerAttachments.test.tsx +76 -0
- package/src/react/primitives/composer/ComposerAttachments.tsx +9 -4
- package/src/react/primitives/composer/ComposerQueue.test.tsx +72 -0
- package/src/react/primitives/composer/ComposerQueue.tsx +7 -4
- package/src/react/primitives/message/MessageAttachments.test.tsx +107 -37
- package/src/react/primitives/message/MessageAttachments.tsx +10 -7
- package/src/react/primitives/message/MessageGroupedParts.tsx +2 -2
- package/src/react/primitives/message/MessageParts.tsx +3 -3
- package/src/react/primitives/threadList/ThreadListItems.test.tsx +99 -0
- package/src/react/primitives/threadList/ThreadListItems.tsx +8 -5
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.destroy.test.tsx +172 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +127 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +7 -1
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +99 -35
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.load-error.test.ts +132 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.switch-delete.test.ts +274 -0
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +223 -152
- package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
- package/src/react/runtimes/RemoteThreadResource.ts +20 -16
- package/src/react/runtimes/assistant-transport/transport-scheduling.test.ts +51 -2
- package/src/react/runtimes/assistant-transport/useLatestRef.ts +2 -2
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.ts +45 -0
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +546 -5
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +546 -103
- package/src/react/runtimes/cloud/auiV0.ts +5 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +103 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.ts +237 -0
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.test.tsx +90 -1
- package/src/react/runtimes/cloud/useCloudThreadListAdapter.tsx +33 -238
- package/src/react/runtimes/external-message-converter.ts +1 -0
- package/src/react/runtimes/useExternalStoreRuntime.lifecycle.test.tsx +41 -0
- package/src/react/runtimes/useExternalStoreRuntime.ts +10 -4
- package/src/react/runtimes/useLocalRuntime.test.tsx +20 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.concurrent.test.tsx +216 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.load-error.test.tsx +108 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +57 -6
- package/src/react/types/MessagePartComponentTypes.ts +7 -3
- package/src/react/types/scopes/tools.ts +2 -0
- package/src/runtime/api/message-part-runtime.ts +3 -3
- package/src/runtime/api/message-runtime.test.ts +75 -0
- package/src/runtime/api/thread-list-item-runtime.ts +10 -3
- package/src/runtime/api/thread-list-runtime.ts +46 -12
- package/src/runtime/api/thread-runtime.test.ts +78 -0
- package/src/runtime/api/thread-runtime.ts +8 -1
- package/src/runtime/base/base-composer-runtime-core.ts +36 -8
- package/src/runtime/base/base-thread-runtime-core.test.ts +149 -4
- package/src/runtime/base/base-thread-runtime-core.ts +16 -8
- package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
- package/src/runtime/interfaces/thread-list-runtime-core.ts +25 -2
- package/src/runtime/interfaces/thread-runtime-core.ts +17 -1
- package/src/runtime/utils/auto-status.test.ts +57 -0
- package/src/runtime/utils/auto-status.ts +13 -1
- package/src/runtime/utils/external-message-conversion.test.ts +165 -0
- package/src/runtime/utils/external-message-conversion.ts +18 -2
- package/src/runtime/utils/message-repository.ts +29 -17
- package/src/runtime/utils/resolveToolApprovalResponse.test.ts +73 -0
- package/src/runtime/utils/resolveToolApprovalResponse.ts +27 -6
- package/src/runtime/utils/thread-message-like.ts +3 -11
- package/src/runtime/utils/tool-call-tree.test.ts +191 -0
- package/src/runtime/utils/tool-call-tree.ts +97 -0
- package/src/runtimes/external-store/external-store-adapter.ts +38 -2
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +18 -13
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +56 -33
- package/src/runtimes/inert/InertThreadRuntimeCore.ts +1 -1
- package/src/runtimes/internal.ts +1 -0
- package/src/runtimes/local/local-thread-runtime-core.test.ts +29 -3
- package/src/runtimes/local/local-thread-runtime-core.ts +5 -1
- package/src/runtimes/remote-thread-list/remote-thread-state.test.ts +238 -0
- package/src/runtimes/remote-thread-list/remote-thread-state.ts +223 -44
- package/src/runtimes/remote-thread-list/title-generation.test.ts +602 -0
- package/src/runtimes/remote-thread-list/title-generation.ts +329 -0
- package/src/runtimes/remote-thread-list/title.test.ts +62 -0
- package/src/runtimes/remote-thread-list/title.ts +16 -0
- package/src/runtimes/remote-thread-list/types.ts +16 -5
- package/src/runtimes/tool-invocations/EDGE_CASES.md +110 -5
- package/src/runtimes/tool-invocations/ToolInvocationTracker.test.ts +750 -136
- package/src/runtimes/tool-invocations/ToolInvocationTracker.ts +144 -91
- package/src/store/clients/external-thread.ts +62 -11
- package/src/store/clients/model-context-client.ts +5 -1
- package/src/store/clients/single-thread-list.ts +1 -0
- package/src/store/clients/suggestions.test.ts +195 -1
- package/src/store/clients/suggestions.ts +45 -34
- package/src/store/index.ts +4 -0
- package/src/store/internal.ts +2 -0
- package/src/store/primitive-predicates.ts +35 -0
- package/src/store/runtime-clients/composer-runtime-client.ts +42 -9
- package/src/store/runtime-clients/message-runtime-client.ts +54 -6
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +4 -2
- package/src/store/runtime-clients/thread-list-runtime-client.ts +17 -2
- package/src/store/runtime-clients/thread-runtime-client.ts +58 -10
- package/src/store/runtime-clients/useSubscribable.ts +8 -2
- package/src/store/scopes/composer.ts +16 -4
- package/src/store/scopes/message.ts +14 -0
- package/src/store/scopes/part.ts +6 -3
- package/src/store/scopes/thread-list-item.ts +5 -2
- package/src/store/scopes/thread.ts +4 -0
- package/src/store/scopes/threads.ts +1 -0
- package/src/subscribable/subscribable.test.ts +50 -0
- package/src/subscribable/subscribable.ts +33 -21
- package/src/tests/MessageRepository.test.ts +116 -0
- package/src/tests/OptimisticState-list-race.test.ts +1 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-initialize-adapter-change.test.ts +38 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-load-race.test.ts +158 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-loadMore.test.ts +78 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-reload.test.ts +52 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-title-race.test.ts +89 -0
- package/src/tests/attachment-adapters.test.ts +14 -0
- package/src/tests/base-composer-runtime-core.test.ts +39 -0
- package/src/tests/external-store-optimistic-id.test.ts +79 -0
- package/src/tests/external-store-repository-instance.test.ts +166 -0
- package/src/tests/external-store-thread-list-runtime-core.test.ts +83 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +49 -34
- package/src/tests/external-thread-attachments.test.tsx +224 -1
- package/src/tests/external-thread-parity.test.tsx +23 -0
- package/src/tests/remote-thread-list-adapter-switch.test.ts +66 -1
- package/src/tests/remote-thread-list-isLoading.test.ts +1 -0
- package/src/tests/thread-list-runtime-getLoadThreadsPromise.test.ts +1 -0
- package/src/tests/thread-switch-events.test.tsx +475 -2
- package/src/tests/tools-scope-migration.test.tsx +28 -0
- package/src/types/attachment.ts +4 -0
- package/src/types/message.ts +50 -2
- package/src/utils/abortable-iterable.test.ts +213 -0
- package/src/utils/abortable-iterable.ts +93 -0
- package/src/utils/composite-context-provider.test.ts +25 -0
- package/src/utils/composite-context-provider.ts +23 -2
- package/src/utils/record.test.ts +48 -0
- package/src/utils/record.ts +11 -0
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
type ReadonlyJSONValue,
|
|
15
15
|
} from "assistant-stream/utils";
|
|
16
16
|
import { isJSONValueEqual } from "../../utils/json/is-json-equal";
|
|
17
|
-
import type { ThreadMessage } from "../../types/message";
|
|
17
|
+
import type { ThreadMessage, ToolCallMessagePart } from "../../types/message";
|
|
18
|
+
import { walkToolCallTree } from "../../runtime/utils/tool-call-tree";
|
|
18
19
|
|
|
19
20
|
const TOOL_EXECUTION_ID = Symbol.for("assistant-stream.tool-execution-id");
|
|
20
21
|
|
|
@@ -54,6 +55,7 @@ type ToolCallEntry = {
|
|
|
54
55
|
/** Active phase — chunks are flowing through `controller`. */
|
|
55
56
|
controller: ToolCallStreamController;
|
|
56
57
|
argsComplete: boolean;
|
|
58
|
+
clientOwned: boolean;
|
|
57
59
|
}
|
|
58
60
|
);
|
|
59
61
|
|
|
@@ -116,6 +118,9 @@ const getToolExecutionId = (value: object): symbol | undefined =>
|
|
|
116
118
|
export class ToolInvocationTracker {
|
|
117
119
|
private readonly _getTools: () => Record<string, Tool> | undefined;
|
|
118
120
|
private readonly _callbacks: ToolInvocationTracker.Callbacks;
|
|
121
|
+
private readonly _isClientToolCall:
|
|
122
|
+
| ((toolCall: ToolCallMessagePart) => boolean | undefined)
|
|
123
|
+
| undefined;
|
|
119
124
|
|
|
120
125
|
private readonly _entries = new Map<string, ToolCallEntry>();
|
|
121
126
|
private readonly _humanInput = new Map<
|
|
@@ -127,6 +132,13 @@ export class ToolInvocationTracker {
|
|
|
127
132
|
}
|
|
128
133
|
>();
|
|
129
134
|
private readonly _executing = new Set<symbol>();
|
|
135
|
+
/**
|
|
136
|
+
* Tool calls whose turn ended before they reached the executor. Held here
|
|
137
|
+
* rather than on the entry because an entry is rebuilt whenever a snapshot
|
|
138
|
+
* re-creates the call, and this is the one reason to skip that no later
|
|
139
|
+
* snapshot carries.
|
|
140
|
+
*/
|
|
141
|
+
private readonly _discardedToolCallIds = new Set<string>();
|
|
130
142
|
private readonly _settledResolvers: SettledResolver[] = [];
|
|
131
143
|
|
|
132
144
|
private _statuses = new Map<string, ToolExecutionStatus>();
|
|
@@ -143,10 +155,12 @@ export class ToolInvocationTracker {
|
|
|
143
155
|
/**
|
|
144
156
|
* Set when the assistant-stream pipeline has died (errored out via
|
|
145
157
|
* `.pipeTo(...).catch(...)`). The next `setState` re-initializes the
|
|
146
|
-
* pipeline and demotes
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
158
|
+
* pipeline and demotes each active entry that reached the executor to
|
|
159
|
+
* restored, so it survives the restart without re-firing `streamCall`.
|
|
160
|
+
* A restart is an execution boundary like `reset()`: an entry that had
|
|
161
|
+
* not reached it starts over and fires once there (F.4). Capped at a
|
|
162
|
+
* single auto-restart per session — repeated failures keep the tracker
|
|
163
|
+
* dead with a more visible error.
|
|
150
164
|
*/
|
|
151
165
|
private _pipelineDead = false;
|
|
152
166
|
private _pipelineRestartUsed = false;
|
|
@@ -154,9 +168,11 @@ export class ToolInvocationTracker {
|
|
|
154
168
|
constructor(
|
|
155
169
|
getTools: () => Record<string, Tool> | undefined,
|
|
156
170
|
callbacks: ToolInvocationTracker.Callbacks,
|
|
171
|
+
isClientToolCall?: (toolCall: ToolCallMessagePart) => boolean | undefined,
|
|
157
172
|
) {
|
|
158
173
|
this._getTools = getTools;
|
|
159
174
|
this._callbacks = callbacks;
|
|
175
|
+
this._isClientToolCall = isClientToolCall;
|
|
160
176
|
|
|
161
177
|
this._initPipeline();
|
|
162
178
|
}
|
|
@@ -222,10 +238,10 @@ export class ToolInvocationTracker {
|
|
|
222
238
|
*/
|
|
223
239
|
public setState(snapshot: ToolInvocationTracker.Snapshot): void {
|
|
224
240
|
try {
|
|
225
|
-
// Recover from a dead pipeline before processing anything.
|
|
226
|
-
//
|
|
227
|
-
// re-fire `streamCall` for
|
|
228
|
-
//
|
|
241
|
+
// Recover from a dead pipeline before processing anything. Entries
|
|
242
|
+
// that reached the executor are demoted to "restored" so the rebuilt
|
|
243
|
+
// pipeline does not re-fire `streamCall` for them; the rest start over
|
|
244
|
+
// across the boundary the restart opens (F.4).
|
|
229
245
|
if (this._pipelineDead) {
|
|
230
246
|
if (this._pipelineRestartUsed) {
|
|
231
247
|
// Already retried once and failed again. Stay dead.
|
|
@@ -291,6 +307,7 @@ export class ToolInvocationTracker {
|
|
|
291
307
|
try {
|
|
292
308
|
this._pendingRestore = true;
|
|
293
309
|
this._entries.clear();
|
|
310
|
+
this._discardedToolCallIds.clear();
|
|
294
311
|
this._lastSnapshot = null;
|
|
295
312
|
void this.abort();
|
|
296
313
|
// Statuses are cleared synchronously: discarded executions may never
|
|
@@ -310,8 +327,13 @@ export class ToolInvocationTracker {
|
|
|
310
327
|
/**
|
|
311
328
|
* Abort any in-flight `execute()` invocations. Resolves once all of them
|
|
312
329
|
* have settled (or immediately if none are running).
|
|
330
|
+
*
|
|
331
|
+
* `discardPending` additionally kills the calls that never reached the
|
|
332
|
+
* executor, for a caller ending the turn rather than interrupting it. The
|
|
333
|
+
* signal cannot reach those: they are waiting on the run to settle (A.10),
|
|
334
|
+
* and the settled snapshot arrives after this installs a fresh controller.
|
|
313
335
|
*/
|
|
314
|
-
public abort(): Promise<void> {
|
|
336
|
+
public abort(options?: { discardPending?: boolean }): Promise<void> {
|
|
315
337
|
try {
|
|
316
338
|
this._humanInput.forEach(({ reject }) => {
|
|
317
339
|
try {
|
|
@@ -323,6 +345,15 @@ export class ToolInvocationTracker {
|
|
|
323
345
|
});
|
|
324
346
|
this._humanInput.clear();
|
|
325
347
|
|
|
348
|
+
if (options?.discardPending) {
|
|
349
|
+
for (const [toolCallId, entry] of this._entries) {
|
|
350
|
+
if (!entry.controller) continue;
|
|
351
|
+
if (entry.argsComplete || entry.hasResult) continue;
|
|
352
|
+
this._discardedToolCallIds.add(toolCallId);
|
|
353
|
+
entry.skipExecute = true;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
326
357
|
this._ac.abort();
|
|
327
358
|
this._ac = new AbortController();
|
|
328
359
|
|
|
@@ -473,6 +504,8 @@ export class ToolInvocationTracker {
|
|
|
473
504
|
if (entry.skipExecute) return;
|
|
474
505
|
|
|
475
506
|
this._executing.add(executionId!);
|
|
507
|
+
// execute can park human() before onExecutionStart; preserve this execution's interrupt.
|
|
508
|
+
if (this._humanInput.get(toolCallId)?.executionId === executionId) return;
|
|
476
509
|
this._setStatus(toolCallId, { type: "executing" });
|
|
477
510
|
}
|
|
478
511
|
|
|
@@ -577,31 +610,40 @@ export class ToolInvocationTracker {
|
|
|
577
610
|
|
|
578
611
|
// ──────────────── internal: snapshot processing ────────────────
|
|
579
612
|
|
|
580
|
-
private
|
|
581
|
-
|
|
582
|
-
|
|
613
|
+
private _warnProviderOwnedSkip(toolName: string, toolCallId: string): void {
|
|
614
|
+
if (process.env.NODE_ENV === "production") return;
|
|
615
|
+
if (this._getTools()?.[toolName]?.execute === undefined) return;
|
|
616
|
+
console.warn(
|
|
617
|
+
"[ToolInvocationTracker] the runtime reports this tool call as provider-owned, so the registered execute is skipped; the provider has to hand the call to the client for it to run (see EDGE_CASES.md A.9)",
|
|
618
|
+
{ toolCallId, toolName },
|
|
619
|
+
);
|
|
583
620
|
}
|
|
584
621
|
|
|
622
|
+
/**
|
|
623
|
+
* Closing the args stream hands the call to the client executor, so it may
|
|
624
|
+
* only happen once the provider can no longer speak about that call. The run
|
|
625
|
+
* ending is the only universal signal for that; an adapter that reports the
|
|
626
|
+
* call as client-owned has said it earlier, per call.
|
|
627
|
+
*/
|
|
585
628
|
private _shouldCloseArgsStream({
|
|
586
|
-
toolName,
|
|
587
629
|
argsText,
|
|
588
630
|
hasResult,
|
|
631
|
+
clientOwned,
|
|
589
632
|
}: {
|
|
590
|
-
toolName: string;
|
|
591
633
|
argsText: string;
|
|
592
634
|
hasResult: boolean;
|
|
635
|
+
clientOwned: boolean;
|
|
593
636
|
}): boolean {
|
|
594
637
|
if (hasResult) return true;
|
|
595
|
-
if (!
|
|
596
|
-
|
|
597
|
-
}
|
|
598
|
-
return isArgsTextComplete(argsText);
|
|
638
|
+
if (!isArgsTextComplete(argsText)) return false;
|
|
639
|
+
return clientOwned || !this._isRunning;
|
|
599
640
|
}
|
|
600
641
|
|
|
601
642
|
private _startActiveEntry(
|
|
602
643
|
toolCallId: string,
|
|
603
644
|
toolName: string,
|
|
604
645
|
skipExecute: boolean,
|
|
646
|
+
clientOwned: boolean,
|
|
605
647
|
): ToolCallEntry {
|
|
606
648
|
const toolCallController = this._controller.addToolCallPart({
|
|
607
649
|
toolName,
|
|
@@ -614,6 +656,7 @@ export class ToolInvocationTracker {
|
|
|
614
656
|
hasResult: false,
|
|
615
657
|
skipExecute,
|
|
616
658
|
argsComplete: false,
|
|
659
|
+
clientOwned,
|
|
617
660
|
};
|
|
618
661
|
this._entries.set(toolCallId, entry);
|
|
619
662
|
return entry;
|
|
@@ -629,6 +672,16 @@ export class ToolInvocationTracker {
|
|
|
629
672
|
private _demoteEntriesToRestored(): void {
|
|
630
673
|
for (const [toolCallId, entry] of this._entries) {
|
|
631
674
|
if (!entry.controller) continue;
|
|
675
|
+
if (!entry.argsComplete && !entry.hasResult) {
|
|
676
|
+
// The call never reached the executor. A restored entry is promoted
|
|
677
|
+
// only when its signature changes, and a call waiting on the run to
|
|
678
|
+
// settle already holds its final args, so demoting it would strand it
|
|
679
|
+
// unexecuted. Dropping it lets the next snapshot start it over; a call
|
|
680
|
+
// whose turn was discarded is held by `_discardedToolCallIds`, not by
|
|
681
|
+
// the entry, so starting over does not revive it.
|
|
682
|
+
this._entries.delete(toolCallId);
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
632
685
|
this._entries.set(toolCallId, {
|
|
633
686
|
toolName: entry.toolName,
|
|
634
687
|
argsText: entry.argsText,
|
|
@@ -683,9 +736,9 @@ export class ToolInvocationTracker {
|
|
|
683
736
|
isEquivalentCompleteArgsText(entry.argsText, content.argsText)
|
|
684
737
|
) {
|
|
685
738
|
const shouldClose = this._shouldCloseArgsStream({
|
|
686
|
-
toolName: content.toolName,
|
|
687
739
|
argsText: content.argsText,
|
|
688
740
|
hasResult,
|
|
741
|
+
clientOwned: entry.clientOwned,
|
|
689
742
|
});
|
|
690
743
|
if (shouldClose) entry.controller.argsText.close();
|
|
691
744
|
entry.argsText = content.argsText;
|
|
@@ -717,9 +770,9 @@ export class ToolInvocationTracker {
|
|
|
717
770
|
const delta = content.argsText.slice(entry.argsText.length);
|
|
718
771
|
entry.controller.argsText.append(delta);
|
|
719
772
|
const shouldClose = this._shouldCloseArgsStream({
|
|
720
|
-
toolName: content.toolName,
|
|
721
773
|
argsText: content.argsText,
|
|
722
774
|
hasResult,
|
|
775
|
+
clientOwned: entry.clientOwned,
|
|
723
776
|
});
|
|
724
777
|
if (shouldClose) entry.controller.argsText.close();
|
|
725
778
|
entry.argsText = content.argsText;
|
|
@@ -732,9 +785,9 @@ export class ToolInvocationTracker {
|
|
|
732
785
|
// gates on the streamed content; a divergent snapshot (A.2) can be
|
|
733
786
|
// complete while the controller still holds an incomplete stale prefix.
|
|
734
787
|
const shouldClose = this._shouldCloseArgsStream({
|
|
735
|
-
toolName: content.toolName,
|
|
736
788
|
argsText: entry.argsText,
|
|
737
789
|
hasResult,
|
|
790
|
+
clientOwned: entry.clientOwned,
|
|
738
791
|
});
|
|
739
792
|
if (shouldClose) {
|
|
740
793
|
entry.controller.argsText.close();
|
|
@@ -746,81 +799,81 @@ export class ToolInvocationTracker {
|
|
|
746
799
|
private _processMessages(messages: readonly ThreadMessage[]): void {
|
|
747
800
|
const isRestore = this._pendingRestore;
|
|
748
801
|
|
|
749
|
-
for (const
|
|
750
|
-
|
|
802
|
+
for (const { part: content } of walkToolCallTree(messages)) {
|
|
803
|
+
const existing = this._entries.get(content.toolCallId);
|
|
804
|
+
|
|
805
|
+
if (isRestore) {
|
|
806
|
+
// Don't overwrite an already-active entry (e.g. live tool-call
|
|
807
|
+
// observed before this restore snapshot landed). Restore can
|
|
808
|
+
// only seed entries the runtime has never seen.
|
|
809
|
+
if (!existing?.controller) {
|
|
810
|
+
this._entries.set(content.toolCallId, {
|
|
811
|
+
toolName: content.toolName,
|
|
812
|
+
argsText: content.argsText,
|
|
813
|
+
hasResult: content.result !== undefined,
|
|
814
|
+
});
|
|
815
|
+
}
|
|
751
816
|
continue;
|
|
752
817
|
}
|
|
753
|
-
for (const content of message.content as readonly ThreadMessage["content"][number][]) {
|
|
754
|
-
if (!content || content.type !== "tool-call") continue;
|
|
755
|
-
|
|
756
|
-
const existing = this._entries.get(content.toolCallId);
|
|
757
|
-
|
|
758
|
-
if (isRestore) {
|
|
759
|
-
// Don't overwrite an already-active entry (e.g. live tool-call
|
|
760
|
-
// observed before this restore snapshot landed). Restore can
|
|
761
|
-
// only seed entries the runtime has never seen.
|
|
762
|
-
if (!existing?.controller) {
|
|
763
|
-
this._entries.set(content.toolCallId, {
|
|
764
|
-
toolName: content.toolName,
|
|
765
|
-
argsText: content.argsText,
|
|
766
|
-
hasResult: content.result !== undefined,
|
|
767
|
-
});
|
|
768
|
-
}
|
|
769
|
-
if (content.messages) this._processMessages(content.messages);
|
|
770
|
-
continue;
|
|
771
|
-
}
|
|
772
818
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
819
|
+
// Live snapshot.
|
|
820
|
+
let entry = existing;
|
|
821
|
+
|
|
822
|
+
// A discarded id is remembered only until the call is answered, which
|
|
823
|
+
// bounds the set to the open calls of a discarded turn.
|
|
824
|
+
if (content.result !== undefined)
|
|
825
|
+
this._discardedToolCallIds.delete(content.toolCallId);
|
|
826
|
+
|
|
827
|
+
if (entry && !entry.controller) {
|
|
828
|
+
// Restored entry observed in a live snapshot. Promote if its
|
|
829
|
+
// signature has changed; otherwise treat as still-historical.
|
|
830
|
+
const signatureChanged =
|
|
831
|
+
content.argsText !== entry.argsText ||
|
|
832
|
+
(content.result !== undefined) !== entry.hasResult;
|
|
833
|
+
if (!signatureChanged) continue;
|
|
834
|
+
this._entries.delete(content.toolCallId);
|
|
835
|
+
entry = undefined;
|
|
836
|
+
}
|
|
789
837
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
);
|
|
796
|
-
|
|
838
|
+
if (!entry) {
|
|
839
|
+
const ownership = this._isClientToolCall?.(content);
|
|
840
|
+
const providerOwned =
|
|
841
|
+
content.result === undefined && ownership === false;
|
|
842
|
+
if (providerOwned)
|
|
843
|
+
this._warnProviderOwnedSkip(content.toolName, content.toolCallId);
|
|
844
|
+
entry = this._startActiveEntry(
|
|
845
|
+
content.toolCallId,
|
|
846
|
+
content.toolName,
|
|
847
|
+
content.result !== undefined ||
|
|
848
|
+
providerOwned ||
|
|
849
|
+
this._discardedToolCallIds.has(content.toolCallId),
|
|
850
|
+
ownership === true,
|
|
851
|
+
);
|
|
852
|
+
}
|
|
797
853
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
this._processArgsText(entry, content);
|
|
801
|
-
|
|
802
|
-
if (content.result !== undefined && !entry.hasResult) {
|
|
803
|
-
// `entry` is in active phase from this point — either just
|
|
804
|
-
// created by `_startActiveEntry`, or pre-existing with a live
|
|
805
|
-
// controller. Narrow once instead of asserting at every use.
|
|
806
|
-
const { controller: activeController } = entry;
|
|
807
|
-
if (!activeController) continue;
|
|
808
|
-
entry.hasResult = true;
|
|
809
|
-
entry.argsComplete = true;
|
|
810
|
-
activeController.setResponse(
|
|
811
|
-
new ToolResponse({
|
|
812
|
-
result: content.result as ReadonlyJSONValue,
|
|
813
|
-
artifact: content.artifact as ReadonlyJSONValue | undefined,
|
|
814
|
-
isError: content.isError,
|
|
815
|
-
...(content.modelContent !== undefined
|
|
816
|
-
? { modelContent: content.modelContent }
|
|
817
|
-
: {}),
|
|
818
|
-
}),
|
|
819
|
-
);
|
|
820
|
-
activeController.close();
|
|
821
|
-
}
|
|
854
|
+
if (content.approval !== undefined) entry.skipExecute = true;
|
|
822
855
|
|
|
823
|
-
|
|
856
|
+
this._processArgsText(entry, content);
|
|
857
|
+
|
|
858
|
+
if (content.result !== undefined && !entry.hasResult) {
|
|
859
|
+
// `entry` is in active phase from this point — either just
|
|
860
|
+
// created by `_startActiveEntry`, or pre-existing with a live
|
|
861
|
+
// controller. Narrow once instead of asserting at every use.
|
|
862
|
+
const { controller: activeController } = entry;
|
|
863
|
+
if (!activeController) continue;
|
|
864
|
+
entry.hasResult = true;
|
|
865
|
+
entry.argsComplete = true;
|
|
866
|
+
activeController.setResponse(
|
|
867
|
+
new ToolResponse({
|
|
868
|
+
result: content.result as ReadonlyJSONValue,
|
|
869
|
+
artifact: content.artifact as ReadonlyJSONValue | undefined,
|
|
870
|
+
isError: content.isError,
|
|
871
|
+
...(content.modelContent !== undefined
|
|
872
|
+
? { modelContent: content.modelContent }
|
|
873
|
+
: {}),
|
|
874
|
+
}),
|
|
875
|
+
);
|
|
876
|
+
activeController.close();
|
|
824
877
|
}
|
|
825
878
|
}
|
|
826
879
|
}
|
|
@@ -21,7 +21,10 @@ import type {
|
|
|
21
21
|
CreateAttachment,
|
|
22
22
|
PendingAttachment,
|
|
23
23
|
} from "../../types/attachment";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
isAttachmentComplete,
|
|
26
|
+
isCreateAttachment,
|
|
27
|
+
} from "../../types/attachment";
|
|
25
28
|
import type {
|
|
26
29
|
AddToolResultOptions,
|
|
27
30
|
RespondToToolApprovalOptions,
|
|
@@ -49,6 +52,7 @@ import {
|
|
|
49
52
|
drainAttachmentAdd,
|
|
50
53
|
} from "../../runtime/utils/attachment-add-operations";
|
|
51
54
|
import { toMessagePartStatus } from "../../utils/normalizePartStatus";
|
|
55
|
+
import { generateId } from "../../utils/id";
|
|
52
56
|
import { ModelContext } from "./model-context-client";
|
|
53
57
|
import { ThreadSuggestions } from "./suggestions";
|
|
54
58
|
import { Tools } from "../../react/client/Tools";
|
|
@@ -118,7 +122,9 @@ export type ExternalThreadProps = {
|
|
|
118
122
|
/** Branch adapter for runtimes that track sibling variants of messages. */
|
|
119
123
|
branches?: ExternalThreadBranchAdapter;
|
|
120
124
|
/** Callback for tool approval decisions. Absent: responding to an approval throws a capability error. */
|
|
121
|
-
onRespondToToolApproval?: (
|
|
125
|
+
onRespondToToolApproval?: (
|
|
126
|
+
options: RespondToToolApprovalOptions,
|
|
127
|
+
) => void | Promise<void>;
|
|
122
128
|
};
|
|
123
129
|
|
|
124
130
|
type MessageClientProps = {
|
|
@@ -130,7 +136,7 @@ type MessageClientProps = {
|
|
|
130
136
|
queue?: ExternalThreadQueueAdapter | undefined;
|
|
131
137
|
branches?: ExternalThreadBranchAdapter | undefined;
|
|
132
138
|
onRespondToToolApproval?:
|
|
133
|
-
| ((options: RespondToToolApprovalOptions) => void)
|
|
139
|
+
| ((options: RespondToToolApprovalOptions) => void | Promise<void>)
|
|
134
140
|
| undefined;
|
|
135
141
|
onAddToolResult?: ((options: AddToolResultOptions) => void) | undefined;
|
|
136
142
|
onResumeToolCall?: ((options: ResumeToolCallOptions) => void) | undefined;
|
|
@@ -313,7 +319,7 @@ type PartResourceProps = {
|
|
|
313
319
|
status: ToolCallMessagePartStatus;
|
|
314
320
|
messageId: string;
|
|
315
321
|
onRespondToToolApproval?:
|
|
316
|
-
| ((options: RespondToToolApprovalOptions) => void)
|
|
322
|
+
| ((options: RespondToToolApprovalOptions) => void | Promise<void>)
|
|
317
323
|
| undefined;
|
|
318
324
|
onAddToolResult?: ((options: AddToolResultOptions) => void) | undefined;
|
|
319
325
|
onResumeToolCall?: ((options: ResumeToolCallOptions) => void) | undefined;
|
|
@@ -382,9 +388,12 @@ const usePartResource = ({
|
|
|
382
388
|
)
|
|
383
389
|
throw new Error("Tool call has no pending approval");
|
|
384
390
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
391
|
+
const options = resolveToolApprovalResponse(part.approval, response);
|
|
392
|
+
try {
|
|
393
|
+
return Promise.resolve(onRespondToToolApproval(options));
|
|
394
|
+
} catch (error) {
|
|
395
|
+
return Promise.reject(error);
|
|
396
|
+
}
|
|
388
397
|
},
|
|
389
398
|
};
|
|
390
399
|
};
|
|
@@ -457,6 +466,35 @@ const useLiveState = <T>(initial: T) => {
|
|
|
457
466
|
return [state, set, ref] as const;
|
|
458
467
|
};
|
|
459
468
|
|
|
469
|
+
// A try/catch inside the resource makes the React Compiler bail out of the
|
|
470
|
+
// whole hook, so the adapter call and its failure status live at module scope.
|
|
471
|
+
const removeAttachmentThroughAdapter = async (
|
|
472
|
+
attachment: Attachment,
|
|
473
|
+
attachmentAdapter: AttachmentAdapter | undefined,
|
|
474
|
+
setAttachments: (
|
|
475
|
+
next:
|
|
476
|
+
| readonly Attachment[]
|
|
477
|
+
| ((prev: readonly Attachment[]) => readonly Attachment[]),
|
|
478
|
+
) => void,
|
|
479
|
+
) => {
|
|
480
|
+
try {
|
|
481
|
+
await attachmentAdapter?.remove(attachment);
|
|
482
|
+
} catch (error) {
|
|
483
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
484
|
+
setAttachments((prev) =>
|
|
485
|
+
prev.map((candidate) =>
|
|
486
|
+
candidate.id === attachment.id && !isAttachmentComplete(candidate)
|
|
487
|
+
? {
|
|
488
|
+
...candidate,
|
|
489
|
+
status: { type: "incomplete", reason: "error", message },
|
|
490
|
+
}
|
|
491
|
+
: candidate,
|
|
492
|
+
),
|
|
493
|
+
);
|
|
494
|
+
throw error;
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
|
|
460
498
|
// Composer Client - minimal implementation
|
|
461
499
|
const useComposerClientResource = ({
|
|
462
500
|
type,
|
|
@@ -510,7 +548,13 @@ const useComposerClientResource = ({
|
|
|
510
548
|
attachment,
|
|
511
549
|
onRemove: async () => {
|
|
512
550
|
attachmentAddOperations.cancel(attachment.id);
|
|
513
|
-
|
|
551
|
+
if (!isAttachmentComplete(attachment)) {
|
|
552
|
+
await removeAttachmentThroughAdapter(
|
|
553
|
+
attachment,
|
|
554
|
+
attachmentAdapter,
|
|
555
|
+
setAttachments,
|
|
556
|
+
);
|
|
557
|
+
}
|
|
514
558
|
setAttachments((prev) =>
|
|
515
559
|
prev.filter((a) => a.id !== attachment.id),
|
|
516
560
|
);
|
|
@@ -632,7 +676,7 @@ const useComposerClientResource = ({
|
|
|
632
676
|
}
|
|
633
677
|
} else if (!isCreateAttachment(fileOrAttachment)) {
|
|
634
678
|
const newAttachment: Attachment = {
|
|
635
|
-
id:
|
|
679
|
+
id: generateId(),
|
|
636
680
|
type: "file",
|
|
637
681
|
name: fileOrAttachment.name,
|
|
638
682
|
contentType: fileOrAttachment.type,
|
|
@@ -643,7 +687,7 @@ const useComposerClientResource = ({
|
|
|
643
687
|
setAttachments((prev) => [...prev, newAttachment]);
|
|
644
688
|
} else {
|
|
645
689
|
const newAttachment: Attachment = {
|
|
646
|
-
id: fileOrAttachment.id ??
|
|
690
|
+
id: fileOrAttachment.id ?? generateId(),
|
|
647
691
|
type: fileOrAttachment.type ?? "document",
|
|
648
692
|
name: fileOrAttachment.name,
|
|
649
693
|
contentType: fileOrAttachment.contentType,
|
|
@@ -899,7 +943,11 @@ const useExternalThread = ({
|
|
|
899
943
|
: undefined;
|
|
900
944
|
};
|
|
901
945
|
|
|
946
|
+
// `messages` changes identity on every streamed token, and this body fans out
|
|
947
|
+
// to one client per message, so pruning during render would re-run the whole
|
|
948
|
+
// fan-out per token. The effect bails out on an unchanged map instead.
|
|
902
949
|
useEffect(() => {
|
|
950
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
903
951
|
setSubmittedFeedback((prev) => {
|
|
904
952
|
const live = Object.entries(prev).filter(([id, entry]) => {
|
|
905
953
|
const msg = messages.find((m) => m.id === id);
|
|
@@ -1107,7 +1155,10 @@ const useExternalThread = ({
|
|
|
1107
1155
|
}
|
|
1108
1156
|
: {
|
|
1109
1157
|
createdAt: message.createdAt ?? new Date(),
|
|
1110
|
-
parentId:
|
|
1158
|
+
parentId:
|
|
1159
|
+
message.parentId === undefined
|
|
1160
|
+
? (messages.at(-1)?.id ?? null)
|
|
1161
|
+
: message.parentId,
|
|
1111
1162
|
sourceId: message.sourceId ?? null,
|
|
1112
1163
|
role: message.role ?? "user",
|
|
1113
1164
|
content: message.content,
|
|
@@ -3,6 +3,7 @@ import { resource } from "@assistant-ui/tap";
|
|
|
3
3
|
import type { ClientOutput } from "@assistant-ui/store";
|
|
4
4
|
import { CompositeContextProvider } from "../../utils/composite-context-provider";
|
|
5
5
|
import type { ModelContextState } from "../scopes/model-context";
|
|
6
|
+
import { shallowEqual } from "@assistant-ui/store/internal";
|
|
6
7
|
|
|
7
8
|
const EMPTY_TOOL_NAMES: readonly string[] = [];
|
|
8
9
|
|
|
@@ -12,7 +13,7 @@ const INITIAL_STATE: ModelContextState = {
|
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
const toolNamesEqual = (a: readonly string[], b: readonly string[]): boolean =>
|
|
15
|
-
a === b || (a
|
|
16
|
+
a === b || shallowEqual(a, b);
|
|
16
17
|
|
|
17
18
|
const deriveState = (
|
|
18
19
|
composite: CompositeContextProvider,
|
|
@@ -36,6 +37,9 @@ const useModelContext = (): ClientOutput<"modelContext"> => {
|
|
|
36
37
|
);
|
|
37
38
|
|
|
38
39
|
useEffect(() => {
|
|
40
|
+
// The composite is an external store; this catches the snapshot up for
|
|
41
|
+
// providers registered between render and subscribe.
|
|
42
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
39
43
|
setState((prev) => deriveState(composite, prev));
|
|
40
44
|
return composite.subscribe(() => {
|
|
41
45
|
setState((prev) => deriveState(composite, prev));
|