@m6d/cortex-client 1.1.1 → 1.1.3

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, NgZone, Injectable, signal, DestroyRef, Pipe, input, ChangeDetectionStrategy, Component, computed, forwardRef, effect, viewChild, model, Injector } from '@angular/core';
2
+ import { InjectionToken, inject, NgZone, Injectable, signal, DestroyRef, Pipe, input, ViewEncapsulation, ChangeDetectionStrategy, Component, computed, forwardRef, effect, viewChild, model, Injector } from '@angular/core';
3
3
  import { Chat } from '@ai-sdk/angular';
4
4
  import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls, isStaticToolUIPart, generateId } from 'ai';
5
5
  import { Observable, retry, timer, share, Subject, of, defer, finalize, tap, switchMap, map, concatMap } from 'rxjs';
@@ -7,11 +7,11 @@ import { fromPromise } from 'rxjs/internal/observable/innerFrom';
7
7
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
8
8
  import * as i1$1 from '@angular/forms';
9
9
  import { FormControl, Validators, FormBuilder, ReactiveFormsModule, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
10
- import { NgClass, NgTemplateOutlet } from '@angular/common';
11
10
  import { TranslatePipe, TranslateService, provideTranslateService, provideTranslateLoader } from '@ngx-translate/core';
12
11
  import { marked } from 'marked';
13
12
  import DOMPurify from 'dompurify';
14
13
  import * as i1 from '@angular/platform-browser';
14
+ import { NgClass, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';
15
15
  import hljs from 'highlight.js/lib/core';
16
16
  import javascript from 'highlight.js/lib/languages/javascript';
17
17
  import json from 'highlight.js/lib/languages/json';
@@ -325,21 +325,21 @@ class MessageTextPartComponent {
325
325
  role = input.required(...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
326
326
  textPart = input.required(...(ngDevMode ? [{ debugName: "textPart" }] : /* istanbul ignore next */ []));
327
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 });
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=\"cortex-text-part\"\n [class.cortex-text-part--assistant]=\"role() === 'assistant'\"\n [class.cortex-text-part--user]=\"role() === 'user'\"\n>\n <div\n class=\"cortex-text-bubble\"\n [class.cortex-text-bubble--assistant]=\"role() === 'assistant'\"\n [class.cortex-text-bubble--user]=\"role() === 'user'\"\n [innerHTML]=\"textPart().text | marked\"\n ></div>\n</div>\n", styles: [".cortex-text-part{width:100%;display:flex;flex-direction:column}.cortex-text-part--assistant{align-items:flex-end}.cortex-text-part--user{align-items:flex-start}[dir=rtl] .cortex-text-part--assistant{align-items:flex-end}[dir=rtl] .cortex-text-part--user{align-items:flex-start}.cortex-text-bubble{max-width:80%;font-size:.8125rem;line-height:1.625;padding:1rem;border-radius:1rem;border:1px solid #e2e8f0;color:#334155}.cortex-text-bubble--assistant{background:#f1f5f9;border-bottom-right-radius:0}[dir=rtl] .cortex-text-bubble--assistant{border-bottom-right-radius:1rem;border-bottom-left-radius:0}.cortex-text-bubble--user{background:#f8fafc;border-bottom-left-radius:0}[dir=rtl] .cortex-text-bubble--user{border-bottom-left-radius:1rem;border-bottom-right-radius:0}.cortex-text-bubble h1,.cortex-text-bubble h2,.cortex-text-bubble h3,.cortex-text-bubble h4,.cortex-text-bubble h5,.cortex-text-bubble h6{margin-top:1.25em;margin-bottom:.5em;font-weight:600;line-height:1.3;color:#1e293b}.cortex-text-bubble h1:first-child,.cortex-text-bubble h2:first-child,.cortex-text-bubble h3:first-child,.cortex-text-bubble h4:first-child,.cortex-text-bubble h5:first-child,.cortex-text-bubble h6:first-child{margin-top:0}.cortex-text-bubble h1{font-size:1.25em}.cortex-text-bubble h2{font-size:1.125em}.cortex-text-bubble h3{font-size:1em}.cortex-text-bubble p{margin-top:.75em;margin-bottom:.75em}.cortex-text-bubble p:first-child{margin-top:0}.cortex-text-bubble p:last-child{margin-bottom:0}.cortex-text-bubble ul,.cortex-text-bubble ol{margin-top:.75em;margin-bottom:.75em;padding-inline-start:1.5em}.cortex-text-bubble ul{list-style-type:disc}.cortex-text-bubble ol{list-style-type:decimal}.cortex-text-bubble li{margin-top:.25em;margin-bottom:.25em}.cortex-text-bubble code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.875em;background:#e2e8f0;padding:.125em .375em;border-radius:.25rem}.cortex-text-bubble pre{margin-top:.75em;margin-bottom:.75em;padding:.75em 1em;background:#1e293b;border-radius:.5rem;overflow-x:auto;font-size:.8125em;line-height:1.6}.cortex-text-bubble pre code{background:transparent;padding:0;color:#e2e8f0}.cortex-text-bubble blockquote{margin-top:.75em;margin-bottom:.75em;padding-inline-start:1em;border-inline-start:3px solid #cbd5e1;color:#64748b;font-style:italic}.cortex-text-bubble a{color:#2563eb;text-decoration:underline}.cortex-text-bubble a:hover{color:#1d4ed8}.cortex-text-bubble table{width:100%;border-collapse:collapse;margin-top:.75em;margin-bottom:.75em;font-size:.875em}.cortex-text-bubble th,.cortex-text-bubble td{border:1px solid #e2e8f0;padding:.375em .75em;text-align:start}.cortex-text-bubble th{background:#f8fafc;font-weight:600}.cortex-text-bubble hr{margin-top:1.5em;margin-bottom:1.5em;border:none;border-top:1px solid #e2e8f0}.cortex-text-bubble img{max-width:100%;height:auto;border-radius:.375rem}\n"], dependencies: [{ kind: "pipe", type: MarkedPipe, name: "marked" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
329
329
  }
330
330
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageTextPartComponent, decorators: [{
331
331
  type: Component,
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" }]
332
+ args: [{ selector: 'cortex-message-text-part', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [MarkedPipe], template: "<div\n class=\"cortex-text-part\"\n [class.cortex-text-part--assistant]=\"role() === 'assistant'\"\n [class.cortex-text-part--user]=\"role() === 'user'\"\n>\n <div\n class=\"cortex-text-bubble\"\n [class.cortex-text-bubble--assistant]=\"role() === 'assistant'\"\n [class.cortex-text-bubble--user]=\"role() === 'user'\"\n [innerHTML]=\"textPart().text | marked\"\n ></div>\n</div>\n", styles: [".cortex-text-part{width:100%;display:flex;flex-direction:column}.cortex-text-part--assistant{align-items:flex-end}.cortex-text-part--user{align-items:flex-start}[dir=rtl] .cortex-text-part--assistant{align-items:flex-end}[dir=rtl] .cortex-text-part--user{align-items:flex-start}.cortex-text-bubble{max-width:80%;font-size:.8125rem;line-height:1.625;padding:1rem;border-radius:1rem;border:1px solid #e2e8f0;color:#334155}.cortex-text-bubble--assistant{background:#f1f5f9;border-bottom-right-radius:0}[dir=rtl] .cortex-text-bubble--assistant{border-bottom-right-radius:1rem;border-bottom-left-radius:0}.cortex-text-bubble--user{background:#f8fafc;border-bottom-left-radius:0}[dir=rtl] .cortex-text-bubble--user{border-bottom-left-radius:1rem;border-bottom-right-radius:0}.cortex-text-bubble h1,.cortex-text-bubble h2,.cortex-text-bubble h3,.cortex-text-bubble h4,.cortex-text-bubble h5,.cortex-text-bubble h6{margin-top:1.25em;margin-bottom:.5em;font-weight:600;line-height:1.3;color:#1e293b}.cortex-text-bubble h1:first-child,.cortex-text-bubble h2:first-child,.cortex-text-bubble h3:first-child,.cortex-text-bubble h4:first-child,.cortex-text-bubble h5:first-child,.cortex-text-bubble h6:first-child{margin-top:0}.cortex-text-bubble h1{font-size:1.25em}.cortex-text-bubble h2{font-size:1.125em}.cortex-text-bubble h3{font-size:1em}.cortex-text-bubble p{margin-top:.75em;margin-bottom:.75em}.cortex-text-bubble p:first-child{margin-top:0}.cortex-text-bubble p:last-child{margin-bottom:0}.cortex-text-bubble ul,.cortex-text-bubble ol{margin-top:.75em;margin-bottom:.75em;padding-inline-start:1.5em}.cortex-text-bubble ul{list-style-type:disc}.cortex-text-bubble ol{list-style-type:decimal}.cortex-text-bubble li{margin-top:.25em;margin-bottom:.25em}.cortex-text-bubble code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.875em;background:#e2e8f0;padding:.125em .375em;border-radius:.25rem}.cortex-text-bubble pre{margin-top:.75em;margin-bottom:.75em;padding:.75em 1em;background:#1e293b;border-radius:.5rem;overflow-x:auto;font-size:.8125em;line-height:1.6}.cortex-text-bubble pre code{background:transparent;padding:0;color:#e2e8f0}.cortex-text-bubble blockquote{margin-top:.75em;margin-bottom:.75em;padding-inline-start:1em;border-inline-start:3px solid #cbd5e1;color:#64748b;font-style:italic}.cortex-text-bubble a{color:#2563eb;text-decoration:underline}.cortex-text-bubble a:hover{color:#1d4ed8}.cortex-text-bubble table{width:100%;border-collapse:collapse;margin-top:.75em;margin-bottom:.75em;font-size:.875em}.cortex-text-bubble th,.cortex-text-bubble td{border:1px solid #e2e8f0;padding:.375em .75em;text-align:start}.cortex-text-bubble th{background:#f8fafc;font-weight:600}.cortex-text-bubble hr{margin-top:1.5em;margin-bottom:1.5em;border:none;border-top:1px solid #e2e8f0}.cortex-text-bubble img{max-width:100%;height:auto;border-radius:.375rem}\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
336
  reasoningPart = input.required(...(ngDevMode ? [{ debugName: "reasoningPart" }] : /* istanbul ignore next */ []));
337
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 });
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=\"cortex-reasoning-details\">\n <summary class=\"cortex-reasoning-details__summary\">\n <div class=\"cortex-reasoning-details__header\">\n <span class=\"cortex-reasoning-details__icon\">\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=\"cortex-reasoning-details__title-group\">\n <div class=\"cortex-reasoning-details__title-row\">\n <div class=\"cortex-reasoning-details__title\">Reasoning</div>\n @if (p.state) {\n <span\n class=\"cortex-reasoning-details__badge\"\n [ngClass]=\"{\n 'cortex-reasoning-details__badge--streaming': p.state === 'streaming',\n 'cortex-reasoning-details__badge--done': p.state === 'done',\n }\"\n >\n {{ p.state === 'streaming' ? 'Streaming' : 'Done' }}\n </span>\n }\n </div>\n </div>\n </div>\n\n <span class=\"cortex-reasoning-details__chevron\" aria-hidden=\"true\">\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=\"cortex-reasoning-details__body\">\n <div class=\"cortex-reasoning-details__content\">\n <pre class=\"cortex-reasoning-details__pre\">{{\n p.text.trim() ? p.text : 'No reasoning provided.'\n }}</pre>\n </div>\n </div>\n</details>\n", styles: [".cortex-reasoning-details{width:100%;border-radius:.5rem;border:1px solid #e2e8f0;background:#f8fafc;overflow:hidden}.cortex-reasoning-details__summary{list-style:none;cursor:pointer;-webkit-user-select:none;user-select:none;padding:.75rem 1rem;display:flex;align-items:center;gap:.75rem}.cortex-reasoning-details__summary::-webkit-details-marker{display:none}.cortex-reasoning-details__header{display:flex;align-items:center;gap:.5rem;min-width:0;flex:1}.cortex-reasoning-details__icon{display:inline-flex;height:1.5rem;width:1.5rem;align-items:center;justify-content:center;border-radius:.25rem;background:#e0e7ff;color:#4f46e5}.cortex-reasoning-details__title-group{min-width:0}.cortex-reasoning-details__title-row{display:flex;align-items:center;gap:.5rem}.cortex-reasoning-details__title{font-weight:500;color:#334155;font-size:.875rem}.cortex-reasoning-details__badge{display:inline-flex;align-items:center;border-radius:.25rem;padding:.125rem .375rem;font-size:.6875rem;font-weight:500}.cortex-reasoning-details__badge--streaming{background:#fef3c7;color:#b45309}.cortex-reasoning-details__badge--done{background:#d1fae5;color:#047857}.cortex-reasoning-details__chevron{margin-inline-start:auto;display:inline-flex;height:1.5rem;width:1.5rem;align-items:center;justify-content:center;border-radius:.25rem;color:#94a3b8;transition:transform .2s}details[open]>summary>.cortex-reasoning-details__chevron{transform:rotate(180deg)}.cortex-reasoning-details__body{padding:0 1rem 1rem}.cortex-reasoning-details__content{margin-top:.25rem;border-radius:.25rem;background:#fff;border:1px solid #e2e8f0;padding:.75rem}.cortex-reasoning-details__pre{margin:0;white-space:pre-wrap;overflow-wrap:break-word;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.75rem;line-height:1.625;color:#334155}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
339
339
  }
340
340
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageReasoningPartComponent, decorators: [{
341
341
  type: Component,
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" }]
342
+ args: [{ selector: 'cortex-message-reasoning-part', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgClass], template: "@let p = reasoningPart();\n<details class=\"cortex-reasoning-details\">\n <summary class=\"cortex-reasoning-details__summary\">\n <div class=\"cortex-reasoning-details__header\">\n <span class=\"cortex-reasoning-details__icon\">\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=\"cortex-reasoning-details__title-group\">\n <div class=\"cortex-reasoning-details__title-row\">\n <div class=\"cortex-reasoning-details__title\">Reasoning</div>\n @if (p.state) {\n <span\n class=\"cortex-reasoning-details__badge\"\n [ngClass]=\"{\n 'cortex-reasoning-details__badge--streaming': p.state === 'streaming',\n 'cortex-reasoning-details__badge--done': p.state === 'done',\n }\"\n >\n {{ p.state === 'streaming' ? 'Streaming' : 'Done' }}\n </span>\n }\n </div>\n </div>\n </div>\n\n <span class=\"cortex-reasoning-details__chevron\" aria-hidden=\"true\">\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=\"cortex-reasoning-details__body\">\n <div class=\"cortex-reasoning-details__content\">\n <pre class=\"cortex-reasoning-details__pre\">{{\n p.text.trim() ? p.text : 'No reasoning provided.'\n }}</pre>\n </div>\n </div>\n</details>\n", styles: [".cortex-reasoning-details{width:100%;border-radius:.5rem;border:1px solid #e2e8f0;background:#f8fafc;overflow:hidden}.cortex-reasoning-details__summary{list-style:none;cursor:pointer;-webkit-user-select:none;user-select:none;padding:.75rem 1rem;display:flex;align-items:center;gap:.75rem}.cortex-reasoning-details__summary::-webkit-details-marker{display:none}.cortex-reasoning-details__header{display:flex;align-items:center;gap:.5rem;min-width:0;flex:1}.cortex-reasoning-details__icon{display:inline-flex;height:1.5rem;width:1.5rem;align-items:center;justify-content:center;border-radius:.25rem;background:#e0e7ff;color:#4f46e5}.cortex-reasoning-details__title-group{min-width:0}.cortex-reasoning-details__title-row{display:flex;align-items:center;gap:.5rem}.cortex-reasoning-details__title{font-weight:500;color:#334155;font-size:.875rem}.cortex-reasoning-details__badge{display:inline-flex;align-items:center;border-radius:.25rem;padding:.125rem .375rem;font-size:.6875rem;font-weight:500}.cortex-reasoning-details__badge--streaming{background:#fef3c7;color:#b45309}.cortex-reasoning-details__badge--done{background:#d1fae5;color:#047857}.cortex-reasoning-details__chevron{margin-inline-start:auto;display:inline-flex;height:1.5rem;width:1.5rem;align-items:center;justify-content:center;border-radius:.25rem;color:#94a3b8;transition:transform .2s}details[open]>summary>.cortex-reasoning-details__chevron{transform:rotate(180deg)}.cortex-reasoning-details__body{padding:0 1rem 1rem}.cortex-reasoning-details__content{margin-top:.25rem;border-radius:.25rem;background:#fff;border:1px solid #e2e8f0;padding:.75rem}.cortex-reasoning-details__pre{margin:0;white-space:pre-wrap;overflow-wrap:break-word;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.75rem;line-height:1.625;color:#334155}\n"] }]
343
343
  }], propDecorators: { reasoningPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "reasoningPart", required: true }] }] } });
344
344
 
345
345
  hljs.registerLanguage('javascript', javascript);
@@ -463,11 +463,11 @@ class JsonTreeComponent {
463
463
  return value;
464
464
  }
465
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)\">&#9662;</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)\">&#9662;</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 });
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: "cortex-json-tree" }, 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)\">&#9662;</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)\">&#9662;</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: [".cortex-json-tree{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.75rem;line-height:1.25rem;-webkit-user-select:text;user-select:text;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, encapsulation: i0.ViewEncapsulation.None });
467
467
  }
468
468
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: JsonTreeComponent, decorators: [{
469
469
  type: Component,
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)\">&#9662;</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)\">&#9662;</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"] }]
470
+ args: [{ selector: 'cortex-json-tree', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgTemplateOutlet], host: { class: 'cortex-json-tree' }, 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)\">&#9662;</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)\">&#9662;</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: [".cortex-json-tree{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.75rem;line-height:1.25rem;-webkit-user-select:text;user-select:text;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 }] }] } });
472
472
 
