@acorex-platform/extension-ai-conversation-client 0.0.38 → 0.0.48
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/fesm2022/{acorex-platform-extension-ai-conversation-client-acorex-platform-extension-ai-conversation-client-CRjLZIU5.mjs → acorex-platform-extension-ai-conversation-client-acorex-platform-extension-ai-conversation-client-DfdGeEG4.mjs} +1002 -271
- package/fesm2022/acorex-platform-extension-ai-conversation-client-acorex-platform-extension-ai-conversation-client-DfdGeEG4.mjs.map +1 -0
- package/fesm2022/{acorex-platform-extension-ai-conversation-client-send-assist-chat-message.command-B3rJWdsz.mjs → acorex-platform-extension-ai-conversation-client-send-assist-chat-message.command-B6QodNVg.mjs} +7 -5
- package/fesm2022/acorex-platform-extension-ai-conversation-client-send-assist-chat-message.command-B6QodNVg.mjs.map +1 -0
- package/fesm2022/{acorex-platform-extension-ai-conversation-client-start-assist-chat.command-qYtaBoTP.mjs → acorex-platform-extension-ai-conversation-client-start-assist-chat.command-zQPeOCRi.mjs} +3 -2
- package/fesm2022/{acorex-platform-extension-ai-conversation-client-start-assist-chat.command-qYtaBoTP.mjs.map → acorex-platform-extension-ai-conversation-client-start-assist-chat.command-zQPeOCRi.mjs.map} +1 -1
- package/fesm2022/acorex-platform-extension-ai-conversation-client.mjs +2 -1
- package/fesm2022/acorex-platform-extension-ai-conversation-client.mjs.map +1 -1
- package/package.json +3 -1
- package/types/acorex-platform-extension-ai-conversation-client.d.ts +50 -4
- package/fesm2022/acorex-platform-extension-ai-conversation-client-acorex-platform-extension-ai-conversation-client-CRjLZIU5.mjs.map +0 -1
- package/fesm2022/acorex-platform-extension-ai-conversation-client-send-assist-chat-message.command-B3rJWdsz.mjs.map +0 -1
|
@@ -1,38 +1,41 @@
|
|
|
1
1
|
import { AXP_SEARCH_PROVIDER, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/common';
|
|
2
2
|
import * as i1$1 from '@acorex-platform/framework-client/core';
|
|
3
3
|
import { AXPComponentSlotModule, provideAppStartUpTask, AXP_APP_STARTUP_PRIORITY } from '@acorex-platform/framework-client/core';
|
|
4
|
-
import {
|
|
5
|
-
import { AXM_AI_MANAGEMENT_MODULE_NAME, AXM_AI_MANAGEMENT_ASSIST_ENTITY_NAME, AXMConversationEntityStoreService, axmChatAiTargetDisplayName, axmChatAiTargetDisplayDescription, axmChatAiTargetAvatarUrl, axmFilterChatAiTargets, axmChatAiPeerParticipantId, axmBuildAiChatConversationMetadata, CONVERSATION_START_ASSIST_CHAT_COMMAND, axmChatAiTargetShortcutDescriptionKey, AXM_ASSIST_DEFAULT_RESOLVER_PORT, axmAssistStarterPromptChipItems, AXMAssistSuggestionChipsComponent, AXM_CHAT_EMPTY_STATE_COMPONENT, AXM_MINI_CHAT_INBOX_CONVERSATION_FILTER, axmConversationHasAiChat, AXMConversationFocusService, axmIsAssistRetryableStatus, axmReadAssistResponseStatus, axmReadReplyToUserMessageId, axmMessageEntityToMessage, axmAssistPersistedMessageLooksComplete, axmShouldPreferPersistedAssistOverLiveCache, axmRoomWithAssistPeerDisplayName, axmSyncAssistPeerDisplayName, axmRoomEntityToConversation, axmIsAssistTerminalStatus, CONVERSATION_SYNC_READ_STATE_COMMAND, axmAssistHasFinalizeMetadata, AXM_CHAT_SIDEBAR_ACTION_PROVIDER, AXMMiniChatHeaderSlotComponent, AXM_CONVERSATION_ASSIST_RESPONSE_PORT, AXM_CHAT_ASSIST_CATALOG_PORT, AXM_CONVERSATION_ASSIST_BACKGROUND_OPERATION_HANDLERS, CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND } from '@acorex-platform/module-conversation-client';
|
|
4
|
+
import { AXPCommandService, AXPRuntimeTransportService, provideCommandSetups } from '@acorex-platform/framework-client/runtime';
|
|
5
|
+
import { AXM_AI_MANAGEMENT_MODULE_NAME, AXM_AI_MANAGEMENT_ASSIST_ENTITY_NAME, AXMEntityChatService, AXMConversationEntityStoreService, axmChatAiTargetDisplayName, axmChatAiTargetDisplayDescription, axmChatAiTargetAvatarUrl, axmFilterChatAiTargets, axmChatAiPeerParticipantId, axmBuildAiChatConversationMetadata, axmEntityRefFromLaunchContext, axmEntityRefForMiniChatPageContext, CONVERSATION_START_ASSIST_CHAT_COMMAND, axmChatAiTargetShortcutDescriptionKey, AXMChatEmptyAssistSessionService, AXM_ASSIST_DEFAULT_RESOLVER_PORT, AXMMiniChatFileDropService, axmAssistStarterPromptChipItems, AXMAssistSuggestionChipsComponent, AXMChatComposerAssistPickerComponent, AXM_CHAT_EMPTY_STATE_COMPONENT, AXM_MINI_CHAT_INBOX_CONVERSATION_FILTER, axmConversationHasAiChat, AXMConversationFocusService, axmIsAssistRetryableStatus, axmReadAssistResponseStatus, axmReadReplyToUserMessageId, axmMessageEntityToMessage, axmAssistPersistedMessageLooksComplete, axmShouldPreferPersistedAssistOverLiveCache, axmRoomWithAssistPeerDisplayName, axmSyncAssistPeerDisplayName, axmRoomEntityToConversation, axmIsAssistTerminalStatus, CONVERSATION_SYNC_READ_STATE_COMMAND, axmAssistHasFinalizeMetadata, AXM_CHAT_SIDEBAR_ACTION_PROVIDER, AXMMiniChatPanelService, AXMMiniChatFooterDockComponent, AXMMiniChatHeaderSlotComponent, AXM_CONVERSATION_ASSIST_RESPONSE_PORT, AXM_CHAT_ASSIST_CATALOG_PORT, AXM_CONVERSATION_ASSIST_BACKGROUND_OPERATION_HANDLERS, CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND } from '@acorex-platform/module-conversation-client';
|
|
6
6
|
import * as i0 from '@angular/core';
|
|
7
|
-
import { inject, Injectable,
|
|
7
|
+
import { inject, Injectable, DestroyRef, viewChild, output, input, computed, signal, effect, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
|
|
8
8
|
import { AXPSystemActionType, runtimeCommandPayloadData } from '@acorex-platform/framework-shared/core';
|
|
9
9
|
import { sortBy } from 'lodash-es';
|
|
10
|
-
import { AXConversationService } from '@acorex/components/conversation';
|
|
10
|
+
import { AXConversationService, AXConversationComposerGenerationStateService } from '@acorex/components/conversation';
|
|
11
11
|
import { AXToastService } from '@acorex/components/toast';
|
|
12
|
-
import * as
|
|
12
|
+
import * as i7 from '@acorex/core/translation';
|
|
13
13
|
import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
|
|
14
14
|
import { AXPSessionService } from '@acorex-platform/framework-client/auth';
|
|
15
|
+
import { AXM_ASSIST_LAUNCH_CONTEXT_METADATA_KEY, axmSanitizeContextualAssistContext, AXM_CONTEXTUAL_ASSIST_STARTER_SYSTEM_PROMPT, axmBuildContextualAssistStarterUserPrompt, axmParseContextualAssistStarterItems } from '@acorex-platform/module-conversation-client/contracts';
|
|
15
16
|
import { AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
|
|
16
17
|
import { Router } from '@angular/router';
|
|
17
|
-
import {
|
|
18
|
+
import { AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY, axpAiChatTextMessage } from '@acorex-platform/module-ai-management-client/contracts';
|
|
18
19
|
import * as i2 from '@acorex/components/button';
|
|
19
20
|
import { AXButtonModule, AXButtonComponent } from '@acorex/components/button';
|
|
20
|
-
import * as
|
|
21
|
+
import * as i3 from '@acorex/components/decorators';
|
|
21
22
|
import { AXDecoratorModule, AXDecoratorGenericComponent } from '@acorex/components/decorators';
|
|
22
|
-
import * as
|
|
23
|
+
import * as i4 from '@acorex/components/dropdown';
|
|
23
24
|
import { AXDropdownModule } from '@acorex/components/dropdown';
|
|
24
|
-
import
|
|
25
|
+
import * as i5 from '@acorex/components/loading';
|
|
26
|
+
import { AXLoadingModule } from '@acorex/components/loading';
|
|
25
27
|
import { AXLocaleService } from '@acorex/core/locale';
|
|
26
|
-
import * as
|
|
28
|
+
import * as i6 from '@angular/common';
|
|
27
29
|
import { CommonModule } from '@angular/common';
|
|
28
|
-
import { toSignal } from '@angular/core/rxjs-interop';
|
|
30
|
+
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
29
31
|
import * as i1 from '@angular/forms';
|
|
30
32
|
import { FormsModule } from '@angular/forms';
|
|
31
33
|
import { AXPAiManagerService } from '@acorex-platform/module-ai-management-client';
|
|
32
|
-
import { AXMAiManagementTransportKeys, AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY, axpAiChatTextMessage } from '@acorex-platform/module-ai-management-client/contracts';
|
|
34
|
+
import { AXMAiManagementTransportKeys, AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY as AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY$1, axpAiChatTextMessage as axpAiChatTextMessage$1 } from '@acorex-platform/module-ai-management-client/contracts';
|
|
33
35
|
import { axmCompareMessagesChronologically, axmExtractAssistIdFromMetadata, AXM_ASSIST_CONVERSATION_TITLE_SYSTEM_PROMPT, axmSanitizeAiGeneratedConversationTitle, extractMessageTextFromPayload, axmEnsureAssistMessageSortsAfterReplyTarget } from '@acorex-platform/module-conversation-client/contracts';
|
|
34
36
|
import { AXPopupService } from '@acorex/components/popup';
|
|
35
37
|
import { AXPAvatarComponent } from '@acorex-platform/framework-client/layout/components';
|
|
38
|
+
import { AXPLayoutThemeService } from '@acorex-platform/framework-client/themes/shared';
|
|
36
39
|
import { AXDataSource, AXComponentCloseEvent, AXClosableComponent } from '@acorex/cdk/common';
|
|
37
40
|
import { AXListComponent } from '@acorex/components/list';
|
|
38
41
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
@@ -169,6 +172,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
169
172
|
class AXMChatAssistLauncherService {
|
|
170
173
|
constructor() {
|
|
171
174
|
this.conversationService = inject(AXConversationService);
|
|
175
|
+
this.entityChatService = inject(AXMEntityChatService);
|
|
172
176
|
this.assistCatalog = inject(AXMChatAssistCatalogService);
|
|
173
177
|
this.entityStore = inject(AXMConversationEntityStoreService);
|
|
174
178
|
this.translationService = inject(AXTranslationService);
|
|
@@ -202,11 +206,11 @@ class AXMChatAssistLauncherService {
|
|
|
202
206
|
this.toastService.danger(message);
|
|
203
207
|
return null;
|
|
204
208
|
}
|
|
205
|
-
return this.startAssistChatFromRow(row, options.navigate !== false);
|
|
209
|
+
return this.startAssistChatFromRow(row, options.navigate !== false, options.launchContext);
|
|
206
210
|
}
|
|
207
|
-
async startAssistChatFromRow(row, navigate = true) {
|
|
211
|
+
async startAssistChatFromRow(row, navigate = true, launchContext) {
|
|
208
212
|
try {
|
|
209
|
-
const conversation = await this.#createTargetConversation(row);
|
|
213
|
+
const conversation = await this.#createTargetConversation(row, launchContext);
|
|
210
214
|
await this.conversationService.selectConversation(conversation.id);
|
|
211
215
|
if (navigate) {
|
|
212
216
|
await this.navigateToConversation(conversation.id);
|
|
@@ -228,18 +232,26 @@ class AXMChatAssistLauncherService {
|
|
|
228
232
|
}
|
|
229
233
|
await this.router.navigate([this.#applicationRouteSegment(), 'chat', scoped]);
|
|
230
234
|
}
|
|
231
|
-
async #createTargetConversation(row) {
|
|
235
|
+
async #createTargetConversation(row, launchContext) {
|
|
232
236
|
await this.assistCatalog.loadCatalogTargets();
|
|
233
237
|
const participantId = axmChatAiPeerParticipantId(row.id);
|
|
234
238
|
const title = this.displayName(row);
|
|
235
239
|
const avatar = this.targetAvatarUrl(row);
|
|
236
240
|
const assistRow = this.assistCatalog.getCachedAssist(row.id);
|
|
237
241
|
const assistSnapshot = assistRow ? this.assistCatalog.toSnapshot(assistRow) : undefined;
|
|
242
|
+
const metadata = axmBuildAiChatConversationMetadata(row, assistSnapshot);
|
|
243
|
+
if (launchContext) {
|
|
244
|
+
metadata[AXM_ASSIST_LAUNCH_CONTEXT_METADATA_KEY] = axmSanitizeContextualAssistContext(launchContext);
|
|
245
|
+
}
|
|
246
|
+
const entityRef = axmEntityRefFromLaunchContext(launchContext) ?? axmEntityRefForMiniChatPageContext(launchContext);
|
|
247
|
+
if (entityRef) {
|
|
248
|
+
return this.entityChatService.createEntityChat(entityRef, row.id, metadata);
|
|
249
|
+
}
|
|
238
250
|
const conversation = await this.conversationService.createConversation([participantId], 'bot', {
|
|
239
251
|
title,
|
|
240
252
|
...(avatar ? { avatar } : {}),
|
|
241
253
|
icon: 'fa-solid fa-robot',
|
|
242
|
-
metadata
|
|
254
|
+
metadata,
|
|
243
255
|
});
|
|
244
256
|
this.entityStore.cacheConversation(conversation);
|
|
245
257
|
this.entityStore.cacheEmptyMessageList(conversation.id);
|
|
@@ -320,126 +332,309 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
320
332
|
type: Injectable
|
|
321
333
|
}] });
|
|
322
334
|
|
|
335
|
+
const FALLBACK_CHIP_KEYS = ['@conversation:chat.contextual-assist.fallback.summarize', '@conversation:chat.contextual-assist.fallback.what-can-i-change', '@conversation:chat.contextual-assist.fallback.explain-record'];
|
|
336
|
+
const DRAFT_KIND_ICONS = {
|
|
337
|
+
image: 'fa-light fa-image',
|
|
338
|
+
video: 'fa-light fa-video',
|
|
339
|
+
audio: 'fa-light fa-music',
|
|
340
|
+
file: 'fa-light fa-file',
|
|
341
|
+
};
|
|
342
|
+
const MAX_EMPTY_DRAFT_FILES = 3;
|
|
323
343
|
class AXMChatEmptyAssistComposerComponent {
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region ----- Lifecycle -----
|
|
324
346
|
constructor() {
|
|
325
|
-
|
|
347
|
+
//#region ----- Services & Dependencies -----
|
|
348
|
+
this.commandService = inject(AXPCommandService);
|
|
326
349
|
this.toastService = inject(AXToastService);
|
|
327
350
|
this.translationService = inject(AXTranslationService);
|
|
328
351
|
this.localeService = inject(AXLocaleService);
|
|
329
352
|
this.assistCatalog = inject(AXMChatAssistCatalogService);
|
|
330
|
-
this.
|
|
353
|
+
this.emptyAssistSession = inject(AXMChatEmptyAssistSessionService);
|
|
354
|
+
this.conversationService = inject(AXConversationService);
|
|
331
355
|
this.defaultAssistResolver = inject(AXM_ASSIST_DEFAULT_RESOLVER_PORT, { optional: true });
|
|
332
|
-
this.
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
this.
|
|
336
|
-
...(ngDevMode ? [{ debugName: "
|
|
356
|
+
this.destroyRef = inject(DestroyRef);
|
|
357
|
+
this.fileDrop = inject(AXMMiniChatFileDropService);
|
|
358
|
+
this.unregisterEmptyDraft = null;
|
|
359
|
+
this.draftInput = viewChild('draftInput', /* @ts-ignore */
|
|
360
|
+
...(ngDevMode ? [{ debugName: "draftInput" }] : /* istanbul ignore next */ []));
|
|
361
|
+
this.fileInput = viewChild('fileInput', /* @ts-ignore */
|
|
362
|
+
...(ngDevMode ? [{ debugName: "fileInput" }] : /* istanbul ignore next */ []));
|
|
363
|
+
//#endregion
|
|
364
|
+
//#region ----- Inputs / Outputs -----
|
|
337
365
|
this.conversationCreated = output();
|
|
338
366
|
this.initialAssistId = input(undefined, /* @ts-ignore */
|
|
339
367
|
...(ngDevMode ? [{ debugName: "initialAssistId" }] : /* istanbul ignore next */ []));
|
|
368
|
+
this.assistSelection = input('optional', /* @ts-ignore */
|
|
369
|
+
...(ngDevMode ? [{ debugName: "assistSelection" }] : /* istanbul ignore next */ []));
|
|
370
|
+
this.acceptExternalFileDrop = input(false, /* @ts-ignore */
|
|
371
|
+
...(ngDevMode ? [{ debugName: "acceptExternalFileDrop" }] : /* istanbul ignore next */ []));
|
|
340
372
|
this.entityId = input(undefined, /* @ts-ignore */
|
|
341
373
|
...(ngDevMode ? [{ debugName: "entityId" }] : /* istanbul ignore next */ []));
|
|
342
374
|
this.entityType = input(undefined, /* @ts-ignore */
|
|
343
375
|
...(ngDevMode ? [{ debugName: "entityType" }] : /* istanbul ignore next */ []));
|
|
344
376
|
this.sendStarterPromptsInPlace = input(false, /* @ts-ignore */
|
|
345
377
|
...(ngDevMode ? [{ debugName: "sendStarterPromptsInPlace" }] : /* istanbul ignore next */ []));
|
|
378
|
+
this.launchContext = input(undefined, /* @ts-ignore */
|
|
379
|
+
...(ngDevMode ? [{ debugName: "launchContext" }] : /* istanbul ignore next */ []));
|
|
346
380
|
this.compact = input(false, /* @ts-ignore */
|
|
347
381
|
...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
|
|
382
|
+
this.assistConversationCreated = input(undefined, /* @ts-ignore */
|
|
383
|
+
...(ngDevMode ? [{ debugName: "assistConversationCreated" }] : /* istanbul ignore next */ []));
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region ----- State Signals -----
|
|
386
|
+
this.localeProfile = toSignal(this.localeService.profileChanged$, {
|
|
387
|
+
initialValue: this.localeService.activeProfile(),
|
|
388
|
+
});
|
|
389
|
+
this.textDirection = computed(() => (this.localeProfile()?.i18nMeta?.rtl === true ? 'rtl' : 'ltr'), /* @ts-ignore */
|
|
390
|
+
...(ngDevMode ? [{ debugName: "textDirection" }] : /* istanbul ignore next */ []));
|
|
391
|
+
this.hasActiveConversation = computed(() => Boolean(this.conversationService.activeConversationId()?.trim()), /* @ts-ignore */
|
|
392
|
+
...(ngDevMode ? [{ debugName: "hasActiveConversation" }] : /* istanbul ignore next */ []));
|
|
348
393
|
this.rows = signal([], /* @ts-ignore */
|
|
349
394
|
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
350
395
|
this.loading = signal(true, /* @ts-ignore */
|
|
351
396
|
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
397
|
+
this.sending = signal(false, /* @ts-ignore */
|
|
398
|
+
...(ngDevMode ? [{ debugName: "sending" }] : /* istanbul ignore next */ []));
|
|
399
|
+
this.chipsLoading = signal(false, /* @ts-ignore */
|
|
400
|
+
...(ngDevMode ? [{ debugName: "chipsLoading" }] : /* istanbul ignore next */ []));
|
|
352
401
|
this.selectedAssistId = signal(undefined, /* @ts-ignore */
|
|
353
402
|
...(ngDevMode ? [{ debugName: "selectedAssistId" }] : /* istanbul ignore next */ []));
|
|
354
|
-
this.starterPromptItems = signal([], /* @ts-ignore */
|
|
355
|
-
...(ngDevMode ? [{ debugName: "starterPromptItems" }] : /* istanbul ignore next */ []));
|
|
356
403
|
this.draftText = signal('', /* @ts-ignore */
|
|
357
404
|
...(ngDevMode ? [{ debugName: "draftText" }] : /* istanbul ignore next */ []));
|
|
358
|
-
this.
|
|
359
|
-
...(ngDevMode ? [{ debugName: "
|
|
405
|
+
this.draftFiles = signal([], /* @ts-ignore */
|
|
406
|
+
...(ngDevMode ? [{ debugName: "draftFiles" }] : /* istanbul ignore next */ []));
|
|
407
|
+
this.starterPromptItems = signal([], /* @ts-ignore */
|
|
408
|
+
...(ngDevMode ? [{ debugName: "starterPromptItems" }] : /* istanbul ignore next */ []));
|
|
409
|
+
this.maxDraftFiles = MAX_EMPTY_DRAFT_FILES;
|
|
360
410
|
this.isBusy = computed(() => this.sending() || this.loading(), /* @ts-ignore */
|
|
361
411
|
...(ngDevMode ? [{ debugName: "isBusy" }] : /* istanbul ignore next */ []));
|
|
362
|
-
this.
|
|
363
|
-
...(ngDevMode ? [{ debugName: "
|
|
412
|
+
this.asksForAssist = computed(() => this.assistSelection() === 'ask' && !this.selectedAssistId(), /* @ts-ignore */
|
|
413
|
+
...(ngDevMode ? [{ debugName: "asksForAssist" }] : /* istanbul ignore next */ []));
|
|
414
|
+
this.canSend = computed(() => {
|
|
415
|
+
if (this.isBusy() || !this.hasDraftContent()) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
if (this.selectedAssistId()) {
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
return this.canResolveAssist();
|
|
422
|
+
}, /* @ts-ignore */
|
|
423
|
+
...(ngDevMode ? [{ debugName: "canSend" }] : /* istanbul ignore next */ []));
|
|
364
424
|
this.selectedAssistLabel = computed(() => {
|
|
365
425
|
const selected = this.rows().find((row) => row.id === this.selectedAssistId());
|
|
366
|
-
return selected?.title;
|
|
426
|
+
return this.translationService.resolve(selected?.title) ?? selected?.name ?? '';
|
|
367
427
|
}, /* @ts-ignore */
|
|
368
428
|
...(ngDevMode ? [{ debugName: "selectedAssistLabel" }] : /* istanbul ignore next */ []));
|
|
369
|
-
this.
|
|
370
|
-
|
|
429
|
+
this.draftPlaceholder = computed(() => {
|
|
430
|
+
if (this.asksForAssist()) {
|
|
431
|
+
return this.translationService.translateSync('@conversation:mini-chat.choose-assist.placeholder');
|
|
432
|
+
}
|
|
433
|
+
if (this.compact()) {
|
|
434
|
+
return this.translationService.translateSync('@conversation:mini-chat.composer.placeholder');
|
|
435
|
+
}
|
|
436
|
+
const assist = this.selectedAssistLabel();
|
|
437
|
+
return this.translationService.translateSync('@conversation:chat.empty-assist.placeholder', {
|
|
438
|
+
params: { assist },
|
|
439
|
+
});
|
|
440
|
+
}, /* @ts-ignore */
|
|
441
|
+
...(ngDevMode ? [{ debugName: "draftPlaceholder" }] : /* istanbul ignore next */ []));
|
|
371
442
|
this.assistsLoadPromise = null;
|
|
372
443
|
this.starterPromptsLoadGeneration = 0;
|
|
444
|
+
this.starterAbort = null;
|
|
445
|
+
this.askAssistCleared = false;
|
|
446
|
+
//#endregion
|
|
447
|
+
//#region ----- Event Handlers -----
|
|
448
|
+
this.onAssistConversationCreated = (conversationId) => {
|
|
449
|
+
const handler = this.assistConversationCreated();
|
|
450
|
+
if (handler) {
|
|
451
|
+
return handler(conversationId);
|
|
452
|
+
}
|
|
453
|
+
this.conversationCreated.emit(conversationId);
|
|
454
|
+
};
|
|
373
455
|
void this.ensureAssistsLoaded();
|
|
456
|
+
this.destroyRef.onDestroy(() => {
|
|
457
|
+
this.unregisterEmptyDraft?.();
|
|
458
|
+
this.starterAbort?.abort();
|
|
459
|
+
this.clearDraftFiles();
|
|
460
|
+
this.emptyAssistSession.closeAssistPicker();
|
|
461
|
+
});
|
|
374
462
|
effect(() => {
|
|
375
|
-
|
|
463
|
+
if (!this.acceptExternalFileDrop()) {
|
|
464
|
+
this.unregisterEmptyDraft?.();
|
|
465
|
+
this.unregisterEmptyDraft = null;
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (this.unregisterEmptyDraft) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
this.unregisterEmptyDraft = this.fileDrop.registerEmptyDraftAdder((files) => this.addDraftFiles(files));
|
|
472
|
+
});
|
|
473
|
+
// Header inbox (`ask`) must not inherit a leftover assist from another surface.
|
|
474
|
+
// Drop that leftover once. A Global AI Settings default, or a later pick, must stick.
|
|
475
|
+
effect(() => {
|
|
476
|
+
const mode = this.assistSelection();
|
|
477
|
+
if (mode !== 'ask') {
|
|
478
|
+
this.askAssistCleared = false;
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (this.askAssistCleared) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
this.askAssistCleared = true;
|
|
485
|
+
this.emptyAssistSession.setSelectedAssistId(this.selectedAssistId()?.trim());
|
|
486
|
+
});
|
|
487
|
+
effect(() => {
|
|
488
|
+
if (this.assistSelection() !== 'locked' || this.loading()) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const requestedId = this.initialAssistId()?.trim();
|
|
492
|
+
if (!requestedId || !this.rows().some((row) => row.id === requestedId)) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (this.selectedAssistId() !== requestedId) {
|
|
496
|
+
this.selectedAssistId.set(requestedId);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
effect(() => {
|
|
500
|
+
const sessionAssistId = this.emptyAssistSession.selectedAssistId();
|
|
501
|
+
if (this.assistSelection() === 'ask' && !sessionAssistId) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (sessionAssistId && sessionAssistId !== this.selectedAssistId()) {
|
|
505
|
+
this.selectedAssistId.set(sessionAssistId);
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
effect(() => {
|
|
509
|
+
this.emptyAssistSession.bind({
|
|
510
|
+
selectedAssistId: this.selectedAssistId(),
|
|
511
|
+
rows: this.rows(),
|
|
512
|
+
entityId: this.entityId(),
|
|
513
|
+
entityType: this.entityType(),
|
|
514
|
+
launchContext: this.launchContext(),
|
|
515
|
+
assistSelection: this.assistSelection(),
|
|
516
|
+
});
|
|
376
517
|
});
|
|
377
518
|
effect(() => {
|
|
378
519
|
this.draftText();
|
|
379
520
|
queueMicrotask(() => this.resizeDraftInput());
|
|
380
521
|
});
|
|
522
|
+
effect(() => {
|
|
523
|
+
const assistId = this.selectedAssistId();
|
|
524
|
+
const launchContext = this.launchContext();
|
|
525
|
+
if (launchContext) {
|
|
526
|
+
void this.loadContextualChips(assistId, launchContext);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
void this.loadStarterPromptsForAssist(assistId);
|
|
530
|
+
});
|
|
381
531
|
}
|
|
382
|
-
|
|
383
|
-
|
|
532
|
+
draftFileIcon(kind) {
|
|
533
|
+
return DRAFT_KIND_ICONS[kind];
|
|
384
534
|
}
|
|
385
|
-
|
|
386
|
-
|
|
535
|
+
browseDraftFiles() {
|
|
536
|
+
this.fileInput()?.nativeElement.click();
|
|
537
|
+
}
|
|
538
|
+
onDraftFilesSelected(event) {
|
|
539
|
+
const input = event.target;
|
|
540
|
+
if (!(input instanceof HTMLInputElement)) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const selected = Array.from(input.files ?? []);
|
|
544
|
+
input.value = '';
|
|
545
|
+
this.addDraftFiles(selected);
|
|
546
|
+
}
|
|
547
|
+
addDraftFiles(files) {
|
|
548
|
+
if (files.length === 0 || this.isBusy()) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const remaining = Math.max(0, MAX_EMPTY_DRAFT_FILES - this.draftFiles().length);
|
|
552
|
+
const accepted = files.slice(0, remaining);
|
|
553
|
+
if (accepted.length === 0) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
this.draftFiles.update((current) => [...current, ...accepted.map((file) => this.toDraftFile(file))]);
|
|
557
|
+
}
|
|
558
|
+
removeDraftFile(id) {
|
|
559
|
+
const current = this.draftFiles();
|
|
560
|
+
const next = current.filter((item) => item.id !== id);
|
|
561
|
+
current.filter((item) => item.id === id).forEach((item) => this.revokePreview(item.preview));
|
|
562
|
+
this.draftFiles.set(next);
|
|
387
563
|
}
|
|
388
564
|
resizeDraftInput() {
|
|
389
565
|
const textarea = this.draftInput()?.nativeElement;
|
|
390
|
-
if (!textarea)
|
|
566
|
+
if (!textarea) {
|
|
391
567
|
return;
|
|
568
|
+
}
|
|
392
569
|
textarea.style.height = '0px';
|
|
393
|
-
textarea.style.height = `${Math.min(textarea.scrollHeight, this.
|
|
570
|
+
textarea.style.height = `${Math.min(textarea.scrollHeight, this.compact() ? 128 : 224)}px`;
|
|
394
571
|
}
|
|
395
572
|
onDraftKeydown(event) {
|
|
396
|
-
if (event.key !== 'Enter' || event.shiftKey || event.isComposing)
|
|
573
|
+
if (event.key !== 'Enter' || event.shiftKey || event.isComposing) {
|
|
397
574
|
return;
|
|
575
|
+
}
|
|
398
576
|
event.preventDefault();
|
|
399
|
-
if (this.canSend())
|
|
577
|
+
if (this.canSend()) {
|
|
400
578
|
void this.send();
|
|
579
|
+
}
|
|
401
580
|
}
|
|
402
581
|
async send() {
|
|
403
|
-
|
|
404
|
-
const text = this.draftText().trim();
|
|
405
|
-
if (!assistId || !text || this.sending())
|
|
582
|
+
if (!this.canSend()) {
|
|
406
583
|
return;
|
|
407
|
-
|
|
408
|
-
|
|
584
|
+
}
|
|
585
|
+
const assistId = await this.ensureSelectedAssist();
|
|
586
|
+
if (!assistId) {
|
|
409
587
|
return;
|
|
588
|
+
}
|
|
589
|
+
const text = this.draftText();
|
|
590
|
+
const files = this.draftFiles().map((item) => item.file);
|
|
410
591
|
this.sending.set(true);
|
|
411
|
-
this.layoutTheme.setOverlayLoading(true);
|
|
412
592
|
try {
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const assistSnapshot = assistRow ? this.assistCatalog.toSnapshot(assistRow) : undefined;
|
|
419
|
-
const conversation = await this.conversationService.createConversation([participantId], 'bot', {
|
|
420
|
-
title: this.translationService.resolve(row.title) ?? row.name,
|
|
421
|
-
...(avatar ? { avatar } : {}),
|
|
422
|
-
icon: 'fa-solid fa-robot',
|
|
423
|
-
metadata: {
|
|
424
|
-
...axmBuildAiChatConversationMetadata(row, assistSnapshot),
|
|
425
|
-
...(entityId && entityType ? { entityId, entityType } : {}),
|
|
426
|
-
},
|
|
427
|
-
});
|
|
428
|
-
await this.conversationService.selectConversation(conversation.id);
|
|
429
|
-
const payload = { type: 'text', text };
|
|
430
|
-
await this.conversationService.sendMessage({ conversationId: conversation.id, type: 'text', payload });
|
|
431
|
-
this.draftText.set('');
|
|
432
|
-
this.conversationCreated.emit(conversation.id);
|
|
433
|
-
}
|
|
434
|
-
catch {
|
|
435
|
-
const message = await this.translationService.translateAsync('@conversation:chat.empty-assist.errors.send');
|
|
436
|
-
this.toastService.danger(message);
|
|
593
|
+
const conversationId = await this.emptyAssistSession.sendWelcome(text, files, this.onAssistConversationCreated);
|
|
594
|
+
if (conversationId) {
|
|
595
|
+
this.draftText.set('');
|
|
596
|
+
this.clearDraftFiles();
|
|
597
|
+
}
|
|
437
598
|
}
|
|
438
599
|
finally {
|
|
439
600
|
this.sending.set(false);
|
|
440
|
-
this.layoutTheme.setOverlayLoading(false);
|
|
441
601
|
}
|
|
442
602
|
}
|
|
603
|
+
//#endregion
|
|
604
|
+
//#region ----- Draft files -----
|
|
605
|
+
toDraftFile(file) {
|
|
606
|
+
const kind = this.classifyDraftFile(file);
|
|
607
|
+
return {
|
|
608
|
+
id: globalThis.crypto?.randomUUID?.() ?? `${file.name}-${file.size}-${Date.now()}`,
|
|
609
|
+
file,
|
|
610
|
+
kind,
|
|
611
|
+
preview: kind === 'image' || kind === 'video' ? URL.createObjectURL(file) : undefined,
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
classifyDraftFile(file) {
|
|
615
|
+
const type = file.type.toLowerCase();
|
|
616
|
+
if (type.startsWith('image/')) {
|
|
617
|
+
return 'image';
|
|
618
|
+
}
|
|
619
|
+
if (type.startsWith('video/')) {
|
|
620
|
+
return 'video';
|
|
621
|
+
}
|
|
622
|
+
if (type.startsWith('audio/')) {
|
|
623
|
+
return 'audio';
|
|
624
|
+
}
|
|
625
|
+
return 'file';
|
|
626
|
+
}
|
|
627
|
+
clearDraftFiles() {
|
|
628
|
+
this.draftFiles().forEach((item) => this.revokePreview(item.preview));
|
|
629
|
+
this.draftFiles.set([]);
|
|
630
|
+
}
|
|
631
|
+
revokePreview(preview) {
|
|
632
|
+
if (preview) {
|
|
633
|
+
URL.revokeObjectURL(preview);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
//#endregion
|
|
637
|
+
//#region ----- Data Loading -----
|
|
443
638
|
async ensureAssistsLoaded() {
|
|
444
639
|
if (!this.assistsLoadPromise)
|
|
445
640
|
this.assistsLoadPromise = this.loadAssistsFromApi();
|
|
@@ -453,7 +648,7 @@ class AXMChatEmptyAssistComposerComponent {
|
|
|
453
648
|
rows = await this.assistCatalog.loadCatalogTargets(true);
|
|
454
649
|
}
|
|
455
650
|
this.rows.set(rows);
|
|
456
|
-
this.selectedAssistId.set(await this.
|
|
651
|
+
this.selectedAssistId.set(await this.resolveAssistIdForMode(rows));
|
|
457
652
|
}
|
|
458
653
|
catch (error) {
|
|
459
654
|
console.error('Failed to load AI chat targets (empty composer):', error);
|
|
@@ -466,17 +661,99 @@ class AXMChatEmptyAssistComposerComponent {
|
|
|
466
661
|
this.loading.set(false);
|
|
467
662
|
}
|
|
468
663
|
}
|
|
469
|
-
|
|
470
|
-
|
|
664
|
+
hasDraftContent() {
|
|
665
|
+
return this.draftText().trim().length > 0 || this.draftFiles().length > 0;
|
|
666
|
+
}
|
|
667
|
+
canResolveAssist() {
|
|
668
|
+
if (this.assistSelection() === 'ask') {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
const rows = this.rows();
|
|
672
|
+
if (this.assistSelection() === 'locked') {
|
|
673
|
+
const requestedId = this.initialAssistId()?.trim();
|
|
674
|
+
return !!requestedId && rows.some((row) => row.id === requestedId);
|
|
675
|
+
}
|
|
676
|
+
return rows.length > 0;
|
|
677
|
+
}
|
|
678
|
+
async ensureSelectedAssist() {
|
|
679
|
+
const current = this.selectedAssistId()?.trim();
|
|
680
|
+
if (current) {
|
|
681
|
+
this.emptyAssistSession.setSelectedAssistId(current);
|
|
682
|
+
return current;
|
|
683
|
+
}
|
|
684
|
+
const assistId = await this.resolveAssistIdForMode(this.rows());
|
|
685
|
+
if (!assistId) {
|
|
471
686
|
return undefined;
|
|
687
|
+
}
|
|
688
|
+
this.selectedAssistId.set(assistId);
|
|
689
|
+
this.emptyAssistSession.setSelectedAssistId(assistId);
|
|
690
|
+
return assistId;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Header (`ask`) uses Global AI Settings → Default Assist.
|
|
694
|
+
* Form designer (`locked`) uses the assist id passed in (Form Designer → Default Assist).
|
|
695
|
+
*/
|
|
696
|
+
async resolveAssistIdForMode(rows) {
|
|
472
697
|
const requestedId = this.initialAssistId()?.trim();
|
|
473
|
-
|
|
474
|
-
|
|
698
|
+
const mode = this.assistSelection();
|
|
699
|
+
if (mode === 'locked') {
|
|
700
|
+
return requestedId ? this.includeAssistRow(rows, requestedId) : undefined;
|
|
701
|
+
}
|
|
702
|
+
if (requestedId) {
|
|
703
|
+
const matched = await this.includeAssistRow(rows, requestedId);
|
|
704
|
+
if (matched) {
|
|
705
|
+
return matched;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (mode === 'ask') {
|
|
709
|
+
const defaultAssistId = await this.resolveDefaultAssistId();
|
|
710
|
+
return defaultAssistId ? this.includeAssistRow(rows, defaultAssistId) : undefined;
|
|
711
|
+
}
|
|
712
|
+
if (!rows.length) {
|
|
713
|
+
return undefined;
|
|
714
|
+
}
|
|
475
715
|
const defaultAssistId = await this.resolveDefaultAssistId();
|
|
476
|
-
if (defaultAssistId
|
|
477
|
-
|
|
716
|
+
if (defaultAssistId) {
|
|
717
|
+
const matched = await this.includeAssistRow(rows, defaultAssistId);
|
|
718
|
+
if (matched) {
|
|
719
|
+
return matched;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
478
722
|
return rows[0]?.id;
|
|
479
723
|
}
|
|
724
|
+
/** Keeps a settings assist selectable even when it is outside the first catalog page. */
|
|
725
|
+
async includeAssistRow(rows, assistId) {
|
|
726
|
+
const id = assistId.trim();
|
|
727
|
+
if (!id) {
|
|
728
|
+
return undefined;
|
|
729
|
+
}
|
|
730
|
+
if (rows.some((row) => row.id === id) || this.rows().some((row) => row.id === id)) {
|
|
731
|
+
return id;
|
|
732
|
+
}
|
|
733
|
+
try {
|
|
734
|
+
const assist = await this.assistCatalog.getAssist(id);
|
|
735
|
+
const resolvedId = assist?.id?.trim();
|
|
736
|
+
if (!assist || !resolvedId) {
|
|
737
|
+
return undefined;
|
|
738
|
+
}
|
|
739
|
+
if (!this.rows().some((row) => row.id === resolvedId)) {
|
|
740
|
+
this.rows.update((current) => [
|
|
741
|
+
...current,
|
|
742
|
+
{
|
|
743
|
+
id: resolvedId,
|
|
744
|
+
name: String(assist.name ?? ''),
|
|
745
|
+
title: assist.title ?? assist.name ?? resolvedId,
|
|
746
|
+
description: assist.description,
|
|
747
|
+
professionImageUrl: assist.professionImageUrl,
|
|
748
|
+
},
|
|
749
|
+
]);
|
|
750
|
+
}
|
|
751
|
+
return resolvedId;
|
|
752
|
+
}
|
|
753
|
+
catch {
|
|
754
|
+
return undefined;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
480
757
|
async resolveDefaultAssistId() {
|
|
481
758
|
if (!this.defaultAssistResolver)
|
|
482
759
|
return undefined;
|
|
@@ -488,6 +765,8 @@ class AXMChatEmptyAssistComposerComponent {
|
|
|
488
765
|
}
|
|
489
766
|
}
|
|
490
767
|
async loadStarterPromptsForAssist(assistId) {
|
|
768
|
+
this.starterAbort?.abort();
|
|
769
|
+
this.chipsLoading.set(false);
|
|
491
770
|
const generation = ++this.starterPromptsLoadGeneration;
|
|
492
771
|
const id = assistId?.trim();
|
|
493
772
|
if (!id) {
|
|
@@ -502,14 +781,15 @@ class AXMChatEmptyAssistComposerComponent {
|
|
|
502
781
|
}
|
|
503
782
|
return;
|
|
504
783
|
}
|
|
505
|
-
const
|
|
506
|
-
const
|
|
507
|
-
const isEntityChat = Boolean(entityId && entityType);
|
|
784
|
+
const entityRef = this.resolveEntityChatRef();
|
|
785
|
+
const isEntityChat = Boolean(entityRef);
|
|
508
786
|
const sendInPlace = this.sendStarterPromptsInPlace();
|
|
787
|
+
const launchContext = this.launchContext();
|
|
509
788
|
this.starterPromptItems.set(axmAssistStarterPromptChipItems(assist, {
|
|
510
789
|
assistId: id,
|
|
511
|
-
...(
|
|
790
|
+
...(entityRef ? { entityId: entityRef.entityId, entityType: entityRef.entityType } : {}),
|
|
512
791
|
...(sendInPlace || isEntityChat ? { navigate: false } : {}),
|
|
792
|
+
...(launchContext ? { launchContext } : {}),
|
|
513
793
|
}));
|
|
514
794
|
}
|
|
515
795
|
catch {
|
|
@@ -517,8 +797,76 @@ class AXMChatEmptyAssistComposerComponent {
|
|
|
517
797
|
this.starterPromptItems.set([]);
|
|
518
798
|
}
|
|
519
799
|
}
|
|
800
|
+
async loadContextualChips(assistId, launchContext) {
|
|
801
|
+
const id = assistId?.trim();
|
|
802
|
+
if (!id) {
|
|
803
|
+
this.starterPromptItems.set([]);
|
|
804
|
+
this.chipsLoading.set(false);
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
this.starterAbort?.abort();
|
|
808
|
+
const abort = new AbortController();
|
|
809
|
+
this.starterAbort = abort;
|
|
810
|
+
const generation = ++this.starterPromptsLoadGeneration;
|
|
811
|
+
this.chipsLoading.set(true);
|
|
812
|
+
try {
|
|
813
|
+
const locale = this.localeService.activeProfile()?.localeInfo?.code ?? 'en-US';
|
|
814
|
+
const context = axmSanitizeContextualAssistContext(launchContext);
|
|
815
|
+
const result = await this.commandService.execute(AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY, {
|
|
816
|
+
assistId: id,
|
|
817
|
+
messages: [axpAiChatTextMessage('system', AXM_CONTEXTUAL_ASSIST_STARTER_SYSTEM_PROMPT), axpAiChatTextMessage('user', axmBuildContextualAssistStarterUserPrompt(context, locale))],
|
|
818
|
+
maxTokens: 512,
|
|
819
|
+
temperature: 0.3,
|
|
820
|
+
});
|
|
821
|
+
if (abort.signal.aborted || generation !== this.starterPromptsLoadGeneration) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
const data = runtimeCommandPayloadData(result);
|
|
825
|
+
const items = axmParseContextualAssistStarterItems(data?.text ?? '');
|
|
826
|
+
const labels = items.length > 0 ? items : await this.fallbackChipLabels();
|
|
827
|
+
this.starterPromptItems.set(this.toInPlaceChipItems(labels, id, context));
|
|
828
|
+
}
|
|
829
|
+
catch {
|
|
830
|
+
if (!abort.signal.aborted && generation === this.starterPromptsLoadGeneration) {
|
|
831
|
+
const labels = await this.fallbackChipLabels();
|
|
832
|
+
this.starterPromptItems.set(this.toInPlaceChipItems(labels, id, axmSanitizeContextualAssistContext(launchContext)));
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
finally {
|
|
836
|
+
if (!abort.signal.aborted && generation === this.starterPromptsLoadGeneration) {
|
|
837
|
+
this.chipsLoading.set(false);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
toInPlaceChipItems(labels, assistId, launchContext) {
|
|
842
|
+
const entityRef = this.resolveEntityChatRef();
|
|
843
|
+
return axmAssistStarterPromptChipItems({ starterPrompts: labels.map((text) => ({ text })) }, {
|
|
844
|
+
assistId,
|
|
845
|
+
navigate: false,
|
|
846
|
+
launchContext,
|
|
847
|
+
...(entityRef ? { entityId: entityRef.entityId, entityType: entityRef.entityType } : {}),
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
resolveEntityChatRef() {
|
|
851
|
+
const entityId = this.entityId()?.trim();
|
|
852
|
+
const entityType = this.entityType()?.trim();
|
|
853
|
+
if (entityId && entityType) {
|
|
854
|
+
return { entityId, entityType };
|
|
855
|
+
}
|
|
856
|
+
return axmEntityRefFromLaunchContext(this.launchContext());
|
|
857
|
+
}
|
|
858
|
+
async fallbackChipLabels() {
|
|
859
|
+
const labels = [];
|
|
860
|
+
for (const key of FALLBACK_CHIP_KEYS) {
|
|
861
|
+
const text = (await this.translationService.translateAsync(key))?.trim();
|
|
862
|
+
if (text) {
|
|
863
|
+
labels.push(text);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return labels;
|
|
867
|
+
}
|
|
520
868
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMChatEmptyAssistComposerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
521
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMChatEmptyAssistComposerComponent, isStandalone: true, selector: "axm-chat-empty-assist-composer", inputs: { initialAssistId: { classPropertyName: "initialAssistId", publicName: "initialAssistId", isSignal: true, isRequired: false, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: false, transformFunction: null }, entityType: { classPropertyName: "entityType", publicName: "entityType", isSignal: true, isRequired: false, transformFunction: null }, sendStarterPromptsInPlace: { classPropertyName: "sendStarterPromptsInPlace", publicName: "sendStarterPromptsInPlace", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { conversationCreated: "conversationCreated" }, host: { properties: { "class.axm-chat-empty-assist-composer-host--compact": "compact()", "attr.dir": "textDirection()", "style.direction": "textDirection()" }, classAttribute: "axm-chat-empty-assist-composer-host" }, viewQueries: [{ propertyName: "draftInput", first: true, predicate: ["draftInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
869
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMChatEmptyAssistComposerComponent, isStandalone: true, selector: "axm-chat-empty-assist-composer", inputs: { initialAssistId: { classPropertyName: "initialAssistId", publicName: "initialAssistId", isSignal: true, isRequired: false, transformFunction: null }, assistSelection: { classPropertyName: "assistSelection", publicName: "assistSelection", isSignal: true, isRequired: false, transformFunction: null }, acceptExternalFileDrop: { classPropertyName: "acceptExternalFileDrop", publicName: "acceptExternalFileDrop", isSignal: true, isRequired: false, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: false, transformFunction: null }, entityType: { classPropertyName: "entityType", publicName: "entityType", isSignal: true, isRequired: false, transformFunction: null }, sendStarterPromptsInPlace: { classPropertyName: "sendStarterPromptsInPlace", publicName: "sendStarterPromptsInPlace", isSignal: true, isRequired: false, transformFunction: null }, launchContext: { classPropertyName: "launchContext", publicName: "launchContext", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, assistConversationCreated: { classPropertyName: "assistConversationCreated", publicName: "assistConversationCreated", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { conversationCreated: "conversationCreated" }, host: { properties: { "class.axm-chat-empty-assist-composer-host--compact": "compact()", "attr.dir": "textDirection()", "style.direction": "textDirection()" }, classAttribute: "axm-chat-empty-assist-composer-host" }, viewQueries: [{ propertyName: "draftInput", first: true, predicate: ["draftInput"], descendants: true, isSignal: true }, { propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
522
870
|
<div class="axm-chat-empty-assist-composer">
|
|
523
871
|
<div class="axm-chat-empty-assist-composer__hero">
|
|
524
872
|
@if (compact()) {
|
|
@@ -527,92 +875,173 @@ class AXMChatEmptyAssistComposerComponent {
|
|
|
527
875
|
</span>
|
|
528
876
|
}
|
|
529
877
|
<div class="axm-chat-empty-assist-composer__caption">
|
|
530
|
-
|
|
878
|
+
@if (asksForAssist()) {
|
|
879
|
+
{{ '@conversation:mini-chat.choose-assist.title' | translate | async }}
|
|
880
|
+
}
|
|
881
|
+
<!-- ----- Default welcome when an assist is already chosen or selection is optional ----- -->
|
|
882
|
+
@else {
|
|
883
|
+
{{ (compact() ? '@conversation:mini-chat.empty.title' : '@conversation:chat.empty-assist.caption') | translate | async }}
|
|
884
|
+
}
|
|
531
885
|
</div>
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
<ax-button color="default" look="blank" class="rounded-full" [disabled]="isBusy()">
|
|
537
|
-
<ax-icon icon="fa-regular fa-sparkles"></ax-icon>
|
|
538
|
-
<span class="axm-chat-empty-assist-composer__assist-text">
|
|
539
|
-
@if (selectedAssistLabel(); as assistLabel) {
|
|
540
|
-
{{ assistLabel | translate | async }}
|
|
541
|
-
} @else {
|
|
542
|
-
{{ '@conversation:chat.empty-assist.assist-default' | translate | async }}
|
|
543
|
-
}
|
|
544
|
-
</span>
|
|
545
|
-
@if (!isBusy()) {
|
|
546
|
-
<ax-dropdown-panel>
|
|
547
|
-
<ax-button-item-list>
|
|
548
|
-
@for (row of rows(); track row.id) {
|
|
549
|
-
<ax-button-item [text]="(row.title | translate | async)!" [selected]="row.id === selectedAssistId()" (onClick)="onAssistIdChange(row.id)"></ax-button-item>
|
|
550
|
-
}
|
|
551
|
-
</ax-button-item-list>
|
|
552
|
-
</ax-dropdown-panel>
|
|
553
|
-
}
|
|
554
|
-
</ax-button>
|
|
555
|
-
} @else {
|
|
556
|
-
<ax-button
|
|
557
|
-
color="default"
|
|
558
|
-
look="blank"
|
|
559
|
-
class="axm-chat-empty-assist-composer__assist-trigger rounded-full"
|
|
560
|
-
[iconOnly]="true"
|
|
561
|
-
[disabled]="isBusy()"
|
|
562
|
-
[attr.aria-label]="('@conversation:chat.empty-assist.assist-default' | translate | async) ?? ''"
|
|
563
|
-
>
|
|
564
|
-
<ax-icon icon="fa-regular fa-sparkles"></ax-icon>
|
|
565
|
-
@if (!isBusy()) {
|
|
566
|
-
<ax-dropdown-panel>
|
|
567
|
-
<ax-button-item-list>
|
|
568
|
-
@for (row of rows(); track row.id) {
|
|
569
|
-
<ax-button-item [text]="(row.title | translate | async)!" [selected]="row.id === selectedAssistId()" (onClick)="onAssistIdChange(row.id)"></ax-button-item>
|
|
570
|
-
}
|
|
571
|
-
</ax-button-item-list>
|
|
572
|
-
</ax-dropdown-panel>
|
|
573
|
-
}
|
|
574
|
-
</ax-button>
|
|
886
|
+
@if (asksForAssist()) {
|
|
887
|
+
<p class="axm-chat-empty-assist-composer__subtitle">
|
|
888
|
+
{{ '@conversation:mini-chat.choose-assist.subtitle' | translate | async }}
|
|
889
|
+
</p>
|
|
575
890
|
}
|
|
891
|
+
<!-- ----- Compact welcome subtitle when the header is not waiting for an assist ----- -->
|
|
892
|
+
@else if (compact()) {
|
|
893
|
+
<p class="axm-chat-empty-assist-composer__subtitle">
|
|
894
|
+
{{ '@conversation:mini-chat.empty.subtitle' | translate | async }}
|
|
895
|
+
</p>
|
|
896
|
+
}
|
|
897
|
+
</div>
|
|
576
898
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
<
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
899
|
+
<!-- ----- Lookalike composer: attach and type stay local until send ----- -->
|
|
900
|
+
@if (!hasActiveConversation()) {
|
|
901
|
+
<div class="axm-chat-empty-assist-composer__composer">
|
|
902
|
+
<!---->
|
|
903
|
+
<!-- ----- Local attachment chips before the first message is sent ----- -->
|
|
904
|
+
@if (draftFiles().length > 0) {
|
|
905
|
+
<div class="axm-chat-empty-assist-composer__attachments">
|
|
906
|
+
<div class="axm-chat-empty-assist-composer__attachments-scroll" role="list">
|
|
907
|
+
@for (attachment of draftFiles(); track attachment.id) {
|
|
908
|
+
<div
|
|
909
|
+
class="axm-chat-empty-assist-composer__attachment"
|
|
910
|
+
role="listitem"
|
|
911
|
+
[class.axm-chat-empty-assist-composer__attachment--media]="attachment.kind === 'image' || attachment.kind === 'video'"
|
|
912
|
+
[class.axm-chat-empty-assist-composer__attachment--file]="attachment.kind === 'audio' || attachment.kind === 'file'"
|
|
913
|
+
[title]="attachment.file.name"
|
|
914
|
+
>
|
|
915
|
+
<!---->
|
|
916
|
+
<!-- ----- Image thumbnail ----- -->
|
|
917
|
+
@if (attachment.kind === 'image' && attachment.preview) {
|
|
918
|
+
<span class="axm-chat-empty-assist-composer__attachment-thumb" aria-hidden="true">
|
|
919
|
+
<img [src]="attachment.preview" alt="" />
|
|
920
|
+
</span>
|
|
921
|
+
}
|
|
922
|
+
<!-- ----- Video thumbnail ----- -->
|
|
923
|
+
@else if (attachment.kind === 'video' && attachment.preview) {
|
|
924
|
+
<span class="axm-chat-empty-assist-composer__attachment-thumb" aria-hidden="true">
|
|
925
|
+
<video [src]="attachment.preview" muted playsinline preload="metadata"></video>
|
|
926
|
+
</span>
|
|
927
|
+
}
|
|
928
|
+
<!-- ----- File name fallback ----- -->
|
|
929
|
+
@else {
|
|
930
|
+
<span class="axm-chat-empty-assist-composer__attachment-icon" aria-hidden="true">
|
|
931
|
+
<i [class]="draftFileIcon(attachment.kind)"></i>
|
|
932
|
+
</span>
|
|
933
|
+
<span class="axm-chat-empty-assist-composer__attachment-name">{{ attachment.file.name }}</span>
|
|
934
|
+
}
|
|
935
|
+
<button
|
|
936
|
+
type="button"
|
|
937
|
+
class="axm-chat-empty-assist-composer__attachment-remove"
|
|
938
|
+
[attr.aria-label]="('@acorex:chat.actions.remove-attachment' | translate | async) ?? ''"
|
|
939
|
+
(click)="removeDraftFile(attachment.id); $event.stopPropagation()"
|
|
940
|
+
>
|
|
941
|
+
<i class="fa-solid fa-xmark"></i>
|
|
942
|
+
</button>
|
|
943
|
+
</div>
|
|
944
|
+
}
|
|
945
|
+
<ax-button
|
|
946
|
+
class="axm-chat-empty-assist-composer__attachment-add ax-sm rounded-full"
|
|
947
|
+
look="blank"
|
|
948
|
+
[iconOnly]="true"
|
|
949
|
+
[disabled]="isBusy() || draftFiles().length >= maxDraftFiles"
|
|
950
|
+
[text]="('@acorex:chat.pickers.common.add-more' | translate | async) ?? ''"
|
|
951
|
+
(onClick)="browseDraftFiles()"
|
|
952
|
+
>
|
|
953
|
+
<ax-prefix>
|
|
954
|
+
<i class="fa-light fa-plus"></i>
|
|
955
|
+
</ax-prefix>
|
|
956
|
+
</ax-button>
|
|
957
|
+
</div>
|
|
958
|
+
</div>
|
|
600
959
|
}
|
|
601
|
-
|
|
602
|
-
|
|
960
|
+
<div class="axm-chat-empty-assist-composer__input-row">
|
|
961
|
+
<div class="axm-chat-empty-assist-composer__actions-start">
|
|
962
|
+
<ax-button
|
|
963
|
+
class="rounded-full text-xl"
|
|
964
|
+
look="blank"
|
|
965
|
+
[iconOnly]="true"
|
|
966
|
+
[disabled]="isBusy() || draftFiles().length >= maxDraftFiles"
|
|
967
|
+
[text]="('@acorex:chat.tooltips.attach-file' | translate | async) ?? ''"
|
|
968
|
+
(onClick)="browseDraftFiles()"
|
|
969
|
+
>
|
|
970
|
+
<ax-prefix>
|
|
971
|
+
<i class="fa-light fa-paperclip"></i>
|
|
972
|
+
</ax-prefix>
|
|
973
|
+
</ax-button>
|
|
974
|
+
@if (assistSelection() !== 'locked') {
|
|
975
|
+
<ax-button class="rounded-full axm-chat-composer-assist-picker" look="blank" [iconOnly]="true" [disabled]="isBusy() || rows().length === 0" [text]="('@conversation:chat.empty-assist.assist-default' | translate | async) ?? ''">
|
|
976
|
+
<ax-prefix>
|
|
977
|
+
<i class="fa-light fa-sparkles"></i>
|
|
978
|
+
</ax-prefix>
|
|
979
|
+
<!---->
|
|
980
|
+
<!-- ----- Assist list as a dropdown, not a popup ----- -->
|
|
981
|
+
@if (rows().length > 0) {
|
|
982
|
+
<ax-dropdown-panel>
|
|
983
|
+
<axm-chat-composer-assist-picker />
|
|
984
|
+
</ax-dropdown-panel>
|
|
985
|
+
}
|
|
986
|
+
</ax-button>
|
|
987
|
+
}
|
|
988
|
+
</div>
|
|
989
|
+
<textarea
|
|
990
|
+
#draftInput
|
|
991
|
+
rows="1"
|
|
992
|
+
class="axm-chat-empty-assist-composer__textarea"
|
|
993
|
+
[ngModel]="draftText()"
|
|
994
|
+
(ngModelChange)="draftText.set($event ?? '')"
|
|
995
|
+
(input)="resizeDraftInput()"
|
|
996
|
+
(keydown)="onDraftKeydown($event)"
|
|
997
|
+
[disabled]="isBusy()"
|
|
998
|
+
[placeholder]="draftPlaceholder()"
|
|
999
|
+
></textarea>
|
|
1000
|
+
<div class="axm-chat-empty-assist-composer__primary">
|
|
1001
|
+
<ax-button
|
|
1002
|
+
class="rounded-full"
|
|
1003
|
+
[class.composer-primary-button--send]="canSend()"
|
|
1004
|
+
look="blank"
|
|
1005
|
+
color="primary"
|
|
1006
|
+
[iconOnly]="true"
|
|
1007
|
+
[disabled]="!canSend()"
|
|
1008
|
+
[text]="('@acorex:chat.actions.send' | translate | async) ?? ''"
|
|
1009
|
+
(onClick)="send()"
|
|
1010
|
+
>
|
|
1011
|
+
<ax-prefix>
|
|
1012
|
+
<i class="fa-solid fa-paper-plane-top"></i>
|
|
1013
|
+
</ax-prefix>
|
|
1014
|
+
</ax-button>
|
|
1015
|
+
</div>
|
|
1016
|
+
</div>
|
|
1017
|
+
<input #fileInput class="axm-chat-empty-assist-composer__file-input" type="file" multiple (change)="onDraftFilesSelected($event)" />
|
|
1018
|
+
</div>
|
|
1019
|
+
}
|
|
603
1020
|
|
|
604
|
-
|
|
1021
|
+
<!-- ----- Starter chips loading indicator ----- -->
|
|
1022
|
+
@if (chipsLoading()) {
|
|
1023
|
+
<div class="axm-chat-empty-assist-composer__chips-loading">
|
|
1024
|
+
<ax-loading></ax-loading>
|
|
1025
|
+
<p class="axm-chat-empty-assist-composer__suggestions-label">
|
|
1026
|
+
{{ '@conversation:chat.contextual-assist.chips-loading' | translate | async }}
|
|
1027
|
+
</p>
|
|
1028
|
+
</div>
|
|
1029
|
+
}
|
|
1030
|
+
<!-- ----- Starter suggestion chips ----- -->
|
|
1031
|
+
@else if (starterPromptItems().length > 0) {
|
|
605
1032
|
<div class="axm-chat-empty-assist-composer__suggestions">
|
|
1033
|
+
<!---->
|
|
1034
|
+
<!-- ----- Compact starter section label ----- -->
|
|
606
1035
|
@if (compact()) {
|
|
607
1036
|
<p class="axm-chat-empty-assist-composer__suggestions-label">
|
|
608
|
-
{{ '@conversation:chat.
|
|
1037
|
+
{{ '@conversation:mini-chat.try-asking' | translate | async }}
|
|
609
1038
|
</p>
|
|
610
1039
|
}
|
|
611
|
-
<axm-assist-suggestion-chips [items]="starterPromptItems()" [compact]="compact()" [sendInPlace]="sendStarterPromptsInPlace()" [disabled]="
|
|
1040
|
+
<axm-assist-suggestion-chips [items]="starterPromptItems()" [compact]="compact()" [sendInPlace]="sendStarterPromptsInPlace()" [disabled]="loading()" (conversationCreated)="conversationCreated.emit($event)" />
|
|
612
1041
|
</div>
|
|
613
1042
|
}
|
|
614
1043
|
</div>
|
|
615
|
-
`, isInline: true, styles: [":host{display:block;width:100%}.axm-chat-empty-assist-composer{display:flex;flex-direction:column;gap:1rem;width:min(100%,64rem);margin-inline:auto}.axm-chat-empty-assist-composer__hero{display:flex;flex-direction:column;align-items:center;gap:.625rem}.axm-chat-empty-assist-composer__hero-icon{display:grid;place-items:center;width:2.5rem;height:2.5rem;border-radius:.875rem;color:rgb(var(--ax-sys-color-primary-600));background:linear-gradient(145deg,rgba(var(--ax-sys-color-primary-500),.14),rgba(var(--ax-sys-color-primary-500),.04));border:1px solid rgba(var(--ax-sys-color-primary-500),.18)}.axm-chat-empty-assist-
|
|
1044
|
+
`, isInline: true, styles: [":host{display:block;width:100%}:host(.axm-chat-empty-assist-composer-host--compact){display:flex;height:100%;min-height:0}.axm-chat-empty-assist-composer{display:flex;flex-direction:column;gap:1rem;width:min(100%,64rem);margin-inline:auto}.axm-chat-empty-assist-composer__hero{display:flex;flex-direction:column;align-items:center;gap:.625rem}.axm-chat-empty-assist-composer__hero-icon{display:grid;place-items:center;width:2.5rem;height:2.5rem;border-radius:.875rem;color:rgb(var(--ax-sys-color-primary-600));background:linear-gradient(145deg,rgba(var(--ax-sys-color-primary-500),.14),rgba(var(--ax-sys-color-primary-500),.04));border:1px solid rgba(var(--ax-sys-color-primary-500),.18)}.axm-chat-empty-assist-composer__composer{position:relative;display:flex;flex-direction:column;width:100%;overflow:hidden;border-radius:2em;border:1px solid rgb(var(--ax-sys-color-border-light-surface));background:rgb(var(--ax-sys-color-lightest-surface))}.axm-chat-empty-assist-composer__attachments{display:flex;align-items:center;width:100%;min-width:0;padding:.125rem .5rem 0;border-bottom:1px solid rgba(var(--ax-sys-color-border-light-surface),.65)}.axm-chat-empty-assist-composer__attachments-scroll{display:flex;flex:1 1 auto;flex-wrap:nowrap;align-items:center;gap:.375rem;min-width:0;width:0;overflow-x:auto;overflow-y:hidden;padding-block:.375rem;scrollbar-width:thin}.axm-chat-empty-assist-composer__attachment{position:relative;display:flex;flex-shrink:0;align-items:center}.axm-chat-empty-assist-composer__attachment--file{width:9.5rem;max-width:9.5rem;height:2rem;gap:.375rem;padding-inline:.375rem .5rem;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-border-light-surface),.85);background:rgb(var(--ax-sys-color-surface))}.axm-chat-empty-assist-composer__attachment-thumb{display:flex;width:2rem;height:2rem;align-items:center;justify-content:center;overflow:hidden;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-border-light-surface),.85);background:rgb(var(--ax-sys-color-surface))}.axm-chat-empty-assist-composer__attachment-thumb img,.axm-chat-empty-assist-composer__attachment-thumb video{width:100%;height:100%;object-fit:cover}.axm-chat-empty-assist-composer__attachment-icon{display:flex;width:1.25rem;height:1.25rem;flex-shrink:0;align-items:center;justify-content:center;font-size:.75rem;color:rgb(var(--ax-sys-color-on-surface));opacity:.72}.axm-chat-empty-assist-composer__attachment-name{min-width:0;flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.75rem;color:rgb(var(--ax-sys-color-on-surface))}.axm-chat-empty-assist-composer__attachment-remove{position:absolute;inset-block-start:-.25rem;inset-inline-end:-.25rem;z-index:1;display:flex;align-items:center;justify-content:center;width:1rem;height:1rem;padding:0;border:none;border-radius:9999px;background:rgb(var(--ax-sys-color-danger-500));color:rgb(var(--ax-sys-color-lightest-surface));font-size:.5rem;cursor:pointer;opacity:0;pointer-events:none;transition:opacity .15s ease}.axm-chat-empty-assist-composer__attachment:hover .axm-chat-empty-assist-composer__attachment-remove,.axm-chat-empty-assist-composer__attachment:focus-within .axm-chat-empty-assist-composer__attachment-remove,.axm-chat-empty-assist-composer__attachment-remove:focus-visible{opacity:1;pointer-events:auto}@media(hover:none){.axm-chat-empty-assist-composer__attachment-remove{opacity:1;pointer-events:auto}}.axm-chat-empty-assist-composer__attachment-add{flex-shrink:0;align-self:center}.axm-chat-empty-assist-composer__attachment-add ax-prefix i{font-size:.875rem;line-height:1}.axm-chat-empty-assist-composer__input-row{display:flex;width:100%;min-width:0;align-items:center;gap:.5rem;padding:.25rem .5rem}.axm-chat-empty-assist-composer__actions-start,.axm-chat-empty-assist-composer__primary{display:flex;flex-shrink:0;align-items:center}.axm-chat-empty-assist-composer__actions-start ax-icon i,.axm-chat-empty-assist-composer__actions-start ax-prefix i,.axm-chat-empty-assist-composer__primary ax-prefix i{font-size:1.375rem;line-height:1}.axm-chat-empty-assist-composer__textarea{flex:1 1 auto;min-width:0;min-height:2.25rem;max-height:14rem;margin:0;padding-block:.25rem;border:none;outline:none;resize:none;overflow:hidden;background:transparent;font-size:inherit;line-height:1.5;color:rgb(var(--ax-sys-color-on-surface))}.axm-chat-empty-assist-composer__textarea::placeholder{color:rgb(var(--ax-sys-color-on-surface));opacity:.45}.axm-chat-empty-assist-composer__file-input{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}.axm-chat-empty-assist-composer__caption{margin-bottom:1.25rem;text-align:center;font-size:clamp(1.9rem,3.4vw,2.7rem);line-height:1.15;font-weight:700;letter-spacing:-.02em;color:rgb(var(--ax-sys-color-on-surface))}.axm-chat-empty-assist-composer__suggestions{display:flex;flex-direction:column;gap:.5rem}.axm-chat-empty-assist-composer__suggestions-label{margin:0;padding-inline:.125rem;font-size:.6875rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:rgb(var(--ax-sys-color-on-surface));opacity:.52}.axm-chat-empty-assist-composer__chips-loading{display:flex;flex-direction:column;align-items:center;gap:.5rem;padding-block:.5rem}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer{width:100%;max-width:none;height:100%;min-height:0;gap:.875rem;justify-content:center;overflow:hidden;padding-block:.5rem .125rem}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__hero{flex-shrink:0;gap:.5rem;padding-block-start:.5rem}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__hero-icon{width:2.5rem;height:2.5rem;border-radius:.875rem;color:rgb(var(--ax-sys-color-primary-600))}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__caption{margin-bottom:0;font-size:1.125rem;line-height:1.3;font-weight:700;letter-spacing:-.03em}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__composer{flex-shrink:0;width:100%;border-radius:1.5rem;border-color:rgba(var(--ax-sys-color-border-light-surface),.95)}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__textarea{min-height:1.625rem;max-height:8rem;font-size:.875rem;line-height:1.4}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__subtitle{margin:0;max-width:20rem;text-align:center;font-size:.8125rem;line-height:1.5;font-weight:400;color:rgb(var(--ax-sys-color-on-surface));opacity:.58}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__suggestions,:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__chips-loading{display:flex;flex-direction:column;flex:0 1 auto;min-height:0;overflow:auto;justify-content:flex-start}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__suggestions{gap:.5rem;margin-top:.125rem}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__suggestions-label{flex-shrink:0;margin-block-end:.125rem;letter-spacing:.02em;text-transform:none;font-size:.75rem;font-weight:500;opacity:.55}:host(.axm-chat-empty-assist-composer-host--compact) axm-assist-suggestion-chips{flex:0 1 auto;min-height:0;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i4.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i5.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXMAssistSuggestionChipsComponent, selector: "axm-assist-suggestion-chips", inputs: ["items", "compact", "sendInPlace", "disabled"], outputs: ["conversationCreated"] }, { kind: "component", type: AXMChatComposerAssistPickerComponent, selector: "axm-chat-composer-assist-picker", inputs: ["__popup__"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i7.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
616
1045
|
}
|
|
617
1046
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMChatEmptyAssistComposerComponent, decorators: [{
|
|
618
1047
|
type: Component,
|
|
@@ -621,7 +1050,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
621
1050
|
'[class.axm-chat-empty-assist-composer-host--compact]': 'compact()',
|
|
622
1051
|
'[attr.dir]': 'textDirection()',
|
|
623
1052
|
'[style.direction]': 'textDirection()',
|
|
624
|
-
}, imports: [CommonModule, FormsModule, AXButtonModule,
|
|
1053
|
+
}, imports: [CommonModule, FormsModule, AXButtonModule, AXDecoratorModule, AXDropdownModule, AXLoadingModule, AXTranslationModule, AXMAssistSuggestionChipsComponent, AXMChatComposerAssistPickerComponent], template: `
|
|
625
1054
|
<div class="axm-chat-empty-assist-composer">
|
|
626
1055
|
<div class="axm-chat-empty-assist-composer__hero">
|
|
627
1056
|
@if (compact()) {
|
|
@@ -630,93 +1059,174 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
630
1059
|
</span>
|
|
631
1060
|
}
|
|
632
1061
|
<div class="axm-chat-empty-assist-composer__caption">
|
|
633
|
-
|
|
1062
|
+
@if (asksForAssist()) {
|
|
1063
|
+
{{ '@conversation:mini-chat.choose-assist.title' | translate | async }}
|
|
1064
|
+
}
|
|
1065
|
+
<!-- ----- Default welcome when an assist is already chosen or selection is optional ----- -->
|
|
1066
|
+
@else {
|
|
1067
|
+
{{ (compact() ? '@conversation:mini-chat.empty.title' : '@conversation:chat.empty-assist.caption') | translate | async }}
|
|
1068
|
+
}
|
|
634
1069
|
</div>
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
<ax-button color="default" look="blank" class="rounded-full" [disabled]="isBusy()">
|
|
640
|
-
<ax-icon icon="fa-regular fa-sparkles"></ax-icon>
|
|
641
|
-
<span class="axm-chat-empty-assist-composer__assist-text">
|
|
642
|
-
@if (selectedAssistLabel(); as assistLabel) {
|
|
643
|
-
{{ assistLabel | translate | async }}
|
|
644
|
-
} @else {
|
|
645
|
-
{{ '@conversation:chat.empty-assist.assist-default' | translate | async }}
|
|
646
|
-
}
|
|
647
|
-
</span>
|
|
648
|
-
@if (!isBusy()) {
|
|
649
|
-
<ax-dropdown-panel>
|
|
650
|
-
<ax-button-item-list>
|
|
651
|
-
@for (row of rows(); track row.id) {
|
|
652
|
-
<ax-button-item [text]="(row.title | translate | async)!" [selected]="row.id === selectedAssistId()" (onClick)="onAssistIdChange(row.id)"></ax-button-item>
|
|
653
|
-
}
|
|
654
|
-
</ax-button-item-list>
|
|
655
|
-
</ax-dropdown-panel>
|
|
656
|
-
}
|
|
657
|
-
</ax-button>
|
|
658
|
-
} @else {
|
|
659
|
-
<ax-button
|
|
660
|
-
color="default"
|
|
661
|
-
look="blank"
|
|
662
|
-
class="axm-chat-empty-assist-composer__assist-trigger rounded-full"
|
|
663
|
-
[iconOnly]="true"
|
|
664
|
-
[disabled]="isBusy()"
|
|
665
|
-
[attr.aria-label]="('@conversation:chat.empty-assist.assist-default' | translate | async) ?? ''"
|
|
666
|
-
>
|
|
667
|
-
<ax-icon icon="fa-regular fa-sparkles"></ax-icon>
|
|
668
|
-
@if (!isBusy()) {
|
|
669
|
-
<ax-dropdown-panel>
|
|
670
|
-
<ax-button-item-list>
|
|
671
|
-
@for (row of rows(); track row.id) {
|
|
672
|
-
<ax-button-item [text]="(row.title | translate | async)!" [selected]="row.id === selectedAssistId()" (onClick)="onAssistIdChange(row.id)"></ax-button-item>
|
|
673
|
-
}
|
|
674
|
-
</ax-button-item-list>
|
|
675
|
-
</ax-dropdown-panel>
|
|
676
|
-
}
|
|
677
|
-
</ax-button>
|
|
1070
|
+
@if (asksForAssist()) {
|
|
1071
|
+
<p class="axm-chat-empty-assist-composer__subtitle">
|
|
1072
|
+
{{ '@conversation:mini-chat.choose-assist.subtitle' | translate | async }}
|
|
1073
|
+
</p>
|
|
678
1074
|
}
|
|
1075
|
+
<!-- ----- Compact welcome subtitle when the header is not waiting for an assist ----- -->
|
|
1076
|
+
@else if (compact()) {
|
|
1077
|
+
<p class="axm-chat-empty-assist-composer__subtitle">
|
|
1078
|
+
{{ '@conversation:mini-chat.empty.subtitle' | translate | async }}
|
|
1079
|
+
</p>
|
|
1080
|
+
}
|
|
1081
|
+
</div>
|
|
679
1082
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
<
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
1083
|
+
<!-- ----- Lookalike composer: attach and type stay local until send ----- -->
|
|
1084
|
+
@if (!hasActiveConversation()) {
|
|
1085
|
+
<div class="axm-chat-empty-assist-composer__composer">
|
|
1086
|
+
<!---->
|
|
1087
|
+
<!-- ----- Local attachment chips before the first message is sent ----- -->
|
|
1088
|
+
@if (draftFiles().length > 0) {
|
|
1089
|
+
<div class="axm-chat-empty-assist-composer__attachments">
|
|
1090
|
+
<div class="axm-chat-empty-assist-composer__attachments-scroll" role="list">
|
|
1091
|
+
@for (attachment of draftFiles(); track attachment.id) {
|
|
1092
|
+
<div
|
|
1093
|
+
class="axm-chat-empty-assist-composer__attachment"
|
|
1094
|
+
role="listitem"
|
|
1095
|
+
[class.axm-chat-empty-assist-composer__attachment--media]="attachment.kind === 'image' || attachment.kind === 'video'"
|
|
1096
|
+
[class.axm-chat-empty-assist-composer__attachment--file]="attachment.kind === 'audio' || attachment.kind === 'file'"
|
|
1097
|
+
[title]="attachment.file.name"
|
|
1098
|
+
>
|
|
1099
|
+
<!---->
|
|
1100
|
+
<!-- ----- Image thumbnail ----- -->
|
|
1101
|
+
@if (attachment.kind === 'image' && attachment.preview) {
|
|
1102
|
+
<span class="axm-chat-empty-assist-composer__attachment-thumb" aria-hidden="true">
|
|
1103
|
+
<img [src]="attachment.preview" alt="" />
|
|
1104
|
+
</span>
|
|
1105
|
+
}
|
|
1106
|
+
<!-- ----- Video thumbnail ----- -->
|
|
1107
|
+
@else if (attachment.kind === 'video' && attachment.preview) {
|
|
1108
|
+
<span class="axm-chat-empty-assist-composer__attachment-thumb" aria-hidden="true">
|
|
1109
|
+
<video [src]="attachment.preview" muted playsinline preload="metadata"></video>
|
|
1110
|
+
</span>
|
|
1111
|
+
}
|
|
1112
|
+
<!-- ----- File name fallback ----- -->
|
|
1113
|
+
@else {
|
|
1114
|
+
<span class="axm-chat-empty-assist-composer__attachment-icon" aria-hidden="true">
|
|
1115
|
+
<i [class]="draftFileIcon(attachment.kind)"></i>
|
|
1116
|
+
</span>
|
|
1117
|
+
<span class="axm-chat-empty-assist-composer__attachment-name">{{ attachment.file.name }}</span>
|
|
1118
|
+
}
|
|
1119
|
+
<button
|
|
1120
|
+
type="button"
|
|
1121
|
+
class="axm-chat-empty-assist-composer__attachment-remove"
|
|
1122
|
+
[attr.aria-label]="('@acorex:chat.actions.remove-attachment' | translate | async) ?? ''"
|
|
1123
|
+
(click)="removeDraftFile(attachment.id); $event.stopPropagation()"
|
|
1124
|
+
>
|
|
1125
|
+
<i class="fa-solid fa-xmark"></i>
|
|
1126
|
+
</button>
|
|
1127
|
+
</div>
|
|
1128
|
+
}
|
|
1129
|
+
<ax-button
|
|
1130
|
+
class="axm-chat-empty-assist-composer__attachment-add ax-sm rounded-full"
|
|
1131
|
+
look="blank"
|
|
1132
|
+
[iconOnly]="true"
|
|
1133
|
+
[disabled]="isBusy() || draftFiles().length >= maxDraftFiles"
|
|
1134
|
+
[text]="('@acorex:chat.pickers.common.add-more' | translate | async) ?? ''"
|
|
1135
|
+
(onClick)="browseDraftFiles()"
|
|
1136
|
+
>
|
|
1137
|
+
<ax-prefix>
|
|
1138
|
+
<i class="fa-light fa-plus"></i>
|
|
1139
|
+
</ax-prefix>
|
|
1140
|
+
</ax-button>
|
|
1141
|
+
</div>
|
|
1142
|
+
</div>
|
|
703
1143
|
}
|
|
704
|
-
|
|
705
|
-
|
|
1144
|
+
<div class="axm-chat-empty-assist-composer__input-row">
|
|
1145
|
+
<div class="axm-chat-empty-assist-composer__actions-start">
|
|
1146
|
+
<ax-button
|
|
1147
|
+
class="rounded-full text-xl"
|
|
1148
|
+
look="blank"
|
|
1149
|
+
[iconOnly]="true"
|
|
1150
|
+
[disabled]="isBusy() || draftFiles().length >= maxDraftFiles"
|
|
1151
|
+
[text]="('@acorex:chat.tooltips.attach-file' | translate | async) ?? ''"
|
|
1152
|
+
(onClick)="browseDraftFiles()"
|
|
1153
|
+
>
|
|
1154
|
+
<ax-prefix>
|
|
1155
|
+
<i class="fa-light fa-paperclip"></i>
|
|
1156
|
+
</ax-prefix>
|
|
1157
|
+
</ax-button>
|
|
1158
|
+
@if (assistSelection() !== 'locked') {
|
|
1159
|
+
<ax-button class="rounded-full axm-chat-composer-assist-picker" look="blank" [iconOnly]="true" [disabled]="isBusy() || rows().length === 0" [text]="('@conversation:chat.empty-assist.assist-default' | translate | async) ?? ''">
|
|
1160
|
+
<ax-prefix>
|
|
1161
|
+
<i class="fa-light fa-sparkles"></i>
|
|
1162
|
+
</ax-prefix>
|
|
1163
|
+
<!---->
|
|
1164
|
+
<!-- ----- Assist list as a dropdown, not a popup ----- -->
|
|
1165
|
+
@if (rows().length > 0) {
|
|
1166
|
+
<ax-dropdown-panel>
|
|
1167
|
+
<axm-chat-composer-assist-picker />
|
|
1168
|
+
</ax-dropdown-panel>
|
|
1169
|
+
}
|
|
1170
|
+
</ax-button>
|
|
1171
|
+
}
|
|
1172
|
+
</div>
|
|
1173
|
+
<textarea
|
|
1174
|
+
#draftInput
|
|
1175
|
+
rows="1"
|
|
1176
|
+
class="axm-chat-empty-assist-composer__textarea"
|
|
1177
|
+
[ngModel]="draftText()"
|
|
1178
|
+
(ngModelChange)="draftText.set($event ?? '')"
|
|
1179
|
+
(input)="resizeDraftInput()"
|
|
1180
|
+
(keydown)="onDraftKeydown($event)"
|
|
1181
|
+
[disabled]="isBusy()"
|
|
1182
|
+
[placeholder]="draftPlaceholder()"
|
|
1183
|
+
></textarea>
|
|
1184
|
+
<div class="axm-chat-empty-assist-composer__primary">
|
|
1185
|
+
<ax-button
|
|
1186
|
+
class="rounded-full"
|
|
1187
|
+
[class.composer-primary-button--send]="canSend()"
|
|
1188
|
+
look="blank"
|
|
1189
|
+
color="primary"
|
|
1190
|
+
[iconOnly]="true"
|
|
1191
|
+
[disabled]="!canSend()"
|
|
1192
|
+
[text]="('@acorex:chat.actions.send' | translate | async) ?? ''"
|
|
1193
|
+
(onClick)="send()"
|
|
1194
|
+
>
|
|
1195
|
+
<ax-prefix>
|
|
1196
|
+
<i class="fa-solid fa-paper-plane-top"></i>
|
|
1197
|
+
</ax-prefix>
|
|
1198
|
+
</ax-button>
|
|
1199
|
+
</div>
|
|
1200
|
+
</div>
|
|
1201
|
+
<input #fileInput class="axm-chat-empty-assist-composer__file-input" type="file" multiple (change)="onDraftFilesSelected($event)" />
|
|
1202
|
+
</div>
|
|
1203
|
+
}
|
|
706
1204
|
|
|
707
|
-
|
|
1205
|
+
<!-- ----- Starter chips loading indicator ----- -->
|
|
1206
|
+
@if (chipsLoading()) {
|
|
1207
|
+
<div class="axm-chat-empty-assist-composer__chips-loading">
|
|
1208
|
+
<ax-loading></ax-loading>
|
|
1209
|
+
<p class="axm-chat-empty-assist-composer__suggestions-label">
|
|
1210
|
+
{{ '@conversation:chat.contextual-assist.chips-loading' | translate | async }}
|
|
1211
|
+
</p>
|
|
1212
|
+
</div>
|
|
1213
|
+
}
|
|
1214
|
+
<!-- ----- Starter suggestion chips ----- -->
|
|
1215
|
+
@else if (starterPromptItems().length > 0) {
|
|
708
1216
|
<div class="axm-chat-empty-assist-composer__suggestions">
|
|
1217
|
+
<!---->
|
|
1218
|
+
<!-- ----- Compact starter section label ----- -->
|
|
709
1219
|
@if (compact()) {
|
|
710
1220
|
<p class="axm-chat-empty-assist-composer__suggestions-label">
|
|
711
|
-
{{ '@conversation:chat.
|
|
1221
|
+
{{ '@conversation:mini-chat.try-asking' | translate | async }}
|
|
712
1222
|
</p>
|
|
713
1223
|
}
|
|
714
|
-
<axm-assist-suggestion-chips [items]="starterPromptItems()" [compact]="compact()" [sendInPlace]="sendStarterPromptsInPlace()" [disabled]="
|
|
1224
|
+
<axm-assist-suggestion-chips [items]="starterPromptItems()" [compact]="compact()" [sendInPlace]="sendStarterPromptsInPlace()" [disabled]="loading()" (conversationCreated)="conversationCreated.emit($event)" />
|
|
715
1225
|
</div>
|
|
716
1226
|
}
|
|
717
1227
|
</div>
|
|
718
|
-
`, styles: [":host{display:block;width:100%}.axm-chat-empty-assist-composer{display:flex;flex-direction:column;gap:1rem;width:min(100%,64rem);margin-inline:auto}.axm-chat-empty-assist-composer__hero{display:flex;flex-direction:column;align-items:center;gap:.625rem}.axm-chat-empty-assist-composer__hero-icon{display:grid;place-items:center;width:2.5rem;height:2.5rem;border-radius:.875rem;color:rgb(var(--ax-sys-color-primary-600));background:linear-gradient(145deg,rgba(var(--ax-sys-color-primary-500),.14),rgba(var(--ax-sys-color-primary-500),.04));border:1px solid rgba(var(--ax-sys-color-primary-500),.18)}.axm-chat-empty-assist-
|
|
719
|
-
}], ctorParameters: () => [], propDecorators: { conversationCreated: [{ type: i0.Output, args: ["conversationCreated"] }], initialAssistId: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialAssistId", required: false }] }], entityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityId", required: false }] }], entityType: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityType", required: false }] }], sendStarterPromptsInPlace: [{ type: i0.Input, args: [{ isSignal: true, alias: "sendStarterPromptsInPlace", required: false }] }],
|
|
1228
|
+
`, styles: [":host{display:block;width:100%}:host(.axm-chat-empty-assist-composer-host--compact){display:flex;height:100%;min-height:0}.axm-chat-empty-assist-composer{display:flex;flex-direction:column;gap:1rem;width:min(100%,64rem);margin-inline:auto}.axm-chat-empty-assist-composer__hero{display:flex;flex-direction:column;align-items:center;gap:.625rem}.axm-chat-empty-assist-composer__hero-icon{display:grid;place-items:center;width:2.5rem;height:2.5rem;border-radius:.875rem;color:rgb(var(--ax-sys-color-primary-600));background:linear-gradient(145deg,rgba(var(--ax-sys-color-primary-500),.14),rgba(var(--ax-sys-color-primary-500),.04));border:1px solid rgba(var(--ax-sys-color-primary-500),.18)}.axm-chat-empty-assist-composer__composer{position:relative;display:flex;flex-direction:column;width:100%;overflow:hidden;border-radius:2em;border:1px solid rgb(var(--ax-sys-color-border-light-surface));background:rgb(var(--ax-sys-color-lightest-surface))}.axm-chat-empty-assist-composer__attachments{display:flex;align-items:center;width:100%;min-width:0;padding:.125rem .5rem 0;border-bottom:1px solid rgba(var(--ax-sys-color-border-light-surface),.65)}.axm-chat-empty-assist-composer__attachments-scroll{display:flex;flex:1 1 auto;flex-wrap:nowrap;align-items:center;gap:.375rem;min-width:0;width:0;overflow-x:auto;overflow-y:hidden;padding-block:.375rem;scrollbar-width:thin}.axm-chat-empty-assist-composer__attachment{position:relative;display:flex;flex-shrink:0;align-items:center}.axm-chat-empty-assist-composer__attachment--file{width:9.5rem;max-width:9.5rem;height:2rem;gap:.375rem;padding-inline:.375rem .5rem;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-border-light-surface),.85);background:rgb(var(--ax-sys-color-surface))}.axm-chat-empty-assist-composer__attachment-thumb{display:flex;width:2rem;height:2rem;align-items:center;justify-content:center;overflow:hidden;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-border-light-surface),.85);background:rgb(var(--ax-sys-color-surface))}.axm-chat-empty-assist-composer__attachment-thumb img,.axm-chat-empty-assist-composer__attachment-thumb video{width:100%;height:100%;object-fit:cover}.axm-chat-empty-assist-composer__attachment-icon{display:flex;width:1.25rem;height:1.25rem;flex-shrink:0;align-items:center;justify-content:center;font-size:.75rem;color:rgb(var(--ax-sys-color-on-surface));opacity:.72}.axm-chat-empty-assist-composer__attachment-name{min-width:0;flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.75rem;color:rgb(var(--ax-sys-color-on-surface))}.axm-chat-empty-assist-composer__attachment-remove{position:absolute;inset-block-start:-.25rem;inset-inline-end:-.25rem;z-index:1;display:flex;align-items:center;justify-content:center;width:1rem;height:1rem;padding:0;border:none;border-radius:9999px;background:rgb(var(--ax-sys-color-danger-500));color:rgb(var(--ax-sys-color-lightest-surface));font-size:.5rem;cursor:pointer;opacity:0;pointer-events:none;transition:opacity .15s ease}.axm-chat-empty-assist-composer__attachment:hover .axm-chat-empty-assist-composer__attachment-remove,.axm-chat-empty-assist-composer__attachment:focus-within .axm-chat-empty-assist-composer__attachment-remove,.axm-chat-empty-assist-composer__attachment-remove:focus-visible{opacity:1;pointer-events:auto}@media(hover:none){.axm-chat-empty-assist-composer__attachment-remove{opacity:1;pointer-events:auto}}.axm-chat-empty-assist-composer__attachment-add{flex-shrink:0;align-self:center}.axm-chat-empty-assist-composer__attachment-add ax-prefix i{font-size:.875rem;line-height:1}.axm-chat-empty-assist-composer__input-row{display:flex;width:100%;min-width:0;align-items:center;gap:.5rem;padding:.25rem .5rem}.axm-chat-empty-assist-composer__actions-start,.axm-chat-empty-assist-composer__primary{display:flex;flex-shrink:0;align-items:center}.axm-chat-empty-assist-composer__actions-start ax-icon i,.axm-chat-empty-assist-composer__actions-start ax-prefix i,.axm-chat-empty-assist-composer__primary ax-prefix i{font-size:1.375rem;line-height:1}.axm-chat-empty-assist-composer__textarea{flex:1 1 auto;min-width:0;min-height:2.25rem;max-height:14rem;margin:0;padding-block:.25rem;border:none;outline:none;resize:none;overflow:hidden;background:transparent;font-size:inherit;line-height:1.5;color:rgb(var(--ax-sys-color-on-surface))}.axm-chat-empty-assist-composer__textarea::placeholder{color:rgb(var(--ax-sys-color-on-surface));opacity:.45}.axm-chat-empty-assist-composer__file-input{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}.axm-chat-empty-assist-composer__caption{margin-bottom:1.25rem;text-align:center;font-size:clamp(1.9rem,3.4vw,2.7rem);line-height:1.15;font-weight:700;letter-spacing:-.02em;color:rgb(var(--ax-sys-color-on-surface))}.axm-chat-empty-assist-composer__suggestions{display:flex;flex-direction:column;gap:.5rem}.axm-chat-empty-assist-composer__suggestions-label{margin:0;padding-inline:.125rem;font-size:.6875rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:rgb(var(--ax-sys-color-on-surface));opacity:.52}.axm-chat-empty-assist-composer__chips-loading{display:flex;flex-direction:column;align-items:center;gap:.5rem;padding-block:.5rem}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer{width:100%;max-width:none;height:100%;min-height:0;gap:.875rem;justify-content:center;overflow:hidden;padding-block:.5rem .125rem}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__hero{flex-shrink:0;gap:.5rem;padding-block-start:.5rem}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__hero-icon{width:2.5rem;height:2.5rem;border-radius:.875rem;color:rgb(var(--ax-sys-color-primary-600))}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__caption{margin-bottom:0;font-size:1.125rem;line-height:1.3;font-weight:700;letter-spacing:-.03em}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__composer{flex-shrink:0;width:100%;border-radius:1.5rem;border-color:rgba(var(--ax-sys-color-border-light-surface),.95)}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__textarea{min-height:1.625rem;max-height:8rem;font-size:.875rem;line-height:1.4}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__subtitle{margin:0;max-width:20rem;text-align:center;font-size:.8125rem;line-height:1.5;font-weight:400;color:rgb(var(--ax-sys-color-on-surface));opacity:.58}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__suggestions,:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__chips-loading{display:flex;flex-direction:column;flex:0 1 auto;min-height:0;overflow:auto;justify-content:flex-start}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__suggestions{gap:.5rem;margin-top:.125rem}:host(.axm-chat-empty-assist-composer-host--compact) .axm-chat-empty-assist-composer__suggestions-label{flex-shrink:0;margin-block-end:.125rem;letter-spacing:.02em;text-transform:none;font-size:.75rem;font-weight:500;opacity:.55}:host(.axm-chat-empty-assist-composer-host--compact) axm-assist-suggestion-chips{flex:0 1 auto;min-height:0;overflow:hidden}\n"] }]
|
|
1229
|
+
}], ctorParameters: () => [], propDecorators: { draftInput: [{ type: i0.ViewChild, args: ['draftInput', { isSignal: true }] }], fileInput: [{ type: i0.ViewChild, args: ['fileInput', { isSignal: true }] }], conversationCreated: [{ type: i0.Output, args: ["conversationCreated"] }], initialAssistId: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialAssistId", required: false }] }], assistSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "assistSelection", required: false }] }], acceptExternalFileDrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptExternalFileDrop", required: false }] }], entityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityId", required: false }] }], entityType: [{ type: i0.Input, args: [{ isSignal: true, alias: "entityType", required: false }] }], sendStarterPromptsInPlace: [{ type: i0.Input, args: [{ isSignal: true, alias: "sendStarterPromptsInPlace", required: false }] }], launchContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "launchContext", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], assistConversationCreated: [{ type: i0.Input, args: [{ isSignal: true, alias: "assistConversationCreated", required: false }] }] } });
|
|
720
1230
|
|
|
721
1231
|
const AXE_CHAT_EMPTY_STATE_PROVIDERS = [
|
|
722
1232
|
{
|
|
@@ -772,6 +1282,7 @@ function coerceTimestampMs(value) {
|
|
|
772
1282
|
* AI generation and entity persistence run on the server ({@link AiConversationAssistResponseService}).
|
|
773
1283
|
*/
|
|
774
1284
|
class AXEConversationAssistResponseService {
|
|
1285
|
+
static { this.ASSIST_SYNC_MIN_INTERVAL_MS = 2000; }
|
|
775
1286
|
constructor() {
|
|
776
1287
|
this.transportService = inject(AXPRuntimeTransportService);
|
|
777
1288
|
this.toastService = inject(AXToastService);
|
|
@@ -779,30 +1290,41 @@ class AXEConversationAssistResponseService {
|
|
|
779
1290
|
this.store = inject(AXMConversationEntityStoreService);
|
|
780
1291
|
this.focus = inject(AXMConversationFocusService);
|
|
781
1292
|
this.commandService = inject(AXPCommandService);
|
|
1293
|
+
this.generationState = inject(AXConversationComposerGenerationStateService);
|
|
1294
|
+
this.destroyRef = inject(DestroyRef);
|
|
782
1295
|
this.messageCache = new Map();
|
|
1296
|
+
this.forgottenMessageIds = new Set();
|
|
783
1297
|
this.conversationCache = new Map();
|
|
784
1298
|
this.streamTasks = new Map();
|
|
785
1299
|
this.streamReconnectTimers = new Map();
|
|
786
1300
|
this.lastAssistSyncAt = new Map();
|
|
787
1301
|
this.currentUserId = '';
|
|
788
1302
|
this.composerGenerationConversationId = null;
|
|
789
|
-
this.
|
|
1303
|
+
this.cancelAssistByConversation = new Map();
|
|
1304
|
+
this.userCancelledConversationIds = new Set();
|
|
1305
|
+
this.generationState.onCancelled.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
|
1306
|
+
const conversationId = this.composerGenerationConversationId?.trim()
|
|
1307
|
+
|| this.focus.getFocusedConversationId()?.trim()
|
|
1308
|
+
|| '';
|
|
1309
|
+
void this.cancelAssistGeneration(conversationId);
|
|
1310
|
+
});
|
|
790
1311
|
}
|
|
791
|
-
|
|
792
|
-
async handleAfterUserMessage(conversationId, _userMessageId, _command, currentUserId) {
|
|
1312
|
+
async handleAfterUserMessage(conversationId, _userMessageId, _command, currentUserId, options) {
|
|
793
1313
|
this.currentUserId = currentUserId;
|
|
794
1314
|
this.ensureAssistStreamSubscription(conversationId);
|
|
795
1315
|
const scoped = conversationId.trim();
|
|
1316
|
+
this.userCancelledConversationIds.delete(scoped);
|
|
796
1317
|
if (!this.conversationCache.has(scoped)) {
|
|
797
1318
|
const storeCached = this.store.getCachedConversation(scoped);
|
|
798
1319
|
if (storeCached) {
|
|
799
1320
|
this.conversationCache.set(scoped, storeCached);
|
|
800
1321
|
}
|
|
801
1322
|
}
|
|
802
|
-
|
|
1323
|
+
const focusedId = this.focus.getFocusedConversationId();
|
|
1324
|
+
if (focusedId === scoped || !focusedId) {
|
|
803
1325
|
this.markComposerGenerating(scoped, true);
|
|
804
1326
|
}
|
|
805
|
-
if (!this.streamTasks.has(scoped)) {
|
|
1327
|
+
if (!options?.skipAssistSync && !this.streamTasks.has(scoped)) {
|
|
806
1328
|
void this.requestAssistSync(conversationId, { force: true });
|
|
807
1329
|
}
|
|
808
1330
|
}
|
|
@@ -827,6 +1349,7 @@ class AXEConversationAssistResponseService {
|
|
|
827
1349
|
this.messageCache.delete(messageId);
|
|
828
1350
|
}
|
|
829
1351
|
this.ensureAssistStreamSubscription(conversationId);
|
|
1352
|
+
this.userCancelledConversationIds.delete(conversationId.trim());
|
|
830
1353
|
if (this.focus.isFocused(conversationId)) {
|
|
831
1354
|
this.markComposerGenerating(conversationId, true);
|
|
832
1355
|
}
|
|
@@ -919,18 +1442,35 @@ class AXEConversationAssistResponseService {
|
|
|
919
1442
|
return streaming.length > 0;
|
|
920
1443
|
}
|
|
921
1444
|
mergeLiveConversationMessages(conversationId, persisted) {
|
|
922
|
-
const byId = new Map(
|
|
1445
|
+
const byId = new Map();
|
|
1446
|
+
for (const message of persisted) {
|
|
1447
|
+
if (message.deleted || this.forgottenMessageIds.has(message.id)) {
|
|
1448
|
+
continue;
|
|
1449
|
+
}
|
|
1450
|
+
byId.set(message.id, message);
|
|
1451
|
+
}
|
|
923
1452
|
for (const message of this.messageCache.values()) {
|
|
924
|
-
if (message.conversationId
|
|
925
|
-
|
|
926
|
-
if (existing && axmShouldPreferPersistedAssistOverLiveCache(existing, message)) {
|
|
927
|
-
continue;
|
|
928
|
-
}
|
|
929
|
-
byId.set(message.id, this.withStreamDraftForDisplay(message));
|
|
1453
|
+
if (message.conversationId !== conversationId || message.deleted || this.forgottenMessageIds.has(message.id)) {
|
|
1454
|
+
continue;
|
|
930
1455
|
}
|
|
1456
|
+
const existing = byId.get(message.id);
|
|
1457
|
+
if (existing && axmShouldPreferPersistedAssistOverLiveCache(existing, message)) {
|
|
1458
|
+
continue;
|
|
1459
|
+
}
|
|
1460
|
+
byId.set(message.id, this.withStreamDraftForDisplay(message));
|
|
931
1461
|
}
|
|
932
1462
|
return [...byId.values()].sort((a, b) => axmCompareMessagesChronologically(a, b));
|
|
933
1463
|
}
|
|
1464
|
+
forgetLiveMessages(messageIds) {
|
|
1465
|
+
for (const rawId of messageIds) {
|
|
1466
|
+
const messageId = rawId.trim();
|
|
1467
|
+
if (!messageId) {
|
|
1468
|
+
continue;
|
|
1469
|
+
}
|
|
1470
|
+
this.forgottenMessageIds.add(messageId);
|
|
1471
|
+
this.messageCache.delete(messageId);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
934
1474
|
ensureAssistStreamSubscription(conversationId) {
|
|
935
1475
|
const key = conversationId.trim();
|
|
936
1476
|
if (!key || this.streamTasks.has(key)) {
|
|
@@ -994,6 +1534,9 @@ class AXEConversationAssistResponseService {
|
|
|
994
1534
|
async handleAssistWireEvent(event) {
|
|
995
1535
|
switch (event.type) {
|
|
996
1536
|
case 'assist_started': {
|
|
1537
|
+
if (this.shouldIgnoreStreamingAfterUserCancel(event.conversationId)) {
|
|
1538
|
+
break;
|
|
1539
|
+
}
|
|
997
1540
|
void this.markUserMessageSeenByAssist(event.conversationId, event.userMessageId);
|
|
998
1541
|
const mapped = axmMessageEntityToMessage(event.message);
|
|
999
1542
|
this.applyLiveMessage(mapped, { isNew: !this.messageCache.has(mapped.id) });
|
|
@@ -1002,12 +1545,16 @@ class AXEConversationAssistResponseService {
|
|
|
1002
1545
|
}
|
|
1003
1546
|
case 'message_patch': {
|
|
1004
1547
|
const mapped = axmMessageEntityToMessage(event.message);
|
|
1548
|
+
const status = axmReadAssistResponseStatus(mapped.metadata);
|
|
1549
|
+
if (status === 'streaming' && this.shouldIgnoreStreamingAfterUserCancel(mapped.conversationId)) {
|
|
1550
|
+
break;
|
|
1551
|
+
}
|
|
1005
1552
|
const isNew = !this.messageCache.has(mapped.id);
|
|
1006
1553
|
this.applyLiveMessage(mapped, { isNew });
|
|
1007
|
-
if (
|
|
1554
|
+
if (status === 'streaming') {
|
|
1008
1555
|
this.syncComposerGeneratingForConversation(mapped.conversationId, true);
|
|
1009
1556
|
}
|
|
1010
|
-
else if (axmIsAssistTerminalStatus(
|
|
1557
|
+
else if (axmIsAssistTerminalStatus(status)) {
|
|
1011
1558
|
this.syncComposerGeneratingForConversation(mapped.conversationId, false);
|
|
1012
1559
|
}
|
|
1013
1560
|
break;
|
|
@@ -1021,6 +1568,10 @@ class AXEConversationAssistResponseService {
|
|
|
1021
1568
|
}
|
|
1022
1569
|
case 'assist_completed': {
|
|
1023
1570
|
const mapped = axmMessageEntityToMessage(event.message);
|
|
1571
|
+
if (this.shouldIgnoreStreamingAfterUserCancel(mapped.conversationId)) {
|
|
1572
|
+
this.syncComposerGeneratingForConversation(mapped.conversationId, false);
|
|
1573
|
+
break;
|
|
1574
|
+
}
|
|
1024
1575
|
this.applyLiveMessage(mapped, { isNew: false });
|
|
1025
1576
|
void this.maybeMarkFocusedIncomingRead(mapped);
|
|
1026
1577
|
if (event.room) {
|
|
@@ -1033,13 +1584,17 @@ class AXEConversationAssistResponseService {
|
|
|
1033
1584
|
case 'assist_failed': {
|
|
1034
1585
|
const mapped = axmMessageEntityToMessage(event.message);
|
|
1035
1586
|
this.applyLiveMessage(mapped, { isNew: false });
|
|
1036
|
-
if (this.focus.isFocused(mapped.conversationId)) {
|
|
1587
|
+
if (this.focus.isFocused(mapped.conversationId) && axmReadAssistResponseStatus(mapped.metadata) === 'failed') {
|
|
1037
1588
|
void this.showAssistToast('@conversation:chat.assist.errors.title', event.error);
|
|
1038
1589
|
}
|
|
1039
1590
|
this.syncComposerGeneratingForConversation(mapped.conversationId, false);
|
|
1040
1591
|
break;
|
|
1041
1592
|
}
|
|
1042
1593
|
case 'frontend_tool_call': {
|
|
1594
|
+
const cancelId = this.composerGenerationConversationId;
|
|
1595
|
+
if (cancelId && this.shouldIgnoreStreamingAfterUserCancel(cancelId)) {
|
|
1596
|
+
break;
|
|
1597
|
+
}
|
|
1043
1598
|
await this.submitFrontendToolResult(event.runId, event.call);
|
|
1044
1599
|
break;
|
|
1045
1600
|
}
|
|
@@ -1049,7 +1604,13 @@ class AXEConversationAssistResponseService {
|
|
|
1049
1604
|
}
|
|
1050
1605
|
async submitFrontendToolResult(runId, call) {
|
|
1051
1606
|
try {
|
|
1052
|
-
await this.transportService.execute(AXMAiManagementTransportKeys.Engine.SubmitToolResult, {
|
|
1607
|
+
const result = await this.transportService.execute(AXMAiManagementTransportKeys.Engine.SubmitToolResult, {
|
|
1608
|
+
runId,
|
|
1609
|
+
call,
|
|
1610
|
+
});
|
|
1611
|
+
if (result && typeof result === 'object' && 'ok' in result && result.ok === false) {
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1053
1614
|
}
|
|
1054
1615
|
catch (error) {
|
|
1055
1616
|
const text = error instanceof Error ? error.message : String(error);
|
|
@@ -1081,10 +1642,10 @@ class AXEConversationAssistResponseService {
|
|
|
1081
1642
|
}
|
|
1082
1643
|
const assistId = axmExtractAssistIdFromMetadata(metadata);
|
|
1083
1644
|
const modelEntityId = typeof metadata['modelEntityId'] === 'string' && metadata['modelEntityId'].trim() ? metadata['modelEntityId'].trim() : undefined;
|
|
1084
|
-
const result = await this.commandService.execute(AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY, {
|
|
1645
|
+
const result = await this.commandService.execute(AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY$1, {
|
|
1085
1646
|
assistId,
|
|
1086
1647
|
modelEntityId,
|
|
1087
|
-
messages: [axpAiChatTextMessage('system', AXM_ASSIST_CONVERSATION_TITLE_SYSTEM_PROMPT), axpAiChatTextMessage('user', scopedText)],
|
|
1648
|
+
messages: [axpAiChatTextMessage$1('system', AXM_ASSIST_CONVERSATION_TITLE_SYSTEM_PROMPT), axpAiChatTextMessage$1('user', scopedText)],
|
|
1088
1649
|
maxTokens: 48,
|
|
1089
1650
|
temperature: 0.3,
|
|
1090
1651
|
});
|
|
@@ -1160,14 +1721,14 @@ class AXEConversationAssistResponseService {
|
|
|
1160
1721
|
if (!scopedId) {
|
|
1161
1722
|
return;
|
|
1162
1723
|
}
|
|
1163
|
-
const message = this.
|
|
1724
|
+
const message = this.store.getCachedMessage(scopedId) ?? this.messageCache.get(scopedId);
|
|
1164
1725
|
if (!message || message.conversationId !== conversationId) {
|
|
1165
1726
|
return;
|
|
1166
1727
|
}
|
|
1167
1728
|
if (message.senderId !== this.currentUserId || message.status === 'read') {
|
|
1168
1729
|
return;
|
|
1169
1730
|
}
|
|
1170
|
-
|
|
1731
|
+
this.store.publishMessageUpdate({ ...message, status: 'read' });
|
|
1171
1732
|
}
|
|
1172
1733
|
async maybeMarkFocusedIncomingRead(message) {
|
|
1173
1734
|
const conversationId = message.conversationId?.trim();
|
|
@@ -1184,6 +1745,20 @@ class AXEConversationAssistResponseService {
|
|
|
1184
1745
|
});
|
|
1185
1746
|
}
|
|
1186
1747
|
applyLiveMessage(message, options) {
|
|
1748
|
+
if (message.deleted || this.forgottenMessageIds.has(message.id)) {
|
|
1749
|
+
this.forgottenMessageIds.add(message.id);
|
|
1750
|
+
this.messageCache.delete(message.id);
|
|
1751
|
+
this.store.publishMessageDeletion(message.id);
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
this.forgottenMessageIds.delete(message.id);
|
|
1755
|
+
if (this.shouldIgnoreStaleUserTextPatch(message)) {
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
if (axmReadAssistResponseStatus(message.metadata) === 'streaming'
|
|
1759
|
+
&& this.shouldIgnoreStreamingAfterUserCancel(message.conversationId)) {
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1187
1762
|
const normalized = this.coerceLaggyStreamingTerminal(message);
|
|
1188
1763
|
if (this.shouldIgnoreStaleStreamingDowngrade(normalized)) {
|
|
1189
1764
|
return;
|
|
@@ -1240,6 +1815,30 @@ class AXEConversationAssistResponseService {
|
|
|
1240
1815
|
delete nextMeta['streamDraftThink'];
|
|
1241
1816
|
return { ...message, metadata: nextMeta };
|
|
1242
1817
|
}
|
|
1818
|
+
/**
|
|
1819
|
+
* After a user-text edit, entity cache / status-seen persist can emit the pre-edit payload.
|
|
1820
|
+
* Keep the newer local bubble (and never put the old text into the live cache).
|
|
1821
|
+
*/
|
|
1822
|
+
shouldIgnoreStaleUserTextPatch(incoming) {
|
|
1823
|
+
if (incoming.metadata?.['isAssistResponse'] === true || incoming.type === 'assist-response') {
|
|
1824
|
+
return false;
|
|
1825
|
+
}
|
|
1826
|
+
if (incoming.type !== 'text') {
|
|
1827
|
+
return false;
|
|
1828
|
+
}
|
|
1829
|
+
const local = this.store.getCachedMessage(incoming.id) ?? this.messageCache.get(incoming.id);
|
|
1830
|
+
if (!local) {
|
|
1831
|
+
return false;
|
|
1832
|
+
}
|
|
1833
|
+
const localText = extractMessageTextFromPayload(local.payload);
|
|
1834
|
+
const incomingText = extractMessageTextFromPayload(incoming.payload);
|
|
1835
|
+
if (localText === incomingText) {
|
|
1836
|
+
return false;
|
|
1837
|
+
}
|
|
1838
|
+
const localEdited = coerceTimestampMs(local.editedAt);
|
|
1839
|
+
const incomingEdited = coerceTimestampMs(incoming.editedAt);
|
|
1840
|
+
return localEdited > 0 && incomingEdited < localEdited + 5000;
|
|
1841
|
+
}
|
|
1243
1842
|
/** Ignore out-of-order streaming patches after a terminal assist state was applied. */
|
|
1244
1843
|
shouldIgnoreStaleStreamingDowngrade(incoming) {
|
|
1245
1844
|
if (axmReadAssistResponseStatus(incoming.metadata) !== 'streaming') {
|
|
@@ -1462,21 +2061,40 @@ class AXEConversationAssistResponseService {
|
|
|
1462
2061
|
return;
|
|
1463
2062
|
}
|
|
1464
2063
|
const hasStreaming = await this.hasStreamingAssistPlaceholders(scoped);
|
|
2064
|
+
if (this.userCancelledConversationIds.has(scoped)) {
|
|
2065
|
+
this.markComposerGenerating(scoped, false);
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
if (hasStreaming && this.shouldDeferGeneratingTrue(scoped)) {
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
1465
2071
|
this.markComposerGenerating(scoped, hasStreaming);
|
|
1466
2072
|
}
|
|
1467
2073
|
async cancelAssistGeneration(conversationId) {
|
|
1468
|
-
|
|
1469
|
-
|
|
2074
|
+
const scoped = conversationId.trim()
|
|
2075
|
+
|| this.composerGenerationConversationId?.trim()
|
|
2076
|
+
|| this.focus.getFocusedConversationId()?.trim()
|
|
2077
|
+
|| this.resolveActiveStreamingConversationId();
|
|
2078
|
+
if (!scoped) {
|
|
2079
|
+
this.markComposerGenerating(null, false);
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
this.userCancelledConversationIds.add(scoped);
|
|
2083
|
+
this.freezeLiveStreamingAsUserCancelled(scoped);
|
|
2084
|
+
const existing = this.cancelAssistByConversation.get(scoped);
|
|
2085
|
+
if (existing) {
|
|
2086
|
+
return existing;
|
|
1470
2087
|
}
|
|
1471
|
-
|
|
1472
|
-
this.
|
|
2088
|
+
const pending = this.runCancelAssistGeneration(scoped).finally(() => {
|
|
2089
|
+
if (this.cancelAssistByConversation.get(scoped) === pending) {
|
|
2090
|
+
this.cancelAssistByConversation.delete(scoped);
|
|
2091
|
+
}
|
|
1473
2092
|
});
|
|
1474
|
-
|
|
2093
|
+
this.cancelAssistByConversation.set(scoped, pending);
|
|
2094
|
+
return pending;
|
|
1475
2095
|
}
|
|
1476
2096
|
async runCancelAssistGeneration(conversationId) {
|
|
1477
|
-
const scoped = conversationId.trim()
|
|
1478
|
-
|| this.composerGenerationConversationId?.trim()
|
|
1479
|
-
|| this.resolveActiveStreamingConversationId();
|
|
2097
|
+
const scoped = conversationId.trim();
|
|
1480
2098
|
if (!scoped) {
|
|
1481
2099
|
this.markComposerGenerating(null, false);
|
|
1482
2100
|
return;
|
|
@@ -1487,32 +2105,68 @@ class AXEConversationAssistResponseService {
|
|
|
1487
2105
|
});
|
|
1488
2106
|
await this.requestAssistSync(scoped, { force: true });
|
|
1489
2107
|
await this.syncAssistMessagesFromStore(scoped);
|
|
2108
|
+
this.markComposerGenerating(scoped, false);
|
|
1490
2109
|
}
|
|
1491
2110
|
catch (error) {
|
|
1492
2111
|
const text = error instanceof Error ? error.message : String(error);
|
|
1493
2112
|
if (this.focus.isFocused(scoped)) {
|
|
1494
2113
|
void this.showAssistToast('@conversation:chat.assist.errors.stream-title', text);
|
|
1495
2114
|
}
|
|
2115
|
+
this.userCancelledConversationIds.delete(scoped);
|
|
2116
|
+
const hasStreaming = await this.hasStreamingAssistPlaceholders(scoped);
|
|
2117
|
+
this.markComposerGenerating(scoped, hasStreaming);
|
|
1496
2118
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
2119
|
+
}
|
|
2120
|
+
freezeLiveStreamingAsUserCancelled(conversationId) {
|
|
2121
|
+
for (const message of [...this.messageCache.values()]) {
|
|
2122
|
+
if (message.conversationId !== conversationId) {
|
|
2123
|
+
continue;
|
|
2124
|
+
}
|
|
2125
|
+
if (axmReadAssistResponseStatus(message.metadata) !== 'streaming') {
|
|
2126
|
+
continue;
|
|
2127
|
+
}
|
|
2128
|
+
const meta = { ...(message.metadata ?? {}) };
|
|
2129
|
+
meta['isStreaming'] = false;
|
|
2130
|
+
meta['assistResponseStatus'] = 'incomplete';
|
|
2131
|
+
meta['assistResponseError'] = 'Cancelled by user.';
|
|
2132
|
+
this.applyLiveMessage({ ...message, metadata: meta }, { isNew: false });
|
|
1499
2133
|
}
|
|
1500
2134
|
}
|
|
2135
|
+
shouldIgnoreStreamingAfterUserCancel(conversationId) {
|
|
2136
|
+
const scoped = conversationId.trim();
|
|
2137
|
+
return this.userCancelledConversationIds.has(scoped) || this.cancelAssistByConversation.has(scoped);
|
|
2138
|
+
}
|
|
1501
2139
|
markComposerGenerating(conversationId, generating) {
|
|
1502
2140
|
if (generating && conversationId) {
|
|
1503
2141
|
this.composerGenerationConversationId = conversationId;
|
|
2142
|
+
this.generationState.setGenerating(true);
|
|
1504
2143
|
return;
|
|
1505
2144
|
}
|
|
1506
2145
|
if (!generating) {
|
|
2146
|
+
if (conversationId &&
|
|
2147
|
+
this.composerGenerationConversationId &&
|
|
2148
|
+
this.composerGenerationConversationId !== conversationId) {
|
|
2149
|
+
return;
|
|
2150
|
+
}
|
|
1507
2151
|
this.composerGenerationConversationId = null;
|
|
2152
|
+
this.generationState.setGenerating(false);
|
|
1508
2153
|
}
|
|
1509
2154
|
}
|
|
1510
2155
|
syncComposerGeneratingForConversation(conversationId, generating) {
|
|
1511
2156
|
if (!this.focus.isFocused(conversationId)) {
|
|
1512
2157
|
return;
|
|
1513
2158
|
}
|
|
2159
|
+
if (generating && this.shouldDeferGeneratingTrue(conversationId)) {
|
|
2160
|
+
return;
|
|
2161
|
+
}
|
|
1514
2162
|
this.markComposerGenerating(conversationId, generating);
|
|
1515
2163
|
}
|
|
2164
|
+
/** Stream patches must not reset `stopping` back to `generating` while cancel is in flight. */
|
|
2165
|
+
shouldDeferGeneratingTrue(conversationId) {
|
|
2166
|
+
return (this.cancelAssistByConversation.has(conversationId)
|
|
2167
|
+
|| this.userCancelledConversationIds.has(conversationId)
|
|
2168
|
+
|| this.generationState.isStopping());
|
|
2169
|
+
}
|
|
1516
2170
|
resolveActiveStreamingConversationId() {
|
|
1517
2171
|
for (const message of this.messageCache.values()) {
|
|
1518
2172
|
if (axmReadAssistResponseStatus(message.metadata) === 'streaming') {
|
|
@@ -1526,7 +2180,7 @@ class AXEConversationAssistResponseService {
|
|
|
1526
2180
|
}
|
|
1527
2181
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEConversationAssistResponseService, decorators: [{
|
|
1528
2182
|
type: Injectable
|
|
1529
|
-
}] });
|
|
2183
|
+
}], ctorParameters: () => [] });
|
|
1530
2184
|
/** @deprecated Use {@link AXEConversationAssistResponseService}. */
|
|
1531
2185
|
const AXCConversationAssistResponseService = AXEConversationAssistResponseService;
|
|
1532
2186
|
|
|
@@ -1764,7 +2418,7 @@ class AXMChatWithAssistDialogComponent extends AXBasePageComponent {
|
|
|
1764
2418
|
</div>
|
|
1765
2419
|
}
|
|
1766
2420
|
</ng-template>
|
|
1767
|
-
`, isInline: true, styles: [":host{display:block}.new-conversation-panel{display:flex;flex-direction:column;width:100%;overflow:hidden}.new-conversation-dialog-content{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column;gap:.75rem}.form-field--grow{flex:1;min-height:0;display:flex;flex-direction:column}.form-field{display:flex;flex-direction:column;gap:.35rem}.users-list-wrap{display:flex;flex-direction:column;height:min(50vh,36rem);overflow:hidden}.users-list-search{flex:0 0 auto;padding:.5rem .75rem;border-bottom:1px solid rgb(var(--ax-sys-color-border-light-surface));background:rgb(var(--ax-sys-color-lighter-surface))}.users-list{display:block;flex:1 1 auto;min-height:0}.user-item-content{display:flex;align-items:center;gap:.75rem;height:100%;padding:.5rem .75rem;min-width:0}.user-item-text{display:flex;flex-direction:column;justify-content:center;min-width:0;flex:1;gap:.125rem}.user-name-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:500;color:rgb(var(--ax-sys-color-on-surface))}.user-description-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:400;opacity:.72;color:rgb(var(--ax-sys-color-on-surface))}.users-list-empty{padding:1rem;text-align:center;font-size:.85rem;opacity:.7}.user-item-skeleton{display:flex;align-items:center;gap:.75rem;height:60px;padding:.5rem 1.25rem;min-width:0}.skeleton-avatar{flex:0 0 auto;width:3rem;height:3rem;border-radius:9999px}.skeleton-text{display:flex;flex-direction:column;min-width:0;flex:1;gap:.5rem}.skeleton-name{height:1rem;width:60%;border-radius:.25rem}.skeleton-description{height:.75rem;width:40%;border-radius:.25rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXListComponent, selector: "ax-list", inputs: ["id", "name", "disabled", "readonly", "valueField", "textField", "textTemplate", "disabledField", "multiple", "selectionMode", "isItemTruncated", "showItemTooltip", "dataSource", "itemHeight", "itemTemplate", "emptyTemplate", "loadingTemplate", "checkbox"], outputs: ["onValueChanged", "disabledChange", "readonlyChange", "onBlur", "onFocus", "onItemClick", "onItemSelected", "onScrolledIndexChanged"] }, { kind: "component", type: AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "component", type: AXPAvatarComponent, selector: "axp-avatar", inputs: ["size", "src", "fullName", "showTitle", "fallbackText", "placeholder"] }, { kind: "component", type: AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "component", type: AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type:
|
|
2421
|
+
`, isInline: true, styles: [":host{display:block}.new-conversation-panel{display:flex;flex-direction:column;width:100%;overflow:hidden}.new-conversation-dialog-content{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column;gap:.75rem}.form-field--grow{flex:1;min-height:0;display:flex;flex-direction:column}.form-field{display:flex;flex-direction:column;gap:.35rem}.users-list-wrap{display:flex;flex-direction:column;height:min(50vh,36rem);overflow:hidden}.users-list-search{flex:0 0 auto;padding:.5rem .75rem;border-bottom:1px solid rgb(var(--ax-sys-color-border-light-surface));background:rgb(var(--ax-sys-color-lighter-surface))}.users-list{display:block;flex:1 1 auto;min-height:0}.user-item-content{display:flex;align-items:center;gap:.75rem;height:100%;padding:.5rem .75rem;min-width:0}.user-item-text{display:flex;flex-direction:column;justify-content:center;min-width:0;flex:1;gap:.125rem}.user-name-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:500;color:rgb(var(--ax-sys-color-on-surface))}.user-description-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:400;opacity:.72;color:rgb(var(--ax-sys-color-on-surface))}.users-list-empty{padding:1rem;text-align:center;font-size:.85rem;opacity:.7}.user-item-skeleton{display:flex;align-items:center;gap:.75rem;height:60px;padding:.5rem 1.25rem;min-width:0}.skeleton-avatar{flex:0 0 auto;width:3rem;height:3rem;border-radius:9999px}.skeleton-text{display:flex;flex-direction:column;min-width:0;flex:1;gap:.5rem}.skeleton-name{height:1rem;width:60%;border-radius:.25rem}.skeleton-description{height:.75rem;width:40%;border-radius:.25rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXListComponent, selector: "ax-list", inputs: ["id", "name", "disabled", "readonly", "valueField", "textField", "textTemplate", "disabledField", "multiple", "selectionMode", "isItemTruncated", "showItemTooltip", "dataSource", "itemHeight", "itemTemplate", "emptyTemplate", "loadingTemplate", "checkbox"], outputs: ["onValueChanged", "disabledChange", "readonlyChange", "onBlur", "onFocus", "onItemClick", "onItemSelected", "onScrolledIndexChanged"] }, { kind: "component", type: AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "component", type: AXPAvatarComponent, selector: "axp-avatar", inputs: ["size", "src", "fullName", "showTitle", "fallbackText", "placeholder", "loading"] }, { kind: "component", type: AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "component", type: AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i7.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1768
2422
|
}
|
|
1769
2423
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMChatWithAssistDialogComponent, decorators: [{
|
|
1770
2424
|
type: Component,
|
|
@@ -1877,6 +2531,67 @@ const AXM_CHAT_SIDEBAR_ASSIST_ACTION_PROVIDERS = [
|
|
|
1877
2531
|
},
|
|
1878
2532
|
];
|
|
1879
2533
|
|
|
2534
|
+
//#region ----- Imports -----
|
|
2535
|
+
//#endregion
|
|
2536
|
+
//#region ----- Service -----
|
|
2537
|
+
/**
|
|
2538
|
+
* Opens the shared mini-chat overlay with caller-supplied assist context.
|
|
2539
|
+
* Same panel as the header inbox so streaming and route persistence stay aligned.
|
|
2540
|
+
*/
|
|
2541
|
+
class AXMContextualAssistLauncherService {
|
|
2542
|
+
constructor() {
|
|
2543
|
+
//#region ----- Services & Dependencies -----
|
|
2544
|
+
this.panelService = inject(AXMMiniChatPanelService);
|
|
2545
|
+
}
|
|
2546
|
+
//#endregion
|
|
2547
|
+
//#region ----- Public API -----
|
|
2548
|
+
isOpen() {
|
|
2549
|
+
return this.panelService.isOpen();
|
|
2550
|
+
}
|
|
2551
|
+
/** True while the window is on screen (a retained hidden window is not visible). */
|
|
2552
|
+
isVisible() {
|
|
2553
|
+
return this.panelService.isVisible();
|
|
2554
|
+
}
|
|
2555
|
+
async open(context, options) {
|
|
2556
|
+
const launchContext = axmSanitizeContextualAssistContext(context);
|
|
2557
|
+
const assistId = options?.assistId?.trim();
|
|
2558
|
+
const entityRef = axmEntityRefFromLaunchContext(launchContext);
|
|
2559
|
+
await this.panelService.open({
|
|
2560
|
+
...(entityRef
|
|
2561
|
+
? { scope: 'entity', entityId: entityRef.entityId, entityType: entityRef.entityType }
|
|
2562
|
+
: { scope: 'inbox' }),
|
|
2563
|
+
forceNewChat: options?.forceNewChat ?? true,
|
|
2564
|
+
showInfoBar: false,
|
|
2565
|
+
showComposer: true,
|
|
2566
|
+
launchContext,
|
|
2567
|
+
...(assistId ? { assistId } : {}),
|
|
2568
|
+
...(options?.assistSelection ? { assistSelection: options.assistSelection } : {}),
|
|
2569
|
+
...(options?.minimizable != null ? { minimizable: options.minimizable } : {}),
|
|
2570
|
+
...(options?.retainOnClose != null ? { retainOnClose: options.retainOnClose } : {}),
|
|
2571
|
+
});
|
|
2572
|
+
}
|
|
2573
|
+
/** Hides a retained window, or destroys the window when retention is off. */
|
|
2574
|
+
dismiss() {
|
|
2575
|
+
this.panelService.dismiss();
|
|
2576
|
+
}
|
|
2577
|
+
/** Closes the panel when it is open; otherwise opens it (restores the last thread). */
|
|
2578
|
+
async toggle(context, options) {
|
|
2579
|
+
if (this.isOpen()) {
|
|
2580
|
+
this.close();
|
|
2581
|
+
return;
|
|
2582
|
+
}
|
|
2583
|
+
await this.open(context, { ...options, forceNewChat: false });
|
|
2584
|
+
}
|
|
2585
|
+
close() {
|
|
2586
|
+
this.panelService.close();
|
|
2587
|
+
}
|
|
2588
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMContextualAssistLauncherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2589
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMContextualAssistLauncherService }); }
|
|
2590
|
+
}
|
|
2591
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMContextualAssistLauncherService, decorators: [{
|
|
2592
|
+
type: Injectable
|
|
2593
|
+
}] });
|
|
2594
|
+
|
|
1880
2595
|
class AXEAIConversationExtensionModule {
|
|
1881
2596
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEAIConversationExtensionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1882
2597
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXEAIConversationExtensionModule, imports: [i1$1.AXPComponentSlotModule] }); }
|
|
@@ -1904,6 +2619,7 @@ class AXEAIConversationExtensionModule {
|
|
|
1904
2619
|
...AXE_MINI_CHAT_INBOX_FILTER_PROVIDERS,
|
|
1905
2620
|
...AXE_ASSIST_DEFAULT_RESOLVER_PROVIDERS,
|
|
1906
2621
|
...AXM_CHAT_SIDEBAR_ASSIST_ACTION_PROVIDERS,
|
|
2622
|
+
AXMContextualAssistLauncherService,
|
|
1907
2623
|
provideAppStartUpTask(() => {
|
|
1908
2624
|
const launcher = inject(AXMChatAssistLauncherService);
|
|
1909
2625
|
return {
|
|
@@ -1917,11 +2633,11 @@ class AXEAIConversationExtensionModule {
|
|
|
1917
2633
|
provideCommandSetups([
|
|
1918
2634
|
{
|
|
1919
2635
|
key: CONVERSATION_START_ASSIST_CHAT_COMMAND,
|
|
1920
|
-
command: () => import('./acorex-platform-extension-ai-conversation-client-start-assist-chat.command-
|
|
2636
|
+
command: () => import('./acorex-platform-extension-ai-conversation-client-start-assist-chat.command-zQPeOCRi.mjs').then((m) => m.AXMConversationStartAssistChatCommand),
|
|
1921
2637
|
},
|
|
1922
2638
|
{
|
|
1923
2639
|
key: CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND,
|
|
1924
|
-
command: () => import('./acorex-platform-extension-ai-conversation-client-send-assist-chat-message.command-
|
|
2640
|
+
command: () => import('./acorex-platform-extension-ai-conversation-client-send-assist-chat-message.command-B6QodNVg.mjs').then((m) => m.AXMConversationSendAssistChatMessageCommand),
|
|
1925
2641
|
},
|
|
1926
2642
|
]),
|
|
1927
2643
|
], imports: [AXPComponentSlotModule.forChild({
|
|
@@ -1932,6 +2648,13 @@ class AXEAIConversationExtensionModule {
|
|
|
1932
2648
|
component: AXMMiniChatHeaderSlotComponent,
|
|
1933
2649
|
},
|
|
1934
2650
|
],
|
|
2651
|
+
'root-footer-end': [
|
|
2652
|
+
{
|
|
2653
|
+
priority: 5,
|
|
2654
|
+
name: 'conversation-mini-chat-dock',
|
|
2655
|
+
component: AXMMiniChatFooterDockComponent,
|
|
2656
|
+
},
|
|
2657
|
+
],
|
|
1935
2658
|
})] }); }
|
|
1936
2659
|
}
|
|
1937
2660
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXEAIConversationExtensionModule, decorators: [{
|
|
@@ -1946,6 +2669,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
1946
2669
|
component: AXMMiniChatHeaderSlotComponent,
|
|
1947
2670
|
},
|
|
1948
2671
|
],
|
|
2672
|
+
'root-footer-end': [
|
|
2673
|
+
{
|
|
2674
|
+
priority: 5,
|
|
2675
|
+
name: 'conversation-mini-chat-dock',
|
|
2676
|
+
component: AXMMiniChatFooterDockComponent,
|
|
2677
|
+
},
|
|
2678
|
+
],
|
|
1949
2679
|
}),
|
|
1950
2680
|
],
|
|
1951
2681
|
providers: [
|
|
@@ -1972,6 +2702,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
1972
2702
|
...AXE_MINI_CHAT_INBOX_FILTER_PROVIDERS,
|
|
1973
2703
|
...AXE_ASSIST_DEFAULT_RESOLVER_PROVIDERS,
|
|
1974
2704
|
...AXM_CHAT_SIDEBAR_ASSIST_ACTION_PROVIDERS,
|
|
2705
|
+
AXMContextualAssistLauncherService,
|
|
1975
2706
|
provideAppStartUpTask(() => {
|
|
1976
2707
|
const launcher = inject(AXMChatAssistLauncherService);
|
|
1977
2708
|
return {
|
|
@@ -1985,11 +2716,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
1985
2716
|
provideCommandSetups([
|
|
1986
2717
|
{
|
|
1987
2718
|
key: CONVERSATION_START_ASSIST_CHAT_COMMAND,
|
|
1988
|
-
command: () => import('./acorex-platform-extension-ai-conversation-client-start-assist-chat.command-
|
|
2719
|
+
command: () => import('./acorex-platform-extension-ai-conversation-client-start-assist-chat.command-zQPeOCRi.mjs').then((m) => m.AXMConversationStartAssistChatCommand),
|
|
1989
2720
|
},
|
|
1990
2721
|
{
|
|
1991
2722
|
key: CONVERSATION_SEND_ASSIST_CHAT_MESSAGE_COMMAND,
|
|
1992
|
-
command: () => import('./acorex-platform-extension-ai-conversation-client-send-assist-chat-message.command-
|
|
2723
|
+
command: () => import('./acorex-platform-extension-ai-conversation-client-send-assist-chat-message.command-B6QodNVg.mjs').then((m) => m.AXMConversationSendAssistChatMessageCommand),
|
|
1993
2724
|
},
|
|
1994
2725
|
]),
|
|
1995
2726
|
],
|
|
@@ -2000,5 +2731,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
2000
2731
|
* Generated bundle index. Do not edit.
|
|
2001
2732
|
*/
|
|
2002
2733
|
|
|
2003
|
-
export { AXMChatAssistLauncherService as A, AXCConversationAssistResponseService as a, AXEAIConversationExtensionModule as b, AXEConversationAssistResponseService as c };
|
|
2004
|
-
//# sourceMappingURL=acorex-platform-extension-ai-conversation-client-acorex-platform-extension-ai-conversation-client-
|
|
2734
|
+
export { AXMChatAssistLauncherService as A, AXCConversationAssistResponseService as a, AXEAIConversationExtensionModule as b, AXEConversationAssistResponseService as c, AXMContextualAssistLauncherService as d };
|
|
2735
|
+
//# sourceMappingURL=acorex-platform-extension-ai-conversation-client-acorex-platform-extension-ai-conversation-client-DfdGeEG4.mjs.map
|