@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
isAttachmentComplete,
|
|
2
3
|
isCreateAttachment,
|
|
3
4
|
type Attachment,
|
|
4
5
|
type CompleteAttachment,
|
|
@@ -34,9 +35,6 @@ import {
|
|
|
34
35
|
drainAttachmentAdd,
|
|
35
36
|
} from "../utils/attachment-add-operations";
|
|
36
37
|
|
|
37
|
-
const isAttachmentComplete = (a: Attachment): a is CompleteAttachment =>
|
|
38
|
-
a.status.type === "complete";
|
|
39
|
-
|
|
40
38
|
export abstract class BaseComposerRuntimeCore
|
|
41
39
|
extends BaseSubscribable
|
|
42
40
|
implements ComposerRuntimeCore
|
|
@@ -161,6 +159,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
161
159
|
private _emptyTextAndAttachments() {
|
|
162
160
|
this._attachments = [];
|
|
163
161
|
this._text = "";
|
|
162
|
+
this._rebaseDictation("");
|
|
164
163
|
this._notifySubscribers();
|
|
165
164
|
}
|
|
166
165
|
|
|
@@ -301,7 +300,10 @@ export abstract class BaseComposerRuntimeCore
|
|
|
301
300
|
void sendTask.catch((error) => {
|
|
302
301
|
this._restoreUnsentDraft(error, generation, draft);
|
|
303
302
|
});
|
|
304
|
-
this._notifyEventSubscribers("send", {
|
|
303
|
+
this._notifyEventSubscribers("send", {
|
|
304
|
+
chars: text.length,
|
|
305
|
+
attachments: finalAttachments.length,
|
|
306
|
+
});
|
|
305
307
|
}
|
|
306
308
|
|
|
307
309
|
/**
|
|
@@ -417,6 +419,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
417
419
|
message,
|
|
418
420
|
undefined,
|
|
419
421
|
err,
|
|
422
|
+
fileOrAttachment.contentType,
|
|
420
423
|
);
|
|
421
424
|
throw err;
|
|
422
425
|
}
|
|
@@ -431,7 +434,9 @@ export abstract class BaseComposerRuntimeCore
|
|
|
431
434
|
};
|
|
432
435
|
this._attachments = [...this._attachments, a];
|
|
433
436
|
this._notifySubscribers();
|
|
434
|
-
this._notifyEventSubscribers("attachmentAdd", {
|
|
437
|
+
this._notifyEventSubscribers("attachmentAdd", {
|
|
438
|
+
...(a.contentType ? { contentType: a.contentType } : undefined),
|
|
439
|
+
});
|
|
435
440
|
return;
|
|
436
441
|
}
|
|
437
442
|
|
|
@@ -439,7 +444,13 @@ export abstract class BaseComposerRuntimeCore
|
|
|
439
444
|
if (!adapter) {
|
|
440
445
|
const message = "Attachments are not supported";
|
|
441
446
|
const err = new Error(message);
|
|
442
|
-
this._safeEmitAttachmentAddError(
|
|
447
|
+
this._safeEmitAttachmentAddError(
|
|
448
|
+
"no-adapter",
|
|
449
|
+
message,
|
|
450
|
+
undefined,
|
|
451
|
+
err,
|
|
452
|
+
fileOrAttachment.type,
|
|
453
|
+
);
|
|
443
454
|
throw err;
|
|
444
455
|
}
|
|
445
456
|
|
|
@@ -451,7 +462,13 @@ export abstract class BaseComposerRuntimeCore
|
|
|
451
462
|
) {
|
|
452
463
|
const message = `File type ${fileOrAttachment.type || "unknown"} is not accepted. Accepted types: ${adapter.accept}`;
|
|
453
464
|
const err = new Error(message);
|
|
454
|
-
this._safeEmitAttachmentAddError(
|
|
465
|
+
this._safeEmitAttachmentAddError(
|
|
466
|
+
"not-accepted",
|
|
467
|
+
message,
|
|
468
|
+
undefined,
|
|
469
|
+
err,
|
|
470
|
+
fileOrAttachment.type,
|
|
471
|
+
);
|
|
455
472
|
throw err;
|
|
456
473
|
}
|
|
457
474
|
|
|
@@ -501,6 +518,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
501
518
|
e instanceof Error ? e.message : String(e),
|
|
502
519
|
lastAttachment?.id,
|
|
503
520
|
e instanceof Error ? e : undefined,
|
|
521
|
+
lastAttachment?.contentType || fileOrAttachment.type,
|
|
504
522
|
);
|
|
505
523
|
throw e;
|
|
506
524
|
} finally {
|
|
@@ -517,9 +535,17 @@ export abstract class BaseComposerRuntimeCore
|
|
|
517
535
|
lastAttachment.status.message ??
|
|
518
536
|
"Attachment upload did not complete successfully.",
|
|
519
537
|
lastAttachment.id,
|
|
538
|
+
undefined,
|
|
539
|
+
lastAttachment.contentType || fileOrAttachment.type,
|
|
520
540
|
);
|
|
521
541
|
} else {
|
|
522
|
-
this._notifyEventSubscribers("attachmentAdd", {
|
|
542
|
+
this._notifyEventSubscribers("attachmentAdd", {
|
|
543
|
+
...(lastAttachment?.contentType
|
|
544
|
+
? { contentType: lastAttachment.contentType }
|
|
545
|
+
: fileOrAttachment.type
|
|
546
|
+
? { contentType: fileOrAttachment.type }
|
|
547
|
+
: undefined),
|
|
548
|
+
});
|
|
523
549
|
}
|
|
524
550
|
}
|
|
525
551
|
|
|
@@ -528,6 +554,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
528
554
|
message: string,
|
|
529
555
|
attachmentId?: string,
|
|
530
556
|
error?: Error,
|
|
557
|
+
contentType?: string,
|
|
531
558
|
) {
|
|
532
559
|
try {
|
|
533
560
|
this._notifyEventSubscribers("attachmentAddError", {
|
|
@@ -535,6 +562,7 @@ export abstract class BaseComposerRuntimeCore
|
|
|
535
562
|
message,
|
|
536
563
|
...(attachmentId !== undefined && { attachmentId }),
|
|
537
564
|
...(error !== undefined && { error }),
|
|
565
|
+
...(contentType ? { contentType } : undefined),
|
|
538
566
|
});
|
|
539
567
|
} catch (subscriberError) {
|
|
540
568
|
console.error(
|
|
@@ -16,6 +16,9 @@ import { BaseThreadRuntimeCore } from "./base-thread-runtime-core";
|
|
|
16
16
|
|
|
17
17
|
const createVoiceAdapter = () => {
|
|
18
18
|
let volumeCallback: ((volume: number) => void) | undefined;
|
|
19
|
+
let transcriptCallback:
|
|
20
|
+
| ((transcript: RealtimeVoiceAdapter.TranscriptItem) => void)
|
|
21
|
+
| undefined;
|
|
19
22
|
const session: RealtimeVoiceAdapter.Session = {
|
|
20
23
|
status: { type: "running" },
|
|
21
24
|
isMuted: false,
|
|
@@ -23,7 +26,12 @@ const createVoiceAdapter = () => {
|
|
|
23
26
|
mute: vi.fn(),
|
|
24
27
|
unmute: vi.fn(),
|
|
25
28
|
onStatusChange: () => () => {},
|
|
26
|
-
onTranscript: () =>
|
|
29
|
+
onTranscript: (callback) => {
|
|
30
|
+
transcriptCallback = callback;
|
|
31
|
+
return () => {
|
|
32
|
+
transcriptCallback = undefined;
|
|
33
|
+
};
|
|
34
|
+
},
|
|
27
35
|
onModeChange: () => () => {},
|
|
28
36
|
onVolumeChange: (callback) => {
|
|
29
37
|
volumeCallback = callback;
|
|
@@ -36,10 +44,13 @@ const createVoiceAdapter = () => {
|
|
|
36
44
|
return {
|
|
37
45
|
adapter: { connect: () => session },
|
|
38
46
|
emitVolume: (volume: number) => volumeCallback?.(volume),
|
|
47
|
+
emitTranscript: (transcript: RealtimeVoiceAdapter.TranscriptItem) =>
|
|
48
|
+
transcriptCallback?.(transcript),
|
|
39
49
|
session,
|
|
40
50
|
} satisfies {
|
|
41
51
|
adapter: RealtimeVoiceAdapter;
|
|
42
52
|
emitVolume: (volume: number) => void;
|
|
53
|
+
emitTranscript: (transcript: RealtimeVoiceAdapter.TranscriptItem) => void;
|
|
43
54
|
session: RealtimeVoiceAdapter.Session;
|
|
44
55
|
};
|
|
45
56
|
};
|
|
@@ -296,3 +307,46 @@ describe("BaseThreadRuntimeCore voice volume subscriptions", () => {
|
|
|
296
307
|
});
|
|
297
308
|
});
|
|
298
309
|
});
|
|
310
|
+
|
|
311
|
+
describe("BaseThreadRuntimeCore voice transcripts", () => {
|
|
312
|
+
it("completes a final-only reply before the next streamed reply", () => {
|
|
313
|
+
const voiceAdapter = createVoiceAdapter();
|
|
314
|
+
const runtime = new TestRuntime(voiceAdapter);
|
|
315
|
+
runtime.connectVoice();
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
voiceAdapter.emitTranscript({
|
|
319
|
+
role: "assistant",
|
|
320
|
+
text: "Finished reply",
|
|
321
|
+
isFinal: true,
|
|
322
|
+
});
|
|
323
|
+
expect(runtime.messages).toMatchObject([
|
|
324
|
+
{
|
|
325
|
+
content: [{ type: "text", text: "Finished reply" }],
|
|
326
|
+
status: { type: "complete", reason: "stop" },
|
|
327
|
+
},
|
|
328
|
+
]);
|
|
329
|
+
|
|
330
|
+
voiceAdapter.emitTranscript({ role: "assistant", text: "Next" });
|
|
331
|
+
expect(runtime.messages.at(-1)?.status).toEqual({ type: "running" });
|
|
332
|
+
|
|
333
|
+
voiceAdapter.emitTranscript({
|
|
334
|
+
role: "assistant",
|
|
335
|
+
text: "Next reply",
|
|
336
|
+
isFinal: true,
|
|
337
|
+
});
|
|
338
|
+
expect(runtime.messages).toMatchObject([
|
|
339
|
+
{
|
|
340
|
+
content: [{ type: "text", text: "Finished reply" }],
|
|
341
|
+
status: { type: "complete", reason: "stop" },
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
content: [{ type: "text", text: "Next reply" }],
|
|
345
|
+
status: { type: "complete", reason: "stop" },
|
|
346
|
+
},
|
|
347
|
+
]);
|
|
348
|
+
} finally {
|
|
349
|
+
runtime.disconnectVoice();
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
});
|
|
@@ -393,6 +393,10 @@ export abstract class BaseThreadRuntimeCore
|
|
|
393
393
|
this._notifySubscribers();
|
|
394
394
|
}
|
|
395
395
|
} else {
|
|
396
|
+
const status: ThreadAssistantMessage["status"] = transcript.isFinal
|
|
397
|
+
? { type: "complete", reason: "stop" }
|
|
398
|
+
: { type: "running" };
|
|
399
|
+
|
|
396
400
|
if (!this._currentAssistantMsg) {
|
|
397
401
|
this._currentAssistantMsg = {
|
|
398
402
|
id: generateId(),
|
|
@@ -405,7 +409,7 @@ export abstract class BaseThreadRuntimeCore
|
|
|
405
409
|
steps: [],
|
|
406
410
|
custom: {},
|
|
407
411
|
},
|
|
408
|
-
status
|
|
412
|
+
status,
|
|
409
413
|
createdAt: new Date(),
|
|
410
414
|
};
|
|
411
415
|
this._voiceMessages.push(this._currentAssistantMsg);
|
|
@@ -415,9 +419,7 @@ export abstract class BaseThreadRuntimeCore
|
|
|
415
419
|
const updated: ThreadAssistantMessage = {
|
|
416
420
|
...this._currentAssistantMsg,
|
|
417
421
|
content: [{ type: "text", text: transcript.text }],
|
|
418
|
-
|
|
419
|
-
? { status: { type: "complete", reason: "stop" } }
|
|
420
|
-
: {}),
|
|
422
|
+
status,
|
|
421
423
|
};
|
|
422
424
|
this._voiceMessages[idx] = updated;
|
|
423
425
|
this._currentAssistantMsg = updated;
|
|
@@ -21,16 +21,21 @@ export type AttachmentAddErrorEvent = {
|
|
|
21
21
|
|
|
22
22
|
export type ComposerRuntimeEventPayload = {
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* Fired after a send with the size of what went out. The composer state is
|
|
25
|
+
* already cleared when it fires, so the counts are only available here.
|
|
26
26
|
*/
|
|
27
|
-
send:
|
|
27
|
+
send: {
|
|
28
|
+
readonly chars: number;
|
|
29
|
+
readonly attachments: number;
|
|
30
|
+
};
|
|
28
31
|
/**
|
|
29
32
|
* @deprecated State-derivable. Observe `state.attachments` via `subscribe` +
|
|
30
33
|
* `getState` instead. Kept for backward compatibility.
|
|
31
34
|
*/
|
|
32
|
-
attachmentAdd:
|
|
33
|
-
attachmentAddError: AttachmentAddErrorEvent
|
|
35
|
+
attachmentAdd: { readonly contentType?: string | undefined };
|
|
36
|
+
attachmentAddError: AttachmentAddErrorEvent & {
|
|
37
|
+
readonly contentType?: string | undefined;
|
|
38
|
+
};
|
|
34
39
|
};
|
|
35
40
|
|
|
36
41
|
export type ComposerRuntimeEventType = keyof ComposerRuntimeEventPayload;
|
|
@@ -26,6 +26,7 @@ export type ThreadListRuntimeEvent = {
|
|
|
26
26
|
|
|
27
27
|
export type ThreadListRuntimeCore = {
|
|
28
28
|
readonly isLoading: boolean;
|
|
29
|
+
readonly loadError?: unknown;
|
|
29
30
|
readonly isLoadingMore?: boolean;
|
|
30
31
|
readonly hasMore?: boolean;
|
|
31
32
|
mainThreadId: string;
|
|
@@ -86,7 +87,10 @@ export type ThreadListRuntimeCore = {
|
|
|
86
87
|
initialize(
|
|
87
88
|
threadId: string,
|
|
88
89
|
): Promise<{ remoteId: string; externalId: string | undefined }>;
|
|
89
|
-
generateTitle(
|
|
90
|
+
generateTitle(
|
|
91
|
+
threadId: string,
|
|
92
|
+
options?: { automatic?: boolean },
|
|
93
|
+
): Promise<void>;
|
|
90
94
|
|
|
91
95
|
subscribe(callback: () => void): Unsubscribe;
|
|
92
96
|
};
|
|
@@ -83,6 +83,74 @@ describe("chunkExternalMessages", () => {
|
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
describe("convertExternalMessageChunk", () => {
|
|
86
|
+
it("keeps separate tool calls without IDs", () => {
|
|
87
|
+
const result = convertExternalMessageChunk(
|
|
88
|
+
{
|
|
89
|
+
inputs: [{}],
|
|
90
|
+
outputs: [
|
|
91
|
+
{
|
|
92
|
+
role: "assistant",
|
|
93
|
+
content: [
|
|
94
|
+
{ type: "tool-call", toolName: "weather", args: {} },
|
|
95
|
+
{ type: "tool-call", toolName: "search", args: {} },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
0,
|
|
101
|
+
1,
|
|
102
|
+
false,
|
|
103
|
+
undefined,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(result.content).toMatchObject([
|
|
107
|
+
{ type: "tool-call", toolName: "weather" },
|
|
108
|
+
{ type: "tool-call", toolName: "search" },
|
|
109
|
+
]);
|
|
110
|
+
const calls = result.content.filter((part) => part.type === "tool-call");
|
|
111
|
+
expect(calls[0]!.toolCallId).not.toBe(calls[1]!.toolCallId);
|
|
112
|
+
expect(calls.map((call) => call.toolCallId)).not.toContain("");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("keeps separate tool calls with empty IDs", () => {
|
|
116
|
+
const result = convertExternalMessageChunk(
|
|
117
|
+
{
|
|
118
|
+
inputs: [{}],
|
|
119
|
+
outputs: [
|
|
120
|
+
{
|
|
121
|
+
role: "assistant",
|
|
122
|
+
content: [
|
|
123
|
+
{
|
|
124
|
+
type: "tool-call",
|
|
125
|
+
toolCallId: "",
|
|
126
|
+
toolName: "weather",
|
|
127
|
+
args: {},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
type: "tool-call",
|
|
131
|
+
toolCallId: "",
|
|
132
|
+
toolName: "search",
|
|
133
|
+
args: {},
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
0,
|
|
140
|
+
1,
|
|
141
|
+
false,
|
|
142
|
+
undefined,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
expect(result.content).toMatchObject([
|
|
146
|
+
{ type: "tool-call", toolName: "weather" },
|
|
147
|
+
{ type: "tool-call", toolName: "search" },
|
|
148
|
+
]);
|
|
149
|
+
const calls = result.content.filter((part) => part.type === "tool-call");
|
|
150
|
+
expect(calls[0]?.toolCallId).not.toBe(calls[1]?.toolCallId);
|
|
151
|
+
expect(calls.map((call) => call.toolCallId)).not.toContain("");
|
|
152
|
+
});
|
|
153
|
+
|
|
86
154
|
it("reuses a cached message when the error status is unchanged", () => {
|
|
87
155
|
const input = {};
|
|
88
156
|
const chunk = {
|
|
@@ -252,7 +252,7 @@ export const joinExternalMessages = (
|
|
|
252
252
|
|
|
253
253
|
// Add content parts, merging reasoning parts with same parentId
|
|
254
254
|
for (const part of content) {
|
|
255
|
-
if (part.type === "tool-call") {
|
|
255
|
+
if (part.type === "tool-call" && part.toolCallId) {
|
|
256
256
|
const existingIdx = assistantMessage.content.findIndex(
|
|
257
257
|
(c) =>
|
|
258
258
|
c.type === "tool-call" && c.toolCallId === part.toolCallId,
|
|
@@ -134,6 +134,16 @@ export class MessageRepository {
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
private selectPathTo(message: RepositoryMessage) {
|
|
138
|
+
for (
|
|
139
|
+
let current: RepositoryMessage | null = message;
|
|
140
|
+
current;
|
|
141
|
+
current = current.prev
|
|
142
|
+
) {
|
|
143
|
+
(current.prev ?? this.root).next = current;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
137
147
|
private performOp(
|
|
138
148
|
newParent: RepositoryMessage | null,
|
|
139
149
|
child: RepositoryMessage,
|
|
@@ -182,12 +192,17 @@ export class MessageRepository {
|
|
|
182
192
|
child.current.id,
|
|
183
193
|
];
|
|
184
194
|
|
|
185
|
-
|
|
195
|
+
child.prev = newParent;
|
|
196
|
+
|
|
197
|
+
if (findHead(child) === this.head) {
|
|
198
|
+
this.selectPathTo(child);
|
|
199
|
+
} else if (newParentOrRoot.next === null) {
|
|
186
200
|
newParentOrRoot.next = child;
|
|
201
|
+
if (this.head === newParentOrRoot) {
|
|
202
|
+
this.head = findHead(child);
|
|
203
|
+
}
|
|
187
204
|
}
|
|
188
205
|
|
|
189
|
-
child.prev = newParent;
|
|
190
|
-
|
|
191
206
|
const newLevel = newParent ? newParent.level + 1 : 0;
|
|
192
207
|
this.updateLevels(child, newLevel);
|
|
193
208
|
}
|
|
@@ -381,8 +396,7 @@ export class MessageRepository {
|
|
|
381
396
|
);
|
|
382
397
|
|
|
383
398
|
const previousHead = this.head;
|
|
384
|
-
|
|
385
|
-
prevOrRoot.next = message;
|
|
399
|
+
this.selectPathTo(message);
|
|
386
400
|
|
|
387
401
|
this.head = findHead(message);
|
|
388
402
|
|
|
@@ -423,17 +437,7 @@ export class MessageRepository {
|
|
|
423
437
|
}
|
|
424
438
|
|
|
425
439
|
this.head = message;
|
|
426
|
-
|
|
427
|
-
let current: RepositoryMessage | null = message;
|
|
428
|
-
current;
|
|
429
|
-
current = current.prev
|
|
430
|
-
) {
|
|
431
|
-
if (current.prev) {
|
|
432
|
-
current.prev.next = current;
|
|
433
|
-
} else {
|
|
434
|
-
this.root.next = current;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
440
|
+
this.selectPathTo(message);
|
|
437
441
|
|
|
438
442
|
this.evictOffBranchOptimisticMessages(previousHead, this.head);
|
|
439
443
|
|
|
@@ -456,7 +460,15 @@ export class MessageRepository {
|
|
|
456
460
|
// Optimistic messages are ephemeral and never persisted. A persisted child
|
|
457
461
|
// of an optimistic node is re-parented onto its nearest persisted ancestor
|
|
458
462
|
// so the exported tree never references a skipped id.
|
|
459
|
-
|
|
463
|
+
// Import and external-state conversion require parents before children, so
|
|
464
|
+
// the tree is walked in pre-order rather than iterated in insertion order.
|
|
465
|
+
const pending = [...this.root.children].reverse();
|
|
466
|
+
while (pending.length > 0) {
|
|
467
|
+
const message = this.messages.get(pending.pop()!);
|
|
468
|
+
if (!message) continue;
|
|
469
|
+
for (let i = message.children.length - 1; i >= 0; i--) {
|
|
470
|
+
pending.push(message.children[i]!);
|
|
471
|
+
}
|
|
460
472
|
if (message.current.metadata?.isOptimistic) continue;
|
|
461
473
|
let prev = message.prev;
|
|
462
474
|
while (prev && prev.current.metadata?.isOptimistic) {
|
|
@@ -179,7 +179,7 @@ export const fromThreadMessageLike = (
|
|
|
179
179
|
const { parentId, messages, ...basePart } = part;
|
|
180
180
|
const commonProps = {
|
|
181
181
|
...basePart,
|
|
182
|
-
toolCallId: part.toolCallId
|
|
182
|
+
toolCallId: part.toolCallId || `tool-${generateId()}`,
|
|
183
183
|
...(parentId !== undefined && { parentId }),
|
|
184
184
|
...(messages !== undefined && { messages }),
|
|
185
185
|
};
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
import type { ExternalStoreThreadListAdapter } from "./external-store-adapter";
|
|
7
7
|
import { invalidateThreadRuntime } from "../../runtime/utils/thread-runtime-lifecycle";
|
|
8
8
|
import { BaseSubscribable } from "../../subscribable/subscribable";
|
|
9
|
+
import { nullProtoRecord } from "../../utils/record";
|
|
9
10
|
|
|
10
11
|
export type ExternalStoreThreadFactory = () => ExternalStoreThreadRuntimeCore;
|
|
11
12
|
|
|
@@ -19,9 +20,11 @@ const DEFAULT_THREAD = Object.freeze({
|
|
|
19
20
|
status: "regular",
|
|
20
21
|
});
|
|
21
22
|
const RESOLVED_PROMISE = Promise.resolve();
|
|
22
|
-
const DEFAULT_THREAD_DATA = Object.freeze(
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const DEFAULT_THREAD_DATA = Object.freeze(
|
|
24
|
+
nullProtoRecord<ThreadListItemCoreState>({
|
|
25
|
+
[DEFAULT_THREAD_ID]: DEFAULT_THREAD,
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
25
28
|
|
|
26
29
|
export class ExternalStoreThreadListRuntimeCore
|
|
27
30
|
extends BaseSubscribable
|
|
@@ -84,7 +87,9 @@ export class ExternalStoreThreadListRuntimeCore
|
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
public getItemById(threadId: string) {
|
|
87
|
-
return this._threadData
|
|
90
|
+
return Object.hasOwn(this._threadData, threadId)
|
|
91
|
+
? this._threadData[threadId]
|
|
92
|
+
: undefined;
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
public __internal_setAdapter(
|
|
@@ -105,6 +110,7 @@ export class ExternalStoreThreadListRuntimeCore
|
|
|
105
110
|
|
|
106
111
|
if (
|
|
107
112
|
!initialLoad &&
|
|
113
|
+
(previousAdapter.isLoading ?? false) === (adapter.isLoading ?? false) &&
|
|
108
114
|
previousThreadId === newThreadId &&
|
|
109
115
|
previousThreads === newThreads &&
|
|
110
116
|
previousArchivedThreads === newArchivedThreads
|
|
@@ -117,9 +123,9 @@ export class ExternalStoreThreadListRuntimeCore
|
|
|
117
123
|
previousArchivedThreads !== newArchivedThreads ||
|
|
118
124
|
previousThreadId !== newThreadId
|
|
119
125
|
) {
|
|
120
|
-
this._threadData =
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
this._threadData = nullProtoRecord(
|
|
127
|
+
DEFAULT_THREAD_DATA,
|
|
128
|
+
Object.fromEntries(
|
|
123
129
|
adapter.threads?.map((t) => [
|
|
124
130
|
t.id,
|
|
125
131
|
{
|
|
@@ -130,7 +136,7 @@ export class ExternalStoreThreadListRuntimeCore
|
|
|
130
136
|
},
|
|
131
137
|
]) ?? [],
|
|
132
138
|
),
|
|
133
|
-
|
|
139
|
+
Object.fromEntries(
|
|
134
140
|
adapter.archivedThreads?.map((t) => [
|
|
135
141
|
t.id,
|
|
136
142
|
{
|
|
@@ -141,7 +147,7 @@ export class ExternalStoreThreadListRuntimeCore
|
|
|
141
147
|
},
|
|
142
148
|
]) ?? [],
|
|
143
149
|
),
|
|
144
|
-
|
|
150
|
+
);
|
|
145
151
|
}
|
|
146
152
|
|
|
147
153
|
if (previousThreads !== newThreads) {
|
|
@@ -160,16 +166,15 @@ export class ExternalStoreThreadListRuntimeCore
|
|
|
160
166
|
this._mainThread = this.threadFactory();
|
|
161
167
|
}
|
|
162
168
|
|
|
163
|
-
if (!this._threadData
|
|
164
|
-
this._threadData = {
|
|
165
|
-
...this._threadData,
|
|
169
|
+
if (!Object.hasOwn(this._threadData, this._mainThreadId)) {
|
|
170
|
+
this._threadData = nullProtoRecord(this._threadData, {
|
|
166
171
|
[this._mainThreadId]: {
|
|
167
172
|
id: this._mainThreadId,
|
|
168
173
|
remoteId: undefined,
|
|
169
174
|
externalId: undefined,
|
|
170
175
|
status: "regular",
|
|
171
176
|
},
|
|
172
|
-
};
|
|
177
|
+
});
|
|
173
178
|
}
|
|
174
179
|
|
|
175
180
|
this._notifySubscribers();
|