473
473
  class MessageToolCallPartComponent {
@@ -516,11 +516,11 @@ class MessageToolCallPartComponent {
516
516
  return type.startsWith('tool-') ? type.slice('tool-'.length) : type;
517
517
  }
518
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 });
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=\"cortex-tool-details\">\n <summary class=\"cortex-tool-details__summary\">\n <div class=\"cortex-tool-details__header\">\n <div class=\"cortex-tool-details__icon-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 20 20\" class=\"cortex-tool-details__icon-svg\" 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=\"cortex-tool-details__info\">\n <div class=\"cortex-tool-details__title-row\">\n <div class=\"cortex-tool-details__name-row\">\n <div class=\"cortex-tool-details__name\" [attr.title]=\"toolCallPart().title || null\">\n {{ toolCallPart().title ?? 'Tool call' }}\n </div>\n @if (toolName()) {\n <span\n class=\"cortex-tool-details__tool-badge\"\n [attr.title]=\"toolCallPart().type || null\"\n >{{ toolName() }}</span\n >\n }\n </div>\n <div class=\"cortex-tool-details__id-line\">\n <span class=\"cortex-tool-details__id-label\">ID</span>\n <span class=\"cortex-tool-details__id-value\"> {{ toolCallPart().toolCallId }}</span>\n @if (toolCallPart().providerExecuted) {\n <span class=\"cortex-tool-details__provider-badge\">\n <span class=\"cortex-tool-details__provider-dot\"></span>\n provider\n </span>\n }\n </div>\n </div>\n\n <div class=\"cortex-tool-details__actions\">\n <span\n class=\"cortex-tool-details__state-badge\"\n [ngClass]=\"{\n 'cortex-tool-details__state-badge--success':\n toolCallPart().state === 'output-available',\n 'cortex-tool-details__state-badge--error': toolCallPart().state === 'output-error',\n 'cortex-tool-details__state-badge--denied': toolCallPart().state === 'output-denied',\n 'cortex-tool-details__state-badge--approval':\n toolCallPart().state === 'approval-requested' ||\n toolCallPart().state === 'approval-responded',\n 'cortex-tool-details__state-badge--pending':\n toolCallPart().state === 'input-streaming' ||\n toolCallPart().state === 'input-available',\n }\"\n >\n @switch (toolCallPart().state) {\n @case ('input-streaming') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--amber cortex-tool-details__status-dot--pulse\"\n ></span>\n Calling\n }\n @case ('input-available') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--amber\"\n ></span>\n Input ready\n }\n @case ('approval-requested') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--violet cortex-tool-details__status-dot--pulse\"\n ></span>\n Needs approval\n }\n @case ('approval-responded') {\n @if (toolCallPart().approval?.approved) {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--emerald\"\n ></span>\n Approved\n } @else {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--slate\"\n ></span>\n Responded\n }\n }\n @case ('output-available') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--emerald\"\n ></span>\n {{ 'translate_completed' | translate }}\n }\n @case ('output-error') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--red\"\n ></span>\n Error\n }\n @case ('output-denied') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--slate\"\n ></span>\n Denied\n }\n }\n </span>\n\n <span class=\"cortex-tool-details__chevron\" aria-hidden=\"true\">\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 </summary>\n\n <div class=\"cortex-tool-details__body\">\n <div class=\"cortex-tool-details__panels\">\n @for (snippet of codeSnippets(); track snippet.key) {\n <div class=\"cortex-tool-details__panel\">\n <div class=\"cortex-tool-details__panel-header\">\n <div class=\"cortex-tool-details__panel-label\">{{ snippet.key }}</div>\n <div class=\"cortex-tool-details__panel-lang\">{{ snippet.lang }}</div>\n </div>\n <pre\n dir=\"ltr\"\n class=\"cortex-tool-details__code-pre\"\n ><code class=\"hljs\" [innerHTML]=\"snippet.value | highlight : snippet.lang\"></code></pre>\n </div>\n }\n\n @if (remainingInput(); as remaining) {\n <div class=\"cortex-tool-details__panel\">\n <div class=\"cortex-tool-details__panel-header\">\n <div class=\"cortex-tool-details__panel-label\">Input</div>\n <div class=\"cortex-tool-details__panel-lang\">json</div>\n </div>\n <div dir=\"ltr\" class=\"cortex-tool-details__tree-container\">\n <cortex-json-tree [data]=\"remaining\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-available') {\n <div class=\"cortex-tool-details__panel cortex-tool-details__panel--success\">\n <div class=\"cortex-tool-details__panel-header cortex-tool-details__panel-header--success\">\n <div class=\"cortex-tool-details__panel-label cortex-tool-details__panel-label--success\">\n Output\n </div>\n <div class=\"cortex-tool-details__panel-lang cortex-tool-details__panel-lang--success\">\n json\n </div>\n </div>\n <div dir=\"ltr\" class=\"cortex-tool-details__tree-container\">\n <cortex-json-tree [data]=\"toolCallPart().output\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-error') {\n <div class=\"cortex-tool-details__panel cortex-tool-details__panel--error\">\n <div class=\"cortex-tool-details__panel-header cortex-tool-details__panel-header--error\">\n <div class=\"cortex-tool-details__panel-label cortex-tool-details__panel-label--error\">\n Error\n </div>\n <div class=\"cortex-tool-details__panel-lang cortex-tool-details__panel-lang--error\">\n text\n </div>\n </div>\n <pre dir=\"ltr\" class=\"cortex-tool-details__error-pre\">{{ toolCallPart().errorText }}</pre>\n </div>\n }\n\n @if (toolCallPart().state === 'output-denied') {\n <div class=\"cortex-tool-details__panel\">\n <div class=\"cortex-tool-details__panel-header\">\n <div class=\"cortex-tool-details__panel-label\">Denied</div>\n <div class=\"cortex-tool-details__panel-lang\">approval</div>\n </div>\n <div class=\"cortex-tool-details__denied-body\">\n Tool execution was denied.\n @if (toolCallPart().approval?.reason) {\n <div class=\"cortex-tool-details__reason-box\">\n <div class=\"cortex-tool-details__reason-label\">Reason</div>\n <div class=\"cortex-tool-details__reason-text\">\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-requested') {\n <div class=\"cortex-tool-details__panel cortex-tool-details__panel--approval\">\n <div\n class=\"cortex-tool-details__panel-header cortex-tool-details__panel-header--approval\"\n >\n <div\n class=\"cortex-tool-details__panel-label cortex-tool-details__panel-label--approval\"\n >\n Approval requested\n </div>\n <div class=\"cortex-tool-details__panel-lang cortex-tool-details__panel-lang--approval\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"cortex-tool-details__approval-body\">\n Waiting for approval to execute this tool.\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-responded') {\n <div class=\"cortex-tool-details__panel cortex-tool-details__panel--approval\">\n <div\n class=\"cortex-tool-details__panel-header cortex-tool-details__panel-header--approval\"\n >\n <div\n class=\"cortex-tool-details__panel-label cortex-tool-details__panel-label--approval\"\n >\n Approval response\n </div>\n <div class=\"cortex-tool-details__panel-lang cortex-tool-details__panel-lang--approval\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"cortex-tool-details__approval-body\">\n @if (toolCallPart().approval?.approved) {\n Approved.\n } @else {\n Response received.\n }\n @if (toolCallPart().approval?.reason) {\n <div\n class=\"cortex-tool-details__reason-box cortex-tool-details__reason-box--approval\"\n >\n <div\n class=\"cortex-tool-details__reason-label cortex-tool-details__reason-label--approval\"\n >\n Reason\n </div>\n <div\n class=\"cortex-tool-details__reason-text cortex-tool-details__reason-text--approval\"\n >\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n</details>\n", styles: [".cortex-tool-details{width:100%;border-radius:.5rem;border:1px solid #e2e8f0;background:#f8fafc;overflow:hidden}.cortex-tool-details__summary{list-style:none;cursor:pointer;-webkit-user-select:none;user-select:none;padding:.75rem 1rem}.cortex-tool-details__summary::-webkit-details-marker{display:none}details[open]>.cortex-tool-details__summary{border-bottom:1px solid #e2e8f0}.cortex-tool-details__header{display:flex;align-items:flex-start;gap:.75rem}.cortex-tool-details__icon-box{flex-shrink:0;margin-top:.125rem;width:1.75rem;height:1.75rem;border-radius:.25rem;background:#1e293b;color:#fff;display:flex;align-items:center;justify-content:center}.cortex-tool-details__icon-svg{width:1rem;height:1rem}.cortex-tool-details__info{min-width:0;flex:1;display:flex;align-items:center;gap:.5rem}.cortex-tool-details__title-row{min-width:0;flex:1}.cortex-tool-details__name-row{display:flex;align-items:center;gap:.5rem;min-width:0}.cortex-tool-details__name{font-weight:500;color:#1e293b;font-size:.875rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cortex-tool-details__tool-badge{display:none;align-items:center;border-radius:.25rem;background:#e2e8f0;padding:.125rem .375rem;font-size:.6875rem;font-weight:500;color:#475569;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}@media(min-width:640px){.cortex-tool-details__tool-badge{display:inline-flex}}.cortex-tool-details__id-line{margin-top:.125rem;font-size:.6875rem;color:#64748b;word-break:break-all}.cortex-tool-details__id-label{font-weight:500;color:#475569}.cortex-tool-details__id-value{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.cortex-tool-details__provider-badge{margin-inline-start:.5rem;display:inline-flex;align-items:center;gap:.25rem;color:#047857}.cortex-tool-details__provider-dot{width:.375rem;height:.375rem;border-radius:9999px;background:#10b981}.cortex-tool-details__actions{display:flex;align-items:center;gap:.5rem}.cortex-tool-details__state-badge{display:inline-flex;align-items:center;gap:.375rem;border-radius:.25rem;padding:.25rem .5rem;font-size:.6875rem;font-weight:500;border:1px solid}.cortex-tool-details__state-badge--success{background:#ecfdf5;color:#047857;border-color:#a7f3d0}.cortex-tool-details__state-badge--error{background:#fef2f2;color:#b91c1c;border-color:#fecaca}.cortex-tool-details__state-badge--denied{background:#f1f5f9;color:#475569;border-color:#e2e8f0}.cortex-tool-details__state-badge--approval{background:#f5f3ff;color:#6d28d9;border-color:#ddd6fe}.cortex-tool-details__state-badge--pending{background:#fffbeb;color:#b45309;border-color:#fde68a}.cortex-tool-details__status-dot{width:.375rem;height:.375rem;border-radius:9999px}.cortex-tool-details__status-dot--amber{background:#f59e0b}.cortex-tool-details__status-dot--violet{background:#8b5cf6}.cortex-tool-details__status-dot--emerald{background:#10b981}.cortex-tool-details__status-dot--red{background:#ef4444}.cortex-tool-details__status-dot--slate{background:#64748b}.cortex-tool-details__status-dot--pulse{animation:cortex-tool-status-pulse 2s ease-in-out infinite}@keyframes cortex-tool-status-pulse{0%,to{opacity:1}50%{opacity:.4}}.cortex-tool-details__chevron{display:inline-flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center;border-radius:.25rem;color:#94a3b8;transition:transform .2s}details[open]>summary .cortex-tool-details__chevron{transform:rotate(180deg)}.cortex-tool-details__body{background:#fff;padding:.75rem 1rem 1rem}.cortex-tool-details__panels{display:grid;gap:.75rem}.cortex-tool-details__panel{border-radius:.5rem;border:1px solid #e2e8f0;overflow:hidden}.cortex-tool-details__panel--success{border-color:#a7f3d0}.cortex-tool-details__panel--error{border-color:#fecaca}.cortex-tool-details__panel--approval{border-color:#ddd6fe}.cortex-tool-details__panel-header{padding:.5rem .75rem;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #e2e8f0;background:#f8fafc}.cortex-tool-details__panel-header--success{border-bottom-color:#a7f3d0;background:#ecfdf5}.cortex-tool-details__panel-header--error{border-bottom-color:#fecaca;background:#fef2f2}.cortex-tool-details__panel-header--approval{border-bottom-color:#ddd6fe;background:#f5f3ff}.cortex-tool-details__panel-label{font-size:.6875rem;font-weight:500;color:#475569}.cortex-tool-details__panel-label--success{color:#047857}.cortex-tool-details__panel-label--error{color:#b91c1c}.cortex-tool-details__panel-label--approval{color:#6d28d9}.cortex-tool-details__panel-lang{font-size:.6875rem;color:#94a3b8;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.cortex-tool-details__panel-lang--success{color:#059669}.cortex-tool-details__panel-lang--error{color:#dc2626}.cortex-tool-details__panel-lang--approval{color:#7c3aed}.cortex-tool-details__code-pre{margin:0;max-height:20rem;overflow:auto;padding:.75rem;font-size:.75rem;line-height:1.25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre;overflow-wrap:break-word}.cortex-tool-details__tree-container{max-height:16rem;overflow:auto;padding:.75rem}.cortex-tool-details__error-pre{margin:0;max-height:16rem;overflow:auto;padding:.75rem;font-size:.75rem;line-height:1.25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;color:#991b1b;white-space:pre-wrap;overflow-wrap:break-word}.cortex-tool-details__denied-body{padding:.75rem;font-size:.75rem;color:#334155}.cortex-tool-details__approval-body{padding:.75rem;font-size:.75rem;color:#5b21b6}.cortex-tool-details__reason-box{margin-top:.5rem;border-radius:.25rem;background:#f8fafc;border:1px solid #e2e8f0;padding:.5rem}.cortex-tool-details__reason-box--approval{background:#f5f3ff;border-color:#ddd6fe}.cortex-tool-details__reason-label{font-size:.6875rem;font-weight:500;color:#475569}.cortex-tool-details__reason-label--approval{color:#6d28d9}.cortex-tool-details__reason-text{margin-top:.25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.75rem;color:#334155;overflow-wrap:break-word}.cortex-tool-details__reason-text--approval{color:#5b21b6}\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, encapsulation: i0.ViewEncapsulation.None });
520
520
  }
