@crestapps/ai-chat-ui 1.0.0-preview.7 → 1.0.0-preview.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ai-chat.js CHANGED
@@ -3,15 +3,18 @@
3
3
  ** Any changes made directly to this file will be overwritten next time its asset group is processed by Gulp.
4
4
  */
5
5
 
6
+ var _excluded = ["placeholder"];
6
7
  function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
7
8
  function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
8
9
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
9
10
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
10
- function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
11
11
  function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
12
12
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
13
13
  function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
14
14
  function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
15
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
16
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
17
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
15
18
  function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
16
19
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
17
20
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
@@ -52,7 +55,7 @@ window.openAIChatManager = function () {
52
55
  minWidth: 320,
53
56
  minHeight: 420
54
57
  },
55
- messageTemplate: "\n <div class=\"ai-chat-messages\">\n <div v-for=\"(message, index) in messages\" :key=\"'msg-' + index\" class=\"ai-chat-message-item\">\n <div>\n <div v-if=\"message.role === 'user'\" class=\"ai-chat-msg-role ai-chat-msg-role-user\">{{ userLabel }}</div>\n <div v-else-if=\"message.role !== 'indicator'\" :class=\"getAssistantRoleClasses(message)\">\n <span :class=\"getAssistantIconClasses(message, index)\"><i :class=\"getAssistantIcon(message)\"></i></span>\n {{ getAssistantLabel(message) }}\n </div>\n <div class=\"ai-chat-message-body lh-base\">\n <h4 v-if=\"message.title\">{{ message.title }}</h4>\n <div v-html=\"message.htmlContent\"></div>\n <span class=\"message-buttons-container\" v-if=\"!isIndicator(message)\">\n <template v-if=\"metricsEnabled && message.role === 'assistant'\">\n <span class=\"ai-chat-message-assistant-feedback\" :data-message-id=\"message.id\">\n <button class=\"btn btn-sm btn-link text-success p-0 me-2 button-message-toolbox rate-up-btn\" @click=\"rateMessage(message, true, $event)\" :title=\"thumbsUpTitle\">\n <i class=\"fa-regular fa-thumbs-up\"></i>\n </button>\n <button class=\"btn btn-sm btn-link text-danger p-0 me-2 button-message-toolbox rate-down-btn\" @click=\"rateMessage(message, false, $event)\" :title=\"thumbsDownTitle\">\n <i class=\"fa-regular fa-thumbs-down\"></i>\n </button>\n </span>\n </template>\n <button v-if=\"textToSpeechEnabled && !isConversationMode && message.role === 'assistant' && !message.isStreaming\" class=\"btn btn-sm btn-link text-secondary p-0 me-1 button-message-toolbox\" :class=\"{ 'tts-playing': ttsPlayingMessageIndex === index }\" @click=\"toggleMessageTts(message, index)\" :title=\"ttsPlayingMessageIndex === index ? 'Pause audio' : 'Read aloud'\">\n <i :class=\"ttsPlayingMessageIndex === index ? 'fa-solid fa-circle-pause' : 'fa-solid fa-circle-play'\"></i>\n </button>\n <button class=\"btn btn-sm btn-link text-secondary p-0 button-message-toolbox\" @click=\"copyResponse(message.content)\" :title=\"copyTitle\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n <div v-for=\"notification in notifications\" :key=\"'notif-' + notification.type\" class=\"ai-chat-notification\" :class=\"'ai-chat-notification-' + (notification.type || 'info') + ' ' + (notification.cssClass || '')\">\n <div class=\"ai-chat-notification-content\">\n <i v-if=\"notification.icon\" :class=\"notification.icon\" class=\"ai-chat-notification-icon\"></i>\n <span class=\"ai-chat-notification-text\">{{ notification.content }}</span>\n <button v-if=\"notification.dismissible\" class=\"btn btn-sm btn-link p-0 ms-2 ai-chat-notification-dismiss\" @click=\"dismissNotification(notification.type)\" title=\"Dismiss\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div v-if=\"notification.actions && notification.actions.length\" class=\"ai-chat-notification-actions\">\n <button v-for=\"action in notification.actions\" :key=\"action.name\" class=\"btn btn-sm\" :class=\"action.cssClass || 'btn-outline-secondary'\" @click=\"handleNotificationAction(notification.type, action.name)\">\n <i v-if=\"action.icon\" :class=\"action.icon\" class=\"me-1\"></i>\n {{ action.label }}\n </button>\n </div>\n </div>\n </div>\n ",
58
+ messageTemplate: "\n <div class=\"ai-chat-messages\">\n <div v-for=\"(message, index) in messages\" :key=\"'msg-' + index\" class=\"ai-chat-message-item\">\n <div>\n <div v-if=\"message.role === 'user'\" class=\"ai-chat-msg-role ai-chat-msg-role-user\">{{ userLabel }}</div>\n <div v-else-if=\"message.role !== 'indicator'\" :class=\"getAssistantRoleClasses(message)\">\n <span :class=\"getAssistantIconClasses(message, index)\"><i :class=\"getAssistantIcon(message)\"></i></span>\n {{ getAssistantLabel(message) }}\n </div>\n <div class=\"ai-chat-message-body lh-base\">\n <h4 v-if=\"message.title\">{{ message.title }}</h4>\n <div v-html=\"message.htmlContent\"></div>\n <ol v-if=\"message.citationReferences && message.citationReferences.length\" class=\"ai-chat-citation-list\">\n <li v-for=\"citation in message.citationReferences\" :key=\"'citation-' + (citation.referenceKey || citation.displayIndex)\" class=\"ai-chat-citation-item\">\n <a v-if=\"citation.link\" :href=\"citation.link\" :target=\"citation.isDownload ? null : '_blank'\" :rel=\"citation.isDownload ? null : 'noopener noreferrer'\">{{ citation.label }}</a>\n <span v-else>{{ citation.label }}</span>\n </li>\n </ol>\n <span class=\"message-buttons-container\" v-if=\"!isIndicator(message)\">\n <template v-if=\"metricsEnabled && message.role === 'assistant'\">\n <span class=\"ai-chat-message-assistant-feedback\" :data-message-id=\"message.id\">\n <button type=\"button\" class=\"btn btn-sm btn-link text-success p-0 me-2 button-message-toolbox rate-up-btn\" @click=\"rateMessage(message, true, $event)\" :title=\"thumbsUpTitle\">\n <i class=\"fa-regular fa-thumbs-up\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-sm btn-link text-danger p-0 me-2 button-message-toolbox rate-down-btn\" @click=\"rateMessage(message, false, $event)\" :title=\"thumbsDownTitle\">\n <i class=\"fa-regular fa-thumbs-down\"></i>\n </button>\n </span>\n </template>\n <button type=\"button\" v-if=\"textToSpeechEnabled && !isConversationMode && message.role === 'assistant' && !message.isStreaming\" class=\"btn btn-sm btn-link text-secondary p-0 me-1 button-message-toolbox\" :class=\"{ 'tts-playing': ttsPlayingMessageIndex === index }\" :data-tts-message-index=\"index\" @click=\"toggleMessageTts(message, index)\" :title=\"ttsPlayingMessageIndex === index ? 'Pause audio' : 'Read aloud'\">\n <span :class=\"ttsPlayingMessageIndex === index ? 'fa-solid fa-circle-pause' : 'fa-solid fa-circle-play'\"></span>\n </button>\n <button type=\"button\" class=\"btn btn-sm btn-link text-secondary p-0 button-message-toolbox\" @click=\"copyResponse(message)\" :title=\"copyTitle\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n <div v-for=\"notification in notifications\" :key=\"'notif-' + notification.type\" class=\"ai-chat-notification\" :class=\"'ai-chat-notification-' + (notification.type || 'info') + ' ' + (notification.cssClass || '')\">\n <div class=\"ai-chat-notification-content\">\n <i v-if=\"notification.icon\" :class=\"notification.icon\" class=\"ai-chat-notification-icon\"></i>\n <span class=\"ai-chat-notification-text\">{{ notification.content }}</span>\n <button type=\"button\" v-if=\"notification.dismissible\" class=\"btn btn-sm btn-link p-0 ms-2 ai-chat-notification-dismiss\" @click=\"dismissNotification(notification.type)\" title=\"Dismiss\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div v-if=\"notification.actions && notification.actions.length\" class=\"ai-chat-notification-actions\">\n <button type=\"button\" v-for=\"action in notification.actions\" :key=\"action.name\" class=\"btn btn-sm\" :class=\"action.cssClass || 'btn-outline-secondary'\" @click=\"handleNotificationAction(notification.type, action.name)\">\n <i v-if=\"action.icon\" :class=\"action.icon\" class=\"me-1\"></i>\n {{ action.label }}\n </button>\n </div>\n </div>\n </div>\n ",
56
59
  indicatorTemplate: "\n <div class=\"ai-chat-msg-role ai-chat-msg-role-assistant\">\n <span class=\"ai-streaming-icon\"><i class=\"fa fa-robot\" style=\"display: inline-block;\"></i></span>\n Assistant\n </div>\n "
57
60
  };
58
61
 
@@ -72,6 +75,42 @@ window.openAIChatManager = function () {
72
75
  span.textContent = text;
73
76
  return span.innerHTML;
74
77
  }
78
+ function containsFontAwesomePlaceholders(root) {
79
+ if (!root || root.nodeType !== 1) {
80
+ return false;
81
+ }
82
+ var selector = 'i[class*="fa-"],i.fa,i.fas,i.far,i.fab';
83
+ if (typeof root.matches === 'function' && root.matches(selector)) {
84
+ return true;
85
+ }
86
+ return typeof root.querySelector === 'function' && !!root.querySelector(selector);
87
+ }
88
+ function refreshFontAwesomeIcons(root) {
89
+ var fontAwesome = window.FontAwesome;
90
+ if (!containsFontAwesomePlaceholders(root) || !fontAwesome || !fontAwesome.dom || typeof fontAwesome.dom.i2svg !== 'function') {
91
+ return;
92
+ }
93
+ fontAwesome.dom.i2svg({
94
+ node: root
95
+ });
96
+ }
97
+ function observeFontAwesomeIcons(root) {
98
+ if (!root || typeof MutationObserver === 'undefined') {
99
+ return null;
100
+ }
101
+ var observer = new MutationObserver(function (mutations) {
102
+ mutations.forEach(function (mutation) {
103
+ mutation.addedNodes.forEach(function (node) {
104
+ refreshFontAwesomeIcons(node);
105
+ });
106
+ });
107
+ });
108
+ observer.observe(root, {
109
+ childList: true,
110
+ subtree: true
111
+ });
112
+ return observer;
113
+ }
75
114
  function parsePixelValue(value) {
76
115
  if (typeof value === 'number' && Number.isFinite(value)) {
77
116
  return value;
@@ -86,16 +125,30 @@ window.openAIChatManager = function () {
86
125
  return Math.min(Math.max(value, min), max);
87
126
  }
88
127
  function normalizeReference(reference) {
89
- var _ref, _normalized$index, _ref2, _normalized$text, _ref3, _normalized$link;
128
+ var _ref, _normalized$index, _ref2, _normalized$text, _ref3, _normalized$title, _ref4, _normalized$link, _ref5, _normalized$reference;
90
129
  if (!reference || _typeof(reference) !== 'object') {
91
130
  return null;
92
131
  }
93
132
  var normalized = Object.assign({}, reference);
94
133
  normalized.index = (_ref = (_normalized$index = normalized.index) !== null && _normalized$index !== void 0 ? _normalized$index : normalized.Index) !== null && _ref !== void 0 ? _ref : 0;
95
134
  normalized.text = (_ref2 = (_normalized$text = normalized.text) !== null && _normalized$text !== void 0 ? _normalized$text : normalized.Text) !== null && _ref2 !== void 0 ? _ref2 : null;
96
- normalized.link = (_ref3 = (_normalized$link = normalized.link) !== null && _normalized$link !== void 0 ? _normalized$link : normalized.Link) !== null && _ref3 !== void 0 ? _ref3 : null;
135
+ normalized.title = (_ref3 = (_normalized$title = normalized.title) !== null && _normalized$title !== void 0 ? _normalized$title : normalized.Title) !== null && _ref3 !== void 0 ? _ref3 : null;
136
+ normalized.link = sanitizeUrl((_ref4 = (_normalized$link = normalized.link) !== null && _normalized$link !== void 0 ? _normalized$link : normalized.Link) !== null && _ref4 !== void 0 ? _ref4 : null);
137
+ normalized.referenceType = (_ref5 = (_normalized$reference = normalized.referenceType) !== null && _normalized$reference !== void 0 ? _normalized$reference : normalized.ReferenceType) !== null && _ref5 !== void 0 ? _ref5 : null;
97
138
  return normalized;
98
139
  }
140
+ function isDownloadCitationReference(reference) {
141
+ if (!reference || _typeof(reference) !== 'object') {
142
+ return false;
143
+ }
144
+ if (typeof reference.referenceType === 'string' && reference.referenceType.toLowerCase() === 'document') {
145
+ return true;
146
+ }
147
+ if (typeof reference.link === 'string' && /\/ai\/documents\/.+\/download(?:$|\?)/i.test(reference.link)) {
148
+ return true;
149
+ }
150
+ return false;
151
+ }
99
152
  function normalizeReferences(references) {
100
153
  if (!references || _typeof(references) !== 'object') {
101
154
  return {};
@@ -110,6 +163,125 @@ window.openAIChatManager = function () {
110
163
  }
111
164
  return normalized;
112
165
  }
166
+ function getCitationLabel(reference, key) {
167
+ return reference.title || reference.text || key;
168
+ }
169
+ function buildCitationDisplay(content, references) {
170
+ var processedContent = (content || '').trim();
171
+ var messageReferences = normalizeReferences(references);
172
+ if (!processedContent || !Object.keys(messageReferences).length) {
173
+ return {
174
+ content: processedContent,
175
+ citations: []
176
+ };
177
+ }
178
+ var citedRefs = Object.entries(messageReferences).filter(function (_ref6) {
179
+ var _ref7 = _slicedToArray(_ref6, 1),
180
+ key = _ref7[0];
181
+ return processedContent.includes(key);
182
+ });
183
+ if (!citedRefs.length) {
184
+ return {
185
+ content: processedContent,
186
+ citations: []
187
+ };
188
+ }
189
+ citedRefs.sort(function (_ref8, _ref9) {
190
+ var _ref0 = _slicedToArray(_ref8, 2),
191
+ a = _ref0[1];
192
+ var _ref1 = _slicedToArray(_ref9, 2),
193
+ b = _ref1[1];
194
+ return a.index - b.index;
195
+ });
196
+ var citations = [];
197
+ var displayIndex = 1;
198
+ var _iterator = _createForOfIteratorHelper(citedRefs),
199
+ _step;
200
+ try {
201
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
202
+ var _step$value = _slicedToArray(_step.value, 2),
203
+ key = _step$value[0],
204
+ value = _step$value[1];
205
+ var placeholder = "__CITE_".concat(displayIndex, "_").concat(value.index || displayIndex, "__");
206
+ processedContent = processedContent.replaceAll(key, placeholder);
207
+ citations.push({
208
+ referenceKey: key,
209
+ displayIndex: displayIndex,
210
+ label: getCitationLabel(value, key),
211
+ link: value.link || null,
212
+ isDownload: isDownloadCitationReference(value),
213
+ placeholder: placeholder
214
+ });
215
+ displayIndex++;
216
+ }
217
+ } catch (err) {
218
+ _iterator.e(err);
219
+ } finally {
220
+ _iterator.f();
221
+ }
222
+ for (var _i2 = 0, _citations = citations; _i2 < _citations.length; _i2++) {
223
+ var citation = _citations[_i2];
224
+ processedContent = processedContent.replaceAll(citation.placeholder, "<sup>".concat(citation.displayIndex, "</sup>"));
225
+ }
226
+ processedContent = processedContent.replaceAll('</sup><sup>', '</sup><sup>,</sup><sup>');
227
+ return {
228
+ content: processedContent,
229
+ citations: citations.map(function (_ref10) {
230
+ var placeholder = _ref10.placeholder,
231
+ citation = _objectWithoutProperties(_ref10, _excluded);
232
+ return citation;
233
+ })
234
+ };
235
+ }
236
+ function buildCopyContent(content, citations) {
237
+ var copyContent = (content || '').trim();
238
+ if (!copyContent || !Array.isArray(citations) || citations.length === 0) {
239
+ return copyContent;
240
+ }
241
+ var _iterator2 = _createForOfIteratorHelper(citations),
242
+ _step2;
243
+ try {
244
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
245
+ var citation = _step2.value;
246
+ copyContent = copyContent.replaceAll(citation.referenceKey, "[".concat(citation.displayIndex, "]"));
247
+ }
248
+ } catch (err) {
249
+ _iterator2.e(err);
250
+ } finally {
251
+ _iterator2.f();
252
+ }
253
+ copyContent += '\n\nReferences:\n';
254
+ var _iterator3 = _createForOfIteratorHelper(citations),
255
+ _step3;
256
+ try {
257
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
258
+ var _citation = _step3.value;
259
+ copyContent += "".concat(_citation.displayIndex, ". ").concat(_citation.label);
260
+ if (_citation.link) {
261
+ copyContent += " - ".concat(_citation.link);
262
+ }
263
+ copyContent += '\n';
264
+ }
265
+ } catch (err) {
266
+ _iterator3.e(err);
267
+ } finally {
268
+ _iterator3.f();
269
+ }
270
+ return copyContent.trimEnd();
271
+ }
272
+ function updateMessagePresentation(message, references) {
273
+ var messageReferences = normalizeReferences(references !== null && references !== void 0 ? references : message.references);
274
+ var rawContent = typeof message.rawContent === 'string' ? message.rawContent : typeof message.content === 'string' ? message.content : '';
275
+ var citationDisplay = buildCitationDisplay(rawContent, messageReferences);
276
+ message.rawContent = rawContent;
277
+ message.content = rawContent;
278
+ message.displayContent = citationDisplay.content;
279
+ message.references = messageReferences;
280
+ message.citationReferences = citationDisplay.citations;
281
+ message.copyContent = buildCopyContent(rawContent, citationDisplay.citations);
282
+ message.htmlContent = parseMarkdownContent(citationDisplay.content, message);
283
+ return message;
284
+ }
113
285
  var renderer = new marked.Renderer();
