@assistant-ui/core 0.3.17 → 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 +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +3 -2
- package/dist/internal.js +3 -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 +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 +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/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/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 +24 -27
- 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 +151 -141
- 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/interactables-legacy/Interactables.js +242 -121
- 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/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/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/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 +103 -103
- 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 +4 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js +401 -34
- package/dist/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.js.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.js +2 -1
- package/dist/react/runtimes/cloud/createCloudThreadListAdapter.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 +63 -23
- package/dist/react/runtimes/useRemoteThreadListRuntime.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 +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 +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.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +6 -5
- 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/utils/external-message-conversion.js +1 -1
- 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/thread-message-like.js +1 -1
- 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/internal.d.ts +2 -2
- package/dist/runtimes/internal.js +2 -2
- 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/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +19 -3
- 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/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 +193 -121
- package/dist/store/runtime-clients/thread-runtime-client.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/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/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/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 +10 -10
- package/src/adapters/attachment.test.ts +50 -1
- package/src/adapters/attachment.ts +7 -4
- package/src/index.ts +1 -0
- package/src/internal.ts +4 -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 +71 -0
- package/src/model-context/frame/provider.ts +37 -7
- 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/types.test.ts +25 -0
- package/src/model-context/types.ts +9 -4
- package/src/react/RuntimeAdapter.test.ts +34 -0
- 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 +148 -6
- package/src/react/client/RemoteThreadList.concurrent.test.tsx +42 -1
- package/src/react/client/RemoteThreadList.test.ts +345 -3
- package/src/react/client/RemoteThreadList.ts +166 -110
- package/src/react/client/Tools.ts +22 -11
- 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/useAssistantTool.ts +2 -2
- package/src/react/model-context/useToolArgsStatus.test.tsx +30 -0
- package/src/react/model-context/useToolArgsStatus.ts +2 -1
- 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 +136 -111
- package/src/react/runtimes/RemoteThreadResource.test.ts +9 -0
- package/src/react/runtimes/RemoteThreadResource.ts +19 -12
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.test.tsx +483 -6
- package/src/react/runtimes/cloud/AssistantCloudThreadHistoryAdapter.ts +504 -68
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.test.ts +15 -0
- package/src/react/runtimes/cloud/createCloudThreadListAdapter.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.load-error.test.tsx +108 -0
- package/src/react/runtimes/useRemoteThreadListRuntime.ts +33 -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 +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 +55 -1
- package/src/runtime/base/base-thread-runtime-core.ts +6 -4
- package/src/runtime/interfaces/composer-runtime-core.ts +10 -5
- package/src/runtime/interfaces/thread-list-runtime-core.ts +5 -1
- package/src/runtime/utils/external-message-conversion.test.ts +68 -0
- package/src/runtime/utils/external-message-conversion.ts +1 -1
- package/src/runtime/utils/message-repository.ts +29 -17
- package/src/runtime/utils/thread-message-like.ts +1 -1
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +18 -13
- package/src/runtimes/internal.ts +1 -0
- 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/store/clients/external-thread.ts +48 -3
- 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/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 +58 -10
- package/src/store/scopes/composer.ts +16 -4
- package/src/store/scopes/message.ts +14 -0
- 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/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 +47 -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-thread-list-runtime-core.test.ts +83 -0
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +27 -18
- package/src/tests/external-thread-attachments.test.tsx +139 -0
- package/src/tests/external-thread-parity.test.tsx +23 -0
- 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 +78 -0
- package/src/tests/tools-scope-migration.test.tsx +28 -0
- package/src/types/attachment.ts +4 -0
- 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
|
@@ -9,17 +9,26 @@ import type {
|
|
|
9
9
|
import type { ExportedMessageRepositoryItem } from "../../../runtime/utils/message-repository";
|
|
10
10
|
import {
|
|
11
11
|
type AssistantCloud,
|
|
12
|
+
type AssistantCloudEvent,
|
|
12
13
|
type AssistantCloudRunReportToolCall,
|
|
13
14
|
CloudMessagePersistence,
|
|
14
15
|
createFormattedPersistence,
|
|
16
|
+
createRunReport,
|
|
15
17
|
createRunTelemetryToolCall,
|
|
18
|
+
deriveRunOutcome,
|
|
19
|
+
describeRunError,
|
|
20
|
+
extractRunTelemetryModelId,
|
|
16
21
|
normalizeRunTelemetryUsage,
|
|
22
|
+
type RunReportOutcome,
|
|
23
|
+
type RunReportStepInit,
|
|
24
|
+
type RunTelemetryUsage,
|
|
17
25
|
type RunTelemetryUsageInit,
|
|
18
26
|
truncateRunTelemetryText,
|
|
19
27
|
} from "assistant-cloud";
|
|
20
28
|
import { auiV0Decode, auiV0Encode } from "./auiV0";
|
|
21
29
|
import { type AssistantClient, getClientId, useAui } from "@assistant-ui/store";
|
|
22
30
|
import type { ThreadListItemMethods } from "../../../store/scopes/thread-list-item";
|
|
31
|
+
import type { FeedbackAdapter } from "../../../adapters/feedback";
|
|
23
32
|
|
|
24
33
|
type CloudThreadListItem = Pick<
|
|
25
34
|
ThreadListItemMethods,
|
|
@@ -64,6 +73,72 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
64
73
|
return this.getPersistence();
|
|
65
74
|
}
|
|
66
75
|
|
|
76
|
+
/**
|
|
77
|
+
* A send is the moment the runtime creates the remote thread, so that one
|
|
78
|
+
* event waits for the id; every other event reads the id that already
|
|
79
|
+
* exists, because initializing a thread nobody has written to would create
|
|
80
|
+
* an empty remote thread just to attribute an event.
|
|
81
|
+
*/
|
|
82
|
+
public async resolveEngagementEventIds(
|
|
83
|
+
threadId: string,
|
|
84
|
+
messageId?: string,
|
|
85
|
+
options?: { awaitThread?: boolean },
|
|
86
|
+
): Promise<Pick<AssistantCloudEvent, "thread_id" | "message_id">> {
|
|
87
|
+
const threadListItem = this.getThreadListItem(threadId);
|
|
88
|
+
if (!threadListItem) return {};
|
|
89
|
+
|
|
90
|
+
let remoteThreadId = threadListItem.getState().remoteId;
|
|
91
|
+
if (!remoteThreadId && options?.awaitThread) {
|
|
92
|
+
remoteThreadId = await threadListItem
|
|
93
|
+
.initialize()
|
|
94
|
+
.then((result) => result.remoteId)
|
|
95
|
+
.catch(() => undefined);
|
|
96
|
+
}
|
|
97
|
+
const remoteMessageId = messageId
|
|
98
|
+
? this.getPersistence(threadListItem).getResolvedRemoteId(messageId)
|
|
99
|
+
: undefined;
|
|
100
|
+
return {
|
|
101
|
+
...(remoteThreadId ? { thread_id: remoteThreadId } : undefined),
|
|
102
|
+
...(remoteMessageId ? { message_id: remoteMessageId } : undefined),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public readonly feedback: FeedbackAdapter = {
|
|
107
|
+
submit: ({ message, type }) => {
|
|
108
|
+
void (async () => {
|
|
109
|
+
const threadListItem = this.tryGetKeyedThreadListItem();
|
|
110
|
+
const remoteThreadId = threadListItem?.getState().remoteId;
|
|
111
|
+
if (!threadListItem || !remoteThreadId) {
|
|
112
|
+
console.warn(
|
|
113
|
+
`[assistant-ui] Skipping feedback for message ${message.id}: the thread has no remote id.`,
|
|
114
|
+
);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const cloudMessageId = await this.getPersistence(
|
|
119
|
+
threadListItem,
|
|
120
|
+
).getRemoteId(message.id);
|
|
121
|
+
if (!cloudMessageId) {
|
|
122
|
+
console.warn(
|
|
123
|
+
`[assistant-ui] Skipping feedback for message ${message.id}: no cloud message id is mapped.`,
|
|
124
|
+
);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
await this.cloudRef.current.threads.messages.feedback(
|
|
129
|
+
remoteThreadId,
|
|
130
|
+
cloudMessageId,
|
|
131
|
+
{ type },
|
|
132
|
+
);
|
|
133
|
+
})().catch((error: unknown) => {
|
|
134
|
+
console.error(
|
|
135
|
+
"[assistant-ui] Cloud feedback submission failed:",
|
|
136
|
+
error,
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
67
142
|
private tryGetKeyedThreadListItem(): CloudThreadListItem | undefined {
|
|
68
143
|
const live = this.aui.threadListItem;
|
|
69
144
|
if (!live.source) return undefined;
|
|
@@ -77,6 +152,21 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
77
152
|
return listed ? this.aui.threads.item({ id }) : live;
|
|
78
153
|
}
|
|
79
154
|
|
|
155
|
+
private getThreadListItem(threadId: string): CloudThreadListItem | undefined {
|
|
156
|
+
const current = this.aui.threadListItem;
|
|
157
|
+
const currentState = current.getState();
|
|
158
|
+
if (currentState.id === threadId || currentState.remoteId === threadId) {
|
|
159
|
+
return current;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const listed = this.aui.threads
|
|
163
|
+
.getState()
|
|
164
|
+
.threadItems.find(
|
|
165
|
+
(item) => item.id === threadId || item.remoteId === threadId,
|
|
166
|
+
);
|
|
167
|
+
return listed ? this.aui.threads.item({ id: listed.id }) : undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
80
170
|
withFormat<TMessage, TStorageFormat extends Record<string, unknown>>(
|
|
81
171
|
formatAdapter: MessageFormatAdapter<TMessage, TStorageFormat>,
|
|
82
172
|
): GenericThreadHistoryAdapter<TMessage> {
|
|
@@ -135,6 +225,7 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
135
225
|
encodedRunMessages,
|
|
136
226
|
options,
|
|
137
227
|
resolvePinned(),
|
|
228
|
+
extractLastRunMessageInfo(items, formatAdapter),
|
|
138
229
|
);
|
|
139
230
|
},
|
|
140
231
|
async load(): Promise<MessageFormatRepository<TMessage>> {
|
|
@@ -162,7 +253,12 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
162
253
|
);
|
|
163
254
|
|
|
164
255
|
if (this.cloudRef.current.telemetry.enabled) {
|
|
165
|
-
this._maybeReportRun(
|
|
256
|
+
this._maybeReportRun(
|
|
257
|
+
remoteId,
|
|
258
|
+
"aui/v0",
|
|
259
|
+
encoded,
|
|
260
|
+
extractRunMessageInfo(message, "aui/v0"),
|
|
261
|
+
);
|
|
166
262
|
}
|
|
167
263
|
}
|
|
168
264
|
|
|
@@ -177,7 +273,12 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
177
273
|
await this._persistence.update(remoteId, message.id, "aui/v0", encoded);
|
|
178
274
|
|
|
179
275
|
if (this.cloudRef.current.telemetry.enabled) {
|
|
180
|
-
this._maybeReportRun(
|
|
276
|
+
this._maybeReportRun(
|
|
277
|
+
remoteId,
|
|
278
|
+
"aui/v0",
|
|
279
|
+
encoded,
|
|
280
|
+
extractRunMessageInfo(message, "aui/v0"),
|
|
281
|
+
);
|
|
181
282
|
}
|
|
182
283
|
}
|
|
183
284
|
|
|
@@ -209,11 +310,12 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
209
310
|
stepTimestamps?: StepTimestamp[];
|
|
210
311
|
},
|
|
211
312
|
threadListItem?: CloudThreadListItem,
|
|
313
|
+
messageInfo?: RunMessageInfo,
|
|
212
314
|
) {
|
|
213
315
|
if (!this.cloudRef.current.telemetry.enabled) return;
|
|
214
316
|
|
|
215
|
-
const
|
|
216
|
-
|
|
317
|
+
const item = threadListItem ?? this.aui.threadListItem;
|
|
318
|
+
const remoteId = item.getState().remoteId;
|
|
217
319
|
if (!remoteId) return;
|
|
218
320
|
|
|
219
321
|
const extracted = extractRunTelemetry(format, runMessages);
|
|
@@ -224,14 +326,21 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
224
326
|
extracted,
|
|
225
327
|
options?.durationMs,
|
|
226
328
|
options?.stepTimestamps,
|
|
329
|
+
messageInfo,
|
|
330
|
+
this.getPersistence(item),
|
|
227
331
|
);
|
|
228
332
|
}
|
|
229
333
|
|
|
230
|
-
private _maybeReportRun<T>(
|
|
334
|
+
private _maybeReportRun<T>(
|
|
335
|
+
remoteId: string,
|
|
336
|
+
format: string,
|
|
337
|
+
content: T,
|
|
338
|
+
messageInfo?: RunMessageInfo,
|
|
339
|
+
) {
|
|
231
340
|
const extracted = extractTelemetry(format, content);
|
|
232
341
|
if (!extracted) return;
|
|
233
342
|
|
|
234
|
-
this._sendReport(remoteId, extracted);
|
|
343
|
+
this._sendReport(remoteId, extracted, undefined, undefined, messageInfo);
|
|
235
344
|
}
|
|
236
345
|
|
|
237
346
|
private _sendReport(
|
|
@@ -239,37 +348,38 @@ class AssistantCloudThreadHistoryAdapter implements ThreadHistoryAdapter {
|
|
|
239
348
|
data: TelemetryData,
|
|
240
349
|
durationMs?: number,
|
|
241
350
|
stepTimestamps?: StepTimestamp[],
|
|
351
|
+
messageInfo?: RunMessageInfo,
|
|
352
|
+
persistence = this._persistence,
|
|
242
353
|
) {
|
|
243
354
|
const mergedSteps = mergeStepTimestamps(data.steps, stepTimestamps);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
:
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
};
|
|
355
|
+
const messageId = messageInfo?.localMessageId
|
|
356
|
+
? persistence.getResolvedRemoteId(messageInfo.localMessageId)
|
|
357
|
+
: undefined;
|
|
358
|
+
const initial = createRunReport({
|
|
359
|
+
threadId: remoteId,
|
|
360
|
+
status: messageInfo?.status ?? data.status,
|
|
361
|
+
outcome: messageInfo?.outcomeType,
|
|
362
|
+
error: messageInfo?.error,
|
|
363
|
+
errorCode: messageInfo?.errorCode,
|
|
364
|
+
messageId,
|
|
365
|
+
traceId: messageInfo?.traceId,
|
|
366
|
+
modelId: data.modelId,
|
|
367
|
+
provider: messageInfo?.provider,
|
|
368
|
+
usage: {
|
|
369
|
+
inputTokens: data.inputTokens,
|
|
370
|
+
outputTokens: data.outputTokens,
|
|
371
|
+
reasoningTokens: data.reasoningTokens,
|
|
372
|
+
cachedInputTokens: data.cachedInputTokens,
|
|
373
|
+
},
|
|
374
|
+
steps: toRunReportSteps(mergedSteps),
|
|
375
|
+
totalSteps: data.totalSteps,
|
|
376
|
+
toolCalls: data.toolCalls,
|
|
377
|
+
durationMs,
|
|
378
|
+
firstTokenMs: messageInfo?.firstTokenMs,
|
|
379
|
+
outputText: data.outputText,
|
|
380
|
+
metadata: data.metadata,
|
|
381
|
+
telemetry: this.cloudRef.current.telemetry,
|
|
382
|
+
});
|
|
273
383
|
|
|
274
384
|
const { beforeReport } = this.cloudRef.current.telemetry;
|
|
275
385
|
const report = beforeReport ? beforeReport(initial) : initial;
|
|
@@ -291,6 +401,23 @@ type TelemetryStepData = {
|
|
|
291
401
|
|
|
292
402
|
type StepTimestamp = { start_ms: number; end_ms: number };
|
|
293
403
|
|
|
404
|
+
function toRunReportSteps(
|
|
405
|
+
steps: TelemetryStepData[] | undefined,
|
|
406
|
+
): RunReportStepInit[] | undefined {
|
|
407
|
+
if (!steps) return undefined;
|
|
408
|
+
return steps.map((step) => ({
|
|
409
|
+
usage: {
|
|
410
|
+
inputTokens: step.input_tokens,
|
|
411
|
+
outputTokens: step.output_tokens,
|
|
412
|
+
reasoningTokens: step.reasoning_tokens,
|
|
413
|
+
cachedInputTokens: step.cached_input_tokens,
|
|
414
|
+
},
|
|
415
|
+
toolCalls: step.tool_calls,
|
|
416
|
+
startMs: step.start_ms,
|
|
417
|
+
endMs: step.end_ms,
|
|
418
|
+
}));
|
|
419
|
+
}
|
|
420
|
+
|
|
294
421
|
function mergeStepTimestamps(
|
|
295
422
|
steps: TelemetryStepData[] | undefined,
|
|
296
423
|
timestamps: StepTimestamp[] | undefined,
|
|
@@ -319,6 +446,101 @@ type TelemetryData = {
|
|
|
319
446
|
modelId?: string;
|
|
320
447
|
};
|
|
321
448
|
|
|
449
|
+
type RunMessageInfo = {
|
|
450
|
+
localMessageId?: string;
|
|
451
|
+
status?: "error";
|
|
452
|
+
outcomeType?: RunReportOutcome;
|
|
453
|
+
error?: string;
|
|
454
|
+
errorCode?: string;
|
|
455
|
+
firstTokenMs?: number;
|
|
456
|
+
traceId?: string;
|
|
457
|
+
provider?: string;
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
function extractLastRunMessageInfo<
|
|
461
|
+
TMessage,
|
|
462
|
+
TStorageFormat extends Record<string, unknown>,
|
|
463
|
+
>(
|
|
464
|
+
items: MessageFormatItem<TMessage>[],
|
|
465
|
+
formatAdapter: MessageFormatAdapter<TMessage, TStorageFormat>,
|
|
466
|
+
): RunMessageInfo | undefined {
|
|
467
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
468
|
+
const item = items[i]!;
|
|
469
|
+
const info = extractRunMessageInfo(
|
|
470
|
+
item.message,
|
|
471
|
+
formatAdapter.format,
|
|
472
|
+
formatAdapter.getId(item.message),
|
|
473
|
+
);
|
|
474
|
+
if (info) return info;
|
|
475
|
+
}
|
|
476
|
+
return undefined;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function extractRunMessageInfo(
|
|
480
|
+
message: unknown,
|
|
481
|
+
format: string,
|
|
482
|
+
localMessageId?: string,
|
|
483
|
+
): RunMessageInfo | undefined {
|
|
484
|
+
if (!isRecord(message) || message.role !== "assistant") return undefined;
|
|
485
|
+
|
|
486
|
+
const status = isRecord(message.status) ? message.status : undefined;
|
|
487
|
+
const metadata = isRecord(message.metadata) ? message.metadata : undefined;
|
|
488
|
+
const custom = isRecord(metadata?.custom) ? metadata.custom : undefined;
|
|
489
|
+
const timing = isRecord(metadata?.timing) ? metadata.timing : undefined;
|
|
490
|
+
const streamStartTime = timing?.streamStartTime;
|
|
491
|
+
const firstTokenTime = timing?.firstTokenTime;
|
|
492
|
+
const firstTokenMs =
|
|
493
|
+
typeof streamStartTime === "number" &&
|
|
494
|
+
Number.isFinite(streamStartTime) &&
|
|
495
|
+
typeof firstTokenTime === "number" &&
|
|
496
|
+
Number.isFinite(firstTokenTime)
|
|
497
|
+
? Math.round(firstTokenTime - streamStartTime)
|
|
498
|
+
: undefined;
|
|
499
|
+
const finishReason =
|
|
500
|
+
status?.type === "incomplete"
|
|
501
|
+
? status.reason
|
|
502
|
+
: typeof metadata?.finishReason === "string"
|
|
503
|
+
? metadata.finishReason
|
|
504
|
+
: undefined;
|
|
505
|
+
const failed = status?.type === "incomplete" && status.reason === "error";
|
|
506
|
+
const outcome = deriveRunOutcome({
|
|
507
|
+
finishReason: typeof finishReason === "string" ? finishReason : undefined,
|
|
508
|
+
isError: failed,
|
|
509
|
+
});
|
|
510
|
+
const outcomeType = outcome.outcome;
|
|
511
|
+
const failure = failed ? describeRunError(status.error) : {};
|
|
512
|
+
const messageId =
|
|
513
|
+
localMessageId ?? (typeof message.id === "string" ? message.id : undefined);
|
|
514
|
+
const traceId =
|
|
515
|
+
format === "aui/v0"
|
|
516
|
+
? custom?.traceId
|
|
517
|
+
: format === "ai-sdk/v6"
|
|
518
|
+
? metadata?.traceId
|
|
519
|
+
: undefined;
|
|
520
|
+
const provider =
|
|
521
|
+
typeof custom?.provider === "string"
|
|
522
|
+
? custom.provider
|
|
523
|
+
: typeof metadata?.provider === "string"
|
|
524
|
+
? metadata.provider
|
|
525
|
+
: undefined;
|
|
526
|
+
|
|
527
|
+
return {
|
|
528
|
+
...(messageId ? { localMessageId: messageId } : undefined),
|
|
529
|
+
...(outcome.status === "error" ? { status: "error" as const } : undefined),
|
|
530
|
+
...(outcomeType ? { outcomeType } : undefined),
|
|
531
|
+
...failure,
|
|
532
|
+
...(firstTokenMs != null && firstTokenMs >= 0
|
|
533
|
+
? { firstTokenMs }
|
|
534
|
+
: undefined),
|
|
535
|
+
...(typeof traceId === "string" ? { traceId } : undefined),
|
|
536
|
+
...(provider !== undefined ? { provider } : undefined),
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
541
|
+
return value !== null && typeof value === "object";
|
|
542
|
+
}
|
|
543
|
+
|
|
322
544
|
function extractTelemetry<T>(format: string, content: T): TelemetryData | null {
|
|
323
545
|
switch (format) {
|
|
324
546
|
case "aui/v0":
|
|
@@ -352,7 +574,7 @@ const AUI_STATUS_MAP: Record<string, TelemetryData["status"]> = {
|
|
|
352
574
|
export function extractAuiV0<T>(content: T): TelemetryData | null {
|
|
353
575
|
const msg = content as {
|
|
354
576
|
role?: string;
|
|
355
|
-
status?: { type: string };
|
|
577
|
+
status?: { type: string; reason?: string };
|
|
356
578
|
content?: readonly {
|
|
357
579
|
type: string;
|
|
358
580
|
text?: string;
|
|
@@ -435,14 +657,14 @@ export function extractAuiV0<T>(content: T): TelemetryData | null {
|
|
|
435
657
|
|
|
436
658
|
const statusType = msg.status?.type;
|
|
437
659
|
const status: TelemetryData["status"] =
|
|
438
|
-
|
|
660
|
+
statusType === "incomplete" && msg.status?.reason === "error"
|
|
661
|
+
? "error"
|
|
662
|
+
: (statusType && AUI_STATUS_MAP[statusType]) || "completed";
|
|
439
663
|
|
|
440
664
|
const metadata = msg.metadata?.custom as Record<string, unknown> | undefined;
|
|
441
|
-
const modelId =
|
|
442
|
-
msg.metadata
|
|
443
|
-
|
|
444
|
-
? msg.metadata.custom.modelId
|
|
445
|
-
: undefined);
|
|
665
|
+
const modelId = extractRunTelemetryModelId(
|
|
666
|
+
msg.metadata as Record<string, unknown> | undefined,
|
|
667
|
+
);
|
|
446
668
|
|
|
447
669
|
const telemetrySteps: TelemetryStepData[] | undefined =
|
|
448
670
|
steps && steps.length > 1
|
|
@@ -556,34 +778,19 @@ function collectAiSdkV6Parts(parts: readonly AiSdkV6Part[]): {
|
|
|
556
778
|
return { textParts, toolCalls, stepsData };
|
|
557
779
|
}
|
|
558
780
|
|
|
559
|
-
function extractModelId(
|
|
560
|
-
metadata?: Record<string, unknown>,
|
|
561
|
-
): string | undefined {
|
|
562
|
-
if (!metadata) return undefined;
|
|
563
|
-
if (typeof metadata.modelId === "string") return metadata.modelId;
|
|
564
|
-
const custom = metadata.custom as Record<string, unknown> | undefined;
|
|
565
|
-
if (typeof custom?.modelId === "string") return custom.modelId;
|
|
566
|
-
return undefined;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
781
|
function buildAiSdkV6Result(
|
|
570
782
|
textParts: string[],
|
|
571
783
|
toolCalls: AssistantCloudRunReportToolCall[],
|
|
572
784
|
totalSteps: number,
|
|
573
785
|
metadata?: Record<string, unknown>,
|
|
574
786
|
stepsData?: { tool_calls: AssistantCloudRunReportToolCall[] }[],
|
|
575
|
-
usage?:
|
|
576
|
-
inputTokens?: number;
|
|
577
|
-
outputTokens?: number;
|
|
578
|
-
reasoningTokens?: number;
|
|
579
|
-
cachedInputTokens?: number;
|
|
580
|
-
},
|
|
787
|
+
usage?: RunTelemetryUsage,
|
|
581
788
|
): TelemetryData {
|
|
582
789
|
const hasText = textParts.length > 0;
|
|
583
790
|
const outputText = hasText
|
|
584
791
|
? truncateRunTelemetryText(textParts.join(""))
|
|
585
792
|
: undefined;
|
|
586
|
-
const modelId =
|
|
793
|
+
const modelId = extractRunTelemetryModelId(metadata);
|
|
587
794
|
|
|
588
795
|
const steps: TelemetryStepData[] | undefined =
|
|
589
796
|
stepsData && stepsData.length > 1
|
|
@@ -617,14 +824,9 @@ function buildAiSdkV6Result(
|
|
|
617
824
|
};
|
|
618
825
|
}
|
|
619
826
|
|
|
620
|
-
function extractAiSdkV6Usage(
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
outputTokens?: number;
|
|
624
|
-
reasoningTokens?: number;
|
|
625
|
-
cachedInputTokens?: number;
|
|
626
|
-
}
|
|
627
|
-
| undefined {
|
|
827
|
+
function extractAiSdkV6Usage(
|
|
828
|
+
metadata?: Record<string, unknown>,
|
|
829
|
+
): RunTelemetryUsage | undefined {
|
|
628
830
|
// Try top-level metadata.usage
|
|
629
831
|
const usage = metadata?.usage as RunTelemetryUsageInit | undefined;
|
|
630
832
|
if (usage) {
|
|
@@ -766,7 +968,7 @@ function aggregateAiSdkV6RunSteps<T>(stepMessages: T[]): TelemetryData | null {
|
|
|
766
968
|
|
|
767
969
|
export function useAssistantCloudThreadHistoryAdapter(
|
|
768
970
|
cloudRef: RefObject<AssistantCloud>,
|
|
769
|
-
): ThreadHistoryAdapter {
|
|
971
|
+
): ThreadHistoryAdapter & { readonly feedback: FeedbackAdapter } {
|
|
770
972
|
const aui = useAui();
|
|
771
973
|
// Not useEffectEvent: history adapter methods run during render (SSR load).
|
|
772
974
|
const auiRef = useRef(aui);
|
|
@@ -777,5 +979,239 @@ export function useAssistantCloudThreadHistoryAdapter(
|
|
|
777
979
|
() =>
|
|
778
980
|
new AssistantCloudThreadHistoryAdapter(cloudRef, () => auiRef.current),
|
|
779
981
|
);
|
|
982
|
+
useAssistantCloudEngagementEvents(cloudRef, adapter, aui);
|
|
780
983
|
return adapter;
|
|
781
984
|
}
|
|
985
|
+
|
|
986
|
+
type RootEngagementTracker = {
|
|
987
|
+
count: number;
|
|
988
|
+
adapter: AssistantCloudThreadHistoryAdapter;
|
|
989
|
+
cloudRef: RefObject<AssistantCloud>;
|
|
990
|
+
dispose: () => void;
|
|
991
|
+
};
|
|
992
|
+
|
|
993
|
+
const rootEngagementTrackers = new WeakMap<
|
|
994
|
+
AssistantClient,
|
|
995
|
+
RootEngagementTracker
|
|
996
|
+
>();
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* Thread switches are a thread list event, so one subscription per assistant
|
|
1000
|
+
* client reports them; every thread runtime mounted under it shares the
|
|
1001
|
+
* subscription and the last one to unmount removes it.
|
|
1002
|
+
*/
|
|
1003
|
+
const useRootEngagementEvents = (
|
|
1004
|
+
cloudRef: RefObject<AssistantCloud>,
|
|
1005
|
+
adapter: AssistantCloudThreadHistoryAdapter,
|
|
1006
|
+
aui: AssistantClient,
|
|
1007
|
+
) => {
|
|
1008
|
+
useEffect(() => {
|
|
1009
|
+
let tracker = rootEngagementTrackers.get(aui);
|
|
1010
|
+
if (!tracker) {
|
|
1011
|
+
const created: RootEngagementTracker = {
|
|
1012
|
+
count: 0,
|
|
1013
|
+
adapter,
|
|
1014
|
+
cloudRef,
|
|
1015
|
+
dispose: () => {},
|
|
1016
|
+
};
|
|
1017
|
+
created.dispose = aui.on(
|
|
1018
|
+
{ scope: "*", event: "threads.selectionChanged" },
|
|
1019
|
+
(payload) => {
|
|
1020
|
+
void created.adapter
|
|
1021
|
+
.resolveEngagementEventIds(payload.threadId)
|
|
1022
|
+
.then((ids) => {
|
|
1023
|
+
if (!ids.thread_id) return;
|
|
1024
|
+
created.cloudRef.current.events?.track({
|
|
1025
|
+
kind: "thread_switched",
|
|
1026
|
+
...ids,
|
|
1027
|
+
});
|
|
1028
|
+
})
|
|
1029
|
+
.catch(() => {});
|
|
1030
|
+
},
|
|
1031
|
+
);
|
|
1032
|
+
rootEngagementTrackers.set(aui, created);
|
|
1033
|
+
tracker = created;
|
|
1034
|
+
}
|
|
1035
|
+
const active = tracker;
|
|
1036
|
+
active.adapter = adapter;
|
|
1037
|
+
active.cloudRef = cloudRef;
|
|
1038
|
+
active.count += 1;
|
|
1039
|
+
return () => {
|
|
1040
|
+
active.count -= 1;
|
|
1041
|
+
if (active.count === 0) {
|
|
1042
|
+
active.dispose();
|
|
1043
|
+
rootEngagementTrackers.delete(aui);
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
}, [adapter, aui, cloudRef]);
|
|
1047
|
+
};
|
|
1048
|
+
|
|
1049
|
+
const useAssistantCloudEngagementEvents = (
|
|
1050
|
+
cloudRef: RefObject<AssistantCloud>,
|
|
1051
|
+
adapter: AssistantCloudThreadHistoryAdapter,
|
|
1052
|
+
aui: AssistantClient,
|
|
1053
|
+
) => {
|
|
1054
|
+
useRootEngagementEvents(cloudRef, adapter, aui);
|
|
1055
|
+
const runStartedAt = useRef(new Map<string, number>());
|
|
1056
|
+
const runEndedAt = useRef(new Map<string, number>());
|
|
1057
|
+
const shownSuggestions = useRef(new Set<string>());
|
|
1058
|
+
|
|
1059
|
+
useEffect(() => {
|
|
1060
|
+
const track = (
|
|
1061
|
+
event: AssistantCloudEvent,
|
|
1062
|
+
threadId: string,
|
|
1063
|
+
messageId?: string,
|
|
1064
|
+
options?: { awaitThread?: boolean },
|
|
1065
|
+
) => {
|
|
1066
|
+
void adapter
|
|
1067
|
+
.resolveEngagementEventIds(threadId, messageId, options)
|
|
1068
|
+
.then((ids) => {
|
|
1069
|
+
cloudRef.current.events?.track({ ...event, ...ids });
|
|
1070
|
+
})
|
|
1071
|
+
.catch(() => {});
|
|
1072
|
+
};
|
|
1073
|
+
const trackRunStopped = (threadId: string) => {
|
|
1074
|
+
const startedAt = runStartedAt.current.get(threadId);
|
|
1075
|
+
if (startedAt === undefined) return;
|
|
1076
|
+
runStartedAt.current.delete(threadId);
|
|
1077
|
+
track(
|
|
1078
|
+
{ kind: "run_stopped", value: Math.max(0, Date.now() - startedAt) },
|
|
1079
|
+
threadId,
|
|
1080
|
+
);
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
const unsubscribers = [
|
|
1084
|
+
aui.on({ scope: "thread", event: "composer.send" }, (payload) => {
|
|
1085
|
+
const previousRunEndedAt = runEndedAt.current.get(payload.threadId);
|
|
1086
|
+
track(
|
|
1087
|
+
{
|
|
1088
|
+
kind: payload.messageId ? "message_edited" : "message_sent",
|
|
1089
|
+
...(payload.messageId
|
|
1090
|
+
? { props: { chars: payload.chars } }
|
|
1091
|
+
: {
|
|
1092
|
+
props: {
|
|
1093
|
+
chars: payload.chars,
|
|
1094
|
+
attachments: payload.attachments,
|
|
1095
|
+
},
|
|
1096
|
+
}),
|
|
1097
|
+
...(!payload.messageId && previousRunEndedAt !== undefined
|
|
1098
|
+
? { value: Math.max(0, Date.now() - previousRunEndedAt) }
|
|
1099
|
+
: undefined),
|
|
1100
|
+
},
|
|
1101
|
+
payload.threadId,
|
|
1102
|
+
payload.messageId,
|
|
1103
|
+
{ awaitThread: !payload.messageId },
|
|
1104
|
+
);
|
|
1105
|
+
if (payload.suggestion) {
|
|
1106
|
+
track({ kind: "suggestion_clicked" }, payload.threadId);
|
|
1107
|
+
}
|
|
1108
|
+
}),
|
|
1109
|
+
aui.on(
|
|
1110
|
+
{ scope: "thread", event: "composer.attachmentAdd" },
|
|
1111
|
+
(payload) => {
|
|
1112
|
+
track(
|
|
1113
|
+
{
|
|
1114
|
+
kind: "attachment_added",
|
|
1115
|
+
...(payload.contentType
|
|
1116
|
+
? { props: { type: payload.contentType } }
|
|
1117
|
+
: undefined),
|
|
1118
|
+
},
|
|
1119
|
+
payload.threadId,
|
|
1120
|
+
payload.messageId,
|
|
1121
|
+
);
|
|
1122
|
+
},
|
|
1123
|
+
),
|
|
1124
|
+
aui.on(
|
|
1125
|
+
{ scope: "thread", event: "composer.attachmentAddError" },
|
|
1126
|
+
(payload) => {
|
|
1127
|
+
track(
|
|
1128
|
+
{
|
|
1129
|
+
kind: "attachment_failed",
|
|
1130
|
+
...(payload.contentType
|
|
1131
|
+
? { props: { type: payload.contentType } }
|
|
1132
|
+
: undefined),
|
|
1133
|
+
},
|
|
1134
|
+
payload.threadId,
|
|
1135
|
+
payload.messageId,
|
|
1136
|
+
);
|
|
1137
|
+
},
|
|
1138
|
+
),
|
|
1139
|
+
aui.on({ scope: "thread", event: "composer.cancel" }, (payload) => {
|
|
1140
|
+
trackRunStopped(payload.threadId);
|
|
1141
|
+
}),
|
|
1142
|
+
aui.on({ scope: "thread", event: "thread.runStart" }, (payload) => {
|
|
1143
|
+
runStartedAt.current.set(payload.threadId, Date.now());
|
|
1144
|
+
}),
|
|
1145
|
+
aui.on({ scope: "thread", event: "thread.runEnd" }, (payload) => {
|
|
1146
|
+
runStartedAt.current.delete(payload.threadId);
|
|
1147
|
+
runEndedAt.current.set(payload.threadId, Date.now());
|
|
1148
|
+
}),
|
|
1149
|
+
aui.on({ scope: "thread", event: "thread.cancelRun" }, (payload) => {
|
|
1150
|
+
trackRunStopped(payload.threadId);
|
|
1151
|
+
}),
|
|
1152
|
+
aui.on({ scope: "thread", event: "thread.voiceStarted" }, (payload) => {
|
|
1153
|
+
track({ kind: "voice_started" }, payload.threadId);
|
|
1154
|
+
}),
|
|
1155
|
+
aui.on({ scope: "thread", event: "message.reload" }, (payload) => {
|
|
1156
|
+
track(
|
|
1157
|
+
{ kind: "message_regenerated" },
|
|
1158
|
+
payload.threadId,
|
|
1159
|
+
payload.messageId,
|
|
1160
|
+
);
|
|
1161
|
+
}),
|
|
1162
|
+
aui.on(
|
|
1163
|
+
{ scope: "thread", event: "message.branchSwitched" },
|
|
1164
|
+
(payload) => {
|
|
1165
|
+
track(
|
|
1166
|
+
{ kind: "branch_switched" },
|
|
1167
|
+
payload.threadId,
|
|
1168
|
+
payload.messageId,
|
|
1169
|
+
);
|
|
1170
|
+
},
|
|
1171
|
+
),
|
|
1172
|
+
aui.on({ scope: "thread", event: "message.copied" }, (payload) => {
|
|
1173
|
+
track({ kind: "message_copied" }, payload.threadId, payload.messageId);
|
|
1174
|
+
}),
|
|
1175
|
+
aui.on({ scope: "thread", event: "message.speak" }, (payload) => {
|
|
1176
|
+
track({ kind: "speech_started" }, payload.threadId, payload.messageId);
|
|
1177
|
+
}),
|
|
1178
|
+
aui.on({ scope: "thread", event: "message.error" }, (payload) => {
|
|
1179
|
+
track(
|
|
1180
|
+
{ kind: "error_shown", props: { reason: payload.reason } },
|
|
1181
|
+
payload.threadId,
|
|
1182
|
+
payload.messageId,
|
|
1183
|
+
);
|
|
1184
|
+
}),
|
|
1185
|
+
];
|
|
1186
|
+
|
|
1187
|
+
return () => {
|
|
1188
|
+
for (const unsubscribe of unsubscribers) unsubscribe();
|
|
1189
|
+
};
|
|
1190
|
+
}, [adapter, aui, cloudRef]);
|
|
1191
|
+
|
|
1192
|
+
useEffect(() => {
|
|
1193
|
+
const reportSuggestions = () => {
|
|
1194
|
+
const { mainThreadId } = aui.threads.getState();
|
|
1195
|
+
if (aui.threadListItem.getState().id !== mainThreadId) return;
|
|
1196
|
+
const { isEmpty, suggestions } = aui.thread.getState();
|
|
1197
|
+
if (
|
|
1198
|
+
!isEmpty ||
|
|
1199
|
+
suggestions.length === 0 ||
|
|
1200
|
+
shownSuggestions.current.has(mainThreadId)
|
|
1201
|
+
) {
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
1204
|
+
shownSuggestions.current.add(mainThreadId);
|
|
1205
|
+
void adapter.resolveEngagementEventIds(mainThreadId).then((ids) => {
|
|
1206
|
+
cloudRef.current.events?.track({
|
|
1207
|
+
kind: "suggestions_shown",
|
|
1208
|
+
value: suggestions.length,
|
|
1209
|
+
...ids,
|
|
1210
|
+
});
|
|
1211
|
+
});
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
reportSuggestions();
|
|
1215
|
+
return aui.subscribe(reportSuggestions);
|
|
1216
|
+
}, [adapter, aui, cloudRef]);
|
|
1217
|
+
};
|