521
521
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageToolCallPartComponent, decorators: [{
522
522
  type: Component,
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" }]
523
+ args: [{ selector: 'cortex-message-tool-call-part', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [HighlightPipe, NgClass, TranslatePipe, JsonTreeComponent], template: "<details class=\"cortex-tool-details\">\n <summary class=\"cortex-tool-details__summary\">\n <div class=\"cortex-tool-details__header\">\n <div class=\"cortex-tool-details__icon-box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 20 20\" class=\"cortex-tool-details__icon-svg\" 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=\"cortex-tool-details__info\">\n <div class=\"cortex-tool-details__title-row\">\n <div class=\"cortex-tool-details__name-row\">\n <div class=\"cortex-tool-details__name\" [attr.title]=\"toolCallPart().title || null\">\n {{ toolCallPart().title ?? 'Tool call' }}\n </div>\n @if (toolName()) {\n <span\n class=\"cortex-tool-details__tool-badge\"\n [attr.title]=\"toolCallPart().type || null\"\n >{{ toolName() }}</span\n >\n }\n </div>\n <div class=\"cortex-tool-details__id-line\">\n <span class=\"cortex-tool-details__id-label\">ID</span>\n <span class=\"cortex-tool-details__id-value\"> {{ toolCallPart().toolCallId }}</span>\n @if (toolCallPart().providerExecuted) {\n <span class=\"cortex-tool-details__provider-badge\">\n <span class=\"cortex-tool-details__provider-dot\"></span>\n provider\n </span>\n }\n </div>\n </div>\n\n <div class=\"cortex-tool-details__actions\">\n <span\n class=\"cortex-tool-details__state-badge\"\n [ngClass]=\"{\n 'cortex-tool-details__state-badge--success':\n toolCallPart().state === 'output-available',\n 'cortex-tool-details__state-badge--error': toolCallPart().state === 'output-error',\n 'cortex-tool-details__state-badge--denied': toolCallPart().state === 'output-denied',\n 'cortex-tool-details__state-badge--approval':\n toolCallPart().state === 'approval-requested' ||\n toolCallPart().state === 'approval-responded',\n 'cortex-tool-details__state-badge--pending':\n toolCallPart().state === 'input-streaming' ||\n toolCallPart().state === 'input-available',\n }\"\n >\n @switch (toolCallPart().state) {\n @case ('input-streaming') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--amber cortex-tool-details__status-dot--pulse\"\n ></span>\n Calling\n }\n @case ('input-available') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--amber\"\n ></span>\n Input ready\n }\n @case ('approval-requested') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--violet cortex-tool-details__status-dot--pulse\"\n ></span>\n Needs approval\n }\n @case ('approval-responded') {\n @if (toolCallPart().approval?.approved) {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--emerald\"\n ></span>\n Approved\n } @else {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--slate\"\n ></span>\n Responded\n }\n }\n @case ('output-available') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--emerald\"\n ></span>\n {{ 'translate_completed' | translate }}\n }\n @case ('output-error') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--red\"\n ></span>\n Error\n }\n @case ('output-denied') {\n <span\n class=\"cortex-tool-details__status-dot cortex-tool-details__status-dot--slate\"\n ></span>\n Denied\n }\n }\n </span>\n\n <span class=\"cortex-tool-details__chevron\" aria-hidden=\"true\">\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 </summary>\n\n <div class=\"cortex-tool-details__body\">\n <div class=\"cortex-tool-details__panels\">\n @for (snippet of codeSnippets(); track snippet.key) {\n <div class=\"cortex-tool-details__panel\">\n <div class=\"cortex-tool-details__panel-header\">\n <div class=\"cortex-tool-details__panel-label\">{{ snippet.key }}</div>\n <div class=\"cortex-tool-details__panel-lang\">{{ snippet.lang }}</div>\n </div>\n <pre\n dir=\"ltr\"\n class=\"cortex-tool-details__code-pre\"\n ><code class=\"hljs\" [innerHTML]=\"snippet.value | highlight : snippet.lang\"></code></pre>\n </div>\n }\n\n @if (remainingInput(); as remaining) {\n <div class=\"cortex-tool-details__panel\">\n <div class=\"cortex-tool-details__panel-header\">\n <div class=\"cortex-tool-details__panel-label\">Input</div>\n <div class=\"cortex-tool-details__panel-lang\">json</div>\n </div>\n <div dir=\"ltr\" class=\"cortex-tool-details__tree-container\">\n <cortex-json-tree [data]=\"remaining\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-available') {\n <div class=\"cortex-tool-details__panel cortex-tool-details__panel--success\">\n <div class=\"cortex-tool-details__panel-header cortex-tool-details__panel-header--success\">\n <div class=\"cortex-tool-details__panel-label cortex-tool-details__panel-label--success\">\n Output\n </div>\n <div class=\"cortex-tool-details__panel-lang cortex-tool-details__panel-lang--success\">\n json\n </div>\n </div>\n <div dir=\"ltr\" class=\"cortex-tool-details__tree-container\">\n <cortex-json-tree [data]=\"toolCallPart().output\" [expandDepth]=\"2\" />\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'output-error') {\n <div class=\"cortex-tool-details__panel cortex-tool-details__panel--error\">\n <div class=\"cortex-tool-details__panel-header cortex-tool-details__panel-header--error\">\n <div class=\"cortex-tool-details__panel-label cortex-tool-details__panel-label--error\">\n Error\n </div>\n <div class=\"cortex-tool-details__panel-lang cortex-tool-details__panel-lang--error\">\n text\n </div>\n </div>\n <pre dir=\"ltr\" class=\"cortex-tool-details__error-pre\">{{ toolCallPart().errorText }}</pre>\n </div>\n }\n\n @if (toolCallPart().state === 'output-denied') {\n <div class=\"cortex-tool-details__panel\">\n <div class=\"cortex-tool-details__panel-header\">\n <div class=\"cortex-tool-details__panel-label\">Denied</div>\n <div class=\"cortex-tool-details__panel-lang\">approval</div>\n </div>\n <div class=\"cortex-tool-details__denied-body\">\n Tool execution was denied.\n @if (toolCallPart().approval?.reason) {\n <div class=\"cortex-tool-details__reason-box\">\n <div class=\"cortex-tool-details__reason-label\">Reason</div>\n <div class=\"cortex-tool-details__reason-text\">\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-requested') {\n <div class=\"cortex-tool-details__panel cortex-tool-details__panel--approval\">\n <div\n class=\"cortex-tool-details__panel-header cortex-tool-details__panel-header--approval\"\n >\n <div\n class=\"cortex-tool-details__panel-label cortex-tool-details__panel-label--approval\"\n >\n Approval requested\n </div>\n <div class=\"cortex-tool-details__panel-lang cortex-tool-details__panel-lang--approval\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"cortex-tool-details__approval-body\">\n Waiting for approval to execute this tool.\n </div>\n </div>\n }\n\n @if (toolCallPart().state === 'approval-responded') {\n <div class=\"cortex-tool-details__panel cortex-tool-details__panel--approval\">\n <div\n class=\"cortex-tool-details__panel-header cortex-tool-details__panel-header--approval\"\n >\n <div\n class=\"cortex-tool-details__panel-label cortex-tool-details__panel-label--approval\"\n >\n Approval response\n </div>\n <div class=\"cortex-tool-details__panel-lang cortex-tool-details__panel-lang--approval\">\n {{ toolCallPart().approval?.id }}\n </div>\n </div>\n <div class=\"cortex-tool-details__approval-body\">\n @if (toolCallPart().approval?.approved) {\n Approved.\n } @else {\n Response received.\n }\n @if (toolCallPart().approval?.reason) {\n <div\n class=\"cortex-tool-details__reason-box cortex-tool-details__reason-box--approval\"\n >\n <div\n class=\"cortex-tool-details__reason-label cortex-tool-details__reason-label--approval\"\n >\n Reason\n </div>\n <div\n class=\"cortex-tool-details__reason-text cortex-tool-details__reason-text--approval\"\n >\n {{ toolCallPart().approval?.reason }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n</details>\n", styles: [".cortex-tool-details{width:100%;border-radius:.5rem;border:1px solid #e2e8f0;background:#f8fafc;overflow:hidden}.cortex-tool-details__summary{list-style:none;cursor:pointer;-webkit-user-select:none;user-select:none;padding:.75rem 1rem}.cortex-tool-details__summary::-webkit-details-marker{display:none}details[open]>.cortex-tool-details__summary{border-bottom:1px solid #e2e8f0}.cortex-tool-details__header{display:flex;align-items:flex-start;gap:.75rem}.cortex-tool-details__icon-box{flex-shrink:0;margin-top:.125rem;width:1.75rem;height:1.75rem;border-radius:.25rem;background:#1e293b;color:#fff;display:flex;align-items:center;justify-content:center}.cortex-tool-details__icon-svg{width:1rem;height:1rem}.cortex-tool-details__info{min-width:0;flex:1;display:flex;align-items:center;gap:.5rem}.cortex-tool-details__title-row{min-width:0;flex:1}.cortex-tool-details__name-row{display:flex;align-items:center;gap:.5rem;min-width:0}.cortex-tool-details__name{font-weight:500;color:#1e293b;font-size:.875rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cortex-tool-details__tool-badge{display:none;align-items:center;border-radius:.25rem;background:#e2e8f0;padding:.125rem .375rem;font-size:.6875rem;font-weight:500;color:#475569;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}@media(min-width:640px){.cortex-tool-details__tool-badge{display:inline-flex}}.cortex-tool-details__id-line{margin-top:.125rem;font-size:.6875rem;color:#64748b;word-break:break-all}.cortex-tool-details__id-label{font-weight:500;color:#475569}.cortex-tool-details__id-value{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.cortex-tool-details__provider-badge{margin-inline-start:.5rem;display:inline-flex;align-items:center;gap:.25rem;color:#047857}.cortex-tool-details__provider-dot{width:.375rem;height:.375rem;border-radius:9999px;background:#10b981}.cortex-tool-details__actions{display:flex;align-items:center;gap:.5rem}.cortex-tool-details__state-badge{display:inline-flex;align-items:center;gap:.375rem;border-radius:.25rem;padding:.25rem .5rem;font-size:.6875rem;font-weight:500;border:1px solid}.cortex-tool-details__state-badge--success{background:#ecfdf5;color:#047857;border-color:#a7f3d0}.cortex-tool-details__state-badge--error{background:#fef2f2;color:#b91c1c;border-color:#fecaca}.cortex-tool-details__state-badge--denied{background:#f1f5f9;color:#475569;border-color:#e2e8f0}.cortex-tool-details__state-badge--approval{background:#f5f3ff;color:#6d28d9;border-color:#ddd6fe}.cortex-tool-details__state-badge--pending{background:#fffbeb;color:#b45309;border-color:#fde68a}.cortex-tool-details__status-dot{width:.375rem;height:.375rem;border-radius:9999px}.cortex-tool-details__status-dot--amber{background:#f59e0b}.cortex-tool-details__status-dot--violet{background:#8b5cf6}.cortex-tool-details__status-dot--emerald{background:#10b981}.cortex-tool-details__status-dot--red{background:#ef4444}.cortex-tool-details__status-dot--slate{background:#64748b}.cortex-tool-details__status-dot--pulse{animation:cortex-tool-status-pulse 2s ease-in-out infinite}@keyframes cortex-tool-status-pulse{0%,to{opacity:1}50%{opacity:.4}}.cortex-tool-details__chevron{display:inline-flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center;border-radius:.25rem;color:#94a3b8;transition:transform .2s}details[open]>summary .cortex-tool-details__chevron{transform:rotate(180deg)}.cortex-tool-details__body{background:#fff;padding:.75rem 1rem 1rem}.cortex-tool-details__panels{display:grid;gap:.75rem}.cortex-tool-details__panel{border-radius:.5rem;border:1px solid #e2e8f0;overflow:hidden}.cortex-tool-details__panel--success{border-color:#a7f3d0}.cortex-tool-details__panel--error{border-color:#fecaca}.cortex-tool-details__panel--approval{border-color:#ddd6fe}.cortex-tool-details__panel-header{padding:.5rem .75rem;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #e2e8f0;background:#f8fafc}.cortex-tool-details__panel-header--success{border-bottom-color:#a7f3d0;background:#ecfdf5}.cortex-tool-details__panel-header--error{border-bottom-color:#fecaca;background:#fef2f2}.cortex-tool-details__panel-header--approval{border-bottom-color:#ddd6fe;background:#f5f3ff}.cortex-tool-details__panel-label{font-size:.6875rem;font-weight:500;color:#475569}.cortex-tool-details__panel-label--success{color:#047857}.cortex-tool-details__panel-label--error{color:#b91c1c}.cortex-tool-details__panel-label--approval{color:#6d28d9}.cortex-tool-details__panel-lang{font-size:.6875rem;color:#94a3b8;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.cortex-tool-details__panel-lang--success{color:#059669}.cortex-tool-details__panel-lang--error{color:#dc2626}.cortex-tool-details__panel-lang--approval{color:#7c3aed}.cortex-tool-details__code-pre{margin:0;max-height:20rem;overflow:auto;padding:.75rem;font-size:.75rem;line-height:1.25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre;overflow-wrap:break-word}.cortex-tool-details__tree-container{max-height:16rem;overflow:auto;padding:.75rem}.cortex-tool-details__error-pre{margin:0;max-height:16rem;overflow:auto;padding:.75rem;font-size:.75rem;line-height:1.25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;color:#991b1b;white-space:pre-wrap;overflow-wrap:break-word}.cortex-tool-details__denied-body{padding:.75rem;font-size:.75rem;color:#334155}.cortex-tool-details__approval-body{padding:.75rem;font-size:.75rem;color:#5b21b6}.cortex-tool-details__reason-box{margin-top:.5rem;border-radius:.25rem;background:#f8fafc;border:1px solid #e2e8f0;padding:.5rem}.cortex-tool-details__reason-box--approval{background:#f5f3ff;border-color:#ddd6fe}.cortex-tool-details__reason-label{font-size:.6875rem;font-weight:500;color:#475569}.cortex-tool-details__reason-label--approval{color:#6d28d9}.cortex-tool-details__reason-text{margin-top:.25rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.75rem;color:#334155;overflow-wrap:break-word}.cortex-tool-details__reason-text--approval{color:#5b21b6}\n"] }]
524
524
  }], propDecorators: { toolCallPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolCallPart", required: true }] }] } });
525
525
 
526
526
  class MessageCaptureFilesPartComponent {
@@ -618,11 +618,11 @@ class MessageCaptureFilesPartComponent {
618
618
  });
619
619
  }
620
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 });
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 } }, host: { classAttribute: "cortex-capture-files" }, ngImport: i0, template: "@if (outputData(); as output) {\n <!-- Result state -->\n @if (output.status === 'success') {\n <div class=\"cortex-capture-success\">\n <div class=\"cortex-capture-success__header\">\n <div class=\"cortex-capture-success__icon\">\n <svg viewBox=\"0 0 20 20\" class=\"cortex-capture-success__icon-svg\" 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=\"cortex-capture-success__title-wrap\">\n <h3 class=\"cortex-capture-success__title\">\n {{ 'translate_files_attached' | translate: { count: data().files.length } }}\n </h3>\n </div>\n </div>\n\n <div class=\"cortex-capture-success__file-list\">\n <ul class=\"cortex-capture-success__files\">\n @for (file of outputData()!.result!; track file.uploadId) {\n <li>\n <button\n type=\"button\"\n (click)=\"downloadFile(file.uploadId)\"\n class=\"cortex-capture-success__download-btn\"\n >\n <svg viewBox=\"0 0 16 16\" class=\"cortex-capture-success__file-icon\" 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=\"cortex-capture-success__file-name\">{{\n data().files[$index].label\n }}</span>\n <svg viewBox=\"0 0 16 16\" class=\"cortex-capture-success__dl-icon\" 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=\"cortex-capture-canceled-wrap\">\n <div class=\"cortex-capture-canceled\">\n <div class=\"cortex-capture-canceled__icon\">\n <svg viewBox=\"0 0 20 20\" class=\"cortex-capture-canceled__icon-svg\" fill=\"none\">\n <path d=\"M6 10h8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </div>\n <span class=\"cortex-capture-canceled__text\">{{\n 'translate_file_upload_skipped' | translate\n }}</span>\n </div>\n </div>\n }\n} @else {\n <!-- Upload form -->\n <form [formGroup]=\"form()\" class=\"cortex-capture-form\">\n @if (data().files.length === 1) {\n <!-- Single file: minimal inline -->\n <fieldset [formArray]=\"form().controls.files\">\n <div [formGroupName]=\"0\" class=\"cortex-capture-form__single\">\n <label for=\"capture-file-0\" class=\"cortex-capture-form__label\">\n {{ data().files[0].label }}\n </label>\n <input hidden formControlName=\"id\" />\n <div class=\"cortex-capture-form__row\">\n <cortex-file-input\n id=\"capture-file-0\"\n formControlName=\"file\"\n class=\"cortex-capture-form__input\"\n />\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"cortex-capture-form__cancel-link\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"cortex-capture-form__submit-btn\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"cortex-capture-form__spinner\" 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=\"cortex-capture-form__spinner-track\"\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 class=\"cortex-capture-form__multi\">\n <div class=\"cortex-capture-form__multi-header\">\n <div class=\"cortex-capture-form__multi-header-row\">\n <div class=\"cortex-capture-form__multi-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 20 20\" class=\"cortex-capture-form__multi-icon-svg\" 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=\"cortex-capture-form__multi-title-wrap\">\n <h3 class=\"cortex-capture-form__multi-title\">\n {{ 'translate_attach_requested_files' | translate }}\n </h3>\n <p class=\"cortex-capture-form__multi-subtitle\">\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=\"cortex-capture-form__multi-fields\">\n @for (file of form().controls.files.value; track $index) {\n <div [formGroupName]=\"$index\" class=\"cortex-capture-form__multi-item\">\n <div class=\"cortex-capture-form__multi-item-header\">\n <label\n [for]=\"'capture-file-' + $index\"\n class=\"cortex-capture-form__multi-item-label\"\n >\n {{ data().files[$index].label }}\n </label>\n <span class=\"cortex-capture-form__required-badge\">\n {{ 'translate_required' | translate }}\n </span>\n </div>\n <input hidden formControlName=\"id\" />\n <cortex-file-input [id]=\"'capture-file-' + $index\" formControlName=\"file\" />\n </div>\n }\n </fieldset>\n\n <div class=\"cortex-capture-form__multi-footer\">\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"cortex-capture-form__cancel-btn\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"cortex-capture-form__submit-btn\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"cortex-capture-form__spinner\" 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=\"cortex-capture-form__spinner-track\"\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: [".cortex-capture-files{display:block;width:100%}.cortex-file-input{display:flex;width:100%;cursor:pointer;align-items:center;border-radius:.5rem;border:1px solid #cbd5e1;background:#f8fafc;transition:border-color .15s}.cortex-file-input:hover{border-color:#94a3b8}.cortex-file-input:focus-within{box-shadow:0 0 0 2px #cbd5e1}.cortex-file-input__btn{margin:.25rem;flex-shrink:0;cursor:pointer;border-radius:.375rem;border:0;background:#1e293b;padding:.375rem .75rem;font-size:.6875rem;font-weight:600;letter-spacing:.025em;color:#f1f5f9}.cortex-file-input__btn:hover{background:#334155}.cortex-file-input__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:0 .75rem;font-size:.75rem;color:#475569}.cortex-file-input__hidden{display:none}.cortex-capture-success{overflow:hidden;border-radius:1rem;border:1px solid #a7f3d0;background:linear-gradient(to bottom,#ecfdf5cc,#fff)}.cortex-capture-success__header{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-success__header{padding:.75rem 1.25rem}}.cortex-capture-success__icon{display:inline-flex;width:2rem;height:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;border:1px solid #a7f3d0;background:#d1fae5;color:#059669}.cortex-capture-success__icon-svg{width:1rem;height:1rem}.cortex-capture-success__title-wrap{min-width:0}.cortex-capture-success__title{font-size:.8125rem;font-weight:600;letter-spacing:-.01em;color:#065f46;margin:0}.cortex-capture-success__file-list{border-top:1px solid #d1fae5;padding:.625rem 1rem}@media(min-width:640px){.cortex-capture-success__file-list{padding:.625rem 1.25rem}}.cortex-capture-success__files{display:flex;flex-wrap:wrap;gap:.5rem;list-style:none;margin:0;padding:0}.cortex-capture-success__download-btn{display:inline-flex;cursor:pointer;align-items:center;gap:.375rem;border-radius:.5rem;border:1px solid #d1fae5;background:#fff;padding:.375rem .625rem;font-size:.75rem;font-weight:500;color:#047857;box-shadow:0 1px 2px #0000000d;transition:all .15s}.cortex-capture-success__download-btn:hover{border-color:#a7f3d0;background:#ecfdf5;box-shadow:0 1px 3px #0000001a}.cortex-capture-success__download-btn:active{transform:scale(.97)}.cortex-capture-success__file-icon{width:.875rem;height:.875rem;flex-shrink:0;color:#6ee7b7}.cortex-capture-success__file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}.cortex-capture-success__dl-icon{width:.75rem;height:.75rem;flex-shrink:0;color:#86efac}.cortex-capture-canceled-wrap{display:flex;justify-content:center}.cortex-capture-canceled{display:inline-flex;align-items:center;gap:.625rem;border-radius:.5rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.625rem 1rem}.cortex-capture-canceled__icon{display:inline-flex;width:1.5rem;height:1.5rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.375rem;border:1px solid #e2e8f0;background:#f1f5f9;color:#94a3b8}.cortex-capture-canceled__icon-svg{width:.75rem;height:.75rem}.cortex-capture-canceled__text{font-size:.8125rem;font-weight:500;color:#94a3b8}.cortex-capture-form{width:100%}.cortex-capture-form__single{border-radius:.75rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.75rem}.cortex-capture-form__label{display:block;margin-bottom:.375rem;font-size:.75rem;color:#64748b}.cortex-capture-form__row{display:flex;align-items:center;gap:.5rem}.cortex-capture-form__input{min-width:0;flex:1}.cortex-capture-form__cancel-link{flex-shrink:0;font-size:.75rem;font-weight:500;color:#94a3b8;background:none;border:0;cursor:pointer;transition:color .15s}.cortex-capture-form__cancel-link:hover{color:#475569}.cortex-capture-form__submit-btn{display:inline-flex;flex-shrink:0;align-items:center;border-radius:.375rem;background:#1e293b;padding:.375rem .75rem;font-size:.75rem;font-weight:500;color:#f1f5f9;border:0;cursor:pointer;transition:background-color .15s}.cortex-capture-form__submit-btn:hover{background:#334155}.cortex-capture-form__submit-btn:active{background:#0f172a}.cortex-capture-form__submit-btn:disabled{cursor:not-allowed;background:#cbd5e1}.cortex-capture-form__spinner{width:.75rem;height:.75rem;margin-inline-end:.375rem;animation:cortex-capture-spin .8s linear infinite}.cortex-capture-form__spinner-track{opacity:.25}@keyframes cortex-capture-spin{to{transform:rotate(360deg)}}.cortex-capture-form__multi{overflow:hidden;border-radius:1rem;border:1px solid #e2e8f0;background:linear-gradient(to bottom,#fff,#f8fafc)}.cortex-capture-form__multi-header{border-bottom:1px solid #e2e8f0;background:#ffffffd9;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-form__multi-header{padding:.75rem 1.25rem}}.cortex-capture-form__multi-header-row{display:flex;align-items:flex-start;gap:.75rem}.cortex-capture-form__multi-icon{margin-top:.125rem;display:inline-flex;width:2rem;height:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;border:1px solid #e2e8f0;background:#f1f5f9;color:#475569}.cortex-capture-form__multi-icon-svg{width:1rem;height:1rem}.cortex-capture-form__multi-title-wrap{min-width:0}.cortex-capture-form__multi-title{font-size:.8125rem;font-weight:600;letter-spacing:-.01em;color:#1e293b;margin:0}.cortex-capture-form__multi-subtitle{margin-top:.125rem;font-size:.6875rem;color:#64748b;margin-bottom:0}.cortex-capture-form__multi-fields{display:grid;gap:.75rem;padding:1rem;border:0}@media(min-width:640px){.cortex-capture-form__multi-fields{padding:1.25rem}}.cortex-capture-form__multi-item{border-radius:.75rem;border:1px solid #e2e8f0;background:#fff;padding:.75rem;transition:border-color .15s}.cortex-capture-form__multi-item:hover{border-color:#cbd5e1}.cortex-capture-form__multi-item-header{margin-bottom:.5rem;display:flex;align-items:center;justify-content:space-between;gap:.5rem}.cortex-capture-form__multi-item-label{display:block;font-size:.75rem;font-weight:500;line-height:1;color:#334155}.cortex-capture-form__required-badge{display:inline-flex;align-items:center;border-radius:.25rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.125rem .375rem;font-size:.625rem;font-weight:500;text-transform:uppercase;letter-spacing:.05em;color:#64748b}.cortex-capture-form__multi-footer{display:flex;align-items:center;justify-content:flex-end;gap:.5rem;border-top:1px solid #e2e8f0;background:#ffffffe6;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-form__multi-footer{padding:.75rem 1.25rem}}.cortex-capture-form__cancel-btn{display:inline-flex;align-items:center;border-radius:.375rem;border:1px solid #cbd5e1;background:#fff;padding:.375rem .75rem;font-size:.75rem;font-weight:500;color:#475569;cursor:pointer;transition:background-color .15s}.cortex-capture-form__cancel-btn:hover{background:#f8fafc}.cortex-capture-form__cancel-btn:active{background:#f1f5f9}\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, encapsulation: i0.ViewEncapsulation.None });
622
622
  }
