@sinequa/assistant 3.1.1 → 3.2.0

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,12 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, inject, Component, Input, Output, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, ContentChild } from '@angular/core';
2
+ import { Injectable, EventEmitter, inject, Component, Input, Output, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, ContentChild, Inject } from '@angular/core';
3
3
  import { Subscription, filter, tap, switchMap, BehaviorSubject, Subject, forkJoin, map, catchError, throwError, shareReplay, fromEvent, merge, takeUntil, finalize } from 'rxjs';
4
4
  import * as i3 from '@sinequa/core/web-services';
5
5
  import { PrincipalWebService, UserSettingsWebService, AuditWebService, SignalRWebService, JsonMethodPluginService } from '@sinequa/core/web-services';
6
6
  import * as i1 from '@angular/common';
7
7
  import { CommonModule } from '@angular/common';
8
8
  import * as i2 from '@angular/forms';
9
- import { FormsModule } from '@angular/forms';
9
+ import { FormsModule, Validators, UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
10
10
  import { LoginService, AuthenticationService } from '@sinequa/core/login';
11
11
  import { Action } from '@sinequa/components/action';
12
12
  import { AbstractFacet } from '@sinequa/components/facet';
@@ -16,9 +16,12 @@ import { UserPreferences } from '@sinequa/components/user-settings';
16
16
  import { NotificationsService } from '@sinequa/core/notification';
17
17
  import { z } from 'zod';
18
18
  import { AppService } from '@sinequa/core/app-utils';
19
- import { IntlService } from '@sinequa/core/intl';
19
+ import * as i6$1 from '@sinequa/core/intl';
20
+ import { IntlService, IntlModule } from '@sinequa/core/intl';
20
21
  import get from 'lodash/get';
21
22
  import { Utils } from '@sinequa/core/base';
23
+ import * as i1$2 from '@sinequa/core/modal';
24
+ import { ModalService, ModalButton, ModalModule, MODAL_MODEL } from '@sinequa/core/modal';
22
25
  import { HttpTransportType, LogLevel } from '@microsoft/signalr';
23
26
  import { unified } from 'unified';
24
27
  import remarkParse from 'remark-parse';
@@ -31,8 +34,13 @@ import { CollapseModule } from '@sinequa/components/collapse';
31
34
  import * as i6 from 'ngx-remark';
32
35
  import { RemarkModule } from 'ngx-remark';
33
36
  import SafeColor from 'safecolor';
34
- import { ModalService, ModalButton, ModalModule } from '@sinequa/core/modal';
37
+ import 'prismjs-components-importer/esm';
38
+ import 'prismjs/plugins/autoloader/prism-autoloader';
35
39
  import { parseISO, isToday, isYesterday, isThisWeek, differenceInDays, endOfYesterday, isThisMonth, differenceInMonths, isThisQuarter, isThisYear, differenceInYears, format } from 'date-fns';
40
+ import * as i4 from '@sinequa/components/modal';
41
+ import { BsModalModule } from '@sinequa/components/modal';
42
+ import * as i5$1 from '@sinequa/core/validation';
43
+ import { ValidationModule } from '@sinequa/core/validation';
36
44
 
37
45
  /**
38
46
  * A service to create and manage instances of ChatService dynamically based on the provided component references and the implementation type (http or websocket)
@@ -83,6 +91,7 @@ class ChatSettingsV3Component {
83
91
  this._update = new EventEmitter();
84
92
  this._cancel = new EventEmitter();
85
93
  this.subscription = new Subscription();
94
+ this.functions = [];
86
95
  this.isAdmin = false;
87
96
  this.loginService = inject(LoginService);
88
97
  this.instanceManagerService = inject(InstanceManagerService);
@@ -93,8 +102,8 @@ class ChatSettingsV3Component {
93
102
  this.isAdmin = this.principalService.principal.isAdministrator;
94
103
  // Init config with a copy of the original chat config, so that it won't be modified by the user until he clicks on save
95
104
  this.config = JSON.parse(JSON.stringify(this.chatService.chatConfig$.value));
96
- this.selectedModel = this.chatService.getModel(this.config.serviceSettings.service_id, this.config.serviceSettings.model_id);
97
- this.updateFunctionsCheckboxes();
105
+ this.selectedModel = this.chatService.getModel(this.config.defaultValues.service_id, this.config.defaultValues.model_id);
106
+ this.initFunctionsList();
98
107
  }));
99
108
  }
100
109
  ngOnDestroy() {
@@ -102,14 +111,14 @@ class ChatSettingsV3Component {
102
111
  }
103
112
  get hasPrompts() {
104
113
  return this.isAdmin
105
- || !!this.config.uiSettings.systemPrompt
106
- || !!this.config.uiSettings.userPrompt;
114
+ || !!this.config.uiSettings.displaySystemPrompt
115
+ || !!this.config.uiSettings.displayUserPrompt;
107
116
  }
108
117
  get hasAdvancedParameters() {
109
118
  return this.isAdmin
110
119
  || !!this.config.uiSettings.temperature
111
120
  || !!this.config.uiSettings.top_p
112
- || !!this.config.uiSettings.maxTokens;
121
+ || !!this.config.uiSettings.max_tokens;
113
122
  }
114
123
  get hasModel() {
115
124
  return this.isAdmin
@@ -118,49 +127,47 @@ class ChatSettingsV3Component {
118
127
  || !!this.config.uiSettings.debug
119
128
  || !!this.config.uiSettings.temperature
120
129
  || !!this.config.uiSettings.top_p
121
- || !!this.config.uiSettings.maxTokens;
130
+ || !!this.config.uiSettings.max_tokens;
122
131
  }
123
132
  instantiateChatService() {
124
133
  this.chatService = this.instanceManagerService.getInstance(this.instanceId);
125
134
  }
126
135
  onChatModelChange(selectedModel) {
127
136
  // Update properties based on the selected model
128
- this.config.serviceSettings.service_id = selectedModel.serviceId;
129
- this.config.serviceSettings.model_id = selectedModel.modelId;
137
+ this.config.defaultValues.service_id = selectedModel.serviceId;
138
+ this.config.defaultValues.model_id = selectedModel.modelId;
139
+ }
140
+ getFunctionDescription(name) {
141
+ var _a, _b;
142
+ return ((_b = (_a = this.chatService.functions) === null || _a === void 0 ? void 0 : _a.find(fn => fn.functionName === name)) === null || _b === void 0 ? void 0 : _b.description) || "";
130
143
  }
131
144
  toggleFunctionsSelection(name) {
132
- if (this.config.functions.includes(name)) {
133
- this.config.functions = this.config.functions.filter(item => item !== name);
134
- }
135
- else {
136
- this.config.functions.push(name);
137
- }
145
+ // Update the enabled property of the function
146
+ const index = this.config.defaultValues.functions.findIndex(func => func.name === name);
147
+ this.config.defaultValues.functions[index].enabled = this.functions[index].enabled;
138
148
  }
139
- updateFunctionsCheckboxes() {
140
- // Update the checkboxes based on config.functions
141
- (this.chatService.functions || []).forEach(item => {
142
- item['selected'] = this.config.functions.includes(item.functionName);
143
- });
149
+ initFunctionsList() {
150
+ this.functions = this.config.defaultValues.functions.filter(func => { var _a; return !!((_a = this.chatService.functions) === null || _a === void 0 ? void 0 : _a.find(fn => fn.functionName === func.name)); });
144
151
  }
145
152
  /**
146
153
  * Save the new chat config in the chat service and the user preferences
147
154
  */
148
155
  save() {
149
156
  this.chatService.updateChatConfig(this.config);
150
- this._update.emit();
157
+ this._update.emit(this.config);
151
158
  }
152
159
  /**
153
160
  * Cancel the current changes
154
161
  */
155
162
  cancel() {
156
- this._cancel.emit();
163
+ this._cancel.emit(this.chatService.chatConfig$.value);
157
164
  }
158
165
  }
159
166
  ChatSettingsV3Component.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatSettingsV3Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