114
286
 
115
287
  // Modify the link rendering to open in a new tab
@@ -275,17 +447,17 @@ window.openAIChatManager = function () {
275
447
  // Defer to requestAnimationFrame so the browser has fully laid out the
276
448
  // canvas elements before Chart.js reads their dimensions.
277
449
  requestAnimationFrame(function () {
278
- var _iterator = _createForOfIteratorHelper(charts),
279
- _step;
450
+ var _iterator4 = _createForOfIteratorHelper(charts),
451
+ _step4;
280
452
  try {
281
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
282
- var c = _step.value;
453
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
454
+ var c = _step4.value;
283
455
  renderChartOnCanvas(c.chartId, c.config);
284
456
  }
285
457
  } catch (err) {
286
- _iterator.e(err);
458
+ _iterator4.e(err);
287
459
  } finally {
288
- _iterator.f();
460
+ _iterator4.f();
289
461
  }
290
462
  });
291
463
  }
@@ -338,8 +510,8 @@ window.openAIChatManager = function () {
338
510
  return;
339
511
  }
340
512
  requestAnimationFrame(function () {
341
- for (var _i2 = 0, _Object$keys = Object.keys(configs); _i2 < _Object$keys.length; _i2++) {
342
- var chartId = _Object$keys[_i2];
513
+ for (var _i3 = 0, _Object$keys = Object.keys(configs); _i3 < _Object$keys.length; _i3++) {
514
+ var chartId = _Object$keys[_i3];
343
515
  renderChartOnCanvas(chartId, configs[chartId]);
344
516
  }
345
517
  });
@@ -363,6 +535,7 @@ window.openAIChatManager = function () {
363
535
  var config = Object.assign({}, defaultConfig, instanceConfig);
364
536
  config.widget = Object.assign({}, defaultConfig.widget || {}, instanceConfig && instanceConfig.widget ? instanceConfig.widget : {});
365
537
  var hasWidgetConfig = !!(instanceConfig && instanceConfig.widget && instanceConfig.widget.chatWidgetContainer && instanceConfig.widget.chatWidgetStateName);
538
+ var widgetBehavior = window.openAIChatWidgetBehavior || null;
366
539
  // Keep defaultConfig in sync so renderers use overridden values
367
540
  defaultConfig = config;
368
541
  if (!config.signalRHubUrl) {
@@ -385,7 +558,7 @@ window.openAIChatManager = function () {
385
558
  console.error('The sendButtonElementSelector is required.');
386
559
  return;
387
560
  }
388
- var app = Vue.createApp({
561
+ var appDefinition = {
389
562
  data: function data() {
390
563
  return {
391
564
  inputElement: null,
@@ -394,18 +567,6 @@ window.openAIChatManager = function () {
394
567
  placeholder: null,
395
568
  isSessionStarted: false,
396
569
  isPlaceholderVisible: true,
397
- chatWidgetStateName: null,
398
- chatWidgetStateSession: null,
399
- chatWidgetLayoutKey: null,
400
- chatHistorySection: null,
401
- widgetContainerElement: null,
402
- widgetToggleButtonElement: null,
403
- widgetResetSizeButtonElement: null,
404
- widgetResizeObserver: null,
405
- widgetViewportResizeHandler: null,
406
- widgetDefaultWidth: null,
407
- widgetDefaultHeight: null,
408
- widgetIsInitialized: false,
409
570
  isStreaming: false,
410
571
  isNavigatingAway: false,
411
572
  autoScroll: true,
@@ -415,6 +576,8 @@ window.openAIChatManager = function () {
415
576
  prompt: '',
416
577
  documents: config.existingDocuments || [],
417
578
  isUploading: false,
579
+ isDocumentOperationPending: false,
580
+ documentOperationQueue: null,
418
581
  uploadErrors: [],
419
582
  isDragOver: false,
420
583
  documentBar: null,
@@ -444,7 +607,11 @@ window.openAIChatManager = function () {
444
607
  conversationModeEnabled: config.chatMode === 'Conversation',
445
608
  conversationButton: null,
446
609
  isConversationMode: false,
447
- notificationDismissTimers: {}
610
+ notificationDismissTimers: {},
611
+ pendingSessionPromise: null,
612
+ pendingSessionResolver: null,
613
+ pendingSessionRejector: null,
614
+ pendingSessionTimeoutId: null
448
615
  };
449
616
  },
450
617
  computed: {
@@ -461,255 +628,6 @@ window.openAIChatManager = function () {
461
628
  handleBeforeUnload: function handleBeforeUnload() {
462
629
  this.isNavigatingAway = true;
463
630
  },
464
- getStoredWidgetLayout: function getStoredWidgetLayout() {
465
- if (!this.chatWidgetLayoutKey || !config.widget.persistLayout) {
466
- return {};
467
- }
468
- try {
469
- var storedLayout = localStorage.getItem(this.chatWidgetLayoutKey);
470
- return storedLayout ? JSON.parse(storedLayout) || {} : {};
471
- } catch (error) {
472
- console.warn('Failed to read widget layout state.', error);
473
- return {};
474
- }
475
- },
476
- saveStoredWidgetLayout: function saveStoredWidgetLayout(partialLayout) {
477
- if (!this.chatWidgetLayoutKey || !config.widget.persistLayout) {
478
- return;
479
- }
480
- var currentLayout = this.getStoredWidgetLayout();
481
- var nextLayout = Object.assign({}, currentLayout);
482
- if (partialLayout.panel !== undefined) {
483
- nextLayout.panel = Object.assign({}, currentLayout.panel || {}, partialLayout.panel || {});
484
- }
485
- if (partialLayout.toggle !== undefined) {
486
- nextLayout.toggle = Object.assign({}, currentLayout.toggle || {}, partialLayout.toggle || {});
487
- }
488
- localStorage.setItem(this.chatWidgetLayoutKey, JSON.stringify(nextLayout));
489
- },
490
- getElementSize: function getElementSize(element, fallbackWidth, fallbackHeight) {
491
- if (!element) {
492
- return {
493
- width: fallbackWidth || 0,
494
- height: fallbackHeight || 0
495
- };
496
- }
497
- var rect = element.getBoundingClientRect();
498
- var computed = window.getComputedStyle(element);
499
- return {
500
- width: Math.round(rect.width || parsePixelValue(computed.width) || fallbackWidth || 0),
501
- height: Math.round(rect.height || parsePixelValue(computed.height) || fallbackHeight || 0)
502
- };
503
- },
504
- clampWidgetPosition: function clampWidgetPosition(left, top, width, height) {
505
- var viewportPadding = 8;
506
- var maxLeft = Math.max(viewportPadding, window.innerWidth - width - viewportPadding);
507
- var maxTop = Math.max(viewportPadding, window.innerHeight - height - viewportPadding);
508
- return {
509
- left: Math.round(clamp(left, viewportPadding, maxLeft)),
510
- top: Math.round(clamp(top, viewportPadding, maxTop))
511
- };
512
- },
513
- applyAbsolutePosition: function applyAbsolutePosition(element, left, top) {
514
- if (!element) {
515
- return;
516
- }
517
- element.style.left = left + 'px';
518
- element.style.top = top + 'px';
519
- element.style.right = 'auto';
520
- element.style.bottom = 'auto';
521
- },
522
- getWidgetDefaultSize: function getWidgetDefaultSize() {
523
- return {
524
- width: this.widgetDefaultWidth || parsePixelValue(config.widget.defaultWidth) || 380,
525
- height: this.widgetDefaultHeight || parsePixelValue(config.widget.defaultHeight) || 520
526
- };
527
- },
528
- persistWidgetPanelPosition: function persistWidgetPanelPosition() {
529
- if (!this.widgetContainerElement || !config.widget.persistLayout) {
530
- return;
531
- }
532
- var panelRect = this.widgetContainerElement.getBoundingClientRect();
533
- this.saveStoredWidgetLayout({
534
- panel: {
535
- left: Math.round(panelRect.left),
536
- top: Math.round(panelRect.top)
537
- }
538
- });
539
- },
540
- persistWidgetTogglePosition: function persistWidgetTogglePosition() {
541
- if (!this.widgetToggleButtonElement || !config.widget.persistLayout) {
542
- return;
543
- }
544
- var toggleRect = this.widgetToggleButtonElement.getBoundingClientRect();
545
- this.saveStoredWidgetLayout({
546
- toggle: {
547
- left: Math.round(toggleRect.left),
548
- top: Math.round(toggleRect.top)
549
- }
550
- });
551
- },
552
- persistWidgetPanelSize: function persistWidgetPanelSize() {
553
- if (!this.widgetContainerElement || !config.widget.enableResizing || !config.widget.persistLayout) {
554
- return;
555
- }
556
- var defaultSize = this.getWidgetDefaultSize();
557
- var currentSize = this.getElementSize(this.widgetContainerElement, defaultSize.width, defaultSize.height);
558
- this.saveStoredWidgetLayout({
559
- panel: {
560
- width: Math.abs(currentSize.width - defaultSize.width) <= 1 ? null : currentSize.width,
561
- height: Math.abs(currentSize.height - defaultSize.height) <= 1 ? null : currentSize.height
562
- }
563
- });
564
- },
565
- updateWidgetResetSizeButtonVisibility: function updateWidgetResetSizeButtonVisibility() {
566
- if (!this.widgetResetSizeButtonElement) {
567
- return;
568
- }
569
- if (!config.widget.enableResizing || !this.widgetContainerElement) {
570
- this.widgetResetSizeButtonElement.classList.add('d-none');
571
- return;
572
- }
573
- var defaultSize = this.getWidgetDefaultSize();
574
- var currentSize = this.getElementSize(this.widgetContainerElement, defaultSize.width, defaultSize.height);
575
- var isResized = Math.abs(currentSize.width - defaultSize.width) > 1 || Math.abs(currentSize.height - defaultSize.height) > 1 || !!this.widgetContainerElement.style.width || !!this.widgetContainerElement.style.height;
576
- this.widgetResetSizeButtonElement.classList.toggle('d-none', !isResized);
577
- },
578
- resetWidgetSize: function resetWidgetSize() {
579
- if (!this.widgetContainerElement || !config.widget.enableResizing) {
580
- return;
581
- }
582
- this.widgetContainerElement.style.removeProperty('width');
583
- this.widgetContainerElement.style.removeProperty('height');
584
- this.persistWidgetPanelSize();
585
- this.constrainWidgetElementsToViewport();
586
- this.updateWidgetResetSizeButtonVisibility();
587
- },
588
- restoreWidgetLayout: function restoreWidgetLayout() {
589
- var storedLayout = this.getStoredWidgetLayout();
590
- if (this.widgetContainerElement && config.widget.enableResizing) {
591
- if (Number.isFinite(storedLayout.panel && storedLayout.panel.width)) {
592
- this.widgetContainerElement.style.width = storedLayout.panel.width + 'px';
593
- } else {
594
- this.widgetContainerElement.style.removeProperty('width');
595
- }
596
- if (Number.isFinite(storedLayout.panel && storedLayout.panel.height)) {
597
- this.widgetContainerElement.style.height = storedLayout.panel.height + 'px';
598
- } else {
599
- this.widgetContainerElement.style.removeProperty('height');
600
- }
601
- }
602
- if (this.widgetContainerElement && config.widget.enableDragging && Number.isFinite(storedLayout.panel && storedLayout.panel.left) && Number.isFinite(storedLayout.panel && storedLayout.panel.top)) {
603
- this.applyAbsolutePosition(this.widgetContainerElement, storedLayout.panel.left, storedLayout.panel.top);
604
- }
605
- if (this.widgetToggleButtonElement && config.widget.enableDragging && Number.isFinite(storedLayout.toggle && storedLayout.toggle.left) && Number.isFinite(storedLayout.toggle && storedLayout.toggle.top)) {
606
- this.applyAbsolutePosition(this.widgetToggleButtonElement, storedLayout.toggle.left, storedLayout.toggle.top);
607
- }
608
- this.constrainWidgetElementsToViewport();
609
- this.updateWidgetResetSizeButtonVisibility();
610
- },
611
- attachDraggableWidgetElement: function attachDraggableWidgetElement(element, handle, layoutKey, suppressClickOnDrag) {
612
- var _this = this;
613
- if (!element || !handle || !config.widget.enableDragging) {
614
- return;
615
- }
616
- var activePointerId = null;
617
- var startX = 0;
618
- var startY = 0;
619
- var startLeft = 0;
620
- var startTop = 0;
621
- var dragged = false;
622
- var dragThreshold = 4;
623
- var interactiveSelector = 'button, a, input, textarea, select, option, label';
624
- var _stopDragging = function stopDragging(event) {
625
- if (activePointerId === null) {
626
- return;
627
- }
628
- if (event && event.pointerId !== undefined && event.pointerId !== activePointerId) {
629
- return;
630
- }
631
- document.removeEventListener('pointermove', onPointerMove);
632
- document.removeEventListener('pointerup', _stopDragging);
633
- document.removeEventListener('pointercancel', _stopDragging);
634
- element.classList.remove('ai-chat-widget-dragging');
635
- activePointerId = null;
636
- if (!dragged) {
637
- return;
638
- }
639
- if (layoutKey === 'panel') {
640
- _this.persistWidgetPanelPosition();
641
- } else if (layoutKey === 'toggle') {
642
- _this.persistWidgetTogglePosition();
643
- }
644
- if (suppressClickOnDrag) {
645
- element.dataset.dragSuppressClick = 'true';
646
- window.setTimeout(function () {
647
- if (element.dataset.dragSuppressClick === 'true') {
648
- element.dataset.dragSuppressClick = 'false';
649
- }
650
- }, 0);
651
- }
652
- };
653
- var onPointerMove = function onPointerMove(event) {
654
- if (activePointerId === null || event.pointerId !== activePointerId) {
655
- return;
656
- }
657
- var deltaX = event.clientX - startX;
658
- var deltaY = event.clientY - startY;
659
- if (!dragged && Math.hypot(deltaX, deltaY) < dragThreshold) {
660
- return;
661
- }
662
- dragged = true;
663
- var defaultSize = _this.getWidgetDefaultSize();
664
- var currentSize = _this.getElementSize(element, layoutKey === 'panel' ? defaultSize.width : 52, layoutKey === 'panel' ? defaultSize.height : 52);
665
- var nextPosition = _this.clampWidgetPosition(startLeft + deltaX, startTop + deltaY, currentSize.width, currentSize.height);
666
- _this.applyAbsolutePosition(element, nextPosition.left, nextPosition.top);
667
- };
668
- handle.addEventListener('pointerdown', function (event) {
669
- if (event.button !== 0) {
670
- return;
671
- }
672
- if (layoutKey === 'panel' && event.target.closest(interactiveSelector)) {
673
- return;
674
- }
675
- var rect = element.getBoundingClientRect();
676
- startX = event.clientX;
677
- startY = event.clientY;
678
- startLeft = rect.left;
679
- startTop = rect.top;
680
- dragged = false;
681
- activePointerId = event.pointerId;
682
- element.classList.add('ai-chat-widget-dragging');
683
- if (handle.setPointerCapture) {
684
- handle.setPointerCapture(event.pointerId);
685
- }
686
- document.addEventListener('pointermove', onPointerMove);
687
- document.addEventListener('pointerup', _stopDragging);
688
- document.addEventListener('pointercancel', _stopDragging);
689
- event.preventDefault();
690
- });
691
- },
692
- constrainWidgetElementsToViewport: function constrainWidgetElementsToViewport() {
693
- if (this.widgetContainerElement && this.widgetContainerElement.style.left) {
694
- var panelDefaultSize = this.getWidgetDefaultSize();
695
- var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
696
- var panelRect = this.widgetContainerElement.getBoundingClientRect();
697
- var clampedPanel = this.clampWidgetPosition(panelRect.left, panelRect.top, panelSize.width, panelSize.height);
698
- this.applyAbsolutePosition(this.widgetContainerElement, clampedPanel.left, clampedPanel.top);
699
- if (config.widget.persistLayout) {
700
- this.persistWidgetPanelPosition();
701
- }
702
- }
703
- if (this.widgetToggleButtonElement && this.widgetToggleButtonElement.style.left) {
704
- var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
705
- var toggleRect = this.widgetToggleButtonElement.getBoundingClientRect();
706
- var clampedToggle = this.clampWidgetPosition(toggleRect.left, toggleRect.top, toggleSize.width, toggleSize.height);
707
- this.applyAbsolutePosition(this.widgetToggleButtonElement, clampedToggle.left, clampedToggle.top);
708
- if (config.widget.persistLayout) {
709
- this.persistWidgetTogglePosition();
710
- }
711
- }
712
- },
713
631
  handleDragOver: function handleDragOver(e) {
714
632
  if (!config.sessionDocumentsEnabled) return;
715
633
  e.preventDefault();
@@ -734,180 +652,272 @@ window.openAIChatManager = function () {
734
652
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
735
653
  if (inputArea) inputArea.classList.remove('ai-chat-drag-over');
736
654
  if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
737
- this.uploadFiles(e.dataTransfer.files);
655
+ this.uploadFiles(Array.from(e.dataTransfer.files));
738
656
  }
739
657
  },
740
658
  triggerFileInput: function triggerFileInput() {
741
- if (!config.sessionDocumentsEnabled) return;
659
+ if (!config.sessionDocumentsEnabled || this.isDocumentOperationPending) return;
742
660
  var fileInput = document.getElementById('ai-chat-doc-input');
743
661
  if (fileInput) fileInput.click();
744
662
  },
745
663
  handleFileInputChange: function handleFileInputChange(e) {
746
- var files = e.target.files;
664
+ var files = e.target.files ? Array.from(e.target.files) : [];
747
665
  if (files && files.length > 0) {
748
666
  this.uploadFiles(files);
749
667
  }
750
668
  e.target.value = '';
751
669
  },
752
- uploadFiles: function uploadFiles(files) {
753
- var _this2 = this;
754
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
755
- var sessionId, profileId, formData, i, response, errorText, uploadError, result, j, _t;
670
+ queueDocumentOperation: function queueDocumentOperation(operation) {
671
+ var self = this;
672
+ var previousOperation = this.documentOperationQueue || Promise.resolve();
673
+ var nextOperation = previousOperation["catch"](function () {}).then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
756
674
  return _regenerator().w(function (_context) {
757
675
  while (1) switch (_context.p = _context.n) {
676
+ case 0:
677
+ self.isDocumentOperationPending = true;
678
+ _context.p = 1;
679
+ _context.n = 2;
680
+ return operation();
681
+ case 2:
682
+ return _context.a(2, _context.v);
683
+ case 3:
684
+ _context.p = 3;
685
+ self.isDocumentOperationPending = false;
686
+ return _context.f(3);
687
+ case 4:
688
+ return _context.a(2);
689
+ }
690
+ }, _callee, null, [[1,, 3, 4]]);
691
+ })));
692
+ this.documentOperationQueue = nextOperation["finally"](function () {
693
+ if (self.documentOperationQueue === nextOperation) {
694
+ self.documentOperationQueue = null;
695
+ }
696
+ });
697
+ return this.documentOperationQueue;
698
+ },
699
+ uploadFiles: function uploadFiles(files) {
700
+ var _this = this;
701
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
702
+ var filesToUpload;
703
+ return _regenerator().w(function (_context3) {
704
+ while (1) switch (_context3.n) {
758
705
  case 0:
759
706
  if (config.uploadDocumentUrl) {
760
- _context.n = 1;
707
+ _context3.n = 1;
761
708
  break;
762
709
  }
763
- return _context.a(2);
710
+ return _context3.a(2);
764
711
  case 1:
765
- sessionId = _this2.getSessionId();
766
- profileId = _this2.getProfileId();
767
- if (!(!sessionId && !profileId)) {
768
- _context.n = 2;
712
+ filesToUpload = Array.isArray(files) ? files.slice() : Array.from(files || []);
713
+ if (!(filesToUpload.length === 0)) {
714
+ _context3.n = 2;
769
715
  break;
770
716
  }
771
- console.warn('Cannot upload documents without a session or profile.');
772
- return _context.a(2);
717
+ return _context3.a(2);
773
718
  case 2:
774
- _this2.isUploading = true;
775
- _this2.uploadErrors = [];
776
- _this2.renderDocumentBar();
777
- _context.p = 3;
778
- formData = new FormData();
779
- if (sessionId) {
780
- formData.append('sessionId', sessionId);
781
- } else {
782
- formData.append('profileId', profileId);
783
- }
784
- for (i = 0; i < files.length; i++) {
785
- formData.append('files', files[i]);
786
- }
787
- _context.n = 4;
788
- return fetch(config.uploadDocumentUrl, {
789
- method: 'POST',
790
- body: formData
791
- });
792
- case 4:
793
- response = _context.v;
794
- if (response.ok) {
795
- _context.n = 6;
796
- break;
797
- }
798
- _context.n = 5;
799
- return response.text();
800
- case 5:
801
- errorText = _context.v;
802
- uploadError = _this2.extractReadableErrorMessage(errorText, 'Upload failed. Please try again.');
803
- console.error('Upload failed:', errorText);
804
- _this2.uploadErrors = [{
805
- fileName: '',
806
- error: uploadError
807
- }];
808
- return _context.a(2);
809
- case 6:
810
- _context.n = 7;
811
- return response.json();
812
- case 7:
813
- result = _context.v;
814
- // If the server created a new session, initialize it.
815
- if (result.sessionId && !sessionId) {
816
- _this2.initializeSession(result.sessionId);
817
- }
818
- if (result.uploaded && result.uploaded.length > 0) {
819
- for (j = 0; j < result.uploaded.length; j++) {
820
- _this2.documents.push(result.uploaded[j]);
821
- }
822
- }
823
- if (result.failed && result.failed.length > 0) {
824
- _this2.uploadErrors = result.failed;
825
- }
826
- _context.n = 9;
827
- break;
828
- case 8:
829
- _context.p = 8;
830
- _t = _context.v;
831
- console.error('Upload error:', _t);
832
- _this2.uploadErrors = [{
833
- fileName: '',
834
- error: 'Upload failed. Please try again.'
835
- }];
836
- case 9:
837
- _context.p = 9;
838
- _this2.isUploading = false;
839
- _this2.renderDocumentBar();
840
- return _context.f(9);
841
- case 10:
842
- return _context.a(2);
719
+ return _context3.a(2, _this.queueDocumentOperation(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
720
+ var sessionId, profileId, formData, i, response, errorText, uploadError, result, _t, _t2;
721
+ return _regenerator().w(function (_context2) {
722
+ while (1) switch (_context2.p = _context2.n) {
723
+ case 0:
724
+ sessionId = _this.getSessionId();
725
+ profileId = _this.getProfileId();
726
+ if (sessionId) {
727
+ _context2.n = 4;
728
+ break;
729
+ }
730
+ _context2.p = 1;
731
+ _context2.n = 2;
732
+ return _this.ensureSessionForDocuments(profileId);
733
+ case 2:
734
+ sessionId = _context2.v;
735
+ _context2.n = 4;
736
+ break;
737
+ case 3:
738
+ _context2.p = 3;
739
+ _t = _context2.v;
740
+ console.error('Failed to create a chat session for document upload:', _t);
741
+ _this.uploadErrors = [{
742
+ fileName: '',
743
+ error: 'Could not create a chat session for the upload.'
744
+ }];
745
+ _this.renderDocumentBar();
746
+ return _context2.a(2);
747
+ case 4:
748
+ if (sessionId) {
749
+ _context2.n = 5;
750
+ break;
751
+ }
752
+ console.warn('Cannot upload documents without a session or profile.');
753
+ _this.uploadErrors = [{
754
+ fileName: '',
755
+ error: 'Could not create a chat session for the upload.'
756
+ }];
757
+ _this.renderDocumentBar();
758
+ return _context2.a(2);
759
+ case 5:
760
+ _this.isUploading = true;
761
+ _this.uploadErrors = [];
762
+ _this.renderDocumentBar();
763
+ _context2.p = 6;
764
+ formData = new FormData();
765
+ formData.append('sessionId', sessionId);
766
+ for (i = 0; i < filesToUpload.length; i++) {
767
+ formData.append('files', filesToUpload[i]);
768
+ }
769
+ _context2.n = 7;
770
+ return fetch(config.uploadDocumentUrl, {
771
+ method: 'POST',
772
+ body: formData
773
+ });
774
+ case 7:
775
+ response = _context2.v;
776
+ if (response.ok) {
777
+ _context2.n = 9;
778
+ break;
779
+ }
780
+ _context2.n = 8;
781
+ return response.text();
782
+ case 8:
783
+ errorText = _context2.v;
784
+ uploadError = _this.extractReadableErrorMessage(errorText, 'Upload failed. Please try again.');
785
+ console.error('Upload failed:', errorText);
786
+ _this.uploadErrors = [{
787
+ fileName: '',
788
+ error: uploadError
789
+ }];
790
+ return _context2.a(2);
791
+ case 9:
792
+ _context2.n = 10;
793
+ return response.json();
794
+ case 10:
795
+ result = _context2.v;
796
+ if (result.sessionId && result.sessionId !== _this.getSessionId()) {
797
+ _this.initializeSession(result.sessionId);
798
+ }
799
+ if (Array.isArray(result.documents)) {
800
+ _this.documents = result.documents;
801
+ } else if (result.uploaded && result.uploaded.length > 0) {
802
+ _this.documents = _this.documents.concat(result.uploaded);
803
+ }
804
+ if (result.failed && result.failed.length > 0) {
805
+ _this.uploadErrors = result.failed;
806
+ }
807
+ _context2.n = 12;
808
+ break;
809
+ case 11:
810
+ _context2.p = 11;
811
+ _t2 = _context2.v;
812
+ console.error('Upload error:', _t2);
813
+ _this.uploadErrors = [{
814
+ fileName: '',
815
+ error: 'Upload failed. Please try again.'
816
+ }];
817
+ if (_this.getSessionId()) {
818
+ _this.reloadCurrentSession();
819
+ }
820
+ case 12:
821
+ _context2.p = 12;
822
+ _this.isUploading = false;
823
+ _this.renderDocumentBar();
824
+ return _context2.f(12);
825
+ case 13:
826
+ return _context2.a(2);
827
+ }
828
+ }, _callee2, null, [[6, 11, 12, 13], [1, 3]]);
829
+ }))));
843
830
  }
844
- }, _callee, null, [[3, 8, 9, 10]]);
831
+ }, _callee3);
845
832
  }))();
846
833
  },
847
834
  removeDocument: function removeDocument(doc) {
848
- var _this3 = this;
849
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
850
- var sessionId, response, idx, errorText, removeError, _t2;
851
- return _regenerator().w(function (_context2) {
852
- while (1) switch (_context2.p = _context2.n) {
835
+ var _this2 = this;
836
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
837
+ return _regenerator().w(function (_context5) {
838
+ while (1) switch (_context5.n) {
853
839
  case 0:
854
840
  if (config.removeDocumentUrl) {
855
- _context2.n = 1;
841
+ _context5.n = 1;
856
842
  break;
857
843
  }
858
- return _context2.a(2);
844
+ return _context5.a(2);
859
845
  case 1:
860
- _context2.p = 1;
861
- sessionId = _this3.getSessionId();
862
- _context2.n = 2;
863
- return fetch(config.removeDocumentUrl, {
864
- method: 'POST',
865
- headers: {
866
- 'Content-Type': 'application/json'
867
- },
868
- body: JSON.stringify({
869
- itemId: sessionId,
870
- documentId: doc.documentId
871
- })
872
- });
873
- case 2:
874
- response = _context2.v;
875
- if (!response.ok) {
876
- _context2.n = 3;
877
- break;
878
- }
879
- idx = _this3.documents.indexOf(doc);
880
- if (idx > -1) _this3.documents.splice(idx, 1);
881
- _context2.n = 5;
882
- break;
883
- case 3:
884
- _context2.n = 4;
885
- return response.text();
886
- case 4:
887
- errorText = _context2.v;
888
- removeError = _this3.extractReadableErrorMessage(errorText, 'Failed to remove document. Please try again.');
889
- console.error('Failed to remove document:', response.status, errorText);
890
- _this3.uploadErrors = [{
891
- fileName: doc.fileName || '',
892
- error: removeError
893
- }];
894
- _this3.renderDocumentBar();
895
- case 5:
896
- _context2.n = 7;
897
- break;
898
- case 6:
899
- _context2.p = 6;
900
- _t2 = _context2.v;
901
- console.error('Remove document error:', _t2);
902
- _this3.uploadErrors = [{
903
- fileName: doc.fileName || '',
904
- error: 'Failed to remove document. Please try again.'
905
- }];
906
- _this3.renderDocumentBar();
907
- case 7:
908
- return _context2.a(2);
846
+ return _context5.a(2, _this2.queueDocumentOperation(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
847
+ var sessionId, response, result, idx, errorText, removeError, _t3;
848
+ return _regenerator().w(function (_context4) {
849
+ while (1) switch (_context4.p = _context4.n) {
850
+ case 0:
851
+ _context4.p = 0;
852
+ sessionId = _this2.getSessionId();
853
+ _context4.n = 1;
854
+ return fetch(config.removeDocumentUrl, {
855
+ method: 'POST',
856
+ headers: {
857
+ 'Content-Type': 'application/json'
858
+ },
859
+ body: JSON.stringify({
860
+ itemId: sessionId,
861
+ documentId: doc.documentId
862
+ })
863
+ });
864
+ case 1:
865
+ response = _context4.v;
866
+ if (!response.ok) {
867
+ _context4.n = 3;
868
+ break;
869
+ }
870
+ _context4.n = 2;
871
+ return response.json();
872
+ case 2:
873
+ result = _context4.v;
874
+ if (Array.isArray(result.documents)) {
875
+ _this2.documents = result.documents;
876
+ } else {
877
+ idx = _this2.documents.indexOf(doc);
878
+ if (idx > -1) {
879
+ _this2.documents.splice(idx, 1);
880
+ }
881
+ }
882
+ _context4.n = 5;
883
+ break;
884
+ case 3:
885
+ _context4.n = 4;
886
+ return response.text();
887
+ case 4:
888
+ errorText = _context4.v;
889
+ removeError = _this2.extractReadableErrorMessage(errorText, 'Failed to remove document. Please try again.');
890
+ console.error('Failed to remove document:', response.status, errorText);
891
+ _this2.uploadErrors = [{
892
+ fileName: doc.fileName || '',
893
+ error: removeError
894
+ }];
895
+ if (sessionId) {
896
+ _this2.reloadCurrentSession();
897
+ }
898
+ _this2.renderDocumentBar();
899
+ case 5:
900
+ _context4.n = 7;
901
+ break;
902
+ case 6:
903
+ _context4.p = 6;
904
+ _t3 = _context4.v;
905
+ console.error('Remove document error:', _t3);
906
+ _this2.uploadErrors = [{
907
+ fileName: doc.fileName || '',
908
+ error: 'Failed to remove document. Please try again.'
909
+ }];
910
+ if (_this2.getSessionId()) {
911
+ _this2.reloadCurrentSession();
912
+ }
913
+ _this2.renderDocumentBar();
914
+ case 7:
915
+ return _context4.a(2);
916
+ }
917
+ }, _callee4, null, [[0, 6]]);
918
+ }))));
909
919
  }
910
- }, _callee2, null, [[1, 6]]);
920
+ }, _callee5);
911
921
  }))();