623
623
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageCaptureFilesPartComponent, decorators: [{
624
624
  type: Component,
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"] }]
625
+ args: [{ selector: 'cortex-message-capture-files-part', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [ReactiveFormsModule, forwardRef(() => FileInputComponent), TranslatePipe], host: { class: 'cortex-capture-files' }, template: "@if (outputData(); as output) {\n <!-- Result state -->\n @if (output.status === 'success') {\n <div class=\"cortex-capture-success\">\n <div class=\"cortex-capture-success__header\">\n <div class=\"cortex-capture-success__icon\">\n <svg viewBox=\"0 0 20 20\" class=\"cortex-capture-success__icon-svg\" 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=\"cortex-capture-success__title-wrap\">\n <h3 class=\"cortex-capture-success__title\">\n {{ 'translate_files_attached' | translate: { count: data().files.length } }}\n </h3>\n </div>\n </div>\n\n <div class=\"cortex-capture-success__file-list\">\n <ul class=\"cortex-capture-success__files\">\n @for (file of outputData()!.result!; track file.uploadId) {\n <li>\n <button\n type=\"button\"\n (click)=\"downloadFile(file.uploadId)\"\n class=\"cortex-capture-success__download-btn\"\n >\n <svg viewBox=\"0 0 16 16\" class=\"cortex-capture-success__file-icon\" 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=\"cortex-capture-success__file-name\">{{\n data().files[$index].label\n }}</span>\n <svg viewBox=\"0 0 16 16\" class=\"cortex-capture-success__dl-icon\" 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=\"cortex-capture-canceled-wrap\">\n <div class=\"cortex-capture-canceled\">\n <div class=\"cortex-capture-canceled__icon\">\n <svg viewBox=\"0 0 20 20\" class=\"cortex-capture-canceled__icon-svg\" fill=\"none\">\n <path d=\"M6 10h8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n </div>\n <span class=\"cortex-capture-canceled__text\">{{\n 'translate_file_upload_skipped' | translate\n }}</span>\n </div>\n </div>\n }\n} @else {\n <!-- Upload form -->\n <form [formGroup]=\"form()\" class=\"cortex-capture-form\">\n @if (data().files.length === 1) {\n <!-- Single file: minimal inline -->\n <fieldset [formArray]=\"form().controls.files\">\n <div [formGroupName]=\"0\" class=\"cortex-capture-form__single\">\n <label for=\"capture-file-0\" class=\"cortex-capture-form__label\">\n {{ data().files[0].label }}\n </label>\n <input hidden formControlName=\"id\" />\n <div class=\"cortex-capture-form__row\">\n <cortex-file-input\n id=\"capture-file-0\"\n formControlName=\"file\"\n class=\"cortex-capture-form__input\"\n />\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"cortex-capture-form__cancel-link\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"cortex-capture-form__submit-btn\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"cortex-capture-form__spinner\" 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=\"cortex-capture-form__spinner-track\"\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 class=\"cortex-capture-form__multi\">\n <div class=\"cortex-capture-form__multi-header\">\n <div class=\"cortex-capture-form__multi-header-row\">\n <div class=\"cortex-capture-form__multi-icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 20 20\" class=\"cortex-capture-form__multi-icon-svg\" 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=\"cortex-capture-form__multi-title-wrap\">\n <h3 class=\"cortex-capture-form__multi-title\">\n {{ 'translate_attach_requested_files' | translate }}\n </h3>\n <p class=\"cortex-capture-form__multi-subtitle\">\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=\"cortex-capture-form__multi-fields\">\n @for (file of form().controls.files.value; track $index) {\n <div [formGroupName]=\"$index\" class=\"cortex-capture-form__multi-item\">\n <div class=\"cortex-capture-form__multi-item-header\">\n <label\n [for]=\"'capture-file-' + $index\"\n class=\"cortex-capture-form__multi-item-label\"\n >\n {{ data().files[$index].label }}\n </label>\n <span class=\"cortex-capture-form__required-badge\">\n {{ 'translate_required' | translate }}\n </span>\n </div>\n <input hidden formControlName=\"id\" />\n <cortex-file-input [id]=\"'capture-file-' + $index\" formControlName=\"file\" />\n </div>\n }\n </fieldset>\n\n <div class=\"cortex-capture-form__multi-footer\">\n <button\n (click)=\"cancel()\"\n [disabled]=\"isLoading()\"\n type=\"button\"\n class=\"cortex-capture-form__cancel-btn\"\n >\n {{ 'translate_cancel' | translate }}\n </button>\n <button\n (click)=\"submit()\"\n type=\"button\"\n class=\"cortex-capture-form__submit-btn\"\n [disabled]=\"form().invalid || isLoading()\"\n >\n @if (isLoading()) {\n <svg class=\"cortex-capture-form__spinner\" 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=\"cortex-capture-form__spinner-track\"\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: [".cortex-capture-files{display:block;width:100%}.cortex-file-input{display:flex;width:100%;cursor:pointer;align-items:center;border-radius:.5rem;border:1px solid #cbd5e1;background:#f8fafc;transition:border-color .15s}.cortex-file-input:hover{border-color:#94a3b8}.cortex-file-input:focus-within{box-shadow:0 0 0 2px #cbd5e1}.cortex-file-input__btn{margin:.25rem;flex-shrink:0;cursor:pointer;border-radius:.375rem;border:0;background:#1e293b;padding:.375rem .75rem;font-size:.6875rem;font-weight:600;letter-spacing:.025em;color:#f1f5f9}.cortex-file-input__btn:hover{background:#334155}.cortex-file-input__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:0 .75rem;font-size:.75rem;color:#475569}.cortex-file-input__hidden{display:none}.cortex-capture-success{overflow:hidden;border-radius:1rem;border:1px solid #a7f3d0;background:linear-gradient(to bottom,#ecfdf5cc,#fff)}.cortex-capture-success__header{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-success__header{padding:.75rem 1.25rem}}.cortex-capture-success__icon{display:inline-flex;width:2rem;height:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;border:1px solid #a7f3d0;background:#d1fae5;color:#059669}.cortex-capture-success__icon-svg{width:1rem;height:1rem}.cortex-capture-success__title-wrap{min-width:0}.cortex-capture-success__title{font-size:.8125rem;font-weight:600;letter-spacing:-.01em;color:#065f46;margin:0}.cortex-capture-success__file-list{border-top:1px solid #d1fae5;padding:.625rem 1rem}@media(min-width:640px){.cortex-capture-success__file-list{padding:.625rem 1.25rem}}.cortex-capture-success__files{display:flex;flex-wrap:wrap;gap:.5rem;list-style:none;margin:0;padding:0}.cortex-capture-success__download-btn{display:inline-flex;cursor:pointer;align-items:center;gap:.375rem;border-radius:.5rem;border:1px solid #d1fae5;background:#fff;padding:.375rem .625rem;font-size:.75rem;font-weight:500;color:#047857;box-shadow:0 1px 2px #0000000d;transition:all .15s}.cortex-capture-success__download-btn:hover{border-color:#a7f3d0;background:#ecfdf5;box-shadow:0 1px 3px #0000001a}.cortex-capture-success__download-btn:active{transform:scale(.97)}.cortex-capture-success__file-icon{width:.875rem;height:.875rem;flex-shrink:0;color:#6ee7b7}.cortex-capture-success__file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}.cortex-capture-success__dl-icon{width:.75rem;height:.75rem;flex-shrink:0;color:#86efac}.cortex-capture-canceled-wrap{display:flex;justify-content:center}.cortex-capture-canceled{display:inline-flex;align-items:center;gap:.625rem;border-radius:.5rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.625rem 1rem}.cortex-capture-canceled__icon{display:inline-flex;width:1.5rem;height:1.5rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.375rem;border:1px solid #e2e8f0;background:#f1f5f9;color:#94a3b8}.cortex-capture-canceled__icon-svg{width:.75rem;height:.75rem}.cortex-capture-canceled__text{font-size:.8125rem;font-weight:500;color:#94a3b8}.cortex-capture-form{width:100%}.cortex-capture-form__single{border-radius:.75rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.75rem}.cortex-capture-form__label{display:block;margin-bottom:.375rem;font-size:.75rem;color:#64748b}.cortex-capture-form__row{display:flex;align-items:center;gap:.5rem}.cortex-capture-form__input{min-width:0;flex:1}.cortex-capture-form__cancel-link{flex-shrink:0;font-size:.75rem;font-weight:500;color:#94a3b8;background:none;border:0;cursor:pointer;transition:color .15s}.cortex-capture-form__cancel-link:hover{color:#475569}.cortex-capture-form__submit-btn{display:inline-flex;flex-shrink:0;align-items:center;border-radius:.375rem;background:#1e293b;padding:.375rem .75rem;font-size:.75rem;font-weight:500;color:#f1f5f9;border:0;cursor:pointer;transition:background-color .15s}.cortex-capture-form__submit-btn:hover{background:#334155}.cortex-capture-form__submit-btn:active{background:#0f172a}.cortex-capture-form__submit-btn:disabled{cursor:not-allowed;background:#cbd5e1}.cortex-capture-form__spinner{width:.75rem;height:.75rem;margin-inline-end:.375rem;animation:cortex-capture-spin .8s linear infinite}.cortex-capture-form__spinner-track{opacity:.25}@keyframes cortex-capture-spin{to{transform:rotate(360deg)}}.cortex-capture-form__multi{overflow:hidden;border-radius:1rem;border:1px solid #e2e8f0;background:linear-gradient(to bottom,#fff,#f8fafc)}.cortex-capture-form__multi-header{border-bottom:1px solid #e2e8f0;background:#ffffffd9;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-form__multi-header{padding:.75rem 1.25rem}}.cortex-capture-form__multi-header-row{display:flex;align-items:flex-start;gap:.75rem}.cortex-capture-form__multi-icon{margin-top:.125rem;display:inline-flex;width:2rem;height:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;border:1px solid #e2e8f0;background:#f1f5f9;color:#475569}.cortex-capture-form__multi-icon-svg{width:1rem;height:1rem}.cortex-capture-form__multi-title-wrap{min-width:0}.cortex-capture-form__multi-title{font-size:.8125rem;font-weight:600;letter-spacing:-.01em;color:#1e293b;margin:0}.cortex-capture-form__multi-subtitle{margin-top:.125rem;font-size:.6875rem;color:#64748b;margin-bottom:0}.cortex-capture-form__multi-fields{display:grid;gap:.75rem;padding:1rem;border:0}@media(min-width:640px){.cortex-capture-form__multi-fields{padding:1.25rem}}.cortex-capture-form__multi-item{border-radius:.75rem;border:1px solid #e2e8f0;background:#fff;padding:.75rem;transition:border-color .15s}.cortex-capture-form__multi-item:hover{border-color:#cbd5e1}.cortex-capture-form__multi-item-header{margin-bottom:.5rem;display:flex;align-items:center;justify-content:space-between;gap:.5rem}.cortex-capture-form__multi-item-label{display:block;font-size:.75rem;font-weight:500;line-height:1;color:#334155}.cortex-capture-form__required-badge{display:inline-flex;align-items:center;border-radius:.25rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.125rem .375rem;font-size:.625rem;font-weight:500;text-transform:uppercase;letter-spacing:.05em;color:#64748b}.cortex-capture-form__multi-footer{display:flex;align-items:center;justify-content:flex-end;gap:.5rem;border-top:1px solid #e2e8f0;background:#ffffffe6;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-form__multi-footer{padding:.75rem 1.25rem}}.cortex-capture-form__cancel-btn{display:inline-flex;align-items:center;border-radius:.375rem;border:1px solid #cbd5e1;background:#fff;padding:.375rem .75rem;font-size:.75rem;font-weight:500;color:#475569;cursor:pointer;transition:background-color .15s}.cortex-capture-form__cancel-btn:hover{background:#f8fafc}.cortex-capture-form__cancel-btn:active{background:#f1f5f9}\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
628
  allowedMimeTypes = input('*/*', ...(ngDevMode ? [{ debugName: "allowedMimeTypes" }] : /* istanbul ignore next */ []));
@@ -665,51 +665,33 @@ class FileInputComponent {
665
665
  multi: true,
666
666
  useExisting: forwardRef(() => FileInputComponent),
667
667
  },
668
- ], ngImport: i0, template: `<div
669
- class="flex w-full cursor-pointer items-center rounded-lg border border-slate-300 bg-slate-50 transition hover:border-slate-400 focus-within:ring-2 focus-within:ring-slate-300"
670
- >
671
- <button
672
- type="button"
673
- (click)="fileInput.click()"
674
- class="m-1 shrink-0 cursor-pointer rounded-md border-0 bg-slate-800 px-3 py-1.5 text-[11px] font-semibold tracking-wide text-slate-100 hover:bg-slate-700"
675
- >
668
+ ], ngImport: i0, template: `<div class="cortex-file-input">
669
+ <button type="button" (click)="fileInput.click()" class="cortex-file-input__btn">
676
670
  {{ 'translate_choose_file' | translate }}
677
671
  </button>
678
- <span class="truncate px-3 text-[12px] text-slate-600">{{
672
+ <span class="cortex-file-input__name">{{
679
673
  value()?.name ?? ('translate_no_file_chosen' | translate)
680
674
  }}</span>
681
- <input #fileInput (change)="loadFile($event)" type="file" class="hidden" />
682
- </div>`, isInline: true, dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
675
+ <input #fileInput (change)="loadFile($event)" type="file" class="cortex-file-input__hidden" />
676
+ </div>`, isInline: true, styles: [".cortex-capture-files{display:block;width:100%}.cortex-file-input{display:flex;width:100%;cursor:pointer;align-items:center;border-radius:.5rem;border:1px solid #cbd5e1;background:#f8fafc;transition:border-color .15s}.cortex-file-input:hover{border-color:#94a3b8}.cortex-file-input:focus-within{box-shadow:0 0 0 2px #cbd5e1}.cortex-file-input__btn{margin:.25rem;flex-shrink:0;cursor:pointer;border-radius:.375rem;border:0;background:#1e293b;padding:.375rem .75rem;font-size:.6875rem;font-weight:600;letter-spacing:.025em;color:#f1f5f9}.cortex-file-input__btn:hover{background:#334155}.cortex-file-input__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:0 .75rem;font-size:.75rem;color:#475569}.cortex-file-input__hidden{display:none}.cortex-capture-success{overflow:hidden;border-radius:1rem;border:1px solid #a7f3d0;background:linear-gradient(to bottom,#ecfdf5cc,#fff)}.cortex-capture-success__header{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-success__header{padding:.75rem 1.25rem}}.cortex-capture-success__icon{display:inline-flex;width:2rem;height:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;border:1px solid #a7f3d0;background:#d1fae5;color:#059669}.cortex-capture-success__icon-svg{width:1rem;height:1rem}.cortex-capture-success__title-wrap{min-width:0}.cortex-capture-success__title{font-size:.8125rem;font-weight:600;letter-spacing:-.01em;color:#065f46;margin:0}.cortex-capture-success__file-list{border-top:1px solid #d1fae5;padding:.625rem 1rem}@media(min-width:640px){.cortex-capture-success__file-list{padding:.625rem 1.25rem}}.cortex-capture-success__files{display:flex;flex-wrap:wrap;gap:.5rem;list-style:none;margin:0;padding:0}.cortex-capture-success__download-btn{display:inline-flex;cursor:pointer;align-items:center;gap:.375rem;border-radius:.5rem;border:1px solid #d1fae5;background:#fff;padding:.375rem .625rem;font-size:.75rem;font-weight:500;color:#047857;box-shadow:0 1px 2px #0000000d;transition:all .15s}.cortex-capture-success__download-btn:hover{border-color:#a7f3d0;background:#ecfdf5;box-shadow:0 1px 3px #0000001a}.cortex-capture-success__download-btn:active{transform:scale(.97)}.cortex-capture-success__file-icon{width:.875rem;height:.875rem;flex-shrink:0;color:#6ee7b7}.cortex-capture-success__file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}.cortex-capture-success__dl-icon{width:.75rem;height:.75rem;flex-shrink:0;color:#86efac}.cortex-capture-canceled-wrap{display:flex;justify-content:center}.cortex-capture-canceled{display:inline-flex;align-items:center;gap:.625rem;border-radius:.5rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.625rem 1rem}.cortex-capture-canceled__icon{display:inline-flex;width:1.5rem;height:1.5rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.375rem;border:1px solid #e2e8f0;background:#f1f5f9;color:#94a3b8}.cortex-capture-canceled__icon-svg{width:.75rem;height:.75rem}.cortex-capture-canceled__text{font-size:.8125rem;font-weight:500;color:#94a3b8}.cortex-capture-form{width:100%}.cortex-capture-form__single{border-radius:.75rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.75rem}.cortex-capture-form__label{display:block;margin-bottom:.375rem;font-size:.75rem;color:#64748b}.cortex-capture-form__row{display:flex;align-items:center;gap:.5rem}.cortex-capture-form__input{min-width:0;flex:1}.cortex-capture-form__cancel-link{flex-shrink:0;font-size:.75rem;font-weight:500;color:#94a3b8;background:none;border:0;cursor:pointer;transition:color .15s}.cortex-capture-form__cancel-link:hover{color:#475569}.cortex-capture-form__submit-btn{display:inline-flex;flex-shrink:0;align-items:center;border-radius:.375rem;background:#1e293b;padding:.375rem .75rem;font-size:.75rem;font-weight:500;color:#f1f5f9;border:0;cursor:pointer;transition:background-color .15s}.cortex-capture-form__submit-btn:hover{background:#334155}.cortex-capture-form__submit-btn:active{background:#0f172a}.cortex-capture-form__submit-btn:disabled{cursor:not-allowed;background:#cbd5e1}.cortex-capture-form__spinner{width:.75rem;height:.75rem;margin-inline-end:.375rem;animation:cortex-capture-spin .8s linear infinite}.cortex-capture-form__spinner-track{opacity:.25}@keyframes cortex-capture-spin{to{transform:rotate(360deg)}}.cortex-capture-form__multi{overflow:hidden;border-radius:1rem;border:1px solid #e2e8f0;background:linear-gradient(to bottom,#fff,#f8fafc)}.cortex-capture-form__multi-header{border-bottom:1px solid #e2e8f0;background:#ffffffd9;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-form__multi-header{padding:.75rem 1.25rem}}.cortex-capture-form__multi-header-row{display:flex;align-items:flex-start;gap:.75rem}.cortex-capture-form__multi-icon{margin-top:.125rem;display:inline-flex;width:2rem;height:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;border:1px solid #e2e8f0;background:#f1f5f9;color:#475569}.cortex-capture-form__multi-icon-svg{width:1rem;height:1rem}.cortex-capture-form__multi-title-wrap{min-width:0}.cortex-capture-form__multi-title{font-size:.8125rem;font-weight:600;letter-spacing:-.01em;color:#1e293b;margin:0}.cortex-capture-form__multi-subtitle{margin-top:.125rem;font-size:.6875rem;color:#64748b;margin-bottom:0}.cortex-capture-form__multi-fields{display:grid;gap:.75rem;padding:1rem;border:0}@media(min-width:640px){.cortex-capture-form__multi-fields{padding:1.25rem}}.cortex-capture-form__multi-item{border-radius:.75rem;border:1px solid #e2e8f0;background:#fff;padding:.75rem;transition:border-color .15s}.cortex-capture-form__multi-item:hover{border-color:#cbd5e1}.cortex-capture-form__multi-item-header{margin-bottom:.5rem;display:flex;align-items:center;justify-content:space-between;gap:.5rem}.cortex-capture-form__multi-item-label{display:block;font-size:.75rem;font-weight:500;line-height:1;color:#334155}.cortex-capture-form__required-badge{display:inline-flex;align-items:center;border-radius:.25rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.125rem .375rem;font-size:.625rem;font-weight:500;text-transform:uppercase;letter-spacing:.05em;color:#64748b}.cortex-capture-form__multi-footer{display:flex;align-items:center;justify-content:flex-end;gap:.5rem;border-top:1px solid #e2e8f0;background:#ffffffe6;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-form__multi-footer{padding:.75rem 1.25rem}}.cortex-capture-form__cancel-btn{display:inline-flex;align-items:center;border-radius:.375rem;border:1px solid #cbd5e1;background:#fff;padding:.375rem .75rem;font-size:.75rem;font-weight:500;color:#475569;cursor:pointer;transition:background-color .15s}.cortex-capture-form__cancel-btn:hover{background:#f8fafc}.cortex-capture-form__cancel-btn:active{background:#f1f5f9}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
683
677
  }
684
678
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: FileInputComponent, decorators: [{
685
679
  type: Component,
686
- args: [{
687
- selector: 'cortex-file-input',
688
- template: `<div
689
- class="flex w-full cursor-pointer items-center rounded-lg border border-slate-300 bg-slate-50 transition hover:border-slate-400 focus-within:ring-2 focus-within:ring-slate-300"
690
- >
691
- <button
692
- type="button"
693
- (click)="fileInput.click()"
694
- class="m-1 shrink-0 cursor-pointer rounded-md border-0 bg-slate-800 px-3 py-1.5 text-[11px] font-semibold tracking-wide text-slate-100 hover:bg-slate-700"
695
- >
680
+ args: [{ selector: 'cortex-file-input', template: `<div class="cortex-file-input">
681
+ <button type="button" (click)="fileInput.click()" class="cortex-file-input__btn">
696
682
  {{ 'translate_choose_file' | translate }}
697
683
  </button>
698
- <span class="truncate px-3 text-[12px] text-slate-600">{{
684
+ <span class="cortex-file-input__name">{{
699
685
  value()?.name ?? ('translate_no_file_chosen' | translate)
700
686
  }}</span>
701
- <input #fileInput (change)="loadFile($event)" type="file" class="hidden" />
702
- </div>`,
703
- changeDetection: ChangeDetectionStrategy.OnPush,
704
- imports: [TranslatePipe],
705
- providers: [
687
+ <input #fileInput (change)="loadFile($event)" type="file" class="cortex-file-input__hidden" />
688
+ </div>`, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [TranslatePipe], providers: [
706
689
  {
707
690
  provide: NG_VALUE_ACCESSOR,
708
691
  multi: true,
709
692
  useExisting: forwardRef(() => FileInputComponent),
710
693
  },
711
- ],
712
- }]
694
+ ], styles: [".cortex-capture-files{display:block;width:100%}.cortex-file-input{display:flex;width:100%;cursor:pointer;align-items:center;border-radius:.5rem;border:1px solid #cbd5e1;background:#f8fafc;transition:border-color .15s}.cortex-file-input:hover{border-color:#94a3b8}.cortex-file-input:focus-within{box-shadow:0 0 0 2px #cbd5e1}.cortex-file-input__btn{margin:.25rem;flex-shrink:0;cursor:pointer;border-radius:.375rem;border:0;background:#1e293b;padding:.375rem .75rem;font-size:.6875rem;font-weight:600;letter-spacing:.025em;color:#f1f5f9}.cortex-file-input__btn:hover{background:#334155}.cortex-file-input__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:0 .75rem;font-size:.75rem;color:#475569}.cortex-file-input__hidden{display:none}.cortex-capture-success{overflow:hidden;border-radius:1rem;border:1px solid #a7f3d0;background:linear-gradient(to bottom,#ecfdf5cc,#fff)}.cortex-capture-success__header{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-success__header{padding:.75rem 1.25rem}}.cortex-capture-success__icon{display:inline-flex;width:2rem;height:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;border:1px solid #a7f3d0;background:#d1fae5;color:#059669}.cortex-capture-success__icon-svg{width:1rem;height:1rem}.cortex-capture-success__title-wrap{min-width:0}.cortex-capture-success__title{font-size:.8125rem;font-weight:600;letter-spacing:-.01em;color:#065f46;margin:0}.cortex-capture-success__file-list{border-top:1px solid #d1fae5;padding:.625rem 1rem}@media(min-width:640px){.cortex-capture-success__file-list{padding:.625rem 1.25rem}}.cortex-capture-success__files{display:flex;flex-wrap:wrap;gap:.5rem;list-style:none;margin:0;padding:0}.cortex-capture-success__download-btn{display:inline-flex;cursor:pointer;align-items:center;gap:.375rem;border-radius:.5rem;border:1px solid #d1fae5;background:#fff;padding:.375rem .625rem;font-size:.75rem;font-weight:500;color:#047857;box-shadow:0 1px 2px #0000000d;transition:all .15s}.cortex-capture-success__download-btn:hover{border-color:#a7f3d0;background:#ecfdf5;box-shadow:0 1px 3px #0000001a}.cortex-capture-success__download-btn:active{transform:scale(.97)}.cortex-capture-success__file-icon{width:.875rem;height:.875rem;flex-shrink:0;color:#6ee7b7}.cortex-capture-success__file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}.cortex-capture-success__dl-icon{width:.75rem;height:.75rem;flex-shrink:0;color:#86efac}.cortex-capture-canceled-wrap{display:flex;justify-content:center}.cortex-capture-canceled{display:inline-flex;align-items:center;gap:.625rem;border-radius:.5rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.625rem 1rem}.cortex-capture-canceled__icon{display:inline-flex;width:1.5rem;height:1.5rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.375rem;border:1px solid #e2e8f0;background:#f1f5f9;color:#94a3b8}.cortex-capture-canceled__icon-svg{width:.75rem;height:.75rem}.cortex-capture-canceled__text{font-size:.8125rem;font-weight:500;color:#94a3b8}.cortex-capture-form{width:100%}.cortex-capture-form__single{border-radius:.75rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.75rem}.cortex-capture-form__label{display:block;margin-bottom:.375rem;font-size:.75rem;color:#64748b}.cortex-capture-form__row{display:flex;align-items:center;gap:.5rem}.cortex-capture-form__input{min-width:0;flex:1}.cortex-capture-form__cancel-link{flex-shrink:0;font-size:.75rem;font-weight:500;color:#94a3b8;background:none;border:0;cursor:pointer;transition:color .15s}.cortex-capture-form__cancel-link:hover{color:#475569}.cortex-capture-form__submit-btn{display:inline-flex;flex-shrink:0;align-items:center;border-radius:.375rem;background:#1e293b;padding:.375rem .75rem;font-size:.75rem;font-weight:500;color:#f1f5f9;border:0;cursor:pointer;transition:background-color .15s}.cortex-capture-form__submit-btn:hover{background:#334155}.cortex-capture-form__submit-btn:active{background:#0f172a}.cortex-capture-form__submit-btn:disabled{cursor:not-allowed;background:#cbd5e1}.cortex-capture-form__spinner{width:.75rem;height:.75rem;margin-inline-end:.375rem;animation:cortex-capture-spin .8s linear infinite}.cortex-capture-form__spinner-track{opacity:.25}@keyframes cortex-capture-spin{to{transform:rotate(360deg)}}.cortex-capture-form__multi{overflow:hidden;border-radius:1rem;border:1px solid #e2e8f0;background:linear-gradient(to bottom,#fff,#f8fafc)}.cortex-capture-form__multi-header{border-bottom:1px solid #e2e8f0;background:#ffffffd9;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-form__multi-header{padding:.75rem 1.25rem}}.cortex-capture-form__multi-header-row{display:flex;align-items:flex-start;gap:.75rem}.cortex-capture-form__multi-icon{margin-top:.125rem;display:inline-flex;width:2rem;height:2rem;flex-shrink:0;align-items:center;justify-content:center;border-radius:.5rem;border:1px solid #e2e8f0;background:#f1f5f9;color:#475569}.cortex-capture-form__multi-icon-svg{width:1rem;height:1rem}.cortex-capture-form__multi-title-wrap{min-width:0}.cortex-capture-form__multi-title{font-size:.8125rem;font-weight:600;letter-spacing:-.01em;color:#1e293b;margin:0}.cortex-capture-form__multi-subtitle{margin-top:.125rem;font-size:.6875rem;color:#64748b;margin-bottom:0}.cortex-capture-form__multi-fields{display:grid;gap:.75rem;padding:1rem;border:0}@media(min-width:640px){.cortex-capture-form__multi-fields{padding:1.25rem}}.cortex-capture-form__multi-item{border-radius:.75rem;border:1px solid #e2e8f0;background:#fff;padding:.75rem;transition:border-color .15s}.cortex-capture-form__multi-item:hover{border-color:#cbd5e1}.cortex-capture-form__multi-item-header{margin-bottom:.5rem;display:flex;align-items:center;justify-content:space-between;gap:.5rem}.cortex-capture-form__multi-item-label{display:block;font-size:.75rem;font-weight:500;line-height:1;color:#334155}.cortex-capture-form__required-badge{display:inline-flex;align-items:center;border-radius:.25rem;border:1px solid #e2e8f0;background:#f8fafc;padding:.125rem .375rem;font-size:.625rem;font-weight:500;text-transform:uppercase;letter-spacing:.05em;color:#64748b}.cortex-capture-form__multi-footer{display:flex;align-items:center;justify-content:flex-end;gap:.5rem;border-top:1px solid #e2e8f0;background:#ffffffe6;padding:.75rem 1rem}@media(min-width:640px){.cortex-capture-form__multi-footer{padding:.75rem 1.25rem}}.cortex-capture-form__cancel-btn{display:inline-flex;align-items:center;border-radius:.375rem;border:1px solid #cbd5e1;background:#fff;padding:.375rem .75rem;font-size:.75rem;font-weight:500;color:#475569;cursor:pointer;transition:background-color .15s}.cortex-capture-form__cancel-btn:hover{background:#f8fafc}.cortex-capture-form__cancel-btn:active{background:#f1f5f9}\n"] }]
713
695
  }], propDecorators: { allowedMimeTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowedMimeTypes", required: false }] }] } });
714
696
  async function convertFileToBase64(file) {
715
697
  return new Promise((resolve, reject) => {
@@ -790,21 +772,21 @@ class MessageToolCallAnimatedComponent {
790
772
  return Math.abs(hash) % STATUS_COUNT;
791
773
  }, ...(ngDevMode ? [{ debugName: "stableIndex" }] : /* istanbul ignore next */ []));
792
774
  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 });
775
+ 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: "cortex-tool-call-animated" }, 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=\"cortex-tool-pill-wrap\">\n <div\n class=\"cortex-tool-pill\"\n [class.cortex-tool-pill--active]=\"active\"\n [class.cortex-tool-pill--complete]=\"state === 'complete'\"\n [class.cortex-tool-pill--error]=\"state === 'error'\"\n [class.cortex-tool-pill--denied]=\"state === 'denied'\"\n >\n <!-- Icon box -->\n <div\n class=\"cortex-tool-pill__icon\"\n [class.cortex-tool-pill__icon--active]=\"active\"\n [class.cortex-tool-pill__icon--complete]=\"state === 'complete'\"\n [class.cortex-tool-pill__icon--error]=\"state === 'error'\"\n [class.cortex-tool-pill__icon--denied]=\"state === 'denied'\"\n >\n <!-- Spinner -->\n <div\n class=\"cortex-tool-pill__spinner\"\n [class.cortex-tool-pill__spinner--visible]=\"active\"\n ></div>\n <!-- Check -->\n <svg\n class=\"cortex-tool-pill__svg\"\n [class.cortex-tool-pill__svg--visible]=\"state === 'complete'\"\n [class.cortex-tool-pill__svg--check]=\"state === 'complete'\"\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=\"cortex-tool-pill__svg\"\n [class.cortex-tool-pill__svg--visible]=\"state === 'error'\"\n [class.cortex-tool-pill__svg--error]=\"state === 'error'\"\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=\"cortex-tool-pill__svg\"\n [class.cortex-tool-pill__svg--visible]=\"state === 'denied'\"\n [class.cortex-tool-pill__svg--denied]=\"state === 'denied'\"\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=\"cortex-tool-pill__title\"\n [class.cortex-tool-pill__title--active]=\"active\"\n [class.cortex-tool-pill__title--complete]=\"state === 'complete'\"\n [class.cortex-tool-pill__title--error]=\"state === 'error'\"\n [class.cortex-tool-pill__title--denied]=\"state === 'denied'\"\n >\n {{ displayTitleKey() | translate }}\n </span>\n\n <!-- Bottom bar -->\n <div class=\"cortex-tool-pill__bar-track\">\n <div\n class=\"cortex-tool-pill__bar\"\n [class.cortex-tool-pill__bar--active]=\"active\"\n [class.cortex-tool-pill__bar--complete]=\"state === 'complete'\"\n [class.cortex-tool-pill__bar--error]=\"state === 'error'\"\n [class.cortex-tool-pill__bar--denied]=\"state === 'denied'\"\n ></div>\n </div>\n </div>\n </div>\n }\n }\n}\n", styles: [".cortex-tool-call-animated{display:block;width:100%}.cortex-tool-pill-wrap{display:flex;justify-content:center}.cortex-tool-pill{display:inline-flex;align-items:center;gap:.625rem;padding:.625rem 1rem;border-radius:.5rem;border:1px solid;position:relative;overflow:hidden;transition:background-color .3s,border-color .3s}.cortex-tool-pill--active{border-color:#c7d2fe;background:#eef2ff}.cortex-tool-pill--complete{border-color:#a7f3d0;background:#ecfdf5}.cortex-tool-pill--error{border-color:#fecaca;background:#fef2f2}.cortex-tool-pill--denied{border-color:#e2e8f0;background:#f8fafc;opacity:.6}.cortex-tool-pill__icon{position:relative;width:1.5rem;height:1.5rem;display:flex;align-items:center;justify-content:center;border-radius:.375rem;border:1px solid;flex-shrink:0;transition:background-color .3s,border-color .3s}.cortex-tool-pill__icon--active{background:#e0e7ff;border-color:#c7d2fe}.cortex-tool-pill__icon--complete{background:#d1fae5;border-color:#a7f3d0}.cortex-tool-pill__icon--error{background:#fee2e2;border-color:#fecaca}.cortex-tool-pill__icon--denied{background:#f1f5f9;border-color:#e2e8f0}.cortex-tool-pill__spinner{position:absolute;width:.75rem;height:.75rem;border:1.5px solid #c7d2fe;border-top-color:#6366f1;border-radius:9999px;opacity:0;transition:opacity .2s}.cortex-tool-pill__spinner--visible{opacity:1;animation:cortex-tool-spin .8s linear infinite}@keyframes cortex-tool-spin{to{transform:rotate(360deg)}}.cortex-tool-pill__svg{position:absolute;width:.75rem;height:.75rem;opacity:0;transform:scale(.6);transition:opacity .2s,transform .2s}.cortex-tool-pill__svg--visible{opacity:1;transform:scale(1)}.cortex-tool-pill__svg--check{color:#059669}.cortex-tool-pill__svg--error{color:#dc2626}.cortex-tool-pill__svg--denied{color:#94a3b8}.cortex-tool-pill__title{font-size:.8125rem;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .3s}.cortex-tool-pill__title--active{color:#4338ca}.cortex-tool-pill__title--complete{color:#047857}.cortex-tool-pill__title--error{color:#dc2626}.cortex-tool-pill__title--denied{color:#94a3b8}.cortex-tool-pill__bar-track{position:absolute;bottom:0;left:0;right:0;height:2px;overflow:hidden}.cortex-tool-pill__bar{height:100%;width:100%;transform-origin:left}.cortex-tool-pill__bar--active{background:#818cf8;animation:cortex-bar-slide 1.5s ease-in-out infinite}.cortex-tool-pill__bar--complete{background:#34d399;animation:cortex-bar-fill .3s ease-out both}.cortex-tool-pill__bar--error{background:#f87171;animation:cortex-bar-fill .3s ease-out both}.cortex-tool-pill__bar--denied{opacity:0}@keyframes cortex-bar-slide{0%{transform:translate(-100%)}to{transform:translate(100%)}}@keyframes cortex-bar-fill{0%{transform:scaleX(0)}to{transform:scaleX(1)}}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: MessageCaptureFilesPartComponent, selector: "cortex-message-capture-files-part", inputs: ["message", "toolPart"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
794
776
  }
795
777
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageToolCallAnimatedComponent, decorators: [{
796
778
  type: Component,
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"] }]
779
+ args: [{ selector: 'cortex-message-tool-call-animated', imports: [NgComponentOutlet, MessageCaptureFilesPartComponent, TranslatePipe], host: { class: 'cortex-tool-call-animated' }, encapsulation: ViewEncapsulation.None, 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=\"cortex-tool-pill-wrap\">\n <div\n class=\"cortex-tool-pill\"\n [class.cortex-tool-pill--active]=\"active\"\n [class.cortex-tool-pill--complete]=\"state === 'complete'\"\n [class.cortex-tool-pill--error]=\"state === 'error'\"\n [class.cortex-tool-pill--denied]=\"state === 'denied'\"\n >\n <!-- Icon box -->\n <div\n class=\"cortex-tool-pill__icon\"\n [class.cortex-tool-pill__icon--active]=\"active\"\n [class.cortex-tool-pill__icon--complete]=\"state === 'complete'\"\n [class.cortex-tool-pill__icon--error]=\"state === 'error'\"\n [class.cortex-tool-pill__icon--denied]=\"state === 'denied'\"\n >\n <!-- Spinner -->\n <div\n class=\"cortex-tool-pill__spinner\"\n [class.cortex-tool-pill__spinner--visible]=\"active\"\n ></div>\n <!-- Check -->\n <svg\n class=\"cortex-tool-pill__svg\"\n [class.cortex-tool-pill__svg--visible]=\"state === 'complete'\"\n [class.cortex-tool-pill__svg--check]=\"state === 'complete'\"\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=\"cortex-tool-pill__svg\"\n [class.cortex-tool-pill__svg--visible]=\"state === 'error'\"\n [class.cortex-tool-pill__svg--error]=\"state === 'error'\"\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=\"cortex-tool-pill__svg\"\n [class.cortex-tool-pill__svg--visible]=\"state === 'denied'\"\n [class.cortex-tool-pill__svg--denied]=\"state === 'denied'\"\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=\"cortex-tool-pill__title\"\n [class.cortex-tool-pill__title--active]=\"active\"\n [class.cortex-tool-pill__title--complete]=\"state === 'complete'\"\n [class.cortex-tool-pill__title--error]=\"state === 'error'\"\n [class.cortex-tool-pill__title--denied]=\"state === 'denied'\"\n >\n {{ displayTitleKey() | translate }}\n </span>\n\n <!-- Bottom bar -->\n <div class=\"cortex-tool-pill__bar-track\">\n <div\n class=\"cortex-tool-pill__bar\"\n [class.cortex-tool-pill__bar--active]=\"active\"\n [class.cortex-tool-pill__bar--complete]=\"state === 'complete'\"\n [class.cortex-tool-pill__bar--error]=\"state === 'error'\"\n [class.cortex-tool-pill__bar--denied]=\"state === 'denied'\"\n ></div>\n </div>\n </div>\n </div>\n }\n }\n}\n", styles: [".cortex-tool-call-animated{display:block;width:100%}.cortex-tool-pill-wrap{display:flex;justify-content:center}.cortex-tool-pill{display:inline-flex;align-items:center;gap:.625rem;padding:.625rem 1rem;border-radius:.5rem;border:1px solid;position:relative;overflow:hidden;transition:background-color .3s,border-color .3s}.cortex-tool-pill--active{border-color:#c7d2fe;background:#eef2ff}.cortex-tool-pill--complete{border-color:#a7f3d0;background:#ecfdf5}.cortex-tool-pill--error{border-color:#fecaca;background:#fef2f2}.cortex-tool-pill--denied{border-color:#e2e8f0;background:#f8fafc;opacity:.6}.cortex-tool-pill__icon{position:relative;width:1.5rem;height:1.5rem;display:flex;align-items:center;justify-content:center;border-radius:.375rem;border:1px solid;flex-shrink:0;transition:background-color .3s,border-color .3s}.cortex-tool-pill__icon--active{background:#e0e7ff;border-color:#c7d2fe}.cortex-tool-pill__icon--complete{background:#d1fae5;border-color:#a7f3d0}.cortex-tool-pill__icon--error{background:#fee2e2;border-color:#fecaca}.cortex-tool-pill__icon--denied{background:#f1f5f9;border-color:#e2e8f0}.cortex-tool-pill__spinner{position:absolute;width:.75rem;height:.75rem;border:1.5px solid #c7d2fe;border-top-color:#6366f1;border-radius:9999px;opacity:0;transition:opacity .2s}.cortex-tool-pill__spinner--visible{opacity:1;animation:cortex-tool-spin .8s linear infinite}@keyframes cortex-tool-spin{to{transform:rotate(360deg)}}.cortex-tool-pill__svg{position:absolute;width:.75rem;height:.75rem;opacity:0;transform:scale(.6);transition:opacity .2s,transform .2s}.cortex-tool-pill__svg--visible{opacity:1;transform:scale(1)}.cortex-tool-pill__svg--check{color:#059669}.cortex-tool-pill__svg--error{color:#dc2626}.cortex-tool-pill__svg--denied{color:#94a3b8}.cortex-tool-pill__title{font-size:.8125rem;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:color .3s}.cortex-tool-pill__title--active{color:#4338ca}.cortex-tool-pill__title--complete{color:#047857}.cortex-tool-pill__title--error{color:#dc2626}.cortex-tool-pill__title--denied{color:#94a3b8}.cortex-tool-pill__bar-track{position:absolute;bottom:0;left:0;right:0;height:2px;overflow:hidden}.cortex-tool-pill__bar{height:100%;width:100%;transform-origin:left}.cortex-tool-pill__bar--active{background:#818cf8;animation:cortex-bar-slide 1.5s ease-in-out infinite}.cortex-tool-pill__bar--complete{background:#34d399;animation:cortex-bar-fill .3s ease-out both}.cortex-tool-pill__bar--error{background:#f87171;animation:cortex-bar-fill .3s ease-out both}.cortex-tool-pill__bar--denied{opacity:0}@keyframes cortex-bar-slide{0%{transform:translate(-100%)}to{transform:translate(100%)}}@keyframes cortex-bar-fill{0%{transform:scaleX(0)}to{transform:scaleX(1)}}\n"] }]
798
780
  }], propDecorators: { message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: true }] }], toolCallPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolCallPart", required: true }] }] } });
799
781
 
800
782
  class MessageReasoningAnimatedComponent {
801
783
  reasoningPart = input.required(...(ngDevMode ? [{ debugName: "reasoningPart" }] : /* istanbul ignore next */ []));
802
784
  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 });
785
+ 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: "cortex-reasoning-animated" }, ngImport: i0, template: "@let p = reasoningPart();\n@let streaming = p.state === 'streaming';\n\n<div\n class=\"cortex-reasoning-pill\"\n [class.cortex-reasoning-pill--streaming]=\"streaming\"\n [class.cortex-reasoning-pill--done]=\"!streaming\"\n>\n <div class=\"cortex-reasoning-pill__dots\">\n <span class=\"cortex-reasoning-dot\" [class.cortex-reasoning-dot--active]=\"streaming\"></span>\n <span\n class=\"cortex-reasoning-dot\"\n [class.cortex-reasoning-dot--active]=\"streaming\"\n [style.animation-delay]=\"streaming ? '200ms' : '0ms'\"\n ></span>\n <span\n class=\"cortex-reasoning-dot\"\n [class.cortex-reasoning-dot--active]=\"streaming\"\n [style.animation-delay]=\"streaming ? '400ms' : '0ms'\"\n ></span>\n <span\n class=\"cortex-reasoning-dot\"\n [class.cortex-reasoning-dot--active]=\"streaming\"\n [style.animation-delay]=\"streaming ? '600ms' : '0ms'\"\n ></span>\n </div>\n\n <span\n class=\"cortex-reasoning-pill__text\"\n [class.cortex-reasoning-pill__text--streaming]=\"streaming\"\n [class.cortex-reasoning-pill__text--done]=\"!streaming\"\n >\n {{ streaming ? ('translate_thinking' | translate) : ('translate_reasoned' | translate) }}\n </span>\n</div>\n", styles: [".cortex-reasoning-animated{display:flex;justify-content:center}.cortex-reasoning-pill{display:inline-flex;align-items:center;gap:.625rem;padding:.5rem 1rem .5rem .75rem;border-radius:.5rem;border:1px solid;transition:background-color .3s,border-color .3s}.cortex-reasoning-pill--streaming{border-color:#c7d2fe;background:#eef2ff}.cortex-reasoning-pill--done{border-color:#e2e8f0;background:#f8fafc}.cortex-reasoning-pill__dots{display:flex;align-items:center;gap:.25rem}.cortex-reasoning-dot{width:5px;height:5px;border-radius:9999px;transition:all .4s;background:#cbd5e1;opacity:.4}.cortex-reasoning-dot--active{background:#a5b4fc;opacity:1;animation:cortex-reasoning-dot-pulse 1.4s ease-in-out infinite}@keyframes cortex-reasoning-dot-pulse{0%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1.3);background-color:#6366f1}}.cortex-reasoning-pill__text{font-size:.8125rem;font-weight:500;transition:color .3s}.cortex-reasoning-pill__text--streaming{color:#4f46e5}.cortex-reasoning-pill__text--done{color:#94a3b8}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
804
786
  }
