max-agent-ui 0.0.10 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,17 +38,23 @@ Add `MaxAssistantComponent` to the consuming component imports and render:
38
38
 
39
39
  ```html
40
40
  <max-assistant
41
- assistantApiUrl="/api"
42
- assistantSourceApp="cortex"
43
- assistantTargetProduct="maxtime"
44
- [context]="assistantContext"
41
+ assistantApiUrl="http://127.0.0.1:8001/chat"
42
+ app="cortex"
45
43
  />
46
44
  ```
47
45
 
48
- Use mock mode while integrating without a backend:
46
+ Or provide shared configuration once:
49
47
 
50
- ```html
51
- <max-assistant [useMockAssistantApi]="true" />
48
+ ```ts
49
+ providers: [
50
+ {
51
+ provide: MAX_ASSISTANT_CONFIG,
52
+ useValue: {
53
+ assistantApiUrl: 'http://127.0.0.1:8001/chat',
54
+ app: 'cortex'
55
+ }
56
+ }
57
+ ]
52
58
  ```
53
59
 
54
60
  Host apps should provide Angular `HttpClient` for real API calls and include their PrimeNG theme and PrimeIcons styles.
@@ -16,12 +16,44 @@ import { TooltipModule } from 'primeng/tooltip';
16
16
  import { HttpClient } from '@angular/common/http';
17
17
  import { throwError } from 'rxjs';
18
18
 
19
+ const DEFAULT_ASSISTANT_BOOTSTRAP = {
20
+ initialMessage: undefined,
21
+ initialSuggestions: []
22
+ };
23
+ const ASSISTANT_BOOTSTRAP_BY_APP = {
24
+ cortex: {
25
+ initialMessage: 'Hi, I am Max, the Maxtime Virtual Assistant. How can I help you today?',
26
+ initialSuggestions: [
27
+ 'What sessions are scheduled for today?',
28
+ 'Which lecturers have planned leave this week?',
29
+ 'List the students who are on leave today.',
30
+ 'List the students who were absent from sessions yesterday.',
31
+ 'Generate the attendance report for a session conducted yesterday.'
32
+ ]
33
+ },
34
+ nemesys: {
35
+ initialMessage: 'Hi, I am Max, the Maxtime Virtual Assistant. How can I help you today?',
36
+ initialSuggestions: ['Show scheduling plans', 'Check resource availability', 'Find conflicts']
37
+ },
38
+ attendance: {
39
+ initialMessage: 'Hi, I am Max, the Maxtime Virtual Assistant. How can I help you today?',
40
+ initialSuggestions: ['Show attendance summary', 'Find missing attendance', 'View reports']
41
+ }
42
+ };
43
+ function getAssistantBootstrapConfig(app) {
44
+ const appKey = app?.trim().toLowerCase();
45
+ if (!appKey) {
46
+ return DEFAULT_ASSISTANT_BOOTSTRAP;
47
+ }
48
+ return ASSISTANT_BOOTSTRAP_BY_APP[appKey] ?? DEFAULT_ASSISTANT_BOOTSTRAP;
49
+ }
50
+
19
51
  const MAX_ASSISTANT_CONFIG = new InjectionToken('MAX_ASSISTANT_CONFIG', {
20
52
  factory: () => ({})
21
53
  });
22
54
 
23
55
  const DEFAULT_ASSISTANT_CHAT_URL = 'https://fhmaof3b4kaxqfbnomfstxyhw40rrcjr.lambda-url.eu-west-2.on.aws/chat';
24
- const DEFAULT_APP = 'assistant';
56
+ const DEFAULT_APP = 'cortex';
25
57
  class MaxAssistantService {
26
58
  config = inject(MAX_ASSISTANT_CONFIG);
27
59
  http = inject(HttpClient, { optional: true });
@@ -76,15 +108,11 @@ const ASSISTANT_UI_COPY = {
76
108
  typingLabel: 'Maxtime virtual assistant is typing',
77
109
  errorMessage: 'Maxtime virtual assistant could not be reached. Please try again.'
78
110
  };
79
- const DEFAULT_ASSISTANT_BOOTSTRAP = {
80
- initialMessage: undefined,
81
- initialSuggestions: []
82
- };
83
111
  class MaxAssistantComponent {
84
112
  messagesViewport;
85
113
  app;
114
+ assistantApiUrl;
86
115
  user = {};
87
- initialConfig = {};
88
116
  panelVisible = signal(false, ...(ngDevMode ? [{ debugName: "panelVisible" }] : /* istanbul ignore next */ []));
89
117
  isSending = signal(false, ...(ngDevMode ? [{ debugName: "isSending" }] : /* istanbul ignore next */ []));
90
118
  input = signal('', ...(ngDevMode ? [{ debugName: "input" }] : /* istanbul ignore next */ []));
@@ -106,11 +134,7 @@ class MaxAssistantComponent {
106
134
  return ASSISTANT_UI_COPY;
107
135
  }
108
136
  get bootstrapConfig() {
109
- return {
110
- ...DEFAULT_ASSISTANT_BOOTSTRAP,
111
- initialMessage: this.initialConfig.initialMessage,
112
- initialSuggestions: this.initialConfig.initialSuggestions ?? []
113
- };
137
+ return getAssistantBootstrapConfig(this.app);
114
138
  }
115
139
  closePanel() {
116
140
  this.panelVisible.set(false);
@@ -171,6 +195,7 @@ class MaxAssistantComponent {
171
195
  }
172
196
  getAssistantConfig() {
173
197
  return {
198
+ assistantApiUrl: this.assistantApiUrl,
174
199
  app: this.app,
175
200
  user: this.user
176
201
  };
@@ -256,7 +281,7 @@ class MaxAssistantComponent {
256
281
  });
257
282
  }
258
283
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: MaxAssistantComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
259
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: MaxAssistantComponent, isStandalone: true, selector: "max-assistant", inputs: { app: "app", user: "user", initialConfig: "initialConfig" }, viewQueries: [{ propertyName: "messagesViewport", first: true, predicate: ["messagesViewport"], descendants: true }], ngImport: i0, template: "<button\n pButton\n type=\"button\"\n class=\"assistant-launcher\"\n [attr.aria-label]=\"uiCopy.launcherLabel\"\n [pTooltip]=\"uiCopy.openTooltip\"\n tooltipPosition=\"left\"\n (click)=\"openPanel()\"\n>\n <span class=\"mascot\" aria-hidden=\"true\"></span>\n</button>\n\n<p-drawer\n [visible]=\"panelVisible()\"\n (visibleChange)=\"panelVisible.set($event)\"\n position=\"right\"\n styleClass=\"assistant-drawer\"\n [modal]=\"false\"\n [blockScroll]=\"false\"\n [showCloseIcon]=\"false\"\n>\n <section class=\"assistant-panel\" [attr.aria-label]=\"uiCopy.title\">\n <header class=\"assistant-header\">\n <span class=\"mascot large\" aria-hidden=\"true\"></span>\n <div>\n <h2>{{ uiCopy.title }}</h2>\n <span>{{ uiCopy.subtitle }}</span>\n </div>\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-times\"\n text\n rounded\n severity=\"secondary\"\n [attr.aria-label]=\"uiCopy.closeLabel\"\n (click)=\"closePanel()\"\n ></button>\n </header>\n\n <div #messagesViewport class=\"assistant-messages\">\n @for(message of messages(); track message.id) {\n <article class=\"message {{ message.role }}\" [class.error]=\"message.isError\">\n @if(message.displayResponse; as responseDetails) {\n <p class=\"assistant-result\">{{ responseDetails.agentInferredResponse || message.content }}</p>\n <button\n type=\"button\"\n class=\"inference-toggle\"\n [attr.aria-expanded]=\"isInferenceDetailsVisible(message.id)\"\n (click)=\"toggleInferenceDetails(message.id)\"\n >\n {{ isInferenceDetailsVisible(message.id) ? 'Hide Details' : 'Show Details' }}\n </button>\n\n @if(isInferenceDetailsVisible(message.id)) {\n <div class=\"response-details\">\n @if(responseDetails.userQuery) {\n <section class=\"response-section\">\n <h3>User Query</h3>\n <p class=\"quoted\">\"{{ responseDetails.userQuery }}\"</p>\n </section>\n }\n\n @if(responseDetails.agentExtractedIntent; as intent) {\n <section class=\"response-section\">\n <h3>Agent Extracted Intent</h3>\n <dl class=\"detail-grid\">\n @if(intent.project || intent.projectKey) {\n <div>\n <dt>Project</dt>\n <dd>\n {{ intent.project || intent.projectKey }}\n @if(intent.projectKey) {\n <span>{{ intent.projectKey }}</span>\n }\n </dd>\n </div>\n }\n @if(intent.module) {\n <div>\n <dt>Module</dt>\n <dd>{{ intent.module }}</dd>\n </div>\n }\n @if(intent.intentLabel) {\n <div>\n <dt>Intent Label</dt>\n <dd>{{ intent.intentLabel }}</dd>\n </div>\n }\n @if(intent.intent) {\n <div>\n <dt>Intent</dt>\n <dd>{{ intent.intent }}</dd>\n </div>\n }\n @if(intent.confidence !== undefined) {\n <div>\n <dt>Confidence</dt>\n <dd>{{ intent.confidence | percent: '1.0-0' }}</dd>\n </div>\n }\n </dl>\n\n @if(message.formattedParameters) {\n <div class=\"json-block\">\n <strong>Parameters</strong>\n <pre>{{ message.formattedParameters }}</pre>\n </div>\n }\n\n @if(intent.api?.url || intent.api?.method) {\n <div class=\"api-call-summary\">\n <strong>API Called</strong>\n <code>{{ intent.api?.method || 'GET' }} {{ intent.api?.url || 'URL not provided' }}</code>\n </div>\n }\n\n @if(message.formattedApiBody) {\n <div class=\"json-block\">\n <strong>API Body</strong>\n <pre>{{ message.formattedApiBody }}</pre>\n </div>\n }\n </section>\n }\n\n @if(message.formattedApiResponse) {\n <section class=\"response-section\">\n <h3>API Response</h3>\n <div class=\"json-block\">\n <strong>JSON</strong>\n <pre>{{ message.formattedApiResponse }}</pre>\n </div>\n </section>\n }\n </div>\n }\n } @else {\n <p>{{ message.content }}</p>\n }\n @if(message.role === 'assistant' && message.suggestions?.length) {\n <div class=\"suggestions\">\n @for(suggestion of message.suggestions ?? []; track suggestion) {\n <button\n pButton\n type=\"button\"\n size=\"small\"\n text\n severity=\"secondary\"\n class=\"suggestion-chip\"\n [label]=\"suggestion\"\n (click)=\"useSuggestion(suggestion)\"\n ></button>\n }\n </div>\n }\n </article>\n }\n @if(isSending()) {\n <article class=\"message assistant typing\" [attr.aria-label]=\"uiCopy.typingLabel\">\n <span></span>\n <span></span>\n <span></span>\n </article>\n }\n </div>\n\n <form class=\"assistant-composer\" (ngSubmit)=\"sendMessage()\">\n <textarea\n pTextarea\n name=\"assistantPrompt\"\n rows=\"2\"\n [placeholder]=\"uiCopy.placeholder\"\n [ngModel]=\"input()\"\n (ngModelChange)=\"input.set($event)\"\n (keydown)=\"onComposerKeydown($event)\"\n >\n </textarea>\n <button\n pButton\n type=\"submit\"\n icon=\"pi pi-send\"\n aria-label=\"Send message\"\n [disabled]=\"!input().trim() || isSending()\"\n ></button>\n </form>\n </section>\n</p-drawer>\n", styles: [":host{position:fixed;right:24px;bottom:24px;z-index:1100}.assistant-launcher{width:70px!important;height:56px!important;min-height:60px!important;padding:0 5px;border:0!important;border-radius:18px!important;color:inherit!important;background:#d7edff!important;box-shadow:0 0 0 1px #0078c824,0 10px 24px #0f172a24!important;overflow:visible}.assistant-launcher:hover,.assistant-launcher:focus-visible{background:#fff!important;box-shadow:0 0 0 2px #0078c838,0 12px 28px #0f172a29!important}.mascot{position:relative;display:grid;place-items:center;width:64px;height:56px;background:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"120\" height=\"96\" viewBox=\"14 10 92 82\" role=\"img\" aria-label=\"Max smiling cloud AI mascot\">%0A <defs>%0A <filter id=\"softShadow\" x=\"-15%\" y=\"-15%\" width=\"130%\" height=\"140%\">%0A <feDropShadow dx=\"0\" dy=\"5\" stdDeviation=\"5\" flood-color=\"%230078C8\" flood-opacity=\"0.16\"/>%0A </filter>%0A </defs>%0A%0A <g fill=\"%230078C8\" opacity=\"0.28\">%0A <circle cx=\"34\" cy=\"57\" r=\"24\"/>%0A <circle cx=\"58\" cy=\"39\" r=\"31\"/>%0A <circle cx=\"86\" cy=\"58\" r=\"25\"/>%0A <rect x=\"28\" y=\"55\" width=\"68\" height=\"27\" rx=\"13.5\"/>%0A </g>%0A%0A <g fill=\"%230078C8\" opacity=\"0.68\" filter=\"url(%23softShadow)\">%0A <circle cx=\"35\" cy=\"59\" r=\"20\"/>%0A <circle cx=\"59\" cy=\"43\" r=\"27\"/>%0A <circle cx=\"84\" cy=\"60\" r=\"21\"/>%0A <rect x=\"31\" y=\"57\" width=\"64\" height=\"24\" rx=\"12\"/>%0A </g>%0A%0A <g fill=\"%23FFD54A\">%0A <path d=\"M46 48l3.4 6.8 6.8 3.4-6.8 3.4L46 68.4l-3.4-6.8-6.8-3.4 6.8-3.4z\"/>%0A <path d=\"M74 48l3.4 6.8 6.8 3.4-6.8 3.4-3.4 6.8-3.4-6.8-6.8-3.4 6.8-3.4z\"/>%0A <path d=\"M88 28l2 4 4 2-4 2-2 4-2-4-4-2 4-2z\"/>%0A </g>%0A%0A <path%0A d=\"M49 72c6 7 20 7 26 0\"%0A fill=\"none\"%0A stroke=\"%23FFD54A\"%0A stroke-width=\"4\"%0A stroke-linecap=\"round\"%0A />%0A</svg>%0A') center/contain no-repeat}.mascot.large{width:58px;height:46px}::ng-deep .assistant-drawer{width:min(560px,100vw)!important}::ng-deep .assistant-drawer .p-drawer-content{padding:0}::ng-deep .assistant-drawer .p-drawer-header{display:none}.assistant-panel{display:grid;grid-template-rows:auto 1fr auto;height:100%;min-height:0;background:var(--background-color, #f8fafc)}.assistant-header,.assistant-composer{display:flex;gap:12px;align-items:center;padding:16px;background:#fff;border-bottom:1px solid var(--border-color, #e2e8f0)}.assistant-header h2{margin:0;font-size:20px}.assistant-header span,.sources span{color:#64748b;font-size:12px;font-weight:700}.assistant-header button{margin-left:auto}.assistant-messages{min-height:0;overflow:auto;padding:18px}.message{width:fit-content;max-width:92%;margin-bottom:14px;padding:12px;border:1px solid var(--border-color, #e2e8f0);border-radius:var(--medium-border-radius, 8px);background:#fff;box-shadow:0 6px 18px #0f172a0f}.message.assistant{width:100%;max-width:100%}.message.user{width:fit-content;max-width:88%;margin-left:auto;color:#fff;background:var(--primary-color, #2563eb);border-color:var(--primary-color, #2563eb)}.message.error{border-color:var(--danger-color, #dc2626)}.message p{margin:0;line-height:1.45}.assistant-result{color:#1e293b}.inference-toggle{display:flex;width:fit-content;margin:10px 0 0 auto;padding:0;border:0;color:var(--primary-color, #2563eb);background:transparent;font:inherit;font-size:13px;font-weight:400;text-decoration:underline;text-underline-offset:3px;cursor:pointer}.inference-toggle:hover{color:var(--primary-dark-color, #1d4ed8)}.inference-toggle:focus-visible{outline:2px solid var(--primary-color, #2563eb);outline-offset:3px}.suggestions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.suggestion-chip{border:1px solid rgba(var(--primary-color-rgb, 37, 99, 235),.28);color:var(--primary-dark-color, #1d4ed8);background:rgba(var(--primary-color-rgb, 37, 99, 235),.08);font-weight:700;box-shadow:0 4px 14px #0f172a0f;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.suggestion-chip:hover{border-color:rgba(var(--primary-color-rgb, 37, 99, 235),.42);color:var(--primary-dark-color, #1d4ed8);background:rgba(var(--primary-color-rgb, 37, 99, 235),.14)}.response-details{display:grid;gap:12px;margin-top:12px}.response-section{display:grid;gap:8px;padding-bottom:12px;border-bottom:1px solid var(--border-color, #e2e8f0)}.response-section:last-child{padding-bottom:0;border-bottom:0}.response-section h3{margin:0;color:#0f172a;font-size:13px;font-weight:800}.quoted{padding:8px 10px;border-left:5px solid var(--primary-color, #2563eb);border-radius:var(--border-radius, 6px);color:#1e293b;background:#f8fafc}.detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0}.detail-grid div{min-width:0;padding:8px;border-radius:var(--border-radius, 6px);background:#f8fafc}.detail-grid dt{margin-bottom:3px;color:#64748b;font-size:11px;font-weight:800;text-transform:uppercase}.detail-grid dd{margin:0;color:#334155;font-size:13px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.detail-grid dd span{display:block;margin-top:2px;color:#64748b;font-size:11px}.api-call-summary,.json-block{display:grid;gap:6px;padding:8px;border-radius:var(--border-radius, 6px);background:#f8fafc}.api-call-summary strong,.json-block strong{color:#64748b;font-size:11px;font-weight:800;text-transform:uppercase}.api-call-summary code{color:var(--secondary-color, #0f172a);font-weight:800;white-space:normal;word-break:break-word}.json-block pre{max-height:220px;margin:0;overflow:auto;color:#0f172a;font-size:12px;line-height:1.45;white-space:pre-wrap;overflow-wrap:anywhere}.typing{display:flex;width:fit-content;max-width:fit-content;gap:5px;align-items:center;padding:4px 0;border:0;background:transparent;box-shadow:none}.typing span{width:7px;height:7px;border-radius:50%;background:var(--primary-color, #2563eb);animation:typing-dot .85s infinite ease-in-out}.typing span:nth-child(2){animation-delay:.15s}.assistant-composer{border-top:1px solid var(--border-color, #e2e8f0);border-bottom:0}.assistant-composer textarea{flex:1;min-height:46px;max-height:120px;resize:vertical}@keyframes typing-dot{0%,80%,to{opacity:.35;transform:translateY(0)}40%{opacity:1;transform:translateY(-4px)}}@keyframes pulse{to{opacity:.35;transform:translateY(-2px)}}@media(max-width:640px){:host{right:16px;bottom:16px}.assistant-launcher{width:62px!important;min-width:62px!important;height:54px!important;min-height:54px!important}.assistant-messages{padding:14px}.detail-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i3.Drawer, selector: "p-drawer", inputs: ["appendTo", "motionOptions", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i4.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["pTextareaPT", "pTextareaUnstyled", "autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "pipe", type: i6.PercentPipe, name: "percent" }] });
284
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: MaxAssistantComponent, isStandalone: true, selector: "max-assistant", inputs: { app: "app", assistantApiUrl: "assistantApiUrl", user: "user" }, viewQueries: [{ propertyName: "messagesViewport", first: true, predicate: ["messagesViewport"], descendants: true }], ngImport: i0, template: "<button\n pButton\n type=\"button\"\n class=\"assistant-launcher\"\n [attr.aria-label]=\"uiCopy.launcherLabel\"\n [pTooltip]=\"uiCopy.openTooltip\"\n tooltipPosition=\"left\"\n (click)=\"openPanel()\"\n>\n <span class=\"mascot\" aria-hidden=\"true\"></span>\n</button>\n\n<p-drawer\n [visible]=\"panelVisible()\"\n (visibleChange)=\"panelVisible.set($event)\"\n position=\"right\"\n styleClass=\"assistant-drawer\"\n [modal]=\"false\"\n [blockScroll]=\"false\"\n [showCloseIcon]=\"false\"\n>\n <section class=\"assistant-panel\" [attr.aria-label]=\"uiCopy.title\">\n <header class=\"assistant-header\">\n <span class=\"mascot large\" aria-hidden=\"true\"></span>\n <div>\n <h2>{{ uiCopy.title }}</h2>\n <span>{{ uiCopy.subtitle }}</span>\n </div>\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-times\"\n text\n rounded\n severity=\"secondary\"\n [attr.aria-label]=\"uiCopy.closeLabel\"\n (click)=\"closePanel()\"\n ></button>\n </header>\n\n <div #messagesViewport class=\"assistant-messages\">\n @for(message of messages(); track message.id) {\n <article class=\"message {{ message.role }}\" [class.error]=\"message.isError\">\n @if(message.displayResponse; as responseDetails) {\n <p class=\"assistant-result\">{{ responseDetails.agentInferredResponse || message.content }}</p>\n <button\n type=\"button\"\n class=\"inference-toggle\"\n [attr.aria-expanded]=\"isInferenceDetailsVisible(message.id)\"\n (click)=\"toggleInferenceDetails(message.id)\"\n >\n {{ isInferenceDetailsVisible(message.id) ? 'Hide Details' : 'Show Details' }}\n </button>\n\n @if(isInferenceDetailsVisible(message.id)) {\n <div class=\"response-details\">\n @if(responseDetails.userQuery) {\n <section class=\"response-section\">\n <h3>User Query</h3>\n <p class=\"quoted\">\"{{ responseDetails.userQuery }}\"</p>\n </section>\n }\n\n @if(responseDetails.agentExtractedIntent; as intent) {\n <section class=\"response-section\">\n <h3>Agent Extracted Intent</h3>\n <dl class=\"detail-grid\">\n @if(intent.project || intent.projectKey) {\n <div>\n <dt>Project</dt>\n <dd>\n {{ intent.project || intent.projectKey }}\n @if(intent.projectKey) {\n <span>{{ intent.projectKey }}</span>\n }\n </dd>\n </div>\n }\n @if(intent.module) {\n <div>\n <dt>Module</dt>\n <dd>{{ intent.module }}</dd>\n </div>\n }\n @if(intent.intentLabel) {\n <div>\n <dt>Intent Label</dt>\n <dd>{{ intent.intentLabel }}</dd>\n </div>\n }\n @if(intent.intent) {\n <div>\n <dt>Intent</dt>\n <dd>{{ intent.intent }}</dd>\n </div>\n }\n @if(intent.confidence !== undefined) {\n <div>\n <dt>Confidence</dt>\n <dd>{{ intent.confidence | percent: '1.0-0' }}</dd>\n </div>\n }\n </dl>\n\n @if(message.formattedParameters) {\n <div class=\"json-block\">\n <strong>Parameters</strong>\n <pre>{{ message.formattedParameters }}</pre>\n </div>\n }\n\n @if(intent.api?.url || intent.api?.method) {\n <div class=\"api-call-summary\">\n <strong>API Called</strong>\n <code>{{ intent.api?.method || 'GET' }} {{ intent.api?.url || 'URL not provided' }}</code>\n </div>\n }\n\n @if(message.formattedApiBody) {\n <div class=\"json-block\">\n <strong>API Body</strong>\n <pre>{{ message.formattedApiBody }}</pre>\n </div>\n }\n </section>\n }\n\n @if(message.formattedApiResponse) {\n <section class=\"response-section\">\n <h3>API Response</h3>\n <div class=\"json-block\">\n <strong>JSON</strong>\n <pre>{{ message.formattedApiResponse }}</pre>\n </div>\n </section>\n }\n </div>\n }\n } @else {\n <p>{{ message.content }}</p>\n }\n @if(message.role === 'assistant' && message.suggestions?.length) {\n <div class=\"suggestions\">\n @for(suggestion of message.suggestions ?? []; track suggestion) {\n <button\n pButton\n type=\"button\"\n size=\"small\"\n text\n severity=\"secondary\"\n class=\"suggestion-chip\"\n [label]=\"suggestion\"\n (click)=\"useSuggestion(suggestion)\"\n ></button>\n }\n </div>\n }\n </article>\n }\n @if(isSending()) {\n <article class=\"message assistant typing\" [attr.aria-label]=\"uiCopy.typingLabel\">\n <span></span>\n <span></span>\n <span></span>\n </article>\n }\n </div>\n\n <form class=\"assistant-composer\" (ngSubmit)=\"sendMessage()\">\n <textarea\n pTextarea\n name=\"assistantPrompt\"\n rows=\"2\"\n [placeholder]=\"uiCopy.placeholder\"\n [ngModel]=\"input()\"\n (ngModelChange)=\"input.set($event)\"\n (keydown)=\"onComposerKeydown($event)\"\n >\n </textarea>\n <button\n pButton\n type=\"submit\"\n icon=\"pi pi-send\"\n aria-label=\"Send message\"\n [disabled]=\"!input().trim() || isSending()\"\n ></button>\n </form>\n </section>\n</p-drawer>\n", styles: [":host{position:fixed;right:24px;bottom:24px;z-index:1100}.assistant-launcher{width:70px!important;height:56px!important;min-height:60px!important;padding:0 5px;border:0!important;border-radius:18px!important;color:inherit!important;background:#d7edff!important;box-shadow:0 0 0 1px #0078c824,0 10px 24px #0f172a24!important;overflow:visible}.assistant-launcher:hover,.assistant-launcher:focus-visible{background:#fff!important;box-shadow:0 0 0 2px #0078c838,0 12px 28px #0f172a29!important}.mascot{position:relative;display:grid;place-items:center;width:64px;height:56px;background:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"120\" height=\"96\" viewBox=\"14 10 92 82\" role=\"img\" aria-label=\"Max smiling cloud AI mascot\">%0A <defs>%0A <filter id=\"softShadow\" x=\"-15%\" y=\"-15%\" width=\"130%\" height=\"140%\">%0A <feDropShadow dx=\"0\" dy=\"5\" stdDeviation=\"5\" flood-color=\"%230078C8\" flood-opacity=\"0.16\"/>%0A </filter>%0A </defs>%0A%0A <g fill=\"%230078C8\" opacity=\"0.28\">%0A <circle cx=\"34\" cy=\"57\" r=\"24\"/>%0A <circle cx=\"58\" cy=\"39\" r=\"31\"/>%0A <circle cx=\"86\" cy=\"58\" r=\"25\"/>%0A <rect x=\"28\" y=\"55\" width=\"68\" height=\"27\" rx=\"13.5\"/>%0A </g>%0A%0A <g fill=\"%230078C8\" opacity=\"0.68\" filter=\"url(%23softShadow)\">%0A <circle cx=\"35\" cy=\"59\" r=\"20\"/>%0A <circle cx=\"59\" cy=\"43\" r=\"27\"/>%0A <circle cx=\"84\" cy=\"60\" r=\"21\"/>%0A <rect x=\"31\" y=\"57\" width=\"64\" height=\"24\" rx=\"12\"/>%0A </g>%0A%0A <g fill=\"%23FFD54A\">%0A <path d=\"M46 48l3.4 6.8 6.8 3.4-6.8 3.4L46 68.4l-3.4-6.8-6.8-3.4 6.8-3.4z\"/>%0A <path d=\"M74 48l3.4 6.8 6.8 3.4-6.8 3.4-3.4 6.8-3.4-6.8-6.8-3.4 6.8-3.4z\"/>%0A <path d=\"M88 28l2 4 4 2-4 2-2 4-2-4-4-2 4-2z\"/>%0A </g>%0A%0A <path%0A d=\"M49 72c6 7 20 7 26 0\"%0A fill=\"none\"%0A stroke=\"%23FFD54A\"%0A stroke-width=\"4\"%0A stroke-linecap=\"round\"%0A />%0A</svg>%0A') center/contain no-repeat}.mascot.large{width:58px;height:46px}::ng-deep .assistant-drawer{width:min(560px,100vw)!important}::ng-deep .assistant-drawer .p-drawer-content{padding:0}::ng-deep .assistant-drawer .p-drawer-header{display:none}.assistant-panel{display:grid;grid-template-rows:auto 1fr auto;height:100%;min-height:0;background:var(--background-color, #f8fafc)}.assistant-header,.assistant-composer{display:flex;gap:12px;align-items:center;padding:16px;background:#fff;border-bottom:1px solid var(--border-color, #e2e8f0)}.assistant-header h2{margin:0;font-size:20px}.assistant-header span,.sources span{color:#64748b;font-size:12px;font-weight:700}.assistant-header button{margin-left:auto}.assistant-messages{min-height:0;overflow:auto;padding:18px}.message{width:fit-content;max-width:92%;margin-bottom:14px;padding:12px;border:1px solid var(--border-color, #e2e8f0);border-radius:var(--medium-border-radius, 8px);background:#fff;box-shadow:0 6px 18px #0f172a0f}.message.assistant{width:100%;max-width:100%}.message.user{width:fit-content;max-width:88%;margin-left:auto;color:#fff;background:var(--primary-color, #2563eb);border-color:var(--primary-color, #2563eb)}.message.error{border-color:var(--danger-color, #dc2626)}.message p{margin:0;line-height:1.45}.assistant-result{color:#1e293b}.inference-toggle{display:flex;width:fit-content;margin:10px 0 0 auto;padding:0;border:0;color:var(--primary-color, #2563eb);background:transparent;font:inherit;font-size:13px;font-weight:400;text-decoration:underline;text-underline-offset:3px;cursor:pointer}.inference-toggle:hover{color:var(--primary-dark-color, #1d4ed8)}.inference-toggle:focus-visible{outline:2px solid var(--primary-color, #2563eb);outline-offset:3px}.suggestions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.suggestion-chip{border:1px solid rgba(var(--primary-color-rgb, 37, 99, 235),.28);color:var(--primary-dark-color, #1d4ed8);background:rgba(var(--primary-color-rgb, 37, 99, 235),.08);font-weight:700;box-shadow:0 4px 14px #0f172a0f;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.suggestion-chip:hover{border-color:rgba(var(--primary-color-rgb, 37, 99, 235),.42);color:var(--primary-dark-color, #1d4ed8);background:rgba(var(--primary-color-rgb, 37, 99, 235),.14)}.response-details{display:grid;gap:12px;margin-top:12px}.response-section{display:grid;gap:8px;padding-bottom:12px;border-bottom:1px solid var(--border-color, #e2e8f0)}.response-section:last-child{padding-bottom:0;border-bottom:0}.response-section h3{margin:0;color:#0f172a;font-size:13px;font-weight:800}.quoted{padding:8px 10px;border-left:5px solid var(--primary-color, #2563eb);border-radius:var(--border-radius, 6px);color:#1e293b;background:#f8fafc}.detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0}.detail-grid div{min-width:0;padding:8px;border-radius:var(--border-radius, 6px);background:#f8fafc}.detail-grid dt{margin-bottom:3px;color:#64748b;font-size:11px;font-weight:800;text-transform:uppercase}.detail-grid dd{margin:0;color:#334155;font-size:13px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.detail-grid dd span{display:block;margin-top:2px;color:#64748b;font-size:11px}.api-call-summary,.json-block{display:grid;gap:6px;padding:8px;border-radius:var(--border-radius, 6px);background:#f8fafc}.api-call-summary strong,.json-block strong{color:#64748b;font-size:11px;font-weight:800;text-transform:uppercase}.api-call-summary code{color:var(--secondary-color, #0f172a);font-weight:800;white-space:normal;word-break:break-word}.json-block pre{max-height:220px;margin:0;overflow:auto;color:#0f172a;font-size:12px;line-height:1.45;white-space:pre-wrap;overflow-wrap:anywhere}.typing{display:flex;width:fit-content;max-width:fit-content;gap:5px;align-items:center;padding:4px 0;border:0;background:transparent;box-shadow:none}.typing span{width:7px;height:7px;border-radius:50%;background:var(--primary-color, #2563eb);animation:typing-dot .85s infinite ease-in-out}.typing span:nth-child(2){animation-delay:.15s}.assistant-composer{border-top:1px solid var(--border-color, #e2e8f0);border-bottom:0}.assistant-composer textarea{flex:1;min-height:46px;max-height:120px;resize:vertical}@keyframes typing-dot{0%,80%,to{opacity:.35;transform:translateY(0)}40%{opacity:1;transform:translateY(-4px)}}@keyframes pulse{to{opacity:.35;transform:translateY(-2px)}}@media(max-width:640px){:host{right:16px;bottom:16px}.assistant-launcher{width:62px!important;min-width:62px!important;height:54px!important;min-height:54px!important}.assistant-messages{padding:14px}.detail-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: DrawerModule }, { kind: "component", type: i3.Drawer, selector: "p-drawer", inputs: ["appendTo", "motionOptions", "blockScroll", "style", "styleClass", "ariaCloseLabel", "autoZIndex", "baseZIndex", "modal", "closeButtonProps", "dismissible", "showCloseIcon", "closeOnEscape", "transitionOptions", "visible", "position", "fullScreen", "header", "maskStyle", "closable"], outputs: ["onShow", "onHide", "visibleChange"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i4.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["pTextareaPT", "pTextareaUnstyled", "autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "pipe", type: i6.PercentPipe, name: "percent" }] });
260
285
  }
261
286
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: MaxAssistantComponent, decorators: [{
262
287
  type: Component,
@@ -266,9 +291,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
266
291
  args: ['messagesViewport']
267
292
  }], app: [{
268
293
  type: Input
269
- }], user: [{
294
+ }], assistantApiUrl: [{
270
295
  type: Input
271
- }], initialConfig: [{
296
+ }], user: [{
272
297
  type: Input
273
298
  }] } });
274
299
 
@@ -1 +1 @@
1
- {"version":3,"file":"max-agent-ui.mjs","sources":["../../../projects/max-agent-ui/src/lib/config/assistant.config.ts","../../../projects/max-agent-ui/src/lib/components/assistant/max-assistant.service.ts","../../../projects/max-agent-ui/src/lib/components/assistant/max-assistant.component.ts","../../../projects/max-agent-ui/src/lib/components/assistant/max-assistant.component.html","../../../projects/max-agent-ui/src/public-api.ts","../../../projects/max-agent-ui/src/max-agent-ui.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nimport { AssistantProduct, AssistantUser } from '../models/assistant.models';\n\nexport interface MaxAssistantConfig {\n assistantApiUrl?: string;\n app?: AssistantProduct;\n user?: Partial<AssistantUser> | (() => Partial<AssistantUser>);\n}\n\nexport const MAX_ASSISTANT_CONFIG = new InjectionToken<MaxAssistantConfig>(\n 'MAX_ASSISTANT_CONFIG',\n {\n factory: () => ({})\n }\n);\n","import { HttpClient } from '@angular/common/http';\nimport { inject, Injectable } from '@angular/core';\nimport { Observable, throwError } from 'rxjs';\n\nimport { MAX_ASSISTANT_CONFIG, MaxAssistantConfig } from '../../config/assistant.config';\nimport {\n AssistantChatRequest,\n AssistantChatResponse,\n AssistantProduct,\n AssistantUser\n} from '../../models/assistant.models';\n\nconst DEFAULT_ASSISTANT_CHAT_URL =\n 'https://fhmaof3b4kaxqfbnomfstxyhw40rrcjr.lambda-url.eu-west-2.on.aws/chat';\nconst DEFAULT_APP = 'assistant';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MaxAssistantService {\n private readonly config = inject(MAX_ASSISTANT_CONFIG);\n private readonly http = inject(HttpClient, { optional: true });\n\n sendMessage(\n message: string,\n conversationId?: string,\n config: MaxAssistantConfig = {}\n ): Observable<AssistantChatResponse> {\n const assistantConfig = {\n ...this.config,\n ...config\n };\n const request: AssistantChatRequest = {\n message,\n conversationId,\n app: this.getApp(assistantConfig),\n user: this.getUser(assistantConfig)\n };\n\n return this.postMessage(request, assistantConfig);\n }\n\n private postMessage(\n request: AssistantChatRequest,\n config: MaxAssistantConfig\n ): Observable<AssistantChatResponse> {\n if (!this.http) {\n return throwError(\n () => new Error('HttpClient is not available. Add provideHttpClient() to the host app.')\n );\n }\n\n return this.http.post<AssistantChatResponse>(this.getChatUrl(config), request);\n }\n\n private getChatUrl(config: MaxAssistantConfig): string {\n return config.assistantApiUrl?.trim() || DEFAULT_ASSISTANT_CHAT_URL;\n }\n\n private getApp(config: MaxAssistantConfig): AssistantProduct {\n return config.app || DEFAULT_APP;\n }\n\n private getUser(config: MaxAssistantConfig): AssistantUser {\n if (typeof config.user === 'function') {\n return config.user();\n }\n\n return config.user ?? {};\n }\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, DestroyRef, ElementRef, inject, Input, signal, ViewChild } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { FormsModule } from '@angular/forms';\nimport { ButtonModule } from 'primeng/button';\nimport { DrawerModule } from 'primeng/drawer';\nimport { TextareaModule } from 'primeng/textarea';\nimport { TooltipModule } from 'primeng/tooltip';\n\nimport { MaxAssistantConfig } from '../../config/assistant.config';\nimport {\n AssistantChatResponse,\n AssistantDisplayResponse,\n AssistantExtractedIntent,\n AssistantFieldMap,\n AssistantMessage,\n AssistantProduct,\n AssistantUser,\n InitialConfig\n} from '../../models/assistant.models';\nimport { MaxAssistantService } from './max-assistant.service';\n\nconst ASSISTANT_UI_COPY = {\n title: 'Max',\n subtitle: 'Maxtime Virtual Assistant',\n launcherLabel: 'Open Maxtime virtual assistant',\n openTooltip: 'Open Maxtime virtual assistant',\n closeLabel: 'Close Maxtime virtual assistant',\n placeholder: 'Ask Maxtime virtual assistant',\n typingLabel: 'Maxtime virtual assistant is typing',\n errorMessage: 'Maxtime virtual assistant could not be reached. Please try again.'\n};\n\ntype AssistantBootstrapConfig = Pick<InitialConfig, 'initialMessage'> &\n Required<Pick<InitialConfig, 'initialSuggestions'>>;\n\nconst DEFAULT_ASSISTANT_BOOTSTRAP: AssistantBootstrapConfig = {\n initialMessage: undefined,\n initialSuggestions: []\n};\n\n@Component({\n selector: 'max-assistant',\n imports: [CommonModule, FormsModule, ButtonModule, DrawerModule, TextareaModule, TooltipModule],\n templateUrl: './max-assistant.component.html',\n styleUrl: './max-assistant.component.scss'\n})\nexport class MaxAssistantComponent {\n @ViewChild('messagesViewport') private messagesViewport?: ElementRef<HTMLElement>;\n\n @Input() app?: AssistantProduct;\n @Input() user:\n | Partial<AssistantUser>\n | (() => Partial<AssistantUser>) = {};\n @Input() initialConfig: InitialConfig = {};\n\n protected readonly panelVisible = signal(false);\n protected readonly isSending = signal(false);\n protected readonly input = signal('');\n protected readonly conversationId = signal<string | undefined>(undefined);\n protected readonly messages = signal<AssistantMessage[]>([]);\n protected readonly expandedInferenceMessageIds = signal<ReadonlySet<string>>(new Set<string>());\n\n private readonly assistantService = inject(MaxAssistantService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected openPanel() {\n this.panelVisible.set(true);\n\n if (!this.messages().length && this.bootstrapConfig.initialMessage) {\n this.messages.set([\n this.createMessage(\n 'assistant',\n this.bootstrapConfig.initialMessage,\n this.bootstrapConfig.initialSuggestions\n )\n ]);\n }\n\n this.scrollToLatest();\n }\n\n protected get uiCopy(): typeof ASSISTANT_UI_COPY {\n return ASSISTANT_UI_COPY;\n }\n\n protected get bootstrapConfig(): AssistantBootstrapConfig {\n return {\n ...DEFAULT_ASSISTANT_BOOTSTRAP,\n initialMessage: this.initialConfig.initialMessage,\n initialSuggestions: this.initialConfig.initialSuggestions ?? []\n };\n }\n\n protected closePanel() {\n this.panelVisible.set(false);\n }\n\n protected sendMessage(message = this.input()) {\n const trimmedMessage = message.trim();\n\n if (!trimmedMessage || this.isSending()) {\n return;\n }\n\n this.input.set('');\n this.appendMessage(this.createMessage('user', trimmedMessage));\n this.isSending.set(true);\n\n this.assistantService\n .sendMessage(trimmedMessage, this.conversationId(), this.getAssistantConfig())\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: response => {\n this.conversationId.set(response.conversationId);\n this.appendMessage(this.createAssistantResponseMessage(response, trimmedMessage));\n this.isSending.set(false);\n },\n error: () => {\n this.appendMessage({\n ...this.createMessage('assistant', this.uiCopy.errorMessage),\n isError: true\n });\n this.isSending.set(false);\n }\n });\n }\n\n protected useSuggestion(suggestion: string) {\n this.sendMessage(suggestion);\n }\n\n protected onComposerKeydown(event: KeyboardEvent) {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n this.sendMessage();\n }\n }\n\n protected isInferenceDetailsVisible(messageId: string): boolean {\n return this.expandedInferenceMessageIds().has(messageId);\n }\n\n protected toggleInferenceDetails(messageId: string) {\n const willOpen = !this.isInferenceDetailsVisible(messageId);\n\n this.expandedInferenceMessageIds.update(expandedIds => {\n const nextExpandedIds = new Set(expandedIds);\n\n if (nextExpandedIds.has(messageId)) {\n nextExpandedIds.delete(messageId);\n } else {\n nextExpandedIds.add(messageId);\n }\n\n return nextExpandedIds;\n });\n\n if (willOpen) {\n this.scrollToLatest();\n }\n }\n\n private getAssistantConfig(): MaxAssistantConfig {\n return {\n app: this.app,\n user: this.user\n };\n }\n\n private appendMessage(message: AssistantMessage) {\n this.messages.update(messages => [...messages, message]);\n this.scrollToLatest();\n }\n\n private createAssistantResponseMessage(\n response: AssistantChatResponse,\n userQuery: string\n ): AssistantMessage {\n const displayResponse = this.createDisplayResponse(response, userQuery);\n\n return this.createMessage(\n 'assistant',\n displayResponse.agentInferredResponse || response.answer,\n response.suggestions,\n response.sources,\n response.intent,\n response.intentLabel,\n response.app,\n response.productLabel,\n response.apiModule,\n response.confidence,\n response.parameters ?? response.entities,\n response.apiCalls,\n response.mockResult,\n response.llmUsed,\n response.availableModules,\n displayResponse\n );\n }\n\n private createMessage(\n role: AssistantMessage['role'],\n content: string,\n suggestions: string[] = [],\n sources: AssistantMessage['sources'] = [],\n intent?: string,\n intentLabel?: string,\n app?: string,\n productLabel?: string,\n apiModule?: string,\n confidence?: number,\n parameters?: AssistantFieldMap,\n apiCalls?: AssistantMessage['apiCalls'],\n mockResult?: AssistantFieldMap,\n llmUsed?: boolean,\n availableModules?: string[],\n displayResponse?: AssistantDisplayResponse\n ): AssistantMessage {\n return {\n id: this.createId(),\n role,\n content,\n displayResponse,\n formattedParameters: this.formatJson(displayResponse?.agentExtractedIntent?.parameters),\n formattedApiBody: this.formatJson(displayResponse?.agentExtractedIntent?.api?.body),\n formattedApiResponse: this.formatJson(displayResponse?.apiResponse),\n suggestions,\n sources,\n intent,\n intentLabel,\n app,\n productLabel,\n apiModule,\n confidence,\n parameters,\n entities: parameters,\n apiCalls,\n mockResult,\n llmUsed,\n availableModules,\n createdAt: new Date()\n };\n }\n\n private createDisplayResponse(\n response: AssistantChatResponse,\n userQuery: string\n ): AssistantDisplayResponse {\n const provided = response.displayResponse ?? {};\n const extractedIntent = this.createExtractedIntent(response, provided.agentExtractedIntent);\n\n return {\n userQuery: provided.userQuery || userQuery,\n agentInferredResponse: provided.agentInferredResponse || response.answer,\n agentExtractedIntent: extractedIntent,\n apiResponse: provided.apiResponse ?? this.getApiResponseFallback(response),\n markdown: provided.markdown\n };\n }\n\n private createExtractedIntent(\n response: AssistantChatResponse,\n provided?: AssistantExtractedIntent\n ): AssistantExtractedIntent {\n return {\n project: provided?.project ?? response.productLabel ?? response.app,\n projectKey: provided?.projectKey ?? response.app,\n module: provided?.module ?? response.apiModule,\n intent: provided?.intent ?? response.intent,\n intentLabel: provided?.intentLabel ?? response.intentLabel,\n confidence: provided?.confidence ?? response.confidence,\n parameters: provided?.parameters ?? response.parameters ?? response.entities,\n api: provided?.api ?? response.apiCalls?.[0]\n };\n }\n\n private getApiResponseFallback(response: AssistantChatResponse): AssistantFieldMap | undefined {\n if (!response.mockResult || !Object.keys(response.mockResult).length) {\n return undefined;\n }\n\n return response.mockResult;\n }\n\n private formatJson(value: unknown): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n return JSON.stringify(value, null, 2);\n }\n\n private createId(): string {\n return globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random()}`;\n }\n\n private scrollToLatest() {\n setTimeout(() => {\n const element = this.messagesViewport?.nativeElement;\n\n if (element) {\n element.scrollTop = element.scrollHeight;\n }\n });\n }\n}\n","<button\n pButton\n type=\"button\"\n class=\"assistant-launcher\"\n [attr.aria-label]=\"uiCopy.launcherLabel\"\n [pTooltip]=\"uiCopy.openTooltip\"\n tooltipPosition=\"left\"\n (click)=\"openPanel()\"\n>\n <span class=\"mascot\" aria-hidden=\"true\"></span>\n</button>\n\n<p-drawer\n [visible]=\"panelVisible()\"\n (visibleChange)=\"panelVisible.set($event)\"\n position=\"right\"\n styleClass=\"assistant-drawer\"\n [modal]=\"false\"\n [blockScroll]=\"false\"\n [showCloseIcon]=\"false\"\n>\n <section class=\"assistant-panel\" [attr.aria-label]=\"uiCopy.title\">\n <header class=\"assistant-header\">\n <span class=\"mascot large\" aria-hidden=\"true\"></span>\n <div>\n <h2>{{ uiCopy.title }}</h2>\n <span>{{ uiCopy.subtitle }}</span>\n </div>\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-times\"\n text\n rounded\n severity=\"secondary\"\n [attr.aria-label]=\"uiCopy.closeLabel\"\n (click)=\"closePanel()\"\n ></button>\n </header>\n\n <div #messagesViewport class=\"assistant-messages\">\n @for(message of messages(); track message.id) {\n <article class=\"message {{ message.role }}\" [class.error]=\"message.isError\">\n @if(message.displayResponse; as responseDetails) {\n <p class=\"assistant-result\">{{ responseDetails.agentInferredResponse || message.content }}</p>\n <button\n type=\"button\"\n class=\"inference-toggle\"\n [attr.aria-expanded]=\"isInferenceDetailsVisible(message.id)\"\n (click)=\"toggleInferenceDetails(message.id)\"\n >\n {{ isInferenceDetailsVisible(message.id) ? 'Hide Details' : 'Show Details' }}\n </button>\n\n @if(isInferenceDetailsVisible(message.id)) {\n <div class=\"response-details\">\n @if(responseDetails.userQuery) {\n <section class=\"response-section\">\n <h3>User Query</h3>\n <p class=\"quoted\">\"{{ responseDetails.userQuery }}\"</p>\n </section>\n }\n\n @if(responseDetails.agentExtractedIntent; as intent) {\n <section class=\"response-section\">\n <h3>Agent Extracted Intent</h3>\n <dl class=\"detail-grid\">\n @if(intent.project || intent.projectKey) {\n <div>\n <dt>Project</dt>\n <dd>\n {{ intent.project || intent.projectKey }}\n @if(intent.projectKey) {\n <span>{{ intent.projectKey }}</span>\n }\n </dd>\n </div>\n }\n @if(intent.module) {\n <div>\n <dt>Module</dt>\n <dd>{{ intent.module }}</dd>\n </div>\n }\n @if(intent.intentLabel) {\n <div>\n <dt>Intent Label</dt>\n <dd>{{ intent.intentLabel }}</dd>\n </div>\n }\n @if(intent.intent) {\n <div>\n <dt>Intent</dt>\n <dd>{{ intent.intent }}</dd>\n </div>\n }\n @if(intent.confidence !== undefined) {\n <div>\n <dt>Confidence</dt>\n <dd>{{ intent.confidence | percent: '1.0-0' }}</dd>\n </div>\n }\n </dl>\n\n @if(message.formattedParameters) {\n <div class=\"json-block\">\n <strong>Parameters</strong>\n <pre>{{ message.formattedParameters }}</pre>\n </div>\n }\n\n @if(intent.api?.url || intent.api?.method) {\n <div class=\"api-call-summary\">\n <strong>API Called</strong>\n <code>{{ intent.api?.method || 'GET' }} {{ intent.api?.url || 'URL not provided' }}</code>\n </div>\n }\n\n @if(message.formattedApiBody) {\n <div class=\"json-block\">\n <strong>API Body</strong>\n <pre>{{ message.formattedApiBody }}</pre>\n </div>\n }\n </section>\n }\n\n @if(message.formattedApiResponse) {\n <section class=\"response-section\">\n <h3>API Response</h3>\n <div class=\"json-block\">\n <strong>JSON</strong>\n <pre>{{ message.formattedApiResponse }}</pre>\n </div>\n </section>\n }\n </div>\n }\n } @else {\n <p>{{ message.content }}</p>\n }\n @if(message.role === 'assistant' && message.suggestions?.length) {\n <div class=\"suggestions\">\n @for(suggestion of message.suggestions ?? []; track suggestion) {\n <button\n pButton\n type=\"button\"\n size=\"small\"\n text\n severity=\"secondary\"\n class=\"suggestion-chip\"\n [label]=\"suggestion\"\n (click)=\"useSuggestion(suggestion)\"\n ></button>\n }\n </div>\n }\n </article>\n }\n @if(isSending()) {\n <article class=\"message assistant typing\" [attr.aria-label]=\"uiCopy.typingLabel\">\n <span></span>\n <span></span>\n <span></span>\n </article>\n }\n </div>\n\n <form class=\"assistant-composer\" (ngSubmit)=\"sendMessage()\">\n <textarea\n pTextarea\n name=\"assistantPrompt\"\n rows=\"2\"\n [placeholder]=\"uiCopy.placeholder\"\n [ngModel]=\"input()\"\n (ngModelChange)=\"input.set($event)\"\n (keydown)=\"onComposerKeydown($event)\"\n >\n </textarea>\n <button\n pButton\n type=\"submit\"\n icon=\"pi pi-send\"\n aria-label=\"Send message\"\n [disabled]=\"!input().trim() || isSending()\"\n ></button>\n </form>\n </section>\n</p-drawer>\n","/*\n * Public API Surface of max-agent-ui\n */\n\nexport * from './lib/components/assistant/max-assistant.component';\nexport * from './lib/config/assistant.config';\nexport * from './lib/models/assistant.models';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"max-agent-ui.mjs","sources":["../../../projects/max-agent-ui/src/lib/config/assistant-bootstrap.config.ts","../../../projects/max-agent-ui/src/lib/config/assistant.config.ts","../../../projects/max-agent-ui/src/lib/components/assistant/max-assistant.service.ts","../../../projects/max-agent-ui/src/lib/components/assistant/max-assistant.component.ts","../../../projects/max-agent-ui/src/lib/components/assistant/max-assistant.component.html","../../../projects/max-agent-ui/src/public-api.ts","../../../projects/max-agent-ui/src/max-agent-ui.ts"],"sourcesContent":["import { AssistantProduct } from '../models/assistant.models';\n\nexport interface AssistantBootstrapConfig {\n initialMessage?: string;\n initialSuggestions: string[];\n}\n\nconst DEFAULT_ASSISTANT_BOOTSTRAP: AssistantBootstrapConfig = {\n initialMessage: undefined,\n initialSuggestions: []\n};\n\nconst ASSISTANT_BOOTSTRAP_BY_APP: Record<string, AssistantBootstrapConfig> = {\n cortex: {\n initialMessage: 'Hi, I am Max, the Maxtime Virtual Assistant. How can I help you today?',\n initialSuggestions: [\n 'What sessions are scheduled for today?',\n 'Which lecturers have planned leave this week?',\n 'List the students who are on leave today.',\n 'List the students who were absent from sessions yesterday.',\n 'Generate the attendance report for a session conducted yesterday.'\n ]\n },\n nemesys: {\n initialMessage: 'Hi, I am Max, the Maxtime Virtual Assistant. How can I help you today?',\n initialSuggestions: ['Show scheduling plans', 'Check resource availability', 'Find conflicts']\n },\n attendance: {\n initialMessage: 'Hi, I am Max, the Maxtime Virtual Assistant. How can I help you today?',\n initialSuggestions: ['Show attendance summary', 'Find missing attendance', 'View reports']\n }\n};\n\nexport function getAssistantBootstrapConfig(app?: AssistantProduct): AssistantBootstrapConfig {\n const appKey = app?.trim().toLowerCase();\n\n if (!appKey) {\n return DEFAULT_ASSISTANT_BOOTSTRAP;\n }\n\n return ASSISTANT_BOOTSTRAP_BY_APP[appKey] ?? DEFAULT_ASSISTANT_BOOTSTRAP;\n}\n","import { InjectionToken } from '@angular/core';\n\nimport { AssistantProduct, AssistantUser } from '../models/assistant.models';\n\nexport interface MaxAssistantConfig {\n assistantApiUrl?: string;\n app?: AssistantProduct;\n user?: Partial<AssistantUser> | (() => Partial<AssistantUser>);\n}\n\nexport const MAX_ASSISTANT_CONFIG = new InjectionToken<MaxAssistantConfig>(\n 'MAX_ASSISTANT_CONFIG',\n {\n factory: () => ({})\n }\n);\n","import { HttpClient } from '@angular/common/http';\nimport { inject, Injectable } from '@angular/core';\nimport { Observable, throwError } from 'rxjs';\n\nimport { MAX_ASSISTANT_CONFIG, MaxAssistantConfig } from '../../config/assistant.config';\nimport {\n AssistantChatRequest,\n AssistantChatResponse,\n AssistantProduct,\n AssistantUser\n} from '../../models/assistant.models';\n\nconst DEFAULT_ASSISTANT_CHAT_URL =\n 'https://fhmaof3b4kaxqfbnomfstxyhw40rrcjr.lambda-url.eu-west-2.on.aws/chat';\nconst DEFAULT_APP = 'cortex';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MaxAssistantService {\n private readonly config = inject(MAX_ASSISTANT_CONFIG);\n private readonly http = inject(HttpClient, { optional: true });\n\n sendMessage(\n message: string,\n conversationId?: string,\n config: MaxAssistantConfig = {}\n ): Observable<AssistantChatResponse> {\n const assistantConfig = {\n ...this.config,\n ...config\n };\n const request: AssistantChatRequest = {\n message,\n conversationId,\n app: this.getApp(assistantConfig),\n user: this.getUser(assistantConfig)\n };\n\n return this.postMessage(request, assistantConfig);\n }\n\n private postMessage(\n request: AssistantChatRequest,\n config: MaxAssistantConfig\n ): Observable<AssistantChatResponse> {\n if (!this.http) {\n return throwError(\n () => new Error('HttpClient is not available. Add provideHttpClient() to the host app.')\n );\n }\n\n return this.http.post<AssistantChatResponse>(this.getChatUrl(config), request);\n }\n\n private getChatUrl(config: MaxAssistantConfig): string {\n return config.assistantApiUrl?.trim() || DEFAULT_ASSISTANT_CHAT_URL;\n }\n\n private getApp(config: MaxAssistantConfig): AssistantProduct {\n return config.app || DEFAULT_APP;\n }\n\n private getUser(config: MaxAssistantConfig): AssistantUser {\n if (typeof config.user === 'function') {\n return config.user();\n }\n\n return config.user ?? {};\n }\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, DestroyRef, ElementRef, inject, Input, signal, ViewChild } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { FormsModule } from '@angular/forms';\nimport { ButtonModule } from 'primeng/button';\nimport { DrawerModule } from 'primeng/drawer';\nimport { TextareaModule } from 'primeng/textarea';\nimport { TooltipModule } from 'primeng/tooltip';\n\nimport {\n AssistantBootstrapConfig,\n getAssistantBootstrapConfig\n} from '../../config/assistant-bootstrap.config';\nimport { MaxAssistantConfig } from '../../config/assistant.config';\nimport {\n AssistantChatResponse,\n AssistantDisplayResponse,\n AssistantExtractedIntent,\n AssistantFieldMap,\n AssistantMessage,\n AssistantProduct,\n AssistantUser\n} from '../../models/assistant.models';\nimport { MaxAssistantService } from './max-assistant.service';\n\nconst ASSISTANT_UI_COPY = {\n title: 'Max',\n subtitle: 'Maxtime Virtual Assistant',\n launcherLabel: 'Open Maxtime virtual assistant',\n openTooltip: 'Open Maxtime virtual assistant',\n closeLabel: 'Close Maxtime virtual assistant',\n placeholder: 'Ask Maxtime virtual assistant',\n typingLabel: 'Maxtime virtual assistant is typing',\n errorMessage: 'Maxtime virtual assistant could not be reached. Please try again.'\n};\n\n@Component({\n selector: 'max-assistant',\n imports: [CommonModule, FormsModule, ButtonModule, DrawerModule, TextareaModule, TooltipModule],\n templateUrl: './max-assistant.component.html',\n styleUrl: './max-assistant.component.scss'\n})\nexport class MaxAssistantComponent {\n @ViewChild('messagesViewport') private messagesViewport?: ElementRef<HTMLElement>;\n\n @Input() app?: AssistantProduct;\n @Input() assistantApiUrl?: string;\n @Input() user:\n | Partial<AssistantUser>\n | (() => Partial<AssistantUser>) = {};\n\n protected readonly panelVisible = signal(false);\n protected readonly isSending = signal(false);\n protected readonly input = signal('');\n protected readonly conversationId = signal<string | undefined>(undefined);\n protected readonly messages = signal<AssistantMessage[]>([]);\n protected readonly expandedInferenceMessageIds = signal<ReadonlySet<string>>(new Set<string>());\n\n private readonly assistantService = inject(MaxAssistantService);\n private readonly destroyRef = inject(DestroyRef);\n\n protected openPanel() {\n this.panelVisible.set(true);\n\n if (!this.messages().length && this.bootstrapConfig.initialMessage) {\n this.messages.set([\n this.createMessage(\n 'assistant',\n this.bootstrapConfig.initialMessage,\n this.bootstrapConfig.initialSuggestions\n )\n ]);\n }\n\n this.scrollToLatest();\n }\n\n protected get uiCopy(): typeof ASSISTANT_UI_COPY {\n return ASSISTANT_UI_COPY;\n }\n\n protected get bootstrapConfig(): AssistantBootstrapConfig {\n return getAssistantBootstrapConfig(this.app);\n }\n\n protected closePanel() {\n this.panelVisible.set(false);\n }\n\n protected sendMessage(message = this.input()) {\n const trimmedMessage = message.trim();\n\n if (!trimmedMessage || this.isSending()) {\n return;\n }\n\n this.input.set('');\n this.appendMessage(this.createMessage('user', trimmedMessage));\n this.isSending.set(true);\n\n this.assistantService\n .sendMessage(trimmedMessage, this.conversationId(), this.getAssistantConfig())\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: response => {\n this.conversationId.set(response.conversationId);\n this.appendMessage(this.createAssistantResponseMessage(response, trimmedMessage));\n this.isSending.set(false);\n },\n error: () => {\n this.appendMessage({\n ...this.createMessage('assistant', this.uiCopy.errorMessage),\n isError: true\n });\n this.isSending.set(false);\n }\n });\n }\n\n protected useSuggestion(suggestion: string) {\n this.sendMessage(suggestion);\n }\n\n protected onComposerKeydown(event: KeyboardEvent) {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n this.sendMessage();\n }\n }\n\n protected isInferenceDetailsVisible(messageId: string): boolean {\n return this.expandedInferenceMessageIds().has(messageId);\n }\n\n protected toggleInferenceDetails(messageId: string) {\n const willOpen = !this.isInferenceDetailsVisible(messageId);\n\n this.expandedInferenceMessageIds.update(expandedIds => {\n const nextExpandedIds = new Set(expandedIds);\n\n if (nextExpandedIds.has(messageId)) {\n nextExpandedIds.delete(messageId);\n } else {\n nextExpandedIds.add(messageId);\n }\n\n return nextExpandedIds;\n });\n\n if (willOpen) {\n this.scrollToLatest();\n }\n }\n\n private getAssistantConfig(): MaxAssistantConfig {\n return {\n assistantApiUrl: this.assistantApiUrl,\n app: this.app,\n user: this.user\n };\n }\n\n private appendMessage(message: AssistantMessage) {\n this.messages.update(messages => [...messages, message]);\n this.scrollToLatest();\n }\n\n private createAssistantResponseMessage(\n response: AssistantChatResponse,\n userQuery: string\n ): AssistantMessage {\n const displayResponse = this.createDisplayResponse(response, userQuery);\n\n return this.createMessage(\n 'assistant',\n displayResponse.agentInferredResponse || response.answer,\n response.suggestions,\n response.sources,\n response.intent,\n response.intentLabel,\n response.app,\n response.productLabel,\n response.apiModule,\n response.confidence,\n response.parameters ?? response.entities,\n response.apiCalls,\n response.mockResult,\n response.llmUsed,\n response.availableModules,\n displayResponse\n );\n }\n\n private createMessage(\n role: AssistantMessage['role'],\n content: string,\n suggestions: string[] = [],\n sources: AssistantMessage['sources'] = [],\n intent?: string,\n intentLabel?: string,\n app?: string,\n productLabel?: string,\n apiModule?: string,\n confidence?: number,\n parameters?: AssistantFieldMap,\n apiCalls?: AssistantMessage['apiCalls'],\n mockResult?: AssistantFieldMap,\n llmUsed?: boolean,\n availableModules?: string[],\n displayResponse?: AssistantDisplayResponse\n ): AssistantMessage {\n return {\n id: this.createId(),\n role,\n content,\n displayResponse,\n formattedParameters: this.formatJson(displayResponse?.agentExtractedIntent?.parameters),\n formattedApiBody: this.formatJson(displayResponse?.agentExtractedIntent?.api?.body),\n formattedApiResponse: this.formatJson(displayResponse?.apiResponse),\n suggestions,\n sources,\n intent,\n intentLabel,\n app,\n productLabel,\n apiModule,\n confidence,\n parameters,\n entities: parameters,\n apiCalls,\n mockResult,\n llmUsed,\n availableModules,\n createdAt: new Date()\n };\n }\n\n private createDisplayResponse(\n response: AssistantChatResponse,\n userQuery: string\n ): AssistantDisplayResponse {\n const provided = response.displayResponse ?? {};\n const extractedIntent = this.createExtractedIntent(response, provided.agentExtractedIntent);\n\n return {\n userQuery: provided.userQuery || userQuery,\n agentInferredResponse: provided.agentInferredResponse || response.answer,\n agentExtractedIntent: extractedIntent,\n apiResponse: provided.apiResponse ?? this.getApiResponseFallback(response),\n markdown: provided.markdown\n };\n }\n\n private createExtractedIntent(\n response: AssistantChatResponse,\n provided?: AssistantExtractedIntent\n ): AssistantExtractedIntent {\n return {\n project: provided?.project ?? response.productLabel ?? response.app,\n projectKey: provided?.projectKey ?? response.app,\n module: provided?.module ?? response.apiModule,\n intent: provided?.intent ?? response.intent,\n intentLabel: provided?.intentLabel ?? response.intentLabel,\n confidence: provided?.confidence ?? response.confidence,\n parameters: provided?.parameters ?? response.parameters ?? response.entities,\n api: provided?.api ?? response.apiCalls?.[0]\n };\n }\n\n private getApiResponseFallback(response: AssistantChatResponse): AssistantFieldMap | undefined {\n if (!response.mockResult || !Object.keys(response.mockResult).length) {\n return undefined;\n }\n\n return response.mockResult;\n }\n\n private formatJson(value: unknown): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n return JSON.stringify(value, null, 2);\n }\n\n private createId(): string {\n return globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random()}`;\n }\n\n private scrollToLatest() {\n setTimeout(() => {\n const element = this.messagesViewport?.nativeElement;\n\n if (element) {\n element.scrollTop = element.scrollHeight;\n }\n });\n }\n}\n","<button\n pButton\n type=\"button\"\n class=\"assistant-launcher\"\n [attr.aria-label]=\"uiCopy.launcherLabel\"\n [pTooltip]=\"uiCopy.openTooltip\"\n tooltipPosition=\"left\"\n (click)=\"openPanel()\"\n>\n <span class=\"mascot\" aria-hidden=\"true\"></span>\n</button>\n\n<p-drawer\n [visible]=\"panelVisible()\"\n (visibleChange)=\"panelVisible.set($event)\"\n position=\"right\"\n styleClass=\"assistant-drawer\"\n [modal]=\"false\"\n [blockScroll]=\"false\"\n [showCloseIcon]=\"false\"\n>\n <section class=\"assistant-panel\" [attr.aria-label]=\"uiCopy.title\">\n <header class=\"assistant-header\">\n <span class=\"mascot large\" aria-hidden=\"true\"></span>\n <div>\n <h2>{{ uiCopy.title }}</h2>\n <span>{{ uiCopy.subtitle }}</span>\n </div>\n <button\n pButton\n type=\"button\"\n icon=\"pi pi-times\"\n text\n rounded\n severity=\"secondary\"\n [attr.aria-label]=\"uiCopy.closeLabel\"\n (click)=\"closePanel()\"\n ></button>\n </header>\n\n <div #messagesViewport class=\"assistant-messages\">\n @for(message of messages(); track message.id) {\n <article class=\"message {{ message.role }}\" [class.error]=\"message.isError\">\n @if(message.displayResponse; as responseDetails) {\n <p class=\"assistant-result\">{{ responseDetails.agentInferredResponse || message.content }}</p>\n <button\n type=\"button\"\n class=\"inference-toggle\"\n [attr.aria-expanded]=\"isInferenceDetailsVisible(message.id)\"\n (click)=\"toggleInferenceDetails(message.id)\"\n >\n {{ isInferenceDetailsVisible(message.id) ? 'Hide Details' : 'Show Details' }}\n </button>\n\n @if(isInferenceDetailsVisible(message.id)) {\n <div class=\"response-details\">\n @if(responseDetails.userQuery) {\n <section class=\"response-section\">\n <h3>User Query</h3>\n <p class=\"quoted\">\"{{ responseDetails.userQuery }}\"</p>\n </section>\n }\n\n @if(responseDetails.agentExtractedIntent; as intent) {\n <section class=\"response-section\">\n <h3>Agent Extracted Intent</h3>\n <dl class=\"detail-grid\">\n @if(intent.project || intent.projectKey) {\n <div>\n <dt>Project</dt>\n <dd>\n {{ intent.project || intent.projectKey }}\n @if(intent.projectKey) {\n <span>{{ intent.projectKey }}</span>\n }\n </dd>\n </div>\n }\n @if(intent.module) {\n <div>\n <dt>Module</dt>\n <dd>{{ intent.module }}</dd>\n </div>\n }\n @if(intent.intentLabel) {\n <div>\n <dt>Intent Label</dt>\n <dd>{{ intent.intentLabel }}</dd>\n </div>\n }\n @if(intent.intent) {\n <div>\n <dt>Intent</dt>\n <dd>{{ intent.intent }}</dd>\n </div>\n }\n @if(intent.confidence !== undefined) {\n <div>\n <dt>Confidence</dt>\n <dd>{{ intent.confidence | percent: '1.0-0' }}</dd>\n </div>\n }\n </dl>\n\n @if(message.formattedParameters) {\n <div class=\"json-block\">\n <strong>Parameters</strong>\n <pre>{{ message.formattedParameters }}</pre>\n </div>\n }\n\n @if(intent.api?.url || intent.api?.method) {\n <div class=\"api-call-summary\">\n <strong>API Called</strong>\n <code>{{ intent.api?.method || 'GET' }} {{ intent.api?.url || 'URL not provided' }}</code>\n </div>\n }\n\n @if(message.formattedApiBody) {\n <div class=\"json-block\">\n <strong>API Body</strong>\n <pre>{{ message.formattedApiBody }}</pre>\n </div>\n }\n </section>\n }\n\n @if(message.formattedApiResponse) {\n <section class=\"response-section\">\n <h3>API Response</h3>\n <div class=\"json-block\">\n <strong>JSON</strong>\n <pre>{{ message.formattedApiResponse }}</pre>\n </div>\n </section>\n }\n </div>\n }\n } @else {\n <p>{{ message.content }}</p>\n }\n @if(message.role === 'assistant' && message.suggestions?.length) {\n <div class=\"suggestions\">\n @for(suggestion of message.suggestions ?? []; track suggestion) {\n <button\n pButton\n type=\"button\"\n size=\"small\"\n text\n severity=\"secondary\"\n class=\"suggestion-chip\"\n [label]=\"suggestion\"\n (click)=\"useSuggestion(suggestion)\"\n ></button>\n }\n </div>\n }\n </article>\n }\n @if(isSending()) {\n <article class=\"message assistant typing\" [attr.aria-label]=\"uiCopy.typingLabel\">\n <span></span>\n <span></span>\n <span></span>\n </article>\n }\n </div>\n\n <form class=\"assistant-composer\" (ngSubmit)=\"sendMessage()\">\n <textarea\n pTextarea\n name=\"assistantPrompt\"\n rows=\"2\"\n [placeholder]=\"uiCopy.placeholder\"\n [ngModel]=\"input()\"\n (ngModelChange)=\"input.set($event)\"\n (keydown)=\"onComposerKeydown($event)\"\n >\n </textarea>\n <button\n pButton\n type=\"submit\"\n icon=\"pi pi-send\"\n aria-label=\"Send message\"\n [disabled]=\"!input().trim() || isSending()\"\n ></button>\n </form>\n </section>\n</p-drawer>\n","/*\n * Public API Surface of max-agent-ui\n */\n\nexport * from './lib/components/assistant/max-assistant.component';\nexport * from './lib/config/assistant.config';\nexport * from './lib/models/assistant.models';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "max-agent-ui",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/"
6
6
  },
@@ -46,10 +46,6 @@ interface AssistantChatRequest {
46
46
  app: AssistantProduct;
47
47
  user: AssistantUser;
48
48
  }
49
- interface InitialConfig {
50
- initialMessage?: string;
51
- initialSuggestions?: string[];
52
- }
53
49
  interface AssistantChatResponse {
54
50
  answer: string;
55
51
  conversationId: string;
@@ -96,6 +92,11 @@ interface AssistantMessage {
96
92
  isError?: boolean;
97
93
  }
98
94
 
95
+ interface AssistantBootstrapConfig {
96
+ initialMessage?: string;
97
+ initialSuggestions: string[];
98
+ }
99
+
99
100
  declare const ASSISTANT_UI_COPY: {
100
101
  title: string;
101
102
  subtitle: string;
@@ -106,12 +107,11 @@ declare const ASSISTANT_UI_COPY: {
106
107
  typingLabel: string;
107
108
  errorMessage: string;
108
109
  };
109
- type AssistantBootstrapConfig = Pick<InitialConfig, 'initialMessage'> & Required<Pick<InitialConfig, 'initialSuggestions'>>;
110
110
  declare class MaxAssistantComponent {
111
111
  private messagesViewport?;
112
112
  app?: AssistantProduct;
113
+ assistantApiUrl?: string;
113
114
  user: Partial<AssistantUser> | (() => Partial<AssistantUser>);
114
- initialConfig: InitialConfig;
115
115
  protected readonly panelVisible: _angular_core.WritableSignal<boolean>;
116
116
  protected readonly isSending: _angular_core.WritableSignal<boolean>;
117
117
  protected readonly input: _angular_core.WritableSignal<string>;
@@ -140,7 +140,7 @@ declare class MaxAssistantComponent {
140
140
  private createId;
141
141
  private scrollToLatest;
142
142
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MaxAssistantComponent, never>;
143
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<MaxAssistantComponent, "max-assistant", never, { "app": { "alias": "app"; "required": false; }; "user": { "alias": "user"; "required": false; }; "initialConfig": { "alias": "initialConfig"; "required": false; }; }, {}, never, never, true, never>;
143
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MaxAssistantComponent, "max-assistant", never, { "app": { "alias": "app"; "required": false; }; "assistantApiUrl": { "alias": "assistantApiUrl"; "required": false; }; "user": { "alias": "user"; "required": false; }; }, {}, never, never, true, never>;
144
144
  }
145
145
 
146
146
  interface MaxAssistantConfig {
@@ -151,4 +151,4 @@ interface MaxAssistantConfig {
151
151
  declare const MAX_ASSISTANT_CONFIG: InjectionToken<MaxAssistantConfig>;
152
152
 
153
153
  export { MAX_ASSISTANT_CONFIG, MaxAssistantComponent };
154
- export type { AssistantApiCall, AssistantChatRequest, AssistantChatResponse, AssistantDisplayResponse, AssistantExtractedIntent, AssistantFieldMap, AssistantFieldValue, AssistantMessage, AssistantProduct, AssistantSource, AssistantUser, InitialConfig, MaxAssistantConfig };
154
+ export type { AssistantApiCall, AssistantChatRequest, AssistantChatResponse, AssistantDisplayResponse, AssistantExtractedIntent, AssistantFieldMap, AssistantFieldValue, AssistantMessage, AssistantProduct, AssistantSource, AssistantUser, MaxAssistantConfig };