912
922
  },
913
923
  formatFileSize: function formatFileSize(bytes) {
@@ -931,7 +941,7 @@ window.openAIChatManager = function () {
931
941
  html += '<span class="badge bg-secondary bg-opacity-25 text-dark d-inline-flex align-items-center gap-1 px-2 py-1" style="font-size: 0.8rem;" title="' + this.escapeHtml(doc.fileName || '') + '">';
932
942
  html += '<i class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></i> ';
933
943
  html += this.escapeHtml(name);
934
- html += ' <button type="button" class="btn-close btn-close-sm ms-1" style="font-size: 0.5rem;" data-doc-index="' + i + '" aria-label="Remove"></button>';
944
+ html += ' <button type="button" class="btn-close btn-close-sm ms-1" style="font-size: 0.5rem;" data-doc-index="' + i + '" aria-label="Remove"' + (this.isDocumentOperationPending ? ' disabled' : '') + '></button>';
935
945
  html += '</span>';
936
946
  }
937
947
  for (var m = 0; m < this.uploadErrors.length; m++) {
@@ -950,7 +960,7 @@ window.openAIChatManager = function () {
950
960
  html += '<span class="spinner-border spinner-border-sm" style="width: 0.7rem; height: 0.7rem;"></span> Uploading...';
951
961
  html += '</span>';
952
962
  }
953
- html += '<button type="button" class="btn btn-sm btn-outline-secondary rounded-pill ai-chat-doc-add-btn d-inline-flex align-items-center gap-1" style="font-size: 0.75rem; padding: 0.15rem 0.5rem;" title="Attach documents">';
963
+ html += '<button type="button" class="btn btn-sm btn-outline-secondary rounded-pill ai-chat-doc-add-btn d-inline-flex align-items-center gap-1" style="font-size: 0.75rem; padding: 0.15rem 0.5rem;" title="Attach documents"' + (this.isDocumentOperationPending ? ' disabled' : '') + '>';
954
964
  html += '<i class="fa-solid fa-paperclip"></i>';
955
965
  if (this.documents.length === 0 && !this.isUploading) {
956
966
  html += ' <span>Attach files</span>';
@@ -973,6 +983,9 @@ window.openAIChatManager = function () {
973
983
  return function (e) {
974
984
  e.preventDefault();
975
985
  e.stopPropagation();
986
+ if (self.isDocumentOperationPending) {
987
+ return;
988
+ }
976
989
  var docToRemove = self.documents[idx];
977
990
  if (docToRemove) self.removeDocument(docToRemove);
978
991
  };
@@ -997,6 +1010,9 @@ window.openAIChatManager = function () {
997
1010
  if (addBtn) {
998
1011
  addBtn.addEventListener('click', function (e) {
999
1012
  e.preventDefault();
1013
+ if (self.isDocumentOperationPending) {
1014
+ return;
1015
+ }
1000
1016
  self.triggerFileInput();
1001
1017
  });
1002
1018
  }
@@ -1073,139 +1089,135 @@ window.openAIChatManager = function () {
1073
1089
  return !!message && message.isStreaming && index === this.lastAssistantIndex && !(appearance && appearance.disableStreamingAnimation);
1074
1090
  },
1075
1091
  startConnection: function startConnection() {
1076
- var _this4 = this;
1077
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
1078
- var _t3;
1079
- return _regenerator().w(function (_context3) {
1080
- while (1) switch (_context3.p = _context3.n) {
1092
+ var _this3 = this;
1093
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
1094
+ var _t4;
1095
+ return _regenerator().w(function (_context6) {
1096
+ while (1) switch (_context6.p = _context6.n) {
1081
1097
  case 0:
1082
- _this4.connection = new signalR.HubConnectionBuilder().withUrl(config.signalRHubUrl).withAutomaticReconnect().build();
1098
+ _this3.connection = new signalR.HubConnectionBuilder().withUrl(config.signalRHubUrl).withAutomaticReconnect().build();
1083
1099
 
1084
1100
  // Allow long-running operations (e.g., multi-step MCP tool calls)
1085
1101
  // without the client disconnecting prematurely.
1086
- _this4.connection.serverTimeoutInMilliseconds = 600000;
1087
- _this4.connection.keepAliveIntervalInMilliseconds = 15000;
1088
- _this4.connection.on("LoadSession", function (data) {
1102
+ _this3.connection.serverTimeoutInMilliseconds = 600000;
1103
+ _this3.connection.keepAliveIntervalInMilliseconds = 15000;
1104
+ _this3.connection.on("LoadSession", function (data) {
1089
1105
  var _data$messages;
1090
- _this4.initializeSession(data.sessionId, true);
1091
- _this4.messages = [];
1092
- _this4.documents = data.documents || [];
1106
+ _this3.initializeSession(data.sessionId, true);
1107
+ _this3.messages = [];
1108
+ _this3.documents = data.documents || [];
1109
+ _this3.uploadErrors = [];
1093
1110
  ((_data$messages = data.messages) !== null && _data$messages !== void 0 ? _data$messages : []).forEach(function (msg) {
1094
- _this4.addMessage(msg);
1095
- _this4.$nextTick(function () {
1111
+ _this3.addMessage(msg);
1112
+ _this3.$nextTick(function () {
1096
1113
  renderChartsInMessage(msg);
1097
1114
  });
1098
1115
  });
1099
1116
 
1100
1117
  // Update feedback icons in the DOM after all messages have rendered.
1101
- _this4.$nextTick(function () {
1102
- _this4.refreshAllFeedbackIcons();
1118
+ _this3.$nextTick(function () {
1119
+ _this3.refreshAllFeedbackIcons();
1103
1120
  });
1104
1121
 
1105
1122
  // When the session is new (no messages) and an initial prompt is configured,
1106
1123
  // automatically send it as the first user message to trigger an AI response.
1107
- if (_this4.messages.length === 0 && config.initialPrompt) {
1108
- _this4.prompt = config.initialPrompt;
1109
- _this4.sendMessage();
1124
+ if (_this3.messages.length === 0 && config.initialPrompt) {
1125
+ _this3.prompt = config.initialPrompt;
1126
+ _this3.sendMessage();
1110
1127
  }
1111
1128
  });
1112
- _this4.connection.on("ReceiveError", function (error) {
1129
+ _this3.connection.on("ReceiveError", function (error) {
1113
1130
  console.error("SignalR Error: ", error);
1114
- if (_this4.isRecording) {
1115
- _this4.stopRecording();
1131
+ if (_this3.isRecording) {
1132
+ _this3.stopRecording();
1116
1133
  }
1117
-
1118
- // If this is a widget with a stale cached session (e.g., profile was deleted),
1119
- // clear the cached session and start fresh with the current profile.
1120
- if (_this4.widgetIsInitialized && !_this4.isSessionStarted && !_this4._attemptedSessionRecovery) {
1121
- _this4._attemptedSessionRecovery = true;
1122
- localStorage.removeItem(_this4.chatWidgetStateSession);
1123
- _this4.startNewSession();
1134
+ if (widgetBehavior && typeof widgetBehavior.handleReceiveError === 'function') {
1135
+ widgetBehavior.handleReceiveError(_this3, error, config);
1124
1136
  }
1125
1137
  });
1126
- _this4.connection.on("MessageRated", function (messageId, userRating) {
1127
- var msg = _this4.messages.find(function (m) {
1138
+ _this3.connection.on("MessageRated", function (messageId, userRating) {
1139
+ var msg = _this3.messages.find(function (m) {
1128
1140
  return m.id === messageId;
1129
1141
  });
1130
1142
  if (msg) {
1131
1143
  msg.userRating = userRating;
1132
1144
  }
1133
1145
  });
1134
- _this4.connection.on("ReceiveTranscript", function (sessionId, text, isFinal) {
1135
- if (_this4.isConversationMode) {
1146
+ _this3.connection.on("ReceiveTranscript", function (sessionId, text, isFinal) {
1147
+ if (_this3.isConversationMode) {
1136
1148
  if (!isFinal && text) {
1137
- _this4._conversationPartialTranscript = text;
1149
+ _this3._conversationPartialTranscript = text;
1138
1150
  var escaped = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1139
1151
  var html = '<p class="ai-partial-transcript">' + escaped + '</p>';
1140
1152
 
1141
1153
  // Show partial transcript as a live user message.
1142
- if (!_this4._conversationPartialMessage) {
1143
- _this4.hidePlaceholder();
1144
- _this4._conversationPartialMessage = {
1154
+ if (!_this3._conversationPartialMessage) {
1155
+ _this3.hidePlaceholder();
1156
+ _this3._conversationPartialMessage = {
1145
1157
  role: 'user',
1146
1158
  content: text,
1147
1159
  htmlContent: html,
1148
1160
  isPartial: true
1149
1161
  };
1150
- _this4.messages.push(_this4._conversationPartialMessage);
1162
+ _this3.messages.push(_this3._conversationPartialMessage);
1151
1163
  } else {
1152
- _this4._conversationPartialMessage.content = text;
1153
- _this4._conversationPartialMessage.htmlContent = html;
1164
+ _this3._conversationPartialMessage.content = text;
1165
+ _this3._conversationPartialMessage.htmlContent = html;
1154
1166
  }
1155
- _this4.scrollToBottom();
1167
+ _this3.scrollToBottom();
1156
1168
  }
1157
1169
  return;
1158
1170
  }
1159
- if (text && !_this4._audioInputSent) {
1160
- _this4.prompt = _this4.preRecordingPrompt + text;
1161
- if (_this4.inputElement) {
1162
- _this4.inputElement.value = _this4.prompt;
1163
- _this4.inputElement.dispatchEvent(new Event('input'));
1171
+ if (text && !_this3._audioInputSent) {
1172
+ _this3.prompt = _this3.preRecordingPrompt + text;
1173
+ if (_this3.inputElement) {
1174
+ _this3.inputElement.value = _this3.prompt;
1175
+ _this3.inputElement.dispatchEvent(new Event('input'));
1164
1176
  }
1165
1177
  }
1166
1178
  });
1167
- _this4.connection.on("ReceiveConversationUserMessage", function (sessionId, text) {
1179
+ _this3.connection.on("ReceiveConversationUserMessage", function (sessionId, text) {
1168
1180
  if (text) {
1169
- _this4.stopAudio();
1181
+ _this3.stopAudio();
1170
1182
 
1171
1183
  // If there's an interrupted assistant message still streaming,
1172
1184
  // mark it as done to stop the spinner animation.
1173
- if (_this4._conversationAssistantMessage) {
1174
- var oldMsg = _this4.messages[_this4._conversationAssistantMessage.index];
1185
+ if (_this3._conversationAssistantMessage) {
1186
+ var oldMsg = _this3.messages[_this3._conversationAssistantMessage.index];
1175
1187
  if (oldMsg) {
1176
1188
  oldMsg.isStreaming = false;
1177
1189
  }
1178
- _this4._conversationAssistantMessage = null;
1190
+ _this3._conversationAssistantMessage = null;
1179
1191
  }
1180
1192
 
1181
1193
  // Replace the partial transcript message with the final one.
1182
- if (_this4._conversationPartialMessage) {
1194
+ if (_this3._conversationPartialMessage) {
1183
1195
  var escaped = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1184
- _this4._conversationPartialMessage.content = text;
1185
- _this4._conversationPartialMessage.htmlContent = '<p>' + escaped + '</p>';
1186
- _this4._conversationPartialMessage.isPartial = false;
1187
- _this4._conversationPartialMessage = null;
1196
+ _this3._conversationPartialMessage.content = text;
1197
+ _this3._conversationPartialMessage.htmlContent = '<p>' + escaped + '</p>';
1198
+ _this3._conversationPartialMessage.isPartial = false;
1199
+ _this3._conversationPartialMessage = null;
1188
1200
  } else {
1189
- _this4.addMessage({
1201
+ _this3.addMessage({
1190
1202
  role: 'user',
1191
1203
  content: text
1192
1204
  });
1193
1205
  }
1194
- _this4.scrollToBottom();
1206
+ _this3.scrollToBottom();
1195
1207
  }
1196
1208
  });
1197
- _this4.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, appearance) {
1198
- if (!_this4._conversationAssistantMessage) {
1199
- _this4.stopAudio();
1200
- _this4.hideTypingIndicator();
1209
+ _this3.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, references, appearance) {
1210
+ if (!_this3._conversationAssistantMessage) {
1211
+ _this3.stopAudio();
1212
+ _this3.hideTypingIndicator();
1201
1213
 
1202
1214
  // Ensure no stale streaming indicators remain from prior messages.
1203
- for (var j = 0; j < _this4.messages.length; j++) {
1204
- if (_this4.messages[j].isStreaming) {
1205
- _this4.messages[j].isStreaming = false;
1215
+ for (var j = 0; j < _this3.messages.length; j++) {
1216
+ if (_this3.messages[j].isStreaming) {
1217
+ _this3.messages[j].isStreaming = false;
1206
1218
  }
1207
1219
  }
1208
- var msgIndex = _this4.messages.length;
1220
+ var msgIndex = _this3.messages.length;
1209
1221
  var newMessage = {
1210
1222
  id: messageId,
1211
1223
  role: "assistant",
@@ -1213,96 +1225,100 @@ window.openAIChatManager = function () {
1213
1225
  htmlContent: "",
1214
1226
  isStreaming: true,
1215
1227
  userRating: null,
1216
- appearance: _this4.normalizeAssistantAppearance(appearance)
1228
+ appearance: _this3.normalizeAssistantAppearance(appearance),
1229
+ references: {}
1217
1230
  };
1218
- _this4.messages.push(newMessage);
1219
- _this4._conversationAssistantMessage = {
1231
+ _this3.messages.push(newMessage);
1232
+ _this3._conversationAssistantMessage = {
1220
1233
  index: msgIndex,
1221
1234
  content: ''
1222
1235
  };
1223
1236
  }
1224
- _this4._conversationAssistantMessage.content += token;
1225
- var msg = _this4.messages[_this4._conversationAssistantMessage.index];
1237
+ _this3._conversationAssistantMessage.content += token;
1238
+ var msg = _this3.messages[_this3._conversationAssistantMessage.index];
1226
1239
  if (msg) {
1227
1240
  if (!msg.appearance) {
1228
- msg.appearance = _this4.normalizeAssistantAppearance(appearance);
1241
+ msg.appearance = _this3.normalizeAssistantAppearance(appearance);
1229
1242
  }
1230
- msg.content = _this4._conversationAssistantMessage.content;
1231
- msg.htmlContent = parseMarkdownContent(msg.content, msg);
1232
- _this4.$nextTick(function () {
1243
+ msg.rawContent = _this3._conversationAssistantMessage.content;
1244
+ msg.references = normalizeReferences(Object.assign({}, msg.references || {}, references || {}));
1245
+ updateMessagePresentation(msg, msg.references);
1246
+ _this3.$nextTick(function () {
1233
1247
  renderChartsInMessage(msg);
1234
- _this4.scrollToBottom();
1248
+ _this3.scrollToBottom();
1235
1249
  });
1236
1250
  }
1237
1251
  });
1238
- _this4.connection.on("ReceiveConversationAssistantComplete", function (sessionId, messageId) {
1239
- if (_this4._conversationAssistantMessage) {
1240
- var msg = _this4.messages[_this4._conversationAssistantMessage.index];
1252
+ _this3.connection.on("ReceiveConversationAssistantComplete", function (sessionId, messageId, references) {
1253
+ if (_this3._conversationAssistantMessage) {
1254
+ var msg = _this3.messages[_this3._conversationAssistantMessage.index];
1241
1255
  if (msg) {
1242
1256
  msg.isStreaming = false;
1257
+ msg.references = normalizeReferences(Object.assign({}, msg.references || {}, references || {}));
1258
+ updateMessagePresentation(msg, msg.references);
1243
1259
  }
1244
- _this4._conversationAssistantMessage = null;
1260
+ _this3._conversationAssistantMessage = null;
1245
1261
  }
1246
1262
  });
1247
- _this4.connection.on("ReceiveAudioChunk", function (sessionId, base64Audio, contentType) {
1263
+ _this3.connection.on("ReceiveAudioChunk", function (sessionId, base64Audio, contentType) {
1248
1264
  if (base64Audio) {
1249
1265
  var binaryString = atob(base64Audio);
1250
1266
  var bytes = new Uint8Array(binaryString.length);
1251
1267
  for (var i = 0; i < binaryString.length; i++) {
1252
1268
  bytes[i] = binaryString.charCodeAt(i);
1253
1269
  }
1254
- _this4.audioChunks.push(bytes);
1270
+ _this3.audioChunks.push(bytes);
1255
1271
  }
1256
1272
  });
1257
- _this4.connection.on("ReceiveAudioComplete", function (sessionId) {
1258
- _this4.playCollectedAudio();
1273
+ _this3.connection.on("ReceiveAudioComplete", function (sessionId) {
1274
+ _this3.playCollectedAudio();
1259
1275
  });
1260
- _this4.connection.on("ReceiveNotification", function (notification) {
1261
- _this4.receiveNotification(notification);
1276
+ _this3.connection.on("ReceiveNotification", function (notification) {
1277
+ _this3.receiveNotification(notification);
1262
1278
  });
1263
- _this4.connection.on("UpdateNotification", function (notification) {
1264
- _this4.updateNotification(notification);
1279
+ _this3.connection.on("UpdateNotification", function (notification) {
1280
+ _this3.updateNotification(notification);
1265
1281
  });
1266
- _this4.connection.on("RemoveNotification", function (notificationType) {
1267
- _this4.removeNotification(notificationType);
1282
+ _this3.connection.on("RemoveNotification", function (notificationType) {
1283
+ _this3.removeNotification(notificationType);
1268
1284
  });
1269
- _this4.connection.onreconnecting(function () {
1285
+ _this3.connection.onreconnecting(function () {
1270
1286
  console.warn("SignalR: reconnecting...");
1271
1287
  });
1272
- _this4.connection.onreconnected(function () {
1288
+ _this3.connection.onreconnected(function () {
1273
1289
  console.info("SignalR: reconnected.");
1274
- if (_this4.isSessionStarted) {
1275
- _this4.reloadCurrentSession();
1290
+ if (_this3.isSessionStarted) {
1291
+ _this3.reloadCurrentSession();
1276
1292
  } else if (config.autoCreateSession) {
1277
- _this4.startNewSession();
1293
+ _this3.startNewSession();
1278
1294
  }
1279
1295
  });
1280
- _this4.connection.onclose(function (error) {
1281
- if (_this4.isNavigatingAway) {
1296
+ _this3.connection.onclose(function (error) {
1297
+ if (_this3.isNavigatingAway) {
1282
1298
  return;
1283
1299
  }
1284
1300
  if (error) {
1285
1301
  console.warn("SignalR connection closed with error:", error.message || error);
1286
1302
  }
1287
1303
  });
1288
- _context3.p = 1;
1289
- _context3.n = 2;
1290
- return _this4.connection.start();
1304
+ _context6.p = 1;
1305
+ _context6.n = 2;
1306
+ return _this3.connection.start();
1291
1307
  case 2:
1292
- _context3.n = 4;
1308
+ _context6.n = 4;
1293
1309
  break;
1294
1310
  case 3:
1295
- _context3.p = 3;
1296
- _t3 = _context3.v;
1297
- console.error("SignalR Connection Error: ", _t3);
1311
+ _context6.p = 3;
1312
+ _t4 = _context6.v;
1313
+ console.error("SignalR Connection Error: ", _t4);
1298
1314
  case 4:
1299
- return _context3.a(2);
1315
+ return _context6.a(2);
1300
1316
  }
1301
- }, _callee3, null, [[1, 3]]);
1317
+ }, _callee6, null, [[1, 3]]);
1302
1318
  }))();
1303
1319
  },
1304
1320
  addMessageInternal: function addMessageInternal(message) {
1305
- var _this5 = this;
1321
+ var _this4 = this;
1306
1322
  if (message.role === 'assistant') {
1307
1323
  message.appearance = this.normalizeAssistantAppearance(message.appearance);
1308
1324
  }
@@ -1316,7 +1332,7 @@ window.openAIChatManager = function () {
1316
1332
  }));
1317
1333
  this.messages.push(message);
1318
1334
  this.$nextTick(function () {
1319
- _this5.fireEvent(new CustomEvent("addedOpenAIPromotMessage", {
1335
+ _this4.fireEvent(new CustomEvent("addedOpenAIPromotMessage", {
1320
1336
  detail: {
1321
1337
  message: message
1322
1338
  }
@@ -1324,105 +1340,32 @@ window.openAIChatManager = function () {
1324
1340
  });
1325
1341
  },
1326
1342
  addMessage: function addMessage(message) {
1327
- var _this6 = this;
1343
+ var _this5 = this;
1328
1344
  // Ensure userRating is always defined for Vue reactivity.
1329
1345
  if (message.userRating === undefined) {
1330
1346
  message.userRating = null;
1331
1347
  }
1332
1348
  if (message.content) {
1333
- var processedContent = message.content.trim();
1334
- message.references = normalizeReferences(message.references);
1335
- if (message.references && _typeof(message.references) === "object" && Object.keys(message.references).length) {
1336
- // Only include references that were actually cited in the response.
1337
- var citedRefs = Object.entries(message.references).filter(function (_ref4) {
1338
- var _ref5 = _slicedToArray(_ref4, 1),
1339
- key = _ref5[0];
1340
- return processedContent.includes(key);
1341
- });
1342
- if (citedRefs.length) {
1343
- // Sort by original index so display indices follow a natural order.
1344
- citedRefs.sort(function (_ref6, _ref7) {
1345
- var _ref8 = _slicedToArray(_ref6, 2),
1346
- a = _ref8[1];
1347
- var _ref9 = _slicedToArray(_ref7, 2),
1348
- b = _ref9[1];
1349
- return a.index - b.index;
1350
- });
1351
-
1352
- // Phase 1: Replace all markers with unique placeholders.
1353
- var displayIndex = 1;
1354
- var _iterator2 = _createForOfIteratorHelper(citedRefs),
1355
- _step2;
1356
- try {
1357
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1358
- var _step2$value = _slicedToArray(_step2.value, 2),
1359
- key = _step2$value[0],
1360
- value = _step2$value[1];
1361
- var placeholder = "__CITE_".concat(value.index, "__");
1362
- processedContent = processedContent.replaceAll(key, placeholder);
1363
- value._displayIndex = displayIndex++;
1364
- value._placeholder = placeholder;
1365
- }
1366
-
1367
- // Phase 2: Replace placeholders with sequential display indices.
1368
- } catch (err) {
1369
- _iterator2.e(err);
1370
- } finally {
1371
- _iterator2.f();
1372
- }
1373
- var _iterator3 = _createForOfIteratorHelper(citedRefs),
1374
- _step3;
1375
- try {
1376
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1377
- var _step3$value = _slicedToArray(_step3.value, 2),
1378
- _value = _step3$value[1];
1379
- processedContent = processedContent.replaceAll(_value._placeholder, "<sup><strong>".concat(_value._displayIndex, "</strong></sup>"));
1380
- }
1381
-
1382
- // if we have multiple references, add a comma to ensure we don't concatenate numbers.
1383
- } catch (err) {
1384
- _iterator3.e(err);
1385
- } finally {
1386
- _iterator3.f();
1387
- }
1388
- processedContent = processedContent.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1389
- processedContent += '<br><br>';
1390
- var _iterator4 = _createForOfIteratorHelper(citedRefs),
1391
- _step4;
1392
- try {
1393
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1394
- var _step4$value = _slicedToArray(_step4.value, 2),
1395
- _key = _step4$value[0],
1396
- _value2 = _step4$value[1];
1397
- var label = _value2.text || _key;
1398
- processedContent += _value2.link ? "**".concat(_value2._displayIndex, "**. [").concat(label, "](").concat(_value2.link, ")<br>") : "**".concat(_value2._displayIndex, "**. ").concat(label, "<br>");
1399
- }
1400
- } catch (err) {
1401
- _iterator4.e(err);
1402
- } finally {
1403
- _iterator4.f();
1404
- }
1405
- }
1406
- }
1407
- message.content = processedContent;
1408
- message.htmlContent = parseMarkdownContent(processedContent, message);
1349
+ var _message$rawContent;
1350
+ message.rawContent = (_message$rawContent = message.rawContent) !== null && _message$rawContent !== void 0 ? _message$rawContent : message.content;
1351
+ updateMessagePresentation(message, message.references);
1409
1352
  }
1410
1353
  this.addMessageInternal(message);
1411
1354
  this.hidePlaceholder();
1412
1355
  this.$nextTick(function () {
1413
1356
  // Render any pending charts once the DOM is updated
1414
1357
  renderChartsInMessage(message);
1415
- _this6.scrollToBottom();
1358
+ _this5.scrollToBottom();
1416
1359
  });
1417
1360
  },
1418
1361
  addMessages: function addMessages(messages) {
1419
- var _this7 = this;
1362
+ var _this6 = this;
1420
1363
  for (var i = 0; i < messages.length; i++) {
1421
1364
  this.addMessageInternal(messages[i]);
1422
1365
  }
1423
1366
  this.hidePlaceholder();
1424
1367
  this.$nextTick(function () {
1425
- _this7.scrollToBottom();
1368
+ _this6.scrollToBottom();
1426
1369
  });
1427
1370
  },
1428
1371
  hidePlaceholder: function hidePlaceholder() {
@@ -1499,7 +1442,7 @@ window.openAIChatManager = function () {
1499
1442
  this.prompt = '';
1500
1443
  },
1501
1444
  startRecording: function startRecording() {
1502
- var _this8 = this;
1445
+ var _this7 = this;
1503
1446
  if (this.isRecording || !this.connection) {
1504
1447
  return;
1505
1448
  }
@@ -1511,27 +1454,27 @@ window.openAIChatManager = function () {
1511
1454
  }
1512
1455
  }).then(function (stream) {
1513
1456
  var mimeType = MediaRecorder.isTypeSupported('audio/ogg;codecs=opus') ? 'audio/ogg;codecs=opus' : MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' : 'audio/webm';
1514
- _this8.mediaRecorder = new MediaRecorder(stream, {
1457
+ _this7.mediaRecorder = new MediaRecorder(stream, {
1515
1458
  mimeType: mimeType,
1516
1459
  audioBitsPerSecond: 128000
1517
1460
  });
1518
- _this8.preRecordingPrompt = _this8.prompt;
1519
- _this8._audioInputSent = false;
1461
+ _this7.preRecordingPrompt = _this7.prompt;
1462
+ _this7._audioInputSent = false;
1520
1463
  var subject = new signalR.Subject();
1521
- var profileId = _this8.getProfileId();
1522
- var sessionId = _this8.getSessionId() || '';
1464
+ var profileId = _this7.getProfileId();
1465
+ var sessionId = _this7.getSessionId() || '';
1523
1466
  var pendingChunk = Promise.resolve();
1524
- _this8.mediaRecorder.addEventListener('dataavailable', function (e) {
1467
+ _this7.mediaRecorder.addEventListener('dataavailable', function (e) {
1525
1468
  if (e.data && e.data.size > 0) {
1526
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
1469
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7() {
1527
1470
  var data, uint8Array, binaryString, base64;
1528
- return _regenerator().w(function (_context4) {
1529
- while (1) switch (_context4.n) {
1471
+ return _regenerator().w(function (_context7) {
1472
+ while (1) switch (_context7.n) {
1530
1473
  case 0:
1531
- _context4.n = 1;
1474
+ _context7.n = 1;
1532
1475
  return e.data.arrayBuffer();
1533
1476
  case 1:
1534
- data = _context4.v;
1477
+ data = _context7.v;
1535
1478
  uint8Array = new Uint8Array(data);
1536
1479
  binaryString = uint8Array.reduce(function (str, _byte) {
1537
1480
  return str + String.fromCharCode(_byte);
@@ -1539,13 +1482,13 @@ window.openAIChatManager = function () {
1539
1482
  base64 = btoa(binaryString);
1540
1483
  subject.next(base64);
1541
1484
  case 2:
1542
- return _context4.a(2);
1485
+ return _context7.a(2);
1543
1486
  }
1544
- }, _callee4);
1487
+ }, _callee7);
1545
1488
  })));
1546
1489
  }
1547
1490
  });
1548
- _this8.mediaRecorder.addEventListener('stop', function () {
1491
+ _this7.mediaRecorder.addEventListener('stop', function () {
1549
1492
  stream.getTracks().forEach(function (track) {
1550
1493
  return track.stop();
1551
1494
  });
@@ -1554,10 +1497,10 @@ window.openAIChatManager = function () {
1554
1497
  });
1555
1498
  });
1556
1499
  var language = navigator.language || document.documentElement.lang || 'en-US';
1557
- _this8.connection.send("SendAudioStream", profileId, sessionId, subject, mimeType, language);
1558
- _this8.mediaRecorder.start(250);
1559
- _this8.isRecording = true;
1560
- _this8.updateMicButton();
1500
+ _this7.connection.send("SendAudioStream", profileId, sessionId, subject, mimeType, language);
1501
+ _this7.mediaRecorder.start(250);
1502
+ _this7.isRecording = true;
1503
+ _this7.updateMicButton();
1561
1504
  })["catch"](function (err) {
1562
1505
  console.error('Microphone access denied:', err);
1563
1506
  });
@@ -1590,7 +1533,7 @@ window.openAIChatManager = function () {
1590
1533
  }
1591
1534
  },
1592
1535
  streamMessage: function streamMessage(profileId, trimmedPrompt, sessionProfileId) {
1593
- var _this9 = this;
1536
+ var _this8 = this;
1594
1537
  if (this.stream) {
1595
1538
  this.stream.dispose();
1596
1539
  this.stream = null;
@@ -1607,14 +1550,14 @@ window.openAIChatManager = function () {
1607
1550
  var currentSessionId = this.getSessionId();
1608
1551
  this.stream = this.connection.stream("SendMessage", profileId, trimmedPrompt, currentSessionId, sessionProfileId).subscribe({
1609
1552
  next: function next(chunk) {
1610
- var message = _this9.messages[messageIndex];
1553
+ var message = _this8.messages[messageIndex];
1611
1554
  if (!message) {
1612
1555
  if (chunk.sessionId && !currentSessionId) {
1613
- _this9.initializeSession(chunk.sessionId);
1556
+ _this8.initializeSession(chunk.sessionId);
1614
1557
  }
1615
- _this9.hideTypingIndicator();
1558
+ _this8.hideTypingIndicator();
1616
1559
  // Re-assign the index after hiding the typing indicator.
1617
- messageIndex = _this9.messages.length;
1560
+ messageIndex = _this8.messages.length;
1618
1561
  var newMessage = {
1619
1562
  id: chunk.messageId,
1620
1563
  role: "assistant",
@@ -1624,16 +1567,16 @@ window.openAIChatManager = function () {
1624
1567
  isStreaming: true,
1625
1568
  userRating: null
1626
1569
  };
1627
- _this9.messages.push(newMessage);
1570
+ _this8.messages.push(newMessage);
1628
1571
  message = newMessage;
1629
1572
  }
1630
1573
  if (chunk.title && (!message.title || message.title !== chunk.title)) {
1631
1574
  message.title = chunk.title;
1632
1575
  }
1633
1576
  if (chunk.references && _typeof(chunk.references) === "object" && Object.keys(chunk.references).length) {
1634
- for (var _i3 = 0, _Object$entries2 = Object.entries(chunk.references); _i3 < _Object$entries2.length; _i3++) {
1577
+ for (var _i4 = 0, _Object$entries2 = Object.entries(chunk.references); _i4 < _Object$entries2.length; _i4++) {
1635
1578
  var _normalizeReference2;
1636
- var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i3], 2),
1579
+ var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i4], 2),
1637
1580
  key = _Object$entries2$_i[0],
1638
1581
  value = _Object$entries2$_i[1];
1639
1582
  references[key] = (_normalizeReference2 = normalizeReference(value)) !== null && _normalizeReference2 !== void 0 ? _normalizeReference2 : {};
@@ -1648,62 +1591,52 @@ window.openAIChatManager = function () {
1648
1591
  if (chunk.responseId) {
1649
1592
  lastResponseId = chunk.responseId;
1650
1593
  }
1651
- var processedContent = chunk.content;
1652
- for (var _i4 = 0, _Object$entries3 = Object.entries(references); _i4 < _Object$entries3.length; _i4++) {
1653
- var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i4], 2),
1654
- _key2 = _Object$entries3$_i[0],
1655
- _value3 = _Object$entries3$_i[1];
1656
- processedContent = processedContent.replaceAll(_key2, "<sup><strong>".concat(_value3.index, "</strong></sup>"));
1657
- }
1658
-
1659
- // Append processed content to the message.
1660
- // if we have multiple references, add a comma to ensure we don't concatenate numbers.
1661
- content += processedContent.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1594
+ content += chunk.content;
1662
1595
  }
1663
1596
 
1664
1597
  // Update the existing message
1665
- message.content = content;
1666
- message.htmlContent = parseMarkdownContent(content, message);
1667
- _this9.messages[messageIndex] = message;
1668
- _this9.$nextTick(function () {
1598
+ message.rawContent = content;
1599
+ updateMessagePresentation(message, references);
1600
+ _this8.messages[messageIndex] = message;
1601
+ _this8.$nextTick(function () {
1669
1602
  renderChartsInMessage(message);
1670
- _this9.scrollToBottom();
1603
+ _this8.scrollToBottom();
1671
1604
  });
1672
1605
  },
1673
1606
  complete: function complete() {
1674
- var _this9$stream;
1675
- _this9.processReferences(references, messageIndex);
1676
- _this9.streamingFinished();
1677
- var msg = _this9.messages[messageIndex];
1607
+ var _this8$stream;
1608
+ _this8.processReferences(references, messageIndex);
1609
+ _this8.streamingFinished();
1610
+ var msg = _this8.messages[messageIndex];
1678
1611
  if (msg) {
1679
1612
  msg.isStreaming = false;
1680
1613
  }
1681
1614
  if (!msg || !msg.content) {
1682
1615
  // No content received at all.
1683
- _this9.hideTypingIndicator();
1616
+ _this8.hideTypingIndicator();
1684
1617
  }
1685
1618
 
1686
1619
  // Trigger text-to-speech only in conversation mode.
1687
- if (_this9.isConversationMode && _this9.textToSpeechEnabled && msg && msg.content) {
1688
- _this9.synthesizeSpeech(msg.content);
1620
+ if (_this8.isConversationMode && _this8.textToSpeechEnabled && msg && msg.content) {
1621
+ _this8.synthesizeSpeech(msg.content);
1689
1622
  }
1690
- (_this9$stream = _this9.stream) === null || _this9$stream === void 0 || _this9$stream.dispose();
1691
- _this9.stream = null;
1623
+ (_this8$stream = _this8.stream) === null || _this8$stream === void 0 || _this8$stream.dispose();
1624
+ _this8.stream = null;
1692
1625
  },
1693
1626
  error: function error(err) {
1694
- var _this9$stream2;
1695
- _this9.processReferences(references, messageIndex);
1696
- _this9.streamingFinished();
1697
- var msg = _this9.messages[messageIndex];
1627
+ var _this8$stream2;
1628
+ _this8.processReferences(references, messageIndex);
1629
+ _this8.streamingFinished();
1630
+ var msg = _this8.messages[messageIndex];
1698
1631
  if (msg) {
1699
1632
  msg.isStreaming = false;
1700
1633
  }
1701
- _this9.hideTypingIndicator();
1702
- if (!_this9.isNavigatingAway) {
1703
- _this9.addMessage(_this9.getServiceDownMessage());
1634
+ _this8.hideTypingIndicator();
1635
+ if (!_this8.isNavigatingAway) {
1636
+ _this8.addMessage(_this8.getServiceDownMessage());
1704
1637
  }
1705
- (_this9$stream2 = _this9.stream) === null || _this9$stream2 === void 0 || _this9$stream2.dispose();
1706
- _this9.stream = null;
1638
+ (_this8$stream2 = _this8.stream) === null || _this8$stream2 === void 0 || _this8$stream2.dispose();
1639
+ _this8.stream = null;
1707
1640
  console.error("Stream error:", err);
1708
1641
  }
1709
1642
  });
@@ -1717,92 +1650,17 @@ window.openAIChatManager = function () {
1717
1650
  return newMessage;
1718
1651
  },
1719
1652
  processReferences: function processReferences(references, messageIndex) {
1720
- var _this0 = this;
1653
+ var _this9 = this;
1721
1654
  references = normalizeReferences(references);
1722
1655
  if (Object.keys(references).length) {
1656
+ var _ref15, _message$rawContent2;
1723
1657
  var message = this.messages[messageIndex];
1724
- var content = message.content || '';
1725
-
1726
- // Only include references that were actually cited in the response.
1727
- // Check both raw [doc:N] markers and already-rendered <sup> tags from streaming.
1728
- var citedRefs = Object.entries(references).filter(function (_ref1) {
1729
- var _ref10 = _slicedToArray(_ref1, 2),
1730
- key = _ref10[0],
1731
- value = _ref10[1];
1732
- return content.includes(key) || content.includes("<sup><strong>".concat(value.index, "</strong></sup>"));
1733
- });
1734
- if (!citedRefs.length) {
1735
- return;
1736
- }
1737
-
1738
- // Sort by original index so display indices follow a natural order.
1739
- citedRefs.sort(function (_ref11, _ref12) {
1740
- var _ref13 = _slicedToArray(_ref11, 2),
1741
- a = _ref13[1];
1742
- var _ref14 = _slicedToArray(_ref12, 2),
1743
- b = _ref14[1];
1744
- return a.index - b.index;
1745
- });
1746
-
1747
- // Phase 1: Replace all markers with unique placeholders to avoid collisions during remapping.
1748
- var processed = content.trim();
1749
- var displayIndex = 1;
1750
- var _iterator5 = _createForOfIteratorHelper(citedRefs),
1751
- _step5;
1752
- try {
1753
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1754
- var _step5$value = _slicedToArray(_step5.value, 2),
1755
- key = _step5$value[0],
1756
- value = _step5$value[1];
1757
- var placeholder = "__CITE_".concat(value.index, "__");
1758
- processed = processed.replaceAll(key, placeholder);
1759
- processed = processed.replaceAll("<sup><strong>".concat(value.index, "</strong></sup>"), placeholder);
1760
- value._displayIndex = displayIndex++;
1761
- value._placeholder = placeholder;
1762
- }
1763
-
1764
- // Phase 2: Replace placeholders with sequential display indices.
1765
- } catch (err) {
1766
- _iterator5.e(err);
1767
- } finally {
1768
- _iterator5.f();
1769
- }
1770
- var _iterator6 = _createForOfIteratorHelper(citedRefs),
1771
- _step6;
1772
- try {
1773
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1774
- var _step6$value = _slicedToArray(_step6.value, 2),
1775
- _value4 = _step6$value[1];
1776
- processed = processed.replaceAll(_value4._placeholder, "<sup><strong>".concat(_value4._displayIndex, "</strong></sup>"));
1777
- }
1778
- } catch (err) {
1779
- _iterator6.e(err);
1780
- } finally {
1781
- _iterator6.f();
1782
- }
1783
- processed = processed.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1784
- processed += '<br><br>';
1785
- var _iterator7 = _createForOfIteratorHelper(citedRefs),
1786
- _step7;
1787
- try {
1788
- for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
1789
- var _step7$value = _slicedToArray(_step7.value, 2),
1790
- _key3 = _step7$value[0],
1791
- _value5 = _step7$value[1];
1792
- var label = _value5.text || _key3;
1793
- processed += _value5.link ? "**".concat(_value5._displayIndex, "**. [").concat(label, "](").concat(_value5.link, ")<br>") : "**".concat(_value5._displayIndex, "**. ").concat(label, "<br>");
1794
- }
1795
- } catch (err) {
1796
- _iterator7.e(err);
1797
- } finally {
1798
- _iterator7.f();
1799
- }
1800
- message.content = processed;
1801
- message.htmlContent = parseMarkdownContent(processed, message);
1658
+ message.rawContent = (_ref15 = (_message$rawContent2 = message.rawContent) !== null && _message$rawContent2 !== void 0 ? _message$rawContent2 : message.content) !== null && _ref15 !== void 0 ? _ref15 : '';
1659
+ updateMessagePresentation(message, references);
1802
1660
  this.messages[messageIndex] = message;
1803
1661
  this.$nextTick(function () {
1804
1662
  renderChartsInMessage(message);
1805
- _this0.scrollToBottom();
1663
+ _this9.scrollToBottom();
1806
1664
  });
1807
1665
  }
1808
1666
  },
@@ -1852,6 +1710,19 @@ window.openAIChatManager = function () {
1852
1710
  }
1853
1711
  this.stopAudio(false);
1854
1712
  },
1713
+ updateTtsPlaybackButtons: function updateTtsPlaybackButtons() {
1714
+ var _this0 = this;
1715
+ if (!this.chatContainer) {
1716
+ return;
1717
+ }
1718
+ var buttons = this.chatContainer.querySelectorAll('[data-tts-message-index]');
1719
+ buttons.forEach(function (button) {
1720
+ var buttonIndex = Number(button.getAttribute('data-tts-message-index'));
1721
+ var isPlaying = buttonIndex === _this0.ttsPlayingMessageIndex;
1722
+ button.classList.toggle('tts-playing', isPlaying);
1723
+ button.setAttribute('title', isPlaying ? 'Pause audio' : 'Read aloud');
1724
+ });
1725
+ },
1855
1726
  synthesizeSpeech: function synthesizeSpeech(text, cacheIndex) {
1856
1727
  var _this1 = this;
1857
1728
  if (!this.textToSpeechEnabled || !text || !this.connection) {
@@ -1865,9 +1736,13 @@ window.openAIChatManager = function () {
1865
1736
  _this1.isPlayingAudio = false;
1866
1737
  _this1.ttsPlayingMessageIndex = -1;
1867
1738
  _this1._ttsCacheIndex = -1;
1739
+ _this1.$nextTick(function () {
1740
+ return _this1.updateTtsPlaybackButtons();
1741
+ });
1868
1742
  });
1869
1743
  },
1870
1744
  toggleMessageTts: function toggleMessageTts(message, index) {
1745
+ var _this10 = this;
1871
1746
  if (this.ttsPlayingMessageIndex === index) {
1872
1747
  this.stopAudio();
1873
1748
  return;
@@ -1879,6 +1754,9 @@ window.openAIChatManager = function () {
1879
1754
  }
1880
1755
  }));
1881
1756
  this.ttsPlayingMessageIndex = index;
1757
+ this.$nextTick(function () {
1758
+ return _this10.updateTtsPlaybackButtons();
1759
+ });
1882
1760
  if (this.ttsAudioCache[index]) {
1883
1761
  this.playAudioBlob(this.ttsAudioCache[index]);
1884
1762
  return;
@@ -1886,10 +1764,14 @@ window.openAIChatManager = function () {
1886
1764
  this.synthesizeSpeech(message.content, index);
1887
1765
  },
1888
1766
  playCollectedAudio: function playCollectedAudio() {
1767
+ var _this11 = this;
1889
1768
  if (this.audioChunks.length === 0) {
1890
1769
  if (!this.currentAudioElement && this.audioPlayQueue.length === 0) {
1891
1770
  this.isPlayingAudio = false;
1892
1771
  this.ttsPlayingMessageIndex = -1;
1772
+ this.$nextTick(function () {
1773
+ return _this11.updateTtsPlaybackButtons();
1774
+ });
1893
1775
  }
1894
1776
  return;
1895
1777
  }
@@ -1898,18 +1780,18 @@ window.openAIChatManager = function () {
1898
1780
  }, 0);
1899
1781
  var combined = new Uint8Array(totalLength);
1900
1782
  var offset = 0;
1901
- var _iterator8 = _createForOfIteratorHelper(this.audioChunks),
1902
- _step8;
1783
+ var _iterator5 = _createForOfIteratorHelper(this.audioChunks),
1784
+ _step5;
1903
1785
  try {
1904
- for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
1905
- var chunk = _step8.value;
1786
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1787
+ var chunk = _step5.value;
1906
1788
  combined.set(chunk, offset);
1907
1789
  offset += chunk.length;
1908
1790
  }
1909
1791
  } catch (err) {
1910
- _iterator8.e(err);
1792
+ _iterator5.e(err);
1911
1793
  } finally {
1912
- _iterator8.f();
1794
+ _iterator5.f();
1913
1795
  }
1914
1796
  this.audioChunks = [];
1915
1797
  var blob = new Blob([combined], {
@@ -1928,45 +1810,53 @@ window.openAIChatManager = function () {
1928
1810
  this.playAudioBlob(blob);
1929
1811
  },
1930
1812
  playAudioBlob: function playAudioBlob(blob) {
1931
- var _this10 = this;
1813
+ var _this12 = this;
1932
1814
  var url = URL.createObjectURL(blob);
1933
1815
  var audio = new Audio(url);
1934
1816
  this.currentAudioUrl = url;
1935
1817
  this.currentAudioElement = audio;
1936
1818
  this.isPlayingAudio = true;
1937
1819
  audio.addEventListener('ended', function () {
1938
- _this10.currentAudioElement = null;
1939
- _this10.currentAudioUrl = null;
1820
+ _this12.currentAudioElement = null;
1821
+ _this12.currentAudioUrl = null;
1940
1822
  URL.revokeObjectURL(url);
1941
- _this10.playNextInQueue();
1823
+ _this12.playNextInQueue();
1942
1824
  });
1943
1825
  audio.addEventListener('error', function () {
1944
- _this10.currentAudioElement = null;
1945
- _this10.currentAudioUrl = null;
1826
+ _this12.currentAudioElement = null;
1827
+ _this12.currentAudioUrl = null;
1946
1828
  URL.revokeObjectURL(url);
1947
- _this10.playNextInQueue();
1829
+ _this12.playNextInQueue();
1948
1830
  });
1949
1831
  audio.play()["catch"](function (err) {
1950
1832
  console.error("Audio playback error:", err);
1951
- _this10.currentAudioElement = null;
1952
- _this10.currentAudioUrl = null;
1833
+ _this12.currentAudioElement = null;
1834
+ _this12.currentAudioUrl = null;
1953
1835
  URL.revokeObjectURL(url);
1954
- _this10.audioPlayQueue = [];
1955
- _this10.isPlayingAudio = false;
1956
- _this10.ttsPlayingMessageIndex = -1;
1836
+ _this12.audioPlayQueue = [];
1837
+ _this12.isPlayingAudio = false;
1838
+ _this12.ttsPlayingMessageIndex = -1;
1839
+ _this12.$nextTick(function () {
1840
+ return _this12.updateTtsPlaybackButtons();
1841
+ });
1957
1842
  });
1958
1843
  },
1959
1844
  playNextInQueue: function playNextInQueue() {
1845
+ var _this13 = this;
1960
1846
  if (this.audioPlayQueue.length > 0) {
1961
1847
  var nextBlob = this.audioPlayQueue.shift();
1962
1848
  this.playAudioBlob(nextBlob);
1963
1849
  } else {
1964
1850
  this.isPlayingAudio = false;
1965
1851
  this.ttsPlayingMessageIndex = -1;
1852
+ this.$nextTick(function () {
1853
+ return _this13.updateTtsPlaybackButtons();
1854
+ });
1966
1855
  this.conversationModeOnAudioEnded();
1967
1856
  }
1968
1857
  },
1969
1858
  stopAudio: function stopAudio() {
1859
+ var _this14 = this;
1970
1860
  if (this.currentAudioElement) {
1971
1861
  this.currentAudioElement.pause();
1972
1862
  this.currentAudioElement.currentTime = 0;
@@ -1980,6 +1870,9 @@ window.openAIChatManager = function () {
1980
1870
  this.audioPlayQueue = [];
1981
1871
  this.isPlayingAudio = false;
1982
1872
  this.ttsPlayingMessageIndex = -1;
1873
+ this.$nextTick(function () {
1874
+ return _this14.updateTtsPlaybackButtons();
1875
+ });
1983
1876
  },
1984
1877
  toggleConversationMode: function toggleConversationMode() {
1985
1878
  if (this.isConversationMode) {
@@ -1989,7 +1882,7 @@ window.openAIChatManager = function () {
1989
1882
  }
1990
1883
  },
1991
1884
  startConversationMode: function startConversationMode() {
1992
- var _this11 = this;
1885
+ var _this15 = this;
1993
1886
  if (!this.conversationModeEnabled || this.isConversationMode || !this.connection) {
1994
1887
  return;
1995
1888
  }
@@ -2009,12 +1902,12 @@ window.openAIChatManager = function () {
2009
1902
  }
2010
1903
  }).then(function (stream) {
2011
1904
  var mimeType = MediaRecorder.isTypeSupported('audio/ogg;codecs=opus') ? 'audio/ogg;codecs=opus' : MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' : 'audio/webm';
2012
- _this11.mediaRecorder = new MediaRecorder(stream, {
1905
+ _this15.mediaRecorder = new MediaRecorder(stream, {
2013
1906
  mimeType: mimeType,
2014
1907
  audioBitsPerSecond: 128000
2015
1908
  });
2016
- _this11._conversationSubject = new signalR.Subject();
2017
- _this11._conversationStream = stream;
1909
+ _this15._conversationSubject = new signalR.Subject();
1910
+ _this15._conversationStream = stream;
2018
1911
 
2019
1912
  // Create an AnalyserNode for volume-based interrupt detection.
2020
1913
  // During TTS playback, detect when the user speaks above
@@ -2023,20 +1916,20 @@ window.openAIChatManager = function () {
2023
1916
  // speaker echo so the STT stream has no gaps.
2024
1917
  var AudioCtx = window.AudioContext || window.webkitAudioContext;
2025
1918
  if (AudioCtx) {
2026
- _this11._conversationAudioCtx = new AudioCtx();
2027
- _this11._conversationAnalyser = _this11._conversationAudioCtx.createAnalyser();
2028
- _this11._conversationAnalyser.fftSize = 256;
2029
- var micSource = _this11._conversationAudioCtx.createMediaStreamSource(stream);
2030
- micSource.connect(_this11._conversationAnalyser);
1919
+ _this15._conversationAudioCtx = new AudioCtx();
1920
+ _this15._conversationAnalyser = _this15._conversationAudioCtx.createAnalyser();
1921
+ _this15._conversationAnalyser.fftSize = 256;
1922
+ var micSource = _this15._conversationAudioCtx.createMediaStreamSource(stream);
1923
+ micSource.connect(_this15._conversationAnalyser);
2031
1924
  }
2032
1925
  var pendingChunk = Promise.resolve();
2033
- var analyser = _this11._conversationAnalyser;
1926
+ var analyser = _this15._conversationAnalyser;
2034
1927
  var interruptVolumeThreshold = 30;
2035
- _this11.mediaRecorder.addEventListener('dataavailable', function (e) {
1928
+ _this15.mediaRecorder.addEventListener('dataavailable', function (e) {
2036
1929
  if (e.data && e.data.size > 0) {
2037
1930
  // During TTS playback, check mic volume to detect
2038
1931
  // user interruption (speaking above threshold).
2039
- if (_this11.isPlayingAudio && analyser) {
1932
+ if (_this15.isPlayingAudio && analyser) {
2040
1933
  var freqData = new Uint8Array(analyser.frequencyBinCount);
2041
1934
  analyser.getByteFrequencyData(freqData);
2042
1935
  var sum = 0;
@@ -2046,61 +1939,61 @@ window.openAIChatManager = function () {
2046
1939
  var avg = sum / freqData.length;
2047
1940
  if (avg >= interruptVolumeThreshold) {
2048
1941
  // User is speaking — interrupt TTS playback.
2049
- _this11.stopAudio();
1942
+ _this15.stopAudio();
2050
1943
  }
2051
1944
  }
2052
1945
 
2053
1946
  // Always send audio to STT — browser echo cancellation
2054
1947
  // handles speaker echo; continuous audio avoids gaps
2055
1948
  // that increase recognition latency.
2056
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
1949
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
2057
1950
  var data, uint8Array, binaryString, base64;
2058
- return _regenerator().w(function (_context5) {
2059
- while (1) switch (_context5.n) {
1951
+ return _regenerator().w(function (_context8) {
1952
+ while (1) switch (_context8.n) {
2060
1953
  case 0:
2061
- _context5.n = 1;
1954
+ _context8.n = 1;
2062
1955
  return e.data.arrayBuffer();
2063
1956
  case 1:
2064
- data = _context5.v;
1957
+ data = _context8.v;
2065
1958
  uint8Array = new Uint8Array(data);
2066
1959
  binaryString = uint8Array.reduce(function (str, _byte2) {
2067
1960
  return str + String.fromCharCode(_byte2);
2068
1961
  }, '');
2069
1962
  base64 = btoa(binaryString);
2070
1963
  try {
2071
- _this11._conversationSubject.next(base64);
1964
+ _this15._conversationSubject.next(base64);
2072
1965
  } catch (err) {
2073
1966
  // Subject may have been completed already.
2074
1967
  }
2075
1968
  case 2:
2076
- return _context5.a(2);
1969
+ return _context8.a(2);
2077
1970
  }
2078
- }, _callee5);
1971
+ }, _callee8);
2079
1972
  })));
2080
1973
  }
2081
1974
  });
2082
- _this11.mediaRecorder.addEventListener('stop', function () {
1975
+ _this15.mediaRecorder.addEventListener('stop', function () {
2083
1976
  stream.getTracks().forEach(function (track) {
2084
1977
  return track.stop();
2085
1978
  });
2086
1979
  pendingChunk.then(function () {
2087
1980
  try {
2088
- _this11._conversationSubject.complete();
1981
+ _this15._conversationSubject.complete();
2089
1982
  } catch (err) {
2090
1983
  // Already completed.
2091
1984
  }
2092
1985
  });
2093
1986
  });
2094
- var profileId = _this11.getProfileId();
2095
- var sessionId = _this11.getSessionId() || '';
1987
+ var profileId = _this15.getProfileId();
1988
+ var sessionId = _this15.getSessionId() || '';
2096
1989
  var language = navigator.language || document.documentElement.lang || 'en-US';
2097
- _this11.connection.send("StartConversation", profileId, sessionId, _this11._conversationSubject, mimeType, language);
2098
- _this11.mediaRecorder.start(250);
2099
- _this11.isRecording = true;
1990
+ _this15.connection.send("StartConversation", profileId, sessionId, _this15._conversationSubject, mimeType, language);
1991
+ _this15.mediaRecorder.start(250);
1992
+ _this15.isRecording = true;
2100
1993
  })["catch"](function (err) {
2101
1994
  console.error('Microphone access denied:', err);
2102
- _this11.isConversationMode = false;
2103
- _this11.updateConversationButton();
1995
+ _this15.isConversationMode = false;
1996
+ _this15.updateConversationButton();
2104
1997
  });
2105
1998
  },
2106
1999
  stopConversationMode: function stopConversationMode() {
@@ -2227,7 +2120,7 @@ window.openAIChatManager = function () {
2227
2120
  return removedCount;
2228
2121
  },
2229
2122
  receiveNotification: function receiveNotification(notification) {
2230
- var _this12 = this;
2123
+ var _this16 = this;
2231
2124
  if (!notification || !notification.type) {
2232
2125
  return;
2233
2126
  }
@@ -2242,7 +2135,7 @@ window.openAIChatManager = function () {
2242
2135
  }
2243
2136
  this.scheduleNotificationDismiss(notification);
2244
2137
  this.$nextTick(function () {
2245
- _this12.scrollToBottom();
2138
+ _this16.scrollToBottom();
2246
2139
  });
2247
2140
  },
2248
2141
  updateNotification: function updateNotification(notification) {
@@ -2259,12 +2152,12 @@ window.openAIChatManager = function () {
2259
2152
  }
2260
2153
  },
2261
2154
  scheduleNotificationDismiss: function scheduleNotificationDismiss(notification) {
2262
- var _this13 = this;
2155
+ var _this17 = this;
2263
2156
  if (!notification || !notification.type || !notification.autoDismissMs || notification.autoDismissMs <= 0) {
2264
2157
  return;
2265
2158
  }
2266
2159
  this.notificationDismissTimers[notification.type] = setTimeout(function () {
2267
- _this13.removeNotification(notification.type);
2160
+ _this17.removeNotification(notification.type);
2268
2161
  }, notification.autoDismissMs);
2269
2162
  },
2270
2163
  clearNotificationDismiss: function clearNotificationDismiss(notificationType) {
@@ -2294,31 +2187,32 @@ window.openAIChatManager = function () {
2294
2187
  });
2295
2188
  },
2296
2189
  scrollToBottom: function scrollToBottom() {
2297
- var _this14 = this;
2190
+ var _this18 = this;
2298
2191
  if (!this.autoScroll) {
2299
2192
  return;
2300
2193
  }
2301
2194
  setTimeout(function () {
2302
- _this14.chatContainer.scrollTop = _this14.chatContainer.scrollHeight - _this14.chatContainer.clientHeight;
2195
+ _this18.chatContainer.scrollTop = _this18.chatContainer.scrollHeight - _this18.chatContainer.clientHeight;
2303
2196
  }, 50);
2304
2197
  },
2305
2198
  handleUserInput: function handleUserInput(event) {
2306
2199
  this.prompt = event.target.value;
2307
2200
  },
2308
2201
  getProfileId: function getProfileId() {
2309
- return this.inputElement.getAttribute('data-profile-id');
2202
+ return this.inputElement ? this.inputElement.getAttribute('data-profile-id') : null;
2310
2203
  },
2311
2204
  setSessionId: function setSessionId(sessionId) {
2205
+ if (!this.inputElement) {
2206
+ return;
2207
+ }
2312
2208
  this.inputElement.setAttribute('data-session-id', sessionId || '');
2313
2209
  },
2314
2210
  resetSession: function resetSession() {
2315
2211
  this.stopRecording();
2212
+ this.rejectPendingSessionRequest('Session was reset.');
2316
2213
  this.setSessionId('');
2317
2214
  this.isSessionStarted = false;
2318
2215
  this.sessionRating = null;
2319
- if (this.widgetIsInitialized) {
2320
- localStorage.removeItem(this.chatWidgetStateSession);
2321
- }
2322
2216
  this.messages = [];
2323
2217
  this.documents = [];
2324
2218
  if (!config.autoCreateSession) {
@@ -2327,6 +2221,9 @@ window.openAIChatManager = function () {
2327
2221
  if (config.autoCreateSession) {
2328
2222
  this.startNewSession();
2329
2223
  }
2224
+ if (widgetBehavior && typeof widgetBehavior.onSessionReset === 'function') {
2225
+ widgetBehavior.onSessionReset(this, config);
2226
+ }
2330
2227
  },
2331
2228
  startNewSession: function startNewSession() {
2332
2229
  if (!this.applyOrchestratorAvailability()) {
@@ -2336,16 +2233,94 @@ window.openAIChatManager = function () {
2336
2233
  if (!profileId || !this.connection) {
2337
2234
  return;
2338
2235
  }
2339
- this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2236
+ this.requestNewSession(profileId)["catch"](function (err) {
2340
2237
  return console.error(err);
2341
2238
  });
2342
2239
  },
2240
+ ensureSessionForDocuments: function ensureSessionForDocuments(profileId) {
2241
+ var _this19 = this;
2242
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
2243
+ var sessionId;
2244
+ return _regenerator().w(function (_context9) {
2245
+ while (1) switch (_context9.n) {
2246
+ case 0:
2247
+ sessionId = _this19.getSessionId();
2248
+ if (!sessionId) {
2249
+ _context9.n = 1;
2250
+ break;
2251
+ }
2252
+ return _context9.a(2, sessionId);
2253
+ case 1:
2254
+ if (!(!profileId || !_this19.connection)) {
2255
+ _context9.n = 2;
2256
+ break;
2257
+ }
2258
+ return _context9.a(2, null);
2259
+ case 2:
2260
+ _context9.n = 3;
2261
+ return _this19.requestNewSession(profileId);
2262
+ case 3:
2263
+ return _context9.a(2, _context9.v);
2264
+ }
2265
+ }, _callee9);
2266
+ }))();
2267
+ },
2268
+ requestNewSession: function requestNewSession(profileId) {
2269
+ var _this20 = this;
2270
+ if (this.pendingSessionPromise) {
2271
+ return this.pendingSessionPromise;
2272
+ }
2273
+ if (!profileId || !this.connection) {
2274
+ return Promise.resolve(null);
2275
+ }
2276
+ this.pendingSessionPromise = new Promise(function (resolve, reject) {
2277
+ _this20.pendingSessionResolver = resolve;
2278
+ _this20.pendingSessionRejector = reject;
2279
+ _this20.pendingSessionTimeoutId = window.setTimeout(function () {
2280
+ _this20.rejectPendingSessionRequest('Timed out while creating a chat session.');
2281
+ }, 15000);
2282
+ });
2283
+ this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2284
+ _this20.rejectPendingSessionRequest(err);
2285
+ });
2286
+ return this.pendingSessionPromise;
2287
+ },
2288
+ resolvePendingSessionRequest: function resolvePendingSessionRequest(sessionId) {
2289
+ if (this.pendingSessionResolver) {
2290
+ this.pendingSessionResolver(sessionId);
2291
+ }
2292
+ this.clearPendingSessionRequest();
2293
+ },
2294
+ rejectPendingSessionRequest: function rejectPendingSessionRequest(error) {
2295
+ if (this.pendingSessionRejector) {
2296
+ this.pendingSessionRejector(error);
2297
+ }
2298
+ this.clearPendingSessionRequest();
2299
+ },
2300
+ clearPendingSessionRequest: function clearPendingSessionRequest() {
2301
+ if (this.pendingSessionTimeoutId) {
2302
+ window.clearTimeout(this.pendingSessionTimeoutId);
2303
+ }
2304
+ this.pendingSessionPromise = null;
2305
+ this.pendingSessionResolver = null;
2306
+ this.pendingSessionRejector = null;
2307
+ this.pendingSessionTimeoutId = null;
2308
+ },
2343
2309
  initializeApp: function initializeApp() {
2344
- var _this15 = this;
2310
+ var _this21 = this;
2345
2311
  this.inputElement = document.querySelector(config.inputElementSelector);
2346
2312
  this.buttonElement = document.querySelector(config.sendButtonElementSelector);
2347
2313
  this.chatContainer = document.querySelector(config.chatContainerElementSelector);
2348
2314
  this.placeholder = document.querySelector(config.placeholderElementSelector);
2315
+ if (!this.inputElement || !this.buttonElement || !this.chatContainer || !this.placeholder) {
2316
+ console.error('AI chat app could not initialize because one or more required elements were not found.', {
2317
+ inputElementSelector: config.inputElementSelector,
2318
+ sendButtonElementSelector: config.sendButtonElementSelector,
2319
+ chatContainerElementSelector: config.chatContainerElementSelector,
2320
+ placeholderElementSelector: config.placeholderElementSelector
2321
+ });
2322
+ return false;
2323
+ }
2349
2324
  this.applyOrchestratorAvailability();
2350
2325
  var sessionId = this.getSessionId();
2351
2326
  if (!hasWidgetConfig && sessionId) {
@@ -2370,7 +2345,7 @@ window.openAIChatManager = function () {
2370
2345
  fileInput.accept = config.allowedExtensions;
2371
2346
  }
2372
2347
  fileInput.addEventListener('change', function (e) {
2373
- return _this15.handleFileInputChange(e);
2348
+ return _this21.handleFileInputChange(e);
2374
2349
  });
2375
2350
  this.documentBar.parentElement.appendChild(fileInput);
2376
2351
 
@@ -2378,13 +2353,13 @@ window.openAIChatManager = function () {
2378
2353
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
2379
2354
  if (inputArea) {
2380
2355
  inputArea.addEventListener('dragover', function (e) {
2381
- return _this15.handleDragOver(e);
2356
+ return _this21.handleDragOver(e);
2382
2357
  });
2383
2358
  inputArea.addEventListener('dragleave', function (e) {
2384
- return _this15.handleDragLeave(e);
2359
+ return _this21.handleDragLeave(e);
2385
2360
  });
2386
2361
  inputArea.addEventListener('drop', function (e) {
2387
- return _this15.handleDrop(e);
2362
+ return _this21.handleDrop(e);
2388
2363
  });
2389
2364
  }
2390
2365
  }
@@ -2392,55 +2367,55 @@ window.openAIChatManager = function () {
2392
2367
 
2393
2368
  // Pause auto-scroll when the user manually scrolls up during streaming.
2394
2369
  this.chatContainer.addEventListener('scroll', function () {
2395
- if (!_this15.stream) {
2370
+ if (!_this21.stream) {
2396
2371
  return;
2397
2372
  }
2398
2373
  var threshold = 30;
2399
- var atBottom = _this15.chatContainer.scrollHeight - _this15.chatContainer.clientHeight - _this15.chatContainer.scrollTop <= threshold;
2400
- _this15.autoScroll = atBottom;
2374
+ var atBottom = _this21.chatContainer.scrollHeight - _this21.chatContainer.clientHeight - _this21.chatContainer.scrollTop <= threshold;
2375
+ _this21.autoScroll = atBottom;
2401
2376
  });
2402
2377
  this.inputElement.addEventListener('keydown', function (event) {
2403
- if (_this15.stream != null) {
2378
+ if (_this21.stream != null) {
2404
2379
  return;
2405
2380
  }
2406
2381
  if (event.key === "Enter" && !event.shiftKey) {
2407
2382
  event.preventDefault();
2408
- _this15.buttonElement.click();
2383
+ _this21.buttonElement.click();
2409
2384
  }
2410
2385
  });
2411
2386
  this.inputElement.addEventListener('input', function (e) {
2412
- _this15.handleUserInput(e);
2387
+ _this21.handleUserInput(e);
2413
2388
  if (e.target.value.trim()) {
2414
- _this15.buttonElement.removeAttribute('disabled');
2389
+ _this21.buttonElement.removeAttribute('disabled');
2415
2390
  } else {
2416
- _this15.buttonElement.setAttribute('disabled', true);
2391
+ _this21.buttonElement.setAttribute('disabled', true);
2417
2392
  }
2418
2393
  });
2419
2394
  this.buttonElement.addEventListener('click', function () {
2420
- if (_this15.stream != null) {
2421
- _this15.stream.dispose();
2422
- _this15.stream = null;
2423
- _this15.streamingFinished();
2424
- _this15.hideTypingIndicator();
2395
+ if (_this21.stream != null) {
2396
+ _this21.stream.dispose();
2397
+ _this21.stream = null;
2398
+ _this21.streamingFinished();
2399
+ _this21.hideTypingIndicator();
2425
2400
 
2426
2401
  // Clean up: remove empty assistant message or stop streaming animation.
2427
- if (_this15.messages.length > 0) {
2428
- var lastMsg = _this15.messages[_this15.messages.length - 1];
2402
+ if (_this21.messages.length > 0) {
2403
+ var lastMsg = _this21.messages[_this21.messages.length - 1];
2429
2404
  if (lastMsg.role === 'assistant' && !lastMsg.content) {
2430
- _this15.messages.pop();
2405
+ _this21.messages.pop();
2431
2406
  } else if (lastMsg.isStreaming) {
2432
2407
  lastMsg.isStreaming = false;
2433
2408
  }
2434
2409
  }
2435
2410
  return;
2436
2411
  }
2437
- _this15.sendMessage();
2412
+ _this21.sendMessage();
2438
2413
  });
2439
2414
  var promptGenerators = document.getElementsByClassName('profile-generated-prompt');
2440
2415
  for (var i = 0; i < promptGenerators.length; i++) {
2441
2416
  promptGenerators[i].addEventListener('click', function (e) {
2442
2417
  e.preventDefault();
2443
- _this15.generatePrompt(e.target);
2418
+ _this21.generatePrompt(e.target);
2444
2419
  });
2445
2420
  }
2446
2421
  var chatSessions = document.getElementsByClassName('chat-session-history-item');
@@ -2452,8 +2427,8 @@ window.openAIChatManager = function () {
2452
2427
  console.error('an element with the class chat-session-history-item with no data-session-id set.');
2453
2428
  return;
2454
2429
  }
2455
- _this15.loadSession(sessionId);
2456
- _this15.showChatScreen();
2430
+ _this21.loadSession(sessionId);
2431
+ _this21.showChatScreen();
2457
2432
  });
2458
2433
  }
2459
2434
  for (var _i5 = 0; _i5 < config.messages.length; _i5++) {
@@ -2462,7 +2437,7 @@ window.openAIChatManager = function () {
2462
2437
 
2463
2438
  // Update feedback icons in the DOM after initial messages have rendered.
2464
2439
  this.$nextTick(function () {
2465
- _this15.refreshAllFeedbackIcons();
2440
+ _this21.refreshAllFeedbackIcons();
2466
2441
  });
2467
2442
 
2468
2443
  // Delegate click for code block copy buttons.
@@ -2494,7 +2469,7 @@ window.openAIChatManager = function () {
2494
2469
  if (this.micButton) {
2495
2470
  this.micButton.style.display = '';
2496
2471
  this.micButton.addEventListener('click', function () {
2497
- _this15.toggleRecording();
2472
+ _this21.toggleRecording();
2498
2473
  });
2499
2474
  }
2500
2475
  }
@@ -2504,10 +2479,11 @@ window.openAIChatManager = function () {
2504
2479
  this.conversationButton = document.querySelector(config.conversationButtonElementSelector);
2505
2480
  if (this.conversationButton) {
2506
2481
  this.conversationButton.addEventListener('click', function () {
2507
- _this15.toggleConversationMode();
2482
+ _this21.toggleConversationMode();
2508
2483
  });
2509
2484
  }
2510
2485
  }
2486
+ return true;
2511
2487
  },
2512
2488
  loadSession: function loadSession(sessionId) {
2513
2489
  this.connection.invoke("LoadSession", sessionId)["catch"](function (err) {
@@ -2522,6 +2498,9 @@ window.openAIChatManager = function () {
2522
2498
  },
2523
2499
  initializeSession: function initializeSession(sessionId, force) {
2524
2500
  if (this.isSessionStarted && !force) {
2501
+ if (sessionId && this.getSessionId() === sessionId) {
2502
+ this.resolvePendingSessionRequest(sessionId);
2503
+ }
2525
2504
  return;
2526
2505
  }
2527
2506
  this.fireEvent(new CustomEvent("initializingSessionOpenAIChat", {
@@ -2531,121 +2510,22 @@ window.openAIChatManager = function () {
2531
2510
  }));
2532
2511
  this.setSessionId(sessionId);
2533
2512
  this.isSessionStarted = true;
2534
- if (this.widgetIsInitialized) {
2535
- localStorage.setItem(this.chatWidgetStateSession, sessionId);
2513
+ this.resolvePendingSessionRequest(sessionId);
2514
+ if (widgetBehavior && typeof widgetBehavior.onSessionInitialized === 'function') {
2515
+ widgetBehavior.onSessionInitialized(this, sessionId, config);
2536
2516
  }
2537
2517
  },
2538
- initializeWidget: function initializeWidget() {
2539
- var _this16 = this;
2540
- if (!config.widget.chatWidgetContainer) {
2541
- console.error('The widget chatWidgetContainer is required.');
2542
- return;
2543
- }
2544
- if (!config.widget.chatWidgetStateName) {
2545
- console.error('The widget chatWidgetStateName is required.');
2546
- return;
2547
- }
2548
- var chatWidgetContainer = document.querySelector(config.widget.chatWidgetContainer);
2549
- if (!chatWidgetContainer) {
2550
- return;
2551
- }
2552
- if (config.widget.chatHistorySection) {
2553
- this.chatHistorySection = document.querySelector(config.widget.chatHistorySection);
2554
- }
2555
- this.chatWidgetStateName = config.widget.chatWidgetStateName;
2556
- this.chatWidgetStateSession = config.widget.chatWidgetStateName + 'Session';
2557
- this.chatWidgetLayoutKey = config.widget.chatWidgetStateName + 'Layout';
2558
- this.widgetContainerElement = chatWidgetContainer;
2559
- this.widgetToggleButtonElement = config.widget.toggleButtonSelector ? document.querySelector(config.widget.toggleButtonSelector) : null;
2560
- this.widgetResetSizeButtonElement = config.widget.resetSizeButtonSelector ? document.querySelector(config.widget.resetSizeButtonSelector) : null;
2561
- this.widgetDefaultWidth = parsePixelValue(config.widget.defaultWidth) || parsePixelValue(window.getComputedStyle(chatWidgetContainer).width) || 380;
2562
- this.widgetDefaultHeight = parsePixelValue(config.widget.defaultHeight) || parsePixelValue(window.getComputedStyle(chatWidgetContainer).height) || 520;
2563
- this.widgetIsInitialized = true;
2564
- if (config.widget.enableResizing) {
2565
- chatWidgetContainer.classList.add('ai-chat-widget-resizable');
2566
- chatWidgetContainer.style.minWidth = (parsePixelValue(config.widget.minWidth) || 320) + 'px';
2567
- chatWidgetContainer.style.minHeight = (parsePixelValue(config.widget.minHeight) || 420) + 'px';
2568
- if (typeof ResizeObserver !== 'undefined') {
2569
- this.widgetResizeObserver = new ResizeObserver(function () {
2570
- _this16.persistWidgetPanelSize();
2571
- _this16.constrainWidgetElementsToViewport();
2572
- _this16.updateWidgetResetSizeButtonVisibility();
2573
- });
2574
- this.widgetResizeObserver.observe(chatWidgetContainer);
2575
- }
2576
- }
2577
- var dragHandleSelector = config.widget.dragHandleSelector || '.ai-chat-widget-header';
2578
- var dragHandle = chatWidgetContainer.querySelector(dragHandleSelector);
2579
- if (config.widget.enableDragging && dragHandle) {
2580
- dragHandle.classList.add('ai-chat-widget-drag-handle');
2581
- chatWidgetContainer.classList.add('ai-chat-widget-draggable');
2582
- this.attachDraggableWidgetElement(chatWidgetContainer, dragHandle, 'panel', false);
2583
- }
2584
- if (config.widget.enableDragging && this.widgetToggleButtonElement) {
2585
- this.widgetToggleButtonElement.classList.add('ai-chat-widget-draggable');
2586
- this.attachDraggableWidgetElement(this.widgetToggleButtonElement, this.widgetToggleButtonElement, 'toggle', true);
2587
- }
2588
- if (this.widgetResetSizeButtonElement) {
2589
- this.widgetResetSizeButtonElement.addEventListener('click', function (event) {
2590
- event.preventDefault();
2591
- _this16.resetWidgetSize();
2592
- });
2593
- }
2594
- this.restoreWidgetLayout();
2595
- if (!this.widgetViewportResizeHandler) {
2596
- this.widgetViewportResizeHandler = function () {
2597
- _this16.constrainWidgetElementsToViewport();
2598
- _this16.updateWidgetResetSizeButtonVisibility();
2599
- };
2600
- window.addEventListener('resize', this.widgetViewportResizeHandler);
2601
- }
2602
-
2603
- // Auto-load the last session so the user always sees previous chat history.
2604
- this.reloadCurrentSession();
2605
- if (config.autoCreateSession && !this.getSessionId()) {
2606
- this.startNewSession();
2607
- }
2608
- if (config.widget.showHistoryButton && this.chatHistorySection) {
2609
- var showHistoryButton = document.querySelector(config.widget.showHistoryButton);
2610
- if (showHistoryButton) {
2611
- showHistoryButton.addEventListener('click', function () {
2612
- _this16.chatHistorySection.classList.toggle('show');
2613
- });
2614
- }
2615
- if (config.widget.closeHistoryButton) {
2616
- var closeHistoryButton = document.querySelector(config.widget.closeHistoryButton);
2617
- if (closeHistoryButton) {
2618
- closeHistoryButton.addEventListener('click', function () {
2619
- _this16.showChatScreen();
2620
- });
2621
- }
2622
- }
2623
- }
2624
- if (config.widget.newChatButton) {
2625
- var newChatButton = document.querySelector(config.widget.newChatButton);
2626
- if (newChatButton) {
2627
- newChatButton.addEventListener('click', function () {
2628
- _this16.resetSession();
2629
- _this16.showChatScreen();
2630
- });
2631
- }
2632
- }
2633
- },
2634
- showChatScreen: function showChatScreen() {
2635
- if (!this.chatHistorySection) {
2636
- return;
2637
- }
2638
- this.chatHistorySection.classList.remove('show');
2639
- },
2640
2518
  getSessionId: function getSessionId() {
2641
- var sessionId = this.inputElement.getAttribute('data-session-id');
2642
- if (!sessionId && this.widgetIsInitialized) {
2643
- sessionId = localStorage.getItem(this.chatWidgetStateSession);
2519
+ var sessionId = this.inputElement ? this.inputElement.getAttribute('data-session-id') : null;
2520
+ if (!sessionId && widgetBehavior && typeof widgetBehavior.resolveSessionId === 'function') {
2521
+ sessionId = widgetBehavior.resolveSessionId(this, config);
2644
2522
  }
2645
2523
  return sessionId;
2646
2524
  },
2647
2525
  copyResponse: function copyResponse(message) {
2648
- navigator.clipboard.writeText(message);
2526
+ var _ref17, _message$copyContent;
2527
+ var text = message && _typeof(message) === 'object' ? (_ref17 = (_message$copyContent = message.copyContent) !== null && _message$copyContent !== void 0 ? _message$copyContent : message.content) !== null && _ref17 !== void 0 ? _ref17 : '' : message !== null && message !== void 0 ? message : '';
2528
+ navigator.clipboard.writeText(text);
2649
2529
  },
2650
2530
  updateFeedbackIcons: function updateFeedbackIcons(container, userRating) {
2651
2531
  if (!container) {
@@ -2654,11 +2534,11 @@ window.openAIChatManager = function () {
2654
2534
  var upBtn = container.querySelector('.rate-up-btn');
2655
2535
  var downBtn = container.querySelector('.rate-down-btn');
2656
2536
 
2657
- // Font Awesome SVG+JS replaces <i> with <svg>, so we must replace
2658
- // the entire button content and let Font Awesome re-process.
2537
+ // Keep feedback icons as simple span-based Font Awesome markup so
2538
+ // later state updates do not depend on i2svg replacement.
2659
2539
  if (upBtn) {
2660
2540
  var upClass = userRating === true ? 'fa-solid fa-thumbs-up' : 'fa-regular fa-thumbs-up';
2661
- var upIcon = document.createElement('i');
2541
+ var upIcon = document.createElement('span');
2662
2542
  upIcon.className = upClass;
2663
2543
  upIcon.style.fontSize = '0.9rem';
2664
2544
  upBtn.textContent = '';
@@ -2666,19 +2546,12 @@ window.openAIChatManager = function () {
2666
2546
  }
2667
2547
  if (downBtn) {
2668
2548
  var downClass = userRating === false ? 'fa-solid fa-thumbs-down' : 'fa-regular fa-thumbs-down';
2669
- var downIcon = document.createElement('i');
2549
+ var downIcon = document.createElement('span');
2670
2550
  downIcon.className = downClass;
2671
2551
  downIcon.style.fontSize = '0.9rem';
2672
2552
  downBtn.textContent = '';
2673
2553
  downBtn.appendChild(downIcon);
2674
2554
  }
2675
-
2676
- // Trigger Font Awesome SVG+JS to convert the new <i> elements.
2677
- if (window.FontAwesome && FontAwesome.dom && FontAwesome.dom.i2svg) {
2678
- FontAwesome.dom.i2svg({
2679
- node: container
2680
- });
2681
- }
2682
2555
  },
2683
2556
  refreshAllFeedbackIcons: function refreshAllFeedbackIcons() {
2684
2557
  var containers = this.$el.querySelectorAll('.ai-chat-message-assistant-feedback');
@@ -2731,12 +2604,18 @@ window.openAIChatManager = function () {
2731
2604
  documents: {
2732
2605
  handler: function handler() {
2733
2606
  this.renderDocumentBar();
2607
+ if (widgetBehavior && typeof widgetBehavior.onDocumentsChanged === 'function') {
2608
+ widgetBehavior.onDocumentsChanged(this, this.documents, config);
2609
+ }
2734
2610
  },
2735
2611
  deep: true
2736
2612
  },
2737
2613
  isUploading: function isUploading() {
2738
2614
  this.renderDocumentBar();
2739
2615
  },
2616
+ isDocumentOperationPending: function isDocumentOperationPending() {
2617
+ this.renderDocumentBar();
2618
+ },
2740
2619
  isPlayingAudio: function isPlayingAudio() {
2741
2620
  // Reserved for future use — volume-based interrupt detection
2742
2621
  // no longer mutes tracks; browser echo cancellation handles echo.
@@ -2762,22 +2641,27 @@ window.openAIChatManager = function () {
2762
2641
  }
2763
2642
  },
2764
2643
  mounted: function mounted() {
2765
- var _this17 = this;
2766
- _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
2767
- return _regenerator().w(function (_context6) {
2768
- while (1) switch (_context6.n) {
2644
+ var _this22 = this;
2645
+ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
2646
+ var isInitialized;
2647
+ return _regenerator().w(function (_context0) {
2648
+ while (1) switch (_context0.n) {
2769
2649
  case 0:
2770
- _context6.n = 1;
2771
- return _this17.startConnection();
2650
+ _context0.n = 1;
2651
+ return _this22.startConnection();
2772
2652
  case 1:
2773
- _this17.initializeApp();
2774
- if (hasWidgetConfig) {
2775
- _this17.initializeWidget();
2653
+ isInitialized = _this22.initializeApp();
2654
+ if (isInitialized && hasWidgetConfig && widgetBehavior && typeof widgetBehavior.onMounted === 'function') {
2655
+ widgetBehavior.onMounted(_this22, config);
2776
2656
  }
2657
+ _this22.$nextTick(function () {
2658
+ refreshFontAwesomeIcons(_this22.$el);
2659
+ _this22.fontAwesomeObserver = observeFontAwesomeIcons(_this22.$el);
2660
+ });
2777
2661
  case 2:
2778
- return _context6.a(2);
2662
+ return _context0.a(2);
2779
2663
  }
2780
- }, _callee6);
2664
+ }, _callee0);
2781
2665
  }))();
2782
2666
  window.addEventListener('beforeunload', this.handleBeforeUnload);
2783
2667
  window.addEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
@@ -2785,6 +2669,10 @@ window.openAIChatManager = function () {
2785
2669
  beforeUnmount: function beforeUnmount() {
2786
2670
  window.removeEventListener('beforeunload', this.handleBeforeUnload);
2787
2671
  window.removeEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
2672
+ if (this.fontAwesomeObserver) {
2673
+ this.fontAwesomeObserver.disconnect();
2674
+ this.fontAwesomeObserver = null;
2675
+ }
2788
2676
  this.stopAudio(false);
2789
2677
  if (this.stream) {
2790
2678
  this.stream.dispose();
@@ -2793,9 +2681,16 @@ window.openAIChatManager = function () {
2793
2681
  if (this.connection) {
2794
2682
  this.connection.stop();
2795
2683
  }
2684
+ if (widgetBehavior && typeof widgetBehavior.onBeforeUnmount === 'function') {
2685
+ widgetBehavior.onBeforeUnmount(this, config);
2686
+ }
2796
2687
  },
2797
2688
  template: config.messageTemplate
2798
- }).mount(config.appElementSelector);
2689
+ };
2690
+ var app = Vue.createApp(appDefinition).mount(config.appElementSelector);
2691
+ if (widgetBehavior && typeof widgetBehavior.attach === 'function') {
2692
+ widgetBehavior.attach(app, config);
2693
+ }
2799
2694
  return app;
2800
2695
  };
2801
2696
  return {