805
787
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageReasoningAnimatedComponent, decorators: [{
806
788
  type: Component,
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"] }]
789
+ args: [{ selector: 'cortex-message-reasoning-animated', imports: [TranslatePipe], host: { class: 'cortex-reasoning-animated' }, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let p = reasoningPart();\n@let streaming = p.state === 'streaming';\n\n<div\n class=\"cortex-reasoning-pill\"\n [class.cortex-reasoning-pill--streaming]=\"streaming\"\n [class.cortex-reasoning-pill--done]=\"!streaming\"\n>\n <div class=\"cortex-reasoning-pill__dots\">\n <span class=\"cortex-reasoning-dot\" [class.cortex-reasoning-dot--active]=\"streaming\"></span>\n <span\n class=\"cortex-reasoning-dot\"\n [class.cortex-reasoning-dot--active]=\"streaming\"\n [style.animation-delay]=\"streaming ? '200ms' : '0ms'\"\n ></span>\n <span\n class=\"cortex-reasoning-dot\"\n [class.cortex-reasoning-dot--active]=\"streaming\"\n [style.animation-delay]=\"streaming ? '400ms' : '0ms'\"\n ></span>\n <span\n class=\"cortex-reasoning-dot\"\n [class.cortex-reasoning-dot--active]=\"streaming\"\n [style.animation-delay]=\"streaming ? '600ms' : '0ms'\"\n ></span>\n </div>\n\n <span\n class=\"cortex-reasoning-pill__text\"\n [class.cortex-reasoning-pill__text--streaming]=\"streaming\"\n [class.cortex-reasoning-pill__text--done]=\"!streaming\"\n >\n {{ streaming ? ('translate_thinking' | translate) : ('translate_reasoned' | translate) }}\n </span>\n</div>\n", styles: [".cortex-reasoning-animated{display:flex;justify-content:center}.cortex-reasoning-pill{display:inline-flex;align-items:center;gap:.625rem;padding:.5rem 1rem .5rem .75rem;border-radius:.5rem;border:1px solid;transition:background-color .3s,border-color .3s}.cortex-reasoning-pill--streaming{border-color:#c7d2fe;background:#eef2ff}.cortex-reasoning-pill--done{border-color:#e2e8f0;background:#f8fafc}.cortex-reasoning-pill__dots{display:flex;align-items:center;gap:.25rem}.cortex-reasoning-dot{width:5px;height:5px;border-radius:9999px;transition:all .4s;background:#cbd5e1;opacity:.4}.cortex-reasoning-dot--active{background:#a5b4fc;opacity:1;animation:cortex-reasoning-dot-pulse 1.4s ease-in-out infinite}@keyframes cortex-reasoning-dot-pulse{0%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1.3);background-color:#6366f1}}.cortex-reasoning-pill__text{font-size:.8125rem;font-weight:500;transition:color .3s}.cortex-reasoning-pill__text--streaming{color:#4f46e5}.cortex-reasoning-pill__text--done{color:#94a3b8}\n"] }]
808
790
  }], propDecorators: { reasoningPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "reasoningPart", required: true }] }] } });