160
- ChatSettingsV3Component.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatSettingsV3Component, isStandalone: true, selector: "sq-chat-settings-v3", inputs: { instanceId: "instanceId" }, outputs: { _update: "update", _cancel: "cancel" }, ngImport: i0, template: "<div class=\"sq-chat-settings\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n \n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of chatService.functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.functionName\" [(ngModel)]=\"func.selected\"\n (ngModelChange)=\"toggleFunctionsSelection(func.functionName)\">\n <label class=\"form-check-label\" [for]=\"func.functionName\" [title]=\"func.description\">{{ func.functionName }}</label>\n </div>\n </div>\n \n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n \n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.serviceSettings.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.serviceSettings.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.serviceSettings.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.serviceSettings.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.maxTokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.serviceSettings.maxTokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.serviceSettings.maxTokens\">\n </div>\n </details>\n \n <hr>\n \n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.systemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.uiSettings.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.userPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.uiSettings.userPrompt\"></textarea>\n </div>\n \n </div>\n \n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n \n</div>", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
167
+ ChatSettingsV3Component.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatSettingsV3Component, isStandalone: true, selector: "sq-chat-settings-v3", inputs: { instanceId: "instanceId" }, outputs: { _update: "update", _cancel: "cancel" }, ngImport: i0, template: "<div class=\"sq-chat-settings\" *ngIf=\"isAdmin || config.uiSettings.display\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n\n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.name\" [(ngModel)]=\"func.enabled\"\n (ngModelChange)=\"toggleFunctionsSelection(func.name)\">\n <label class=\"form-check-label\" [for]=\"func.name\" [title]=\"getFunctionDescription(func.name)\">{{ func.name }}</label>\n </div>\n </div>\n\n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.defaultValues.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n\n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.defaultValues.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.defaultValues.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.defaultValues.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.defaultValues.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.max_tokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.defaultValues.max_tokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.defaultValues.max_tokens\">\n </div>\n </details>\n\n <hr>\n\n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displaySystemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.defaultValues.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displayUserPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.defaultValues.userPrompt\"></textarea>\n </div>\n\n </div>\n\n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n\n</div>\n", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
161
168
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatSettingsV3Component, decorators: [{
162
169
  type: Component,
163
- args: [{ selector: 'sq-chat-settings-v3', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"sq-chat-settings\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n \n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of chatService.functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.functionName\" [(ngModel)]=\"func.selected\"\n (ngModelChange)=\"toggleFunctionsSelection(func.functionName)\">\n <label class=\"form-check-label\" [for]=\"func.functionName\" [title]=\"func.description\">{{ func.functionName }}</label>\n </div>\n </div>\n \n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n \n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.serviceSettings.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.serviceSettings.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.serviceSettings.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.serviceSettings.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.maxTokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.serviceSettings.maxTokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.serviceSettings.maxTokens\">\n </div>\n </details>\n \n <hr>\n \n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.systemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.uiSettings.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.userPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.uiSettings.userPrompt\"></textarea>\n </div>\n \n </div>\n \n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n \n</div>", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\n"] }]
170
+ args: [{ selector: 'sq-chat-settings-v3', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"sq-chat-settings\" *ngIf=\"isAdmin || config.uiSettings.display\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n\n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.name\" [(ngModel)]=\"func.enabled\"\n (ngModelChange)=\"toggleFunctionsSelection(func.name)\">\n <label class=\"form-check-label\" [for]=\"func.name\" [title]=\"getFunctionDescription(func.name)\">{{ func.name }}</label>\n </div>\n </div>\n\n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.defaultValues.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n\n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.defaultValues.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.defaultValues.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.defaultValues.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.defaultValues.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.max_tokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.defaultValues.max_tokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.defaultValues.max_tokens\">\n </div>\n </details>\n\n <hr>\n\n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displaySystemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.defaultValues.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displayUserPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.defaultValues.userPrompt\"></textarea>\n </div>\n\n </div>\n\n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n\n</div>\n", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\n"] }]
164
171
  }], propDecorators: { instanceId: [{
165
172
  type: Input
166
173
  }], _update: [{
@@ -171,8 +178,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
171
178
  args: ["cancel"]
172
179
  }] } });
173
180
 
174
- // Define the Zod representation for the globalSettings object
175
- const globalSettingsSchema = z.object({
181
+ // Define the Zod representation for the connectionSettings object
182
+ const connectionSettingsSchema = z.object({
176
183
  restEndpoint: z.string().optional(),
177
184
  websocketEndpoint: z.string().optional(),
178
185
  signalRTransport: z.enum(["WebSockets", "ServerSentEvents", "LongPolling", "None"]),
@@ -186,50 +193,10 @@ const serviceSettingsSchema = z.object({
186
193
  model_id: z.string(),
187
194
  temperature: z.number(),
188
195
  top_p: z.number(),
189
- maxTokens: z.number(),
190
- results_per_prompt: z.number(),
191
- presence_penalty: z.number(),
192
- frequency_penalty: z.number(),
193
- });
194
- // Define the Zod representation for the TextChunksOptions interface
195
- const textChunksOptionsSchema = z.object({
196
- extendMode: z.enum(['None', 'Sentence', 'Chars']).optional(),
197
- extendScope: z.number().optional(),
198
- });
199
- // Define the Zod representation for the contextOptions object
200
- const contextOptionsSchema = z.object({
201
- docColumns: z.array(z.string()),
202
- textChunkFillGaps: z.number(),
203
- html: z.boolean(),
204
- topPassagesOptions: z.object({
205
- topPassages: z.number(),
206
- topPassagesMinScore: z.number(),
207
- textChunkOptions: textChunksOptionsSchema,
208
- }),
209
- matchingPassagesOptions: z.object({
210
- matchingPassagesPerDoc: z.number(),
211
- fromTopDocuments: z.number(),
212
- matchingPassagesMinScore: z.number(),
213
- textChunkOptions: textChunksOptionsSchema,
214
- }),
215
- relevantExtractsOptions: z.object({
216
- topRelevantExtractsPerDoc: z.number(),
217
- fromTopDocuments: z.number(),
218
- textChunkOptions: textChunksOptionsSchema,
219
- }),
220
- htmlOptions: z.object({
221
- images: z.boolean(),
222
- links: z.boolean(),
223
- tables: z.boolean(),
224
- extendTables: z.boolean(),
225
- }),
226
- });
227
- // Define the Zod representation for the contextSettings object
228
- const contextSettingsSchema = z.object({
229
- app: z.string().optional(),
230
- query: z.object({}).optional(),
231
- contextOptions: contextOptionsSchema,
196
+ max_tokens: z.number()
232
197
  });
198
+ // Define the Zod representation for the additionalServiceSettings object
199
+ const additionalServiceSettingsSchema = z.object({});
233
200
  // Define the Zod representation for the uiSettings object
234
201
  const uiSettingsSchema = z.object({
235
202
  display: z.boolean(),
@@ -237,22 +204,58 @@ const uiSettingsSchema = z.object({
237
204
  functions: z.boolean(),
238
205
  temperature: z.boolean(),
239
206
  top_p: z.boolean(),
240
- maxTokens: z.boolean(),
207
+ max_tokens: z.boolean(),
241
208
  debug: z.boolean(),
242
209
  displaySystemPrompt: z.boolean(),
210
+ displayUserPrompt: z.boolean()
211
+ });
212
+ // Define the Zod representation for the defaultValues object
213
+ const defaultValuesSchema = z.object({
214
+ service_id: z.string(),
215
+ model_id: z.string(),
216
+ functions: z.array(z.object({
217
+ name: z.string(),
218
+ enabled: z.boolean()
219
+ })),
220
+ temperature: z.number(),
221
+ top_p: z.number(),
222
+ max_tokens: z.number(),
223
+ debug: z.boolean(),
243
224
  systemPrompt: z.string(),
225
+ userPrompt: z.string()
226
+ });
227
+ // Define the Zod representation for the modeSettings object
228
+ const initializationSchema = z.object({
229
+ event: z.enum(['Query', 'Prompt']),
230
+ forcedWorkflow: z.string().optional(),
231
+ displayUserQuery: z.boolean().optional(), // Optional for event 'Prompt'
232
+ }).refine(data => ((data.event === "Query") ? (!!data.forcedWorkflow && data.displayUserQuery !== undefined && data.displayUserQuery !== null) : true), {
233
+ message: "The 'forcedWorkflow' and 'displayUserQuery' properties must be provided when the initialization's event is 'Query'.",
234
+ });
235
+ const modeSettingsSchema = z.object({
236
+ enabledUserInput: z.boolean(),
244
237
  displayUserPrompt: z.boolean(),
245
- userPrompt: z.string(),
238
+ sendUserPrompt: z.boolean(),
239
+ initialization: initializationSchema
240
+ });
241
+ // Define the Zod representation for the savedChatSettings object
242
+ const savedChatSettingsSchema = z.object({
243
+ enabled: z.boolean(),
244
+ display: z.boolean()
245
+ });
246
+ // Define the Zod representation for the globalSettings object
247
+ const globalSettingsSchema = z.object({
248
+ disclaimer: z.string().optional(),
246
249
  });
247
250
  // Define the Zod representation for the entire ChatConfig object
248
251
  const chatConfigSchema = z.object({
249
- globalSettings: globalSettingsSchema,
250
- serviceSettings: serviceSettingsSchema,
251
- contextSettings: contextSettingsSchema,
252
+ connectionSettings: connectionSettingsSchema,
253
+ defaultValues: defaultValuesSchema,
254
+ modeSettings: modeSettingsSchema,
252
255
  uiSettings: uiSettingsSchema,
253
- functions: z.array(z.string()),
254
- debug: z.boolean(),
255
- saveChats: z.boolean()
256
+ additionalServiceSettings: additionalServiceSettingsSchema,
257
+ savedChatSettings: savedChatSettingsSchema,
258
+ globalSettings: globalSettingsSchema
256
259
  });
257
260
 
258
261
  class ChatService {
@@ -269,7 +272,6 @@ class ChatService {
269
272
  this.savedChats$ = new BehaviorSubject([]);
270
273
  /** Emit the saved chat to load */
271
274
  this.loadSavedChat$ = new BehaviorSubject(undefined);
272
- this.searchService = inject(SearchService);
273
275
  this.userSettingsService = inject(UserSettingsWebService);
274
276
  this.notificationsService = inject(NotificationsService);
275
277
  this.auditService = inject(AuditWebService);
@@ -277,6 +279,7 @@ class ChatService {
277
279
  this.loginService = inject(LoginService);
278
280
  this.appService = inject(AppService);
279
281
  this.intlService = inject(IntlService);
282
+ this.modalService = inject(ModalService);
280
283
  }
281
284
  get assistants() {
282
285
  if (!this.userSettingsService.userSettings)
@@ -314,22 +317,69 @@ class ChatService {
314
317
  this._savedChatId = savedChatId;
315
318
  }
316
319
  /**
317
- * Initialize the chat config by merging the default config with the user preferences and the app config
318
- * override desc order: user preferences > app config > default config
320
+ * Initialize the chat config by managing ONLY sub-object **defaultValues** configs of the standard app config (defined in the customization json tab ) and the user preferences.
321
+ * To do so, a tracking mechanism is implemented to notify the user about the available updates in the defaultValues object of the standard app config.
322
+ * The rest of the config object coming from "standard app config" is used as it is without any override.
323
+ * Thus, the user preferences are used only for the defaultValues object.
324
+ * This provide a centralized way to manage the rest of the config object by admins and ensure a unique common behavior for all users.
319
325
  */
320
326
  initChatConfig() {
321
- var _a, _b, _c;
327
+ var _a, _b, _c, _d, _e;
322
328
  const key = this.chatInstanceId;
323
329
  const userSettingsConfig = this.assistants[key] || {};
324
- const defaultChatConfig = (_c = (_b = (_a = this.appService.app) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.assistants) === null || _c === void 0 ? void 0 : _c[key];
325
- // Validate the object against the schema
330
+ const standardChatConfig = (_c = (_b = (_a = this.appService.app) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.assistants) === null || _c === void 0 ? void 0 : _c[key];
326
331
  try {
327
- chatConfigSchema.parse(defaultChatConfig);
328
- // Merge configs with override desc order: user preferences > app config > default config
329
- const chatConfig = Object.assign(Object.assign({}, defaultChatConfig), userSettingsConfig);
330
- // Update the chat config and store it in the user preferences
331
- this.updateChatConfig(chatConfig, false);
332
- this.initConfig$.next(true);
332
+ // Validate the whole config object against the schema
333
+ chatConfigSchema.parse(standardChatConfig);
334
+ // If the user preferences do not contain a config's defaultValues object, keep using the standard app config and nothing to store in the user preferences
335
+ if (!userSettingsConfig.defaultValues) {
336
+ this.chatConfig$.next(Object.assign({}, standardChatConfig));
337
+ this.initConfig$.next(true);
338
+ }
339
+ else { // If the user has its own defaultValues in its userSettings, then we need to check for potential updates made by admins in the meantime and how he wants to manage them
340
+ // Retrieve already stored hashes in the user settings if exists
341
+ const appliedDefaultValuesHash = (_d = userSettingsConfig.hashes) === null || _d === void 0 ? void 0 : _d["applied-defaultValues-hash"];
342
+ const skippedDefaultValuesHash = (_e = userSettingsConfig.hashes) === null || _e === void 0 ? void 0 : _e["skipped-defaultValues-hash"];
343
+ // Create a hash of the current defaultValues of the standardChatConfig
344
+ const currentDefaultValuesHash = Utils.sha512(JSON.stringify(standardChatConfig.defaultValues));
345
+ // Implement the tracking mechanism to notify the user about the available updates in the defaultValues object of the standard app config
346
+ const condition = (currentDefaultValuesHash !== appliedDefaultValuesHash) && (currentDefaultValuesHash !== skippedDefaultValuesHash);
347
+ if (condition) {
348
+ this.modalService
349
+ .confirm({
350
+ title: "Available updates !",
351
+ message: "Changes have been made to the default configuration. Do you want to update your own version ?",
352
+ buttons: [
353
+ new ModalButton({ result: -4 /* ModalResult.No */, text: "See no more" }),
354
+ new ModalButton({ result: -7 /* ModalResult.Ignore */, text: "Remind me later" }),
355
+ new ModalButton({ result: -1 /* ModalResult.OK */, text: "Update", primary: true })
356
+ ],
357
+ confirmType: 2 /* ConfirmType.Warning */
358
+ }).then(res => {
359
+ if (res === -1 /* ModalResult.OK */) {
360
+ const hashes = { "applied-defaultValues-hash": currentDefaultValuesHash, "skipped-defaultValues-hash": undefined };
361
+ // Update the chat config and store its defaultValues in the user preferences
362
+ this.updateChatConfig(Object.assign({}, standardChatConfig), hashes, true);
363
+ this.initConfig$.next(true);
364
+ }
365
+ else if (res === -4 /* ModalResult.No */) {
366
+ // Do not notify the user about changes while this skipped version is not updated
367
+ const hashes = Object.assign(Object.assign({}, userSettingsConfig.hashes), { "skipped-defaultValues-hash": currentDefaultValuesHash });
368
+ this.updateChatConfig(Object.assign(Object.assign({}, standardChatConfig), { defaultValues: userSettingsConfig.defaultValues }), hashes, false);
369
+ this.initConfig$.next(true);
370
+ }
371
+ else {
372
+ // Just pick the version in the user settings, nothing to be updated
373
+ this.chatConfig$.next(Object.assign(Object.assign({}, standardChatConfig), { defaultValues: userSettingsConfig.defaultValues }));
374
+ this.initConfig$.next(true);
375
+ }
376
+ });
377
+ }
378
+ else { // No available updates Or updates has been already skipped, then just pick the version in the user settings
379
+ this.chatConfig$.next(Object.assign(Object.assign({}, standardChatConfig), { defaultValues: userSettingsConfig.defaultValues }));
380
+ this.initConfig$.next(true);
381
+ }
382
+ }
333
383
  }
334
384
  catch (error) {
335
385
  this.notificationsService.error(`Missing valid configuration for the assistant instance '${key}'`);
@@ -337,25 +387,25 @@ class ChatService {
337
387
  }
338
388
  }
339
389
  /**
340
- * Update the chat config and store it in the user preferences
390
+ * Update the chat config and store its defaultValues in the user preferences
341
391
  * @param config The updated chat config
342
392
  * @param notify Whether to notify the user about the update
343
393
  * @param successCallback The callback to execute if the update is successful
344
394
  * @param errorCallback The callback to execute if the update fails
345
395
  */
346
- updateChatConfig(config, notify = true, successCallback, errorCallback) {
396
+ updateChatConfig(config, hashes, notify = true, successCallback, errorCallback) {
347
397
  this.chatConfig$.next(config);
348
398
  const assistants = Object.assign({}, this.assistants);
349
- assistants[this.chatInstanceId] = config;
350
- this.userSettingsService.patch({ assistants }).subscribe(next => {
351
- if (notify) {
352
- successCallback ? successCallback() : this.notificationsService.success(`The configuration of the assistant instance '${this.chatInstanceId}' has been successfully updated`);
353
- }
354
- }, error => {
399
+ assistants[this.chatInstanceId] = Object.assign(Object.assign({}, assistants[this.chatInstanceId]), { defaultValues: config.defaultValues, hashes });
400
+ this.userSettingsService.patch({ assistants }).subscribe(next => { }, error => {
355
401
  if (notify) {
356
402
  errorCallback ? errorCallback() : this.notificationsService.error(`The update of the assistant instance '${this.chatInstanceId}' configuration failed`);
357
403
  }
358
404
  console.error("Could not patch assistants!", error);
405
+ }, () => {
406
+ if (notify) {
407
+ successCallback ? successCallback() : this.notificationsService.success(`The assistant instance '${this.chatInstanceId}' configuration has been successfully updated`);
408
+ }
359
409
  });
360
410
  }
361
411
  /**
@@ -479,8 +529,8 @@ class WebSocketChatService extends ChatService {
479
529
  * It can be overridden by the app config
480
530
  */
481
531
  getRequestsUrl() {
482
- if (this.chatConfig$.value.globalSettings.websocketEndpoint) {
483
- this.REQUEST_URL = this.chatConfig$.value.globalSettings.websocketEndpoint;
532
+ if (this.chatConfig$.value.connectionSettings.websocketEndpoint) {
533
+ this.REQUEST_URL = this.chatConfig$.value.connectionSettings.websocketEndpoint;
484
534
  }
485
535
  else {
486
536
  throw new Error(`The property 'websocketEndpoint' must be provided when attempting to use 'WebSocket' in assistant instance`);
@@ -495,7 +545,7 @@ class WebSocketChatService extends ChatService {
495
545
  modelsSubject.complete();
496
546
  });
497
547
  // Send the request to get the list of models
498
- this.connection.invoke('ListModels', { debug: this.chatConfig$.value.debug })
548
+ this.connection.invoke('ListModels', { debug: this.chatConfig$.value.defaultValues.debug })
499
549
  .catch(error => {
500
550
  console.error('Error invoking ListModels:', error);
501
551
  modelsSubject.complete();
@@ -506,12 +556,13 @@ class WebSocketChatService extends ChatService {
506
556
  listFunctions() {
507
557
  const functionsSubject = new Subject();
508
558
  this.connection.on('ListFunctions', (res) => {
509
- this.functions = res.functions;
559
+ var _a;
560
+ this.functions = (_a = res.functions) === null || _a === void 0 ? void 0 : _a.filter(func => func.enabled);
510
561
  functionsSubject.next(this.functions);
511
562
  functionsSubject.complete();
512
563
  });
513
564
  // Send the request to get the list of functions
514
- this.connection.invoke('ListFunctions', { debug: this.chatConfig$.value.debug })
565
+ this.connection.invoke('ListFunctions', { debug: this.chatConfig$.value.defaultValues.debug })
515
566
  .catch(error => {
516
567
  console.error('Error invoking ListFunctions:', error);
517
568
  functionsSubject.complete();
@@ -519,18 +570,22 @@ class WebSocketChatService extends ChatService {
519
570
  });
520
571
  return functionsSubject.asObservable();
521
572
  }
522
- fetch(messages, query = this.searchService.query) {
573
+ fetch(messages, query) {
574
+ var _a;
523
575
  // Start streaming by invoking the Chat method
524
576
  this.streaming$.next(true);
525
577
  // Prepare the payload to send to the Chat method
526
578
  const data = {
527
579
  history: messages,
528
- functions: this.chatConfig$.value.functions,
529
- debug: this.chatConfig$.value.debug,
530
- serviceSettings: this.chatConfig$.value.serviceSettings,
531
- contextSettings: Object.assign(Object.assign({}, this.chatConfig$.value.contextSettings), { app: this.appService.appName, query })
580
+ functions: (_a = this.chatConfig$.value.defaultValues.functions) === null || _a === void 0 ? void 0 : _a.filter(func => func.enabled).map(func => func.name),
581
+ debug: this.chatConfig$.value.defaultValues.debug,
582
+ serviceSettings: Object.assign({ service_id: this.chatConfig$.value.defaultValues.service_id, model_id: this.chatConfig$.value.defaultValues.model_id, top_p: this.chatConfig$.value.defaultValues.top_p, temperature: this.chatConfig$.value.defaultValues.temperature, max_tokens: this.chatConfig$.value.defaultValues.max_tokens }, this.chatConfig$.value.additionalServiceSettings),
583
+ appQuery: {
584
+ app: this.appService.appName,
585
+ query
586
+ }
532
587
  };
533
- if (this.chatConfig$.value.saveChats) {
588
+ if (this.chatConfig$.value.savedChatSettings.enabled) {
534
589
  data.instanceId = this.chatInstanceId;
535
590
  data.savedChatId = this.savedChatId;
536
591
  }
@@ -550,7 +605,7 @@ class WebSocketChatService extends ChatService {
550
605
  );
551
606
  // Invoke the Chat method
552
607
  this.connection.invoke('Chat', data)
553
- .then(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.serviceSettings.service_id)) // When the server indicates it has successfully finished invoking the method, notify the audit service with the recent chat history
608
+ .then(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.defaultValues.service_id)) // When the server indicates it has successfully finished invoking the method, notify the audit service with the recent chat history
554
609
  .catch(error => {
555
610
  console.error('Error invoking Chat:', error);
556
611
  return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection
@@ -592,7 +647,7 @@ class WebSocketChatService extends ChatService {
592
647
  listSavedChat() {
593
648
  const data = {
594
649
  instanceId: this.chatInstanceId,
595
- debug: this.chatConfig$.value.debug
650
+ debug: this.chatConfig$.value.defaultValues.debug
596
651
  };
597
652
  this.connection.on('SavedChatList', (res) => {
598
653
  this.savedChats$.next(res.savedChats); // emits the result to the savedChats$ subject
@@ -609,7 +664,7 @@ class WebSocketChatService extends ChatService {
609
664
  const data = {
610
665
  instanceId: this.chatInstanceId,
611
666
  savedChatId: id,
612
- debug: this.chatConfig$.value.debug
667
+ debug: this.chatConfig$.value.defaultValues.debug
613
668
  };
614
669
  this.connection.on('SavedChatGet', (res) => {
615
670
  savedChatSubject.next(res.savedChat);
@@ -624,12 +679,33 @@ class WebSocketChatService extends ChatService {
624
679
  });
625
680
  return savedChatSubject.asObservable();
626
681
  }
682
+ updateSavedChat(id, name) {
683
+ const updateSavedChatSubject = new Subject();
684
+ const data = {
685
+ instanceId: this.chatInstanceId,
686
+ savedChatId: id,
687
+ title: name,
688
+ debug: this.chatConfig$.value.defaultValues.debug
689
+ };
690
+ this.connection.on('SavedChatUpdate', (res) => {
691
+ updateSavedChatSubject.next(res.savedChat);
692
+ updateSavedChatSubject.complete();
693
+ });
694
+ // Invoke the method SavedChatUpdate
695
+ this.connection.invoke('SavedChatUpdate', data)
696
+ .catch(error => {
697
+ console.error('Error invoking SavedChatUpdate:', error);
698
+ updateSavedChatSubject.complete();
699
+ return Promise.resolve();
700
+ });
701
+ return updateSavedChatSubject.asObservable();
702
+ }
627
703
  deleteSavedChat(ids) {
628
704
  const deleteSavedChatSubject = new Subject();
629
705
  const data = {
630
706
  instanceId: this.chatInstanceId,
631
707
  SavedChatIds: ids,
632
- debug: this.chatConfig$.value.debug
708
+ debug: this.chatConfig$.value.defaultValues.debug
633
709
  };
634
710
  this.connection.on('SavedChatDelete', (res) => {
635
711
  deleteSavedChatSubject.next(res.deleteCount);
@@ -792,7 +868,7 @@ class WebSocketChatService extends ChatService {
792
868
  }
793
869
  getTransports() {
794
870
  var _a;
795
- switch ((_a = this.chatConfig$.value) === null || _a === void 0 ? void 0 : _a.globalSettings.signalRTransport) {
871
+ switch ((_a = this.chatConfig$.value) === null || _a === void 0 ? void 0 : _a.connectionSettings.signalRTransport) {
796
872
  case "WebSockets":
797
873
  return HttpTransportType.WebSockets;
798
874
  case "ServerSentEvents":
@@ -805,7 +881,7 @@ class WebSocketChatService extends ChatService {
805
881
  }
806
882
  getLogLevel() {
807
883
  var _a;
808
- switch ((_a = this.chatConfig$.value) === null || _a === void 0 ? void 0 : _a.globalSettings.signalRLogLevel) {
884
+ switch ((_a = this.chatConfig$.value) === null || _a === void 0 ? void 0 : _a.connectionSettings.signalRLogLevel) {
809
885
  case "Critical":
810
886
  return LogLevel.Critical; // Log level for diagnostic messages that indicate a failure that will terminate the entire application.
811
887
  case "Debug":
@@ -1080,10 +1156,10 @@ class ChatReferenceComponent {
1080
1156
  }
1081
1157
  }
1082
1158
  ChatReferenceComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1083
- ChatReferenceComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatReferenceComponent, isStandalone: true, selector: "sq-chat-reference", inputs: { reference: "reference", attachment: "attachment", partId: "partId" }, outputs: { openDocument: "openDocument", openPreview: "openPreview" }, ngImport: i0, template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"openDocument.emit(attachment.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:#fff}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem)}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:#000}.reference-data i.active{color:#fff;background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:#000}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "component", type: FormatIconComponent, selector: "sq-format-icon", inputs: ["extension"] }] });
1159
+ ChatReferenceComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatReferenceComponent, isStandalone: true, selector: "sq-chat-reference", inputs: { reference: "reference", attachment: "attachment", partId: "partId" }, outputs: { openDocument: "openDocument", openPreview: "openPreview" }, ngImport: i0, template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"openDocument.emit(attachment.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:var(--ast-reference-expanded-hover-bg, white)}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem)}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:var(--ast-reference-icon-color, black)}.reference-data i.active{color:var(--ast-reference-icon-active-color, white);background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:var(--ast-reference-passages-color, black)}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "component", type: FormatIconComponent, selector: "sq-format-icon", inputs: ["extension"] }] });
1084
1160
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, decorators: [{
1085
1161
  type: Component,
1086
- args: [{ selector: 'sq-chat-reference', standalone: true, imports: [CommonModule, UtilsModule, FormatIconComponent], template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"openDocument.emit(attachment.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:#fff}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem)}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:#000}.reference-data i.active{color:#fff;background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:#000}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"] }]
1162
+ args: [{ selector: 'sq-chat-reference', standalone: true, imports: [CommonModule, UtilsModule, FormatIconComponent], template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"openDocument.emit(attachment.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:var(--ast-reference-expanded-hover-bg, white)}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem)}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:var(--ast-reference-icon-color, black)}.reference-data i.active{color:var(--ast-reference-icon-active-color, white);background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:var(--ast-reference-passages-color, black)}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"] }]
1087
1163
  }], propDecorators: { reference: [{
1088
1164
  type: Input
1089
1165
  }], attachment: [{
@@ -1233,11 +1309,11 @@ class ChatMessageComponent {
1233
1309
  }
1234
1310
  }
1235
1311
  ChatMessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, deps: [{ token: i1$1.SearchService }, { token: i2$1.UIService }, { token: i3.PrincipalWebService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1236
- ChatMessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatMessageComponent, isStandalone: true, selector: "sq-chat-message", inputs: { message: "message", conversation: "conversation", assistantIcon: "assistantIcon", streaming: "streaming", canEdit: "canEdit", canRegenerate: "canRegenerate", canCopy: "canCopy" }, outputs: { referenceClicked: "referenceClicked", edit: "edit", regenerate: "regenerate", openPreview: "openPreview" }, usesOnChanges: true, ngImport: i0, template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message.role\">\n <i [ngClass]=\"assistantIcon\" [style.--sq-size.px]=\"24\" *ngIf=\"message.role === 'assistant'\"></i>\n <sq-initials-avatar [fullName]=\"name\" *ngIf=\"message.role !== 'assistant'\"></sq-initials-avatar>\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\" [title]=\"step.time ?? ''\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-fw fa-spin fa-circle-notch\" *ngIf=\"!step.done\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\">: {{step.content}}</span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <remark *ngIf=\"message.role === 'assistant'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n (click)=\"openDocument(attachment.record)\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}</a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference [class.expanded]=\"attachment.$expanded\" [attachment]=\"attachment\" [reference]=\"reference\"\n (openPreview)=\"openPreview.emit($event)\" (openDocument)=\"openDocument($event)\"></sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n \n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-action\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\"\n (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\"\n (click)=\"copyToClipboard(message.content)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\"\n (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openPreview.emit($event)\"\n (openDocument)=\"openDocument($event)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host{display:flex}:host:not(:hover) .sq-chat-message-action{display:none}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:block;border:1px solid #ccc;border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:#f8f8f8;border:1px solid #ddd;padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.sq-chat-message-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:var(--ast-size-2, .5rem);display:flex;flex-direction:column}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "component", type: i5.Collapse, selector: "sq-collapse", inputs: ["collapsed"] }, { kind: "ngmodule", type: RemarkModule }, { kind: "component", type: i6.RemarkComponent, selector: "remark", inputs: ["markdown", "processor", "debug"] }, { kind: "directive", type: i6.RemarkTemplateDirective, selector: "[remarkTemplate]", inputs: ["remarkTemplate"] }, { kind: "component", type: InitialsAvatarComponent, selector: "sq-initials-avatar", inputs: ["fullName", "size"] }, { kind: "component", type: ChatReferenceComponent, selector: "sq-chat-reference", inputs: ["reference", "attachment", "partId"], outputs: ["openDocument", "openPreview"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1312
+ ChatMessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatMessageComponent, isStandalone: true, selector: "sq-chat-message", inputs: { message: "message", conversation: "conversation", assistantIcon: "assistantIcon", streaming: "streaming", canEdit: "canEdit", canRegenerate: "canRegenerate", canCopy: "canCopy" }, outputs: { referenceClicked: "referenceClicked", edit: "edit", regenerate: "regenerate", openPreview: "openPreview" }, usesOnChanges: true, ngImport: i0, template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message.role\">\n <i [ngClass]=\"assistantIcon\" [style.--sq-size.px]=\"24\" *ngIf=\"message.role === 'assistant'\"></i>\n <sq-initials-avatar [fullName]=\"name\" *ngIf=\"message.role !== 'assistant'\"></sq-initials-avatar>\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-fw fa-spin fa-circle-notch\" *ngIf=\"!step.done\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\">: {{step.content}}</span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <remark *ngIf=\"message.role === 'assistant'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n (click)=\"openDocument(attachment.record)\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}</a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference [class.expanded]=\"attachment.$expanded\" [attachment]=\"attachment\" [reference]=\"reference\"\n (openPreview)=\"openPreview.emit($event)\" (openDocument)=\"openDocument($event)\"></sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n \n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-action\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\"\n (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\"\n (click)=\"copyToClipboard(message.content)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\"\n (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openPreview.emit($event)\"\n (openDocument)=\"openDocument($event)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host{display:flex}:host:not(:hover) .sq-chat-message-action{display:none}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:block;border:1px solid;border-color:var(--ast-message-table-border-color, #ccc);border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:var(--ast-message-table-tr-bg, #f8f8f8);border:1px solid;border-color:var(--ast-message-table-tr-border-color, #ddd);padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-content ::ng-deep .reference{color:var(--ast-message-reference-color, black)!important}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.sq-chat-message-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:var(--ast-size-2, .5rem);display:flex;flex-direction:column}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "component", type: i5.Collapse, selector: "sq-collapse", inputs: ["collapsed"] }, { kind: "ngmodule", type: RemarkModule }, { kind: "component", type: i6.RemarkComponent, selector: "remark", inputs: ["markdown", "processor", "debug"] }, { kind: "directive", type: i6.RemarkTemplateDirective, selector: "[remarkTemplate]", inputs: ["remarkTemplate"] }, { kind: "component", type: InitialsAvatarComponent, selector: "sq-initials-avatar", inputs: ["fullName", "size"] }, { kind: "component", type: ChatReferenceComponent, selector: "sq-chat-reference", inputs: ["reference", "attachment", "partId"], outputs: ["openDocument", "openPreview"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1237
1313
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, decorators: [{
1238
1314
  type: Component,
1239
1315
  args: [{ selector: "sq-chat-message", changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, UtilsModule, CollapseModule, RemarkModule,
1240
- InitialsAvatarComponent, ChatReferenceComponent], template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message.role\">\n <i [ngClass]=\"assistantIcon\" [style.--sq-size.px]=\"24\" *ngIf=\"message.role === 'assistant'\"></i>\n <sq-initials-avatar [fullName]=\"name\" *ngIf=\"message.role !== 'assistant'\"></sq-initials-avatar>\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\" [title]=\"step.time ?? ''\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-fw fa-spin fa-circle-notch\" *ngIf=\"!step.done\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\">: {{step.content}}</span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <remark *ngIf=\"message.role === 'assistant'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n (click)=\"openDocument(attachment.record)\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}</a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference [class.expanded]=\"attachment.$expanded\" [attachment]=\"attachment\" [reference]=\"reference\"\n (openPreview)=\"openPreview.emit($event)\" (openDocument)=\"openDocument($event)\"></sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n \n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-action\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\"\n (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\"\n (click)=\"copyToClipboard(message.content)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\"\n (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openPreview.emit($event)\"\n (openDocument)=\"openDocument($event)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host{display:flex}:host:not(:hover) .sq-chat-message-action{display:none}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:block;border:1px solid #ccc;border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:#f8f8f8;border:1px solid #ddd;padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.sq-chat-message-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:var(--ast-size-2, .5rem);display:flex;flex-direction:column}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}\n"] }]
1316
+ InitialsAvatarComponent, ChatReferenceComponent], template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message.role\">\n <i [ngClass]=\"assistantIcon\" [style.--sq-size.px]=\"24\" *ngIf=\"message.role === 'assistant'\"></i>\n <sq-initials-avatar [fullName]=\"name\" *ngIf=\"message.role !== 'assistant'\"></sq-initials-avatar>\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-fw fa-spin fa-circle-notch\" *ngIf=\"!step.done\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\">: {{step.content}}</span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <remark *ngIf=\"message.role === 'assistant'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n (click)=\"openDocument(attachment.record)\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}</a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference [class.expanded]=\"attachment.$expanded\" [attachment]=\"attachment\" [reference]=\"reference\"\n (openPreview)=\"openPreview.emit($event)\" (openDocument)=\"openDocument($event)\"></sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n \n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-action\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\"\n (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\"\n (click)=\"copyToClipboard(message.content)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\"\n (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openPreview.emit($event)\"\n (openDocument)=\"openDocument($event)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host{display:flex}:host:not(:hover) .sq-chat-message-action{display:none}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:block;border:1px solid;border-color:var(--ast-message-table-border-color, #ccc);border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:var(--ast-message-table-tr-bg, #f8f8f8);border:1px solid;border-color:var(--ast-message-table-tr-border-color, #ddd);padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-content ::ng-deep .reference{color:var(--ast-message-reference-color, black)!important}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.sq-chat-message-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:var(--ast-size-2, .5rem);display:flex;flex-direction:column}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}\n"] }]
1241
1317
  }], ctorParameters: function () { return [{ type: i1$1.SearchService }, { type: i2$1.UIService }, { type: i3.PrincipalWebService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { message: [{
1242
1318
  type: Input
1243
1319
  }], conversation: [{
@@ -1280,7 +1356,10 @@ class RestChatService extends ChatService {
1280
1356
  this.listFunctions()
1281
1357
  ])),
1282
1358
  // Map the results of parallel requests to a boolean indicating success
1283
- map(([models, functions]) => !!models && !!functions),
1359
+ map(([models, functions]) => {
1360
+ this.initProcess$.next(true);
1361
+ return !!models && !!functions;
1362
+ }),
1284
1363
  // Any errors during the process are caught, logged, and re-thrown to propagate the error further
1285
1364
  catchError((error) => {
1286
1365
  console.error('Error occurred:', error);
@@ -1294,8 +1373,8 @@ class RestChatService extends ChatService {
1294
1373
  * It can be overridden by the app config
1295
1374
  */
1296
1375
  getRequestsUrl() {
1297
- if (this.chatConfig$.value.globalSettings.restEndpoint) {
1298
- this.REQUEST_URL = this.chatConfig$.value.globalSettings.restEndpoint;
1376
+ if (this.chatConfig$.value.connectionSettings.restEndpoint) {
1377
+ this.REQUEST_URL = this.chatConfig$.value.connectionSettings.restEndpoint;
1299
1378
  }
1300
1379
  else {
1301
1380
  throw new Error(`The property 'restEndpoint' must be provided when attempting to use 'REST' in assistant instance`);
@@ -1304,7 +1383,7 @@ class RestChatService extends ChatService {
1304
1383
  listModels() {
1305
1384
  const data = {
1306
1385
  action: "listmodels",
1307
- debug: this.chatConfig$.value.debug
1386
+ debug: this.chatConfig$.value.defaultValues.debug
1308
1387
  };
1309
1388
  return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.models), tap(models => this.models = models === null || models === void 0 ? void 0 : models.filter(model => !!model.enable)), catchError((error) => {
1310
1389
  console.error('Error invoking listmodels:', error);
@@ -1314,26 +1393,30 @@ class RestChatService extends ChatService {
1314
1393
  listFunctions() {
1315
1394
  const data = {
1316
1395
  action: "listfunctions",
1317
- debug: this.chatConfig$.value.debug
1396
+ debug: this.chatConfig$.value.defaultValues.debug
1318
1397
  };
1319
- return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.functions), tap(functions => this.functions = functions), catchError((error) => {
1398
+ return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.functions), tap((functions) => this.functions = functions === null || functions === void 0 ? void 0 : functions.filter(func => func.enabled && !!this.chatConfig$.value.defaultValues.functions.find(fn => fn.name === func.functionName))), catchError((error) => {
1320
1399
  console.error('Error invoking listfunctions:', error);
1321
1400
  return throwError(() => error);
1322
1401
  }));
1323
1402
  }
1324
- fetch(messages, query = this.searchService.query) {
1403
+ fetch(messages, query) {
1404
+ var _a;
1325
1405
  // Start streaming by invoking the Chat method
1326
1406
  this.streaming$.next(true);
1327
1407
  // Prepare the payload to send to the Chat method
1328
1408
  const data = {
1329
1409
  action: "chat",
1330
1410
  history: messages,
1331
- functions: this.chatConfig$.value.functions,
1332
- debug: this.chatConfig$.value.debug,
1333
- serviceSettings: this.chatConfig$.value.serviceSettings,
1334
- contextSettings: Object.assign(Object.assign({}, this.chatConfig$.value.contextSettings), { app: this.appService.appName, query })
1411
+ functions: (_a = this.chatConfig$.value.defaultValues.functions) === null || _a === void 0 ? void 0 : _a.filter(func => func.enabled).map(func => func.name),
1412
+ debug: this.chatConfig$.value.defaultValues.debug,
1413
+ serviceSettings: Object.assign({ service_id: this.chatConfig$.value.defaultValues.service_id, model_id: this.chatConfig$.value.defaultValues.model_id, top_p: this.chatConfig$.value.defaultValues.top_p, temperature: this.chatConfig$.value.defaultValues.temperature, max_tokens: this.chatConfig$.value.defaultValues.max_tokens }, this.chatConfig$.value.additionalServiceSettings),
1414
+ appQuery: {
1415
+ app: this.appService.appName,
1416
+ query
1417
+ }
1335
1418
  };
1336
- if (this.chatConfig$.value.saveChats) {
1419
+ if (this.chatConfig$.value.savedChatSettings.enabled) {
1337
1420
  data.instanceId = this.chatInstanceId;
1338
1421
  data.savedChatId = this.savedChatId;
1339
1422
  }
@@ -1375,13 +1458,13 @@ class RestChatService extends ChatService {
1375
1458
  this.chatHistory = res.history;
1376
1459
  // Return the result
1377
1460
  return { history: [...messages, response], executionTime: res.executionTime };
1378
- }), tap(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.serviceSettings.service_id)), finalize(() => this.streaming$.next(false)));
1461
+ }), tap(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.defaultValues.service_id)), finalize(() => this.streaming$.next(false)));
1379
1462
  }
1380
1463
  listSavedChat() {
1381
1464
  const data = {
1382
1465
  action: "SavedChatList",
1383
1466
  instanceId: this.chatInstanceId,
1384
- debug: this.chatConfig$.value.debug
1467
+ debug: this.chatConfig$.value.defaultValues.debug
1385
1468
  };
1386
1469
  this.jsonMethodWebService.get(this.REQUEST_URL, data).subscribe(res => this.savedChats$.next(res.savedChats), error => {
1387
1470
  console.error('Error occurred while calling the SavedChatList API:', error);
@@ -1393,7 +1476,7 @@ class RestChatService extends ChatService {
1393
1476
  action: "SavedChatGet",
1394
1477
  instanceId: this.chatInstanceId,
1395
1478
  savedChatId: id,
1396
- debug: this.chatConfig$.value.debug
1479
+ debug: this.chatConfig$.value.defaultValues.debug
1397
1480
  };
1398
1481
  return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.savedChat), catchError((error) => {
1399
1482
  console.error('Error occurred while calling the SavedChatGet API:', error);
@@ -1401,12 +1484,26 @@ class RestChatService extends ChatService {
1401
1484
  return throwError(() => error);
1402
1485
  }));
1403
1486
  }
1487
+ updateSavedChat(id, name) {
1488
+ const data = {
1489
+ action: "SavedChatUpdate",
1490
+ instanceId: this.chatInstanceId,
1491
+ savedChatId: id,
1492
+ title: name,
1493
+ debug: this.chatConfig$.value.defaultValues.debug
1494
+ };
1495
+ return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.savedChat), catchError((error) => {
1496
+ console.error('Error occurred while calling the SavedChatUpdate API:', error);
1497
+ this.notificationsService.error('Error occurred while calling the SavedChatUpdate API');
1498
+ return throwError(() => error);
1499
+ }));
1500
+ }
1404
1501
  deleteSavedChat(ids) {
1405
1502
  const data = {
1406
1503
  action: "SavedChatDelete",
1407
1504
  instanceId: this.chatInstanceId,
1408
1505
  savedChatIds: ids,
1409
- debug: this.chatConfig$.value.debug
1506
+ debug: this.chatConfig$.value.defaultValues.debug
1410
1507
  };
1411
1508
  return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(map(res => res.deletedCount), catchError((error) => {
1412
1509
  console.error('Error occurred while calling the SavedChatDelete API:', error);
@@ -1424,14 +1521,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
1424
1521
  class ChatComponent extends AbstractFacet {
1425
1522
  constructor() {
1426
1523
  super();
1524
+ this.loginService = inject(LoginService);
1525
+ this.websocketService = inject(WebSocketChatService);
1526
+ this.restService = inject(RestChatService);
1527
+ this.instanceManagerService = inject(InstanceManagerService);
1528
+ this.searchService = inject(SearchService);
1529
+ this.principalService = inject(PrincipalWebService);
1530
+ this.cdr = inject(ChangeDetectorRef);
1531
+ /** Define the query to use to fetch answers */
1532
+ this.query = this.searchService.query;
1427
1533
  /** Define the protocol to be used for this chat instance*/
1428
1534
  this.protocol = "WEBSOCKET";
1429
1535
  /** Map of listeners overriding default registered ones*/
1430
1536
  this.messageHandlers = new Map();
1431
1537
  /** When the assistant answer a user question, automatically scroll down to the bottom of the discussion */
1432
1538
  this.automaticScrollToLastResponse = false;
1433
- this.enableChat = true;
1434
- this.showCredits = true;
1435
1539
  this.customAssistantIcon = '';
1436
1540
  this.data = new EventEmitter();
1437
1541
  this.referenceClicked = new EventEmitter();
@@ -1444,16 +1548,10 @@ class ChatComponent extends AbstractFacet {
1444
1548
  this._actions = [];
1445
1549
  this.sub = new Subscription();
1446
1550
  this.changes$ = new BehaviorSubject(undefined);
1447
- this.handleFirstChanges = false;
1551
+ this.firstChangesHandled = false;
1448
1552
  this.isAtBottom = true;
1449
1553
  this.initializationError = false;
1450
- this.loginService = inject(LoginService);
1451
- this.websocketService = inject(WebSocketChatService);
1452
- this.restService = inject(RestChatService);
1453
- this.instanceManagerService = inject(InstanceManagerService);
1454
- this.searchService = inject(SearchService);
1455
- this.principalService = inject(PrincipalWebService);
1456
- this.cdr = inject(ChangeDetectorRef);
1554
+ this.enabledUserInput = false;
1457
1555
  this._actions.push(new Action({
1458
1556
  icon: 'fas fa-sync',
1459
1557
  title: 'Reset chat',
@@ -1463,13 +1561,14 @@ class ChatComponent extends AbstractFacet {
1463
1561
  ngOnInit() {
1464
1562
  this.sub.add(this.loginService.events.pipe(filter(e => e.type === 'login-complete'), tap(_ => this.instantiateChatService()), map(_ => this.chatService.initChatConfig()), switchMap(() => this.chatService.initConfig$), filter(initConfig => !!initConfig), switchMap(_ => this.chatService.init()), filter(success => !!success), tap(_ => this.onLoadChat()), switchMap(_ => this.chatService.chatConfig$), tap(config => {
1465
1563
  this.config = config;
1564
+ this.enabledUserInput = this.config.modeSettings.enabledUserInput;
1466
1565
  this._config.emit(config);
1467
1566
  try {
1468
1567
  this.updateModelDescription();
1469
- if (!this.handleFirstChanges) {
1568
+ if (!this.firstChangesHandled) {
1470
1569
  this.handleChanges();
1471
1570
  this.addScrollListener();
1472
- this.handleFirstChanges = true;
1571
+ this.firstChangesHandled = true;
1473
1572
  }
1474
1573
  }
1475
1574
  catch (error) {
@@ -1506,12 +1605,35 @@ class ChatComponent extends AbstractFacet {
1506
1605
  get actions() { return this._actions; }
1507
1606
  handleChanges() {
1508
1607
  const changes = this.changes$.value;
1608
+ // If the chat service is a WebSocketChatService, handle the override of the message handlers if exists
1509
1609
  if ((changes === null || changes === void 0 ? void 0 : changes.messageHandlers) && this.messageHandlers && this.chatService instanceof WebSocketChatService) {
1510
1610
  this.chatService.overrideMessageHandlers(this.messageHandlers);
1511
1611
  }
1512
- if (!this.messages$.value || (changes === null || changes === void 0 ? void 0 : changes.chat)) {
1513
- // Load the chat
1514
- this.chat ? this.openChat(this.chat.messages) : this.loadDefaultChat();
1612
+ // Initialize the chat with the provided chat messages if exists, otherwise load the default chat
1613
+ // Once the chat is initialized (firstChangesHandled is true), allow opening the chat with the new provided messages (if exists)
1614
+ if (!this.firstChangesHandled || (changes === null || changes === void 0 ? void 0 : changes.chat)) {
1615
+ const openChat = () => {
1616
+ if (this.messages$.value && this.config.savedChatSettings.enabled) {
1617
+ this.chatService.listSavedChat(); // Refresh the list of saved chats
1618
+ }
1619
+ this.openChat(this.chat.messages);
1620
+ };
1621
+ this.chat ? openChat() : this.loadDefaultChat();
1622
+ }
1623
+ // If the chat is initialized and the initialization event is "Query", then a fresh new chat should be started with the provided query
1624
+ if (this.firstChangesHandled && (changes === null || changes === void 0 ? void 0 : changes.query) && this.config.modeSettings.initialization.event === 'Query') {
1625
+ const systemMsg = { role: 'system', content: this.config.defaultValues.systemPrompt, additionalProperties: { display: false } };
1626
+ const userMsg = { role: 'user', content: ChatService.formatPrompt(this.config.defaultValues.userPrompt, { principal: this.principalService.principal }), additionalProperties: { display: this.config.modeSettings.displayUserPrompt } };
1627
+ // If the provided query text is not empty, then add the user query message to the chat history and invoke the assistant
1628
+ // Otherwise, just start a new chat with a warning message inviting the user to perform a full text search to retrieve some results
1629
+ if (!!this.query.text) {
1630
+ const userQueryMsg = { role: 'user', content: this.query.text, additionalProperties: { display: this.config.modeSettings.initialization.displayUserQuery, query: this.query, forcedWorkflow: this.config.modeSettings.initialization.forcedWorkflow, isUserInput: true } };
1631
+ this.openChat(this.config.modeSettings.sendUserPrompt ? [systemMsg, userMsg, userQueryMsg] : [systemMsg, userQueryMsg]);
1632
+ }
1633
+ else {
1634
+ const warningMsg = { role: 'assistant', content: "You must perform a full text search to retrieve some results", additionalProperties: { display: true } };
1635
+ this.openChat([warningMsg]);
1636
+ }
1515
1637
  }
1516
1638
  }
1517
1639
  addScrollListener() {
@@ -1522,7 +1644,7 @@ class ChatComponent extends AbstractFacet {
1522
1644
  }
1523
1645
  updateModelDescription() {
1524
1646
  var _a;
1525
- this.modelDescription = this.chatService.getModel(this.config.serviceSettings.service_id, this.config.serviceSettings.model_id);
1647
+ this.modelDescription = this.chatService.getModel(this.config.defaultValues.service_id, this.config.defaultValues.model_id);
1526
1648
  this.assistantIcon = !!this.customAssistantIcon ? this.customAssistantIcon : 'sq-sinequa';
1527
1649
  switch ((_a = this.modelDescription) === null || _a === void 0 ? void 0 : _a.provider) {
1528
1650
  case 'Google':
@@ -1559,7 +1681,7 @@ class ChatComponent extends AbstractFacet {
1559
1681
  }
1560
1682
  }
1561
1683
  fetchAnswer(question, conversation) {
1562
- const userMsg = { role: 'user', content: question, additionalProperties: { display: true } };
1684
+ const userMsg = { role: 'user', content: question, additionalProperties: { display: true, isUserInput: true } };
1563
1685
  const messages = [...conversation, userMsg];
1564
1686
  this.messages$.next(messages);
1565
1687
  this.fetch(messages);
@@ -1619,16 +1741,46 @@ class ChatComponent extends AbstractFacet {
1619
1741
  }
1620
1742
  }, 10);
1621
1743
  }
1744
+ /**
1745
+ * Start a new chat with the defaultValues settings
1746
+ * If the savedChat feature is enabled, the list of saved chats will be refreshed
1747
+ */
1622
1748
  newChat() {
1623
- this.chatService.listSavedChat(); // Refresh the list of saved chats
1749
+ if (this.config.savedChatSettings.enabled) {
1750
+ this.chatService.listSavedChat(); // Refresh the list of saved chats
1751
+ }
1624
1752
  this.loadDefaultChat(); // Start a new chat
1625
1753
  }
1754
+ /**
1755
+ * Start the default chat with the defaultValues settings
1756
+ * If the chat is meant to be initialized with event === "Query", the corresponding user query message will be added to the chat history
1757
+ */
1626
1758
  loadDefaultChat() {
1627
- this.openChat([
1628
- { role: 'system', content: this.config.uiSettings.systemPrompt, additionalProperties: { display: false } },
1629
- { role: 'user', content: ChatService.formatPrompt(this.config.uiSettings.userPrompt, { principal: this.principalService.principal }), additionalProperties: { display: true } },
1630
- ]);
1759
+ const systemMsg = { role: 'system', content: this.config.defaultValues.systemPrompt, additionalProperties: { display: false } };
1760
+ const userMsg = { role: 'user', content: ChatService.formatPrompt(this.config.defaultValues.userPrompt, { principal: this.principalService.principal }), additionalProperties: { display: this.config.modeSettings.displayUserPrompt } };
1761
+ if (this.config.modeSettings.initialization.event === 'Query') {
1762
+ // If the provided query text is not empty, then add the user query message to the chat history and invoke the assistant
1763
+ // Otherwise, just start a new chat with a warning message inviting the user to perform a full text search to retrieve some results
1764
+ if (!!this.query.text) {
1765
+ const userQueryMsg = { role: 'user', content: this.query.text, additionalProperties: { display: this.config.modeSettings.initialization.displayUserQuery, query: this.query, forcedWorkflow: this.config.modeSettings.initialization.forcedWorkflow, isUserInput: true } };
1766
+ this.openChat(this.config.modeSettings.sendUserPrompt ? [systemMsg, userMsg, userQueryMsg] : [systemMsg, userQueryMsg]);
1767
+ }
1768
+ else {
1769
+ const warningMsg = { role: 'assistant', content: "You must perform a full text search to retrieve some results", additionalProperties: { display: true } };
1770
+ this.openChat([warningMsg]);
1771
+ }
1772
+ }
1773
+ else {
1774
+ this.openChat([systemMsg, userMsg]);
1775
+ }
1631
1776
  }
1777
+ /**
1778
+ * Start/open a new chat with the provided messages and chatId
1779
+ * If the last message is from the user, a request to the assistant is made to get an answer
1780
+ * If the last message is from the assistant, the conversation is loaded right away
1781
+ * @param messages The list of messages of the chat
1782
+ * @param chatId The id of the chat. If not provided, a new id will be generated
1783
+ */
1632
1784
  openChat(messages, chatId) {
1633
1785
  if (!messages || !Array.isArray(messages)) {
1634
1786
  console.error('Error occurs while trying to load the chat discussion. Invalid messages received :', messages);
@@ -1647,6 +1799,11 @@ class ChatComponent extends AbstractFacet {
1647
1799
  this.terminateFetch();
1648
1800
  }
1649
1801
  }
1802
+ /**
1803
+ * Reset the chat by clearing the messages and the chat history
1804
+ * The question input will be focused after the chat is reset
1805
+ * The fetch subscription will be terminated
1806
+ */
1650
1807
  resetChat() {
1651
1808
  if (this.messages$.value) {
1652
1809
  this.messages$.next(undefined); // Reset chat
@@ -1658,8 +1815,7 @@ class ChatComponent extends AbstractFacet {
1658
1815
  onLoadChat() {
1659
1816
  this.loading$.next(true);
1660
1817
  this.sub.add(this.chatService.loadSavedChat$
1661
- .pipe(filter(savedChat => !!savedChat), switchMap(savedChat => this.chatService.getSavedChat(savedChat.id)), filter(savedChatHistory => !!savedChatHistory), tap(savedChatHistory => this.openChat(savedChatHistory.History, savedChatHistory.id)), finalize(() => this.chatService.listSavedChat()) // Refresh the list of saved chats
1662
- ).subscribe());
1818
+ .pipe(filter(savedChat => !!savedChat), switchMap(savedChat => this.chatService.getSavedChat(savedChat.id)), filter(savedChatHistory => !!savedChatHistory), tap(savedChatHistory => this.openChat(savedChatHistory.history, savedChatHistory.id))).subscribe());
1663
1819
  }
1664
1820
  terminateFetch() {
1665
1821
  var _a;
@@ -1729,16 +1885,16 @@ class ChatComponent extends AbstractFacet {
1729
1885
  }
1730
1886
  }
1731
1887
  ChatComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1732
- ChatComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatComponent, isStandalone: true, selector: "sq-chat-v3", inputs: { instanceId: "instanceId", query: "query", protocol: "protocol", messageHandlers: "messageHandlers", automaticScrollToLastResponse: "automaticScrollToLastResponse", chat: "chat", enableChat: "enableChat", showCredits: "showCredits", customAssistantIcon: "customAssistantIcon" }, outputs: { data: "data", referenceClicked: "referenceClicked", openPreview: "openPreview", loading$: "loading", error: "error", _config: "config" }, providers: [
1888
+ ChatComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatComponent, isStandalone: true, selector: "sq-chat-v3", inputs: { instanceId: "instanceId", query: "query", protocol: "protocol", messageHandlers: "messageHandlers", automaticScrollToLastResponse: "automaticScrollToLastResponse", chat: "chat", customAssistantIcon: "customAssistantIcon" }, outputs: { data: "data", referenceClicked: "referenceClicked", openPreview: "openPreview", loading$: "loading", error: "error", _config: "config" }, providers: [
1733
1889
  RestChatService,
1734
1890
  WebSocketChatService
1735
- ], queries: [{ propertyName: "loadingTpl", first: true, predicate: ["loadingTpl"], descendants: true }], viewQueries: [{ propertyName: "messageList", first: true, predicate: ["messageList"], descendants: true }, { propertyName: "questionInput", first: true, predicate: ["questionInput"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "\n<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n\n <ul class=\"list-group list-group-flush overflow-auto pb-5\" #messageList>\n <ng-container *ngFor=\"let message of messages; let index = index; let last = last\">\n <!-- Regular messages -->\n <li class=\"list-group-item\" *ngIf=\"message.additionalProperties.display\"\n [class.opacity-50]=\"messageToEdit && messageToEdit < index + 1\">\n <sq-chat-message\n [class.sq-user-message]=\"message.role !== 'assistant'\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [assistantIcon]=\"customAssistantIcon || assistantIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role !== 'assistant'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"!(last && (chatService.streaming$ | async)) && messageToEdit === undefined && message.role === 'assistant'\"\n (edit)=\"editMessage(index)\" (regenerate)=\"regenerateMessage(index)\"\n (referenceClicked)=\"referenceClicked.emit($event)\"\n (openPreview)=\"openPreview.emit($event)\">\n </sq-chat-message>\n </li>\n </ng-container>\n\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <div class=\"user-input mt-auto\" *ngIf=\"enableChat\">\n <div class=\"py-2\">\n <ng-container *ngTemplateOutlet=\"inputTpl\"></ng-container>\n <div class=\"text-end small text-muted px-3\" *ngIf=\"showCredits\">\n powered by {{modelDescription?.displayName}} <ng-container *ngIf=\"privacyUrl\"> - <a [href]=\"privacyUrl\" target=\"_blank\">privacy notice</a></ng-container>\n </div>\n </div>\n </div>\n </div>\n</ng-container>\n\n<!-- NG TEMPLATES-->\n\n<ng-template #loadingTplDefault>\n <div class=\"spinner-grow text-success d-block mx-auto my-5\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n</ng-template>\n\n<ng-template #inputTpl>\n <div class=\"px-3 py-1\">\n <div class=\"ast-input-container\">\n <i class=\"fas fa-search\"></i>\n <input #questionInput\n type=\"text\" class=\"form-control\"\n placeholder=\"Ask something\" autofocus\n [(ngModel)]=\"question\"\n (keyup)=\"onKeyUp($event)\"\n [disabled]=\"(loading$ | async) || (chatService.streaming$ | async)\">\n <button\n *ngIf=\"!(chatService.streaming$ | async) && !(loading$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Send message\"\n (click)=\"submitQuestion()\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n <!--<button\n *ngIf=\"(chatService.streaming$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Stop generating\"\n (click)=\"terminateFetch()\">\n <i class=\"fas fa-stop\"></i>\n </button>-->\n <button\n *ngIf=\"messageToEdit\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Cancel edition\"\n (click)=\"messageToEdit = undefined; question = ''\">\n <i class=\"fas fa-undo-alt\"></i>\n </button>\n <div class=\"sq-floating-scroll\" *ngIf=\"!isAtBottom\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{font-size:.875rem}:host>div>.user-input>div:not(.progress),:host>div>ul>li{width:var(--ast-chat-container-width, 100%);max-width:100%;margin-left:auto;margin-right:auto}:host>div>ul{padding-top:var(--ast-chat-padding-top, 0);padding-bottom:var(--ast-chat-padding-bottom, 0)}li.attachment>p{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;-webkit-line-clamp:3}li.attachment.expanded>p{display:block}.progress{--bs-progress-height: 3px}.progress.disabled{--bs-progress-height: 20px;--bs-progress-bar-bg: var(--bs-danger)}.user-input{z-index:1}.user-input ul.list-group{max-height:30vh}.form-control:disabled{background-color:#ededed}a.disabled{cursor:default;opacity:.5}.no-max-height{max-height:initial!important}.sq-floating-scroll{position:absolute;right:50%;bottom:75px;text-align:center}.sq-floating-scroll .btn{background-color:#fff}.sq-floating-scroll .btn:hover{background-color:#fff;opacity:.9}.ast-input-container{display:flex;align-items:center;background-color:var(--ast-input-bg, #F8F8F8);border-radius:var(--ast-size-3, .75rem)}.ast-input-container>i{padding-left:var(--ast-size-3, .75rem);color:#212529bf}.ast-input-container input{padding-left:var(--ast-size-3, .75rem);padding-right:var(--ast-size-3, .75rem)}.ast-input-container input,.ast-input-container button,.ast-input-container button:hover{background-color:transparent;border:0}.ast-input-container button:not(:hover){color:#212529bf}sq-chat-message.sq-user-message{float:var(--ast-user-message-float, none)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ChatMessageComponent, selector: "sq-chat-message", inputs: ["message", "conversation", "assistantIcon", "streaming", "canEdit", "canRegenerate", "canCopy"], outputs: ["referenceClicked", "edit", "regenerate", "openPreview"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1891
+ ], queries: [{ propertyName: "loadingTpl", first: true, predicate: ["loadingTpl"], descendants: true }], viewQueries: [{ propertyName: "messageList", first: true, predicate: ["messageList"], descendants: true }, { propertyName: "questionInput", first: true, predicate: ["questionInput"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "\n<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n\n <ul class=\"list-group list-group-flush overflow-auto pe-2\" #messageList>\n <ng-container *ngFor=\"let message of messages; let index = index; let last = last\">\n <!-- Regular messages -->\n <li class=\"list-group-item\" *ngIf=\"message.additionalProperties.display\"\n [class.opacity-50]=\"messageToEdit && messageToEdit < index + 1\">\n <sq-chat-message\n [class.sq-user-message]=\"message.role !== 'assistant'\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [assistantIcon]=\"customAssistantIcon || assistantIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role !== 'assistant'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"!(last && (chatService.streaming$ | async)) && messageToEdit === undefined && message.role === 'assistant'\"\n (edit)=\"editMessage(index)\" (regenerate)=\"regenerateMessage(index)\"\n (referenceClicked)=\"referenceClicked.emit($event)\"\n (openPreview)=\"openPreview.emit($event)\">\n </sq-chat-message>\n </li>\n </ng-container>\n\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <div class=\"user-input mt-auto\" *ngIf=\"enabledUserInput\">\n <div class=\"py-2\">\n <ng-container *ngTemplateOutlet=\"inputTpl\"></ng-container>\n <div class=\"text-end small text-muted px-3\" *ngIf=\"!!config?.globalSettings?.disclaimer\">\n {{ config?.globalSettings?.disclaimer }}\n </div>\n </div>\n </div>\n </div>\n</ng-container>\n\n<!-- NG TEMPLATES-->\n\n<ng-template #loadingTplDefault>\n <div class=\"spinner-grow text-primary d-block mx-auto my-5\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n</ng-template>\n\n<ng-template #inputTpl>\n <div class=\"px-3 py-1\">\n <div class=\"ast-input-container\">\n <i class=\"fas fa-search\"></i>\n <input #questionInput\n type=\"text\" class=\"form-control\"\n placeholder=\"Ask something\" autofocus\n [(ngModel)]=\"question\"\n (keyup)=\"onKeyUp($event)\"\n [disabled]=\"(loading$ | async) || (chatService.streaming$ | async)\">\n <button\n *ngIf=\"!(chatService.streaming$ | async) && !(loading$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Send message\"\n (click)=\"submitQuestion()\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n <!--<button\n *ngIf=\"(chatService.streaming$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Stop generating\"\n (click)=\"terminateFetch()\">\n <i class=\"fas fa-stop\"></i>\n </button>-->\n <button\n *ngIf=\"messageToEdit\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Cancel edition\"\n (click)=\"messageToEdit = undefined; question = ''\">\n <i class=\"fas fa-undo-alt\"></i>\n </button>\n <div class=\"sq-floating-scroll\" *ngIf=\"!isAtBottom\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{font-size:.875rem}:host>div>.user-input>div:not(.progress),:host>div>ul>li{width:var(--ast-chat-container-width, 100%);max-width:100%;margin-left:auto;margin-right:auto}:host>div>ul{padding-top:var(--ast-chat-padding-top, 0);padding-bottom:var(--ast-chat-padding-bottom, 0)}li.attachment>p{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;-webkit-line-clamp:3}li.attachment.expanded>p{display:block}.progress{--bs-progress-height: 3px}.progress.disabled{--bs-progress-height: 20px;--bs-progress-bar-bg: var(--bs-danger)}.user-input{z-index:1}.user-input ul.list-group{max-height:30vh}.form-control:disabled{background-color:#ededed}a.disabled{cursor:default;opacity:.5}.no-max-height{max-height:initial!important}.sq-floating-scroll{position:absolute;right:50%;bottom:75px;text-align:center}.sq-floating-scroll .btn{background-color:#fff}.sq-floating-scroll .btn:hover{background-color:#fff;opacity:.9}.ast-input-container{display:flex;align-items:center;background-color:var(--ast-input-bg, #F8F8F8);border-radius:var(--ast-size-3, .75rem)}.ast-input-container>i{padding-left:var(--ast-size-3, .75rem);color:var(--ast-muted-color, rgba(33, 37, 41, .75))}.ast-input-container input{padding-left:var(--ast-size-3, .75rem);padding-right:var(--ast-size-3, .75rem)}.ast-input-container input,.ast-input-container button,.ast-input-container button:hover{background-color:transparent;border:0}.ast-input-container button:hover{color:var(--ast-primary-color, #005DA7)}.ast-input-container button:not(:hover){color:var(--ast-muted-color, rgba(33, 37, 41, .75))}sq-chat-message.sq-user-message{float:var(--ast-user-message-float, none)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ChatMessageComponent, selector: "sq-chat-message", inputs: ["message", "conversation", "assistantIcon", "streaming", "canEdit", "canRegenerate", "canCopy"], outputs: ["referenceClicked", "edit", "regenerate", "openPreview"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1736
1892
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, decorators: [{
1737
1893
  type: Component,
1738
1894
  args: [{ selector: 'sq-chat-v3', providers: [
1739
1895
  RestChatService,
1740
1896
  WebSocketChatService
1741
- ], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent], template: "\n<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n\n <ul class=\"list-group list-group-flush overflow-auto pb-5\" #messageList>\n <ng-container *ngFor=\"let message of messages; let index = index; let last = last\">\n <!-- Regular messages -->\n <li class=\"list-group-item\" *ngIf=\"message.additionalProperties.display\"\n [class.opacity-50]=\"messageToEdit && messageToEdit < index + 1\">\n <sq-chat-message\n [class.sq-user-message]=\"message.role !== 'assistant'\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [assistantIcon]=\"customAssistantIcon || assistantIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role !== 'assistant'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"!(last && (chatService.streaming$ | async)) && messageToEdit === undefined && message.role === 'assistant'\"\n (edit)=\"editMessage(index)\" (regenerate)=\"regenerateMessage(index)\"\n (referenceClicked)=\"referenceClicked.emit($event)\"\n (openPreview)=\"openPreview.emit($event)\">\n </sq-chat-message>\n </li>\n </ng-container>\n\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <div class=\"user-input mt-auto\" *ngIf=\"enableChat\">\n <div class=\"py-2\">\n <ng-container *ngTemplateOutlet=\"inputTpl\"></ng-container>\n <div class=\"text-end small text-muted px-3\" *ngIf=\"showCredits\">\n powered by {{modelDescription?.displayName}} <ng-container *ngIf=\"privacyUrl\"> - <a [href]=\"privacyUrl\" target=\"_blank\">privacy notice</a></ng-container>\n </div>\n </div>\n </div>\n </div>\n</ng-container>\n\n<!-- NG TEMPLATES-->\n\n<ng-template #loadingTplDefault>\n <div class=\"spinner-grow text-success d-block mx-auto my-5\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n</ng-template>\n\n<ng-template #inputTpl>\n <div class=\"px-3 py-1\">\n <div class=\"ast-input-container\">\n <i class=\"fas fa-search\"></i>\n <input #questionInput\n type=\"text\" class=\"form-control\"\n placeholder=\"Ask something\" autofocus\n [(ngModel)]=\"question\"\n (keyup)=\"onKeyUp($event)\"\n [disabled]=\"(loading$ | async) || (chatService.streaming$ | async)\">\n <button\n *ngIf=\"!(chatService.streaming$ | async) && !(loading$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Send message\"\n (click)=\"submitQuestion()\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n <!--<button\n *ngIf=\"(chatService.streaming$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Stop generating\"\n (click)=\"terminateFetch()\">\n <i class=\"fas fa-stop\"></i>\n </button>-->\n <button\n *ngIf=\"messageToEdit\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Cancel edition\"\n (click)=\"messageToEdit = undefined; question = ''\">\n <i class=\"fas fa-undo-alt\"></i>\n </button>\n <div class=\"sq-floating-scroll\" *ngIf=\"!isAtBottom\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{font-size:.875rem}:host>div>.user-input>div:not(.progress),:host>div>ul>li{width:var(--ast-chat-container-width, 100%);max-width:100%;margin-left:auto;margin-right:auto}:host>div>ul{padding-top:var(--ast-chat-padding-top, 0);padding-bottom:var(--ast-chat-padding-bottom, 0)}li.attachment>p{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;-webkit-line-clamp:3}li.attachment.expanded>p{display:block}.progress{--bs-progress-height: 3px}.progress.disabled{--bs-progress-height: 20px;--bs-progress-bar-bg: var(--bs-danger)}.user-input{z-index:1}.user-input ul.list-group{max-height:30vh}.form-control:disabled{background-color:#ededed}a.disabled{cursor:default;opacity:.5}.no-max-height{max-height:initial!important}.sq-floating-scroll{position:absolute;right:50%;bottom:75px;text-align:center}.sq-floating-scroll .btn{background-color:#fff}.sq-floating-scroll .btn:hover{background-color:#fff;opacity:.9}.ast-input-container{display:flex;align-items:center;background-color:var(--ast-input-bg, #F8F8F8);border-radius:var(--ast-size-3, .75rem)}.ast-input-container>i{padding-left:var(--ast-size-3, .75rem);color:#212529bf}.ast-input-container input{padding-left:var(--ast-size-3, .75rem);padding-right:var(--ast-size-3, .75rem)}.ast-input-container input,.ast-input-container button,.ast-input-container button:hover{background-color:transparent;border:0}.ast-input-container button:not(:hover){color:#212529bf}sq-chat-message.sq-user-message{float:var(--ast-user-message-float, none)}\n"] }]
1897
+ ], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent], template: "\n<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n\n <ul class=\"list-group list-group-flush overflow-auto pe-2\" #messageList>\n <ng-container *ngFor=\"let message of messages; let index = index; let last = last\">\n <!-- Regular messages -->\n <li class=\"list-group-item\" *ngIf=\"message.additionalProperties.display\"\n [class.opacity-50]=\"messageToEdit && messageToEdit < index + 1\">\n <sq-chat-message\n [class.sq-user-message]=\"message.role !== 'assistant'\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [assistantIcon]=\"customAssistantIcon || assistantIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role !== 'assistant'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"!(last && (chatService.streaming$ | async)) && messageToEdit === undefined && message.role === 'assistant'\"\n (edit)=\"editMessage(index)\" (regenerate)=\"regenerateMessage(index)\"\n (referenceClicked)=\"referenceClicked.emit($event)\"\n (openPreview)=\"openPreview.emit($event)\">\n </sq-chat-message>\n </li>\n </ng-container>\n\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <div class=\"user-input mt-auto\" *ngIf=\"enabledUserInput\">\n <div class=\"py-2\">\n <ng-container *ngTemplateOutlet=\"inputTpl\"></ng-container>\n <div class=\"text-end small text-muted px-3\" *ngIf=\"!!config?.globalSettings?.disclaimer\">\n {{ config?.globalSettings?.disclaimer }}\n </div>\n </div>\n </div>\n </div>\n</ng-container>\n\n<!-- NG TEMPLATES-->\n\n<ng-template #loadingTplDefault>\n <div class=\"spinner-grow text-primary d-block mx-auto my-5\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n</ng-template>\n\n<ng-template #inputTpl>\n <div class=\"px-3 py-1\">\n <div class=\"ast-input-container\">\n <i class=\"fas fa-search\"></i>\n <input #questionInput\n type=\"text\" class=\"form-control\"\n placeholder=\"Ask something\" autofocus\n [(ngModel)]=\"question\"\n (keyup)=\"onKeyUp($event)\"\n [disabled]=\"(loading$ | async) || (chatService.streaming$ | async)\">\n <button\n *ngIf=\"!(chatService.streaming$ | async) && !(loading$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Send message\"\n (click)=\"submitQuestion()\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n <!--<button\n *ngIf=\"(chatService.streaming$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Stop generating\"\n (click)=\"terminateFetch()\">\n <i class=\"fas fa-stop\"></i>\n </button>-->\n <button\n *ngIf=\"messageToEdit\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Cancel edition\"\n (click)=\"messageToEdit = undefined; question = ''\">\n <i class=\"fas fa-undo-alt\"></i>\n </button>\n <div class=\"sq-floating-scroll\" *ngIf=\"!isAtBottom\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{font-size:.875rem}:host>div>.user-input>div:not(.progress),:host>div>ul>li{width:var(--ast-chat-container-width, 100%);max-width:100%;margin-left:auto;margin-right:auto}:host>div>ul{padding-top:var(--ast-chat-padding-top, 0);padding-bottom:var(--ast-chat-padding-bottom, 0)}li.attachment>p{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;-webkit-line-clamp:3}li.attachment.expanded>p{display:block}.progress{--bs-progress-height: 3px}.progress.disabled{--bs-progress-height: 20px;--bs-progress-bar-bg: var(--bs-danger)}.user-input{z-index:1}.user-input ul.list-group{max-height:30vh}.form-control:disabled{background-color:#ededed}a.disabled{cursor:default;opacity:.5}.no-max-height{max-height:initial!important}.sq-floating-scroll{position:absolute;right:50%;bottom:75px;text-align:center}.sq-floating-scroll .btn{background-color:#fff}.sq-floating-scroll .btn:hover{background-color:#fff;opacity:.9}.ast-input-container{display:flex;align-items:center;background-color:var(--ast-input-bg, #F8F8F8);border-radius:var(--ast-size-3, .75rem)}.ast-input-container>i{padding-left:var(--ast-size-3, .75rem);color:var(--ast-muted-color, rgba(33, 37, 41, .75))}.ast-input-container input{padding-left:var(--ast-size-3, .75rem);padding-right:var(--ast-size-3, .75rem)}.ast-input-container input,.ast-input-container button,.ast-input-container button:hover{background-color:transparent;border:0}.ast-input-container button:hover{color:var(--ast-primary-color, #005DA7)}.ast-input-container button:not(:hover){color:var(--ast-muted-color, rgba(33, 37, 41, .75))}sq-chat-message.sq-user-message{float:var(--ast-user-message-float, none)}\n"] }]
1742
1898
  }], ctorParameters: function () { return []; }, propDecorators: { instanceId: [{
1743
1899
  type: Input
1744
1900
  }], query: [{
@@ -1751,10 +1907,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
1751
1907
  type: Input
1752
1908
  }], chat: [{
1753
1909
  type: Input
1754
- }], enableChat: [{
1755
- type: Input
1756
- }], showCredits: [{
1757
- type: Input
1758
1910
  }], customAssistantIcon: [{
1759
1911
  type: Input
1760
1912
  }], data: [{
@@ -1807,12 +1959,42 @@ class SavedChatsComponent {
1807
1959
  this.chatService = this.instanceManagerService.getInstance(this.instanceId);
1808
1960
  }
1809
1961
  onListSavedChat() {
1810
- this.subscription.add(this.chatService.savedChats$.subscribe((savedChats) => this.groupedSavedChats$.next(this._groupSavedChatsByDate(savedChats))));
1962
+ this.subscription.add(this.chatService.savedChats$.subscribe((savedChats) => {
1963
+ this.currentChatId = undefined;
1964
+ this.groupedSavedChats$.next(this._groupSavedChatsByDate(savedChats));
1965
+ }));
1811
1966
  }
1812
1967
  onLoad(savedChat) {
1968
+ this.currentChatId = savedChat.id;
1813
1969
  this.chatService.loadSavedChat$.next(savedChat);
1970
+ this.chatService.listSavedChat();
1814
1971
  this.load.emit(savedChat);
1815
1972
  }
1973
+ onRename(savedChat) {
1974
+ const model = {
1975
+ title: 'Rename saved discussion',
1976
+ message: `Please enter a new name for the discussion "${savedChat.title}".`,
1977
+ buttons: [
1978
+ new ModalButton({ result: -2 /* ModalResult.Cancel */ }),
1979
+ new ModalButton({ result: -1 /* ModalResult.OK */, text: "Rename", primary: true })
1980
+ ],
1981
+ output: savedChat.title,
1982
+ validators: [Validators.required]
1983
+ };
1984
+ this.modalService.prompt(model).then(res => {
1985
+ if (res === -1 /* ModalResult.OK */) {
1986
+ this.subscription.add(this.chatService.updateSavedChat(savedChat.id, model.output)
1987
+ .pipe(tap(() => {
1988
+ this.notificationsService.success(`The saved discussion "${savedChat.title}" has been successfully renamed to "${model.output}".`);
1989
+ this.chatService.listSavedChat();
1990
+ }), catchError((error) => {
1991
+ console.error('Error occurred while updating the saved chat:', error);
1992
+ this.notificationsService.error(`Error occurred while updating the saved discussion "${savedChat.title}"`);
1993
+ return throwError(() => error);
1994
+ })).subscribe());
1995
+ }
1996
+ });
1997
+ }
1816
1998
  onDelete(savedChat) {
1817
1999
  this.modalService
1818
2000
  .confirm({
@@ -1889,10 +2071,10 @@ class SavedChatsComponent {
1889
2071
  }
1890
2072
  }
1891
2073
  SavedChatsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: SavedChatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1892
- SavedChatsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: SavedChatsComponent, isStandalone: true, selector: "sq-saved-chats-v3", inputs: { instanceId: "instanceId" }, outputs: { load: "load", delete: "delete" }, ngImport: i0, template: "<div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\" class=\"saved-chat p-2\">\n <span class=\"title me-1\" (click)=\"onLoad(savedChat)\">{{savedChat.title}}</span>\n <i class=\"saved-chat-actions fas fa-trash ms-1\" [sqTooltip]=\"'Delete'\" (click)=\"onDelete(savedChat)\"></i>\n </div>\n</div>\n", styles: [".saved-chats .saved-chat-date{font-weight:500;color:#a9a9a9;margin-top:.5rem}.saved-chats .saved-chat{display:flex;align-items:center;cursor:pointer;margin-left:.25rem}.saved-chats .saved-chat span{flex-grow:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.saved-chats .saved-chat .saved-chat-actions{display:none}.saved-chats .saved-chat:hover{color:#ff732e;background-color:#fff8f1}.saved-chats .saved-chat:hover .saved-chat-actions{display:block}.saved-chats .title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ModalModule }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }] });
2074
+ SavedChatsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: SavedChatsComponent, isStandalone: true, selector: "sq-saved-chats-v3", inputs: { instanceId: "instanceId" }, outputs: { load: "load", delete: "delete" }, ngImport: i0, template: "<ng-container *ngIf=\"(chatService.chatConfig$ | async)?.savedChatSettings.display\">\n <div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\" class=\"saved-chat p-2\" [class.active]=\"currentChatId === savedChat.id\"\n (click)=\"onLoad(savedChat)\">\n <span class=\"title me-1\">{{savedChat.title}}</span>\n <i class=\"saved-chat-actions fas fa-pen mx-1\" [sqTooltip]=\"'Rename'\"\n (click)=\"$event.stopPropagation(); onRename(savedChat)\"></i>\n <i class=\"saved-chat-actions fas fa-trash ms-1\" [sqTooltip]=\"'Delete'\"\n (click)=\"$event.stopPropagation(); onDelete(savedChat)\"></i>\n </div>\n </div>\n</ng-container>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}.saved-chats .saved-chat-date{font-weight:500;color:#a9a9a9;margin-top:.5rem}.saved-chats .saved-chat{display:flex;align-items:center;cursor:pointer;margin-left:.25rem}.saved-chats .saved-chat span{flex-grow:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.saved-chats .saved-chat .saved-chat-actions{display:none}.saved-chats .saved-chat:hover,.saved-chats .saved-chat.active{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-saved-chat-hover-background, #FFF8F1)}.saved-chats .saved-chat:hover .saved-chat-actions{display:block}.saved-chats .title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ModalModule }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }] });
1893
2075
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: SavedChatsComponent, decorators: [{
1894
2076
  type: Component,
1895
- args: [{ selector: 'sq-saved-chats-v3', standalone: true, imports: [CommonModule, ModalModule, UtilsModule], template: "<div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\" class=\"saved-chat p-2\">\n <span class=\"title me-1\" (click)=\"onLoad(savedChat)\">{{savedChat.title}}</span>\n <i class=\"saved-chat-actions fas fa-trash ms-1\" [sqTooltip]=\"'Delete'\" (click)=\"onDelete(savedChat)\"></i>\n </div>\n</div>\n", styles: [".saved-chats .saved-chat-date{font-weight:500;color:#a9a9a9;margin-top:.5rem}.saved-chats .saved-chat{display:flex;align-items:center;cursor:pointer;margin-left:.25rem}.saved-chats .saved-chat span{flex-grow:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.saved-chats .saved-chat .saved-chat-actions{display:none}.saved-chats .saved-chat:hover{color:#ff732e;background-color:#fff8f1}.saved-chats .saved-chat:hover .saved-chat-actions{display:block}.saved-chats .title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
2077
+ args: [{ selector: 'sq-saved-chats-v3', standalone: true, imports: [CommonModule, ModalModule, UtilsModule], template: "<ng-container *ngIf=\"(chatService.chatConfig$ | async)?.savedChatSettings.display\">\n <div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\" class=\"saved-chat p-2\" [class.active]=\"currentChatId === savedChat.id\"\n (click)=\"onLoad(savedChat)\">\n <span class=\"title me-1\">{{savedChat.title}}</span>\n <i class=\"saved-chat-actions fas fa-pen mx-1\" [sqTooltip]=\"'Rename'\"\n (click)=\"$event.stopPropagation(); onRename(savedChat)\"></i>\n <i class=\"saved-chat-actions fas fa-trash ms-1\" [sqTooltip]=\"'Delete'\"\n (click)=\"$event.stopPropagation(); onDelete(savedChat)\"></i>\n </div>\n </div>\n</ng-container>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}.saved-chats .saved-chat-date{font-weight:500;color:#a9a9a9;margin-top:.5rem}.saved-chats .saved-chat{display:flex;align-items:center;cursor:pointer;margin-left:.25rem}.saved-chats .saved-chat span{flex-grow:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.saved-chats .saved-chat .saved-chat-actions{display:none}.saved-chats .saved-chat:hover,.saved-chats .saved-chat.active{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-saved-chat-hover-background, #FFF8F1)}.saved-chats .saved-chat:hover .saved-chat-actions{display:block}.saved-chats .title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
1896
2078
  }], propDecorators: { instanceId: [{
1897
2079
  type: Input
1898
2080
  }], load: [{
@@ -1917,9 +2099,83 @@ const enAssistant = Utils.merge({}, _enAssistant);
1917
2099
  const frAssistant = Utils.merge({}, _frAssistant);
1918
2100
  const deAssistant = Utils.merge({}, _deAssistant);
1919
2101
 
2102
+ class ChatPrompt {
2103
+ constructor(model, modalRef, formBuilder) {
2104
+ this.model = model;
2105
+ this.modalRef = modalRef;
2106
+ this.formBuilder = formBuilder;
2107
+ this.defaultButtons = [
2108
+ new ModalButton({
2109
+ result: -1 /* ModalResult.OK */,
2110
+ primary: true,
2111
+ validation: this.form
2112
+ }),
2113
+ new ModalButton({
2114
+ result: -2 /* ModalResult.Cancel */
2115
+ })
2116
+ ];
2117
+ }
2118
+ ngOnInit() {
2119
+ this.inputControl = new UntypedFormControl(this.model.output, this.model.validators || Validators.required);
2120
+ this.form = this.formBuilder.group({
2121
+ input: this.inputControl
2122
+ });
2123
+ this.formChanges = Utils.subscribe(this.form.valueChanges, (value) => {
2124
+ this.model.output = this.inputControl.value;
2125
+ });
2126
+ }
2127
+ ngOnDestroy() {
2128
+ this.formChanges.unsubscribe();
2129
+ }
2130
+ get title() {
2131
+ return this.model.title ? this.model.title : "msg#modal.prompt.title";
2132
+ }
2133
+ get buttons() {
2134
+ return (this.model.buttons && this.model.buttons.length > 0) ? this.model.buttons : this.defaultButtons;
2135
+ }
2136
+ }
2137
+ ChatPrompt.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatPrompt, deps: [{ token: MODAL_MODEL }, { token: i1$2.ModalRef }, { token: i2.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component });
2138
+ ChatPrompt.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatPrompt, isStandalone: true, selector: "sq-chat-prompt", ngImport: i0, template: `
2139
+ <form name="prompt" novalidate [formGroup]="form">
2140
+ <sq-modal [title]="title" [buttons]="buttons">
2141
+ <div class="mb-3 sq-form-group">
2142
+ <label class="form-label" for="input">{{model.message | sqMessage:model.messageParams}}</label>
2143
+ <input [sqValidation]="form" type="text" class="form-control" id="input" formControlName="input" spellcheck="off" sqAutofocus *ngIf="!model.rowCount">
2144
+ <textarea [sqValidation]="form" type="text" class="form-control" id="input" formControlName="input" spellcheck="on" rows="{{model.rowCount}}" sqAutofocus *ngIf="!!model.rowCount">
2145
+ </textarea>
2146
+ </div>
2147
+ </sq-modal>
2148
+ </form>
2149
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: BsModalModule }, { kind: "component", type: i4.BsModal, selector: "sq-modal", inputs: ["title", "buttons", "showHeader", "showFooter", "isProcessingState"] }, { kind: "ngmodule", type: ValidationModule }, { kind: "directive", type: i5$1.ValidationDirective, selector: "[sqValidation]", inputs: ["sqValidation"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: IntlModule }, { kind: "pipe", type: i6$1.MessagePipe, name: "sqMessage" }] });
2150
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatPrompt, decorators: [{
2151
+ type: Component,
2152
+ args: [{
2153
+ selector: "sq-chat-prompt",
2154
+ template: `
2155
+ <form name="prompt" novalidate [formGroup]="form">
2156
+ <sq-modal [title]="title" [buttons]="buttons">
2157
+ <div class="mb-3 sq-form-group">
2158
+ <label class="form-label" for="input">{{model.message | sqMessage:model.messageParams}}</label>
2159
+ <input [sqValidation]="form" type="text" class="form-control" id="input" formControlName="input" spellcheck="off" sqAutofocus *ngIf="!model.rowCount">
2160
+ <textarea [sqValidation]="form" type="text" class="form-control" id="input" formControlName="input" spellcheck="on" rows="{{model.rowCount}}" sqAutofocus *ngIf="!!model.rowCount">
2161
+ </textarea>
2162
+ </div>
2163
+ </sq-modal>
2164
+ </form>
2165
+ `,
2166
+ standalone: true,
2167
+ imports: [CommonModule, BsModalModule, ValidationModule, ReactiveFormsModule, IntlModule],
2168
+ }]
2169
+ }], ctorParameters: function () {
2170
+ return [{ type: undefined, decorators: [{
2171
+ type: Inject,
2172
+ args: [MODAL_MODEL]
2173
+ }] }, { type: i1$2.ModalRef }, { type: i2.UntypedFormBuilder }];
2174
+ } });
2175
+
1920
2176
  /**
1921
2177
  * Generated bundle index. Do not edit.
1922
2178
  */
1923
2179
 
1924
- export { ChatComponent, ChatService, ChatSettingsV3Component, FormatIconComponent, InitialsAvatarComponent, InstanceManagerService, RestChatService, SavedChatsComponent, WebSocketChatService, chatConfigSchema, deAssistant, enAssistant, frAssistant, globalSettingsSchema };
2180
+ export { ChatComponent, ChatPrompt, ChatService, ChatSettingsV3Component, FormatIconComponent, InitialsAvatarComponent, InstanceManagerService, RestChatService, SavedChatsComponent, WebSocketChatService, chatConfigSchema, connectionSettingsSchema, deAssistant, enAssistant, frAssistant };
1925
2181
  //# sourceMappingURL=sinequa-assistant-chat.mjs.map