@praxisui/ai 8.0.0-beta.25 → 8.0.0-beta.27
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/praxisui-ai.mjs +335 -9
- package/index.d.ts +28 -2
- package/package.json +2 -2
package/fesm2022/praxisui-ai.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Component, Injectable, InjectionToken, Optional, Inject, inject, signal, computed, ChangeDetectorRef, ElementRef, ViewChild, Input, ChangeDetectionStrategy, EventEmitter, Output } from '@angular/core';
|
|
3
3
|
import { SchemaType, GoogleGenerativeAI } from '@google/generative-ai';
|
|
4
|
-
import { throwError, from, Observable, of, BehaviorSubject, tap, map as map$1, isObservable, firstValueFrom } from 'rxjs';
|
|
4
|
+
import { throwError, from, Observable, of, BehaviorSubject, tap, map as map$1, catchError as catchError$1, isObservable, firstValueFrom } from 'rxjs';
|
|
5
5
|
import { map, catchError, filter, take } from 'rxjs/operators';
|
|
6
6
|
import { HttpClient, HttpParams, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
|
|
7
7
|
import * as i3 from '@angular/common';
|
|
@@ -451,6 +451,125 @@ class BaseAiAdapter {
|
|
|
451
451
|
}
|
|
452
452
|
}
|
|
453
453
|
|
|
454
|
+
const GOVERNED_DECISION_TERMS = [
|
|
455
|
+
'regra',
|
|
456
|
+
'politica',
|
|
457
|
+
'policy',
|
|
458
|
+
'compliance',
|
|
459
|
+
'lgpd',
|
|
460
|
+
'privacidade',
|
|
461
|
+
'aprovacao',
|
|
462
|
+
'aprovar',
|
|
463
|
+
'publicar',
|
|
464
|
+
'materializar',
|
|
465
|
+
'enforcement',
|
|
466
|
+
'validacao de negocio',
|
|
467
|
+
'validar negocio',
|
|
468
|
+
'elegibilidade',
|
|
469
|
+
'permissao',
|
|
470
|
+
'acesso',
|
|
471
|
+
];
|
|
472
|
+
const LOCAL_COMPOSITION_SCOPE_TERMS = [
|
|
473
|
+
'local/editorial',
|
|
474
|
+
'local editorial',
|
|
475
|
+
'conteudo local',
|
|
476
|
+
'conteudo editorial',
|
|
477
|
+
'dados locais',
|
|
478
|
+
'apenas editorial',
|
|
479
|
+
'apenas visual',
|
|
480
|
+
'somente visual',
|
|
481
|
+
'so visual',
|
|
482
|
+
'exemplo visual',
|
|
483
|
+
'cards de exemplo',
|
|
484
|
+
'lista de exemplo',
|
|
485
|
+
'ficticio',
|
|
486
|
+
'ficticia',
|
|
487
|
+
'ficticias',
|
|
488
|
+
'demo',
|
|
489
|
+
'demonstracao',
|
|
490
|
+
'exemplo',
|
|
491
|
+
'sem api real',
|
|
492
|
+
'sem conectar api',
|
|
493
|
+
'sem schema externo',
|
|
494
|
+
'sem criar regra',
|
|
495
|
+
'sem regra de negocio',
|
|
496
|
+
'nao criar regra',
|
|
497
|
+
'nao e regra',
|
|
498
|
+
'nao alterar regra',
|
|
499
|
+
'nao alterar politica',
|
|
500
|
+
'sem criar regra de negocio',
|
|
501
|
+
];
|
|
502
|
+
const DEFAULT_LOCAL_COMPOSITION_TERMS = [
|
|
503
|
+
'pagina',
|
|
504
|
+
'page',
|
|
505
|
+
'widget',
|
|
506
|
+
'widgets',
|
|
507
|
+
'tela',
|
|
508
|
+
'dashboard',
|
|
509
|
+
'layout',
|
|
510
|
+
'visual',
|
|
511
|
+
'editorial',
|
|
512
|
+
'formulario',
|
|
513
|
+
'form',
|
|
514
|
+
'campo',
|
|
515
|
+
'campos',
|
|
516
|
+
'secao',
|
|
517
|
+
'secoes',
|
|
518
|
+
'abas',
|
|
519
|
+
'aba',
|
|
520
|
+
'tabs',
|
|
521
|
+
'tab',
|
|
522
|
+
'lista',
|
|
523
|
+
'list',
|
|
524
|
+
'card',
|
|
525
|
+
'cards',
|
|
526
|
+
'item',
|
|
527
|
+
'itens',
|
|
528
|
+
'tabela',
|
|
529
|
+
'table',
|
|
530
|
+
'crud',
|
|
531
|
+
'coluna',
|
|
532
|
+
'colunas',
|
|
533
|
+
'acoes',
|
|
534
|
+
'sla',
|
|
535
|
+
'status',
|
|
536
|
+
'stepper',
|
|
537
|
+
'etapa',
|
|
538
|
+
'etapas',
|
|
539
|
+
'painel',
|
|
540
|
+
'paineis',
|
|
541
|
+
'expansion',
|
|
542
|
+
'accordion',
|
|
543
|
+
'acordeao',
|
|
544
|
+
'texto',
|
|
545
|
+
'subtitulo',
|
|
546
|
+
'conteudo',
|
|
547
|
+
];
|
|
548
|
+
function shouldRoutePromptToGovernedDecision(prompt, contextHints, options = {}) {
|
|
549
|
+
const normalized = normalizeAuthoringPrompt(prompt);
|
|
550
|
+
if (isExplicitLocalCompositionPrompt(normalized, options.localCompositionTerms)) {
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
const recommendedFlow = toRecord(contextHints?.['domainCatalog'])?.['recommendedAuthoringFlow'];
|
|
554
|
+
if (recommendedFlow === 'shared_rule_authoring')
|
|
555
|
+
return true;
|
|
556
|
+
return GOVERNED_DECISION_TERMS.some((term) => normalized.includes(term));
|
|
557
|
+
}
|
|
558
|
+
function normalizeAuthoringPrompt(prompt) {
|
|
559
|
+
return prompt.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
|
|
560
|
+
}
|
|
561
|
+
function isExplicitLocalCompositionPrompt(normalizedPrompt, localCompositionTerms = DEFAULT_LOCAL_COMPOSITION_TERMS) {
|
|
562
|
+
const hasLocalScope = LOCAL_COMPOSITION_SCOPE_TERMS.some((term) => normalizedPrompt.includes(term));
|
|
563
|
+
if (!hasLocalScope)
|
|
564
|
+
return false;
|
|
565
|
+
return localCompositionTerms.some((term) => normalizedPrompt.includes(term));
|
|
566
|
+
}
|
|
567
|
+
function toRecord(value) {
|
|
568
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
569
|
+
? value
|
|
570
|
+
: null;
|
|
571
|
+
}
|
|
572
|
+
|
|
454
573
|
class SchemaMinifierService {
|
|
455
574
|
/**
|
|
456
575
|
* Converts complete FieldSchemas into a minified version for AI context (Token optimized)
|
|
@@ -1015,7 +1134,7 @@ class AiBackendApiService {
|
|
|
1015
1134
|
}
|
|
1016
1135
|
getPatch(request) {
|
|
1017
1136
|
const normalizedRequest = {
|
|
1018
|
-
...request,
|
|
1137
|
+
...this.normalizeLegacyPatchConversationIds(request),
|
|
1019
1138
|
contractVersion: this.normalizeContractVersion(request.contractVersion),
|
|
1020
1139
|
schemaHash: this.normalizeContractSchemaHash(request.schemaHash),
|
|
1021
1140
|
};
|
|
@@ -1028,7 +1147,7 @@ class AiBackendApiService {
|
|
|
1028
1147
|
}
|
|
1029
1148
|
startPatchStream(request) {
|
|
1030
1149
|
const normalizedRequest = {
|
|
1031
|
-
...request,
|
|
1150
|
+
...this.normalizeLegacyPatchConversationIds(request),
|
|
1032
1151
|
contractVersion: this.normalizeContractVersion(request.contractVersion),
|
|
1033
1152
|
schemaHash: this.normalizeContractSchemaHash(request.schemaHash),
|
|
1034
1153
|
};
|
|
@@ -1286,6 +1405,20 @@ class AiBackendApiService {
|
|
|
1286
1405
|
}
|
|
1287
1406
|
return AI_INTENT_CONTRACT_SCHEMA_HASH;
|
|
1288
1407
|
}
|
|
1408
|
+
normalizeLegacyPatchConversationIds(request) {
|
|
1409
|
+
const normalized = { ...request };
|
|
1410
|
+
if (!this.isUuid(normalized.sessionId)) {
|
|
1411
|
+
delete normalized.sessionId;
|
|
1412
|
+
}
|
|
1413
|
+
if (!this.isUuid(normalized.clientTurnId)) {
|
|
1414
|
+
delete normalized.clientTurnId;
|
|
1415
|
+
}
|
|
1416
|
+
return normalized;
|
|
1417
|
+
}
|
|
1418
|
+
isUuid(value) {
|
|
1419
|
+
return typeof value === 'string'
|
|
1420
|
+
&& /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value.trim());
|
|
1421
|
+
}
|
|
1289
1422
|
authoringManifestUrl(componentId) {
|
|
1290
1423
|
return `${this.baseUrl}/authoring/manifests/${encodeURIComponent(componentId)}`;
|
|
1291
1424
|
}
|
|
@@ -1986,8 +2119,18 @@ class PraxisAssistantTurnController {
|
|
|
1986
2119
|
if (!handler) {
|
|
1987
2120
|
return of(this.snapshot());
|
|
1988
2121
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
2122
|
+
let flowResult;
|
|
2123
|
+
try {
|
|
2124
|
+
flowResult = handler.call(this.flow, request);
|
|
2125
|
+
}
|
|
2126
|
+
catch (error) {
|
|
2127
|
+
this.applyResult(this.buildFlowErrorResult(error));
|
|
2128
|
+
return of(this.snapshot());
|
|
2129
|
+
}
|
|
2130
|
+
return this.toObservable(flowResult).pipe(tap((result) => this.applyResult(result)), map$1(() => this.snapshot()), catchError$1((error) => {
|
|
2131
|
+
this.applyResult(this.buildFlowErrorResult(error));
|
|
2132
|
+
return of(this.snapshot());
|
|
2133
|
+
}));
|
|
1991
2134
|
}
|
|
1992
2135
|
buildRequest(partial) {
|
|
1993
2136
|
const current = this.stateSubject.value;
|
|
@@ -2181,6 +2324,59 @@ class PraxisAssistantTurnController {
|
|
|
2181
2324
|
toObservable(value) {
|
|
2182
2325
|
return isObservable(value) ? value : from(value);
|
|
2183
2326
|
}
|
|
2327
|
+
buildFlowErrorResult(error) {
|
|
2328
|
+
const detail = this.describeFlowError(error);
|
|
2329
|
+
const message = detail
|
|
2330
|
+
? `The assistant could not finish this request. ${detail}`
|
|
2331
|
+
: 'The assistant could not finish this request. Try again or review the active context.';
|
|
2332
|
+
return {
|
|
2333
|
+
state: 'error',
|
|
2334
|
+
phase: this.stateSubject.value.phase,
|
|
2335
|
+
assistantMessage: message,
|
|
2336
|
+
errorText: message,
|
|
2337
|
+
canApply: this.stateSubject.value.canApply,
|
|
2338
|
+
diagnostics: {
|
|
2339
|
+
error: this.serializeFlowError(error),
|
|
2340
|
+
},
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2343
|
+
describeFlowError(error) {
|
|
2344
|
+
const record = this.toRecord(error);
|
|
2345
|
+
const status = this.toNumber(record?.['status']);
|
|
2346
|
+
const statusText = this.toString(record?.['statusText']);
|
|
2347
|
+
const message = this.toString(record?.['message']);
|
|
2348
|
+
if (status || statusText) {
|
|
2349
|
+
return `Request failed${status ? ` with HTTP ${status}` : ''}${statusText ? ` (${statusText})` : ''}.`;
|
|
2350
|
+
}
|
|
2351
|
+
if (message) {
|
|
2352
|
+
return message;
|
|
2353
|
+
}
|
|
2354
|
+
return '';
|
|
2355
|
+
}
|
|
2356
|
+
serializeFlowError(error) {
|
|
2357
|
+
const record = this.toRecord(error);
|
|
2358
|
+
if (!record) {
|
|
2359
|
+
return { message: String(error ?? 'unknown') };
|
|
2360
|
+
}
|
|
2361
|
+
return {
|
|
2362
|
+
name: this.toString(record['name']) || undefined,
|
|
2363
|
+
message: this.toString(record['message']) || undefined,
|
|
2364
|
+
status: this.toNumber(record['status']) ?? undefined,
|
|
2365
|
+
statusText: this.toString(record['statusText']) || undefined,
|
|
2366
|
+
url: this.toString(record['url']) || undefined,
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
toRecord(value) {
|
|
2370
|
+
return value && typeof value === 'object'
|
|
2371
|
+
? value
|
|
2372
|
+
: null;
|
|
2373
|
+
}
|
|
2374
|
+
toString(value) {
|
|
2375
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
2376
|
+
}
|
|
2377
|
+
toNumber(value) {
|
|
2378
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
2379
|
+
}
|
|
2184
2380
|
}
|
|
2185
2381
|
|
|
2186
2382
|
class PraxisAssistantSessionRegistryService {
|
|
@@ -6819,7 +7015,13 @@ class PraxisAiAssistantShellComponent {
|
|
|
6819
7015
|
getQuickReplyAriaLabel(reply) {
|
|
6820
7016
|
const label = reply.label?.trim() ?? '';
|
|
6821
7017
|
const description = reply.description?.trim();
|
|
6822
|
-
|
|
7018
|
+
const presentation = this.getQuickReplyPresentationItems(reply)
|
|
7019
|
+
.map((item) => `${item.label}: ${item.value}`)
|
|
7020
|
+
.join('. ');
|
|
7021
|
+
return [label, description, presentation]
|
|
7022
|
+
.filter((segment) => typeof segment === 'string' && segment.length > 0)
|
|
7023
|
+
.map((segment) => this.trimSentencePunctuation(segment))
|
|
7024
|
+
.join('. ');
|
|
6823
7025
|
}
|
|
6824
7026
|
getQuickReplyTechnicalDetails(reply) {
|
|
6825
7027
|
const hints = reply.contextHints;
|
|
@@ -6836,6 +7038,127 @@ class PraxisAiAssistantShellComponent {
|
|
|
6836
7038
|
schemaUrl ? `Schema: ${schemaUrl}` : '',
|
|
6837
7039
|
].filter(Boolean).join('\n');
|
|
6838
7040
|
}
|
|
7041
|
+
getQuickReplyPresentationItems(reply) {
|
|
7042
|
+
const hints = reply.contextHints;
|
|
7043
|
+
const presentation = this.asRecord(hints?.['presentation']);
|
|
7044
|
+
const resolvedPresentation = presentation ?? this.defaultQuickReplyPresentation(reply);
|
|
7045
|
+
if (!resolvedPresentation)
|
|
7046
|
+
return [];
|
|
7047
|
+
const items = [
|
|
7048
|
+
{
|
|
7049
|
+
key: 'bestFor',
|
|
7050
|
+
label: 'Indicado para',
|
|
7051
|
+
icon: 'ads_click',
|
|
7052
|
+
value: this.stringHint(resolvedPresentation, 'bestFor'),
|
|
7053
|
+
},
|
|
7054
|
+
{
|
|
7055
|
+
key: 'returns',
|
|
7056
|
+
label: 'Retorna',
|
|
7057
|
+
icon: 'stacked_line_chart',
|
|
7058
|
+
value: this.stringHint(resolvedPresentation, 'returns'),
|
|
7059
|
+
},
|
|
7060
|
+
{
|
|
7061
|
+
key: 'nextStep',
|
|
7062
|
+
label: 'Próximo passo',
|
|
7063
|
+
icon: 'arrow_forward',
|
|
7064
|
+
value: this.stringHint(resolvedPresentation, 'nextStep'),
|
|
7065
|
+
},
|
|
7066
|
+
];
|
|
7067
|
+
return items.filter((item) => item.value.length > 0);
|
|
7068
|
+
}
|
|
7069
|
+
defaultQuickReplyPresentation(reply) {
|
|
7070
|
+
const kind = (reply.kind || reply.tone || '').toLowerCase();
|
|
7071
|
+
switch (kind) {
|
|
7072
|
+
case 'confirm':
|
|
7073
|
+
case 'primary':
|
|
7074
|
+
case 'analytics':
|
|
7075
|
+
return {
|
|
7076
|
+
bestFor: 'Validar a recomendação antes de salvar ou materializar a página.',
|
|
7077
|
+
returns: 'Uma prévia governada com layout, widgets e sinais de decisão.',
|
|
7078
|
+
nextStep: 'Abra a prévia e revise se a composição atende ao objetivo.',
|
|
7079
|
+
};
|
|
7080
|
+
case 'resource':
|
|
7081
|
+
case 'suggestion':
|
|
7082
|
+
return {
|
|
7083
|
+
bestFor: 'Explorar uma fonte de dados candidata para gráficos e indicadores.',
|
|
7084
|
+
returns: 'Campos, métricas prováveis e caminhos de drill-down disponíveis.',
|
|
7085
|
+
nextStep: 'Clique para usar esta fonte como contexto da próxima decisão.',
|
|
7086
|
+
};
|
|
7087
|
+
case 'revise':
|
|
7088
|
+
case 'warning':
|
|
7089
|
+
return {
|
|
7090
|
+
bestFor: 'Ajustar objetivo, escopo, dados ou métricas antes de gerar a prévia.',
|
|
7091
|
+
returns: 'Um pedido mais preciso, com menos ambiguidade para a IA.',
|
|
7092
|
+
nextStep: 'Refine a intenção e rode novamente quando estiver claro.',
|
|
7093
|
+
};
|
|
7094
|
+
default:
|
|
7095
|
+
return null;
|
|
7096
|
+
}
|
|
7097
|
+
}
|
|
7098
|
+
getQuickReplyCategoryLabel(reply) {
|
|
7099
|
+
const kind = (reply.kind || reply.tone || '').toLowerCase();
|
|
7100
|
+
switch (kind) {
|
|
7101
|
+
case 'confirm':
|
|
7102
|
+
case 'primary':
|
|
7103
|
+
case 'analytics':
|
|
7104
|
+
return 'Recomendado';
|
|
7105
|
+
case 'revise':
|
|
7106
|
+
case 'warning':
|
|
7107
|
+
return 'Ajustar antes';
|
|
7108
|
+
case 'resource':
|
|
7109
|
+
case 'suggestion':
|
|
7110
|
+
return 'Fonte candidata';
|
|
7111
|
+
case 'success':
|
|
7112
|
+
return 'Pronto para usar';
|
|
7113
|
+
case 'cancel':
|
|
7114
|
+
case 'danger':
|
|
7115
|
+
return 'Encerrar';
|
|
7116
|
+
default:
|
|
7117
|
+
return 'Opção guiada';
|
|
7118
|
+
}
|
|
7119
|
+
}
|
|
7120
|
+
getQuickReplyIcon(reply) {
|
|
7121
|
+
const explicitIcon = reply.icon?.trim();
|
|
7122
|
+
if (explicitIcon)
|
|
7123
|
+
return explicitIcon;
|
|
7124
|
+
const kind = (reply.kind || reply.tone || '').toLowerCase();
|
|
7125
|
+
switch (kind) {
|
|
7126
|
+
case 'confirm':
|
|
7127
|
+
case 'primary':
|
|
7128
|
+
return 'auto_awesome';
|
|
7129
|
+
case 'analytics':
|
|
7130
|
+
return 'query_stats';
|
|
7131
|
+
case 'resource':
|
|
7132
|
+
case 'suggestion':
|
|
7133
|
+
return 'dataset';
|
|
7134
|
+
case 'revise':
|
|
7135
|
+
case 'warning':
|
|
7136
|
+
return 'tune';
|
|
7137
|
+
case 'cancel':
|
|
7138
|
+
case 'danger':
|
|
7139
|
+
return 'close';
|
|
7140
|
+
case 'success':
|
|
7141
|
+
return 'check_circle';
|
|
7142
|
+
default:
|
|
7143
|
+
return 'touch_app';
|
|
7144
|
+
}
|
|
7145
|
+
}
|
|
7146
|
+
getQuickReplyCtaLabel(reply) {
|
|
7147
|
+
const kind = (reply.kind || reply.tone || '').toLowerCase();
|
|
7148
|
+
switch (kind) {
|
|
7149
|
+
case 'revise':
|
|
7150
|
+
case 'warning':
|
|
7151
|
+
return 'Refinar';
|
|
7152
|
+
case 'cancel':
|
|
7153
|
+
case 'danger':
|
|
7154
|
+
return 'Cancelar';
|
|
7155
|
+
case 'resource':
|
|
7156
|
+
case 'suggestion':
|
|
7157
|
+
return 'Explorar';
|
|
7158
|
+
default:
|
|
7159
|
+
return 'Usar esta opção';
|
|
7160
|
+
}
|
|
7161
|
+
}
|
|
6839
7162
|
getQuickReplyTone(reply) {
|
|
6840
7163
|
const tone = (reply.tone || reply.kind || 'neutral').toLowerCase();
|
|
6841
7164
|
switch (tone) {
|
|
@@ -6867,6 +7190,9 @@ class PraxisAiAssistantShellComponent {
|
|
|
6867
7190
|
const value = source[key];
|
|
6868
7191
|
return typeof value === 'string' ? value.trim() : '';
|
|
6869
7192
|
}
|
|
7193
|
+
trimSentencePunctuation(value) {
|
|
7194
|
+
return value.trim().replace(/[.!?]+$/u, '');
|
|
7195
|
+
}
|
|
6870
7196
|
getCloseIcon() {
|
|
6871
7197
|
const label = this.resolvedLabels.close.toLocaleLowerCase('pt-BR');
|
|
6872
7198
|
return label.includes('minimiz') ? 'remove' : 'close';
|
|
@@ -7184,7 +7510,7 @@ class PraxisAiAssistantShellComponent {
|
|
|
7184
7510
|
this.ownedPreviewUrls.delete(previewUrl);
|
|
7185
7511
|
}
|
|
7186
7512
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisAiAssistantShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7187
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisAiAssistantShellComponent, isStandalone: true, selector: "praxis-ai-assistant-shell", inputs: { labels: "labels", mode: "mode", state: "state", contextItems: "contextItems", attachments: "attachments", messages: "messages", quickReplies: "quickReplies", prompt: "prompt", statusText: "statusText", errorText: "errorText", testIdPrefix: "testIdPrefix", panelTestId: "panelTestId", submitTestId: "submitTestId", applyTestId: "applyTestId", primaryAction: "primaryAction", secondaryActions: "secondaryActions", governanceActions: "governanceActions", busy: "busy", canSubmit: "canSubmit", canApply: "canApply", submitOnEnter: "submitOnEnter", showAttachAction: "showAttachAction", enablePastedAttachments: "enablePastedAttachments", enableFileAttachments: "enableFileAttachments", attachmentAccept: "attachmentAccept", attachmentMultiple: "attachmentMultiple", draggable: "draggable", resizable: "resizable", minWidth: "minWidth", minHeight: "minHeight", margin: "margin", layout: "layout" }, outputs: { promptChange: "promptChange", submitPrompt: "submitPrompt", apply: "apply", retryTurn: "retryTurn", cancelTurn: "cancelTurn", shellAction: "shellAction", close: "close", attach: "attach", attachmentsPasted: "attachmentsPasted", attachmentsSelected: "attachmentsSelected", removeAttachment: "removeAttachment", messageAction: "messageAction", editMessage: "editMessage", resendMessage: "resendMessage", quickReply: "quickReply", layoutChange: "layoutChange" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, static: true }, { propertyName: "conversation", first: true, predicate: ["conversation"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section\n #panel\n class=\"praxis-ai-assistant-shell\"\n role=\"dialog\"\n [attr.aria-label]=\"resolvedLabels.title\"\n [attr.aria-busy]=\"busy ? 'true' : null\"\n [style.left.px]=\"currentLayout.left\"\n [style.top.px]=\"currentLayout.top\"\n [style.width.px]=\"currentLayout.width\"\n [style.height.px]=\"currentLayout.height\"\n [attr.data-testid]=\"panelTestId || testIdPrefix\"\n>\n <header\n class=\"praxis-ai-assistant-shell__header\"\n [attr.data-testid]=\"testIdPrefix + '-drag-handle'\"\n [attr.aria-label]=\"resolvedLabels.dragHandleAria\"\n (pointerdown)=\"startDrag($event)\"\n >\n <div class=\"praxis-ai-assistant-shell__identity\" aria-hidden=\"true\">\n <mat-icon>auto_awesome</mat-icon>\n </div>\n <div class=\"praxis-ai-assistant-shell__title-group\">\n <div class=\"praxis-ai-assistant-shell__title-row\">\n <strong>{{ resolvedLabels.title }}</strong>\n <div class=\"praxis-ai-assistant-shell__badges\" aria-hidden=\"true\">\n <span class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--context\">\n {{ getModeLabel() }}\n </span>\n <span\n class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--state\"\n [class.praxis-ai-assistant-shell__badge--error]=\"state === 'error'\"\n >\n <span class=\"praxis-ai-assistant-shell__state-dot\" aria-hidden=\"true\"></span>\n {{ getStateLabel() }}\n </span>\n </div>\n </div>\n <p *ngIf=\"resolvedLabels.subtitle\">{{ resolvedLabels.subtitle }}</p>\n </div>\n <div class=\"praxis-ai-assistant-shell__header-actions\">\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"getResetLayoutLabel()\"\n [attr.aria-label]=\"getResetLayoutLabel()\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"resetLayout()\"\n [attr.data-testid]=\"testIdPrefix + '-reset-layout'\"\n >\n <mat-icon>center_focus_strong</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"resolvedLabels.close\"\n [attr.aria-label]=\"resolvedLabels.close\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"close.emit()\"\n [attr.data-testid]=\"testIdPrefix + '-close'\"\n >\n <mat-icon>{{ getCloseIcon() }}</mat-icon>\n </button>\n </div>\n </header>\n\n <div class=\"praxis-ai-assistant-shell__body\">\n <div\n *ngIf=\"contextItems.length\"\n class=\"praxis-ai-assistant-shell__context\"\n [attr.aria-label]=\"resolvedLabels.contextAria\"\n [attr.data-testid]=\"testIdPrefix + '-context'\"\n >\n <span\n *ngFor=\"let item of contextItems; trackBy: trackContextItem\"\n class=\"praxis-ai-assistant-shell__context-item\"\n [attr.data-testid]=\"testIdPrefix + '-context-' + item.id\"\n >\n <mat-icon *ngIf=\"item.icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__context-label\">{{ item.label }}</span>\n <span *ngIf=\"item.value\" class=\"praxis-ai-assistant-shell__context-value\">{{ item.value }}</span>\n </span>\n </div>\n\n <div\n #conversation\n class=\"praxis-ai-assistant-shell__conversation\"\n [attr.data-testid]=\"testIdPrefix + '-conversation'\"\n [attr.aria-label]=\"resolvedLabels.conversationAria\"\n >\n <article\n *ngIf=\"!messages.length\"\n class=\"praxis-ai-assistant-shell__message praxis-ai-assistant-shell__message--assistant\"\n [attr.data-testid]=\"testIdPrefix + '-message-assistant-empty'\"\n >\n {{ resolvedLabels.emptyConversation }}\n </article>\n <article\n *ngFor=\"let message of messages; trackBy: trackMessage\"\n class=\"praxis-ai-assistant-shell__message\"\n [class.praxis-ai-assistant-shell__message--user]=\"message.role === 'user'\"\n [class.praxis-ai-assistant-shell__message--assistant]=\"message.role === 'assistant'\"\n [class.praxis-ai-assistant-shell__message--status]=\"message.role === 'status'\"\n [class.praxis-ai-assistant-shell__message--error]=\"message.role === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-message-' + message.role\"\n >\n {{ message.text }}\n <div\n *ngIf=\"message.actions?.length || message.editable || message.resendable\"\n class=\"praxis-ai-assistant-shell__message-actions\"\n >\n <button\n *ngIf=\"message.editable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.editMessage\"\n [attr.aria-label]=\"resolvedLabels.editMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-edit-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'edit', label: resolvedLabels.editMessage, kind: 'edit' })\"\n >\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n <button\n *ngIf=\"message.resendable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.resendMessage\"\n [attr.aria-label]=\"resolvedLabels.resendMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-resend-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'resend', label: resolvedLabels.resendMessage, kind: 'resend' })\"\n >\n <mat-icon aria-hidden=\"true\">replay</mat-icon>\n </button>\n <ng-container *ngFor=\"let action of message.actions || []; trackBy: trackMessageAction\">\n <button\n *ngIf=\"isMessageActionIconOnly(action); else textualMessageAction\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy || action.disabled\"\n [matTooltip]=\"getMessageActionLabel(action)\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n <mat-icon aria-hidden=\"true\">{{ getMessageActionIcon(action) }}</mat-icon>\n </button>\n <ng-template #textualMessageAction>\n <button\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action\"\n [disabled]=\"busy || action.disabled\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n {{ action.label }}\n </button>\n </ng-template>\n </ng-container>\n </div>\n </article>\n </div>\n\n <div\n *ngIf=\"attachments.length\"\n class=\"praxis-ai-assistant-shell__attachments\"\n [attr.aria-label]=\"resolvedLabels.attachmentsAria\"\n [attr.data-testid]=\"testIdPrefix + '-attachments'\"\n >\n <div\n *ngFor=\"let attachment of attachments; trackBy: trackAttachment\"\n class=\"praxis-ai-assistant-shell__attachment\"\n [class.praxis-ai-assistant-shell__attachment--error]=\"attachment.status === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-' + attachment.id\"\n >\n <img\n *ngIf=\"attachment.previewUrl && attachment.kind === 'image'\"\n class=\"praxis-ai-assistant-shell__attachment-preview\"\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.name\"\n >\n <span class=\"praxis-ai-assistant-shell__attachment-name\">{{ attachment.name }}</span>\n <span class=\"praxis-ai-assistant-shell__attachment-kind\">{{ attachment.kind }}</span>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.removeAttachment\"\n [attr.aria-label]=\"resolvedLabels.removeAttachment + ': ' + attachment.name\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-remove-' + attachment.id\"\n (click)=\"onRemoveAttachment(attachment)\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div\n *ngIf=\"quickReplies.length\"\n class=\"praxis-ai-assistant-shell__quick-replies\"\n [attr.data-testid]=\"testIdPrefix + '-quick-replies'\"\n [attr.aria-label]=\"resolvedLabels.quickRepliesAria\"\n >\n <button\n *ngFor=\"let reply of quickReplies; trackBy: trackQuickReply\"\n mat-stroked-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__quick-reply\"\n [ngClass]=\"'praxis-ai-assistant-shell__quick-reply--tone-' + getQuickReplyTone(reply)\"\n [attr.data-testid]=\"testIdPrefix + '-quick-reply-' + (reply.id || reply.kind)\"\n [attr.aria-label]=\"getQuickReplyAriaLabel(reply)\"\n [disabled]=\"busy\"\n (click)=\"onQuickReply(reply)\"\n >\n <mat-icon\n *ngIf=\"reply.icon\"\n class=\"praxis-ai-assistant-shell__quick-reply-icon\"\n aria-hidden=\"true\"\n >\n {{ reply.icon }}\n </mat-icon>\n <span class=\"praxis-ai-assistant-shell__quick-reply-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-label\">{{ reply.label }}</span>\n <span\n *ngIf=\"reply.description\"\n class=\"praxis-ai-assistant-shell__quick-reply-description\"\n >\n {{ reply.description }}\n </span>\n </span>\n <mat-icon\n *ngIf=\"getQuickReplyTechnicalDetails(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-details\"\n [matTooltip]=\"getQuickReplyTechnicalDetails(reply)\"\n [attr.aria-label]=\"resolvedLabels.quickReplyDetails\"\n >\n info\n </mat-icon>\n </button>\n </div>\n <p\n *ngIf=\"statusText\"\n class=\"praxis-ai-assistant-shell__status\"\n [attr.data-testid]=\"testIdPrefix + '-status'\"\n >\n {{ statusText }}\n </p>\n <p\n *ngIf=\"errorText\"\n class=\"praxis-ai-assistant-shell__error\"\n [attr.data-testid]=\"testIdPrefix + '-error'\"\n >\n {{ errorText }}\n </p>\n </div>\n\n <footer class=\"praxis-ai-assistant-shell__footer\">\n <label class=\"praxis-ai-assistant-shell__label\" for=\"praxis-ai-assistant-shell-prompt\">\n {{ resolvedLabels.prompt }}\n </label>\n <div class=\"praxis-ai-assistant-shell__composer\">\n <textarea\n id=\"praxis-ai-assistant-shell-prompt\"\n class=\"praxis-ai-assistant-shell__prompt\"\n [attr.data-testid]=\"testIdPrefix + '-prompt'\"\n [placeholder]=\"resolvedLabels.promptPlaceholder\"\n [ngModel]=\"currentPrompt\"\n [disabled]=\"busy\"\n (ngModelChange)=\"onPromptInput($event)\"\n (keydown)=\"onPromptKeydown($event)\"\n (paste)=\"onPromptPaste($event)\"\n ></textarea>\n <div class=\"praxis-ai-assistant-shell__composer-actions\">\n <ng-container *ngIf=\"showAttachAction\">\n <input\n #attachmentInput\n type=\"file\"\n hidden\n [attr.accept]=\"attachmentAccept || null\"\n [attr.multiple]=\"attachmentMultiple ? '' : null\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-input'\"\n (change)=\"onAttachmentFilesSelected($event)\"\n >\n <button\n mat-stroked-button\n type=\"button\"\n [disabled]=\"busy\"\n (click)=\"onAttachClick(attachmentInput)\"\n [attr.data-testid]=\"testIdPrefix + '-attach'\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ resolvedLabels.attach }}\n </button>\n </ng-container>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--primary\"\n [class.praxis-ai-assistant-shell__action--icon-only]=\"getPrimaryAction().iconOnly\"\n [matTooltip]=\"getPrimaryActionTooltip(getPrimaryAction())\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(getPrimaryAction())\"\n [disabled]=\"isShellActionDisabled(getPrimaryAction())\"\n (click)=\"onShellAction(getPrimaryAction())\"\n [attr.data-testid]=\"getPrimaryAction().testId || (submitTestId || (testIdPrefix + '-submit'))\"\n [attr.aria-label]=\"getPrimaryAction().ariaLabel || getPrimaryAction().label\"\n >\n <mat-icon *ngIf=\"getPrimaryAction().icon\" aria-hidden=\"true\">{{ getPrimaryAction().icon }}</mat-icon>\n <span *ngIf=\"!getPrimaryAction().iconOnly\">{{ getPrimaryAction().label }}</span>\n </button>\n <button\n *ngFor=\"let action of getSecondaryActions(); trackBy: trackShellAction\"\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--secondary\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(action)\"\n [disabled]=\"isShellActionDisabled(action)\"\n (click)=\"onShellAction(action)\"\n [attr.data-testid]=\"action.testId || (testIdPrefix + '-action-' + action.id)\"\n [attr.aria-label]=\"action.ariaLabel || action.label\"\n >\n <mat-icon *ngIf=\"action.icon\" aria-hidden=\"true\">{{ action.icon }}</mat-icon>\n {{ action.label }}\n </button>\n <mat-spinner *ngIf=\"busy\" diameter=\"20\" [attr.data-testid]=\"testIdPrefix + '-spinner'\"></mat-spinner>\n </div>\n </div>\n </footer>\n\n <ng-container *ngIf=\"resizable\">\n <span\n *ngFor=\"let direction of resizeHandles; trackBy: trackResizeHandle\"\n class=\"praxis-ai-assistant-shell__resize-handle praxis-ai-assistant-shell__resize-handle--{{ direction }}\"\n [attr.data-testid]=\"direction === 'se' ? testIdPrefix + '-resize-handle' : testIdPrefix + '-resize-handle-' + direction\"\n aria-hidden=\"true\"\n role=\"presentation\"\n (pointerdown)=\"startResize(direction, $event)\"\n ></span>\n </ng-container>\n</section>\n", styles: [":host{display:block}.praxis-ai-assistant-shell{position:fixed;box-sizing:border-box;min-width:360px;min-height:360px;display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface, #f8fafc);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface, #0f172a);box-shadow:0 24px 60px #0006;z-index:var(--praxis-ai-assistant-shell-z-index, 1200)}.praxis-ai-assistant-shell__header{flex:0 0 auto;display:flex;align-items:flex-start;gap:9px;padding:10px 10px 9px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 72%,transparent);background:var(--md-sys-color-surface-container, #172033)}.praxis-ai-assistant-shell__header{justify-content:flex-start;border-bottom:1px solid;cursor:move;touch-action:none}.praxis-ai-assistant-shell__identity{flex:0 0 auto;display:grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--md-sys-color-primary, #60a5fa);color:var(--md-sys-color-on-primary, #020617);box-shadow:0 6px 16px #60a5fa38}.praxis-ai-assistant-shell__identity mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__title-group{min-width:0;flex:1 1 auto;display:grid;gap:4px}.praxis-ai-assistant-shell__title-row{min-width:0;display:flex;align-items:center;gap:8px}.praxis-ai-assistant-shell__badges{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:4px;min-width:0;flex-wrap:wrap}.praxis-ai-assistant-shell__badge{display:inline-flex;align-items:center;gap:5px;min-height:20px;max-width:120px;padding:2px 7px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 80%,transparent);border-radius:8px;color:var(--md-sys-color-on-surface-variant, #cbd5e1);background:var(--md-sys-color-surface-container-high, #263244);font-size:11px;line-height:1.2;overflow-wrap:anywhere}.praxis-ai-assistant-shell__badge--context{color:var(--md-sys-color-on-surface, #f8fafc);background:color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 9%,var(--md-sys-color-surface-container-high, #263244))}.praxis-ai-assistant-shell__badge--state{border-color:transparent;background:transparent;color:var(--md-sys-color-on-surface-variant, #cbd5e1);padding-inline:3px}.praxis-ai-assistant-shell__badge--error{color:var(--md-sys-color-error, #ff6b6b);border-color:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 60%,transparent)}.praxis-ai-assistant-shell__state-dot{flex:0 0 auto;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-primary, #60a5fa);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 16%,transparent)}.praxis-ai-assistant-shell__badge--error .praxis-ai-assistant-shell__state-dot{background:var(--md-sys-color-error, #ff6b6b);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 16%,transparent)}.praxis-ai-assistant-shell__title-group strong,.praxis-ai-assistant-shell__title-group p{min-width:0;margin:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__title-group strong{flex:1 1 auto;font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__title-group p{color:var(--md-sys-color-on-surface-variant, #cbd5e1);font-size:11.5px;line-height:1.3}.praxis-ai-assistant-shell__header-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-top:-3px}.praxis-ai-assistant-shell__header-actions button{width:34px;height:34px;color:var(--md-sys-color-on-surface-variant, #cbd5e1);opacity:.78}.praxis-ai-assistant-shell__header-actions button:hover,.praxis-ai-assistant-shell__header-actions button:focus-visible{opacity:1}.praxis-ai-assistant-shell__header-actions mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__body{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:12px;padding:14px 14px 8px;overflow:auto;background:linear-gradient(180deg,var(--md-sys-color-surface-container-low, #111827),var(--md-sys-color-surface, #0f172a))}.praxis-ai-assistant-shell__context,.praxis-ai-assistant-shell__attachments{flex:0 0 auto;display:flex;align-items:center;gap:8px;overflow-x:auto}.praxis-ai-assistant-shell__context-item{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;max-width:240px;padding:5px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244);font-size:12px;line-height:1.25}.praxis-ai-assistant-shell__context-item mat-icon{width:16px;height:16px;font-size:16px}.praxis-ai-assistant-shell__context-label,.praxis-ai-assistant-shell__context-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__context-label{color:var(--md-sys-color-on-surface, #f8fafc)}.praxis-ai-assistant-shell__context-value{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-ai-assistant-shell__prompt{box-sizing:border-box;width:100%;min-height:56px;max-height:128px;resize:none;border:0;padding:12px;color:var(--md-sys-color-on-surface, #f8fafc);background:transparent;font:inherit;line-height:1.45;outline:none}.praxis-ai-assistant-shell__conversation{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:8px;overflow:auto;padding:2px}.praxis-ai-assistant-shell__message{max-width:86%;align-self:flex-start;padding:9px 11px;border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244);color:var(--md-sys-color-on-surface, #f8fafc);font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__message-actions{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}.praxis-ai-assistant-shell__message-action{min-height:28px;padding:0 8px;border-radius:8px;font-size:12px}.praxis-ai-assistant-shell__message-action--icon{width:30px;min-width:30px;height:30px;padding:0;color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__message-action--icon mat-icon{width:17px;height:17px;font-size:17px}.praxis-ai-assistant-shell__message--assistant{border-bottom-left-radius:2px}.praxis-ai-assistant-shell__message--user{align-self:flex-end;border-bottom-right-radius:2px;background:var(--md-sys-color-primary-container, #17375f);color:var(--md-sys-color-on-primary-container, #f8fafc)}.praxis-ai-assistant-shell__message--status{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__message--error,.praxis-ai-assistant-shell__error{color:var(--md-sys-color-error, #ff6b6b)}.praxis-ai-assistant-shell__quick-replies{display:flex;flex-wrap:wrap;gap:8px}.praxis-ai-assistant-shell__attachment{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;max-width:260px;min-height:34px;padding:4px 4px 4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244)}.praxis-ai-assistant-shell__attachment--error{border-color:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 60%,transparent)}.praxis-ai-assistant-shell__attachment-preview{flex:0 0 auto;width:28px;height:28px;border-radius:6px;object-fit:cover}.praxis-ai-assistant-shell__attachment-name,.praxis-ai-assistant-shell__attachment-kind{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.praxis-ai-assistant-shell__attachment-name{color:var(--md-sys-color-on-surface, #f8fafc)}.praxis-ai-assistant-shell__attachment-kind{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__quick-reply{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-primary, #60a5fa);--praxis-ai-assistant-shell-quick-reply-background: color-mix( in srgb, var(--praxis-ai-assistant-shell-quick-reply-accent) 12%, var(--md-sys-color-surface-container-high, #263244) );--praxis-ai-assistant-shell-quick-reply-foreground: var(--md-sys-color-on-surface, #f8fafc);max-width:100%;min-height:38px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 58%,transparent);border-radius:8px;color:var(--praxis-ai-assistant-shell-quick-reply-foreground);background:var(--praxis-ai-assistant-shell-quick-reply-background);white-space:normal;text-align:left}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{min-width:0;display:inline-flex;align-items:center;gap:8px;width:100%}.praxis-ai-assistant-shell__quick-reply-icon{flex:0 0 auto;width:18px;height:18px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:18px}.praxis-ai-assistant-shell__quick-reply-details{flex:0 0 auto;width:16px;height:16px;color:var(--md-sys-color-on-surface-variant, #94a3b8);font-size:16px;opacity:.82}.praxis-ai-assistant-shell__quick-reply-copy{min-width:0;display:grid;gap:2px}.praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply-description{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-label{font-weight:600;line-height:1.2}.praxis-ai-assistant-shell__quick-reply-description{color:var(--md-sys-color-on-surface-variant, #cbd5e1);font-size:11px;line-height:1.25}.praxis-ai-assistant-shell__quick-reply--tone-analytics{--praxis-ai-assistant-shell-quick-reply-accent: #38bdf8}.praxis-ai-assistant-shell__quick-reply--tone-resource{--praxis-ai-assistant-shell-quick-reply-accent: #34d399}.praxis-ai-assistant-shell__quick-reply--tone-warning{--praxis-ai-assistant-shell-quick-reply-accent: #facc15}.praxis-ai-assistant-shell__quick-reply--tone-success{--praxis-ai-assistant-shell-quick-reply-accent: #22c55e}.praxis-ai-assistant-shell__quick-reply--tone-danger{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-error, #ff6b6b)}.praxis-ai-assistant-shell__quick-reply--tone-neutral{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-outline, #94a3b8)}.praxis-ai-assistant-shell__status,.praxis-ai-assistant-shell__error{margin:0;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__footer{flex:0 0 auto;padding:10px 12px 12px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 72%,transparent);background:var(--md-sys-color-surface-container-low, #111827)}.praxis-ai-assistant-shell__composer{display:grid;gap:8px;border:1px solid var(--md-sys-color-outline-variant, #334155);border-radius:8px;background:var(--md-sys-color-surface-container-lowest, #020617);box-shadow:inset 0 1px #ffffff0a}.praxis-ai-assistant-shell__composer:focus-within{border-color:var(--md-sys-color-primary, #60a5fa);box-shadow:0 0 0 2px #60a5fa29}.praxis-ai-assistant-shell__composer-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:0 8px 8px;flex-wrap:wrap}.praxis-ai-assistant-shell__action{min-height:36px;border-radius:10px;font-weight:650}.praxis-ai-assistant-shell__action mat-icon{width:18px;height:18px;margin-right:6px;font-size:18px}.praxis-ai-assistant-shell__action--icon-only{width:40px;min-width:40px;height:40px;padding-inline:0;border-radius:50%}.praxis-ai-assistant-shell__action--icon-only mat-icon{margin-right:0}.praxis-ai-assistant-shell__action--secondary{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__action--tone-governance{color:var(--md-sys-color-primary, #60a5fa);background:color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-success{color:#34d399;background:color-mix(in srgb,#34d399 10%,transparent)}.praxis-ai-assistant-shell__action--tone-warning{color:#facc15;background:color-mix(in srgb,#facc15 10%,transparent)}.praxis-ai-assistant-shell__action--tone-danger{color:var(--md-sys-color-error, #ff6b6b);background:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 10%,transparent)}.praxis-ai-assistant-shell__resize-handle{position:absolute;z-index:2;border:0;background:transparent;touch-action:none}.praxis-ai-assistant-shell__resize-handle--n,.praxis-ai-assistant-shell__resize-handle--s{left:16px;right:16px;height:10px;cursor:ns-resize}.praxis-ai-assistant-shell__resize-handle--n{top:-5px}.praxis-ai-assistant-shell__resize-handle--s{bottom:-5px}.praxis-ai-assistant-shell__resize-handle--e,.praxis-ai-assistant-shell__resize-handle--w{top:16px;bottom:16px;width:10px;cursor:ew-resize}.praxis-ai-assistant-shell__resize-handle--e{right:-5px}.praxis-ai-assistant-shell__resize-handle--w{left:-5px}.praxis-ai-assistant-shell__resize-handle--ne,.praxis-ai-assistant-shell__resize-handle--nw,.praxis-ai-assistant-shell__resize-handle--se,.praxis-ai-assistant-shell__resize-handle--sw{width:22px;height:22px}.praxis-ai-assistant-shell__resize-handle--ne{top:-5px;right:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--nw{top:-5px;left:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--se{right:-5px;bottom:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--sw{bottom:-5px;left:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--se:after{content:\"\";position:absolute;right:8px;bottom:8px;width:10px;height:10px;border-right:2px solid var(--md-sys-color-outline, #94a3b8);border-bottom:2px solid var(--md-sys-color-outline, #94a3b8)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7513
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisAiAssistantShellComponent, isStandalone: true, selector: "praxis-ai-assistant-shell", inputs: { labels: "labels", mode: "mode", state: "state", contextItems: "contextItems", attachments: "attachments", messages: "messages", quickReplies: "quickReplies", prompt: "prompt", statusText: "statusText", errorText: "errorText", testIdPrefix: "testIdPrefix", panelTestId: "panelTestId", submitTestId: "submitTestId", applyTestId: "applyTestId", primaryAction: "primaryAction", secondaryActions: "secondaryActions", governanceActions: "governanceActions", busy: "busy", canSubmit: "canSubmit", canApply: "canApply", submitOnEnter: "submitOnEnter", showAttachAction: "showAttachAction", enablePastedAttachments: "enablePastedAttachments", enableFileAttachments: "enableFileAttachments", attachmentAccept: "attachmentAccept", attachmentMultiple: "attachmentMultiple", draggable: "draggable", resizable: "resizable", minWidth: "minWidth", minHeight: "minHeight", margin: "margin", layout: "layout" }, outputs: { promptChange: "promptChange", submitPrompt: "submitPrompt", apply: "apply", retryTurn: "retryTurn", cancelTurn: "cancelTurn", shellAction: "shellAction", close: "close", attach: "attach", attachmentsPasted: "attachmentsPasted", attachmentsSelected: "attachmentsSelected", removeAttachment: "removeAttachment", messageAction: "messageAction", editMessage: "editMessage", resendMessage: "resendMessage", quickReply: "quickReply", layoutChange: "layoutChange" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, static: true }, { propertyName: "conversation", first: true, predicate: ["conversation"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section\n #panel\n class=\"praxis-ai-assistant-shell\"\n role=\"dialog\"\n [attr.aria-label]=\"resolvedLabels.title\"\n [attr.aria-busy]=\"busy ? 'true' : null\"\n [style.left.px]=\"currentLayout.left\"\n [style.top.px]=\"currentLayout.top\"\n [style.width.px]=\"currentLayout.width\"\n [style.height.px]=\"currentLayout.height\"\n [attr.data-testid]=\"panelTestId || testIdPrefix\"\n>\n <header\n class=\"praxis-ai-assistant-shell__header\"\n [attr.data-testid]=\"testIdPrefix + '-drag-handle'\"\n [attr.aria-label]=\"resolvedLabels.dragHandleAria\"\n (pointerdown)=\"startDrag($event)\"\n >\n <div class=\"praxis-ai-assistant-shell__identity\" aria-hidden=\"true\">\n <mat-icon>auto_awesome</mat-icon>\n </div>\n <div class=\"praxis-ai-assistant-shell__title-group\">\n <div class=\"praxis-ai-assistant-shell__title-row\">\n <strong>{{ resolvedLabels.title }}</strong>\n <div class=\"praxis-ai-assistant-shell__badges\" aria-hidden=\"true\">\n <span class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--context\">\n {{ getModeLabel() }}\n </span>\n <span\n class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--state\"\n [class.praxis-ai-assistant-shell__badge--error]=\"state === 'error'\"\n >\n <span class=\"praxis-ai-assistant-shell__state-dot\" aria-hidden=\"true\"></span>\n {{ getStateLabel() }}\n </span>\n </div>\n </div>\n <p *ngIf=\"resolvedLabels.subtitle\">{{ resolvedLabels.subtitle }}</p>\n </div>\n <div class=\"praxis-ai-assistant-shell__header-actions\">\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"getResetLayoutLabel()\"\n [attr.aria-label]=\"getResetLayoutLabel()\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"resetLayout()\"\n [attr.data-testid]=\"testIdPrefix + '-reset-layout'\"\n >\n <mat-icon>center_focus_strong</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"resolvedLabels.close\"\n [attr.aria-label]=\"resolvedLabels.close\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"close.emit()\"\n [attr.data-testid]=\"testIdPrefix + '-close'\"\n >\n <mat-icon>{{ getCloseIcon() }}</mat-icon>\n </button>\n </div>\n </header>\n\n <div class=\"praxis-ai-assistant-shell__body\">\n <div\n *ngIf=\"contextItems.length\"\n class=\"praxis-ai-assistant-shell__context\"\n [attr.aria-label]=\"resolvedLabels.contextAria\"\n [attr.data-testid]=\"testIdPrefix + '-context'\"\n >\n <span\n *ngFor=\"let item of contextItems; trackBy: trackContextItem\"\n class=\"praxis-ai-assistant-shell__context-item\"\n [attr.data-testid]=\"testIdPrefix + '-context-' + item.id\"\n >\n <mat-icon *ngIf=\"item.icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__context-label\">{{ item.label }}</span>\n <span *ngIf=\"item.value\" class=\"praxis-ai-assistant-shell__context-value\">{{ item.value }}</span>\n </span>\n </div>\n\n <div\n #conversation\n class=\"praxis-ai-assistant-shell__conversation\"\n [attr.data-testid]=\"testIdPrefix + '-conversation'\"\n [attr.aria-label]=\"resolvedLabels.conversationAria\"\n >\n <article\n *ngIf=\"!messages.length\"\n class=\"praxis-ai-assistant-shell__message praxis-ai-assistant-shell__message--assistant\"\n [attr.data-testid]=\"testIdPrefix + '-message-assistant-empty'\"\n >\n {{ resolvedLabels.emptyConversation }}\n </article>\n <article\n *ngFor=\"let message of messages; trackBy: trackMessage\"\n class=\"praxis-ai-assistant-shell__message\"\n [class.praxis-ai-assistant-shell__message--user]=\"message.role === 'user'\"\n [class.praxis-ai-assistant-shell__message--assistant]=\"message.role === 'assistant'\"\n [class.praxis-ai-assistant-shell__message--status]=\"message.role === 'status'\"\n [class.praxis-ai-assistant-shell__message--error]=\"message.role === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-message-' + message.role\"\n >\n {{ message.text }}\n <div\n *ngIf=\"message.actions?.length || message.editable || message.resendable\"\n class=\"praxis-ai-assistant-shell__message-actions\"\n >\n <button\n *ngIf=\"message.editable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.editMessage\"\n [attr.aria-label]=\"resolvedLabels.editMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-edit-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'edit', label: resolvedLabels.editMessage, kind: 'edit' })\"\n >\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n <button\n *ngIf=\"message.resendable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.resendMessage\"\n [attr.aria-label]=\"resolvedLabels.resendMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-resend-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'resend', label: resolvedLabels.resendMessage, kind: 'resend' })\"\n >\n <mat-icon aria-hidden=\"true\">replay</mat-icon>\n </button>\n <ng-container *ngFor=\"let action of message.actions || []; trackBy: trackMessageAction\">\n <button\n *ngIf=\"isMessageActionIconOnly(action); else textualMessageAction\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy || action.disabled\"\n [matTooltip]=\"getMessageActionLabel(action)\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n <mat-icon aria-hidden=\"true\">{{ getMessageActionIcon(action) }}</mat-icon>\n </button>\n <ng-template #textualMessageAction>\n <button\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action\"\n [disabled]=\"busy || action.disabled\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n {{ action.label }}\n </button>\n </ng-template>\n </ng-container>\n </div>\n </article>\n </div>\n\n <div\n *ngIf=\"attachments.length\"\n class=\"praxis-ai-assistant-shell__attachments\"\n [attr.aria-label]=\"resolvedLabels.attachmentsAria\"\n [attr.data-testid]=\"testIdPrefix + '-attachments'\"\n >\n <div\n *ngFor=\"let attachment of attachments; trackBy: trackAttachment\"\n class=\"praxis-ai-assistant-shell__attachment\"\n [class.praxis-ai-assistant-shell__attachment--error]=\"attachment.status === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-' + attachment.id\"\n >\n <img\n *ngIf=\"attachment.previewUrl && attachment.kind === 'image'\"\n class=\"praxis-ai-assistant-shell__attachment-preview\"\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.name\"\n >\n <span class=\"praxis-ai-assistant-shell__attachment-name\">{{ attachment.name }}</span>\n <span class=\"praxis-ai-assistant-shell__attachment-kind\">{{ attachment.kind }}</span>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.removeAttachment\"\n [attr.aria-label]=\"resolvedLabels.removeAttachment + ': ' + attachment.name\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-remove-' + attachment.id\"\n (click)=\"onRemoveAttachment(attachment)\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div\n *ngIf=\"quickReplies.length\"\n class=\"praxis-ai-assistant-shell__quick-replies\"\n [attr.data-testid]=\"testIdPrefix + '-quick-replies'\"\n [attr.aria-label]=\"resolvedLabels.quickRepliesAria\"\n >\n <button\n *ngFor=\"let reply of quickReplies; trackBy: trackQuickReply\"\n mat-stroked-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__quick-reply\"\n [ngClass]=\"'praxis-ai-assistant-shell__quick-reply--tone-' + getQuickReplyTone(reply)\"\n [attr.data-testid]=\"testIdPrefix + '-quick-reply-' + (reply.id || reply.kind)\"\n [attr.aria-label]=\"getQuickReplyAriaLabel(reply)\"\n [disabled]=\"busy\"\n (click)=\"onQuickReply(reply)\"\n >\n <span class=\"praxis-ai-assistant-shell__quick-reply-icon-frame\" aria-hidden=\"true\">\n <mat-icon\n class=\"praxis-ai-assistant-shell__quick-reply-icon\"\n >\n {{ getQuickReplyIcon(reply) }}\n </mat-icon>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-header\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-label\">{{ reply.label }}</span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-badge\">\n {{ getQuickReplyCategoryLabel(reply) }}\n </span>\n </span>\n <span\n *ngIf=\"reply.description\"\n class=\"praxis-ai-assistant-shell__quick-reply-description\"\n >\n {{ reply.description }}\n </span>\n <span\n *ngIf=\"getQuickReplyPresentationItems(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-insights\"\n >\n <span\n *ngFor=\"let item of getQuickReplyPresentationItems(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-insight\"\n >\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-label\">\n {{ item.label }}\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-value\">\n {{ item.value }}\n </span>\n </span>\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-cta\">\n {{ getQuickReplyCtaLabel(reply) }}\n <mat-icon aria-hidden=\"true\">arrow_forward</mat-icon>\n </span>\n </span>\n <mat-icon\n *ngIf=\"getQuickReplyTechnicalDetails(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-details\"\n [matTooltip]=\"getQuickReplyTechnicalDetails(reply)\"\n [attr.aria-label]=\"resolvedLabels.quickReplyDetails\"\n >\n info\n </mat-icon>\n </button>\n </div>\n <p\n *ngIf=\"statusText\"\n class=\"praxis-ai-assistant-shell__status\"\n [attr.data-testid]=\"testIdPrefix + '-status'\"\n >\n {{ statusText }}\n </p>\n <p\n *ngIf=\"errorText\"\n class=\"praxis-ai-assistant-shell__error\"\n [attr.data-testid]=\"testIdPrefix + '-error'\"\n >\n {{ errorText }}\n </p>\n </div>\n\n <footer class=\"praxis-ai-assistant-shell__footer\">\n <label class=\"praxis-ai-assistant-shell__label\" for=\"praxis-ai-assistant-shell-prompt\">\n {{ resolvedLabels.prompt }}\n </label>\n <div class=\"praxis-ai-assistant-shell__composer\">\n <textarea\n id=\"praxis-ai-assistant-shell-prompt\"\n class=\"praxis-ai-assistant-shell__prompt\"\n [attr.data-testid]=\"testIdPrefix + '-prompt'\"\n [placeholder]=\"resolvedLabels.promptPlaceholder\"\n [ngModel]=\"currentPrompt\"\n [disabled]=\"busy\"\n (ngModelChange)=\"onPromptInput($event)\"\n (keydown)=\"onPromptKeydown($event)\"\n (paste)=\"onPromptPaste($event)\"\n ></textarea>\n <div class=\"praxis-ai-assistant-shell__composer-actions\">\n <ng-container *ngIf=\"showAttachAction\">\n <input\n #attachmentInput\n type=\"file\"\n hidden\n [attr.accept]=\"attachmentAccept || null\"\n [attr.multiple]=\"attachmentMultiple ? '' : null\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-input'\"\n (change)=\"onAttachmentFilesSelected($event)\"\n >\n <button\n mat-stroked-button\n type=\"button\"\n [disabled]=\"busy\"\n (click)=\"onAttachClick(attachmentInput)\"\n [attr.data-testid]=\"testIdPrefix + '-attach'\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ resolvedLabels.attach }}\n </button>\n </ng-container>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--primary\"\n [class.praxis-ai-assistant-shell__action--icon-only]=\"getPrimaryAction().iconOnly\"\n [matTooltip]=\"getPrimaryActionTooltip(getPrimaryAction())\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(getPrimaryAction())\"\n [disabled]=\"isShellActionDisabled(getPrimaryAction())\"\n (click)=\"onShellAction(getPrimaryAction())\"\n [attr.data-testid]=\"getPrimaryAction().testId || (submitTestId || (testIdPrefix + '-submit'))\"\n [attr.aria-label]=\"getPrimaryAction().ariaLabel || getPrimaryAction().label\"\n >\n <mat-icon *ngIf=\"getPrimaryAction().icon\" aria-hidden=\"true\">{{ getPrimaryAction().icon }}</mat-icon>\n <span *ngIf=\"!getPrimaryAction().iconOnly\">{{ getPrimaryAction().label }}</span>\n </button>\n <button\n *ngFor=\"let action of getSecondaryActions(); trackBy: trackShellAction\"\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--secondary\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(action)\"\n [disabled]=\"isShellActionDisabled(action)\"\n (click)=\"onShellAction(action)\"\n [attr.data-testid]=\"action.testId || (testIdPrefix + '-action-' + action.id)\"\n [attr.aria-label]=\"action.ariaLabel || action.label\"\n >\n <mat-icon *ngIf=\"action.icon\" aria-hidden=\"true\">{{ action.icon }}</mat-icon>\n {{ action.label }}\n </button>\n <mat-spinner *ngIf=\"busy\" diameter=\"20\" [attr.data-testid]=\"testIdPrefix + '-spinner'\"></mat-spinner>\n </div>\n </div>\n </footer>\n\n <ng-container *ngIf=\"resizable\">\n <span\n *ngFor=\"let direction of resizeHandles; trackBy: trackResizeHandle\"\n class=\"praxis-ai-assistant-shell__resize-handle praxis-ai-assistant-shell__resize-handle--{{ direction }}\"\n [attr.data-testid]=\"direction === 'se' ? testIdPrefix + '-resize-handle' : testIdPrefix + '-resize-handle-' + direction\"\n aria-hidden=\"true\"\n role=\"presentation\"\n (pointerdown)=\"startResize(direction, $event)\"\n ></span>\n </ng-container>\n</section>\n", styles: [":host{display:block}.praxis-ai-assistant-shell{position:fixed;box-sizing:border-box;min-width:360px;min-height:360px;display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface, #f8fafc);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface, #0f172a);box-shadow:0 24px 60px #0006;z-index:var(--praxis-ai-assistant-shell-z-index, 1200)}.praxis-ai-assistant-shell__header{flex:0 0 auto;display:flex;align-items:flex-start;gap:9px;padding:10px 10px 9px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 72%,transparent);background:var(--md-sys-color-surface-container, #172033)}.praxis-ai-assistant-shell__header{justify-content:flex-start;border-bottom:1px solid;cursor:move;touch-action:none}.praxis-ai-assistant-shell__identity{flex:0 0 auto;display:grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--md-sys-color-primary, #60a5fa);color:var(--md-sys-color-on-primary, #020617);box-shadow:0 6px 16px #60a5fa38}.praxis-ai-assistant-shell__identity mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__title-group{min-width:0;flex:1 1 auto;display:grid;gap:4px}.praxis-ai-assistant-shell__title-row{min-width:0;display:flex;align-items:center;gap:8px}.praxis-ai-assistant-shell__badges{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:4px;min-width:0;flex-wrap:wrap}.praxis-ai-assistant-shell__badge{display:inline-flex;align-items:center;gap:5px;min-height:20px;max-width:120px;padding:2px 7px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 80%,transparent);border-radius:8px;color:var(--md-sys-color-on-surface-variant, #cbd5e1);background:var(--md-sys-color-surface-container-high, #263244);font-size:11px;line-height:1.2;overflow-wrap:anywhere}.praxis-ai-assistant-shell__badge--context{color:var(--md-sys-color-on-surface, #f8fafc);background:color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 9%,var(--md-sys-color-surface-container-high, #263244))}.praxis-ai-assistant-shell__badge--state{border-color:transparent;background:transparent;color:var(--md-sys-color-on-surface-variant, #cbd5e1);padding-inline:3px}.praxis-ai-assistant-shell__badge--error{color:var(--md-sys-color-error, #ff6b6b);border-color:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 60%,transparent)}.praxis-ai-assistant-shell__state-dot{flex:0 0 auto;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-primary, #60a5fa);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 16%,transparent)}.praxis-ai-assistant-shell__badge--error .praxis-ai-assistant-shell__state-dot{background:var(--md-sys-color-error, #ff6b6b);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 16%,transparent)}.praxis-ai-assistant-shell__title-group strong,.praxis-ai-assistant-shell__title-group p{min-width:0;margin:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__title-group strong{flex:1 1 auto;font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__title-group p{color:var(--md-sys-color-on-surface-variant, #cbd5e1);font-size:11.5px;line-height:1.3}.praxis-ai-assistant-shell__header-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-top:-3px}.praxis-ai-assistant-shell__header-actions button{width:34px;height:34px;color:var(--md-sys-color-on-surface-variant, #cbd5e1);opacity:.78}.praxis-ai-assistant-shell__header-actions button:hover,.praxis-ai-assistant-shell__header-actions button:focus-visible{opacity:1}.praxis-ai-assistant-shell__header-actions mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__body{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:12px;padding:14px 14px 8px;overflow:auto;background:linear-gradient(180deg,var(--md-sys-color-surface-container-low, #111827),var(--md-sys-color-surface, #0f172a))}.praxis-ai-assistant-shell__context,.praxis-ai-assistant-shell__attachments{flex:0 0 auto;display:flex;align-items:center;gap:8px;overflow-x:auto}.praxis-ai-assistant-shell__context-item{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;max-width:240px;padding:5px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244);font-size:12px;line-height:1.25}.praxis-ai-assistant-shell__context-item mat-icon{width:16px;height:16px;font-size:16px}.praxis-ai-assistant-shell__context-label,.praxis-ai-assistant-shell__context-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__context-label{color:var(--md-sys-color-on-surface, #f8fafc)}.praxis-ai-assistant-shell__context-value{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-ai-assistant-shell__prompt{box-sizing:border-box;width:100%;min-height:56px;max-height:128px;resize:none;border:0;padding:12px;color:var(--md-sys-color-on-surface, #f8fafc);background:transparent;font:inherit;line-height:1.45;outline:none}.praxis-ai-assistant-shell__conversation{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:8px;overflow:auto;padding:2px}.praxis-ai-assistant-shell__message{max-width:86%;align-self:flex-start;padding:9px 11px;border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244);color:var(--md-sys-color-on-surface, #f8fafc);font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__message-actions{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}.praxis-ai-assistant-shell__message-action{min-height:28px;padding:0 8px;border-radius:8px;font-size:12px}.praxis-ai-assistant-shell__message-action--icon{width:30px;min-width:30px;height:30px;padding:0;color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__message-action--icon mat-icon{width:17px;height:17px;font-size:17px}.praxis-ai-assistant-shell__message--assistant{border-bottom-left-radius:2px}.praxis-ai-assistant-shell__message--user{align-self:flex-end;border-bottom-right-radius:2px;background:var(--md-sys-color-primary-container, #17375f);color:var(--md-sys-color-on-primary-container, #f8fafc)}.praxis-ai-assistant-shell__message--status{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__message--error,.praxis-ai-assistant-shell__error{color:var(--md-sys-color-error, #ff6b6b)}.praxis-ai-assistant-shell__quick-replies{display:flex;flex-wrap:wrap;gap:10px;align-items:stretch}.praxis-ai-assistant-shell__attachment{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;max-width:260px;min-height:34px;padding:4px 4px 4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244)}.praxis-ai-assistant-shell__attachment--error{border-color:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 60%,transparent)}.praxis-ai-assistant-shell__attachment-preview{flex:0 0 auto;width:28px;height:28px;border-radius:6px;object-fit:cover}.praxis-ai-assistant-shell__attachment-name,.praxis-ai-assistant-shell__attachment-kind{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.praxis-ai-assistant-shell__attachment-name{color:var(--md-sys-color-on-surface, #f8fafc)}.praxis-ai-assistant-shell__attachment-kind{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__quick-reply{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-primary, #60a5fa);--praxis-ai-assistant-shell-quick-reply-background: color-mix( in srgb, var(--praxis-ai-assistant-shell-quick-reply-accent) 9%, var(--md-sys-color-surface-container-high, #263244) );--praxis-ai-assistant-shell-quick-reply-foreground: var(--md-sys-color-on-surface, #f8fafc);width:min(100%,680px);max-width:100%;height:auto;min-height:0;padding:14px;align-items:stretch;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 42%,transparent);border-radius:20px;color:var(--praxis-ai-assistant-shell-quick-reply-foreground);background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 20%,transparent),transparent 52%),radial-gradient(circle at 92% 10%,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 20%,transparent),transparent 34%),var(--praxis-ai-assistant-shell-quick-reply-background);box-shadow:0 16px 36px color-mix(in srgb,#000 20%,transparent),inset 0 1px color-mix(in srgb,#fff 14%,transparent);letter-spacing:normal;white-space:normal;text-align:left;text-transform:none;-webkit-user-select:none;user-select:none;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease,background .16s ease;--mdc-outlined-button-container-height: auto;--mat-outlined-button-horizontal-padding: 0}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 74%,transparent);box-shadow:0 18px 42px color-mix(in srgb,#000 24%,transparent),0 0 0 3px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 18%,transparent),inset 0 1px color-mix(in srgb,#fff 18%,transparent);transform:translateY(-1px)}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{min-width:0;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:flex-start;gap:13px;width:100%;height:auto;line-height:normal}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mat-mdc-button-touch-target{height:100%;min-height:48px}.praxis-ai-assistant-shell__quick-reply-icon-frame{flex:0 0 auto;width:42px;height:42px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 28%,transparent);border-radius:15px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);background:linear-gradient(145deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent),color-mix(in srgb,#fff 5%,transparent))}.praxis-ai-assistant-shell__quick-reply-icon{width:24px;height:24px;font-size:24px}.praxis-ai-assistant-shell__quick-reply-details{flex:0 0 auto;width:22px;height:22px;display:inline-grid;place-items:center;border-radius:50%;color:var(--md-sys-color-on-surface-variant, #94a3b8);background:color-mix(in srgb,var(--md-sys-color-outline, #94a3b8) 14%,transparent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-copy{min-width:0;display:grid;gap:9px;flex:1 1 auto}.praxis-ai-assistant-shell__quick-reply-header{min-width:0;display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply-description{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-label{color:var(--md-sys-color-on-surface, #f8fafc);font-size:17px;font-weight:760;letter-spacing:.005em;line-height:1.18;text-transform:none}.praxis-ai-assistant-shell__quick-reply-badge{flex:0 0 auto;max-width:42%;padding:4px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 28%,transparent);border-radius:999px;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 86%,#fff);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 11%,transparent);font-size:10.5px;font-weight:700;letter-spacing:.02em;line-height:1.1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-description{color:color-mix(in srgb,var(--md-sys-color-on-surface, #f8fafc) 78%,transparent);font-size:13px;line-height:1.42}.praxis-ai-assistant-shell__quick-reply-insights{display:grid;gap:6px;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 18%,transparent);border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest, #020617) 30%,transparent)}.praxis-ai-assistant-shell__quick-reply-insight{min-width:0;display:grid;grid-template-columns:18px minmax(0,1fr);gap:8px;align-items:start;color:color-mix(in srgb,var(--md-sys-color-on-surface, #f8fafc) 86%,transparent);font-size:12px;line-height:1.35}.praxis-ai-assistant-shell__quick-reply-insight mat-icon{width:17px;height:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-insight-copy{min-width:0;display:grid;gap:1px}.praxis-ai-assistant-shell__quick-reply-insight-label{color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 82%,#fff);font-size:10.5px;font-weight:760;letter-spacing:.045em;line-height:1.2;text-transform:uppercase}.praxis-ai-assistant-shell__quick-reply-insight-value{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-cta{display:inline-flex;align-items:center;justify-self:start;gap:5px;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 84%,#fff);font-size:12px;font-weight:760;letter-spacing:.01em;line-height:1.2}.praxis-ai-assistant-shell__quick-reply-cta mat-icon{width:15px;height:15px;font-size:15px;transition:transform .16s ease}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled) .praxis-ai-assistant-shell__quick-reply-cta mat-icon,.praxis-ai-assistant-shell__quick-reply:focus-visible .praxis-ai-assistant-shell__quick-reply-cta mat-icon{transform:translate(2px)}.praxis-ai-assistant-shell__quick-reply--tone-analytics{--praxis-ai-assistant-shell-quick-reply-accent: #38bdf8}.praxis-ai-assistant-shell__quick-reply--tone-resource{--praxis-ai-assistant-shell-quick-reply-accent: #34d399}.praxis-ai-assistant-shell__quick-reply--tone-warning{--praxis-ai-assistant-shell-quick-reply-accent: #facc15}.praxis-ai-assistant-shell__quick-reply--tone-success{--praxis-ai-assistant-shell-quick-reply-accent: #22c55e}.praxis-ai-assistant-shell__quick-reply--tone-danger{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-error, #ff6b6b)}.praxis-ai-assistant-shell__quick-reply--tone-neutral{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-outline, #94a3b8)}.praxis-ai-assistant-shell__status,.praxis-ai-assistant-shell__error{margin:0;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__footer{flex:0 0 auto;padding:10px 12px 12px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 72%,transparent);background:var(--md-sys-color-surface-container-low, #111827)}.praxis-ai-assistant-shell__composer{display:grid;gap:8px;border:1px solid var(--md-sys-color-outline-variant, #334155);border-radius:8px;background:var(--md-sys-color-surface-container-lowest, #020617);box-shadow:inset 0 1px #ffffff0a}.praxis-ai-assistant-shell__composer:focus-within{border-color:var(--md-sys-color-primary, #60a5fa);box-shadow:0 0 0 2px #60a5fa29}.praxis-ai-assistant-shell__composer-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:0 8px 8px;flex-wrap:wrap}.praxis-ai-assistant-shell__action{min-height:36px;border-radius:10px;font-weight:650}.praxis-ai-assistant-shell__action mat-icon{width:18px;height:18px;margin-right:6px;font-size:18px}.praxis-ai-assistant-shell__action--icon-only{width:40px;min-width:40px;height:40px;padding-inline:0;border-radius:50%}.praxis-ai-assistant-shell__action--icon-only mat-icon{margin-right:0}.praxis-ai-assistant-shell__action--secondary{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__action--tone-governance{color:var(--md-sys-color-primary, #60a5fa);background:color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-success{color:#34d399;background:color-mix(in srgb,#34d399 10%,transparent)}.praxis-ai-assistant-shell__action--tone-warning{color:#facc15;background:color-mix(in srgb,#facc15 10%,transparent)}.praxis-ai-assistant-shell__action--tone-danger{color:var(--md-sys-color-error, #ff6b6b);background:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 10%,transparent)}.praxis-ai-assistant-shell__resize-handle{position:absolute;z-index:2;border:0;background:transparent;touch-action:none}.praxis-ai-assistant-shell__resize-handle--n,.praxis-ai-assistant-shell__resize-handle--s{left:16px;right:16px;height:10px;cursor:ns-resize}.praxis-ai-assistant-shell__resize-handle--n{top:-5px}.praxis-ai-assistant-shell__resize-handle--s{bottom:-5px}.praxis-ai-assistant-shell__resize-handle--e,.praxis-ai-assistant-shell__resize-handle--w{top:16px;bottom:16px;width:10px;cursor:ew-resize}.praxis-ai-assistant-shell__resize-handle--e{right:-5px}.praxis-ai-assistant-shell__resize-handle--w{left:-5px}.praxis-ai-assistant-shell__resize-handle--ne,.praxis-ai-assistant-shell__resize-handle--nw,.praxis-ai-assistant-shell__resize-handle--se,.praxis-ai-assistant-shell__resize-handle--sw{width:22px;height:22px}.praxis-ai-assistant-shell__resize-handle--ne{top:-5px;right:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--nw{top:-5px;left:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--se{right:-5px;bottom:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--sw{bottom:-5px;left:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--se:after{content:\"\";position:absolute;right:8px;bottom:8px;width:10px;height:10px;border-right:2px solid var(--md-sys-color-outline, #94a3b8);border-bottom:2px solid var(--md-sys-color-outline, #94a3b8)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7188
7514
|
}
|
|
7189
7515
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisAiAssistantShellComponent, decorators: [{
|
|
7190
7516
|
type: Component,
|
|
@@ -7195,7 +7521,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
7195
7521
|
MatIconModule,
|
|
7196
7522
|
MatProgressSpinnerModule,
|
|
7197
7523
|
MatTooltipModule,
|
|
7198
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n #panel\n class=\"praxis-ai-assistant-shell\"\n role=\"dialog\"\n [attr.aria-label]=\"resolvedLabels.title\"\n [attr.aria-busy]=\"busy ? 'true' : null\"\n [style.left.px]=\"currentLayout.left\"\n [style.top.px]=\"currentLayout.top\"\n [style.width.px]=\"currentLayout.width\"\n [style.height.px]=\"currentLayout.height\"\n [attr.data-testid]=\"panelTestId || testIdPrefix\"\n>\n <header\n class=\"praxis-ai-assistant-shell__header\"\n [attr.data-testid]=\"testIdPrefix + '-drag-handle'\"\n [attr.aria-label]=\"resolvedLabels.dragHandleAria\"\n (pointerdown)=\"startDrag($event)\"\n >\n <div class=\"praxis-ai-assistant-shell__identity\" aria-hidden=\"true\">\n <mat-icon>auto_awesome</mat-icon>\n </div>\n <div class=\"praxis-ai-assistant-shell__title-group\">\n <div class=\"praxis-ai-assistant-shell__title-row\">\n <strong>{{ resolvedLabels.title }}</strong>\n <div class=\"praxis-ai-assistant-shell__badges\" aria-hidden=\"true\">\n <span class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--context\">\n {{ getModeLabel() }}\n </span>\n <span\n class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--state\"\n [class.praxis-ai-assistant-shell__badge--error]=\"state === 'error'\"\n >\n <span class=\"praxis-ai-assistant-shell__state-dot\" aria-hidden=\"true\"></span>\n {{ getStateLabel() }}\n </span>\n </div>\n </div>\n <p *ngIf=\"resolvedLabels.subtitle\">{{ resolvedLabels.subtitle }}</p>\n </div>\n <div class=\"praxis-ai-assistant-shell__header-actions\">\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"getResetLayoutLabel()\"\n [attr.aria-label]=\"getResetLayoutLabel()\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"resetLayout()\"\n [attr.data-testid]=\"testIdPrefix + '-reset-layout'\"\n >\n <mat-icon>center_focus_strong</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"resolvedLabels.close\"\n [attr.aria-label]=\"resolvedLabels.close\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"close.emit()\"\n [attr.data-testid]=\"testIdPrefix + '-close'\"\n >\n <mat-icon>{{ getCloseIcon() }}</mat-icon>\n </button>\n </div>\n </header>\n\n <div class=\"praxis-ai-assistant-shell__body\">\n <div\n *ngIf=\"contextItems.length\"\n class=\"praxis-ai-assistant-shell__context\"\n [attr.aria-label]=\"resolvedLabels.contextAria\"\n [attr.data-testid]=\"testIdPrefix + '-context'\"\n >\n <span\n *ngFor=\"let item of contextItems; trackBy: trackContextItem\"\n class=\"praxis-ai-assistant-shell__context-item\"\n [attr.data-testid]=\"testIdPrefix + '-context-' + item.id\"\n >\n <mat-icon *ngIf=\"item.icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__context-label\">{{ item.label }}</span>\n <span *ngIf=\"item.value\" class=\"praxis-ai-assistant-shell__context-value\">{{ item.value }}</span>\n </span>\n </div>\n\n <div\n #conversation\n class=\"praxis-ai-assistant-shell__conversation\"\n [attr.data-testid]=\"testIdPrefix + '-conversation'\"\n [attr.aria-label]=\"resolvedLabels.conversationAria\"\n >\n <article\n *ngIf=\"!messages.length\"\n class=\"praxis-ai-assistant-shell__message praxis-ai-assistant-shell__message--assistant\"\n [attr.data-testid]=\"testIdPrefix + '-message-assistant-empty'\"\n >\n {{ resolvedLabels.emptyConversation }}\n </article>\n <article\n *ngFor=\"let message of messages; trackBy: trackMessage\"\n class=\"praxis-ai-assistant-shell__message\"\n [class.praxis-ai-assistant-shell__message--user]=\"message.role === 'user'\"\n [class.praxis-ai-assistant-shell__message--assistant]=\"message.role === 'assistant'\"\n [class.praxis-ai-assistant-shell__message--status]=\"message.role === 'status'\"\n [class.praxis-ai-assistant-shell__message--error]=\"message.role === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-message-' + message.role\"\n >\n {{ message.text }}\n <div\n *ngIf=\"message.actions?.length || message.editable || message.resendable\"\n class=\"praxis-ai-assistant-shell__message-actions\"\n >\n <button\n *ngIf=\"message.editable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.editMessage\"\n [attr.aria-label]=\"resolvedLabels.editMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-edit-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'edit', label: resolvedLabels.editMessage, kind: 'edit' })\"\n >\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n <button\n *ngIf=\"message.resendable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.resendMessage\"\n [attr.aria-label]=\"resolvedLabels.resendMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-resend-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'resend', label: resolvedLabels.resendMessage, kind: 'resend' })\"\n >\n <mat-icon aria-hidden=\"true\">replay</mat-icon>\n </button>\n <ng-container *ngFor=\"let action of message.actions || []; trackBy: trackMessageAction\">\n <button\n *ngIf=\"isMessageActionIconOnly(action); else textualMessageAction\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy || action.disabled\"\n [matTooltip]=\"getMessageActionLabel(action)\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n <mat-icon aria-hidden=\"true\">{{ getMessageActionIcon(action) }}</mat-icon>\n </button>\n <ng-template #textualMessageAction>\n <button\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action\"\n [disabled]=\"busy || action.disabled\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n {{ action.label }}\n </button>\n </ng-template>\n </ng-container>\n </div>\n </article>\n </div>\n\n <div\n *ngIf=\"attachments.length\"\n class=\"praxis-ai-assistant-shell__attachments\"\n [attr.aria-label]=\"resolvedLabels.attachmentsAria\"\n [attr.data-testid]=\"testIdPrefix + '-attachments'\"\n >\n <div\n *ngFor=\"let attachment of attachments; trackBy: trackAttachment\"\n class=\"praxis-ai-assistant-shell__attachment\"\n [class.praxis-ai-assistant-shell__attachment--error]=\"attachment.status === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-' + attachment.id\"\n >\n <img\n *ngIf=\"attachment.previewUrl && attachment.kind === 'image'\"\n class=\"praxis-ai-assistant-shell__attachment-preview\"\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.name\"\n >\n <span class=\"praxis-ai-assistant-shell__attachment-name\">{{ attachment.name }}</span>\n <span class=\"praxis-ai-assistant-shell__attachment-kind\">{{ attachment.kind }}</span>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.removeAttachment\"\n [attr.aria-label]=\"resolvedLabels.removeAttachment + ': ' + attachment.name\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-remove-' + attachment.id\"\n (click)=\"onRemoveAttachment(attachment)\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div\n *ngIf=\"quickReplies.length\"\n class=\"praxis-ai-assistant-shell__quick-replies\"\n [attr.data-testid]=\"testIdPrefix + '-quick-replies'\"\n [attr.aria-label]=\"resolvedLabels.quickRepliesAria\"\n >\n <button\n *ngFor=\"let reply of quickReplies; trackBy: trackQuickReply\"\n mat-stroked-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__quick-reply\"\n [ngClass]=\"'praxis-ai-assistant-shell__quick-reply--tone-' + getQuickReplyTone(reply)\"\n [attr.data-testid]=\"testIdPrefix + '-quick-reply-' + (reply.id || reply.kind)\"\n [attr.aria-label]=\"getQuickReplyAriaLabel(reply)\"\n [disabled]=\"busy\"\n (click)=\"onQuickReply(reply)\"\n >\n <mat-icon\n *ngIf=\"reply.icon\"\n class=\"praxis-ai-assistant-shell__quick-reply-icon\"\n aria-hidden=\"true\"\n >\n {{ reply.icon }}\n </mat-icon>\n <span class=\"praxis-ai-assistant-shell__quick-reply-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-label\">{{ reply.label }}</span>\n <span\n *ngIf=\"reply.description\"\n class=\"praxis-ai-assistant-shell__quick-reply-description\"\n >\n {{ reply.description }}\n </span>\n </span>\n <mat-icon\n *ngIf=\"getQuickReplyTechnicalDetails(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-details\"\n [matTooltip]=\"getQuickReplyTechnicalDetails(reply)\"\n [attr.aria-label]=\"resolvedLabels.quickReplyDetails\"\n >\n info\n </mat-icon>\n </button>\n </div>\n <p\n *ngIf=\"statusText\"\n class=\"praxis-ai-assistant-shell__status\"\n [attr.data-testid]=\"testIdPrefix + '-status'\"\n >\n {{ statusText }}\n </p>\n <p\n *ngIf=\"errorText\"\n class=\"praxis-ai-assistant-shell__error\"\n [attr.data-testid]=\"testIdPrefix + '-error'\"\n >\n {{ errorText }}\n </p>\n </div>\n\n <footer class=\"praxis-ai-assistant-shell__footer\">\n <label class=\"praxis-ai-assistant-shell__label\" for=\"praxis-ai-assistant-shell-prompt\">\n {{ resolvedLabels.prompt }}\n </label>\n <div class=\"praxis-ai-assistant-shell__composer\">\n <textarea\n id=\"praxis-ai-assistant-shell-prompt\"\n class=\"praxis-ai-assistant-shell__prompt\"\n [attr.data-testid]=\"testIdPrefix + '-prompt'\"\n [placeholder]=\"resolvedLabels.promptPlaceholder\"\n [ngModel]=\"currentPrompt\"\n [disabled]=\"busy\"\n (ngModelChange)=\"onPromptInput($event)\"\n (keydown)=\"onPromptKeydown($event)\"\n (paste)=\"onPromptPaste($event)\"\n ></textarea>\n <div class=\"praxis-ai-assistant-shell__composer-actions\">\n <ng-container *ngIf=\"showAttachAction\">\n <input\n #attachmentInput\n type=\"file\"\n hidden\n [attr.accept]=\"attachmentAccept || null\"\n [attr.multiple]=\"attachmentMultiple ? '' : null\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-input'\"\n (change)=\"onAttachmentFilesSelected($event)\"\n >\n <button\n mat-stroked-button\n type=\"button\"\n [disabled]=\"busy\"\n (click)=\"onAttachClick(attachmentInput)\"\n [attr.data-testid]=\"testIdPrefix + '-attach'\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ resolvedLabels.attach }}\n </button>\n </ng-container>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--primary\"\n [class.praxis-ai-assistant-shell__action--icon-only]=\"getPrimaryAction().iconOnly\"\n [matTooltip]=\"getPrimaryActionTooltip(getPrimaryAction())\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(getPrimaryAction())\"\n [disabled]=\"isShellActionDisabled(getPrimaryAction())\"\n (click)=\"onShellAction(getPrimaryAction())\"\n [attr.data-testid]=\"getPrimaryAction().testId || (submitTestId || (testIdPrefix + '-submit'))\"\n [attr.aria-label]=\"getPrimaryAction().ariaLabel || getPrimaryAction().label\"\n >\n <mat-icon *ngIf=\"getPrimaryAction().icon\" aria-hidden=\"true\">{{ getPrimaryAction().icon }}</mat-icon>\n <span *ngIf=\"!getPrimaryAction().iconOnly\">{{ getPrimaryAction().label }}</span>\n </button>\n <button\n *ngFor=\"let action of getSecondaryActions(); trackBy: trackShellAction\"\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--secondary\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(action)\"\n [disabled]=\"isShellActionDisabled(action)\"\n (click)=\"onShellAction(action)\"\n [attr.data-testid]=\"action.testId || (testIdPrefix + '-action-' + action.id)\"\n [attr.aria-label]=\"action.ariaLabel || action.label\"\n >\n <mat-icon *ngIf=\"action.icon\" aria-hidden=\"true\">{{ action.icon }}</mat-icon>\n {{ action.label }}\n </button>\n <mat-spinner *ngIf=\"busy\" diameter=\"20\" [attr.data-testid]=\"testIdPrefix + '-spinner'\"></mat-spinner>\n </div>\n </div>\n </footer>\n\n <ng-container *ngIf=\"resizable\">\n <span\n *ngFor=\"let direction of resizeHandles; trackBy: trackResizeHandle\"\n class=\"praxis-ai-assistant-shell__resize-handle praxis-ai-assistant-shell__resize-handle--{{ direction }}\"\n [attr.data-testid]=\"direction === 'se' ? testIdPrefix + '-resize-handle' : testIdPrefix + '-resize-handle-' + direction\"\n aria-hidden=\"true\"\n role=\"presentation\"\n (pointerdown)=\"startResize(direction, $event)\"\n ></span>\n </ng-container>\n</section>\n", styles: [":host{display:block}.praxis-ai-assistant-shell{position:fixed;box-sizing:border-box;min-width:360px;min-height:360px;display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface, #f8fafc);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface, #0f172a);box-shadow:0 24px 60px #0006;z-index:var(--praxis-ai-assistant-shell-z-index, 1200)}.praxis-ai-assistant-shell__header{flex:0 0 auto;display:flex;align-items:flex-start;gap:9px;padding:10px 10px 9px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 72%,transparent);background:var(--md-sys-color-surface-container, #172033)}.praxis-ai-assistant-shell__header{justify-content:flex-start;border-bottom:1px solid;cursor:move;touch-action:none}.praxis-ai-assistant-shell__identity{flex:0 0 auto;display:grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--md-sys-color-primary, #60a5fa);color:var(--md-sys-color-on-primary, #020617);box-shadow:0 6px 16px #60a5fa38}.praxis-ai-assistant-shell__identity mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__title-group{min-width:0;flex:1 1 auto;display:grid;gap:4px}.praxis-ai-assistant-shell__title-row{min-width:0;display:flex;align-items:center;gap:8px}.praxis-ai-assistant-shell__badges{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:4px;min-width:0;flex-wrap:wrap}.praxis-ai-assistant-shell__badge{display:inline-flex;align-items:center;gap:5px;min-height:20px;max-width:120px;padding:2px 7px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 80%,transparent);border-radius:8px;color:var(--md-sys-color-on-surface-variant, #cbd5e1);background:var(--md-sys-color-surface-container-high, #263244);font-size:11px;line-height:1.2;overflow-wrap:anywhere}.praxis-ai-assistant-shell__badge--context{color:var(--md-sys-color-on-surface, #f8fafc);background:color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 9%,var(--md-sys-color-surface-container-high, #263244))}.praxis-ai-assistant-shell__badge--state{border-color:transparent;background:transparent;color:var(--md-sys-color-on-surface-variant, #cbd5e1);padding-inline:3px}.praxis-ai-assistant-shell__badge--error{color:var(--md-sys-color-error, #ff6b6b);border-color:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 60%,transparent)}.praxis-ai-assistant-shell__state-dot{flex:0 0 auto;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-primary, #60a5fa);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 16%,transparent)}.praxis-ai-assistant-shell__badge--error .praxis-ai-assistant-shell__state-dot{background:var(--md-sys-color-error, #ff6b6b);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 16%,transparent)}.praxis-ai-assistant-shell__title-group strong,.praxis-ai-assistant-shell__title-group p{min-width:0;margin:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__title-group strong{flex:1 1 auto;font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__title-group p{color:var(--md-sys-color-on-surface-variant, #cbd5e1);font-size:11.5px;line-height:1.3}.praxis-ai-assistant-shell__header-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-top:-3px}.praxis-ai-assistant-shell__header-actions button{width:34px;height:34px;color:var(--md-sys-color-on-surface-variant, #cbd5e1);opacity:.78}.praxis-ai-assistant-shell__header-actions button:hover,.praxis-ai-assistant-shell__header-actions button:focus-visible{opacity:1}.praxis-ai-assistant-shell__header-actions mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__body{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:12px;padding:14px 14px 8px;overflow:auto;background:linear-gradient(180deg,var(--md-sys-color-surface-container-low, #111827),var(--md-sys-color-surface, #0f172a))}.praxis-ai-assistant-shell__context,.praxis-ai-assistant-shell__attachments{flex:0 0 auto;display:flex;align-items:center;gap:8px;overflow-x:auto}.praxis-ai-assistant-shell__context-item{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;max-width:240px;padding:5px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244);font-size:12px;line-height:1.25}.praxis-ai-assistant-shell__context-item mat-icon{width:16px;height:16px;font-size:16px}.praxis-ai-assistant-shell__context-label,.praxis-ai-assistant-shell__context-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__context-label{color:var(--md-sys-color-on-surface, #f8fafc)}.praxis-ai-assistant-shell__context-value{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-ai-assistant-shell__prompt{box-sizing:border-box;width:100%;min-height:56px;max-height:128px;resize:none;border:0;padding:12px;color:var(--md-sys-color-on-surface, #f8fafc);background:transparent;font:inherit;line-height:1.45;outline:none}.praxis-ai-assistant-shell__conversation{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:8px;overflow:auto;padding:2px}.praxis-ai-assistant-shell__message{max-width:86%;align-self:flex-start;padding:9px 11px;border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244);color:var(--md-sys-color-on-surface, #f8fafc);font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__message-actions{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}.praxis-ai-assistant-shell__message-action{min-height:28px;padding:0 8px;border-radius:8px;font-size:12px}.praxis-ai-assistant-shell__message-action--icon{width:30px;min-width:30px;height:30px;padding:0;color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__message-action--icon mat-icon{width:17px;height:17px;font-size:17px}.praxis-ai-assistant-shell__message--assistant{border-bottom-left-radius:2px}.praxis-ai-assistant-shell__message--user{align-self:flex-end;border-bottom-right-radius:2px;background:var(--md-sys-color-primary-container, #17375f);color:var(--md-sys-color-on-primary-container, #f8fafc)}.praxis-ai-assistant-shell__message--status{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__message--error,.praxis-ai-assistant-shell__error{color:var(--md-sys-color-error, #ff6b6b)}.praxis-ai-assistant-shell__quick-replies{display:flex;flex-wrap:wrap;gap:8px}.praxis-ai-assistant-shell__attachment{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;max-width:260px;min-height:34px;padding:4px 4px 4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244)}.praxis-ai-assistant-shell__attachment--error{border-color:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 60%,transparent)}.praxis-ai-assistant-shell__attachment-preview{flex:0 0 auto;width:28px;height:28px;border-radius:6px;object-fit:cover}.praxis-ai-assistant-shell__attachment-name,.praxis-ai-assistant-shell__attachment-kind{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.praxis-ai-assistant-shell__attachment-name{color:var(--md-sys-color-on-surface, #f8fafc)}.praxis-ai-assistant-shell__attachment-kind{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__quick-reply{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-primary, #60a5fa);--praxis-ai-assistant-shell-quick-reply-background: color-mix( in srgb, var(--praxis-ai-assistant-shell-quick-reply-accent) 12%, var(--md-sys-color-surface-container-high, #263244) );--praxis-ai-assistant-shell-quick-reply-foreground: var(--md-sys-color-on-surface, #f8fafc);max-width:100%;min-height:38px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 58%,transparent);border-radius:8px;color:var(--praxis-ai-assistant-shell-quick-reply-foreground);background:var(--praxis-ai-assistant-shell-quick-reply-background);white-space:normal;text-align:left}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{min-width:0;display:inline-flex;align-items:center;gap:8px;width:100%}.praxis-ai-assistant-shell__quick-reply-icon{flex:0 0 auto;width:18px;height:18px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:18px}.praxis-ai-assistant-shell__quick-reply-details{flex:0 0 auto;width:16px;height:16px;color:var(--md-sys-color-on-surface-variant, #94a3b8);font-size:16px;opacity:.82}.praxis-ai-assistant-shell__quick-reply-copy{min-width:0;display:grid;gap:2px}.praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply-description{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-label{font-weight:600;line-height:1.2}.praxis-ai-assistant-shell__quick-reply-description{color:var(--md-sys-color-on-surface-variant, #cbd5e1);font-size:11px;line-height:1.25}.praxis-ai-assistant-shell__quick-reply--tone-analytics{--praxis-ai-assistant-shell-quick-reply-accent: #38bdf8}.praxis-ai-assistant-shell__quick-reply--tone-resource{--praxis-ai-assistant-shell-quick-reply-accent: #34d399}.praxis-ai-assistant-shell__quick-reply--tone-warning{--praxis-ai-assistant-shell-quick-reply-accent: #facc15}.praxis-ai-assistant-shell__quick-reply--tone-success{--praxis-ai-assistant-shell-quick-reply-accent: #22c55e}.praxis-ai-assistant-shell__quick-reply--tone-danger{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-error, #ff6b6b)}.praxis-ai-assistant-shell__quick-reply--tone-neutral{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-outline, #94a3b8)}.praxis-ai-assistant-shell__status,.praxis-ai-assistant-shell__error{margin:0;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__footer{flex:0 0 auto;padding:10px 12px 12px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 72%,transparent);background:var(--md-sys-color-surface-container-low, #111827)}.praxis-ai-assistant-shell__composer{display:grid;gap:8px;border:1px solid var(--md-sys-color-outline-variant, #334155);border-radius:8px;background:var(--md-sys-color-surface-container-lowest, #020617);box-shadow:inset 0 1px #ffffff0a}.praxis-ai-assistant-shell__composer:focus-within{border-color:var(--md-sys-color-primary, #60a5fa);box-shadow:0 0 0 2px #60a5fa29}.praxis-ai-assistant-shell__composer-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:0 8px 8px;flex-wrap:wrap}.praxis-ai-assistant-shell__action{min-height:36px;border-radius:10px;font-weight:650}.praxis-ai-assistant-shell__action mat-icon{width:18px;height:18px;margin-right:6px;font-size:18px}.praxis-ai-assistant-shell__action--icon-only{width:40px;min-width:40px;height:40px;padding-inline:0;border-radius:50%}.praxis-ai-assistant-shell__action--icon-only mat-icon{margin-right:0}.praxis-ai-assistant-shell__action--secondary{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__action--tone-governance{color:var(--md-sys-color-primary, #60a5fa);background:color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-success{color:#34d399;background:color-mix(in srgb,#34d399 10%,transparent)}.praxis-ai-assistant-shell__action--tone-warning{color:#facc15;background:color-mix(in srgb,#facc15 10%,transparent)}.praxis-ai-assistant-shell__action--tone-danger{color:var(--md-sys-color-error, #ff6b6b);background:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 10%,transparent)}.praxis-ai-assistant-shell__resize-handle{position:absolute;z-index:2;border:0;background:transparent;touch-action:none}.praxis-ai-assistant-shell__resize-handle--n,.praxis-ai-assistant-shell__resize-handle--s{left:16px;right:16px;height:10px;cursor:ns-resize}.praxis-ai-assistant-shell__resize-handle--n{top:-5px}.praxis-ai-assistant-shell__resize-handle--s{bottom:-5px}.praxis-ai-assistant-shell__resize-handle--e,.praxis-ai-assistant-shell__resize-handle--w{top:16px;bottom:16px;width:10px;cursor:ew-resize}.praxis-ai-assistant-shell__resize-handle--e{right:-5px}.praxis-ai-assistant-shell__resize-handle--w{left:-5px}.praxis-ai-assistant-shell__resize-handle--ne,.praxis-ai-assistant-shell__resize-handle--nw,.praxis-ai-assistant-shell__resize-handle--se,.praxis-ai-assistant-shell__resize-handle--sw{width:22px;height:22px}.praxis-ai-assistant-shell__resize-handle--ne{top:-5px;right:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--nw{top:-5px;left:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--se{right:-5px;bottom:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--sw{bottom:-5px;left:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--se:after{content:\"\";position:absolute;right:8px;bottom:8px;width:10px;height:10px;border-right:2px solid var(--md-sys-color-outline, #94a3b8);border-bottom:2px solid var(--md-sys-color-outline, #94a3b8)}\n"] }]
|
|
7524
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n #panel\n class=\"praxis-ai-assistant-shell\"\n role=\"dialog\"\n [attr.aria-label]=\"resolvedLabels.title\"\n [attr.aria-busy]=\"busy ? 'true' : null\"\n [style.left.px]=\"currentLayout.left\"\n [style.top.px]=\"currentLayout.top\"\n [style.width.px]=\"currentLayout.width\"\n [style.height.px]=\"currentLayout.height\"\n [attr.data-testid]=\"panelTestId || testIdPrefix\"\n>\n <header\n class=\"praxis-ai-assistant-shell__header\"\n [attr.data-testid]=\"testIdPrefix + '-drag-handle'\"\n [attr.aria-label]=\"resolvedLabels.dragHandleAria\"\n (pointerdown)=\"startDrag($event)\"\n >\n <div class=\"praxis-ai-assistant-shell__identity\" aria-hidden=\"true\">\n <mat-icon>auto_awesome</mat-icon>\n </div>\n <div class=\"praxis-ai-assistant-shell__title-group\">\n <div class=\"praxis-ai-assistant-shell__title-row\">\n <strong>{{ resolvedLabels.title }}</strong>\n <div class=\"praxis-ai-assistant-shell__badges\" aria-hidden=\"true\">\n <span class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--context\">\n {{ getModeLabel() }}\n </span>\n <span\n class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--state\"\n [class.praxis-ai-assistant-shell__badge--error]=\"state === 'error'\"\n >\n <span class=\"praxis-ai-assistant-shell__state-dot\" aria-hidden=\"true\"></span>\n {{ getStateLabel() }}\n </span>\n </div>\n </div>\n <p *ngIf=\"resolvedLabels.subtitle\">{{ resolvedLabels.subtitle }}</p>\n </div>\n <div class=\"praxis-ai-assistant-shell__header-actions\">\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"getResetLayoutLabel()\"\n [attr.aria-label]=\"getResetLayoutLabel()\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"resetLayout()\"\n [attr.data-testid]=\"testIdPrefix + '-reset-layout'\"\n >\n <mat-icon>center_focus_strong</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"resolvedLabels.close\"\n [attr.aria-label]=\"resolvedLabels.close\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"close.emit()\"\n [attr.data-testid]=\"testIdPrefix + '-close'\"\n >\n <mat-icon>{{ getCloseIcon() }}</mat-icon>\n </button>\n </div>\n </header>\n\n <div class=\"praxis-ai-assistant-shell__body\">\n <div\n *ngIf=\"contextItems.length\"\n class=\"praxis-ai-assistant-shell__context\"\n [attr.aria-label]=\"resolvedLabels.contextAria\"\n [attr.data-testid]=\"testIdPrefix + '-context'\"\n >\n <span\n *ngFor=\"let item of contextItems; trackBy: trackContextItem\"\n class=\"praxis-ai-assistant-shell__context-item\"\n [attr.data-testid]=\"testIdPrefix + '-context-' + item.id\"\n >\n <mat-icon *ngIf=\"item.icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__context-label\">{{ item.label }}</span>\n <span *ngIf=\"item.value\" class=\"praxis-ai-assistant-shell__context-value\">{{ item.value }}</span>\n </span>\n </div>\n\n <div\n #conversation\n class=\"praxis-ai-assistant-shell__conversation\"\n [attr.data-testid]=\"testIdPrefix + '-conversation'\"\n [attr.aria-label]=\"resolvedLabels.conversationAria\"\n >\n <article\n *ngIf=\"!messages.length\"\n class=\"praxis-ai-assistant-shell__message praxis-ai-assistant-shell__message--assistant\"\n [attr.data-testid]=\"testIdPrefix + '-message-assistant-empty'\"\n >\n {{ resolvedLabels.emptyConversation }}\n </article>\n <article\n *ngFor=\"let message of messages; trackBy: trackMessage\"\n class=\"praxis-ai-assistant-shell__message\"\n [class.praxis-ai-assistant-shell__message--user]=\"message.role === 'user'\"\n [class.praxis-ai-assistant-shell__message--assistant]=\"message.role === 'assistant'\"\n [class.praxis-ai-assistant-shell__message--status]=\"message.role === 'status'\"\n [class.praxis-ai-assistant-shell__message--error]=\"message.role === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-message-' + message.role\"\n >\n {{ message.text }}\n <div\n *ngIf=\"message.actions?.length || message.editable || message.resendable\"\n class=\"praxis-ai-assistant-shell__message-actions\"\n >\n <button\n *ngIf=\"message.editable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.editMessage\"\n [attr.aria-label]=\"resolvedLabels.editMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-edit-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'edit', label: resolvedLabels.editMessage, kind: 'edit' })\"\n >\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n <button\n *ngIf=\"message.resendable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.resendMessage\"\n [attr.aria-label]=\"resolvedLabels.resendMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-resend-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'resend', label: resolvedLabels.resendMessage, kind: 'resend' })\"\n >\n <mat-icon aria-hidden=\"true\">replay</mat-icon>\n </button>\n <ng-container *ngFor=\"let action of message.actions || []; trackBy: trackMessageAction\">\n <button\n *ngIf=\"isMessageActionIconOnly(action); else textualMessageAction\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy || action.disabled\"\n [matTooltip]=\"getMessageActionLabel(action)\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n <mat-icon aria-hidden=\"true\">{{ getMessageActionIcon(action) }}</mat-icon>\n </button>\n <ng-template #textualMessageAction>\n <button\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action\"\n [disabled]=\"busy || action.disabled\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n {{ action.label }}\n </button>\n </ng-template>\n </ng-container>\n </div>\n </article>\n </div>\n\n <div\n *ngIf=\"attachments.length\"\n class=\"praxis-ai-assistant-shell__attachments\"\n [attr.aria-label]=\"resolvedLabels.attachmentsAria\"\n [attr.data-testid]=\"testIdPrefix + '-attachments'\"\n >\n <div\n *ngFor=\"let attachment of attachments; trackBy: trackAttachment\"\n class=\"praxis-ai-assistant-shell__attachment\"\n [class.praxis-ai-assistant-shell__attachment--error]=\"attachment.status === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-' + attachment.id\"\n >\n <img\n *ngIf=\"attachment.previewUrl && attachment.kind === 'image'\"\n class=\"praxis-ai-assistant-shell__attachment-preview\"\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.name\"\n >\n <span class=\"praxis-ai-assistant-shell__attachment-name\">{{ attachment.name }}</span>\n <span class=\"praxis-ai-assistant-shell__attachment-kind\">{{ attachment.kind }}</span>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.removeAttachment\"\n [attr.aria-label]=\"resolvedLabels.removeAttachment + ': ' + attachment.name\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-remove-' + attachment.id\"\n (click)=\"onRemoveAttachment(attachment)\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div\n *ngIf=\"quickReplies.length\"\n class=\"praxis-ai-assistant-shell__quick-replies\"\n [attr.data-testid]=\"testIdPrefix + '-quick-replies'\"\n [attr.aria-label]=\"resolvedLabels.quickRepliesAria\"\n >\n <button\n *ngFor=\"let reply of quickReplies; trackBy: trackQuickReply\"\n mat-stroked-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__quick-reply\"\n [ngClass]=\"'praxis-ai-assistant-shell__quick-reply--tone-' + getQuickReplyTone(reply)\"\n [attr.data-testid]=\"testIdPrefix + '-quick-reply-' + (reply.id || reply.kind)\"\n [attr.aria-label]=\"getQuickReplyAriaLabel(reply)\"\n [disabled]=\"busy\"\n (click)=\"onQuickReply(reply)\"\n >\n <span class=\"praxis-ai-assistant-shell__quick-reply-icon-frame\" aria-hidden=\"true\">\n <mat-icon\n class=\"praxis-ai-assistant-shell__quick-reply-icon\"\n >\n {{ getQuickReplyIcon(reply) }}\n </mat-icon>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-header\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-label\">{{ reply.label }}</span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-badge\">\n {{ getQuickReplyCategoryLabel(reply) }}\n </span>\n </span>\n <span\n *ngIf=\"reply.description\"\n class=\"praxis-ai-assistant-shell__quick-reply-description\"\n >\n {{ reply.description }}\n </span>\n <span\n *ngIf=\"getQuickReplyPresentationItems(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-insights\"\n >\n <span\n *ngFor=\"let item of getQuickReplyPresentationItems(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-insight\"\n >\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-label\">\n {{ item.label }}\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-value\">\n {{ item.value }}\n </span>\n </span>\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-cta\">\n {{ getQuickReplyCtaLabel(reply) }}\n <mat-icon aria-hidden=\"true\">arrow_forward</mat-icon>\n </span>\n </span>\n <mat-icon\n *ngIf=\"getQuickReplyTechnicalDetails(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-details\"\n [matTooltip]=\"getQuickReplyTechnicalDetails(reply)\"\n [attr.aria-label]=\"resolvedLabels.quickReplyDetails\"\n >\n info\n </mat-icon>\n </button>\n </div>\n <p\n *ngIf=\"statusText\"\n class=\"praxis-ai-assistant-shell__status\"\n [attr.data-testid]=\"testIdPrefix + '-status'\"\n >\n {{ statusText }}\n </p>\n <p\n *ngIf=\"errorText\"\n class=\"praxis-ai-assistant-shell__error\"\n [attr.data-testid]=\"testIdPrefix + '-error'\"\n >\n {{ errorText }}\n </p>\n </div>\n\n <footer class=\"praxis-ai-assistant-shell__footer\">\n <label class=\"praxis-ai-assistant-shell__label\" for=\"praxis-ai-assistant-shell-prompt\">\n {{ resolvedLabels.prompt }}\n </label>\n <div class=\"praxis-ai-assistant-shell__composer\">\n <textarea\n id=\"praxis-ai-assistant-shell-prompt\"\n class=\"praxis-ai-assistant-shell__prompt\"\n [attr.data-testid]=\"testIdPrefix + '-prompt'\"\n [placeholder]=\"resolvedLabels.promptPlaceholder\"\n [ngModel]=\"currentPrompt\"\n [disabled]=\"busy\"\n (ngModelChange)=\"onPromptInput($event)\"\n (keydown)=\"onPromptKeydown($event)\"\n (paste)=\"onPromptPaste($event)\"\n ></textarea>\n <div class=\"praxis-ai-assistant-shell__composer-actions\">\n <ng-container *ngIf=\"showAttachAction\">\n <input\n #attachmentInput\n type=\"file\"\n hidden\n [attr.accept]=\"attachmentAccept || null\"\n [attr.multiple]=\"attachmentMultiple ? '' : null\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-input'\"\n (change)=\"onAttachmentFilesSelected($event)\"\n >\n <button\n mat-stroked-button\n type=\"button\"\n [disabled]=\"busy\"\n (click)=\"onAttachClick(attachmentInput)\"\n [attr.data-testid]=\"testIdPrefix + '-attach'\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ resolvedLabels.attach }}\n </button>\n </ng-container>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--primary\"\n [class.praxis-ai-assistant-shell__action--icon-only]=\"getPrimaryAction().iconOnly\"\n [matTooltip]=\"getPrimaryActionTooltip(getPrimaryAction())\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(getPrimaryAction())\"\n [disabled]=\"isShellActionDisabled(getPrimaryAction())\"\n (click)=\"onShellAction(getPrimaryAction())\"\n [attr.data-testid]=\"getPrimaryAction().testId || (submitTestId || (testIdPrefix + '-submit'))\"\n [attr.aria-label]=\"getPrimaryAction().ariaLabel || getPrimaryAction().label\"\n >\n <mat-icon *ngIf=\"getPrimaryAction().icon\" aria-hidden=\"true\">{{ getPrimaryAction().icon }}</mat-icon>\n <span *ngIf=\"!getPrimaryAction().iconOnly\">{{ getPrimaryAction().label }}</span>\n </button>\n <button\n *ngFor=\"let action of getSecondaryActions(); trackBy: trackShellAction\"\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--secondary\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(action)\"\n [disabled]=\"isShellActionDisabled(action)\"\n (click)=\"onShellAction(action)\"\n [attr.data-testid]=\"action.testId || (testIdPrefix + '-action-' + action.id)\"\n [attr.aria-label]=\"action.ariaLabel || action.label\"\n >\n <mat-icon *ngIf=\"action.icon\" aria-hidden=\"true\">{{ action.icon }}</mat-icon>\n {{ action.label }}\n </button>\n <mat-spinner *ngIf=\"busy\" diameter=\"20\" [attr.data-testid]=\"testIdPrefix + '-spinner'\"></mat-spinner>\n </div>\n </div>\n </footer>\n\n <ng-container *ngIf=\"resizable\">\n <span\n *ngFor=\"let direction of resizeHandles; trackBy: trackResizeHandle\"\n class=\"praxis-ai-assistant-shell__resize-handle praxis-ai-assistant-shell__resize-handle--{{ direction }}\"\n [attr.data-testid]=\"direction === 'se' ? testIdPrefix + '-resize-handle' : testIdPrefix + '-resize-handle-' + direction\"\n aria-hidden=\"true\"\n role=\"presentation\"\n (pointerdown)=\"startResize(direction, $event)\"\n ></span>\n </ng-container>\n</section>\n", styles: [":host{display:block}.praxis-ai-assistant-shell{position:fixed;box-sizing:border-box;min-width:360px;min-height:360px;display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface, #f8fafc);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface, #0f172a);box-shadow:0 24px 60px #0006;z-index:var(--praxis-ai-assistant-shell-z-index, 1200)}.praxis-ai-assistant-shell__header{flex:0 0 auto;display:flex;align-items:flex-start;gap:9px;padding:10px 10px 9px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 72%,transparent);background:var(--md-sys-color-surface-container, #172033)}.praxis-ai-assistant-shell__header{justify-content:flex-start;border-bottom:1px solid;cursor:move;touch-action:none}.praxis-ai-assistant-shell__identity{flex:0 0 auto;display:grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--md-sys-color-primary, #60a5fa);color:var(--md-sys-color-on-primary, #020617);box-shadow:0 6px 16px #60a5fa38}.praxis-ai-assistant-shell__identity mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__title-group{min-width:0;flex:1 1 auto;display:grid;gap:4px}.praxis-ai-assistant-shell__title-row{min-width:0;display:flex;align-items:center;gap:8px}.praxis-ai-assistant-shell__badges{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:4px;min-width:0;flex-wrap:wrap}.praxis-ai-assistant-shell__badge{display:inline-flex;align-items:center;gap:5px;min-height:20px;max-width:120px;padding:2px 7px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 80%,transparent);border-radius:8px;color:var(--md-sys-color-on-surface-variant, #cbd5e1);background:var(--md-sys-color-surface-container-high, #263244);font-size:11px;line-height:1.2;overflow-wrap:anywhere}.praxis-ai-assistant-shell__badge--context{color:var(--md-sys-color-on-surface, #f8fafc);background:color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 9%,var(--md-sys-color-surface-container-high, #263244))}.praxis-ai-assistant-shell__badge--state{border-color:transparent;background:transparent;color:var(--md-sys-color-on-surface-variant, #cbd5e1);padding-inline:3px}.praxis-ai-assistant-shell__badge--error{color:var(--md-sys-color-error, #ff6b6b);border-color:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 60%,transparent)}.praxis-ai-assistant-shell__state-dot{flex:0 0 auto;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-primary, #60a5fa);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 16%,transparent)}.praxis-ai-assistant-shell__badge--error .praxis-ai-assistant-shell__state-dot{background:var(--md-sys-color-error, #ff6b6b);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 16%,transparent)}.praxis-ai-assistant-shell__title-group strong,.praxis-ai-assistant-shell__title-group p{min-width:0;margin:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__title-group strong{flex:1 1 auto;font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__title-group p{color:var(--md-sys-color-on-surface-variant, #cbd5e1);font-size:11.5px;line-height:1.3}.praxis-ai-assistant-shell__header-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-top:-3px}.praxis-ai-assistant-shell__header-actions button{width:34px;height:34px;color:var(--md-sys-color-on-surface-variant, #cbd5e1);opacity:.78}.praxis-ai-assistant-shell__header-actions button:hover,.praxis-ai-assistant-shell__header-actions button:focus-visible{opacity:1}.praxis-ai-assistant-shell__header-actions mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__body{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:12px;padding:14px 14px 8px;overflow:auto;background:linear-gradient(180deg,var(--md-sys-color-surface-container-low, #111827),var(--md-sys-color-surface, #0f172a))}.praxis-ai-assistant-shell__context,.praxis-ai-assistant-shell__attachments{flex:0 0 auto;display:flex;align-items:center;gap:8px;overflow-x:auto}.praxis-ai-assistant-shell__context-item{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;max-width:240px;padding:5px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244);font-size:12px;line-height:1.25}.praxis-ai-assistant-shell__context-item mat-icon{width:16px;height:16px;font-size:16px}.praxis-ai-assistant-shell__context-label,.praxis-ai-assistant-shell__context-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__context-label{color:var(--md-sys-color-on-surface, #f8fafc)}.praxis-ai-assistant-shell__context-value{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-ai-assistant-shell__prompt{box-sizing:border-box;width:100%;min-height:56px;max-height:128px;resize:none;border:0;padding:12px;color:var(--md-sys-color-on-surface, #f8fafc);background:transparent;font:inherit;line-height:1.45;outline:none}.praxis-ai-assistant-shell__conversation{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:8px;overflow:auto;padding:2px}.praxis-ai-assistant-shell__message{max-width:86%;align-self:flex-start;padding:9px 11px;border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244);color:var(--md-sys-color-on-surface, #f8fafc);font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__message-actions{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}.praxis-ai-assistant-shell__message-action{min-height:28px;padding:0 8px;border-radius:8px;font-size:12px}.praxis-ai-assistant-shell__message-action--icon{width:30px;min-width:30px;height:30px;padding:0;color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__message-action--icon mat-icon{width:17px;height:17px;font-size:17px}.praxis-ai-assistant-shell__message--assistant{border-bottom-left-radius:2px}.praxis-ai-assistant-shell__message--user{align-self:flex-end;border-bottom-right-radius:2px;background:var(--md-sys-color-primary-container, #17375f);color:var(--md-sys-color-on-primary-container, #f8fafc)}.praxis-ai-assistant-shell__message--status{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__message--error,.praxis-ai-assistant-shell__error{color:var(--md-sys-color-error, #ff6b6b)}.praxis-ai-assistant-shell__quick-replies{display:flex;flex-wrap:wrap;gap:10px;align-items:stretch}.praxis-ai-assistant-shell__attachment{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;max-width:260px;min-height:34px;padding:4px 4px 4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high, #263244)}.praxis-ai-assistant-shell__attachment--error{border-color:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 60%,transparent)}.praxis-ai-assistant-shell__attachment-preview{flex:0 0 auto;width:28px;height:28px;border-radius:6px;object-fit:cover}.praxis-ai-assistant-shell__attachment-name,.praxis-ai-assistant-shell__attachment-kind{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.praxis-ai-assistant-shell__attachment-name{color:var(--md-sys-color-on-surface, #f8fafc)}.praxis-ai-assistant-shell__attachment-kind{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__quick-reply{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-primary, #60a5fa);--praxis-ai-assistant-shell-quick-reply-background: color-mix( in srgb, var(--praxis-ai-assistant-shell-quick-reply-accent) 9%, var(--md-sys-color-surface-container-high, #263244) );--praxis-ai-assistant-shell-quick-reply-foreground: var(--md-sys-color-on-surface, #f8fafc);width:min(100%,680px);max-width:100%;height:auto;min-height:0;padding:14px;align-items:stretch;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 42%,transparent);border-radius:20px;color:var(--praxis-ai-assistant-shell-quick-reply-foreground);background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 20%,transparent),transparent 52%),radial-gradient(circle at 92% 10%,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 20%,transparent),transparent 34%),var(--praxis-ai-assistant-shell-quick-reply-background);box-shadow:0 16px 36px color-mix(in srgb,#000 20%,transparent),inset 0 1px color-mix(in srgb,#fff 14%,transparent);letter-spacing:normal;white-space:normal;text-align:left;text-transform:none;-webkit-user-select:none;user-select:none;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease,background .16s ease;--mdc-outlined-button-container-height: auto;--mat-outlined-button-horizontal-padding: 0}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 74%,transparent);box-shadow:0 18px 42px color-mix(in srgb,#000 24%,transparent),0 0 0 3px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 18%,transparent),inset 0 1px color-mix(in srgb,#fff 18%,transparent);transform:translateY(-1px)}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{min-width:0;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:flex-start;gap:13px;width:100%;height:auto;line-height:normal}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mat-mdc-button-touch-target{height:100%;min-height:48px}.praxis-ai-assistant-shell__quick-reply-icon-frame{flex:0 0 auto;width:42px;height:42px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 28%,transparent);border-radius:15px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);background:linear-gradient(145deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent),color-mix(in srgb,#fff 5%,transparent))}.praxis-ai-assistant-shell__quick-reply-icon{width:24px;height:24px;font-size:24px}.praxis-ai-assistant-shell__quick-reply-details{flex:0 0 auto;width:22px;height:22px;display:inline-grid;place-items:center;border-radius:50%;color:var(--md-sys-color-on-surface-variant, #94a3b8);background:color-mix(in srgb,var(--md-sys-color-outline, #94a3b8) 14%,transparent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-copy{min-width:0;display:grid;gap:9px;flex:1 1 auto}.praxis-ai-assistant-shell__quick-reply-header{min-width:0;display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply-description{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-label{color:var(--md-sys-color-on-surface, #f8fafc);font-size:17px;font-weight:760;letter-spacing:.005em;line-height:1.18;text-transform:none}.praxis-ai-assistant-shell__quick-reply-badge{flex:0 0 auto;max-width:42%;padding:4px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 28%,transparent);border-radius:999px;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 86%,#fff);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 11%,transparent);font-size:10.5px;font-weight:700;letter-spacing:.02em;line-height:1.1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-description{color:color-mix(in srgb,var(--md-sys-color-on-surface, #f8fafc) 78%,transparent);font-size:13px;line-height:1.42}.praxis-ai-assistant-shell__quick-reply-insights{display:grid;gap:6px;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 18%,transparent);border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-lowest, #020617) 30%,transparent)}.praxis-ai-assistant-shell__quick-reply-insight{min-width:0;display:grid;grid-template-columns:18px minmax(0,1fr);gap:8px;align-items:start;color:color-mix(in srgb,var(--md-sys-color-on-surface, #f8fafc) 86%,transparent);font-size:12px;line-height:1.35}.praxis-ai-assistant-shell__quick-reply-insight mat-icon{width:17px;height:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-insight-copy{min-width:0;display:grid;gap:1px}.praxis-ai-assistant-shell__quick-reply-insight-label{color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 82%,#fff);font-size:10.5px;font-weight:760;letter-spacing:.045em;line-height:1.2;text-transform:uppercase}.praxis-ai-assistant-shell__quick-reply-insight-value{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-cta{display:inline-flex;align-items:center;justify-self:start;gap:5px;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 84%,#fff);font-size:12px;font-weight:760;letter-spacing:.01em;line-height:1.2}.praxis-ai-assistant-shell__quick-reply-cta mat-icon{width:15px;height:15px;font-size:15px;transition:transform .16s ease}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled) .praxis-ai-assistant-shell__quick-reply-cta mat-icon,.praxis-ai-assistant-shell__quick-reply:focus-visible .praxis-ai-assistant-shell__quick-reply-cta mat-icon{transform:translate(2px)}.praxis-ai-assistant-shell__quick-reply--tone-analytics{--praxis-ai-assistant-shell-quick-reply-accent: #38bdf8}.praxis-ai-assistant-shell__quick-reply--tone-resource{--praxis-ai-assistant-shell-quick-reply-accent: #34d399}.praxis-ai-assistant-shell__quick-reply--tone-warning{--praxis-ai-assistant-shell-quick-reply-accent: #facc15}.praxis-ai-assistant-shell__quick-reply--tone-success{--praxis-ai-assistant-shell-quick-reply-accent: #22c55e}.praxis-ai-assistant-shell__quick-reply--tone-danger{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-error, #ff6b6b)}.praxis-ai-assistant-shell__quick-reply--tone-neutral{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-outline, #94a3b8)}.praxis-ai-assistant-shell__status,.praxis-ai-assistant-shell__error{margin:0;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__footer{flex:0 0 auto;padding:10px 12px 12px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #334155) 72%,transparent);background:var(--md-sys-color-surface-container-low, #111827)}.praxis-ai-assistant-shell__composer{display:grid;gap:8px;border:1px solid var(--md-sys-color-outline-variant, #334155);border-radius:8px;background:var(--md-sys-color-surface-container-lowest, #020617);box-shadow:inset 0 1px #ffffff0a}.praxis-ai-assistant-shell__composer:focus-within{border-color:var(--md-sys-color-primary, #60a5fa);box-shadow:0 0 0 2px #60a5fa29}.praxis-ai-assistant-shell__composer-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:0 8px 8px;flex-wrap:wrap}.praxis-ai-assistant-shell__action{min-height:36px;border-radius:10px;font-weight:650}.praxis-ai-assistant-shell__action mat-icon{width:18px;height:18px;margin-right:6px;font-size:18px}.praxis-ai-assistant-shell__action--icon-only{width:40px;min-width:40px;height:40px;padding-inline:0;border-radius:50%}.praxis-ai-assistant-shell__action--icon-only mat-icon{margin-right:0}.praxis-ai-assistant-shell__action--secondary{color:var(--md-sys-color-on-surface-variant, #cbd5e1)}.praxis-ai-assistant-shell__action--tone-governance{color:var(--md-sys-color-primary, #60a5fa);background:color-mix(in srgb,var(--md-sys-color-primary, #60a5fa) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-success{color:#34d399;background:color-mix(in srgb,#34d399 10%,transparent)}.praxis-ai-assistant-shell__action--tone-warning{color:#facc15;background:color-mix(in srgb,#facc15 10%,transparent)}.praxis-ai-assistant-shell__action--tone-danger{color:var(--md-sys-color-error, #ff6b6b);background:color-mix(in srgb,var(--md-sys-color-error, #ff6b6b) 10%,transparent)}.praxis-ai-assistant-shell__resize-handle{position:absolute;z-index:2;border:0;background:transparent;touch-action:none}.praxis-ai-assistant-shell__resize-handle--n,.praxis-ai-assistant-shell__resize-handle--s{left:16px;right:16px;height:10px;cursor:ns-resize}.praxis-ai-assistant-shell__resize-handle--n{top:-5px}.praxis-ai-assistant-shell__resize-handle--s{bottom:-5px}.praxis-ai-assistant-shell__resize-handle--e,.praxis-ai-assistant-shell__resize-handle--w{top:16px;bottom:16px;width:10px;cursor:ew-resize}.praxis-ai-assistant-shell__resize-handle--e{right:-5px}.praxis-ai-assistant-shell__resize-handle--w{left:-5px}.praxis-ai-assistant-shell__resize-handle--ne,.praxis-ai-assistant-shell__resize-handle--nw,.praxis-ai-assistant-shell__resize-handle--se,.praxis-ai-assistant-shell__resize-handle--sw{width:22px;height:22px}.praxis-ai-assistant-shell__resize-handle--ne{top:-5px;right:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--nw{top:-5px;left:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--se{right:-5px;bottom:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--sw{bottom:-5px;left:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--se:after{content:\"\";position:absolute;right:8px;bottom:8px;width:10px;height:10px;border-right:2px solid var(--md-sys-color-outline, #94a3b8);border-bottom:2px solid var(--md-sys-color-outline, #94a3b8)}\n"] }]
|
|
7199
7525
|
}], propDecorators: { labels: [{
|
|
7200
7526
|
type: Input
|
|
7201
7527
|
}], mode: [{
|
|
@@ -8372,4 +8698,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
8372
8698
|
* Generated bundle index. Do not edit.
|
|
8373
8699
|
*/
|
|
8374
8700
|
|
|
8375
|
-
export { AI_BACKEND_CONFIG_STORE, AI_BACKEND_STORAGE_OPTIONS, AI_CONTRACT_SCHEMA_HASH, AI_CONTRACT_VERSION, AI_INTENT_CONTRACT_SCHEMA_HASH, AI_INTENT_CONTRACT_VERSION, AI_STREAM_EVENT_SCHEMA_VERSION, AI_STREAM_EVENT_TYPES, AiBackendApiService, AiPatchStreamConnectionError, AiResponseValidatorService, AiRuleWizardDialogComponent, BaseAiAdapter, PRAXIS_ASSISTANT_CONTEXT_ATTACHMENT_LIMIT, PRAXIS_ASSISTANT_CONTEXT_ITEM_LIMIT, PRAXIS_ASSISTANT_CONTEXT_SCHEMA_FIELD_LIMIT, PRAXIS_ASSISTANT_CONTEXT_TEXT_LIMIT, PraxisAi, PraxisAiAssistantComponent, PraxisAiAssistantDockComponent, PraxisAiAssistantSessionHostComponent, PraxisAiAssistantShellComponent, PraxisAiService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnController, PraxisAssistantTurnOrchestratorService, SchemaMinifierService, createPraxisAssistantViewportLayout, normalizePraxisAssistantAttachmentSummary, normalizePraxisAssistantContextSnapshot, sanitizePraxisAssistantText, toPraxisAssistantConversationMessages };
|
|
8701
|
+
export { AI_BACKEND_CONFIG_STORE, AI_BACKEND_STORAGE_OPTIONS, AI_CONTRACT_SCHEMA_HASH, AI_CONTRACT_VERSION, AI_INTENT_CONTRACT_SCHEMA_HASH, AI_INTENT_CONTRACT_VERSION, AI_STREAM_EVENT_SCHEMA_VERSION, AI_STREAM_EVENT_TYPES, AiBackendApiService, AiPatchStreamConnectionError, AiResponseValidatorService, AiRuleWizardDialogComponent, BaseAiAdapter, PRAXIS_ASSISTANT_CONTEXT_ATTACHMENT_LIMIT, PRAXIS_ASSISTANT_CONTEXT_ITEM_LIMIT, PRAXIS_ASSISTANT_CONTEXT_SCHEMA_FIELD_LIMIT, PRAXIS_ASSISTANT_CONTEXT_TEXT_LIMIT, PraxisAi, PraxisAiAssistantComponent, PraxisAiAssistantDockComponent, PraxisAiAssistantSessionHostComponent, PraxisAiAssistantShellComponent, PraxisAiService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnController, PraxisAssistantTurnOrchestratorService, SchemaMinifierService, createPraxisAssistantViewportLayout, normalizeAuthoringPrompt, normalizePraxisAssistantAttachmentSummary, normalizePraxisAssistantContextSnapshot, sanitizePraxisAssistantText, shouldRoutePromptToGovernedDecision, toPraxisAssistantConversationMessages };
|
package/index.d.ts
CHANGED
|
@@ -1029,6 +1029,12 @@ declare abstract class BaseAiAdapter<TConfig = any> implements AiConfigAdapter<T
|
|
|
1029
1029
|
protected getCriticalWarnings(patch: any): string[];
|
|
1030
1030
|
}
|
|
1031
1031
|
|
|
1032
|
+
interface AiGovernedDecisionRoutingOptions {
|
|
1033
|
+
localCompositionTerms?: readonly string[];
|
|
1034
|
+
}
|
|
1035
|
+
declare function shouldRoutePromptToGovernedDecision(prompt: string, contextHints?: AiJsonObject, options?: AiGovernedDecisionRoutingOptions): boolean;
|
|
1036
|
+
declare function normalizeAuthoringPrompt(prompt: string): string;
|
|
1037
|
+
|
|
1032
1038
|
interface FieldSchemaLike {
|
|
1033
1039
|
label: string;
|
|
1034
1040
|
type: string;
|
|
@@ -1262,6 +1268,8 @@ declare class AiBackendApiService {
|
|
|
1262
1268
|
private buildHeaders;
|
|
1263
1269
|
private normalizeContractVersion;
|
|
1264
1270
|
private normalizeContractSchemaHash;
|
|
1271
|
+
private normalizeLegacyPatchConversationIds;
|
|
1272
|
+
private isUuid;
|
|
1265
1273
|
private authoringManifestUrl;
|
|
1266
1274
|
private resolveHeaderMap;
|
|
1267
1275
|
private parsePatchStreamEnvelope;
|
|
@@ -1352,6 +1360,12 @@ declare class PraxisAssistantTurnController {
|
|
|
1352
1360
|
private patchState;
|
|
1353
1361
|
private cloneState;
|
|
1354
1362
|
private toObservable;
|
|
1363
|
+
private buildFlowErrorResult;
|
|
1364
|
+
private describeFlowError;
|
|
1365
|
+
private serializeFlowError;
|
|
1366
|
+
private toRecord;
|
|
1367
|
+
private toString;
|
|
1368
|
+
private toNumber;
|
|
1355
1369
|
}
|
|
1356
1370
|
|
|
1357
1371
|
type PraxisAssistantSessionVisibility = 'active' | 'minimized';
|
|
@@ -1846,6 +1860,12 @@ declare class PraxisAiAssistantComponent implements OnDestroy {
|
|
|
1846
1860
|
}
|
|
1847
1861
|
|
|
1848
1862
|
type ResizeDirection = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';
|
|
1863
|
+
interface QuickReplyPresentationItem {
|
|
1864
|
+
key: 'bestFor' | 'returns' | 'nextStep';
|
|
1865
|
+
label: string;
|
|
1866
|
+
icon: string;
|
|
1867
|
+
value: string;
|
|
1868
|
+
}
|
|
1849
1869
|
declare class PraxisAiAssistantShellComponent implements OnChanges, OnDestroy {
|
|
1850
1870
|
labels: Partial<PraxisAssistantShellLabels> | null;
|
|
1851
1871
|
mode: PraxisAssistantShellMode;
|
|
@@ -1931,9 +1951,15 @@ declare class PraxisAiAssistantShellComponent implements OnChanges, OnDestroy {
|
|
|
1931
1951
|
protected onQuickReply(reply: PraxisAssistantShellQuickReply): void;
|
|
1932
1952
|
protected getQuickReplyAriaLabel(reply: PraxisAssistantShellQuickReply): string;
|
|
1933
1953
|
protected getQuickReplyTechnicalDetails(reply: PraxisAssistantShellQuickReply): string;
|
|
1954
|
+
protected getQuickReplyPresentationItems(reply: PraxisAssistantShellQuickReply): readonly QuickReplyPresentationItem[];
|
|
1955
|
+
private defaultQuickReplyPresentation;
|
|
1956
|
+
protected getQuickReplyCategoryLabel(reply: PraxisAssistantShellQuickReply): string;
|
|
1957
|
+
protected getQuickReplyIcon(reply: PraxisAssistantShellQuickReply): string;
|
|
1958
|
+
protected getQuickReplyCtaLabel(reply: PraxisAssistantShellQuickReply): string;
|
|
1934
1959
|
protected getQuickReplyTone(reply: PraxisAssistantShellQuickReply): string;
|
|
1935
1960
|
private asRecord;
|
|
1936
1961
|
private stringHint;
|
|
1962
|
+
private trimSentencePunctuation;
|
|
1937
1963
|
protected getCloseIcon(): string;
|
|
1938
1964
|
protected getResetLayoutLabel(): string;
|
|
1939
1965
|
protected resetLayout(): void;
|
|
@@ -2087,5 +2113,5 @@ declare class AiRuleWizardDialogComponent implements OnInit {
|
|
|
2087
2113
|
static ɵcmp: i0.ɵɵComponentDeclaration<AiRuleWizardDialogComponent, "praxis-ai-rule-wizard-dialog", never, {}, {}, never, never, true, never>;
|
|
2088
2114
|
}
|
|
2089
2115
|
|
|
2090
|
-
export { AI_BACKEND_CONFIG_STORE, AI_BACKEND_STORAGE_OPTIONS, AI_CONTRACT_SCHEMA_HASH, AI_CONTRACT_VERSION, AI_INTENT_CONTRACT_SCHEMA_HASH, AI_INTENT_CONTRACT_VERSION, AI_STREAM_EVENT_SCHEMA_VERSION, AI_STREAM_EVENT_TYPES, AiBackendApiService, AiPatchStreamConnectionError, AiResponseValidatorService, AiRuleWizardDialogComponent, BaseAiAdapter, PRAXIS_ASSISTANT_CONTEXT_ATTACHMENT_LIMIT, PRAXIS_ASSISTANT_CONTEXT_ITEM_LIMIT, PRAXIS_ASSISTANT_CONTEXT_SCHEMA_FIELD_LIMIT, PRAXIS_ASSISTANT_CONTEXT_TEXT_LIMIT, PraxisAi, PraxisAiAssistantComponent, PraxisAiAssistantDockComponent, PraxisAiAssistantSessionHostComponent, PraxisAiAssistantShellComponent, PraxisAiService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnController, PraxisAssistantTurnOrchestratorService, SchemaMinifierService, createPraxisAssistantViewportLayout, normalizePraxisAssistantAttachmentSummary, normalizePraxisAssistantContextSnapshot, sanitizePraxisAssistantText, toPraxisAssistantConversationMessages };
|
|
2091
|
-
export type { AgenticAuthoringApplyRequestContract, AgenticAuthoringApplyResultContract, AgenticAuthoringAttachmentSummaryContract, AgenticAuthoringCandidateContract, AgenticAuthoringComponentCapabilitiesResultContract, AgenticAuthoringComponentCapabilityCatalogContract, AgenticAuthoringComponentCapabilityContract, AgenticAuthoringComponentCapabilityExampleContract, AgenticAuthoringComponentFieldAliasContract, AgenticAuthoringConversationContextContract, AgenticAuthoringConversationMessageContract, AgenticAuthoringIntentResolutionRequestContract, AgenticAuthoringIntentResolutionResultContract, AgenticAuthoringManifestCompileResult, AgenticAuthoringManifestCompileResultContract, AgenticAuthoringManifestEditPlanRequest, AgenticAuthoringManifestEditPlanRequestContract, AgenticAuthoringManifestValidationResult, AgenticAuthoringManifestValidationResultContract, AgenticAuthoringPendingClarificationContract, AgenticAuthoringPlanRequestContract, AgenticAuthoringPreviewResultContract, AgenticAuthoringQuickReplyContract, AgenticAuthoringResolveTargetRequest, AgenticAuthoringResolveTargetRequestContract, AgenticAuthoringResolvedTarget, AgenticAuthoringResolvedTargetContract, AgenticAuthoringResourceCandidatesRequestContract, AgenticAuthoringResourceCandidatesResultContract, AgenticAuthoringTurnStreamConnection, AgenticAuthoringTurnStreamEnvelope, AgenticAuthoringTurnStreamEnvelopeContract, AgenticAuthoringTurnStreamRequest, AgenticAuthoringTurnStreamRequestContract, AgenticAuthoringTurnStreamStartResponse, AgenticAuthoringTurnStreamStartResponseContract, AiBackendConfigStore, AiBackendStorageOptions, AiChatMessage, AiChatMessageContract, AiClarificationUiContract, AiConfigAdapter, AiContextDTO, AiContextHintsContract, AiContextTemplate, AiContextTemplateMeta, AiCurrentStateDigest, AiCurrentStateDigestContract, AiDomainCatalogContextHintContract, AiDomainCatalogContextHintIntent, AiDomainCatalogContextHintItemType, AiDomainCatalogRelationshipHintContract, AiExamplePair, AiGlobalConfigSnapshot, AiHeaderContext, AiIntegrationConfig, AiJsonArray, AiJsonObject, AiJsonPrimitive, AiJsonValue, AiMemoryInfoContract, AiModel, AiOptionContract, AiOrchestratorRequest, AiOrchestratorRequestContract, AiOrchestratorResponse, AiOrchestratorResponseContract, AiOrchestratorResponseType, AiPatchDiff, AiPatchDiffContract, AiPatchStreamCancelResponse, AiPatchStreamCancelResponseContract, AiPatchStreamConnection, AiPatchStreamConnectionErrorKind, AiPatchStreamEnvelope, AiPatchStreamEnvelopeContract, AiPatchStreamEventType, AiPatchStreamStartResponse, AiPatchStreamStartResponseContract, AiProviderCatalogItem, AiProviderCatalogResponse, AiProviderModelsRequest, AiProviderModelsResponse, AiProviderStatusResponse, AiProviderTestRequest, AiProviderTestResponse, AiResponseCompileResult, AiRuleResponse, AiSchemaContext, AiSchemaContextContract, AiSuggestion, AiSuggestionsRequest, AiSuggestionsResponse, AiTurnStreamEventType, AiUiContextRef, AiUiContextRefContract, AiValidationError, AiValidationResult, AiValidationWarning, AiWizardData, Capability, FieldSchemaLike, MinifiedField, PatchResult, PraxisAssistantActionContract, PraxisAssistantActionKind, PraxisAssistantAttachmentKind, PraxisAssistantAttachmentSummary, PraxisAssistantAuthoringManifestRef, PraxisAssistantCapabilityRef, PraxisAssistantClarificationOption, PraxisAssistantClarificationQuestion, PraxisAssistantClarificationQuestionType, PraxisAssistantComponentType, PraxisAssistantContextItem, PraxisAssistantContextMode, PraxisAssistantContextSessionDescriptor, PraxisAssistantContextSnapshot, PraxisAssistantConversationMessage, PraxisAssistantConversationMessageRole, PraxisAssistantDigest, PraxisAssistantDockTone, PraxisAssistantGovernanceHint, PraxisAssistantIdentity, PraxisAssistantOpenRequest, PraxisAssistantOwnerType, PraxisAssistantPendingClarification, PraxisAssistantRiskLevel, PraxisAssistantSessionDescriptor, PraxisAssistantSessionIdentityRef, PraxisAssistantSessionSnapshot, PraxisAssistantSessionVisibility, PraxisAssistantShellAction, PraxisAssistantShellActionTone, PraxisAssistantShellAttachment, PraxisAssistantShellContextItem, PraxisAssistantShellLabels, PraxisAssistantShellLayout, PraxisAssistantShellMessage, PraxisAssistantShellMessageAction, PraxisAssistantShellMessageRole, PraxisAssistantShellMode, PraxisAssistantShellQuickReply, PraxisAssistantShellState, PraxisAssistantTargetKind, PraxisAssistantTargetRef, PraxisAssistantTurnAction, PraxisAssistantTurnControllerOptions, PraxisAssistantTurnFlow, PraxisAssistantTurnPhase, PraxisAssistantTurnRequest, PraxisAssistantTurnResult, PraxisAssistantTurnViewState, PraxisAssistantViewportLayoutOptions, ProblemResponseContract, PromptContext, RulePropertyDefinition, RulePropertySchema, RulePropertyType, ValidationContext, ValueKind };
|
|
2116
|
+
export { AI_BACKEND_CONFIG_STORE, AI_BACKEND_STORAGE_OPTIONS, AI_CONTRACT_SCHEMA_HASH, AI_CONTRACT_VERSION, AI_INTENT_CONTRACT_SCHEMA_HASH, AI_INTENT_CONTRACT_VERSION, AI_STREAM_EVENT_SCHEMA_VERSION, AI_STREAM_EVENT_TYPES, AiBackendApiService, AiPatchStreamConnectionError, AiResponseValidatorService, AiRuleWizardDialogComponent, BaseAiAdapter, PRAXIS_ASSISTANT_CONTEXT_ATTACHMENT_LIMIT, PRAXIS_ASSISTANT_CONTEXT_ITEM_LIMIT, PRAXIS_ASSISTANT_CONTEXT_SCHEMA_FIELD_LIMIT, PRAXIS_ASSISTANT_CONTEXT_TEXT_LIMIT, PraxisAi, PraxisAiAssistantComponent, PraxisAiAssistantDockComponent, PraxisAiAssistantSessionHostComponent, PraxisAiAssistantShellComponent, PraxisAiService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnController, PraxisAssistantTurnOrchestratorService, SchemaMinifierService, createPraxisAssistantViewportLayout, normalizeAuthoringPrompt, normalizePraxisAssistantAttachmentSummary, normalizePraxisAssistantContextSnapshot, sanitizePraxisAssistantText, shouldRoutePromptToGovernedDecision, toPraxisAssistantConversationMessages };
|
|
2117
|
+
export type { AgenticAuthoringApplyRequestContract, AgenticAuthoringApplyResultContract, AgenticAuthoringAttachmentSummaryContract, AgenticAuthoringCandidateContract, AgenticAuthoringComponentCapabilitiesResultContract, AgenticAuthoringComponentCapabilityCatalogContract, AgenticAuthoringComponentCapabilityContract, AgenticAuthoringComponentCapabilityExampleContract, AgenticAuthoringComponentFieldAliasContract, AgenticAuthoringConversationContextContract, AgenticAuthoringConversationMessageContract, AgenticAuthoringIntentResolutionRequestContract, AgenticAuthoringIntentResolutionResultContract, AgenticAuthoringManifestCompileResult, AgenticAuthoringManifestCompileResultContract, AgenticAuthoringManifestEditPlanRequest, AgenticAuthoringManifestEditPlanRequestContract, AgenticAuthoringManifestValidationResult, AgenticAuthoringManifestValidationResultContract, AgenticAuthoringPendingClarificationContract, AgenticAuthoringPlanRequestContract, AgenticAuthoringPreviewResultContract, AgenticAuthoringQuickReplyContract, AgenticAuthoringResolveTargetRequest, AgenticAuthoringResolveTargetRequestContract, AgenticAuthoringResolvedTarget, AgenticAuthoringResolvedTargetContract, AgenticAuthoringResourceCandidatesRequestContract, AgenticAuthoringResourceCandidatesResultContract, AgenticAuthoringTurnStreamConnection, AgenticAuthoringTurnStreamEnvelope, AgenticAuthoringTurnStreamEnvelopeContract, AgenticAuthoringTurnStreamRequest, AgenticAuthoringTurnStreamRequestContract, AgenticAuthoringTurnStreamStartResponse, AgenticAuthoringTurnStreamStartResponseContract, AiBackendConfigStore, AiBackendStorageOptions, AiChatMessage, AiChatMessageContract, AiClarificationUiContract, AiConfigAdapter, AiContextDTO, AiContextHintsContract, AiContextTemplate, AiContextTemplateMeta, AiCurrentStateDigest, AiCurrentStateDigestContract, AiDomainCatalogContextHintContract, AiDomainCatalogContextHintIntent, AiDomainCatalogContextHintItemType, AiDomainCatalogRelationshipHintContract, AiExamplePair, AiGlobalConfigSnapshot, AiGovernedDecisionRoutingOptions, AiHeaderContext, AiIntegrationConfig, AiJsonArray, AiJsonObject, AiJsonPrimitive, AiJsonValue, AiMemoryInfoContract, AiModel, AiOptionContract, AiOrchestratorRequest, AiOrchestratorRequestContract, AiOrchestratorResponse, AiOrchestratorResponseContract, AiOrchestratorResponseType, AiPatchDiff, AiPatchDiffContract, AiPatchStreamCancelResponse, AiPatchStreamCancelResponseContract, AiPatchStreamConnection, AiPatchStreamConnectionErrorKind, AiPatchStreamEnvelope, AiPatchStreamEnvelopeContract, AiPatchStreamEventType, AiPatchStreamStartResponse, AiPatchStreamStartResponseContract, AiProviderCatalogItem, AiProviderCatalogResponse, AiProviderModelsRequest, AiProviderModelsResponse, AiProviderStatusResponse, AiProviderTestRequest, AiProviderTestResponse, AiResponseCompileResult, AiRuleResponse, AiSchemaContext, AiSchemaContextContract, AiSuggestion, AiSuggestionsRequest, AiSuggestionsResponse, AiTurnStreamEventType, AiUiContextRef, AiUiContextRefContract, AiValidationError, AiValidationResult, AiValidationWarning, AiWizardData, Capability, FieldSchemaLike, MinifiedField, PatchResult, PraxisAssistantActionContract, PraxisAssistantActionKind, PraxisAssistantAttachmentKind, PraxisAssistantAttachmentSummary, PraxisAssistantAuthoringManifestRef, PraxisAssistantCapabilityRef, PraxisAssistantClarificationOption, PraxisAssistantClarificationQuestion, PraxisAssistantClarificationQuestionType, PraxisAssistantComponentType, PraxisAssistantContextItem, PraxisAssistantContextMode, PraxisAssistantContextSessionDescriptor, PraxisAssistantContextSnapshot, PraxisAssistantConversationMessage, PraxisAssistantConversationMessageRole, PraxisAssistantDigest, PraxisAssistantDockTone, PraxisAssistantGovernanceHint, PraxisAssistantIdentity, PraxisAssistantOpenRequest, PraxisAssistantOwnerType, PraxisAssistantPendingClarification, PraxisAssistantRiskLevel, PraxisAssistantSessionDescriptor, PraxisAssistantSessionIdentityRef, PraxisAssistantSessionSnapshot, PraxisAssistantSessionVisibility, PraxisAssistantShellAction, PraxisAssistantShellActionTone, PraxisAssistantShellAttachment, PraxisAssistantShellContextItem, PraxisAssistantShellLabels, PraxisAssistantShellLayout, PraxisAssistantShellMessage, PraxisAssistantShellMessageAction, PraxisAssistantShellMessageRole, PraxisAssistantShellMode, PraxisAssistantShellQuickReply, PraxisAssistantShellState, PraxisAssistantTargetKind, PraxisAssistantTargetRef, PraxisAssistantTurnAction, PraxisAssistantTurnControllerOptions, PraxisAssistantTurnFlow, PraxisAssistantTurnPhase, PraxisAssistantTurnRequest, PraxisAssistantTurnResult, PraxisAssistantTurnViewState, PraxisAssistantViewportLayoutOptions, ProblemResponseContract, PromptContext, RulePropertyDefinition, RulePropertySchema, RulePropertyType, ValidationContext, ValueKind };
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/ai",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.27",
|
|
4
4
|
"description": "AI building blocks and assistant integration for Praxis UI applications.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": "^20.3.0",
|
|
7
7
|
"@angular/core": "^20.3.0",
|
|
8
|
-
"@praxisui/core": "^8.0.0-beta.
|
|
8
|
+
"@praxisui/core": "^8.0.0-beta.27",
|
|
9
9
|
"@angular/cdk": "^20.1.0",
|
|
10
10
|
"@angular/forms": "^20.3.0",
|
|
11
11
|
"@angular/material": "^20.1.0",
|