809
791
 
810
792
  class MessagePartComponent {
@@ -822,7 +804,7 @@ class MessagePartComponent {
822
804
  return toolName ? (this.config.toolComponents?.[toolName] ?? null) : null;
823
805
  }, ...(ngDevMode ? [{ debugName: "customToolComponent" }] : /* istanbul ignore next */ []));
824
806
  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 });
807
+ 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.cortex-message-part--animated": "animate()" }, classAttribute: "cortex-message-part" }, 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=\"cortex-unhandled-type\">Unhandled type: {{ part().type }}</p>\n }\n }\n}\n", styles: [".cortex-message-part{display:block}.cortex-message-part:empty{display:none}.cortex-message-part--animated{animation:cortex-part-fade-in-up .2s cubic-bezier(.34,1.56,.64,1) both}@keyframes cortex-part-fade-in-up{0%{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}.cortex-unhandled-type{text-align:center;font-size:.75rem;color:#94a3b8}\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, encapsulation: i0.ViewEncapsulation.None });
826
808
  }
827
809
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessagePartComponent, decorators: [{
828
810
  type: Component,
@@ -832,9 +814,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImpor
832
814
  MessageToolCallPartComponent,
833
815
  MessageToolCallAnimatedComponent,
834
816
  MessageReasoningAnimatedComponent,
835
- ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
836
- '[class.animate-part-enter]': 'animate()',
837
- }, 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"] }]
817
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
818
+ class: 'cortex-message-part',
819
+ '[class.cortex-message-part--animated]': 'animate()',
820
+ }, 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=\"cortex-unhandled-type\">Unhandled type: {{ part().type }}</p>\n }\n }\n}\n", styles: [".cortex-message-part{display:block}.cortex-message-part:empty{display:none}.cortex-message-part--animated{animation:cortex-part-fade-in-up .2s cubic-bezier(.34,1.56,.64,1) both}@keyframes cortex-part-fade-in-up{0%{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}.cortex-unhandled-type{text-align:center;font-size:.75rem;color:#94a3b8}\n"] }]
838
821
  }], 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
822
 
840
823
  class MessageComponent {
@@ -874,11 +857,11 @@ class MessageComponent {
874
857
  });
875
858
  }
876
859
  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 });
860
+ 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 } }, host: { classAttribute: "cortex-message" }, ngImport: i0, template: "@if (visibleParts().length) {\n <div class=\"cortex-message-parts\">\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: [".cortex-message:empty{display:none}.cortex-message-parts{width:100%;display:flex;flex-direction:column;gap:.5rem}\n"], dependencies: [{ kind: "component", type: MessagePartComponent, selector: "cortex-message-part", inputs: ["message", "part", "debugMode", "animate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
878
861
  }
879
862
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageComponent, decorators: [{
880
863
  type: Component,
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"] }]
864
+ args: [{ selector: 'cortex-message', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [MessagePartComponent], host: { class: 'cortex-message' }, template: "@if (visibleParts().length) {\n <div class=\"cortex-message-parts\">\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: [".cortex-message:empty{display:none}.cortex-message-parts{width:100%;display:flex;flex-direction:column;gap:.5rem}\n"] }]
882
865
  }], 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
866
 
884
867
  class MessageListComponent {
@@ -931,11 +914,11 @@ class MessageListComponent {
931
914
  }
932
915
  }
933
916
  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 });
