@m6d/cortex-client 1.0.2 → 1.1.1
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/README.md +1 -1
- package/fesm2022/m6d-cortex-client.mjs +105 -108
- package/fesm2022/m6d-cortex-client.mjs.map +1 -1
- package/package.json +1 -1
- package/styles.css +1 -1
- package/types/m6d-cortex-client.d.ts +1 -1
|
@@ -53,10 +53,10 @@ class CortexClientWebSocketService {
|
|
|
53
53
|
get events() {
|
|
54
54
|
return this.events$;
|
|
55
55
|
}
|
|
56
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
57
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
56
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexClientWebSocketService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
57
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexClientWebSocketService });
|
|
58
58
|
}
|
|
59
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
59
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexClientWebSocketService, decorators: [{
|
|
60
60
|
type: Injectable
|
|
61
61
|
}], ctorParameters: () => [] });
|
|
62
62
|
function deriveWsUrl(baseUrl) {
|
|
@@ -76,12 +76,12 @@ function appendTokenToUrl(wsUrl, headers) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
class CortexChatService {
|
|
79
|
-
threads = signal(undefined, ...(ngDevMode ? [{ debugName: "threads" }] : []));
|
|
80
|
-
selectedThread = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedThread" }] : []));
|
|
81
|
-
chat = signal(undefined, ...(ngDevMode ? [{ debugName: "chat" }] : []));
|
|
82
|
-
isLoadingMessages = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingMessages" }] : []));
|
|
83
|
-
isAgentWorking = signal(false, ...(ngDevMode ? [{ debugName: "isAgentWorking" }] : []));
|
|
84
|
-
hasPendingToolCalls = signal(false, ...(ngDevMode ? [{ debugName: "hasPendingToolCalls" }] : []));
|
|
79
|
+
threads = signal(undefined, ...(ngDevMode ? [{ debugName: "threads" }] : /* istanbul ignore next */ []));
|
|
80
|
+
selectedThread = signal(undefined, ...(ngDevMode ? [{ debugName: "selectedThread" }] : /* istanbul ignore next */ []));
|
|
81
|
+
chat = signal(undefined, ...(ngDevMode ? [{ debugName: "chat" }] : /* istanbul ignore next */ []));
|
|
82
|
+
isLoadingMessages = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingMessages" }] : /* istanbul ignore next */ []));
|
|
83
|
+
isAgentWorking = signal(false, ...(ngDevMode ? [{ debugName: "isAgentWorking" }] : /* istanbul ignore next */ []));
|
|
84
|
+
hasPendingToolCalls = signal(false, ...(ngDevMode ? [{ debugName: "hasPendingToolCalls" }] : /* istanbul ignore next */ []));
|
|
85
85
|
events = new Subject();
|
|
86
86
|
config = inject(CORTEX_CLIENT_CONFIG);
|
|
87
87
|
wsService = inject(CortexClientWebSocketService);
|
|
@@ -267,10 +267,10 @@ class CortexChatService {
|
|
|
267
267
|
const text = await res.text();
|
|
268
268
|
return text ? JSON.parse(text) : undefined;
|
|
269
269
|
}
|
|
270
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
271
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
270
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
271
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexChatService });
|
|
272
272
|
}
|
|
273
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
273
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexChatService, decorators: [{
|
|
274
274
|
type: Injectable
|
|
275
275
|
}], ctorParameters: () => [] });
|
|
276
276
|
/**
|
|
@@ -310,10 +310,10 @@ class MarkedPipe {
|
|
|
310
310
|
.replace(/<(t[hd])([\s>])/g, '<$1 style="padding:0.5rem 1rem"$2');
|
|
311
311
|
return this.sanitizer.bypassSecurityTrustHtml(DOMPurify.sanitize(html));
|
|
312
312
|
}
|
|
313
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
314
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.
|
|
313
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MarkedPipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
|
|
314
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.3", ngImport: i0, type: MarkedPipe, isStandalone: true, name: "marked" });
|
|
315
315
|
}
|
|
316
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
316
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MarkedPipe, decorators: [{
|
|
317
317
|
type: Pipe,
|
|
318
318
|
args: [{
|
|
319
319
|
name: 'marked',
|
|
@@ -322,22 +322,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
322
322
|
}], ctorParameters: () => [{ type: i1.DomSanitizer }] });
|
|
323
323
|
|
|
324
324
|
class MessageTextPartComponent {
|
|
325
|
-
role = input.required(...(ngDevMode ? [{ debugName: "role" }] : []));
|
|
326
|
-
textPart = input.required(...(ngDevMode ? [{ debugName: "textPart" }] : []));
|
|
327
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
328
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
325
|
+
role = input.required(...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
|
|
326
|
+
textPart = input.required(...(ngDevMode ? [{ debugName: "textPart" }] : /* istanbul ignore next */ []));
|
|
327
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageTextPartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
328
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.3", type: MessageTextPartComponent, isStandalone: true, selector: "cortex-message-text-part", inputs: { role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: true, transformFunction: null }, textPart: { classPropertyName: "textPart", publicName: "textPart", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"w-full flex flex-col\"\n [ngClass]=\"{\n 'items-end': role() === 'assistant',\n 'items-start': role() === 'user',\n }\"\n>\n <div\n class=\"max-w-4/5 text-[13px] leading-relaxed p-4 rounded-2xl border border-slate-200 prose\"\n [ngClass]=\"{\n 'bg-slate-100 text-slate-700 ltr:rounded-br-none rtl:rounded-bl-none': role() === 'assistant',\n 'bg-slate-50 text-slate-700 ltr:rounded-bl-none rtl:rounded-br-none': role() === 'user',\n }\"\n [innerHTML]=\"textPart().text | marked\"\n ></div>\n</div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: MarkedPipe, name: "marked" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
329
329
|
}
|
|
330
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
330
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageTextPartComponent, decorators: [{
|
|
331
331
|
type: Component,
|
|
332
332
|
args: [{ selector: 'cortex-message-text-part', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass, MarkedPipe], template: "<div\n class=\"w-full flex flex-col\"\n [ngClass]=\"{\n 'items-end': role() === 'assistant',\n 'items-start': role() === 'user',\n }\"\n>\n <div\n class=\"max-w-4/5 text-[13px] leading-relaxed p-4 rounded-2xl border border-slate-200 prose\"\n [ngClass]=\"{\n 'bg-slate-100 text-slate-700 ltr:rounded-br-none rtl:rounded-bl-none': role() === 'assistant',\n 'bg-slate-50 text-slate-700 ltr:rounded-bl-none rtl:rounded-br-none': role() === 'user',\n }\"\n [innerHTML]=\"textPart().text | marked\"\n ></div>\n</div>\n" }]
|
|
333
333
|
}], propDecorators: { role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: true }] }], textPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "textPart", required: true }] }] } });
|
|
334
334
|
|
|
335
335
|
class MessageReasoningPartComponent {
|
|
336
|
-
reasoningPart = input.required(...(ngDevMode ? [{ debugName: "reasoningPart" }] : []));
|
|
337
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
338
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
336
|
+
reasoningPart = input.required(...(ngDevMode ? [{ debugName: "reasoningPart" }] : /* istanbul ignore next */ []));
|
|
337
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageReasoningPartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
338
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: MessageReasoningPartComponent, isStandalone: true, selector: "cortex-message-reasoning-part", inputs: { reasoningPart: { classPropertyName: "reasoningPart", publicName: "reasoningPart", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@let p = reasoningPart();\n<details class=\"group w-full rounded-lg border border-slate-200 bg-slate-50 overflow-hidden\">\n <summary\n class=\"list-none [&::-webkit-details-marker]:hidden cursor-pointer select-none px-4 py-3 flex items-center gap-3\"\n >\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\n <span\n class=\"inline-flex h-6 w-6 items-center justify-center rounded bg-indigo-100 text-indigo-600\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M10 2C6.686 2 4 4.686 4 8c0 1.655.672 3.154 1.757 4.243.362.363.576.858.576 1.371V14.5a1 1 0 0 0 1 1h5.334a1 1 0 0 0 1-1v-.886c0-.513.214-1.008.576-1.371A5.978 5.978 0 0 0 16 8c0-3.314-2.686-6-6-6Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M7.5 17.5h5M8.5 8a2 2 0 0 1 2-2\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n\n <div class=\"min-w-0\">\n <div class=\"flex items-center gap-2\">\n <div class=\"font-medium text-slate-700 text-sm\">Reasoning</div>\n @if (p.state) {\n <span\n class=\"inline-flex items-center rounded px-1.5 py-0.5 text-[11px] font-medium\"\n [class.bg-amber-100.text-amber-700]=\"p.state === 'streaming'\"\n [class.bg-emerald-100.text-emerald-700]=\"p.state === 'done'\"\n >\n {{ p.state === 'streaming' ? 'Streaming' : 'Done' }}\n </span>\n }\n </div>\n </div>\n </div>\n\n <span\n class=\"ml-auto inline-flex h-6 w-6 items-center justify-center rounded text-slate-400 transition group-open:rotate-180\"\n aria-hidden=\"true\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"m5.75 8.25 4.25 4.25 4.25-4.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n </summary>\n\n <div class=\"px-4 pb-4\">\n <div class=\"mt-1 rounded bg-white border border-slate-200 p-3\">\n <pre\n class=\"m-0 whitespace-pre-wrap wrap-break-word font-mono text-xs leading-relaxed text-slate-700\"\n >{{ p.text.trim() ? p.text : 'No reasoning provided.' }}</pre\n >\n </div>\n </div>\n</details>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
339
339
|
}
|
|
340
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
340
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageReasoningPartComponent, decorators: [{
|
|
341
341
|
type: Component,
|
|
342
342
|
args: [{ selector: 'cortex-message-reasoning-part', changeDetection: ChangeDetectionStrategy.OnPush, template: "@let p = reasoningPart();\n<details class=\"group w-full rounded-lg border border-slate-200 bg-slate-50 overflow-hidden\">\n <summary\n class=\"list-none [&::-webkit-details-marker]:hidden cursor-pointer select-none px-4 py-3 flex items-center gap-3\"\n >\n <div class=\"flex items-center gap-2 min-w-0 flex-1\">\n <span\n class=\"inline-flex h-6 w-6 items-center justify-center rounded bg-indigo-100 text-indigo-600\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M10 2C6.686 2 4 4.686 4 8c0 1.655.672 3.154 1.757 4.243.362.363.576.858.576 1.371V14.5a1 1 0 0 0 1 1h5.334a1 1 0 0 0 1-1v-.886c0-.513.214-1.008.576-1.371A5.978 5.978 0 0 0 16 8c0-3.314-2.686-6-6-6Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M7.5 17.5h5M8.5 8a2 2 0 0 1 2-2\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n\n <div class=\"min-w-0\">\n <div class=\"flex items-center gap-2\">\n <div class=\"font-medium text-slate-700 text-sm\">Reasoning</div>\n @if (p.state) {\n <span\n class=\"inline-flex items-center rounded px-1.5 py-0.5 text-[11px] font-medium\"\n [class.bg-amber-100.text-amber-700]=\"p.state === 'streaming'\"\n [class.bg-emerald-100.text-emerald-700]=\"p.state === 'done'\"\n >\n {{ p.state === 'streaming' ? 'Streaming' : 'Done' }}\n </span>\n }\n </div>\n </div>\n </div>\n\n <span\n class=\"ml-auto inline-flex h-6 w-6 items-center justify-center rounded text-slate-400 transition group-open:rotate-180\"\n aria-hidden=\"true\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"m5.75 8.25 4.25 4.25 4.25-4.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n </summary>\n\n <div class=\"px-4 pb-4\">\n <div class=\"mt-1 rounded bg-white border border-slate-200 p-3\">\n <pre\n class=\"m-0 whitespace-pre-wrap wrap-break-word font-mono text-xs leading-relaxed text-slate-700\"\n >{{ p.text.trim() ? p.text : 'No reasoning provided.' }}</pre\n >\n </div>\n </div>\n</details>\n" }]
|
|
343
343
|
}], propDecorators: { reasoningPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "reasoningPart", required: true }] }] } });
|
|
@@ -361,17 +361,17 @@ class HighlightPipe {
|
|
|
361
361
|
escapeHtml(str) {
|
|
362
362
|
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
363
363
|
}
|
|
364
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
365
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.
|
|
364
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: HighlightPipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
|
|
365
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.3", ngImport: i0, type: HighlightPipe, isStandalone: true, name: "highlight" });
|
|
366
366
|
}
|
|
367
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
367
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: HighlightPipe, decorators: [{
|
|
368
368
|
type: Pipe,
|
|
369
369
|
args: [{ name: 'highlight', standalone: true }]
|
|
370
370
|
}], ctorParameters: () => [{ type: i1.DomSanitizer }] });
|
|
371
371
|
|
|
372
372
|
class JsonTreeComponent {
|
|
373
|
-
data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
374
|
-
expandDepth = input(1, ...(ngDevMode ? [{ debugName: "expandDepth" }] : []));
|
|
373
|
+
data = input.required(...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
374
|
+
expandDepth = input(1, ...(ngDevMode ? [{ debugName: "expandDepth" }] : /* istanbul ignore next */ []));
|
|
375
375
|
collapsedPaths = new Set();
|
|
376
376
|
userToggled = new Set();
|
|
377
377
|
isCollapsed(path, depth) {
|
|
@@ -462,10 +462,10 @@ class JsonTreeComponent {
|
|
|
462
462
|
}
|
|
463
463
|
return value;
|
|
464
464
|
}
|
|
465
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
466
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
465
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: JsonTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
466
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: JsonTreeComponent, isStandalone: true, selector: "cortex-json-tree", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, expandDepth: { classPropertyName: "expandDepth", publicName: "expandDepth", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block font-mono text-[12px] leading-5 select-text" }, ngImport: i0, template: "<!-- Entry point: parse and render the root value -->\n<ng-container\n *ngTemplateOutlet=\"valueTemplate; context: { $implicit: parsed(data()), path: '$', depth: 0 }\"\n/>\n\n<!-- Recursive value renderer -->\n<ng-template #valueTemplate let-value let-path=\"path\" let-depth=\"depth\">\n @if (isObject(value)) {\n @if (objectLength(value) === 0) {\n <span class=\"jt-bracket\">{{ '{' }}{{ '}' }}</span>\n } @else {\n <span class=\"jt-toggle\" (click)=\"toggle(path, depth); $event.stopPropagation()\" role=\"button\">\n <span class=\"jt-arrow\" [class.jt-arrow--collapsed]=\"isCollapsed(path, depth)\">▾</span>\n <span class=\"jt-bracket\">{{ '{' }}</span>\n </span>\n @if (isCollapsed(path, depth)) {\n <span\n class=\"jt-collapsed-hint\"\n (click)=\"toggle(path, depth); $event.stopPropagation()\"\n role=\"button\"\n >{{ objectLength(value) }}\n {{ objectLength(value) === 1 ? 'property' : 'properties' }}</span\n ><span class=\"jt-bracket\">{{ '}' }}</span>\n } @else {\n <div class=\"jt-indent\">\n @for (entry of objectEntries(value); track entry[0]; let last = $last) {\n <div class=\"jt-line\">\n <span class=\"jt-key\">\"{{ entry[0] }}\"</span><span class=\"jt-colon\">: </span>\n @if (isContainer(entry[1])) {\n <ng-container\n *ngTemplateOutlet=\"\n valueTemplate;\n context: { $implicit: entry[1], path: path + '.' + entry[0], depth: depth + 1 }\n \"\n />\n } @else {\n <span [class]=\"primitiveClass(entry[1])\">{{ formatPrimitive(entry[1]) }}</span>\n }\n @if (!last) {\n <span class=\"jt-comma\">,</span>\n }\n </div>\n }\n </div>\n <span class=\"jt-bracket\">{{ '}' }}</span>\n }\n }\n } @else if (isArray(value)) {\n @if (arrayLength(value) === 0) {\n <span class=\"jt-bracket\">[]</span>\n } @else {\n <span class=\"jt-toggle\" (click)=\"toggle(path, depth); $event.stopPropagation()\" role=\"button\">\n <span class=\"jt-arrow\" [class.jt-arrow--collapsed]=\"isCollapsed(path, depth)\">▾</span>\n <span class=\"jt-bracket\">[</span>\n </span>\n @if (isCollapsed(path, depth)) {\n <span\n class=\"jt-collapsed-hint\"\n (click)=\"toggle(path, depth); $event.stopPropagation()\"\n role=\"button\"\n >{{ arrayLength(value) }} {{ arrayLength(value) === 1 ? 'item' : 'items' }}</span\n ><span class=\"jt-bracket\">]</span>\n } @else {\n <div class=\"jt-indent\">\n @for (item of arrayItems(value); track $index; let last = $last) {\n <div class=\"jt-line\">\n @if (isContainer(item)) {\n <ng-container\n *ngTemplateOutlet=\"\n valueTemplate;\n context: { $implicit: item, path: path + '[' + $index + ']', depth: depth + 1 }\n \"\n />\n } @else {\n <span [class]=\"primitiveClass(item)\">{{ formatPrimitive(item) }}</span>\n }\n @if (!last) {\n <span class=\"jt-comma\">,</span>\n }\n </div>\n }\n </div>\n <span class=\"jt-bracket\">]</span>\n }\n }\n } @else {\n <span [class]=\"primitiveClass(value)\">{{ formatPrimitive(value) }}</span>\n }\n</ng-template>\n", styles: [":host{white-space:pre-wrap;word-break:break-word}.jt-indent{padding-inline-start:1.25em;border-inline-start:1px solid #e2e8f0;margin-inline-start:.3em}.jt-line{position:relative}.jt-toggle{cursor:pointer;-webkit-user-select:none;user-select:none}.jt-toggle:hover .jt-arrow{color:#475569}.jt-arrow{display:inline-block;width:1em;text-align:center;color:#94a3b8;font-size:.7em;transition:transform .15s ease;vertical-align:middle}.jt-arrow--collapsed{transform:rotate(-90deg)}.jt-bracket{color:#64748b}.jt-key{color:#6366f1}.jt-colon{color:#64748b}.jt-comma{color:#94a3b8}.jt-string{color:#059669}.jt-number{color:#2563eb}.jt-boolean{color:#d97706}.jt-null{color:#94a3b8;font-style:italic}.jt-collapsed-hint{display:inline-block;padding:0 .4em;margin:0 .15em;font-size:10px;line-height:1.5;color:#94a3b8;background:#f8fafc;border:1px solid #e2e8f0;border-radius:3px;font-style:italic;cursor:pointer;-webkit-user-select:none;user-select:none;vertical-align:middle}.jt-collapsed-hint:hover{color:#64748b;border-color:#cbd5e1;background:#f1f5f9}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
467
467
|
}
|
|
468
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
468
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: JsonTreeComponent, decorators: [{
|
|
469
469
|
type: Component,
|
|
470
470
|
args: [{ selector: 'cortex-json-tree', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet], host: { class: 'block font-mono text-[12px] leading-5 select-text' }, template: "<!-- Entry point: parse and render the root value -->\n<ng-container\n *ngTemplateOutlet=\"valueTemplate; context: { $implicit: parsed(data()), path: '$', depth: 0 }\"\n/>\n\n<!-- Recursive value renderer -->\n<ng-template #valueTemplate let-value let-path=\"path\" let-depth=\"depth\">\n @if (isObject(value)) {\n @if (objectLength(value) === 0) {\n <span class=\"jt-bracket\">{{ '{' }}{{ '}' }}</span>\n } @else {\n <span class=\"jt-toggle\" (click)=\"toggle(path, depth); $event.stopPropagation()\" role=\"button\">\n <span class=\"jt-arrow\" [class.jt-arrow--collapsed]=\"isCollapsed(path, depth)\">▾</span>\n <span class=\"jt-bracket\">{{ '{' }}</span>\n </span>\n @if (isCollapsed(path, depth)) {\n <span\n class=\"jt-collapsed-hint\"\n (click)=\"toggle(path, depth); $event.stopPropagation()\"\n role=\"button\"\n >{{ objectLength(value) }}\n {{ objectLength(value) === 1 ? 'property' : 'properties' }}</span\n ><span class=\"jt-bracket\">{{ '}' }}</span>\n } @else {\n <div class=\"jt-indent\">\n @for (entry of objectEntries(value); track entry[0]; let last = $last) {\n <div class=\"jt-line\">\n <span class=\"jt-key\">\"{{ entry[0] }}\"</span><span class=\"jt-colon\">: </span>\n @if (isContainer(entry[1])) {\n <ng-container\n *ngTemplateOutlet=\"\n valueTemplate;\n context: { $implicit: entry[1], path: path + '.' + entry[0], depth: depth + 1 }\n \"\n />\n } @else {\n <span [class]=\"primitiveClass(entry[1])\">{{ formatPrimitive(entry[1]) }}</span>\n }\n @if (!last) {\n <span class=\"jt-comma\">,</span>\n }\n </div>\n }\n </div>\n <span class=\"jt-bracket\">{{ '}' }}</span>\n }\n }\n } @else if (isArray(value)) {\n @if (arrayLength(value) === 0) {\n <span class=\"jt-bracket\">[]</span>\n } @else {\n <span class=\"jt-toggle\" (click)=\"toggle(path, depth); $event.stopPropagation()\" role=\"button\">\n <span class=\"jt-arrow\" [class.jt-arrow--collapsed]=\"isCollapsed(path, depth)\">▾</span>\n <span class=\"jt-bracket\">[</span>\n </span>\n @if (isCollapsed(path, depth)) {\n <span\n class=\"jt-collapsed-hint\"\n (click)=\"toggle(path, depth); $event.stopPropagation()\"\n role=\"button\"\n >{{ arrayLength(value) }} {{ arrayLength(value) === 1 ? 'item' : 'items' }}</span\n ><span class=\"jt-bracket\">]</span>\n } @else {\n <div class=\"jt-indent\">\n @for (item of arrayItems(value); track $index; let last = $last) {\n <div class=\"jt-line\">\n @if (isContainer(item)) {\n <ng-container\n *ngTemplateOutlet=\"\n valueTemplate;\n context: { $implicit: item, path: path + '[' + $index + ']', depth: depth + 1 }\n \"\n />\n } @else {\n <span [class]=\"primitiveClass(item)\">{{ formatPrimitive(item) }}</span>\n }\n @if (!last) {\n <span class=\"jt-comma\">,</span>\n }\n </div>\n }\n </div>\n <span class=\"jt-bracket\">]</span>\n }\n }\n } @else {\n <span [class]=\"primitiveClass(value)\">{{ formatPrimitive(value) }}</span>\n }\n</ng-template>\n", styles: [":host{white-space:pre-wrap;word-break:break-word}.jt-indent{padding-inline-start:1.25em;border-inline-start:1px solid #e2e8f0;margin-inline-start:.3em}.jt-line{position:relative}.jt-toggle{cursor:pointer;-webkit-user-select:none;user-select:none}.jt-toggle:hover .jt-arrow{color:#475569}.jt-arrow{display:inline-block;width:1em;text-align:center;color:#94a3b8;font-size:.7em;transition:transform .15s ease;vertical-align:middle}.jt-arrow--collapsed{transform:rotate(-90deg)}.jt-bracket{color:#64748b}.jt-key{color:#6366f1}.jt-colon{color:#64748b}.jt-comma{color:#94a3b8}.jt-string{color:#059669}.jt-number{color:#2563eb}.jt-boolean{color:#d97706}.jt-null{color:#94a3b8;font-style:italic}.jt-collapsed-hint{display:inline-block;padding:0 .4em;margin:0 .15em;font-size:10px;line-height:1.5;color:#94a3b8;background:#f8fafc;border:1px solid #e2e8f0;border-radius:3px;font-style:italic;cursor:pointer;-webkit-user-select:none;user-select:none;vertical-align:middle}.jt-collapsed-hint:hover{color:#64748b;border-color:#cbd5e1;background:#f1f5f9}\n"] }]
|
|
471
471
|
}], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], expandDepth: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandDepth", required: false }] }] } });
|
|
@@ -475,7 +475,7 @@ class MessageToolCallPartComponent {
|
|
|
475
475
|
code: 'javascript',
|
|
476
476
|
query: 'cypher',
|
|
477
477
|
};
|
|
478
|
-
toolCallPart = input.required(...(ngDevMode ? [{ debugName: "toolCallPart" }] : []));
|
|
478
|
+
toolCallPart = input.required(...(ngDevMode ? [{ debugName: "toolCallPart" }] : /* istanbul ignore next */ []));
|
|
479
479
|
codeSnippets = computed(() => {
|
|
480
480
|
const inp = this.toolCallPart().input;
|
|
481
481
|
if (!inp || typeof inp !== 'object')
|
|
@@ -492,7 +492,7 @@ class MessageToolCallPartComponent {
|
|
|
492
492
|
}
|
|
493
493
|
}
|
|
494
494
|
return snippets;
|
|
495
|
-
}, ...(ngDevMode ? [{ debugName: "codeSnippets" }] : []));
|
|
495
|
+
}, ...(ngDevMode ? [{ debugName: "codeSnippets" }] : /* istanbul ignore next */ []));
|
|
496
496
|
remainingInput = computed(() => {
|
|
497
497
|
const inp = this.toolCallPart().input;
|
|
498
498
|
if (!inp || typeof inp !== 'object')
|
|
@@ -508,33 +508,33 @@ class MessageToolCallPartComponent {
|
|
|
508
508
|
}
|
|
509
509
|
}
|
|
510
510
|
return hasKeys ? remaining : null;
|
|
511
|
-
}, ...(ngDevMode ? [{ debugName: "remainingInput" }] : []));
|
|
511
|
+
}, ...(ngDevMode ? [{ debugName: "remainingInput" }] : /* istanbul ignore next */ []));
|
|
512
512
|
toolName() {
|
|
513
513
|
const type = this.toolCallPart().type;
|
|
514
514
|
if (!type)
|
|
515
515
|
return '';
|
|
516
516
|
return type.startsWith('tool-') ? type.slice('tool-'.length) : type;
|
|
517
517
|
}
|
|
518
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
519
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: MessageToolCallPartComponent, isStandalone: true, selector: "cortex-message-tool-call-part", inputs: { toolCallPart: { classPropertyName: "toolCallPart", publicName: "toolCallPart", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<details class=\"group w-full rounded-lg border border-slate-200 bg-slate-50 overflow-hidden\">\n <summary\n class=\"list-none [&::-webkit-details-marker]:hidden cursor-pointer select-none px-4 py-3 group-open:border-b group-open:border-slate-200\"\n >\n <div class=\"flex items-start gap-3\">\n <div\n class=\"shrink-0 mt-0.5 size-7 rounded bg-slate-800 text-white flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M6.5 6.5 3.75 10l2.75 3.5M13.5 6.5 16.25 10l-2.75 3.5M11.25 5.75 8.75 14.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex items-center gap-2\">\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex items-center gap-2 min-w-0\">\n <div\n class=\"font-medium text-slate-800 text-sm truncate\"\n [attr.title]=\"toolCallPart().title || null\"\n >\n {{ toolCallPart().title ?? 'Tool call' }}\n </div>\n @if (toolName()) {\n <span\n class=\"hidden sm:inline-flex items-center rounded bg-slate-200 px-1.5 py-0.5 text-[11px] font-medium text-slate-600 font-mono\"\n [attr.title]=\"toolCallPart().type || null\"\n >{{ toolName() }}</span\n >\n }\n </div>\n <div class=\"mt-0.5 text-[11px] text-slate-500 break-all\">\n <span class=\"font-medium text-slate-600\">ID</span>\n <span class=\"font-mono\"> {{ toolCallPart().toolCallId }}</span>\n @if (toolCallPart().providerExecuted) {\n <span class=\"ml-2 inline-flex items-center gap-1 text-emerald-700\">\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span>\n provider\n </span>\n }\n </div>\n </div>\n\n <div class=\"flex items-center gap-2\">\n <span\n class=\"inline-flex items-center gap-1.5 rounded px-2 py-1 text-[11px] font-medium border\"\n [ngClass]=\"{\n 'bg-emerald-50 text-emerald-700 border-emerald-200':\n toolCallPart().state === 'output-available',\n 'bg-red-50 text-red-700 border-red-200': toolCallPart().state === 'output-error',\n 'bg-slate-100 text-slate-600 border-slate-200':\n toolCallPart().state === 'output-denied',\n 'bg-violet-50 text-violet-700 border-violet-200':\n toolCallPart().state === 'approval-requested' ||\n toolCallPart().state === 'approval-responded',\n 'bg-amber-50 text-amber-700 border-amber-200':\n toolCallPart().state === 'input-streaming' ||\n toolCallPart().state === 'input-available',\n }\"\n >\n @switch (toolCallPart().state) {\n @case ('input-streaming') {\n <span class=\"size-1.5 rounded-full bg-amber-500 animate-pulse\"></span>\n Calling\n }\n @case ('input-available') {\n <span class=\"size-1.5 rounded-full bg-amber-500\"></span> Input ready\n }\n @case ('approval-requested') {\n <span class=\"size-1.5 rounded-full bg-violet-500 animate-pulse\"></span>\n Needs approval\n }\n @case ('approval-responded') {\n @if (toolCallPart().approval?.approved) {\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span> Approved\n } @else {\n <span class=\"size-1.5 rounded-full bg-slate-500\"></span> Responded\n }\n }\n @case ('output-available') {\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span>\n {{ 'translate_completed' | translate }}\n }\n @case ('output-error') {\n <span class=\"size-1.5 rounded-full bg-red-500\"></span> Error\n }\n @case ('output-denied') {\n <span class=\"size-1.5 rounded-full bg-slate-500\"></span> Denied\n }\n }\n </span>\n\n <span\n class=\"inline-flex size-6 items-center justify-center rounded text-slate-400 transition group-open:rotate-180\"\n aria-hidden=\"true\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"m5.75 8.25 4.25 4.25 4.25-4.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n </div>\n </div>\n </div>\n </div>\n </summary>\n\n <div class=\"bg-white px-4 pb-4 pt-3\">\n <div class=\"grid gap-3\">\n @for (snippet of codeSnippets(); track snippet.key) {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">\n {{ snippet.key }}\n </div>\n <div class=\"text-[11px] text-slate-400 font-mono\">\n {{ snippet.lang }}\n </div>\n </div>\n <pre\n dir=\"ltr\"\n class=\"m-0 max-h-80 overflow-auto p-3 text-[12px] leading-5 font-mono whitespace-pre wrap-break-word\"\n ><code class=\"hljs\" [innerHTML]=\"snippet.value | highlight : snippet.lang\"></code></pre>\n </div>\n }\n\n @if (remainingInput(); as remaining) {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">Input</div>\n <div class=\"text-[11px] text-slate-400 font-mono\">json</div>\n </div>\n <div dir=\"ltr\" class=\"max-h-64 overflow-auto p-3\">\n <cortex-json-tree [data]=\"remaining\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-available') {\n <div class=\"rounded-lg border border-emerald-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-emerald-200 bg-emerald-50\"\n >\n <div class=\"text-[11px] font-medium text-emerald-700\">Output</div>\n <div class=\"text-[11px] text-emerald-600 font-mono\">json</div>\n </div>\n <div dir=\"ltr\" class=\"max-h-64 overflow-auto p-3\">\n <cortex-json-tree [data]=\"toolCallPart().output\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-error') {\n <div class=\"rounded-lg border border-red-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-red-200 bg-red-50\"\n >\n <div class=\"text-[11px] font-medium text-red-700\">Error</div>\n <div class=\"text-[11px] text-red-600 font-mono\">text</div>\n </div>\n <pre\n dir=\"ltr\"\n class=\"m-0 max-h-64 overflow-auto p-3 text-[12px] leading-5 font-mono text-red-800 whitespace-pre-wrap wrap-break-word\"\n >{{ toolCallPart().errorText }}</pre\n >\n </div>\n }\n\n @if (toolCallPart().state === 'output-denied') {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">Denied</div>\n <div class=\"text-[11px] text-slate-500 font-mono\">approval</div>\n </div>\n <div class=\"p-3 text-[12px] text-slate-700\">\n Tool execution was denied.\n @if (toolCallPart().approval?.reason) {\n <div class=\"mt-2 rounded bg-slate-50 border border-slate-200 p-2\">\n <div class=\"text-[11px] font-medium text-slate-600\">Reason</div>\n <div class=\"mt-1 font-mono text-[12px] text-slate-700 wrap-break-word\">\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-requested') {\n <div class=\"rounded-lg border border-violet-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-violet-200 bg-violet-50\"\n >\n <div class=\"text-[11px] font-medium text-violet-700\">Approval requested</div>\n <div class=\"text-[11px] text-violet-600 font-mono\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"p-3 text-[12px] text-violet-800\">\n Waiting for approval to execute this tool.\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-responded') {\n <div class=\"rounded-lg border border-violet-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-violet-200 bg-violet-50\"\n >\n <div class=\"text-[11px] font-medium text-violet-700\">Approval response</div>\n <div class=\"text-[11px] text-violet-600 font-mono\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"p-3 text-[12px] text-violet-800\">\n @if (toolCallPart().approval?.approved) {\n Approved.\n } @else {\n Response received.\n }\n @if (toolCallPart().approval?.reason) {\n <div class=\"mt-2 rounded bg-violet-50 border border-violet-200 p-2\">\n <div class=\"text-[11px] font-medium text-violet-700\">Reason</div>\n <div class=\"mt-1 font-mono text-[12px] text-violet-800 wrap-break-word\">\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n</details>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: JsonTreeComponent, selector: "cortex-json-tree", inputs: ["data", "expandDepth"] }, { kind: "pipe", type: HighlightPipe, name: "highlight" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
518
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageToolCallPartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
519
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: MessageToolCallPartComponent, isStandalone: true, selector: "cortex-message-tool-call-part", inputs: { toolCallPart: { classPropertyName: "toolCallPart", publicName: "toolCallPart", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<details class=\"group w-full rounded-lg border border-slate-200 bg-slate-50 overflow-hidden\">\n <summary\n class=\"list-none [&::-webkit-details-marker]:hidden cursor-pointer select-none px-4 py-3 group-open:border-b group-open:border-slate-200\"\n >\n <div class=\"flex items-start gap-3\">\n <div\n class=\"shrink-0 mt-0.5 size-7 rounded bg-slate-800 text-white flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M6.5 6.5 3.75 10l2.75 3.5M13.5 6.5 16.25 10l-2.75 3.5M11.25 5.75 8.75 14.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex items-center gap-2\">\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex items-center gap-2 min-w-0\">\n <div\n class=\"font-medium text-slate-800 text-sm truncate\"\n [attr.title]=\"toolCallPart().title || null\"\n >\n {{ toolCallPart().title ?? 'Tool call' }}\n </div>\n @if (toolName()) {\n <span\n class=\"hidden sm:inline-flex items-center rounded bg-slate-200 px-1.5 py-0.5 text-[11px] font-medium text-slate-600 font-mono\"\n [attr.title]=\"toolCallPart().type || null\"\n >{{ toolName() }}</span\n >\n }\n </div>\n <div class=\"mt-0.5 text-[11px] text-slate-500 break-all\">\n <span class=\"font-medium text-slate-600\">ID</span>\n <span class=\"font-mono\"> {{ toolCallPart().toolCallId }}</span>\n @if (toolCallPart().providerExecuted) {\n <span class=\"ml-2 inline-flex items-center gap-1 text-emerald-700\">\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span>\n provider\n </span>\n }\n </div>\n </div>\n\n <div class=\"flex items-center gap-2\">\n <span\n class=\"inline-flex items-center gap-1.5 rounded px-2 py-1 text-[11px] font-medium border\"\n [ngClass]=\"{\n 'bg-emerald-50 text-emerald-700 border-emerald-200':\n toolCallPart().state === 'output-available',\n 'bg-red-50 text-red-700 border-red-200': toolCallPart().state === 'output-error',\n 'bg-slate-100 text-slate-600 border-slate-200':\n toolCallPart().state === 'output-denied',\n 'bg-violet-50 text-violet-700 border-violet-200':\n toolCallPart().state === 'approval-requested' ||\n toolCallPart().state === 'approval-responded',\n 'bg-amber-50 text-amber-700 border-amber-200':\n toolCallPart().state === 'input-streaming' ||\n toolCallPart().state === 'input-available',\n }\"\n >\n @switch (toolCallPart().state) {\n @case ('input-streaming') {\n <span class=\"size-1.5 rounded-full bg-amber-500 animate-pulse\"></span>\n Calling\n }\n @case ('input-available') {\n <span class=\"size-1.5 rounded-full bg-amber-500\"></span> Input ready\n }\n @case ('approval-requested') {\n <span class=\"size-1.5 rounded-full bg-violet-500 animate-pulse\"></span>\n Needs approval\n }\n @case ('approval-responded') {\n @if (toolCallPart().approval?.approved) {\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span> Approved\n } @else {\n <span class=\"size-1.5 rounded-full bg-slate-500\"></span> Responded\n }\n }\n @case ('output-available') {\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span>\n {{ 'translate_completed' | translate }}\n }\n @case ('output-error') {\n <span class=\"size-1.5 rounded-full bg-red-500\"></span> Error\n }\n @case ('output-denied') {\n <span class=\"size-1.5 rounded-full bg-slate-500\"></span> Denied\n }\n }\n </span>\n\n <span\n class=\"inline-flex size-6 items-center justify-center rounded text-slate-400 transition group-open:rotate-180\"\n aria-hidden=\"true\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"m5.75 8.25 4.25 4.25 4.25-4.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n </div>\n </div>\n </div>\n </div>\n </summary>\n\n <div class=\"bg-white px-4 pb-4 pt-3\">\n <div class=\"grid gap-3\">\n @for (snippet of codeSnippets(); track snippet.key) {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">\n {{ snippet.key }}\n </div>\n <div class=\"text-[11px] text-slate-400 font-mono\">\n {{ snippet.lang }}\n </div>\n </div>\n <pre\n dir=\"ltr\"\n class=\"m-0 max-h-80 overflow-auto p-3 text-[12px] leading-5 font-mono whitespace-pre wrap-break-word\"\n ><code class=\"hljs\" [innerHTML]=\"snippet.value | highlight : snippet.lang\"></code></pre>\n </div>\n }\n\n @if (remainingInput(); as remaining) {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">Input</div>\n <div class=\"text-[11px] text-slate-400 font-mono\">json</div>\n </div>\n <div dir=\"ltr\" class=\"max-h-64 overflow-auto p-3\">\n <cortex-json-tree [data]=\"remaining\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-available') {\n <div class=\"rounded-lg border border-emerald-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-emerald-200 bg-emerald-50\"\n >\n <div class=\"text-[11px] font-medium text-emerald-700\">Output</div>\n <div class=\"text-[11px] text-emerald-600 font-mono\">json</div>\n </div>\n <div dir=\"ltr\" class=\"max-h-64 overflow-auto p-3\">\n <cortex-json-tree [data]=\"toolCallPart().output\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-error') {\n <div class=\"rounded-lg border border-red-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-red-200 bg-red-50\"\n >\n <div class=\"text-[11px] font-medium text-red-700\">Error</div>\n <div class=\"text-[11px] text-red-600 font-mono\">text</div>\n </div>\n <pre\n dir=\"ltr\"\n class=\"m-0 max-h-64 overflow-auto p-3 text-[12px] leading-5 font-mono text-red-800 whitespace-pre-wrap wrap-break-word\"\n >{{ toolCallPart().errorText }}</pre\n >\n </div>\n }\n\n @if (toolCallPart().state === 'output-denied') {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">Denied</div>\n <div class=\"text-[11px] text-slate-500 font-mono\">approval</div>\n </div>\n <div class=\"p-3 text-[12px] text-slate-700\">\n Tool execution was denied.\n @if (toolCallPart().approval?.reason) {\n <div class=\"mt-2 rounded bg-slate-50 border border-slate-200 p-2\">\n <div class=\"text-[11px] font-medium text-slate-600\">Reason</div>\n <div class=\"mt-1 font-mono text-[12px] text-slate-700 wrap-break-word\">\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-requested') {\n <div class=\"rounded-lg border border-violet-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-violet-200 bg-violet-50\"\n >\n <div class=\"text-[11px] font-medium text-violet-700\">Approval requested</div>\n <div class=\"text-[11px] text-violet-600 font-mono\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"p-3 text-[12px] text-violet-800\">\n Waiting for approval to execute this tool.\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-responded') {\n <div class=\"rounded-lg border border-violet-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-violet-200 bg-violet-50\"\n >\n <div class=\"text-[11px] font-medium text-violet-700\">Approval response</div>\n <div class=\"text-[11px] text-violet-600 font-mono\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"p-3 text-[12px] text-violet-800\">\n @if (toolCallPart().approval?.approved) {\n Approved.\n } @else {\n Response received.\n }\n @if (toolCallPart().approval?.reason) {\n <div class=\"mt-2 rounded bg-violet-50 border border-violet-200 p-2\">\n <div class=\"text-[11px] font-medium text-violet-700\">Reason</div>\n <div class=\"mt-1 font-mono text-[12px] text-violet-800 wrap-break-word\">\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n</details>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: JsonTreeComponent, selector: "cortex-json-tree", inputs: ["data", "expandDepth"] }, { kind: "pipe", type: HighlightPipe, name: "highlight" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
520
520
|
}
|
|
521
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
521
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageToolCallPartComponent, decorators: [{
|
|
522
522
|
type: Component,
|
|
523
523
|
args: [{ selector: 'cortex-message-tool-call-part', changeDetection: ChangeDetectionStrategy.OnPush, imports: [HighlightPipe, NgClass, TranslatePipe, JsonTreeComponent], template: "<details class=\"group w-full rounded-lg border border-slate-200 bg-slate-50 overflow-hidden\">\n <summary\n class=\"list-none [&::-webkit-details-marker]:hidden cursor-pointer select-none px-4 py-3 group-open:border-b group-open:border-slate-200\"\n >\n <div class=\"flex items-start gap-3\">\n <div\n class=\"shrink-0 mt-0.5 size-7 rounded bg-slate-800 text-white flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M6.5 6.5 3.75 10l2.75 3.5M13.5 6.5 16.25 10l-2.75 3.5M11.25 5.75 8.75 14.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex items-center gap-2\">\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex items-center gap-2 min-w-0\">\n <div\n class=\"font-medium text-slate-800 text-sm truncate\"\n [attr.title]=\"toolCallPart().title || null\"\n >\n {{ toolCallPart().title ?? 'Tool call' }}\n </div>\n @if (toolName()) {\n <span\n class=\"hidden sm:inline-flex items-center rounded bg-slate-200 px-1.5 py-0.5 text-[11px] font-medium text-slate-600 font-mono\"\n [attr.title]=\"toolCallPart().type || null\"\n >{{ toolName() }}</span\n >\n }\n </div>\n <div class=\"mt-0.5 text-[11px] text-slate-500 break-all\">\n <span class=\"font-medium text-slate-600\">ID</span>\n <span class=\"font-mono\"> {{ toolCallPart().toolCallId }}</span>\n @if (toolCallPart().providerExecuted) {\n <span class=\"ml-2 inline-flex items-center gap-1 text-emerald-700\">\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span>\n provider\n </span>\n }\n </div>\n </div>\n\n <div class=\"flex items-center gap-2\">\n <span\n class=\"inline-flex items-center gap-1.5 rounded px-2 py-1 text-[11px] font-medium border\"\n [ngClass]=\"{\n 'bg-emerald-50 text-emerald-700 border-emerald-200':\n toolCallPart().state === 'output-available',\n 'bg-red-50 text-red-700 border-red-200': toolCallPart().state === 'output-error',\n 'bg-slate-100 text-slate-600 border-slate-200':\n toolCallPart().state === 'output-denied',\n 'bg-violet-50 text-violet-700 border-violet-200':\n toolCallPart().state === 'approval-requested' ||\n toolCallPart().state === 'approval-responded',\n 'bg-amber-50 text-amber-700 border-amber-200':\n toolCallPart().state === 'input-streaming' ||\n toolCallPart().state === 'input-available',\n }\"\n >\n @switch (toolCallPart().state) {\n @case ('input-streaming') {\n <span class=\"size-1.5 rounded-full bg-amber-500 animate-pulse\"></span>\n Calling\n }\n @case ('input-available') {\n <span class=\"size-1.5 rounded-full bg-amber-500\"></span> Input ready\n }\n @case ('approval-requested') {\n <span class=\"size-1.5 rounded-full bg-violet-500 animate-pulse\"></span>\n Needs approval\n }\n @case ('approval-responded') {\n @if (toolCallPart().approval?.approved) {\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span> Approved\n } @else {\n <span class=\"size-1.5 rounded-full bg-slate-500\"></span> Responded\n }\n }\n @case ('output-available') {\n <span class=\"size-1.5 rounded-full bg-emerald-500\"></span>\n {{ 'translate_completed' | translate }}\n }\n @case ('output-error') {\n <span class=\"size-1.5 rounded-full bg-red-500\"></span> Error\n }\n @case ('output-denied') {\n <span class=\"size-1.5 rounded-full bg-slate-500\"></span> Denied\n }\n }\n </span>\n\n <span\n class=\"inline-flex size-6 items-center justify-center rounded text-slate-400 transition group-open:rotate-180\"\n aria-hidden=\"true\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"m5.75 8.25 4.25 4.25 4.25-4.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n </div>\n </div>\n </div>\n </div>\n </summary>\n\n <div class=\"bg-white px-4 pb-4 pt-3\">\n <div class=\"grid gap-3\">\n @for (snippet of codeSnippets(); track snippet.key) {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">\n {{ snippet.key }}\n </div>\n <div class=\"text-[11px] text-slate-400 font-mono\">\n {{ snippet.lang }}\n </div>\n </div>\n <pre\n dir=\"ltr\"\n class=\"m-0 max-h-80 overflow-auto p-3 text-[12px] leading-5 font-mono whitespace-pre wrap-break-word\"\n ><code class=\"hljs\" [innerHTML]=\"snippet.value | highlight : snippet.lang\"></code></pre>\n </div>\n }\n\n @if (remainingInput(); as remaining) {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">Input</div>\n <div class=\"text-[11px] text-slate-400 font-mono\">json</div>\n </div>\n <div dir=\"ltr\" class=\"max-h-64 overflow-auto p-3\">\n <cortex-json-tree [data]=\"remaining\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-available') {\n <div class=\"rounded-lg border border-emerald-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-emerald-200 bg-emerald-50\"\n >\n <div class=\"text-[11px] font-medium text-emerald-700\">Output</div>\n <div class=\"text-[11px] text-emerald-600 font-mono\">json</div>\n </div>\n <div dir=\"ltr\" class=\"max-h-64 overflow-auto p-3\">\n <cortex-json-tree [data]=\"toolCallPart().output\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-error') {\n <div class=\"rounded-lg border border-red-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-red-200 bg-red-50\"\n >\n <div class=\"text-[11px] font-medium text-red-700\">Error</div>\n <div class=\"text-[11px] text-red-600 font-mono\">text</div>\n </div>\n <pre\n dir=\"ltr\"\n class=\"m-0 max-h-64 overflow-auto p-3 text-[12px] leading-5 font-mono text-red-800 whitespace-pre-wrap wrap-break-word\"\n >{{ toolCallPart().errorText }}</pre\n >\n </div>\n }\n\n @if (toolCallPart().state === 'output-denied') {\n <div class=\"rounded-lg border border-slate-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-slate-200 bg-slate-50\"\n >\n <div class=\"text-[11px] font-medium text-slate-600\">Denied</div>\n <div class=\"text-[11px] text-slate-500 font-mono\">approval</div>\n </div>\n <div class=\"p-3 text-[12px] text-slate-700\">\n Tool execution was denied.\n @if (toolCallPart().approval?.reason) {\n <div class=\"mt-2 rounded bg-slate-50 border border-slate-200 p-2\">\n <div class=\"text-[11px] font-medium text-slate-600\">Reason</div>\n <div class=\"mt-1 font-mono text-[12px] text-slate-700 wrap-break-word\">\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-requested') {\n <div class=\"rounded-lg border border-violet-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-violet-200 bg-violet-50\"\n >\n <div class=\"text-[11px] font-medium text-violet-700\">Approval requested</div>\n <div class=\"text-[11px] text-violet-600 font-mono\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"p-3 text-[12px] text-violet-800\">\n Waiting for approval to execute this tool.\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-responded') {\n <div class=\"rounded-lg border border-violet-200 overflow-hidden\">\n <div\n class=\"px-3 py-2 flex items-center justify-between border-b border-violet-200 bg-violet-50\"\n >\n <div class=\"text-[11px] font-medium text-violet-700\">Approval response</div>\n <div class=\"text-[11px] text-violet-600 font-mono\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"p-3 text-[12px] text-violet-800\">\n @if (toolCallPart().approval?.approved) {\n Approved.\n } @else {\n Response received.\n }\n @if (toolCallPart().approval?.reason) {\n <div class=\"mt-2 rounded bg-violet-50 border border-violet-200 p-2\">\n <div class=\"text-[11px] font-medium text-violet-700\">Reason</div>\n <div class=\"mt-1 font-mono text-[12px] text-violet-800 wrap-break-word\">\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n</details>\n" }]
|
|
524
524
|
}], propDecorators: { toolCallPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolCallPart", required: true }] }] } });
|
|
525
525
|
|
|
526
526
|
class MessageCaptureFilesPartComponent {
|
|
527
|
-
message = input.required(...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
528
|
-
toolPart = input.required(...(ngDevMode ? [{ debugName: "toolPart" }] : []));
|
|
529
|
-
data = computed(() => this.toolPart().input, ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
530
|
-
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
527
|
+
message = input.required(...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
528
|
+
toolPart = input.required(...(ngDevMode ? [{ debugName: "toolPart" }] : /* istanbul ignore next */ []));
|
|
529
|
+
data = computed(() => this.toolPart().input, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
530
|
+
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
531
531
|
outputData = computed(() => {
|
|
532
532
|
const raw = this.toolPart().output;
|
|
533
533
|
if (!raw)
|
|
534
534
|
return null;
|
|
535
535
|
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
536
536
|
return parsed;
|
|
537
|
-
}, ...(ngDevMode ? [{ debugName: "outputData" }] : []));
|
|
537
|
+
}, ...(ngDevMode ? [{ debugName: "outputData" }] : /* istanbul ignore next */ []));
|
|
538
538
|
form = computed(() => {
|
|
539
539
|
const form = this.fb.group({
|
|
540
540
|
files: this.fb.array(this.data().files.map((x) => this.fb.group({
|
|
@@ -549,7 +549,7 @@ class MessageCaptureFilesPartComponent {
|
|
|
549
549
|
form.disable();
|
|
550
550
|
}
|
|
551
551
|
return form;
|
|
552
|
-
}, ...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
552
|
+
}, ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
553
553
|
fb = inject(FormBuilder);
|
|
554
554
|
chatService = inject(CortexChatService);
|
|
555
555
|
config = inject(CORTEX_CLIENT_CONFIG);
|
|
@@ -617,19 +617,19 @@ class MessageCaptureFilesPartComponent {
|
|
|
617
617
|
},
|
|
618
618
|
});
|
|
619
619
|
}
|
|
620
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
621
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: MessageCaptureFilesPartComponent, isStandalone: true, selector: "cortex-message-capture-files-part", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, toolPart: { classPropertyName: "toolPart", publicName: "toolPart", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@if (outputData(); as output) {\n <!-- \u2500\u2500 Result state \u2500\u2500 -->\n @if (output.status === 'success') {\n <div\n class=\"overflow-hidden rounded-2xl border border-emerald-200 bg-linear-to-b from-emerald-50/80 to-white\"\n >\n <div class=\"flex items-center gap-3 px-4 py-3 sm:px-5\">\n <div\n class=\"inline-flex size-8 shrink-0 items-center justify-center rounded-lg border border-emerald-200 bg-emerald-100 text-emerald-600\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M5.5 10.5 L8.5 13.5 L14.5 7\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n <div class=\"min-w-0\">\n <h3 class=\"text-[13px] font-semibold tracking-tight text-emerald-800\">\n {{ 'translate_files_attached' | translate: { count: data().files.length } }}\n </h3>\n </div>\n </div>\n\n <div class=\"border-t border-emerald-100 px-4 py-2.5 sm:px-5\">\n <ul class=\"flex flex-wrap gap-2\">\n @for (file of outputData()!.result!; track file.uploadId) {\n <li>\n <button\n type=\"button\"\n (click)=\"downloadFile(file.uploadId)\"\n class=\"inline-flex cursor-pointer items-center gap-1.5 rounded-lg border border-emerald-100 bg-white px-2.5 py-1.5 text-[12px] font-medium text-emerald-700 shadow-xs transition-all hover:border-emerald-200 hover:bg-emerald-50 hover:shadow-sm active:scale-[0.97]\"\n >\n <svg viewBox=\"0 0 16 16\" class=\"size-3.5 shrink-0 text-emerald-400\" fill=\"none\">\n <path\n d=\"M4 1.5h5.172a2 2 0 0 1 1.414.586l2.328 2.328a2 2 0 0 1 .586 1.414V12.5a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n />\n <path\n d=\"M9.5 1.5v2a2 2 0 0 0 2 2h2\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n stroke-linecap=\"round\"\n />\n </svg>\n <span class=\"truncate max-w-[180px]\">{{ data().files[$index].label }}</span>\n <svg viewBox=\"0 0 16 16\" class=\"size-3 shrink-0 text-emerald-300\" fill=\"none\">\n <path\n d=\"M8 3v7m0 0L5.5 7.5M8 10l2.5-2.5M3 13h10\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\n </div>\n </div>\n } @else {\n <!-- Canceled state -->\n <div class=\"flex justify-center\">\n <div\n class=\"inline-flex items-center gap-2.5 rounded-lg border border-slate-200 bg-slate-50 px-4 py-2.5\"\n >\n <div\n class=\"inline-flex size-6 shrink-0 items-center justify-center rounded-md border border-slate-200 bg-slate-100 text-slate-400\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-3\" fill=\"none\">\n <path d=\"M6 10h8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </div>\n <span class=\"text-[13px] font-medium text-slate-400\">{{\n 'translate_file_upload_skipped' | translate\n }}</span>\n </div>\n </div>\n }\n} @else {\n <!-- \u2500\u2500 Upload form \u2500\u2500 -->\n <form [formGroup]=\"form()\" class=\"w-full\">\n @if (data().files.length === 1) {\n <!-- Single file: minimal inline -->\n <fieldset [formArray]=\"form().controls.files\">\n <div [formGroupName]=\"0\" class=\"rounded-xl border border-slate-200 bg-slate-50 p-3\">\n <label for=\"capture-file-0\" class=\"mb-1.5 block text-[12px] text-slate-500\">\n {{ data().files[0].label }}\n </label>\n <input hidden formControlName=\"id\" />\n <div class=\"flex items-center gap-2\">\n <cortex-file-input id=\"capture-file-0\" formControlName=\"file\" class=\"min-w-0 flex-1\" />\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"shrink-0 text-[12px] font-medium text-slate-400 transition-colors hover:text-slate-600\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"inline-flex shrink-0 items-center rounded-md bg-slate-800 px-3 py-1.5 text-[12px] font-medium text-slate-100 transition-colors hover:bg-slate-700 active:bg-slate-900 disabled:cursor-not-allowed disabled:bg-slate-300\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"mr-1.5 size-3 animate-spin\" viewBox=\"0 0 16 16\" fill=\"none\">\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n class=\"opacity-25\"\n />\n <path\n d=\"M14 8a6 6 0 0 0-6-6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ 'translate_uploading' | translate }}\n } @else {\n {{ 'translate_submit' | translate }}\n }\n </button>\n </div>\n </div>\n </fieldset>\n } @else {\n <!-- Multi-file: full form -->\n <div\n class=\"overflow-hidden rounded-2xl border border-slate-200 bg-gradient-to-b from-white to-slate-50\"\n >\n <div class=\"border-b border-slate-200 bg-white/85 px-4 py-3 sm:px-5\">\n <div class=\"flex items-start gap-3\">\n <div\n class=\"mt-0.5 inline-flex size-8 shrink-0 items-center justify-center rounded-lg border border-slate-200 bg-slate-100 text-slate-600\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M4 13.5a3.5 3.5 0 0 1-.5-6.97 5.002 5.002 0 0 1 9.78-1.03A4.5 4.5 0 0 1 15.5 14\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M10 10v7m0-7-2.5 2.5M10 10l2.5 2.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n\n <div class=\"min-w-0\">\n <h3 class=\"text-[13px] font-semibold tracking-tight text-slate-800\">\n {{ 'translate_attach_requested_files' | translate }}\n </h3>\n <p class=\"mt-0.5 text-[11px] text-slate-500\">\n {{ 'translate_n_files_required' | translate: { count: data().files.length } }}\n </p>\n </div>\n </div>\n </div>\n\n <fieldset [formArray]=\"form().controls.files\" class=\"grid gap-3 p-4 sm:p-5\">\n @for (file of form().controls.files.value; track $index) {\n <div\n [formGroupName]=\"$index\"\n class=\"rounded-xl border border-slate-200 bg-white p-3 transition-colors hover:border-slate-300\"\n >\n <div class=\"mb-2 flex items-center justify-between gap-2\">\n <label\n [for]=\"'capture-file-' + $index\"\n class=\"block text-[12px] font-medium leading-none text-slate-700\"\n >\n {{ data().files[$index].label }}\n </label>\n <span\n class=\"inline-flex items-center rounded border border-slate-200 bg-slate-50 px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-slate-500\"\n >\n {{ 'translate_required' | translate }}\n </span>\n </div>\n\n <input hidden formControlName=\"id\" />\n <cortex-file-input [id]=\"'capture-file-' + $index\" formControlName=\"file\" />\n </div>\n }\n </fieldset>\n\n <div\n class=\"flex items-center justify-end gap-2 border-t border-slate-200 bg-white/90 px-4 py-3 sm:px-5\"\n >\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"inline-flex items-center rounded-md border border-slate-300 bg-white px-3 py-1.5 text-[12px] font-medium text-slate-600 transition-colors hover:bg-slate-50 active:bg-slate-100\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"inline-flex items-center rounded-md bg-slate-800 px-3 py-1.5 text-[12px] font-medium text-slate-100 transition-colors hover:bg-slate-700 active:bg-slate-900 disabled:cursor-not-allowed disabled:bg-slate-300\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"mr-1.5 size-3 animate-spin\" viewBox=\"0 0 16 16\" fill=\"none\">\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n class=\"opacity-25\"\n />\n <path\n d=\"M14 8a6 6 0 0 0-6-6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ 'translate_uploading' | translate }}\n } @else {\n {{ 'translate_submit_files' | translate }}\n }\n </button>\n </div>\n </div>\n }\n </form>\n}\n", styles: [":host{display:block;width:100%}\n/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "directive", type: i0.forwardRef(() => i1$1.ɵNgNoValidate), selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i0.forwardRef(() => i1$1.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: i0.forwardRef(() => i1$1.NgControlStatus), selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgControlStatusGroup), selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i0.forwardRef(() => i1$1.FormGroupDirective), selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.FormArrayDirective), selector: "[formArray]", inputs: ["formArray"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.FormControlName), selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.FormGroupName), selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: i0.forwardRef(() => FileInputComponent), selector: "cortex-file-input", inputs: ["allowedMimeTypes"] }, { kind: "pipe", type: i0.forwardRef(() => TranslatePipe), name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
620
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageCaptureFilesPartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
621
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: MessageCaptureFilesPartComponent, isStandalone: true, selector: "cortex-message-capture-files-part", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, toolPart: { classPropertyName: "toolPart", publicName: "toolPart", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@if (outputData(); as output) {\n <!-- \u2500\u2500 Result state \u2500\u2500 -->\n @if (output.status === 'success') {\n <div\n class=\"overflow-hidden rounded-2xl border border-emerald-200 bg-linear-to-b from-emerald-50/80 to-white\"\n >\n <div class=\"flex items-center gap-3 px-4 py-3 sm:px-5\">\n <div\n class=\"inline-flex size-8 shrink-0 items-center justify-center rounded-lg border border-emerald-200 bg-emerald-100 text-emerald-600\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M5.5 10.5 L8.5 13.5 L14.5 7\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n <div class=\"min-w-0\">\n <h3 class=\"text-[13px] font-semibold tracking-tight text-emerald-800\">\n {{ 'translate_files_attached' | translate: { count: data().files.length } }}\n </h3>\n </div>\n </div>\n\n <div class=\"border-t border-emerald-100 px-4 py-2.5 sm:px-5\">\n <ul class=\"flex flex-wrap gap-2\">\n @for (file of outputData()!.result!; track file.uploadId) {\n <li>\n <button\n type=\"button\"\n (click)=\"downloadFile(file.uploadId)\"\n class=\"inline-flex cursor-pointer items-center gap-1.5 rounded-lg border border-emerald-100 bg-white px-2.5 py-1.5 text-[12px] font-medium text-emerald-700 shadow-xs transition-all hover:border-emerald-200 hover:bg-emerald-50 hover:shadow-sm active:scale-[0.97]\"\n >\n <svg viewBox=\"0 0 16 16\" class=\"size-3.5 shrink-0 text-emerald-400\" fill=\"none\">\n <path\n d=\"M4 1.5h5.172a2 2 0 0 1 1.414.586l2.328 2.328a2 2 0 0 1 .586 1.414V12.5a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n />\n <path\n d=\"M9.5 1.5v2a2 2 0 0 0 2 2h2\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n stroke-linecap=\"round\"\n />\n </svg>\n <span class=\"truncate max-w-[180px]\">{{ data().files[$index].label }}</span>\n <svg viewBox=\"0 0 16 16\" class=\"size-3 shrink-0 text-emerald-300\" fill=\"none\">\n <path\n d=\"M8 3v7m0 0L5.5 7.5M8 10l2.5-2.5M3 13h10\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\n </div>\n </div>\n } @else {\n <!-- Canceled state -->\n <div class=\"flex justify-center\">\n <div\n class=\"inline-flex items-center gap-2.5 rounded-lg border border-slate-200 bg-slate-50 px-4 py-2.5\"\n >\n <div\n class=\"inline-flex size-6 shrink-0 items-center justify-center rounded-md border border-slate-200 bg-slate-100 text-slate-400\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-3\" fill=\"none\">\n <path d=\"M6 10h8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </div>\n <span class=\"text-[13px] font-medium text-slate-400\">{{\n 'translate_file_upload_skipped' | translate\n }}</span>\n </div>\n </div>\n }\n} @else {\n <!-- \u2500\u2500 Upload form \u2500\u2500 -->\n <form [formGroup]=\"form()\" class=\"w-full\">\n @if (data().files.length === 1) {\n <!-- Single file: minimal inline -->\n <fieldset [formArray]=\"form().controls.files\">\n <div [formGroupName]=\"0\" class=\"rounded-xl border border-slate-200 bg-slate-50 p-3\">\n <label for=\"capture-file-0\" class=\"mb-1.5 block text-[12px] text-slate-500\">\n {{ data().files[0].label }}\n </label>\n <input hidden formControlName=\"id\" />\n <div class=\"flex items-center gap-2\">\n <cortex-file-input id=\"capture-file-0\" formControlName=\"file\" class=\"min-w-0 flex-1\" />\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"shrink-0 text-[12px] font-medium text-slate-400 transition-colors hover:text-slate-600\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"inline-flex shrink-0 items-center rounded-md bg-slate-800 px-3 py-1.5 text-[12px] font-medium text-slate-100 transition-colors hover:bg-slate-700 active:bg-slate-900 disabled:cursor-not-allowed disabled:bg-slate-300\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"mr-1.5 size-3 animate-spin\" viewBox=\"0 0 16 16\" fill=\"none\">\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n class=\"opacity-25\"\n />\n <path\n d=\"M14 8a6 6 0 0 0-6-6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ 'translate_uploading' | translate }}\n } @else {\n {{ 'translate_submit' | translate }}\n }\n </button>\n </div>\n </div>\n </fieldset>\n } @else {\n <!-- Multi-file: full form -->\n <div\n class=\"overflow-hidden rounded-2xl border border-slate-200 bg-gradient-to-b from-white to-slate-50\"\n >\n <div class=\"border-b border-slate-200 bg-white/85 px-4 py-3 sm:px-5\">\n <div class=\"flex items-start gap-3\">\n <div\n class=\"mt-0.5 inline-flex size-8 shrink-0 items-center justify-center rounded-lg border border-slate-200 bg-slate-100 text-slate-600\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M4 13.5a3.5 3.5 0 0 1-.5-6.97 5.002 5.002 0 0 1 9.78-1.03A4.5 4.5 0 0 1 15.5 14\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M10 10v7m0-7-2.5 2.5M10 10l2.5 2.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n\n <div class=\"min-w-0\">\n <h3 class=\"text-[13px] font-semibold tracking-tight text-slate-800\">\n {{ 'translate_attach_requested_files' | translate }}\n </h3>\n <p class=\"mt-0.5 text-[11px] text-slate-500\">\n {{ 'translate_n_files_required' | translate: { count: data().files.length } }}\n </p>\n </div>\n </div>\n </div>\n\n <fieldset [formArray]=\"form().controls.files\" class=\"grid gap-3 p-4 sm:p-5\">\n @for (file of form().controls.files.value; track $index) {\n <div\n [formGroupName]=\"$index\"\n class=\"rounded-xl border border-slate-200 bg-white p-3 transition-colors hover:border-slate-300\"\n >\n <div class=\"mb-2 flex items-center justify-between gap-2\">\n <label\n [for]=\"'capture-file-' + $index\"\n class=\"block text-[12px] font-medium leading-none text-slate-700\"\n >\n {{ data().files[$index].label }}\n </label>\n <span\n class=\"inline-flex items-center rounded border border-slate-200 bg-slate-50 px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-slate-500\"\n >\n {{ 'translate_required' | translate }}\n </span>\n </div>\n\n <input hidden formControlName=\"id\" />\n <cortex-file-input [id]=\"'capture-file-' + $index\" formControlName=\"file\" />\n </div>\n }\n </fieldset>\n\n <div\n class=\"flex items-center justify-end gap-2 border-t border-slate-200 bg-white/90 px-4 py-3 sm:px-5\"\n >\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"inline-flex items-center rounded-md border border-slate-300 bg-white px-3 py-1.5 text-[12px] font-medium text-slate-600 transition-colors hover:bg-slate-50 active:bg-slate-100\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"inline-flex items-center rounded-md bg-slate-800 px-3 py-1.5 text-[12px] font-medium text-slate-100 transition-colors hover:bg-slate-700 active:bg-slate-900 disabled:cursor-not-allowed disabled:bg-slate-300\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"mr-1.5 size-3 animate-spin\" viewBox=\"0 0 16 16\" fill=\"none\">\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n class=\"opacity-25\"\n />\n <path\n d=\"M14 8a6 6 0 0 0-6-6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ 'translate_uploading' | translate }}\n } @else {\n {{ 'translate_submit_files' | translate }}\n }\n </button>\n </div>\n </div>\n }\n </form>\n}\n", styles: [":host{display:block;width:100%}\n/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "directive", type: i0.forwardRef(() => i1$1.ɵNgNoValidate), selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i0.forwardRef(() => i1$1.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: i0.forwardRef(() => i1$1.NgControlStatus), selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgControlStatusGroup), selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i0.forwardRef(() => i1$1.FormGroupDirective), selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.FormArrayDirective), selector: "[formArray]", inputs: ["formArray"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.FormControlName), selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.FormGroupName), selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: i0.forwardRef(() => FileInputComponent), selector: "cortex-file-input", inputs: ["allowedMimeTypes"] }, { kind: "pipe", type: i0.forwardRef(() => TranslatePipe), name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
622
622
|
}
|
|
623
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
623
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageCaptureFilesPartComponent, decorators: [{
|
|
624
624
|
type: Component,
|
|
625
625
|
args: [{ selector: 'cortex-message-capture-files-part', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ReactiveFormsModule, forwardRef(() => FileInputComponent), TranslatePipe], template: "@if (outputData(); as output) {\n <!-- \u2500\u2500 Result state \u2500\u2500 -->\n @if (output.status === 'success') {\n <div\n class=\"overflow-hidden rounded-2xl border border-emerald-200 bg-linear-to-b from-emerald-50/80 to-white\"\n >\n <div class=\"flex items-center gap-3 px-4 py-3 sm:px-5\">\n <div\n class=\"inline-flex size-8 shrink-0 items-center justify-center rounded-lg border border-emerald-200 bg-emerald-100 text-emerald-600\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M5.5 10.5 L8.5 13.5 L14.5 7\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n <div class=\"min-w-0\">\n <h3 class=\"text-[13px] font-semibold tracking-tight text-emerald-800\">\n {{ 'translate_files_attached' | translate: { count: data().files.length } }}\n </h3>\n </div>\n </div>\n\n <div class=\"border-t border-emerald-100 px-4 py-2.5 sm:px-5\">\n <ul class=\"flex flex-wrap gap-2\">\n @for (file of outputData()!.result!; track file.uploadId) {\n <li>\n <button\n type=\"button\"\n (click)=\"downloadFile(file.uploadId)\"\n class=\"inline-flex cursor-pointer items-center gap-1.5 rounded-lg border border-emerald-100 bg-white px-2.5 py-1.5 text-[12px] font-medium text-emerald-700 shadow-xs transition-all hover:border-emerald-200 hover:bg-emerald-50 hover:shadow-sm active:scale-[0.97]\"\n >\n <svg viewBox=\"0 0 16 16\" class=\"size-3.5 shrink-0 text-emerald-400\" fill=\"none\">\n <path\n d=\"M4 1.5h5.172a2 2 0 0 1 1.414.586l2.328 2.328a2 2 0 0 1 .586 1.414V12.5a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n />\n <path\n d=\"M9.5 1.5v2a2 2 0 0 0 2 2h2\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n stroke-linecap=\"round\"\n />\n </svg>\n <span class=\"truncate max-w-[180px]\">{{ data().files[$index].label }}</span>\n <svg viewBox=\"0 0 16 16\" class=\"size-3 shrink-0 text-emerald-300\" fill=\"none\">\n <path\n d=\"M8 3v7m0 0L5.5 7.5M8 10l2.5-2.5M3 13h10\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\n </div>\n </div>\n } @else {\n <!-- Canceled state -->\n <div class=\"flex justify-center\">\n <div\n class=\"inline-flex items-center gap-2.5 rounded-lg border border-slate-200 bg-slate-50 px-4 py-2.5\"\n >\n <div\n class=\"inline-flex size-6 shrink-0 items-center justify-center rounded-md border border-slate-200 bg-slate-100 text-slate-400\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-3\" fill=\"none\">\n <path d=\"M6 10h8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </div>\n <span class=\"text-[13px] font-medium text-slate-400\">{{\n 'translate_file_upload_skipped' | translate\n }}</span>\n </div>\n </div>\n }\n} @else {\n <!-- \u2500\u2500 Upload form \u2500\u2500 -->\n <form [formGroup]=\"form()\" class=\"w-full\">\n @if (data().files.length === 1) {\n <!-- Single file: minimal inline -->\n <fieldset [formArray]=\"form().controls.files\">\n <div [formGroupName]=\"0\" class=\"rounded-xl border border-slate-200 bg-slate-50 p-3\">\n <label for=\"capture-file-0\" class=\"mb-1.5 block text-[12px] text-slate-500\">\n {{ data().files[0].label }}\n </label>\n <input hidden formControlName=\"id\" />\n <div class=\"flex items-center gap-2\">\n <cortex-file-input id=\"capture-file-0\" formControlName=\"file\" class=\"min-w-0 flex-1\" />\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"shrink-0 text-[12px] font-medium text-slate-400 transition-colors hover:text-slate-600\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"inline-flex shrink-0 items-center rounded-md bg-slate-800 px-3 py-1.5 text-[12px] font-medium text-slate-100 transition-colors hover:bg-slate-700 active:bg-slate-900 disabled:cursor-not-allowed disabled:bg-slate-300\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"mr-1.5 size-3 animate-spin\" viewBox=\"0 0 16 16\" fill=\"none\">\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n class=\"opacity-25\"\n />\n <path\n d=\"M14 8a6 6 0 0 0-6-6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ 'translate_uploading' | translate }}\n } @else {\n {{ 'translate_submit' | translate }}\n }\n </button>\n </div>\n </div>\n </fieldset>\n } @else {\n <!-- Multi-file: full form -->\n <div\n class=\"overflow-hidden rounded-2xl border border-slate-200 bg-gradient-to-b from-white to-slate-50\"\n >\n <div class=\"border-b border-slate-200 bg-white/85 px-4 py-3 sm:px-5\">\n <div class=\"flex items-start gap-3\">\n <div\n class=\"mt-0.5 inline-flex size-8 shrink-0 items-center justify-center rounded-lg border border-slate-200 bg-slate-100 text-slate-600\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" class=\"size-4\" fill=\"none\">\n <path\n d=\"M4 13.5a3.5 3.5 0 0 1-.5-6.97 5.002 5.002 0 0 1 9.78-1.03A4.5 4.5 0 0 1 15.5 14\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M10 10v7m0-7-2.5 2.5M10 10l2.5 2.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n\n <div class=\"min-w-0\">\n <h3 class=\"text-[13px] font-semibold tracking-tight text-slate-800\">\n {{ 'translate_attach_requested_files' | translate }}\n </h3>\n <p class=\"mt-0.5 text-[11px] text-slate-500\">\n {{ 'translate_n_files_required' | translate: { count: data().files.length } }}\n </p>\n </div>\n </div>\n </div>\n\n <fieldset [formArray]=\"form().controls.files\" class=\"grid gap-3 p-4 sm:p-5\">\n @for (file of form().controls.files.value; track $index) {\n <div\n [formGroupName]=\"$index\"\n class=\"rounded-xl border border-slate-200 bg-white p-3 transition-colors hover:border-slate-300\"\n >\n <div class=\"mb-2 flex items-center justify-between gap-2\">\n <label\n [for]=\"'capture-file-' + $index\"\n class=\"block text-[12px] font-medium leading-none text-slate-700\"\n >\n {{ data().files[$index].label }}\n </label>\n <span\n class=\"inline-flex items-center rounded border border-slate-200 bg-slate-50 px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-slate-500\"\n >\n {{ 'translate_required' | translate }}\n </span>\n </div>\n\n <input hidden formControlName=\"id\" />\n <cortex-file-input [id]=\"'capture-file-' + $index\" formControlName=\"file\" />\n </div>\n }\n </fieldset>\n\n <div\n class=\"flex items-center justify-end gap-2 border-t border-slate-200 bg-white/90 px-4 py-3 sm:px-5\"\n >\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"inline-flex items-center rounded-md border border-slate-300 bg-white px-3 py-1.5 text-[12px] font-medium text-slate-600 transition-colors hover:bg-slate-50 active:bg-slate-100\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"inline-flex items-center rounded-md bg-slate-800 px-3 py-1.5 text-[12px] font-medium text-slate-100 transition-colors hover:bg-slate-700 active:bg-slate-900 disabled:cursor-not-allowed disabled:bg-slate-300\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"mr-1.5 size-3 animate-spin\" viewBox=\"0 0 16 16\" fill=\"none\">\n <circle\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n class=\"opacity-25\"\n />\n <path\n d=\"M14 8a6 6 0 0 0-6-6\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ 'translate_uploading' | translate }}\n } @else {\n {{ 'translate_submit_files' | translate }}\n }\n </button>\n </div>\n </div>\n }\n </form>\n}\n", styles: [":host{display:block;width:100%}\n/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\n"] }]
|
|
626
626
|
}], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], toolPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolPart", required: true }] }] } });
|
|
627
627
|
class FileInputComponent {
|
|
628
|
-
allowedMimeTypes = input('*/*', ...(ngDevMode ? [{ debugName: "allowedMimeTypes" }] : []));
|
|
629
|
-
value = signal(undefined, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
630
|
-
isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
628
|
+
allowedMimeTypes = input('*/*', ...(ngDevMode ? [{ debugName: "allowedMimeTypes" }] : /* istanbul ignore next */ []));
|
|
629
|
+
value = signal(undefined, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
630
|
+
isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
631
631
|
onTouch;
|
|
632
|
-
isProcessing = signal(false, ...(ngDevMode ? [{ debugName: "isProcessing" }] : []));
|
|
632
|
+
isProcessing = signal(false, ...(ngDevMode ? [{ debugName: "isProcessing" }] : /* istanbul ignore next */ []));
|
|
633
633
|
onChange;
|
|
634
634
|
writeValue(value) {
|
|
635
635
|
this.value.set(value);
|
|
@@ -658,8 +658,8 @@ class FileInputComponent {
|
|
|
658
658
|
this.value.set(value);
|
|
659
659
|
this.onChange?.(value);
|
|
660
660
|
}
|
|
661
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
662
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
661
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: FileInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
662
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.3", type: FileInputComponent, isStandalone: true, selector: "cortex-file-input", inputs: { allowedMimeTypes: { classPropertyName: "allowedMimeTypes", publicName: "allowedMimeTypes", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
663
663
|
{
|
|
664
664
|
provide: NG_VALUE_ACCESSOR,
|
|
665
665
|
multi: true,
|
|
@@ -681,7 +681,7 @@ class FileInputComponent {
|
|
|
681
681
|
<input #fileInput (change)="loadFile($event)" type="file" class="hidden" />
|
|
682
682
|
</div>`, isInline: true, dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
683
683
|
}
|
|
684
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
684
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: FileInputComponent, decorators: [{
|
|
685
685
|
type: Component,
|
|
686
686
|
args: [{
|
|
687
687
|
selector: 'cortex-file-input',
|
|
@@ -734,14 +734,14 @@ async function convertFileToBase64(file) {
|
|
|
734
734
|
|
|
735
735
|
const STATUS_COUNT = 10;
|
|
736
736
|
class MessageToolCallAnimatedComponent {
|
|
737
|
-
message = input.required(...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
738
|
-
toolCallPart = input.required(...(ngDevMode ? [{ debugName: "toolCallPart" }] : []));
|
|
737
|
+
message = input.required(...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
738
|
+
toolCallPart = input.required(...(ngDevMode ? [{ debugName: "toolCallPart" }] : /* istanbul ignore next */ []));
|
|
739
739
|
config = inject(CORTEX_CLIENT_CONFIG);
|
|
740
740
|
customComponent = computed(() => {
|
|
741
741
|
const toolName = this.toolCallPart().type;
|
|
742
742
|
const name = toolName?.startsWith('tool-') ? toolName.slice('tool-'.length) : toolName;
|
|
743
743
|
return name ? (this.config.toolComponents?.[name] ?? null) : null;
|
|
744
|
-
}, ...(ngDevMode ? [{ debugName: "customComponent" }] : []));
|
|
744
|
+
}, ...(ngDevMode ? [{ debugName: "customComponent" }] : /* istanbul ignore next */ []));
|
|
745
745
|
animState = computed(() => {
|
|
746
746
|
const state = this.toolCallPart().state;
|
|
747
747
|
switch (state) {
|
|
@@ -760,11 +760,11 @@ class MessageToolCallAnimatedComponent {
|
|
|
760
760
|
default:
|
|
761
761
|
return 'processing';
|
|
762
762
|
}
|
|
763
|
-
}, ...(ngDevMode ? [{ debugName: "animState" }] : []));
|
|
763
|
+
}, ...(ngDevMode ? [{ debugName: "animState" }] : /* istanbul ignore next */ []));
|
|
764
764
|
isActive = computed(() => {
|
|
765
765
|
const s = this.animState();
|
|
766
766
|
return s === 'starting' || s === 'processing';
|
|
767
|
-
}, ...(ngDevMode ? [{ debugName: "isActive" }] : []));
|
|
767
|
+
}, ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
|
|
768
768
|
displayTitleKey = computed(() => {
|
|
769
769
|
const state = this.animState();
|
|
770
770
|
switch (state) {
|
|
@@ -780,7 +780,7 @@ class MessageToolCallAnimatedComponent {
|
|
|
780
780
|
default:
|
|
781
781
|
return `translate_tool_status_${this.stableIndex()}`;
|
|
782
782
|
}
|
|
783
|
-
}, ...(ngDevMode ? [{ debugName: "displayTitleKey" }] : []));
|
|
783
|
+
}, ...(ngDevMode ? [{ debugName: "displayTitleKey" }] : /* istanbul ignore next */ []));
|
|
784
784
|
stableIndex = computed(() => {
|
|
785
785
|
const id = this.toolCallPart().toolCallId ?? '';
|
|
786
786
|
let hash = 0;
|
|
@@ -788,30 +788,30 @@ class MessageToolCallAnimatedComponent {
|
|
|
788
788
|
hash = (hash * 31 + id.charCodeAt(i)) | 0;
|
|
789
789
|
}
|
|
790
790
|
return Math.abs(hash) % STATUS_COUNT;
|
|
791
|
-
}, ...(ngDevMode ? [{ debugName: "stableIndex" }] : []));
|
|
792
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
793
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
791
|
+
}, ...(ngDevMode ? [{ debugName: "stableIndex" }] : /* istanbul ignore next */ []));
|
|
792
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageToolCallAnimatedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
793
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: MessageToolCallAnimatedComponent, isStandalone: true, selector: "cortex-message-tool-call-animated", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, toolCallPart: { classPropertyName: "toolCallPart", publicName: "toolCallPart", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "block w-full" }, ngImport: i0, template: "@if (customComponent(); as custom) {\n <ng-container\n *ngComponentOutlet=\"custom; inputs: { toolCallPart: toolCallPart(), message: message() }\"\n />\n} @else {\n @switch (toolCallPart().type) {\n @case ('tool-captureFiles') {\n <cortex-message-capture-files-part [toolPart]=\"toolCallPart()\" [message]=\"message()\" />\n }\n @default {\n @let state = animState();\n @let active = isActive();\n\n <div class=\"flex justify-center\">\n <div\n class=\"inline-flex items-center gap-2.5 py-2.5 px-4 rounded-lg border relative overflow-hidden transition-colors duration-300\"\n [ngClass]=\"{\n 'border-indigo-200 bg-indigo-50': active,\n 'border-emerald-200 bg-emerald-50': state === 'complete',\n 'border-red-200 bg-red-50': state === 'error',\n 'border-slate-200 bg-slate-50 opacity-60': state === 'denied',\n }\"\n >\n <!-- Icon box -->\n <div\n class=\"relative size-6 flex items-center justify-center rounded-md border shrink-0 transition-colors duration-300\"\n [ngClass]=\"{\n 'bg-indigo-100 border-indigo-200': active,\n 'bg-emerald-100 border-emerald-200': state === 'complete',\n 'bg-red-100 border-red-200': state === 'error',\n 'bg-slate-100 border-slate-200': state === 'denied',\n }\"\n >\n <!-- Spinner -->\n <div\n class=\"absolute size-3 border-[1.5px] border-indigo-200 border-t-indigo-500 rounded-full animate-spin transition-opacity duration-200\"\n [ngClass]=\"active ? 'opacity-100' : 'opacity-0'\"\n ></div>\n <!-- Check -->\n <svg\n class=\"absolute size-3 transition-all duration-200\"\n [ngClass]=\"\n state === 'complete'\n ? 'opacity-100 scale-100 text-emerald-600'\n : 'opacity-0 scale-[0.6]'\n \"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n >\n <path\n d=\"M5.5 10.5 L8.5 13.5 L14.5 7\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <!-- Error -->\n <svg\n class=\"absolute size-3 transition-all duration-200\"\n [ngClass]=\"\n state === 'error' ? 'opacity-100 scale-100 text-red-600' : 'opacity-0 scale-[0.6]'\n \"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n >\n <path\n d=\"M6.5 6.5 L13.5 13.5 M13.5 6.5 L6.5 13.5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n <!-- Denied -->\n <svg\n class=\"absolute size-3 transition-all duration-200\"\n [ngClass]=\"\n state === 'denied'\n ? 'opacity-100 scale-100 text-slate-400'\n : 'opacity-0 scale-[0.6]'\n \"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n >\n <path\n d=\"M6 10 L14 10\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n\n <!-- Title -->\n <span\n class=\"text-[13px] font-medium whitespace-nowrap overflow-hidden text-ellipsis transition-colors duration-300\"\n [ngClass]=\"{\n 'text-indigo-700': active,\n 'text-emerald-700': state === 'complete',\n 'text-red-600': state === 'error',\n 'text-slate-400': state === 'denied',\n }\"\n >\n {{ displayTitleKey() | translate }}\n </span>\n\n <!-- Bottom bar -->\n <div class=\"absolute bottom-0 inset-x-0 h-0.5 overflow-hidden\">\n <div\n class=\"h-full w-full origin-left\"\n [ngClass]=\"{\n 'bg-indigo-400 animate-bar-slide': active,\n 'bg-emerald-400 animate-bar-fill': state === 'complete',\n 'bg-red-400 animate-bar-fill': state === 'error',\n 'opacity-0': state === 'denied',\n }\"\n ></div>\n </div>\n </div>\n </div>\n }\n }\n}\n", styles: [".animate-bar-slide{animation:bar-slide 1.5s ease-in-out infinite}.animate-bar-fill{animation:bar-fill .3s ease-out both}@keyframes bar-slide{0%{transform:translate(-100%)}to{transform:translate(100%)}}@keyframes bar-fill{0%{transform:scaleX(0)}to{transform:scaleX(1)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MessageCaptureFilesPartComponent, selector: "cortex-message-capture-files-part", inputs: ["message", "toolPart"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
794
794
|
}
|
|
795
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
795
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageToolCallAnimatedComponent, decorators: [{
|
|
796
796
|
type: Component,
|
|
797
797
|
args: [{ selector: 'cortex-message-tool-call-animated', imports: [NgClass, MessageCaptureFilesPartComponent, TranslatePipe], host: { class: 'block w-full' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (customComponent(); as custom) {\n <ng-container\n *ngComponentOutlet=\"custom; inputs: { toolCallPart: toolCallPart(), message: message() }\"\n />\n} @else {\n @switch (toolCallPart().type) {\n @case ('tool-captureFiles') {\n <cortex-message-capture-files-part [toolPart]=\"toolCallPart()\" [message]=\"message()\" />\n }\n @default {\n @let state = animState();\n @let active = isActive();\n\n <div class=\"flex justify-center\">\n <div\n class=\"inline-flex items-center gap-2.5 py-2.5 px-4 rounded-lg border relative overflow-hidden transition-colors duration-300\"\n [ngClass]=\"{\n 'border-indigo-200 bg-indigo-50': active,\n 'border-emerald-200 bg-emerald-50': state === 'complete',\n 'border-red-200 bg-red-50': state === 'error',\n 'border-slate-200 bg-slate-50 opacity-60': state === 'denied',\n }\"\n >\n <!-- Icon box -->\n <div\n class=\"relative size-6 flex items-center justify-center rounded-md border shrink-0 transition-colors duration-300\"\n [ngClass]=\"{\n 'bg-indigo-100 border-indigo-200': active,\n 'bg-emerald-100 border-emerald-200': state === 'complete',\n 'bg-red-100 border-red-200': state === 'error',\n 'bg-slate-100 border-slate-200': state === 'denied',\n }\"\n >\n <!-- Spinner -->\n <div\n class=\"absolute size-3 border-[1.5px] border-indigo-200 border-t-indigo-500 rounded-full animate-spin transition-opacity duration-200\"\n [ngClass]=\"active ? 'opacity-100' : 'opacity-0'\"\n ></div>\n <!-- Check -->\n <svg\n class=\"absolute size-3 transition-all duration-200\"\n [ngClass]=\"\n state === 'complete'\n ? 'opacity-100 scale-100 text-emerald-600'\n : 'opacity-0 scale-[0.6]'\n \"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n >\n <path\n d=\"M5.5 10.5 L8.5 13.5 L14.5 7\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <!-- Error -->\n <svg\n class=\"absolute size-3 transition-all duration-200\"\n [ngClass]=\"\n state === 'error' ? 'opacity-100 scale-100 text-red-600' : 'opacity-0 scale-[0.6]'\n \"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n >\n <path\n d=\"M6.5 6.5 L13.5 13.5 M13.5 6.5 L6.5 13.5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n <!-- Denied -->\n <svg\n class=\"absolute size-3 transition-all duration-200\"\n [ngClass]=\"\n state === 'denied'\n ? 'opacity-100 scale-100 text-slate-400'\n : 'opacity-0 scale-[0.6]'\n \"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n >\n <path\n d=\"M6 10 L14 10\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n\n <!-- Title -->\n <span\n class=\"text-[13px] font-medium whitespace-nowrap overflow-hidden text-ellipsis transition-colors duration-300\"\n [ngClass]=\"{\n 'text-indigo-700': active,\n 'text-emerald-700': state === 'complete',\n 'text-red-600': state === 'error',\n 'text-slate-400': state === 'denied',\n }\"\n >\n {{ displayTitleKey() | translate }}\n </span>\n\n <!-- Bottom bar -->\n <div class=\"absolute bottom-0 inset-x-0 h-0.5 overflow-hidden\">\n <div\n class=\"h-full w-full origin-left\"\n [ngClass]=\"{\n 'bg-indigo-400 animate-bar-slide': active,\n 'bg-emerald-400 animate-bar-fill': state === 'complete',\n 'bg-red-400 animate-bar-fill': state === 'error',\n 'opacity-0': state === 'denied',\n }\"\n ></div>\n </div>\n </div>\n </div>\n }\n }\n}\n", styles: [".animate-bar-slide{animation:bar-slide 1.5s ease-in-out infinite}.animate-bar-fill{animation:bar-fill .3s ease-out both}@keyframes bar-slide{0%{transform:translate(-100%)}to{transform:translate(100%)}}@keyframes bar-fill{0%{transform:scaleX(0)}to{transform:scaleX(1)}}\n"] }]
|
|
798
798
|
}], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], toolCallPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolCallPart", required: true }] }] } });
|
|
799
799
|
|
|
800
800
|
class MessageReasoningAnimatedComponent {
|
|
801
|
-
reasoningPart = input.required(...(ngDevMode ? [{ debugName: "reasoningPart" }] : []));
|
|
802
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
803
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
801
|
+
reasoningPart = input.required(...(ngDevMode ? [{ debugName: "reasoningPart" }] : /* istanbul ignore next */ []));
|
|
802
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageReasoningAnimatedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
803
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.3", type: MessageReasoningAnimatedComponent, isStandalone: true, selector: "cortex-message-reasoning-animated", inputs: { reasoningPart: { classPropertyName: "reasoningPart", publicName: "reasoningPart", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "flex justify-center" }, ngImport: i0, template: "@let p = reasoningPart();\n@let streaming = p.state === 'streaming';\n\n<div\n class=\"inline-flex items-center gap-2.5 py-2 pl-3 pr-4 rounded-lg border transition-colors duration-300\"\n [ngClass]=\"streaming ? 'border-indigo-200 bg-indigo-50' : 'border-slate-200 bg-slate-50'\"\n>\n <div class=\"flex items-center gap-1\">\n <span\n class=\"size-[5px] rounded-full transition-all duration-400\"\n [ngClass]=\"streaming ? 'animate-dot-pulse bg-indigo-300' : 'bg-slate-300 opacity-40'\"\n ></span>\n <span\n class=\"size-[5px] rounded-full transition-all duration-400\"\n [ngClass]=\"streaming ? 'animate-dot-pulse bg-indigo-300' : 'bg-slate-300 opacity-40'\"\n [style.animation-delay]=\"streaming ? '200ms' : '0ms'\"\n ></span>\n <span\n class=\"size-[5px] rounded-full transition-all duration-400\"\n [ngClass]=\"streaming ? 'animate-dot-pulse bg-indigo-300' : 'bg-slate-300 opacity-40'\"\n [style.animation-delay]=\"streaming ? '400ms' : '0ms'\"\n ></span>\n <span\n class=\"size-[5px] rounded-full transition-all duration-400\"\n [ngClass]=\"streaming ? 'animate-dot-pulse bg-indigo-300' : 'bg-slate-300 opacity-40'\"\n [style.animation-delay]=\"streaming ? '600ms' : '0ms'\"\n ></span>\n </div>\n\n <span\n class=\"text-[13px] font-medium transition-colors duration-300\"\n [ngClass]=\"streaming ? 'text-indigo-600' : 'text-slate-400'\"\n >\n {{ streaming ? ('translate_thinking' | translate) : ('translate_reasoned' | translate) }}\n </span>\n</div>\n", styles: [".animate-dot-pulse{animation:dot-pulse 1.4s ease-in-out infinite}@keyframes dot-pulse{0%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1.3);background-color:#6366f1}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
804
804
|
}
|
|
805
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
805
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageReasoningAnimatedComponent, decorators: [{
|
|
806
806
|
type: Component,
|
|
807
807
|
args: [{ selector: 'cortex-message-reasoning-animated', imports: [NgClass, TranslatePipe], host: { class: 'flex justify-center' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let p = reasoningPart();\n@let streaming = p.state === 'streaming';\n\n<div\n class=\"inline-flex items-center gap-2.5 py-2 pl-3 pr-4 rounded-lg border transition-colors duration-300\"\n [ngClass]=\"streaming ? 'border-indigo-200 bg-indigo-50' : 'border-slate-200 bg-slate-50'\"\n>\n <div class=\"flex items-center gap-1\">\n <span\n class=\"size-[5px] rounded-full transition-all duration-400\"\n [ngClass]=\"streaming ? 'animate-dot-pulse bg-indigo-300' : 'bg-slate-300 opacity-40'\"\n ></span>\n <span\n class=\"size-[5px] rounded-full transition-all duration-400\"\n [ngClass]=\"streaming ? 'animate-dot-pulse bg-indigo-300' : 'bg-slate-300 opacity-40'\"\n [style.animation-delay]=\"streaming ? '200ms' : '0ms'\"\n ></span>\n <span\n class=\"size-[5px] rounded-full transition-all duration-400\"\n [ngClass]=\"streaming ? 'animate-dot-pulse bg-indigo-300' : 'bg-slate-300 opacity-40'\"\n [style.animation-delay]=\"streaming ? '400ms' : '0ms'\"\n ></span>\n <span\n class=\"size-[5px] rounded-full transition-all duration-400\"\n [ngClass]=\"streaming ? 'animate-dot-pulse bg-indigo-300' : 'bg-slate-300 opacity-40'\"\n [style.animation-delay]=\"streaming ? '600ms' : '0ms'\"\n ></span>\n </div>\n\n <span\n class=\"text-[13px] font-medium transition-colors duration-300\"\n [ngClass]=\"streaming ? 'text-indigo-600' : 'text-slate-400'\"\n >\n {{ streaming ? ('translate_thinking' | translate) : ('translate_reasoned' | translate) }}\n </span>\n</div>\n", styles: [".animate-dot-pulse{animation:dot-pulse 1.4s ease-in-out infinite}@keyframes dot-pulse{0%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1.3);background-color:#6366f1}}\n"] }]
|
|
808
808
|
}], propDecorators: { reasoningPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "reasoningPart", required: true }] }] } });
|
|
809
809
|
|
|
810
810
|
class MessagePartComponent {
|
|
811
|
-
message = input.required(...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
812
|
-
part = input.required(...(ngDevMode ? [{ debugName: "part" }] : []));
|
|
813
|
-
debugMode = input(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : []));
|
|
814
|
-
animate = input(false, ...(ngDevMode ? [{ debugName: "animate" }] : []));
|
|
811
|
+
message = input.required(...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
812
|
+
part = input.required(...(ngDevMode ? [{ debugName: "part" }] : /* istanbul ignore next */ []));
|
|
813
|
+
debugMode = input(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : /* istanbul ignore next */ []));
|
|
814
|
+
animate = input(false, ...(ngDevMode ? [{ debugName: "animate" }] : /* istanbul ignore next */ []));
|
|
815
815
|
config = inject(CORTEX_CLIENT_CONFIG);
|
|
816
816
|
isStaticToolUIPart = isStaticToolUIPart;
|
|
817
817
|
customToolComponent = computed(() => {
|
|
@@ -820,11 +820,11 @@ class MessagePartComponent {
|
|
|
820
820
|
return null;
|
|
821
821
|
const toolName = p.type?.startsWith('tool-') ? p.type.slice('tool-'.length) : p.type;
|
|
822
822
|
return toolName ? (this.config.toolComponents?.[toolName] ?? null) : null;
|
|
823
|
-
}, ...(ngDevMode ? [{ debugName: "customToolComponent" }] : []));
|
|
824
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
825
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
823
|
+
}, ...(ngDevMode ? [{ debugName: "customToolComponent" }] : /* istanbul ignore next */ []));
|
|
824
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessagePartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
825
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: MessagePartComponent, isStandalone: true, selector: "cortex-message-part", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, part: { classPropertyName: "part", publicName: "part", isSignal: true, isRequired: true, transformFunction: null }, debugMode: { classPropertyName: "debugMode", publicName: "debugMode", isSignal: true, isRequired: false, transformFunction: null }, animate: { classPropertyName: "animate", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.animate-part-enter": "animate()" } }, ngImport: i0, template: "@let myPart = part();\n@switch (myPart.type) {\n @case ('text') {\n <cortex-message-text-part [textPart]=\"myPart\" [role]=\"message().role\" />\n }\n @case ('reasoning') {\n @if (debugMode()) {\n <cortex-message-reasoning-part [reasoningPart]=\"myPart\" />\n } @else {\n <cortex-message-reasoning-animated [reasoningPart]=\"myPart\" />\n }\n }\n @default {\n @if (isStaticToolUIPart(myPart)) {\n @if (!debugMode() || customToolComponent()) {\n <cortex-message-tool-call-animated [toolCallPart]=\"myPart\" [message]=\"message()\" />\n } @else {\n <cortex-message-tool-call-part [toolCallPart]=\"myPart\" />\n }\n } @else {\n <p class=\"text-center text-xs text-slate-400\">Unhandled type: {{ part().type }}</p>\n }\n }\n}\n", styles: [":host{display:block}:host:empty{display:none}:host.animate-part-enter{animation:partFadeInUp .2s cubic-bezier(.34,1.56,.64,1) both}@keyframes partFadeInUp{0%{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}\n/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: MessageTextPartComponent, selector: "cortex-message-text-part", inputs: ["role", "textPart"] }, { kind: "component", type: MessageReasoningPartComponent, selector: "cortex-message-reasoning-part", inputs: ["reasoningPart"] }, { kind: "component", type: MessageToolCallPartComponent, selector: "cortex-message-tool-call-part", inputs: ["toolCallPart"] }, { kind: "component", type: MessageToolCallAnimatedComponent, selector: "cortex-message-tool-call-animated", inputs: ["message", "toolCallPart"] }, { kind: "component", type: MessageReasoningAnimatedComponent, selector: "cortex-message-reasoning-animated", inputs: ["reasoningPart"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
826
826
|
}
|
|
827
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
827
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessagePartComponent, decorators: [{
|
|
828
828
|
type: Component,
|
|
829
829
|
args: [{ selector: 'cortex-message-part', imports: [
|
|
830
830
|
MessageTextPartComponent,
|
|
@@ -838,11 +838,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
838
838
|
}], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], part: [{ type: i0.Input, args: [{ isSignal: true, alias: "part", required: true }] }], debugMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "debugMode", required: false }] }], animate: [{ type: i0.Input, args: [{ isSignal: true, alias: "animate", required: false }] }] } });
|
|
839
839
|
|
|
840
840
|
class MessageComponent {
|
|
841
|
-
message = input.required(...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
842
|
-
debugMode = input(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : []));
|
|
843
|
-
animate = input(false, ...(ngDevMode ? [{ debugName: "animate" }] : []));
|
|
844
|
-
visibleParts = computed(() => this.parts().filter((x) => x.type !== 'step-start'), ...(ngDevMode ? [{ debugName: "visibleParts" }] : []));
|
|
845
|
-
parts = signal([], ...(ngDevMode ? [{ debugName: "parts" }] : []));
|
|
841
|
+
message = input.required(...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
842
|
+
debugMode = input(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : /* istanbul ignore next */ []));
|
|
843
|
+
animate = input(false, ...(ngDevMode ? [{ debugName: "animate" }] : /* istanbul ignore next */ []));
|
|
844
|
+
visibleParts = computed(() => this.parts().filter((x) => x.type !== 'step-start'), ...(ngDevMode ? [{ debugName: "visibleParts" }] : /* istanbul ignore next */ []));
|
|
845
|
+
parts = signal([], ...(ngDevMode ? [{ debugName: "parts" }] : /* istanbul ignore next */ []));
|
|
846
846
|
constructor() {
|
|
847
847
|
effect(() => {
|
|
848
848
|
const parts = this.message().parts;
|
|
@@ -873,21 +873,21 @@ class MessageComponent {
|
|
|
873
873
|
};
|
|
874
874
|
});
|
|
875
875
|
}
|
|
876
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
877
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
876
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
877
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: MessageComponent, isStandalone: true, selector: "cortex-message", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: true, transformFunction: null }, debugMode: { classPropertyName: "debugMode", publicName: "debugMode", isSignal: true, isRequired: false, transformFunction: null }, animate: { classPropertyName: "animate", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (visibleParts().length) {\n <div class=\"w-full flex flex-col gap-2\">\n @for (part of visibleParts(); track $index) {\n <cortex-message-part\n [part]=\"part\"\n [message]=\"message()\"\n [debugMode]=\"debugMode()\"\n [animate]=\"animate()\"\n />\n }\n </div>\n}\n", styles: [":host:empty{display:none}\n/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: MessagePartComponent, selector: "cortex-message-part", inputs: ["message", "part", "debugMode", "animate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
878
878
|
}
|
|
879
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
879
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageComponent, decorators: [{
|
|
880
880
|
type: Component,
|
|
881
881
|
args: [{ selector: 'cortex-message', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MessagePartComponent], template: "@if (visibleParts().length) {\n <div class=\"w-full flex flex-col gap-2\">\n @for (part of visibleParts(); track $index) {\n <cortex-message-part\n [part]=\"part\"\n [message]=\"message()\"\n [debugMode]=\"debugMode()\"\n [animate]=\"animate()\"\n />\n }\n </div>\n}\n", styles: [":host:empty{display:none}\n/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\n"] }]
|
|
882
882
|
}], ctorParameters: () => [], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], debugMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "debugMode", required: false }] }], animate: [{ type: i0.Input, args: [{ isSignal: true, alias: "animate", required: false }] }] } });
|
|
883
883
|
|
|
884
884
|
class MessageListComponent {
|
|
885
885
|
chatService;
|
|
886
|
-
debugMode = input(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : []));
|
|
887
|
-
messagesContainer = viewChild('messagesContainer', ...(ngDevMode ? [{ debugName: "messagesContainer" }] : []));
|
|
886
|
+
debugMode = input(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : /* istanbul ignore next */ []));
|
|
887
|
+
messagesContainer = viewChild('messagesContainer', ...(ngDevMode ? [{ debugName: "messagesContainer" }] : /* istanbul ignore next */ []));
|
|
888
888
|
shouldScrollToBottom = true;
|
|
889
889
|
isNearBottom = true;
|
|
890
|
-
animateNewParts = signal(false, ...(ngDevMode ? [{ debugName: "animateNewParts" }] : []));
|
|
890
|
+
animateNewParts = signal(false, ...(ngDevMode ? [{ debugName: "animateNewParts" }] : /* istanbul ignore next */ []));
|
|
891
891
|
constructor(chatService, destroyRef) {
|
|
892
892
|
this.chatService = chatService;
|
|
893
893
|
this.scrollToBottom();
|
|
@@ -930,10 +930,10 @@ class MessageListComponent {
|
|
|
930
930
|
el.scrollTop = el.scrollHeight;
|
|
931
931
|
}
|
|
932
932
|
}
|
|
933
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
934
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
933
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageListComponent, deps: [{ token: CortexChatService }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
934
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: MessageListComponent, isStandalone: true, selector: "cortex-message-list", inputs: { debugMode: { classPropertyName: "debugMode", publicName: "debugMode", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "messagesContainer", first: true, predicate: ["messagesContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"h-full overflow-y-auto w-full flex flex-col gap-2 p-4\"\n #messagesContainer\n (scroll)=\"onScroll()\"\n>\n @for (message of chatService.chat()?.messages; track message.id) {\n <cortex-message [message]=\"message\" [debugMode]=\"debugMode()\" [animate]=\"animateNewParts()\" />\n }\n</div>\n", dependencies: [{ kind: "component", type: MessageComponent, selector: "cortex-message", inputs: ["message", "debugMode", "animate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
935
935
|
}
|
|
936
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
936
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageListComponent, decorators: [{
|
|
937
937
|
type: Component,
|
|
938
938
|
args: [{ selector: 'cortex-message-list', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MessageComponent], template: "<div\n class=\"h-full overflow-y-auto w-full flex flex-col gap-2 p-4\"\n #messagesContainer\n (scroll)=\"onScroll()\"\n>\n @for (message of chatService.chat()?.messages; track message.id) {\n <cortex-message [message]=\"message\" [debugMode]=\"debugMode()\" [animate]=\"animateNewParts()\" />\n }\n</div>\n" }]
|
|
939
939
|
}], ctorParameters: () => [{ type: CortexChatService }, { type: i0.DestroyRef }], propDecorators: { debugMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "debugMode", required: false }] }], messagesContainer: [{ type: i0.ViewChild, args: ['messagesContainer', { isSignal: true }] }] } });
|
|
@@ -1137,18 +1137,18 @@ class CortexClientTranslateLoader {
|
|
|
1137
1137
|
|
|
1138
1138
|
class CortexClientConfigRef {
|
|
1139
1139
|
config;
|
|
1140
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1141
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1140
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexClientConfigRef, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1141
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexClientConfigRef });
|
|
1142
1142
|
}
|
|
1143
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1143
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexClientConfigRef, decorators: [{
|
|
1144
1144
|
type: Injectable
|
|
1145
1145
|
}] });
|
|
1146
1146
|
class CortexChatWidgetComponent {
|
|
1147
|
-
config = input.required(...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
1148
|
-
text = model('', ...(ngDevMode ? [{ debugName: "text" }] : []));
|
|
1149
|
-
debugMode = signal(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : []));
|
|
1150
|
-
screen = signal('threads', ...(ngDevMode ? [{ debugName: "screen" }] : []));
|
|
1151
|
-
theme = signal(undefined, ...(ngDevMode ? [{ debugName: "theme" }] : []));
|
|
1147
|
+
config = input.required(...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
|
|
1148
|
+
text = model('', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
1149
|
+
debugMode = signal(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : /* istanbul ignore next */ []));
|
|
1150
|
+
screen = signal('threads', ...(ngDevMode ? [{ debugName: "screen" }] : /* istanbul ignore next */ []));
|
|
1151
|
+
theme = signal(undefined, ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
|
|
1152
1152
|
chatService;
|
|
1153
1153
|
configRef = inject(CortexClientConfigRef);
|
|
1154
1154
|
injector = inject(Injector);
|
|
@@ -1157,10 +1157,7 @@ class CortexChatWidgetComponent {
|
|
|
1157
1157
|
this.theme.set(this.config().theme);
|
|
1158
1158
|
this.chatService = this.injector.get(CortexChatService);
|
|
1159
1159
|
const translateService = this.injector.get(TranslateService);
|
|
1160
|
-
translateService.use(this.config().locale
|
|
1161
|
-
effect(() => {
|
|
1162
|
-
translateService.use(this.config().locale());
|
|
1163
|
-
}, { injector: this.injector });
|
|
1160
|
+
translateService.use(this.config().locale);
|
|
1164
1161
|
}
|
|
1165
1162
|
toggleDebugMode() {
|
|
1166
1163
|
this.debugMode.update((v) => !v);
|
|
@@ -1192,8 +1189,8 @@ class CortexChatWidgetComponent {
|
|
|
1192
1189
|
this.chatService.deselectThread();
|
|
1193
1190
|
this.screen.set('chat');
|
|
1194
1191
|
}
|
|
1195
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1196
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1192
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexChatWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1193
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.3", type: CortexChatWidgetComponent, isStandalone: true, selector: "cortex-chat-widget", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { text: "textChange" }, host: { properties: { "style.--cortex-primary-color": "theme()?.primaryColor", "style.--cortex-bg-color": "theme()?.backgroundColor", "style.--cortex-surface-color": "theme()?.surfaceColor", "style.--cortex-text-color": "theme()?.textColor", "style.--cortex-border-radius": "theme()?.borderRadius" }, classAttribute: "block" }, providers: [
|
|
1197
1194
|
CortexClientConfigRef,
|
|
1198
1195
|
{
|
|
1199
1196
|
provide: CORTEX_CLIENT_CONFIG,
|
|
@@ -1207,7 +1204,7 @@ class CortexChatWidgetComponent {
|
|
|
1207
1204
|
}),
|
|
1208
1205
|
], ngImport: i0, template: "<div class=\"w-full h-full relative overflow-hidden bg-slate-5\">\n <!-- \u2550\u2550\u2550 SCREEN 1: THREADS \u2550\u2550\u2550 -->\n <div\n class=\"absolute inset-0 flex flex-col transition-transform duration-300 ease-out\"\n [ngClass]=\"\n screen() === 'threads' ? 'translate-x-0' : 'ltr:-translate-x-full rtl:translate-x-full'\n \"\n >\n <!-- Threads header -->\n <div class=\"shrink-0 px-5 pt-5 pb-4 flex items-center justify-between\">\n <div>\n <h2 class=\"text-[15px] font-semibold text-slate-800 tracking-tight\">\n {{ 'translate_threads' | translate }}\n </h2>\n <p class=\"text-[11px] text-slate-400 mt-0.5\">\n {{\n 'translate_n_conversations' | translate: { count: chatService.threads()?.length ?? 0 }\n }}\n </p>\n </div>\n <button\n (click)=\"newChat()\"\n class=\"inline-flex items-center gap-1.5 text-[12px] font-medium text-slate-100 bg-slate-800 px-3 py-1.5 rounded-md hover:bg-slate-700 active:bg-slate-900 transition-colors cursor-pointer\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M8 3v10M3 8h10\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ 'translate_new' | translate }}\n </button>\n </div>\n\n <!-- Threads list -->\n <div class=\"flex-1 overflow-y-auto px-3 pb-3\">\n <!-- Threads loading skeleton -->\n @if (chatService.threads() === undefined) {\n @for (i of [1, 2, 3, 4]; track i) {\n <div class=\"flex items-center gap-3 px-3 py-3 mb-0.5\">\n <div class=\"skeleton shrink-0 size-8\"></div>\n <div class=\"flex-1 flex flex-col gap-1.5\">\n <div class=\"skeleton h-3.5\" [style.width]=\"40 + i * 12 + '%'\"></div>\n </div>\n </div>\n }\n } @else {\n @for (thread of chatService.threads(); track thread.id) {\n <button\n (click)=\"selectThread(thread)\"\n class=\"group w-full text-start px-3 py-3 rounded-lg flex items-center gap-3 transition-colors cursor-pointer mb-0.5\"\n [ngClass]=\"{\n 'bg-slate-200 text-slate-100': thread.id === chatService.selectedThread()?.id,\n 'text-slate-600 hover:bg-slate-100 active:bg-slate-150':\n thread.id !== chatService.selectedThread()?.id,\n }\"\n >\n <!-- Thread icon -->\n <div\n class=\"shrink-0 size-8 rounded-md flex items-center justify-center text-[11px] font-semibold rtl:transform rtl:rotate-180\"\n [ngClass]=\"{\n 'bg-slate-700 text-slate-300': thread.id === chatService.selectedThread()?.id,\n 'bg-slate-200 text-slate-500': thread.id !== chatService.selectedThread()?.id,\n }\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M2.5 4.5h11M2.5 8h7M2.5 11.5h9\"\n stroke=\"currentColor\"\n stroke-width=\"1.3\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n\n <!-- Thread info -->\n <div class=\"min-w-0 flex-1\">\n <p\n class=\"text-[13px] font-medium truncate leading-tight\"\n [ngClass]=\"{\n 'text-slate-100': thread.id === chatService.selectedThread()?.id,\n 'text-slate-700': thread.id !== chatService.selectedThread()?.id,\n }\"\n >\n {{ thread.title ?? ('translate_untitled' | translate) }}\n </p>\n </div>\n\n <!-- Delete button -->\n <button\n (click)=\"$event.stopPropagation(); chatService.deleteThread(thread.id).subscribe()\"\n class=\"shrink-0 opacity-0 group-hover:opacity-100 transition-opacity size-7 rounded-md flex items-center justify-center cursor-pointer\"\n [ngClass]=\"{\n 'hover:bg-slate-600 text-slate-400': thread.id === chatService.selectedThread()?.id,\n 'hover:bg-slate-200 text-slate-400': thread.id !== chatService.selectedThread()?.id,\n }\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M4 4l8 8M12 4l-8 8\"\n stroke=\"currentColor\"\n stroke-width=\"1.3\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n\n <!-- Arrow -->\n <svg\n class=\"shrink-0 transition-colors rtl:transform rtl:rotate-180\"\n [ngClass]=\"{\n 'text-slate-500': thread.id === chatService.selectedThread()?.id,\n 'text-slate-300 group-hover:text-slate-400':\n thread.id !== chatService.selectedThread()?.id,\n }\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M6 4l4 4-4 4\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n\n @if (!chatService.threads()?.length) {\n <div class=\"flex flex-col items-center justify-center py-16 text-center\">\n <div class=\"size-10 rounded-lg bg-slate-200 flex items-center justify-center mb-3\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 16 16\" fill=\"none\" class=\"text-slate-400\">\n <path\n d=\"M2.5 4.5h11M2.5 8h7M2.5 11.5h9\"\n stroke=\"currentColor\"\n stroke-width=\"1.3\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n <p class=\"text-[13px] text-slate-400 font-medium\">No threads yet</p>\n <p class=\"text-[11px] text-slate-350 mt-1\">Start a new conversation</p>\n </div>\n }\n }\n </div>\n </div>\n\n <!-- \u2550\u2550\u2550 SCREEN 2: CHAT \u2550\u2550\u2550 -->\n <div\n class=\"absolute inset-0 flex flex-col transition-transform duration-300 ease-out\"\n [ngClass]=\"screen() === 'chat' ? 'translate-x-0' : 'ltr:translate-x-full rtl:-translate-x-full'\"\n >\n <!-- Chat header -->\n <div class=\"shrink-0 h-12 px-4 flex items-center gap-3 border-b border-slate-200 bg-white\">\n <!-- Back button -->\n <button\n (click)=\"goBack()\"\n class=\"shrink-0 size-8 rounded-md flex items-center justify-center text-slate-400 hover:text-slate-600 hover:bg-slate-100 transition-colors cursor-pointer\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"rtl:transform rtl:rotate-180\"\n >\n <path\n d=\"M10 3L5 8l5 5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n\n <!-- Title -->\n <div class=\"min-w-0 flex-1\">\n <p class=\"text-[13px] font-medium text-slate-700 truncate\">\n {{ chatService.selectedThread()?.title ?? ('translate_new_chat' | translate) }}\n </p>\n </div>\n\n <!-- Debug toggle -->\n <button\n (click)=\"toggleDebugMode()\"\n class=\"shrink-0 text-[11px] font-medium px-2.5 py-1 rounded-md transition-colors cursor-pointer\"\n [ngClass]=\"{\n 'bg-amber-50 text-amber-600 hover:bg-amber-100': debugMode(),\n 'bg-slate-100 text-slate-400 hover:bg-slate-200': !debugMode(),\n }\"\n >\n {{ debugMode() ? ('translate_debug' | translate) : ('translate_normal' | translate) }}\n </button>\n </div>\n\n <!-- Messages loading skeleton -->\n @if (chatService.isLoadingMessages() && !chatService.isAgentWorking()) {\n <div class=\"flex-1 overflow-hidden p-4 flex flex-col gap-2\">\n <!-- User message skeleton -->\n <div class=\"w-full flex flex-col items-start\">\n <div\n class=\"max-w-4/5 p-4 rounded-2xl rounded-bl-none border border-slate-200 bg-slate-50 flex flex-col gap-2\"\n >\n <div class=\"skeleton h-3 w-52\"></div>\n <div class=\"skeleton h-3 w-36\"></div>\n </div>\n </div>\n <!-- Assistant message skeleton -->\n <div class=\"w-full flex flex-col items-end\">\n <div\n class=\"max-w-4/5 p-4 rounded-2xl rounded-br-none border border-slate-200 bg-slate-100 flex flex-col gap-2\"\n >\n <div class=\"skeleton h-3 w-64\"></div>\n <div class=\"skeleton h-3 w-72\"></div>\n <div class=\"skeleton h-3 w-48\"></div>\n </div>\n </div>\n <!-- User message skeleton -->\n <div class=\"w-full flex flex-col items-start\">\n <div\n class=\"max-w-4/5 p-4 rounded-2xl rounded-bl-none border border-slate-200 bg-slate-50 flex flex-col gap-2\"\n >\n <div class=\"skeleton h-3 w-44\"></div>\n </div>\n </div>\n <!-- Assistant message skeleton -->\n <div class=\"w-full flex flex-col items-end\">\n <div\n class=\"max-w-4/5 p-4 rounded-2xl rounded-br-none border border-slate-200 bg-slate-100 flex flex-col gap-2\"\n >\n <div class=\"skeleton h-3 w-56\"></div>\n <div class=\"skeleton h-3 w-60\"></div>\n </div>\n </div>\n </div>\n } @else {\n <!-- Messages area -->\n <cortex-message-list class=\"flex-1 overflow-hidden\" [debugMode]=\"debugMode()\" />\n }\n\n <!-- Agent working indicator -->\n @if (chatService.isAgentWorking() && !chatService.hasPendingToolCalls()) {\n <div class=\"shrink-0 px-4 py-1.5 flex items-center gap-1.5\">\n <div class=\"flex items-center gap-[3px]\">\n <span class=\"cortex-working-dot block size-[5px] rounded-full bg-slate-400\"></span>\n <span class=\"cortex-working-dot block size-[5px] rounded-full bg-slate-400\"></span>\n <span class=\"cortex-working-dot block size-[5px] rounded-full bg-slate-400\"></span>\n </div>\n <span class=\"text-[11px] text-slate-400 font-medium\">{{\n 'translate_thinking' | translate\n }}</span>\n </div>\n }\n\n <!-- Chat input (hidden during pending tool calls) -->\n @if (!chatService.hasPendingToolCalls()) {\n <div class=\"shrink-0 p-3 bg-white border-t border-slate-200\">\n <div\n class=\"flex items-end gap-2 rounded-xl border border-slate-200 p-1.5 transition-colors\"\n [ngClass]=\"{\n 'bg-slate-100': chatService.isAgentWorking(),\n 'bg-slate-50 focus-within:border-slate-300 focus-within:bg-white':\n !chatService.isAgentWorking(),\n }\"\n >\n <textarea\n (keydown)=\"onKeydown($event)\"\n [(ngModel)]=\"text\"\n [placeholder]=\"\n chatService.isAgentWorking() ? '' : ('translate_type_a_message' | translate)\n \"\n [disabled]=\"chatService.isAgentWorking()\"\n rows=\"1\"\n class=\"flex-1 bg-transparent resize-none border-0 outline-none text-[13px] placeholder:text-slate-350 py-1.5 px-2 min-h-[28px] max-h-[120px] leading-snug disabled:cursor-not-allowed disabled:border-0\"\n [ngClass]=\"{\n 'text-slate-400': chatService.isAgentWorking(),\n 'text-slate-700': !chatService.isAgentWorking(),\n }\"\n ></textarea>\n @if (chatService.isAgentWorking()) {\n <!-- Stop button -->\n <button\n (click)=\"chatService.abort()\"\n class=\"stop-btn shrink-0 size-8 rounded-lg flex items-center justify-center cursor-pointer relative\"\n >\n <!-- Pulsing ring -->\n <span class=\"stop-btn-ring absolute inset-0 rounded-lg\"></span>\n <!-- Stop icon (rounded square) -->\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" class=\"relative z-10\">\n <rect x=\"1\" y=\"1\" width=\"10\" height=\"10\" rx=\"2.5\" fill=\"currentColor\" />\n </svg>\n </button>\n } @else {\n <!-- Send button -->\n <button\n (click)=\"send()\"\n class=\"shrink-0 size-8 rounded-lg flex items-center justify-center transition-colors\"\n [ngClass]=\"{\n 'bg-slate-200 text-slate-400': !text().trim(),\n 'bg-slate-800 text-white hover:bg-slate-700 cursor-pointer': text().trim(),\n }\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"rtl:transform rtl:rotate-180\"\n >\n <path\n d=\"M3 8h10M9 4l4 4-4 4\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n </div>\n }\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";@keyframes skeleton-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.skeleton{background:linear-gradient(90deg,#e2e8f0,#f1f5f9,#e2e8f0 80%);background-size:200% 100%;animation:skeleton-shimmer 1.8s ease-in-out infinite;border-radius:6px}@keyframes cortex-pulse{0%,to{opacity:.4}50%{opacity:1}}@keyframes cortex-dot-bounce{0%,80%,to{transform:translateY(0)}40%{transform:translateY(-3px)}}.cortex-working-dot{animation:cortex-pulse 1.6s ease-in-out infinite,cortex-dot-bounce 1.2s ease-in-out infinite}.cortex-working-dot:nth-child(2){animation-delay:.15s}.cortex-working-dot:nth-child(3){animation-delay:.3s}@keyframes stop-pulse-ring{0%{opacity:.45;transform:scale(1)}50%{opacity:.15;transform:scale(1.12)}to{opacity:.45;transform:scale(1)}}@keyframes stop-fade-in{0%{opacity:0;transform:scale(.7)}to{opacity:1;transform:scale(1)}}.stop-btn{background:#e11d48;color:#fff;animation:stop-fade-in .2s ease-out both;transition:background .15s ease}.stop-btn:hover{background:#be123c}.stop-btn:active{transform:scale(.92)}.stop-btn-ring{background:#e11d48;animation:stop-pulse-ring 2s ease-in-out infinite;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: MessageListComponent, selector: "cortex-message-list", inputs: ["debugMode"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1209
1206
|
}
|
|
1210
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1207
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexChatWidgetComponent, decorators: [{
|
|
1211
1208
|
type: Component,
|
|
1212
1209
|
args: [{ selector: 'cortex-chat-widget', imports: [NgClass, MessageListComponent, FormsModule, TranslatePipe], providers: [
|
|
1213
1210
|
CortexClientConfigRef,
|
|
@@ -1265,10 +1262,10 @@ class PrettyJsonPipe {
|
|
|
1265
1262
|
}
|
|
1266
1263
|
return value;
|
|
1267
1264
|
}
|
|
1268
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1269
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.
|
|
1265
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: PrettyJsonPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1266
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.3", ngImport: i0, type: PrettyJsonPipe, isStandalone: true, name: "prettyJson" });
|
|
1270
1267
|
}
|
|
1271
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1268
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: PrettyJsonPipe, decorators: [{
|
|
1272
1269
|
type: Pipe,
|
|
1273
1270
|
args: [{ name: 'prettyJson', standalone: true }]
|
|
1274
1271
|
}] });
|