917
+ 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 class=\"cortex-message-list\" #messagesContainer (scroll)=\"onScroll()\">\n @for (message of chatService.chat()?.messages; track message.id) {\n <cortex-message [message]=\"message\" [debugMode]=\"debugMode()\" [animate]=\"animateNewParts()\" />\n }\n</div>\n", styles: [".cortex-message-list{height:100%;overflow-y:auto;width:100%;display:flex;flex-direction:column;gap:.5rem;padding:1rem}\n"], dependencies: [{ kind: "component", type: MessageComponent, selector: "cortex-message", inputs: ["message", "debugMode", "animate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
935
918
  }
936
919
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: MessageListComponent, decorators: [{
937
920
  type: Component,
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" }]
921
+ args: [{ selector: 'cortex-message-list', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [MessageComponent], template: "<div class=\"cortex-message-list\" #messagesContainer (scroll)=\"onScroll()\">\n @for (message of chatService.chat()?.messages; track message.id) {\n <cortex-message [message]=\"message\" [debugMode]=\"debugMode()\" [animate]=\"animateNewParts()\" />\n }\n</div>\n", styles: [".cortex-message-list{height:100%;overflow-y:auto;width:100%;display:flex;flex-direction:column;gap:.5rem;padding:1rem}\n"] }]
939
922
  }], 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 }] }] } });
940
923
 
941
924
  var translate_new$1 = "New";
@@ -1148,13 +1131,11 @@ class CortexChatWidgetComponent {
1148
1131
  text = model('', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
1149
1132
  debugMode = signal(false, ...(ngDevMode ? [{ debugName: "debugMode" }] : /* istanbul ignore next */ []));
1150
1133
  screen = signal('threads', ...(ngDevMode ? [{ debugName: "screen" }] : /* istanbul ignore next */ []));
1151
- theme = signal(undefined, ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
1152
1134
  chatService;
1153
1135
  configRef = inject(CortexClientConfigRef);
1154
1136
  injector = inject(Injector);
1155
1137
  ngOnInit() {
1156
1138
  this.configRef.config = this.config();
1157
- this.theme.set(this.config().theme);
1158
1139
  this.chatService = this.injector.get(CortexChatService);
1159
1140
  const translateService = this.injector.get(TranslateService);
1160
1141
  translateService.use(this.config().locale);
@@ -1190,7 +1171,7 @@ class CortexChatWidgetComponent {
1190
1171
  this.screen.set('chat');
1191
1172
  }
1192
1173
  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: [
1174
+ 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: { classAttribute: "cortex-widget" }, providers: [
1194
1175
  CortexClientConfigRef,
1195
1176
  {
1196
1177
  provide: CORTEX_CLIENT_CONFIG,
@@ -1202,11 +1183,11 @@ class CortexChatWidgetComponent {
1202
1183
  fallbackLang: 'en',
1203
1184
  loader: provideTranslateLoader(CortexClientTranslateLoader),
1204
1185
  }),
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 });
1186
+ ], ngImport: i0, template: "<div class=\"cortex-widget__container\">\n <!-- SCREEN 1: THREADS -->\n <div\n class=\"cortex-widget__screen\"\n [class.cortex-widget__screen--active]=\"screen() === 'threads'\"\n [class.cortex-widget__screen--left]=\"screen() !== 'threads'\"\n >\n <!-- Threads header -->\n <div class=\"cortex-widget__threads-header\">\n <div>\n <h2 class=\"cortex-widget__threads-title\">\n {{ 'translate_threads' | translate }}\n </h2>\n <p class=\"cortex-widget__threads-count\">\n {{\n 'translate_n_conversations' | translate: { count: chatService.threads()?.length ?? 0 }\n }}\n </p>\n </div>\n <button (click)=\"newChat()\" class=\"cortex-widget__new-chat-btn\">\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=\"cortex-widget__threads-list\">\n <!-- Threads loading skeleton -->\n @if (chatService.threads() === undefined) {\n @for (i of [1, 2, 3, 4]; track i) {\n <div class=\"cortex-widget__thread-skeleton\">\n <div class=\"cortex-skeleton cortex-widget__thread-skeleton-icon\"></div>\n <div class=\"cortex-widget__thread-skeleton-lines\">\n <div\n class=\"cortex-skeleton cortex-widget__thread-skeleton-line\"\n [style.width]=\"40 + i * 12 + '%'\"\n ></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=\"cortex-widget__thread-item\"\n [class.cortex-widget__thread-item--active]=\"\n thread.id === chatService.selectedThread()?.id\n \"\n >\n <!-- Thread icon -->\n <div\n class=\"cortex-widget__thread-icon\"\n [class.cortex-widget__thread-icon--active]=\"\n 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=\"cortex-widget__thread-info\">\n <p\n class=\"cortex-widget__thread-title\"\n [class.cortex-widget__thread-title--active]=\"\n 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=\"cortex-widget__thread-delete\"\n [class.cortex-widget__thread-delete--active]=\"\n 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=\"cortex-widget__thread-arrow\"\n [class.cortex-widget__thread-arrow--active]=\"\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=\"cortex-widget__threads-empty\">\n <div class=\"cortex-widget__threads-empty-icon\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"cortex-widget__threads-empty-svg\"\n >\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=\"cortex-widget__threads-empty-title\">No threads yet</p>\n <p class=\"cortex-widget__threads-empty-subtitle\">Start a new conversation</p>\n </div>\n }\n }\n </div>\n </div>\n\n <!-- SCREEN 2: CHAT -->\n <div\n class=\"cortex-widget__screen\"\n [class.cortex-widget__screen--active]=\"screen() === 'chat'\"\n [class.cortex-widget__screen--right]=\"screen() !== 'chat'\"\n >\n <!-- Chat header -->\n <div class=\"cortex-widget__chat-header\">\n <!-- Back button -->\n <button (click)=\"goBack()\" class=\"cortex-widget__back-btn\">\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"cortex-widget__back-icon\"\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=\"cortex-widget__chat-title-wrap\">\n <p class=\"cortex-widget__chat-title\">\n {{ chatService.selectedThread()?.title ?? ('translate_new_chat' | translate) }}\n </p>\n </div>\n\n <!-- Debug toggle -->\n <button\n (click)=\"toggleDebugMode()\"\n class=\"cortex-widget__debug-btn\"\n [class.cortex-widget__debug-btn--on]=\"debugMode()\"\n [class.cortex-widget__debug-btn--off]=\"!debugMode()\"\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=\"cortex-widget__messages-skeleton\">\n <!-- User message skeleton -->\n <div class=\"cortex-widget__msg-skel cortex-widget__msg-skel--user\">\n <div class=\"cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--user\">\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 13rem\"></div>\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 9rem\"></div>\n </div>\n </div>\n <!-- Assistant message skeleton -->\n <div class=\"cortex-widget__msg-skel cortex-widget__msg-skel--assistant\">\n <div class=\"cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--assistant\">\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 16rem\"></div>\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 18rem\"></div>\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 12rem\"></div>\n </div>\n </div>\n <!-- User message skeleton -->\n <div class=\"cortex-widget__msg-skel cortex-widget__msg-skel--user\">\n <div class=\"cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--user\">\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 11rem\"></div>\n </div>\n </div>\n <!-- Assistant message skeleton -->\n <div class=\"cortex-widget__msg-skel cortex-widget__msg-skel--assistant\">\n <div class=\"cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--assistant\">\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 14rem\"></div>\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 15rem\"></div>\n </div>\n </div>\n </div>\n } @else {\n <!-- Messages area -->\n <cortex-message-list class=\"cortex-widget__messages\" [debugMode]=\"debugMode()\" />\n }\n\n <!-- Agent working indicator -->\n @if (chatService.isAgentWorking() && !chatService.hasPendingToolCalls()) {\n <div class=\"cortex-widget__working\">\n <div class=\"cortex-widget__working-dots\">\n <span class=\"cortex-working-dot\"></span>\n <span class=\"cortex-working-dot\"></span>\n <span class=\"cortex-working-dot\"></span>\n </div>\n <span class=\"cortex-widget__working-text\">{{ 'translate_thinking' | translate }}</span>\n </div>\n }\n\n <!-- Chat input (hidden during pending tool calls) -->\n @if (!chatService.hasPendingToolCalls()) {\n <div class=\"cortex-widget__input-area\">\n <div\n class=\"cortex-widget__input-box\"\n [class.cortex-widget__input-box--disabled]=\"chatService.isAgentWorking()\"\n [class.cortex-widget__input-box--enabled]=\"!chatService.isAgentWorking()\"\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=\"cortex-widget__textarea\"\n [class.cortex-widget__textarea--disabled]=\"chatService.isAgentWorking()\"\n ></textarea>\n @if (chatService.isAgentWorking()) {\n <!-- Stop button -->\n <button (click)=\"chatService.abort()\" class=\"cortex-stop-btn\">\n <!-- Pulsing ring -->\n <span class=\"cortex-stop-btn__ring\"></span>\n <!-- Stop icon (rounded square) -->\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n class=\"cortex-stop-btn__icon\"\n >\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=\"cortex-widget__send-btn\"\n [class.cortex-widget__send-btn--empty]=\"!text().trim()\"\n [class.cortex-widget__send-btn--ready]=\"!!text().trim()\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"cortex-widget__send-icon\"\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: [".cortex-widget{display:block}.cortex-widget__container{width:100%;height:100%;position:relative;overflow:hidden}.cortex-widget__screen{position:absolute;inset:0;display:flex;flex-direction:column;transition:transform .3s ease-out}.cortex-widget__screen--active{transform:translate(0)}.cortex-widget__screen--left{transform:translate(-100%)}[dir=rtl] .cortex-widget__screen--left,.cortex-widget__screen--right{transform:translate(100%)}[dir=rtl] .cortex-widget__screen--right{transform:translate(-100%)}.cortex-widget__threads-header{flex-shrink:0;padding:1.25rem 1.25rem 1rem;display:flex;align-items:center;justify-content:space-between}.cortex-widget__threads-title{font-size:.9375rem;font-weight:600;color:#1e293b;letter-spacing:-.01em;margin:0}.cortex-widget__threads-count{font-size:.6875rem;color:#94a3b8;margin-top:.125rem;margin-bottom:0}.cortex-widget__new-chat-btn{display:inline-flex;align-items:center;gap:.375rem;font-size:.75rem;font-weight:500;color:#f1f5f9;background:#1e293b;padding:.375rem .75rem;border-radius:.375rem;border:0;cursor:pointer;transition:background-color .15s}.cortex-widget__new-chat-btn:hover{background:#334155}.cortex-widget__new-chat-btn:active{background:#0f172a}.cortex-widget__threads-list{flex:1;overflow-y:auto;padding:0 .75rem .75rem}.cortex-widget__thread-skeleton{display:flex;align-items:center;gap:.75rem;padding:.75rem;margin-bottom:.125rem}.cortex-widget__thread-skeleton-icon{flex-shrink:0;width:2rem;height:2rem}.cortex-widget__thread-skeleton-lines{flex:1;display:flex;flex-direction:column;gap:.375rem}.cortex-widget__thread-skeleton-line{height:.875rem}@keyframes cortex-skeleton-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.cortex-skeleton{background:linear-gradient(90deg,#e2e8f0,#f1f5f9,#e2e8f0 80%);background-size:200% 100%;animation:cortex-skeleton-shimmer 1.8s ease-in-out infinite;border-radius:6px}.cortex-widget__thread-item{width:100%;text-align:start;padding:.75rem;border-radius:.5rem;display:flex;align-items:center;gap:.75rem;transition:background-color .15s;cursor:pointer;margin-bottom:.125rem;border:0;background:transparent;color:#475569}.cortex-widget__thread-item:hover{background:#f1f5f9}.cortex-widget__thread-item:active{background:#e8ecf1}.cortex-widget__thread-item--active{background:#e2e8f0;color:#f1f5f9}.cortex-widget__thread-icon{flex-shrink:0;width:2rem;height:2rem;border-radius:.375rem;display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:600;background:#e2e8f0;color:#64748b}[dir=rtl] .cortex-widget__thread-icon{transform:rotate(180deg)}.cortex-widget__thread-icon--active{background:#334155;color:#cbd5e1}.cortex-widget__thread-info{min-width:0;flex:1}.cortex-widget__thread-title{font-size:.8125rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.25;margin:0;color:#334155}.cortex-widget__thread-title--active{color:#f1f5f9}.cortex-widget__thread-delete{flex-shrink:0;opacity:0;width:1.75rem;height:1.75rem;border-radius:.375rem;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:opacity .15s;background:transparent;border:0;color:#94a3b8}.cortex-widget__thread-item:hover>.cortex-widget__thread-delete{opacity:1}.cortex-widget__thread-delete:hover{background:#e2e8f0}.cortex-widget__thread-delete--active:hover{background:#475569}.cortex-widget__thread-arrow{flex-shrink:0;transition:color .15s;color:#cbd5e1}[dir=rtl] .cortex-widget__thread-arrow{transform:rotate(180deg)}.cortex-widget__thread-item:hover>.cortex-widget__thread-arrow{color:#94a3b8}.cortex-widget__thread-arrow--active{color:#64748b}.cortex-widget__threads-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:4rem 0;text-align:center}.cortex-widget__threads-empty-icon{width:2.5rem;height:2.5rem;border-radius:.5rem;background:#e2e8f0;display:flex;align-items:center;justify-content:center;margin-bottom:.75rem}.cortex-widget__threads-empty-svg{color:#94a3b8}.cortex-widget__threads-empty-title{font-size:.8125rem;color:#94a3b8;font-weight:500;margin:0}.cortex-widget__threads-empty-subtitle{font-size:.6875rem;color:#a5afbd;margin-top:.25rem;margin-bottom:0}.cortex-widget__chat-header{flex-shrink:0;height:3rem;padding:0 1rem;display:flex;align-items:center;gap:.75rem;border-bottom:1px solid #e2e8f0;background:#fff}.cortex-widget__back-btn{flex-shrink:0;width:2rem;height:2rem;border-radius:.375rem;display:flex;align-items:center;justify-content:center;color:#94a3b8;background:transparent;border:0;cursor:pointer;transition:color .15s,background-color .15s}.cortex-widget__back-btn:hover{color:#475569;background:#f1f5f9}[dir=rtl] .cortex-widget__back-icon{transform:rotate(180deg)}.cortex-widget__chat-title-wrap{min-width:0;flex:1}.cortex-widget__chat-title{font-size:.8125rem;font-weight:500;color:#334155;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin:0}.cortex-widget__debug-btn{flex-shrink:0;font-size:.6875rem;font-weight:500;padding:.25rem .625rem;border-radius:.375rem;border:0;cursor:pointer;transition:background-color .15s}.cortex-widget__debug-btn--on{background:#fef3c7;color:#d97706}.cortex-widget__debug-btn--on:hover{background:#fde68a}.cortex-widget__debug-btn--off{background:#f1f5f9;color:#94a3b8}.cortex-widget__debug-btn--off:hover{background:#e2e8f0}.cortex-widget__messages-skeleton{flex:1;overflow:hidden;padding:1rem;display:flex;flex-direction:column;gap:.5rem}.cortex-widget__msg-skel{width:100%;display:flex;flex-direction:column}.cortex-widget__msg-skel--user{align-items:flex-start}.cortex-widget__msg-skel--assistant{align-items:flex-end}.cortex-widget__msg-skel-bubble{max-width:80%;padding:1rem;border-radius:1rem;border:1px solid #e2e8f0;display:flex;flex-direction:column;gap:.5rem}.cortex-widget__msg-skel-bubble--user{background:#f8fafc;border-bottom-left-radius:0}.cortex-widget__msg-skel-bubble--assistant{background:#f1f5f9;border-bottom-right-radius:0}.cortex-widget__msg-skel-line{height:.75rem}.cortex-widget__messages{flex:1;overflow:hidden}.cortex-widget__working{flex-shrink:0;padding:.375rem 1rem;display:flex;align-items:center;gap:.375rem}.cortex-widget__working-dots{display:flex;align-items:center;gap:3px}@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{display:block;width:5px;height:5px;border-radius:9999px;background:#94a3b8;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}.cortex-widget__working-text{font-size:.6875rem;color:#94a3b8;font-weight:500}.cortex-widget__input-area{flex-shrink:0;padding:.75rem;background:#fff;border-top:1px solid #e2e8f0}.cortex-widget__input-box{display:flex;align-items:flex-end;gap:.5rem;border-radius:.75rem;border:1px solid #e2e8f0;padding:.375rem;transition:border-color .15s,background-color .15s}.cortex-widget__input-box--disabled{background:#f1f5f9}.cortex-widget__input-box--enabled{background:#f8fafc}.cortex-widget__input-box--enabled:focus-within{border-color:#cbd5e1;background:#fff}.cortex-widget__textarea{flex:1;background:transparent;resize:none;border:0;outline:none;font-size:.8125rem;padding:.375rem .5rem;min-height:28px;max-height:120px;line-height:1.375;color:#334155}.cortex-widget__textarea::placeholder{color:#a5afbd}.cortex-widget__textarea--disabled{color:#94a3b8;cursor:not-allowed}.cortex-widget__textarea:disabled{cursor:not-allowed;border:0}@keyframes cortex-stop-pulse-ring{0%{opacity:.45;transform:scale(1)}50%{opacity:.15;transform:scale(1.12)}to{opacity:.45;transform:scale(1)}}@keyframes cortex-stop-fade-in{0%{opacity:0;transform:scale(.7)}to{opacity:1;transform:scale(1)}}.cortex-stop-btn{flex-shrink:0;width:2rem;height:2rem;border-radius:.5rem;display:flex;align-items:center;justify-content:center;cursor:pointer;position:relative;background:#e11d48;color:#fff;border:0;animation:cortex-stop-fade-in .2s ease-out both;transition:background .15s ease}.cortex-stop-btn:hover{background:#be123c}.cortex-stop-btn:active{transform:scale(.92)}.cortex-stop-btn__ring{position:absolute;inset:0;border-radius:.5rem;background:#e11d48;animation:cortex-stop-pulse-ring 2s ease-in-out infinite;pointer-events:none}.cortex-stop-btn__icon{position:relative;z-index:1}.cortex-widget__send-btn{flex-shrink:0;width:2rem;height:2rem;border-radius:.5rem;display:flex;align-items:center;justify-content:center;border:0;transition:background-color .15s}.cortex-widget__send-btn--empty{background:#e2e8f0;color:#94a3b8}.cortex-widget__send-btn--ready{background:#1e293b;color:#fff;cursor:pointer}.cortex-widget__send-btn--ready:hover{background:#334155}[dir=rtl] .cortex-widget__send-icon{transform:rotate(180deg)}\n"], dependencies: [{ 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, encapsulation: i0.ViewEncapsulation.None });
1206
1187
  }
1207
1188
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImport: i0, type: CortexChatWidgetComponent, decorators: [{
1208
1189
  type: Component,
1209
- args: [{ selector: 'cortex-chat-widget', imports: [NgClass, MessageListComponent, FormsModule, TranslatePipe], providers: [
1190
+ args: [{ selector: 'cortex-chat-widget', imports: [MessageListComponent, FormsModule, TranslatePipe], providers: [
1210
1191
  CortexClientConfigRef,
1211
1192
  {
1212
1193
  provide: CORTEX_CLIENT_CONFIG,
@@ -1218,14 +1199,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.3", ngImpor
1218
1199
  fallbackLang: 'en',
1219
1200
  loader: provideTranslateLoader(CortexClientTranslateLoader),
1220
1201
  }),
1221
- ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1222
- class: 'block',
1223
- '[style.--cortex-primary-color]': 'theme()?.primaryColor',
1224
- '[style.--cortex-bg-color]': 'theme()?.backgroundColor',
1225
- '[style.--cortex-surface-color]': 'theme()?.surfaceColor',
1226
- '[style.--cortex-text-color]': 'theme()?.textColor',
1227
- '[style.--cortex-border-radius]': 'theme()?.borderRadius',
1228
- }, 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"] }]
1202
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'cortex-widget' }, template: "<div class=\"cortex-widget__container\">\n <!-- SCREEN 1: THREADS -->\n <div\n class=\"cortex-widget__screen\"\n [class.cortex-widget__screen--active]=\"screen() === 'threads'\"\n [class.cortex-widget__screen--left]=\"screen() !== 'threads'\"\n >\n <!-- Threads header -->\n <div class=\"cortex-widget__threads-header\">\n <div>\n <h2 class=\"cortex-widget__threads-title\">\n {{ 'translate_threads' | translate }}\n </h2>\n <p class=\"cortex-widget__threads-count\">\n {{\n 'translate_n_conversations' | translate: { count: chatService.threads()?.length ?? 0 }\n }}\n </p>\n </div>\n <button (click)=\"newChat()\" class=\"cortex-widget__new-chat-btn\">\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=\"cortex-widget__threads-list\">\n <!-- Threads loading skeleton -->\n @if (chatService.threads() === undefined) {\n @for (i of [1, 2, 3, 4]; track i) {\n <div class=\"cortex-widget__thread-skeleton\">\n <div class=\"cortex-skeleton cortex-widget__thread-skeleton-icon\"></div>\n <div class=\"cortex-widget__thread-skeleton-lines\">\n <div\n class=\"cortex-skeleton cortex-widget__thread-skeleton-line\"\n [style.width]=\"40 + i * 12 + '%'\"\n ></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=\"cortex-widget__thread-item\"\n [class.cortex-widget__thread-item--active]=\"\n thread.id === chatService.selectedThread()?.id\n \"\n >\n <!-- Thread icon -->\n <div\n class=\"cortex-widget__thread-icon\"\n [class.cortex-widget__thread-icon--active]=\"\n 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=\"cortex-widget__thread-info\">\n <p\n class=\"cortex-widget__thread-title\"\n [class.cortex-widget__thread-title--active]=\"\n 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=\"cortex-widget__thread-delete\"\n [class.cortex-widget__thread-delete--active]=\"\n 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=\"cortex-widget__thread-arrow\"\n [class.cortex-widget__thread-arrow--active]=\"\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=\"cortex-widget__threads-empty\">\n <div class=\"cortex-widget__threads-empty-icon\">\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"cortex-widget__threads-empty-svg\"\n >\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=\"cortex-widget__threads-empty-title\">No threads yet</p>\n <p class=\"cortex-widget__threads-empty-subtitle\">Start a new conversation</p>\n </div>\n }\n }\n </div>\n </div>\n\n <!-- SCREEN 2: CHAT -->\n <div\n class=\"cortex-widget__screen\"\n [class.cortex-widget__screen--active]=\"screen() === 'chat'\"\n [class.cortex-widget__screen--right]=\"screen() !== 'chat'\"\n >\n <!-- Chat header -->\n <div class=\"cortex-widget__chat-header\">\n <!-- Back button -->\n <button (click)=\"goBack()\" class=\"cortex-widget__back-btn\">\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"cortex-widget__back-icon\"\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=\"cortex-widget__chat-title-wrap\">\n <p class=\"cortex-widget__chat-title\">\n {{ chatService.selectedThread()?.title ?? ('translate_new_chat' | translate) }}\n </p>\n </div>\n\n <!-- Debug toggle -->\n <button\n (click)=\"toggleDebugMode()\"\n class=\"cortex-widget__debug-btn\"\n [class.cortex-widget__debug-btn--on]=\"debugMode()\"\n [class.cortex-widget__debug-btn--off]=\"!debugMode()\"\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=\"cortex-widget__messages-skeleton\">\n <!-- User message skeleton -->\n <div class=\"cortex-widget__msg-skel cortex-widget__msg-skel--user\">\n <div class=\"cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--user\">\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 13rem\"></div>\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 9rem\"></div>\n </div>\n </div>\n <!-- Assistant message skeleton -->\n <div class=\"cortex-widget__msg-skel cortex-widget__msg-skel--assistant\">\n <div class=\"cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--assistant\">\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 16rem\"></div>\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 18rem\"></div>\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 12rem\"></div>\n </div>\n </div>\n <!-- User message skeleton -->\n <div class=\"cortex-widget__msg-skel cortex-widget__msg-skel--user\">\n <div class=\"cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--user\">\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 11rem\"></div>\n </div>\n </div>\n <!-- Assistant message skeleton -->\n <div class=\"cortex-widget__msg-skel cortex-widget__msg-skel--assistant\">\n <div class=\"cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--assistant\">\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 14rem\"></div>\n <div class=\"cortex-skeleton cortex-widget__msg-skel-line\" style=\"width: 15rem\"></div>\n </div>\n </div>\n </div>\n } @else {\n <!-- Messages area -->\n <cortex-message-list class=\"cortex-widget__messages\" [debugMode]=\"debugMode()\" />\n }\n\n <!-- Agent working indicator -->\n @if (chatService.isAgentWorking() && !chatService.hasPendingToolCalls()) {\n <div class=\"cortex-widget__working\">\n <div class=\"cortex-widget__working-dots\">\n <span class=\"cortex-working-dot\"></span>\n <span class=\"cortex-working-dot\"></span>\n <span class=\"cortex-working-dot\"></span>\n </div>\n <span class=\"cortex-widget__working-text\">{{ 'translate_thinking' | translate }}</span>\n </div>\n }\n\n <!-- Chat input (hidden during pending tool calls) -->\n @if (!chatService.hasPendingToolCalls()) {\n <div class=\"cortex-widget__input-area\">\n <div\n class=\"cortex-widget__input-box\"\n [class.cortex-widget__input-box--disabled]=\"chatService.isAgentWorking()\"\n [class.cortex-widget__input-box--enabled]=\"!chatService.isAgentWorking()\"\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=\"cortex-widget__textarea\"\n [class.cortex-widget__textarea--disabled]=\"chatService.isAgentWorking()\"\n ></textarea>\n @if (chatService.isAgentWorking()) {\n <!-- Stop button -->\n <button (click)=\"chatService.abort()\" class=\"cortex-stop-btn\">\n <!-- Pulsing ring -->\n <span class=\"cortex-stop-btn__ring\"></span>\n <!-- Stop icon (rounded square) -->\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n class=\"cortex-stop-btn__icon\"\n >\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=\"cortex-widget__send-btn\"\n [class.cortex-widget__send-btn--empty]=\"!text().trim()\"\n [class.cortex-widget__send-btn--ready]=\"!!text().trim()\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n class=\"cortex-widget__send-icon\"\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: [".cortex-widget{display:block}.cortex-widget__container{width:100%;height:100%;position:relative;overflow:hidden}.cortex-widget__screen{position:absolute;inset:0;display:flex;flex-direction:column;transition:transform .3s ease-out}.cortex-widget__screen--active{transform:translate(0)}.cortex-widget__screen--left{transform:translate(-100%)}[dir=rtl] .cortex-widget__screen--left,.cortex-widget__screen--right{transform:translate(100%)}[dir=rtl] .cortex-widget__screen--right{transform:translate(-100%)}.cortex-widget__threads-header{flex-shrink:0;padding:1.25rem 1.25rem 1rem;display:flex;align-items:center;justify-content:space-between}.cortex-widget__threads-title{font-size:.9375rem;font-weight:600;color:#1e293b;letter-spacing:-.01em;margin:0}.cortex-widget__threads-count{font-size:.6875rem;color:#94a3b8;margin-top:.125rem;margin-bottom:0}.cortex-widget__new-chat-btn{display:inline-flex;align-items:center;gap:.375rem;font-size:.75rem;font-weight:500;color:#f1f5f9;background:#1e293b;padding:.375rem .75rem;border-radius:.375rem;border:0;cursor:pointer;transition:background-color .15s}.cortex-widget__new-chat-btn:hover{background:#334155}.cortex-widget__new-chat-btn:active{background:#0f172a}.cortex-widget__threads-list{flex:1;overflow-y:auto;padding:0 .75rem .75rem}.cortex-widget__thread-skeleton{display:flex;align-items:center;gap:.75rem;padding:.75rem;margin-bottom:.125rem}.cortex-widget__thread-skeleton-icon{flex-shrink:0;width:2rem;height:2rem}.cortex-widget__thread-skeleton-lines{flex:1;display:flex;flex-direction:column;gap:.375rem}.cortex-widget__thread-skeleton-line{height:.875rem}@keyframes cortex-skeleton-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.cortex-skeleton{background:linear-gradient(90deg,#e2e8f0,#f1f5f9,#e2e8f0 80%);background-size:200% 100%;animation:cortex-skeleton-shimmer 1.8s ease-in-out infinite;border-radius:6px}.cortex-widget__thread-item{width:100%;text-align:start;padding:.75rem;border-radius:.5rem;display:flex;align-items:center;gap:.75rem;transition:background-color .15s;cursor:pointer;margin-bottom:.125rem;border:0;background:transparent;color:#475569}.cortex-widget__thread-item:hover{background:#f1f5f9}.cortex-widget__thread-item:active{background:#e8ecf1}.cortex-widget__thread-item--active{background:#e2e8f0;color:#f1f5f9}.cortex-widget__thread-icon{flex-shrink:0;width:2rem;height:2rem;border-radius:.375rem;display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:600;background:#e2e8f0;color:#64748b}[dir=rtl] .cortex-widget__thread-icon{transform:rotate(180deg)}.cortex-widget__thread-icon--active{background:#334155;color:#cbd5e1}.cortex-widget__thread-info{min-width:0;flex:1}.cortex-widget__thread-title{font-size:.8125rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.25;margin:0;color:#334155}.cortex-widget__thread-title--active{color:#f1f5f9}.cortex-widget__thread-delete{flex-shrink:0;opacity:0;width:1.75rem;height:1.75rem;border-radius:.375rem;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:opacity .15s;background:transparent;border:0;color:#94a3b8}.cortex-widget__thread-item:hover>.cortex-widget__thread-delete{opacity:1}.cortex-widget__thread-delete:hover{background:#e2e8f0}.cortex-widget__thread-delete--active:hover{background:#475569}.cortex-widget__thread-arrow{flex-shrink:0;transition:color .15s;color:#cbd5e1}[dir=rtl] .cortex-widget__thread-arrow{transform:rotate(180deg)}.cortex-widget__thread-item:hover>.cortex-widget__thread-arrow{color:#94a3b8}.cortex-widget__thread-arrow--active{color:#64748b}.cortex-widget__threads-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:4rem 0;text-align:center}.cortex-widget__threads-empty-icon{width:2.5rem;height:2.5rem;border-radius:.5rem;background:#e2e8f0;display:flex;align-items:center;justify-content:center;margin-bottom:.75rem}.cortex-widget__threads-empty-svg{color:#94a3b8}.cortex-widget__threads-empty-title{font-size:.8125rem;color:#94a3b8;font-weight:500;margin:0}.cortex-widget__threads-empty-subtitle{font-size:.6875rem;color:#a5afbd;margin-top:.25rem;margin-bottom:0}.cortex-widget__chat-header{flex-shrink:0;height:3rem;padding:0 1rem;display:flex;align-items:center;gap:.75rem;border-bottom:1px solid #e2e8f0;background:#fff}.cortex-widget__back-btn{flex-shrink:0;width:2rem;height:2rem;border-radius:.375rem;display:flex;align-items:center;justify-content:center;color:#94a3b8;background:transparent;border:0;cursor:pointer;transition:color .15s,background-color .15s}.cortex-widget__back-btn:hover{color:#475569;background:#f1f5f9}[dir=rtl] .cortex-widget__back-icon{transform:rotate(180deg)}.cortex-widget__chat-title-wrap{min-width:0;flex:1}.cortex-widget__chat-title{font-size:.8125rem;font-weight:500;color:#334155;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin:0}.cortex-widget__debug-btn{flex-shrink:0;font-size:.6875rem;font-weight:500;padding:.25rem .625rem;border-radius:.375rem;border:0;cursor:pointer;transition:background-color .15s}.cortex-widget__debug-btn--on{background:#fef3c7;color:#d97706}.cortex-widget__debug-btn--on:hover{background:#fde68a}.cortex-widget__debug-btn--off{background:#f1f5f9;color:#94a3b8}.cortex-widget__debug-btn--off:hover{background:#e2e8f0}.cortex-widget__messages-skeleton{flex:1;overflow:hidden;padding:1rem;display:flex;flex-direction:column;gap:.5rem}.cortex-widget__msg-skel{width:100%;display:flex;flex-direction:column}.cortex-widget__msg-skel--user{align-items:flex-start}.cortex-widget__msg-skel--assistant{align-items:flex-end}.cortex-widget__msg-skel-bubble{max-width:80%;padding:1rem;border-radius:1rem;border:1px solid #e2e8f0;display:flex;flex-direction:column;gap:.5rem}.cortex-widget__msg-skel-bubble--user{background:#f8fafc;border-bottom-left-radius:0}.cortex-widget__msg-skel-bubble--assistant{background:#f1f5f9;border-bottom-right-radius:0}.cortex-widget__msg-skel-line{height:.75rem}.cortex-widget__messages{flex:1;overflow:hidden}.cortex-widget__working{flex-shrink:0;padding:.375rem 1rem;display:flex;align-items:center;gap:.375rem}.cortex-widget__working-dots{display:flex;align-items:center;gap:3px}@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{display:block;width:5px;height:5px;border-radius:9999px;background:#94a3b8;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}.cortex-widget__working-text{font-size:.6875rem;color:#94a3b8;font-weight:500}.cortex-widget__input-area{flex-shrink:0;padding:.75rem;background:#fff;border-top:1px solid #e2e8f0}.cortex-widget__input-box{display:flex;align-items:flex-end;gap:.5rem;border-radius:.75rem;border:1px solid #e2e8f0;padding:.375rem;transition:border-color .15s,background-color .15s}.cortex-widget__input-box--disabled{background:#f1f5f9}.cortex-widget__input-box--enabled{background:#f8fafc}.cortex-widget__input-box--enabled:focus-within{border-color:#cbd5e1;background:#fff}.cortex-widget__textarea{flex:1;background:transparent;resize:none;border:0;outline:none;font-size:.8125rem;padding:.375rem .5rem;min-height:28px;max-height:120px;line-height:1.375;color:#334155}.cortex-widget__textarea::placeholder{color:#a5afbd}.cortex-widget__textarea--disabled{color:#94a3b8;cursor:not-allowed}.cortex-widget__textarea:disabled{cursor:not-allowed;border:0}@keyframes cortex-stop-pulse-ring{0%{opacity:.45;transform:scale(1)}50%{opacity:.15;transform:scale(1.12)}to{opacity:.45;transform:scale(1)}}@keyframes cortex-stop-fade-in{0%{opacity:0;transform:scale(.7)}to{opacity:1;transform:scale(1)}}.cortex-stop-btn{flex-shrink:0;width:2rem;height:2rem;border-radius:.5rem;display:flex;align-items:center;justify-content:center;cursor:pointer;position:relative;background:#e11d48;color:#fff;border:0;animation:cortex-stop-fade-in .2s ease-out both;transition:background .15s ease}.cortex-stop-btn:hover{background:#be123c}.cortex-stop-btn:active{transform:scale(.92)}.cortex-stop-btn__ring{position:absolute;inset:0;border-radius:.5rem;background:#e11d48;animation:cortex-stop-pulse-ring 2s ease-in-out infinite;pointer-events:none}.cortex-stop-btn__icon{position:relative;z-index:1}.cortex-widget__send-btn{flex-shrink:0;width:2rem;height:2rem;border-radius:.5rem;display:flex;align-items:center;justify-content:center;border:0;transition:background-color .15s}.cortex-widget__send-btn--empty{background:#e2e8f0;color:#94a3b8}.cortex-widget__send-btn--ready{background:#1e293b;color:#fff;cursor:pointer}.cortex-widget__send-btn--ready:hover{background:#334155}[dir=rtl] .cortex-widget__send-icon{transform:rotate(180deg)}\n"] }]
1229
1203
  }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }, { type: i0.Output, args: ["textChange"] }] } });
1230
1204
 
1231
1205
  class PrettyJsonPipe {