@crestapps/ai-chat-ui 1.0.0-preview.9 → 1.0.0-rc.2

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,8 +55,8 @@ 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)\"><span :class=\"getAssistantIcon(message)\"></span></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 <span class=\"fa-regular fa-thumbs-up\"></span>\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 <span class=\"fa-regular fa-thumbs-down\"></span>\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 }\" :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 class=\"btn btn-sm btn-link text-secondary p-0 button-message-toolbox\" @click=\"copyResponse(message.content)\" :title=\"copyTitle\">\n <span class=\"fa-solid fa-copy\"></span>\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 <span v-if=\"notification.icon\" :class=\"notification.icon\" class=\"ai-chat-notification-icon\"></span>\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 <span class=\"fa-solid fa-xmark\"></span>\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 <span v-if=\"action.icon\" :class=\"action.icon\" class=\"me-1\"></span>\n {{ action.label }}\n </button>\n </div>\n </div>\n </div>\n ",
56
- indicatorTemplate: "\n <div class=\"ai-chat-msg-role ai-chat-msg-role-assistant\">\n <span class=\"ai-streaming-icon\"><span class=\"fa fa-robot\" style=\"display: inline-block;\"></span></span>\n Assistant\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 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 }\" :data-tts-message-index=\"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)\" :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 ",
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
 
59
62
  // Sanitize URLs to prevent javascript: protocol injection.
@@ -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
@@ -140,7 +312,7 @@ window.openAIChatManager = function () {
140
312
  highlighted = escapeHtmlEntities(code);
141
313
  }
142
314
  var langDisplay = lang ? escapeHtmlEntities(lang) : 'code';
143
- return "<div class=\"ai-code-block\"><div class=\"ai-code-header\"><span class=\"ai-code-lang\"><span class=\"fa-solid fa-code\"></span> ".concat(langDisplay, "</span><button type=\"button\" class=\"ai-code-copy-btn\" title=\"Copy code\"><span class=\"fa-regular fa-copy\"></span></button></div><pre><code class=\"hljs").concat(lang ? ' language-' + lang : '', "\">").concat(highlighted, "</code></pre></div>");
315
+ return "<div class=\"ai-code-block\"><div class=\"ai-code-header\"><span class=\"ai-code-lang\"><i class=\"fa-solid fa-code\"></i> ".concat(langDisplay, "</span><button type=\"button\" class=\"ai-code-copy-btn\" title=\"Copy code\"><i class=\"fa-regular fa-copy\"></i></button></div><pre><code class=\"hljs").concat(lang ? ' language-' + lang : '', "\">").concat(highlighted, "</code></pre></div>");
144
316
  };
145
317
 
146
318
  // Custom image renderer for generated images with thumbnail styling and download button.
@@ -150,7 +322,7 @@ window.openAIChatManager = function () {
150
322
  if (!src) return '';
151
323
  var alt = data.text || defaultConfig.generatedImageAltText;
152
324
  var maxWidth = defaultConfig.generatedImageMaxWidth;
153
- return "<div class=\"generated-image-container\">\n <img src=\"".concat(src, "\" alt=\"").concat(alt, "\" class=\"img-thumbnail\" style=\"max-width: ").concat(maxWidth, "px; height: auto;\" />\n <div class=\"mt-2\">\n <a href=\"").concat(src, "\" target=\"_blank\" download=\"").concat(alt, "\" title=\"").concat(defaultConfig.downloadImageTitle, "\" class=\"btn btn-sm btn-outline-secondary ai-download-image\">\n <span class=\"fa-solid fa-download\"></span>\n </a>\n </div>\n </div>");
325
+ return "<div class=\"generated-image-container\">\n <img src=\"".concat(src, "\" alt=\"").concat(alt, "\" class=\"img-thumbnail\" style=\"max-width: ").concat(maxWidth, "px; height: auto;\" />\n <div class=\"mt-2\">\n <a href=\"").concat(src, "\" target=\"_blank\" download=\"").concat(alt, "\" title=\"").concat(defaultConfig.downloadImageTitle, "\" class=\"btn btn-sm btn-outline-secondary ai-download-image\">\n <i class=\"fa-solid fa-download\"></i>\n </a>\n </div>\n </div>");
154
326
  };
155
327
 
156
328
  // Chart counter for unique IDs
@@ -164,7 +336,7 @@ window.openAIChatManager = function () {
164
336
  // its DOM update to render charts it didn't create itself.
165
337
  window.__chartConfigs = window.__chartConfigs || {};
166
338
  function createChartHtml(chartId) {
167
- return "<div class=\"chart-container\" style=\"position: relative; width: 100%; max-width: 560px; min-height: 420px;\">" + "<canvas id=\"".concat(chartId, "\"></canvas>") + "</div>" + "<div class=\"mt-2\">" + "<button type=\"button\" class=\"btn btn-sm btn-outline-secondary download-chart-btn\" data-chart-id=\"".concat(chartId, "\" title=\"").concat(defaultConfig.downloadChartTitle, "\">") + "<span class=\"fa-solid fa-download\"></span> ".concat(defaultConfig.downloadChartButtonText) + "</button>" + "</div>";
339
+ return "<div class=\"chart-container\" style=\"position: relative; width: 100%; max-width: 560px; min-height: 420px;\">" + "<canvas id=\"".concat(chartId, "\"></canvas>") + "</div>" + "<div class=\"mt-2\">" + "<button type=\"button\" class=\"btn btn-sm btn-outline-secondary download-chart-btn\" data-chart-id=\"".concat(chartId, "\" title=\"").concat(defaultConfig.downloadChartTitle, "\">") + "<i class=\"fa-solid fa-download\"></i> ".concat(defaultConfig.downloadChartButtonText) + "</button>" + "</div>";
168
340
  }
169
341
 
170
342
  // Register [chart:{...json...}] as a native marked block extension so the
@@ -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,336 +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.position !== undefined) {
486
- nextLayout.position = Object.assign({}, currentLayout.position || {}, partialLayout.position || {});
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
- getElementPosition: function getElementPosition(element) {
505
- if (!element) {
506
- return {
507
- left: 0,
508
- top: 0
509
- };
510
- }
511
- var rect = element.getBoundingClientRect();
512
- var computed = window.getComputedStyle(element);
513
- var inlineLeft = parsePixelValue(element.style.left);
514
- var inlineTop = parsePixelValue(element.style.top);
515
- var computedLeft = parsePixelValue(computed.left);
516
- var computedTop = parsePixelValue(computed.top);
517
- var isHidden = computed.display === 'none';
518
- return {
519
- left: Math.round(isHidden && Number.isFinite(inlineLeft) ? inlineLeft : rect.left || inlineLeft || computedLeft || 0),
520
- top: Math.round(isHidden && Number.isFinite(inlineTop) ? inlineTop : rect.top || inlineTop || computedTop || 0)
521
- };
522
- },
523
- clampWidgetPosition: function clampWidgetPosition(left, top, width, height) {
524
- var viewportPadding = 8;
525
- var maxLeft = Math.max(viewportPadding, window.innerWidth - width - viewportPadding);
526
- var maxTop = Math.max(viewportPadding, window.innerHeight - height - viewportPadding);
527
- return {
528
- left: Math.round(clamp(left, viewportPadding, maxLeft)),
529
- top: Math.round(clamp(top, viewportPadding, maxTop))
530
- };
531
- },
532
- applyAbsolutePosition: function applyAbsolutePosition(element, left, top) {
533
- if (!element) {
534
- return;
535
- }
536
- element.style.left = left + 'px';
537
- element.style.top = top + 'px';
538
- element.style.right = 'auto';
539
- element.style.bottom = 'auto';
540
- },
541
- getWidgetDefaultSize: function getWidgetDefaultSize() {
542
- return {
543
- width: this.widgetDefaultWidth || parsePixelValue(config.widget.defaultWidth) || 380,
544
- height: this.widgetDefaultHeight || parsePixelValue(config.widget.defaultHeight) || 520
545
- };
546
- },
547
- getWidgetToggleGap: function getWidgetToggleGap() {
548
- return 8;
549
- },
550
- isWidgetPanelVisible: function isWidgetPanelVisible() {
551
- if (!this.widgetContainerElement) {
552
- return false;
553
- }
554
- var computed = window.getComputedStyle(this.widgetContainerElement);
555
- return this.widgetContainerElement.classList.contains('open') && computed.display !== 'none';
556
- },
557
- persistWidgetPanelPosition: function persistWidgetPanelPosition() {
558
- if (!this.widgetContainerElement || !config.widget.persistLayout) {
559
- return;
560
- }
561
- var panelDefaultSize = this.getWidgetDefaultSize();
562
- var panelPosition = this.getElementPosition(this.widgetContainerElement);
563
- var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
564
- var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
565
- var linkedPosition = this.clampWidgetPosition(panelPosition.left + panelSize.width - toggleSize.width, panelPosition.top + panelSize.height + this.getWidgetToggleGap(), toggleSize.width, toggleSize.height);
566
- this.saveStoredWidgetLayout({
567
- position: {
568
- left: linkedPosition.left,
569
- top: linkedPosition.top
570
- }
571
- });
572
- },
573
- persistWidgetTogglePosition: function persistWidgetTogglePosition() {
574
- if (!this.widgetToggleButtonElement || !config.widget.persistLayout) {
575
- return;
576
- }
577
- var toggleRect = this.widgetToggleButtonElement.getBoundingClientRect();
578
- this.saveStoredWidgetLayout({
579
- position: {
580
- left: this.getElementPosition(this.widgetToggleButtonElement).left,
581
- top: this.getElementPosition(this.widgetToggleButtonElement).top
582
- }
583
- });
584
- },
585
- persistWidgetPanelSize: function persistWidgetPanelSize() {
586
- if (!this.widgetContainerElement || !config.widget.enableResizing || !config.widget.persistLayout) {
587
- return;
588
- }
589
- var defaultSize = this.getWidgetDefaultSize();
590
- var currentSize = this.getElementSize(this.widgetContainerElement, defaultSize.width, defaultSize.height);
591
- this.saveStoredWidgetLayout({
592
- panel: {
593
- width: Math.abs(currentSize.width - defaultSize.width) <= 1 ? null : currentSize.width,
594
- height: Math.abs(currentSize.height - defaultSize.height) <= 1 ? null : currentSize.height
595
- }
596
- });
597
- },
598
- syncTogglePositionToPanel: function syncTogglePositionToPanel() {
599
- var persistLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
600
- if (!this.widgetContainerElement || !this.widgetToggleButtonElement) {
601
- return;
602
- }
603
- var panelDefaultSize = this.getWidgetDefaultSize();
604
- var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
605
- var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
606
- var panelPosition = this.getElementPosition(this.widgetContainerElement);
607
- var linkedPosition = this.clampWidgetPosition(panelPosition.left + panelSize.width - toggleSize.width, panelPosition.top + panelSize.height + this.getWidgetToggleGap(), toggleSize.width, toggleSize.height);
608
- this.applyAbsolutePosition(this.widgetToggleButtonElement, linkedPosition.left, linkedPosition.top);
609
- if (persistLayout && config.widget.persistLayout) {
610
- this.persistWidgetTogglePosition();
611
- }
612
- },
613
- syncPanelPositionToToggle: function syncPanelPositionToToggle() {
614
- var persistLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
615
- if (!this.widgetContainerElement || !this.widgetToggleButtonElement) {
616
- return;
617
- }
618
- var panelDefaultSize = this.getWidgetDefaultSize();
619
- var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
620
- var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
621
- var togglePosition = this.getElementPosition(this.widgetToggleButtonElement);
622
- var linkedPosition = this.clampWidgetPosition(togglePosition.left + toggleSize.width - panelSize.width, togglePosition.top - panelSize.height - this.getWidgetToggleGap(), panelSize.width, panelSize.height);
623
- this.applyAbsolutePosition(this.widgetContainerElement, linkedPosition.left, linkedPosition.top);
624
- if (persistLayout && config.widget.persistLayout) {
625
- this.persistWidgetPanelPosition();
626
- }
627
- },
628
- updateWidgetResetSizeButtonVisibility: function updateWidgetResetSizeButtonVisibility() {
629
- if (!this.widgetResetSizeButtonElement) {
630
- return;
631
- }
632
- if (!config.widget.enableResizing || !this.widgetContainerElement) {
633
- this.widgetResetSizeButtonElement.classList.add('d-none');
634
- return;
635
- }
636
- var defaultSize = this.getWidgetDefaultSize();
637
- var currentSize = this.getElementSize(this.widgetContainerElement, defaultSize.width, defaultSize.height);
638
- var isResized = Math.abs(currentSize.width - defaultSize.width) > 1 || Math.abs(currentSize.height - defaultSize.height) > 1 || !!this.widgetContainerElement.style.width || !!this.widgetContainerElement.style.height;
639
- this.widgetResetSizeButtonElement.classList.toggle('d-none', !isResized);
640
- },
641
- resetWidgetSize: function resetWidgetSize() {
642
- if (!this.widgetContainerElement || !config.widget.enableResizing) {
643
- return;
644
- }
645
- this.widgetContainerElement.style.removeProperty('width');
646
- this.widgetContainerElement.style.removeProperty('height');
647
- this.persistWidgetPanelSize();
648
- this.constrainWidgetElementsToViewport();
649
- this.updateWidgetResetSizeButtonVisibility();
650
- },
651
- restoreWidgetLayout: function restoreWidgetLayout() {
652
- var storedLayout = this.getStoredWidgetLayout();
653
- if (this.widgetContainerElement && config.widget.enableResizing) {
654
- if (Number.isFinite(storedLayout.panel && storedLayout.panel.width)) {
655
- this.widgetContainerElement.style.width = storedLayout.panel.width + 'px';
656
- } else {
657
- this.widgetContainerElement.style.removeProperty('width');
658
- }
659
- if (Number.isFinite(storedLayout.panel && storedLayout.panel.height)) {
660
- this.widgetContainerElement.style.height = storedLayout.panel.height + 'px';
661
- } else {
662
- this.widgetContainerElement.style.removeProperty('height');
663
- }
664
- }
665
- if (this.widgetToggleButtonElement && config.widget.enableDragging && Number.isFinite(storedLayout.position && storedLayout.position.left) && Number.isFinite(storedLayout.position && storedLayout.position.top)) {
666
- this.applyAbsolutePosition(this.widgetToggleButtonElement, storedLayout.position.left, storedLayout.position.top);
667
- this.syncPanelPositionToToggle(false);
668
- } else if (this.widgetToggleButtonElement && config.widget.enableDragging && Number.isFinite(storedLayout.toggle && storedLayout.toggle.left) && Number.isFinite(storedLayout.toggle && storedLayout.toggle.top)) {
669
- this.applyAbsolutePosition(this.widgetToggleButtonElement, storedLayout.toggle.left, storedLayout.toggle.top);
670
- this.syncPanelPositionToToggle(false);
671
- } else if (this.widgetContainerElement && config.widget.enableDragging && Number.isFinite(storedLayout.panel && storedLayout.panel.left) && Number.isFinite(storedLayout.panel && storedLayout.panel.top)) {
672
- this.applyAbsolutePosition(this.widgetContainerElement, storedLayout.panel.left, storedLayout.panel.top);
673
- this.syncTogglePositionToPanel(false);
674
- }
675
- this.constrainWidgetElementsToViewport();
676
- this.updateWidgetResetSizeButtonVisibility();
677
- },
678
- attachDraggableWidgetElement: function attachDraggableWidgetElement(element, handle, layoutKey, suppressClickOnDrag) {
679
- var _this = this;
680
- if (!element || !handle || !config.widget.enableDragging) {
681
- return;
682
- }
683
- var activePointerId = null;
684
- var startX = 0;
685
- var startY = 0;
686
- var startLeft = 0;
687
- var startTop = 0;
688
- var dragged = false;
689
- var dragThreshold = 4;
690
- var interactiveSelector = 'button, a, input, textarea, select, option, label';
691
- var _stopDragging = function stopDragging(event) {
692
- if (activePointerId === null) {
693
- return;
694
- }
695
- if (event && event.pointerId !== undefined && event.pointerId !== activePointerId) {
696
- return;
697
- }
698
- document.removeEventListener('pointermove', onPointerMove);
699
- document.removeEventListener('pointerup', _stopDragging);
700
- document.removeEventListener('pointercancel', _stopDragging);
701
- element.classList.remove('ai-chat-widget-dragging');
702
- activePointerId = null;
703
- if (!dragged) {
704
- return;
705
- }
706
- if (layoutKey === 'panel') {
707
- _this.syncTogglePositionToPanel(false);
708
- _this.persistWidgetPanelPosition();
709
- } else if (layoutKey === 'toggle') {
710
- _this.syncPanelPositionToToggle(false);
711
- _this.persistWidgetTogglePosition();
712
- }
713
- if (config.widget.persistLayout) {
714
- _this.persistWidgetPanelPosition();
715
- _this.persistWidgetTogglePosition();
716
- }
717
- if (suppressClickOnDrag) {
718
- element.dataset.dragSuppressClick = 'true';
719
- window.setTimeout(function () {
720
- if (element.dataset.dragSuppressClick === 'true') {
721
- element.dataset.dragSuppressClick = 'false';
722
- }
723
- }, 0);
724
- }
725
- };
726
- var onPointerMove = function onPointerMove(event) {
727
- if (activePointerId === null || event.pointerId !== activePointerId) {
728
- return;
729
- }
730
- var deltaX = event.clientX - startX;
731
- var deltaY = event.clientY - startY;
732
- if (!dragged && Math.hypot(deltaX, deltaY) < dragThreshold) {
733
- return;
734
- }
735
- dragged = true;
736
- var defaultSize = _this.getWidgetDefaultSize();
737
- var currentSize = _this.getElementSize(element, layoutKey === 'panel' ? defaultSize.width : 52, layoutKey === 'panel' ? defaultSize.height : 52);
738
- var nextPosition = _this.clampWidgetPosition(startLeft + deltaX, startTop + deltaY, currentSize.width, currentSize.height);
739
- _this.applyAbsolutePosition(element, nextPosition.left, nextPosition.top);
740
- if (layoutKey === 'panel') {
741
- _this.syncTogglePositionToPanel(false);
742
- } else if (layoutKey === 'toggle') {
743
- _this.syncPanelPositionToToggle(false);
744
- }
745
- };
746
- handle.addEventListener('pointerdown', function (event) {
747
- if (event.button !== 0) {
748
- return;
749
- }
750
- if (layoutKey === 'panel' && event.target.closest(interactiveSelector)) {
751
- return;
752
- }
753
- var rect = element.getBoundingClientRect();
754
- startX = event.clientX;
755
- startY = event.clientY;
756
- startLeft = rect.left;
757
- startTop = rect.top;
758
- dragged = false;
759
- activePointerId = event.pointerId;
760
- element.classList.add('ai-chat-widget-dragging');
761
- if (handle.setPointerCapture) {
762
- handle.setPointerCapture(event.pointerId);
763
- }
764
- document.addEventListener('pointermove', onPointerMove);
765
- document.addEventListener('pointerup', _stopDragging);
766
- document.addEventListener('pointercancel', _stopDragging);
767
- event.preventDefault();
768
- });
769
- },
770
- constrainWidgetElementsToViewport: function constrainWidgetElementsToViewport() {
771
- if (this.widgetContainerElement && this.widgetContainerElement.style.left && this.isWidgetPanelVisible()) {
772
- var panelDefaultSize = this.getWidgetDefaultSize();
773
- var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
774
- var panelPosition = this.getElementPosition(this.widgetContainerElement);
775
- var clampedPanel = this.clampWidgetPosition(panelPosition.left, panelPosition.top, panelSize.width, panelSize.height);
776
- this.applyAbsolutePosition(this.widgetContainerElement, clampedPanel.left, clampedPanel.top);
777
- this.syncTogglePositionToPanel(false);
778
- if (config.widget.persistLayout) {
779
- this.persistWidgetPanelPosition();
780
- this.persistWidgetTogglePosition();
781
- }
782
- } else if (this.widgetToggleButtonElement && this.widgetToggleButtonElement.style.left) {
783
- var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
784
- var togglePosition = this.getElementPosition(this.widgetToggleButtonElement);
785
- var clampedToggle = this.clampWidgetPosition(togglePosition.left, togglePosition.top, toggleSize.width, toggleSize.height);
786
- this.applyAbsolutePosition(this.widgetToggleButtonElement, clampedToggle.left, clampedToggle.top);
787
- this.syncPanelPositionToToggle(false);
788
- if (config.widget.persistLayout) {
789
- this.persistWidgetTogglePosition();
790
- this.persistWidgetPanelPosition();
791
- }
792
- }
793
- },
794
631
  handleDragOver: function handleDragOver(e) {
795
632
  if (!config.sessionDocumentsEnabled) return;
796
633
  e.preventDefault();
@@ -815,180 +652,272 @@ window.openAIChatManager = function () {
815
652
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
816
653
  if (inputArea) inputArea.classList.remove('ai-chat-drag-over');
817
654
  if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
818
- this.uploadFiles(e.dataTransfer.files);
655
+ this.uploadFiles(Array.from(e.dataTransfer.files));
819
656
  }
820
657
  },
821
658
  triggerFileInput: function triggerFileInput() {
822
- if (!config.sessionDocumentsEnabled) return;
659
+ if (!config.sessionDocumentsEnabled || this.isDocumentOperationPending) return;
823
660
  var fileInput = document.getElementById('ai-chat-doc-input');
824
661
  if (fileInput) fileInput.click();
825
662
  },
826
663
  handleFileInputChange: function handleFileInputChange(e) {
827
- var files = e.target.files;
664
+ var files = e.target.files ? Array.from(e.target.files) : [];
828
665
  if (files && files.length > 0) {
829
666
  this.uploadFiles(files);
830
667
  }
831
668
  e.target.value = '';
832
669
  },
833
- uploadFiles: function uploadFiles(files) {
834
- var _this2 = this;
835
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
836
- 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() {
837
674
  return _regenerator().w(function (_context) {
838
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) {
839
705
  case 0:
840
706
  if (config.uploadDocumentUrl) {
841
- _context.n = 1;
707
+ _context3.n = 1;
842
708
  break;
843
709
  }
844
- return _context.a(2);
710
+ return _context3.a(2);
845
711
  case 1:
846
- sessionId = _this2.getSessionId();
847
- profileId = _this2.getProfileId();
848
- if (!(!sessionId && !profileId)) {
849
- _context.n = 2;
712
+ filesToUpload = Array.isArray(files) ? files.slice() : Array.from(files || []);
713
+ if (!(filesToUpload.length === 0)) {
714
+ _context3.n = 2;
850
715
  break;
851
716
  }
852
- console.warn('Cannot upload documents without a session or profile.');
853
- return _context.a(2);
717
+ return _context3.a(2);
854
718
  case 2:
855
- _this2.isUploading = true;
856
- _this2.uploadErrors = [];
857
- _this2.renderDocumentBar();
858
- _context.p = 3;
859
- formData = new FormData();
860
- if (sessionId) {
861
- formData.append('sessionId', sessionId);
862
- } else {
863
- formData.append('profileId', profileId);
864
- }
865
- for (i = 0; i < files.length; i++) {
866
- formData.append('files', files[i]);
867
- }
868
- _context.n = 4;
869
- return fetch(config.uploadDocumentUrl, {
870
- method: 'POST',
871
- body: formData
872
- });
873
- case 4:
874
- response = _context.v;
875
- if (response.ok) {
876
- _context.n = 6;
877
- break;
878
- }
879
- _context.n = 5;
880
- return response.text();
881
- case 5:
882
- errorText = _context.v;
883
- uploadError = _this2.extractReadableErrorMessage(errorText, 'Upload failed. Please try again.');
884
- console.error('Upload failed:', errorText);
885
- _this2.uploadErrors = [{
886
- fileName: '',
887
- error: uploadError
888
- }];
889
- return _context.a(2);
890
- case 6:
891
- _context.n = 7;
892
- return response.json();
893
- case 7:
894
- result = _context.v;
895
- // If the server created a new session, initialize it.
896
- if (result.sessionId && !sessionId) {
897
- _this2.initializeSession(result.sessionId);
898
- }
899
- if (result.uploaded && result.uploaded.length > 0) {
900
- for (j = 0; j < result.uploaded.length; j++) {
901
- _this2.documents.push(result.uploaded[j]);
902
- }
903
- }
904
- if (result.failed && result.failed.length > 0) {
905
- _this2.uploadErrors = result.failed;
906
- }
907
- _context.n = 9;
908
- break;
909
- case 8:
910
- _context.p = 8;
911
- _t = _context.v;
912
- console.error('Upload error:', _t);
913
- _this2.uploadErrors = [{
914
- fileName: '',
915
- error: 'Upload failed. Please try again.'
916
- }];
917
- case 9:
918
- _context.p = 9;
919
- _this2.isUploading = false;
920
- _this2.renderDocumentBar();
921
- return _context.f(9);
922
- case 10:
923
- 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
+ }))));
924
830
  }
925
- }, _callee, null, [[3, 8, 9, 10]]);
831
+ }, _callee3);
926
832
  }))();
927
833
  },
928
834
  removeDocument: function removeDocument(doc) {
929
- var _this3 = this;
930
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
931
- var sessionId, response, idx, errorText, removeError, _t2;
932
- return _regenerator().w(function (_context2) {
933
- 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) {
934
839
  case 0:
935
840
  if (config.removeDocumentUrl) {
936
- _context2.n = 1;
841
+ _context5.n = 1;
937
842
  break;
938
843
  }
939
- return _context2.a(2);
844
+ return _context5.a(2);
940
845
  case 1:
941
- _context2.p = 1;
942
- sessionId = _this3.getSessionId();
943
- _context2.n = 2;
944
- return fetch(config.removeDocumentUrl, {
945
- method: 'POST',
946
- headers: {
947
- 'Content-Type': 'application/json'
948
- },
949
- body: JSON.stringify({
950
- itemId: sessionId,
951
- documentId: doc.documentId
952
- })
953
- });
954
- case 2:
955
- response = _context2.v;
956
- if (!response.ok) {
957
- _context2.n = 3;
958
- break;
959
- }
960
- idx = _this3.documents.indexOf(doc);
961
- if (idx > -1) _this3.documents.splice(idx, 1);
962
- _context2.n = 5;
963
- break;
964
- case 3:
965
- _context2.n = 4;
966
- return response.text();
967
- case 4:
968
- errorText = _context2.v;
969
- removeError = _this3.extractReadableErrorMessage(errorText, 'Failed to remove document. Please try again.');
970
- console.error('Failed to remove document:', response.status, errorText);
971
- _this3.uploadErrors = [{
972
- fileName: doc.fileName || '',
973
- error: removeError
974
- }];
975
- _this3.renderDocumentBar();
976
- case 5:
977
- _context2.n = 7;
978
- break;
979
- case 6:
980
- _context2.p = 6;
981
- _t2 = _context2.v;
982
- console.error('Remove document error:', _t2);
983
- _this3.uploadErrors = [{
984
- fileName: doc.fileName || '',
985
- error: 'Failed to remove document. Please try again.'
986
- }];
987
- _this3.renderDocumentBar();
988
- case 7:
989
- 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
+ }))));
990
919
  }
991
- }, _callee2, null, [[1, 6]]);
920
+ }, _callee5);
992
921
  }))();
993
922
  },
994
923
  formatFileSize: function formatFileSize(bytes) {
@@ -1010,9 +939,9 @@ window.openAIChatManager = function () {
1010
939
  var name = doc.fileName || 'Document';
1011
940
  if (name.length > 20) name = name.substring(0, 17) + '...';
1012
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 || '') + '">';
1013
- html += '<span class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></span> ';
942
+ html += '<i class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></i> ';
1014
943
  html += this.escapeHtml(name);
1015
- 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>';
1016
945
  html += '</span>';
1017
946
  }
1018
947
  for (var m = 0; m < this.uploadErrors.length; m++) {
@@ -1021,7 +950,7 @@ window.openAIChatManager = function () {
1021
950
  var errorMsg = failedItem.error || 'Upload failed';
1022
951
  if (failedName.length > 15) failedName = failedName.substring(0, 12) + '...';
1023
952
  html += '<span class="badge bg-danger bg-opacity-25 text-danger d-inline-flex align-items-center gap-1 px-2 py-1" style="font-size: 0.8rem;" title="' + this.escapeHtml((failedItem.fileName || '') + ': ' + errorMsg) + '">';
1024
- html += '<span class="fa-solid fa-circle-exclamation" style="font-size: 0.7rem;"></span> ';
953
+ html += '<i class="fa-solid fa-circle-exclamation" style="font-size: 0.7rem;"></i> ';
1025
954
  html += this.escapeHtml(failedName);
1026
955
  html += ' <button type="button" class="btn-close btn-close-sm ms-1" style="font-size: 0.5rem;" data-error-index="' + m + '" aria-label="Dismiss"></button>';
1027
956
  html += '</span>';
@@ -1031,8 +960,8 @@ window.openAIChatManager = function () {
1031
960
  html += '<span class="spinner-border spinner-border-sm" style="width: 0.7rem; height: 0.7rem;"></span> Uploading...';
1032
961
  html += '</span>';
1033
962
  }
1034
- 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">';
1035
- html += '<span class="fa-solid fa-paperclip"></span>';
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' : '') + '>';
964
+ html += '<i class="fa-solid fa-paperclip"></i>';
1036
965
  if (this.documents.length === 0 && !this.isUploading) {
1037
966
  html += ' <span>Attach files</span>';
1038
967
  }
@@ -1054,6 +983,9 @@ window.openAIChatManager = function () {
1054
983
  return function (e) {
1055
984
  e.preventDefault();
1056
985
  e.stopPropagation();
986
+ if (self.isDocumentOperationPending) {
987
+ return;
988
+ }
1057
989
  var docToRemove = self.documents[idx];
1058
990
  if (docToRemove) self.removeDocument(docToRemove);
1059
991
  };
@@ -1078,6 +1010,9 @@ window.openAIChatManager = function () {
1078
1010
  if (addBtn) {
1079
1011
  addBtn.addEventListener('click', function (e) {
1080
1012
  e.preventDefault();
1013
+ if (self.isDocumentOperationPending) {
1014
+ return;
1015
+ }
1081
1016
  self.triggerFileInput();
1082
1017
  });
1083
1018
  }
@@ -1154,139 +1089,135 @@ window.openAIChatManager = function () {
1154
1089
  return !!message && message.isStreaming && index === this.lastAssistantIndex && !(appearance && appearance.disableStreamingAnimation);
1155
1090
  },
1156
1091
  startConnection: function startConnection() {
1157
- var _this4 = this;
1158
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
1159
- var _t3;
1160
- return _regenerator().w(function (_context3) {
1161
- 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) {
1162
1097
  case 0:
1163
- _this4.connection = new signalR.HubConnectionBuilder().withUrl(config.signalRHubUrl).withAutomaticReconnect().build();
1098
+ _this3.connection = new signalR.HubConnectionBuilder().withUrl(config.signalRHubUrl).withAutomaticReconnect().build();
1164
1099
 
1165
1100
  // Allow long-running operations (e.g., multi-step MCP tool calls)
1166
1101
  // without the client disconnecting prematurely.
1167
- _this4.connection.serverTimeoutInMilliseconds = 600000;
1168
- _this4.connection.keepAliveIntervalInMilliseconds = 15000;
1169
- _this4.connection.on("LoadSession", function (data) {
1102
+ _this3.connection.serverTimeoutInMilliseconds = 600000;
1103
+ _this3.connection.keepAliveIntervalInMilliseconds = 15000;
1104
+ _this3.connection.on("LoadSession", function (data) {
1170
1105
  var _data$messages;
1171
- _this4.initializeSession(data.sessionId, true);
1172
- _this4.messages = [];
1173
- _this4.documents = data.documents || [];
1106
+ _this3.initializeSession(data.sessionId, true);
1107
+ _this3.messages = [];
1108
+ _this3.documents = data.documents || [];
1109
+ _this3.uploadErrors = [];
1174
1110
  ((_data$messages = data.messages) !== null && _data$messages !== void 0 ? _data$messages : []).forEach(function (msg) {
1175
- _this4.addMessage(msg);
1176
- _this4.$nextTick(function () {
1111
+ _this3.addMessage(msg);
1112
+ _this3.$nextTick(function () {
1177
1113
  renderChartsInMessage(msg);
1178
1114
  });
1179
1115
  });
1180
1116
 
1181
1117
  // Update feedback icons in the DOM after all messages have rendered.
1182
- _this4.$nextTick(function () {
1183
- _this4.refreshAllFeedbackIcons();
1118
+ _this3.$nextTick(function () {
1119
+ _this3.refreshAllFeedbackIcons();
1184
1120
  });
1185
1121
 
1186
1122
  // When the session is new (no messages) and an initial prompt is configured,
1187
1123
  // automatically send it as the first user message to trigger an AI response.
1188
- if (_this4.messages.length === 0 && config.initialPrompt) {
1189
- _this4.prompt = config.initialPrompt;
1190
- _this4.sendMessage();
1124
+ if (_this3.messages.length === 0 && config.initialPrompt) {
1125
+ _this3.prompt = config.initialPrompt;
1126
+ _this3.sendMessage();
1191
1127
  }
1192
1128
  });
1193
- _this4.connection.on("ReceiveError", function (error) {
1129
+ _this3.connection.on("ReceiveError", function (error) {
1194
1130
  console.error("SignalR Error: ", error);
1195
- if (_this4.isRecording) {
1196
- _this4.stopRecording();
1131
+ if (_this3.isRecording) {
1132
+ _this3.stopRecording();
1197
1133
  }
1198
-
1199
- // If this is a widget with a stale cached session (e.g., profile was deleted),
1200
- // clear the cached session and start fresh with the current profile.
1201
- if (_this4.widgetIsInitialized && !_this4.isSessionStarted && !_this4._attemptedSessionRecovery) {
1202
- _this4._attemptedSessionRecovery = true;
1203
- localStorage.removeItem(_this4.chatWidgetStateSession);
1204
- _this4.startNewSession();
1134
+ if (widgetBehavior && typeof widgetBehavior.handleReceiveError === 'function') {
1135
+ widgetBehavior.handleReceiveError(_this3, error, config);
1205
1136
  }
1206
1137
  });
1207
- _this4.connection.on("MessageRated", function (messageId, userRating) {
1208
- var msg = _this4.messages.find(function (m) {
1138
+ _this3.connection.on("MessageRated", function (messageId, userRating) {
1139
+ var msg = _this3.messages.find(function (m) {
1209
1140
  return m.id === messageId;
1210
1141
  });
1211
1142
  if (msg) {
1212
1143
  msg.userRating = userRating;
1213
1144
  }
1214
1145
  });
1215
- _this4.connection.on("ReceiveTranscript", function (sessionId, text, isFinal) {
1216
- if (_this4.isConversationMode) {
1146
+ _this3.connection.on("ReceiveTranscript", function (sessionId, text, isFinal) {
1147
+ if (_this3.isConversationMode) {
1217
1148
  if (!isFinal && text) {
1218
- _this4._conversationPartialTranscript = text;
1149
+ _this3._conversationPartialTranscript = text;
1219
1150
  var escaped = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1220
1151
  var html = '<p class="ai-partial-transcript">' + escaped + '</p>';
1221
1152
 
1222
1153
  // Show partial transcript as a live user message.
1223
- if (!_this4._conversationPartialMessage) {
1224
- _this4.hidePlaceholder();
1225
- _this4._conversationPartialMessage = {
1154
+ if (!_this3._conversationPartialMessage) {
1155
+ _this3.hidePlaceholder();
1156
+ _this3._conversationPartialMessage = {
1226
1157
  role: 'user',
1227
1158
  content: text,
1228
1159
  htmlContent: html,
1229
1160
  isPartial: true
1230
1161
  };
1231
- _this4.messages.push(_this4._conversationPartialMessage);
1162
+ _this3.messages.push(_this3._conversationPartialMessage);
1232
1163
  } else {
1233
- _this4._conversationPartialMessage.content = text;
1234
- _this4._conversationPartialMessage.htmlContent = html;
1164
+ _this3._conversationPartialMessage.content = text;
1165
+ _this3._conversationPartialMessage.htmlContent = html;
1235
1166
  }
1236
- _this4.scrollToBottom();
1167
+ _this3.scrollToBottom();
1237
1168
  }
1238
1169
  return;
1239
1170
  }
1240
- if (text && !_this4._audioInputSent) {
1241
- _this4.prompt = _this4.preRecordingPrompt + text;
1242
- if (_this4.inputElement) {
1243
- _this4.inputElement.value = _this4.prompt;
1244
- _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'));
1245
1176
  }
1246
1177
  }
1247
1178
  });
1248
- _this4.connection.on("ReceiveConversationUserMessage", function (sessionId, text) {
1179
+ _this3.connection.on("ReceiveConversationUserMessage", function (sessionId, text) {
1249
1180
  if (text) {
1250
- _this4.stopAudio();
1181
+ _this3.stopAudio();
1251
1182
 
1252
1183
  // If there's an interrupted assistant message still streaming,
1253
1184
  // mark it as done to stop the spinner animation.
1254
- if (_this4._conversationAssistantMessage) {
1255
- var oldMsg = _this4.messages[_this4._conversationAssistantMessage.index];
1185
+ if (_this3._conversationAssistantMessage) {
1186
+ var oldMsg = _this3.messages[_this3._conversationAssistantMessage.index];
1256
1187
  if (oldMsg) {
1257
1188
  oldMsg.isStreaming = false;
1258
1189
  }
1259
- _this4._conversationAssistantMessage = null;
1190
+ _this3._conversationAssistantMessage = null;
1260
1191
  }
1261
1192
 
1262
1193
  // Replace the partial transcript message with the final one.
1263
- if (_this4._conversationPartialMessage) {
1194
+ if (_this3._conversationPartialMessage) {
1264
1195
  var escaped = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1265
- _this4._conversationPartialMessage.content = text;
1266
- _this4._conversationPartialMessage.htmlContent = '<p>' + escaped + '</p>';
1267
- _this4._conversationPartialMessage.isPartial = false;
1268
- _this4._conversationPartialMessage = null;
1196
+ _this3._conversationPartialMessage.content = text;
1197
+ _this3._conversationPartialMessage.htmlContent = '<p>' + escaped + '</p>';
1198
+ _this3._conversationPartialMessage.isPartial = false;
1199
+ _this3._conversationPartialMessage = null;
1269
1200
  } else {
1270
- _this4.addMessage({
1201
+ _this3.addMessage({
1271
1202
  role: 'user',
1272
1203
  content: text
1273
1204
  });
1274
1205
  }
1275
- _this4.scrollToBottom();
1206
+ _this3.scrollToBottom();
1276
1207
  }
1277
1208
  });
1278
- _this4.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, appearance) {
1279
- if (!_this4._conversationAssistantMessage) {
1280
- _this4.stopAudio();
1281
- _this4.hideTypingIndicator();
1209
+ _this3.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, references, appearance) {
1210
+ if (!_this3._conversationAssistantMessage) {
1211
+ _this3.stopAudio();
1212
+ _this3.hideTypingIndicator();
1282
1213
 
1283
1214
  // Ensure no stale streaming indicators remain from prior messages.
1284
- for (var j = 0; j < _this4.messages.length; j++) {
1285
- if (_this4.messages[j].isStreaming) {
1286
- _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;
1287
1218
  }
1288
1219
  }
1289
- var msgIndex = _this4.messages.length;
1220
+ var msgIndex = _this3.messages.length;
1290
1221
  var newMessage = {
1291
1222
  id: messageId,
1292
1223
  role: "assistant",
@@ -1294,96 +1225,100 @@ window.openAIChatManager = function () {
1294
1225
  htmlContent: "",
1295
1226
  isStreaming: true,
1296
1227
  userRating: null,
1297
- appearance: _this4.normalizeAssistantAppearance(appearance)
1228
+ appearance: _this3.normalizeAssistantAppearance(appearance),
1229
+ references: {}
1298
1230
  };
1299
- _this4.messages.push(newMessage);
1300
- _this4._conversationAssistantMessage = {
1231
+ _this3.messages.push(newMessage);
1232
+ _this3._conversationAssistantMessage = {
1301
1233
  index: msgIndex,
1302
1234
  content: ''
1303
1235
  };
1304
1236
  }
1305
- _this4._conversationAssistantMessage.content += token;
1306
- var msg = _this4.messages[_this4._conversationAssistantMessage.index];
1237
+ _this3._conversationAssistantMessage.content += token;
1238
+ var msg = _this3.messages[_this3._conversationAssistantMessage.index];
1307
1239
  if (msg) {
1308
1240
  if (!msg.appearance) {
1309
- msg.appearance = _this4.normalizeAssistantAppearance(appearance);
1241
+ msg.appearance = _this3.normalizeAssistantAppearance(appearance);
1310
1242
  }
1311
- msg.content = _this4._conversationAssistantMessage.content;
1312
- msg.htmlContent = parseMarkdownContent(msg.content, msg);
1313
- _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 () {
1314
1247
  renderChartsInMessage(msg);
1315
- _this4.scrollToBottom();
1248
+ _this3.scrollToBottom();
1316
1249
  });
1317
1250
  }
1318
1251
  });
1319
- _this4.connection.on("ReceiveConversationAssistantComplete", function (sessionId, messageId) {
1320
- if (_this4._conversationAssistantMessage) {
1321
- 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];
1322
1255
  if (msg) {
1323
1256
  msg.isStreaming = false;
1257
+ msg.references = normalizeReferences(Object.assign({}, msg.references || {}, references || {}));
1258
+ updateMessagePresentation(msg, msg.references);
1324
1259
  }
1325
- _this4._conversationAssistantMessage = null;
1260
+ _this3._conversationAssistantMessage = null;
1326
1261
  }
1327
1262
  });
1328
- _this4.connection.on("ReceiveAudioChunk", function (sessionId, base64Audio, contentType) {
1263
+ _this3.connection.on("ReceiveAudioChunk", function (sessionId, base64Audio, contentType) {
1329
1264
  if (base64Audio) {
1330
1265
  var binaryString = atob(base64Audio);
1331
1266
  var bytes = new Uint8Array(binaryString.length);
1332
1267
  for (var i = 0; i < binaryString.length; i++) {
1333
1268
  bytes[i] = binaryString.charCodeAt(i);
1334
1269
  }
1335
- _this4.audioChunks.push(bytes);
1270
+ _this3.audioChunks.push(bytes);
1336
1271
  }
1337
1272
  });
1338
- _this4.connection.on("ReceiveAudioComplete", function (sessionId) {
1339
- _this4.playCollectedAudio();
1273
+ _this3.connection.on("ReceiveAudioComplete", function (sessionId) {
1274
+ _this3.playCollectedAudio();
1340
1275
  });
1341
- _this4.connection.on("ReceiveNotification", function (notification) {
1342
- _this4.receiveNotification(notification);
1276
+ _this3.connection.on("ReceiveNotification", function (notification) {
1277
+ _this3.receiveNotification(notification);
1343
1278
  });
1344
- _this4.connection.on("UpdateNotification", function (notification) {
1345
- _this4.updateNotification(notification);
1279
+ _this3.connection.on("UpdateNotification", function (notification) {
1280
+ _this3.updateNotification(notification);
1346
1281
  });
1347
- _this4.connection.on("RemoveNotification", function (notificationType) {
1348
- _this4.removeNotification(notificationType);
1282
+ _this3.connection.on("RemoveNotification", function (notificationType) {
1283
+ _this3.removeNotification(notificationType);
1349
1284
  });
1350
- _this4.connection.onreconnecting(function () {
1285
+ _this3.connection.onreconnecting(function () {
1351
1286
  console.warn("SignalR: reconnecting...");
1352
1287
  });
1353
- _this4.connection.onreconnected(function () {
1288
+ _this3.connection.onreconnected(function () {
1354
1289
  console.info("SignalR: reconnected.");
1355
- if (_this4.isSessionStarted) {
1356
- _this4.reloadCurrentSession();
1290
+ if (_this3.isSessionStarted) {
1291
+ _this3.reloadCurrentSession();
1357
1292
  } else if (config.autoCreateSession) {
1358
- _this4.startNewSession();
1293
+ _this3.startNewSession();
1359
1294
  }
1360
1295
  });
1361
- _this4.connection.onclose(function (error) {
1362
- if (_this4.isNavigatingAway) {
1296
+ _this3.connection.onclose(function (error) {
1297
+ if (_this3.isNavigatingAway) {
1363
1298
  return;
1364
1299
  }
1365
1300
  if (error) {
1366
1301
  console.warn("SignalR connection closed with error:", error.message || error);
1367
1302
  }
1368
1303
  });
1369
- _context3.p = 1;
1370
- _context3.n = 2;
1371
- return _this4.connection.start();
1304
+ _context6.p = 1;
1305
+ _context6.n = 2;
1306
+ return _this3.connection.start();
1372
1307
  case 2:
1373
- _context3.n = 4;
1308
+ _context6.n = 4;
1374
1309
  break;
1375
1310
  case 3:
1376
- _context3.p = 3;
1377
- _t3 = _context3.v;
1378
- console.error("SignalR Connection Error: ", _t3);
1311
+ _context6.p = 3;
1312
+ _t4 = _context6.v;
1313
+ console.error("SignalR Connection Error: ", _t4);
1379
1314
  case 4:
1380
- return _context3.a(2);
1315
+ return _context6.a(2);
1381
1316
  }
1382
- }, _callee3, null, [[1, 3]]);
1317
+ }, _callee6, null, [[1, 3]]);
1383
1318
  }))();
1384
1319
  },
1385
1320
  addMessageInternal: function addMessageInternal(message) {
1386
- var _this5 = this;
1321
+ var _this4 = this;
1387
1322
  if (message.role === 'assistant') {
1388
1323
  message.appearance = this.normalizeAssistantAppearance(message.appearance);
1389
1324
  }
@@ -1397,7 +1332,7 @@ window.openAIChatManager = function () {
1397
1332
  }));
1398
1333
  this.messages.push(message);
1399
1334
  this.$nextTick(function () {
1400
- _this5.fireEvent(new CustomEvent("addedOpenAIPromotMessage", {
1335
+ _this4.fireEvent(new CustomEvent("addedOpenAIPromotMessage", {
1401
1336
  detail: {
1402
1337
  message: message
1403
1338
  }
@@ -1405,105 +1340,32 @@ window.openAIChatManager = function () {
1405
1340
  });
1406
1341
  },
1407
1342
  addMessage: function addMessage(message) {
1408
- var _this6 = this;
1343
+ var _this5 = this;
1409
1344
  // Ensure userRating is always defined for Vue reactivity.
1410
1345
  if (message.userRating === undefined) {
1411
1346
  message.userRating = null;
1412
1347
  }
1413
1348
  if (message.content) {
1414
- var processedContent = message.content.trim();
1415
- message.references = normalizeReferences(message.references);
1416
- if (message.references && _typeof(message.references) === "object" && Object.keys(message.references).length) {
1417
- // Only include references that were actually cited in the response.
1418
- var citedRefs = Object.entries(message.references).filter(function (_ref4) {
1419
- var _ref5 = _slicedToArray(_ref4, 1),
1420
- key = _ref5[0];
1421
- return processedContent.includes(key);
1422
- });
1423
- if (citedRefs.length) {
1424
- // Sort by original index so display indices follow a natural order.
1425
- citedRefs.sort(function (_ref6, _ref7) {
1426
- var _ref8 = _slicedToArray(_ref6, 2),
1427
- a = _ref8[1];
1428
- var _ref9 = _slicedToArray(_ref7, 2),
1429
- b = _ref9[1];
1430
- return a.index - b.index;
1431
- });
1432
-
1433
- // Phase 1: Replace all markers with unique placeholders.
1434
- var displayIndex = 1;
1435
- var _iterator2 = _createForOfIteratorHelper(citedRefs),
1436
- _step2;
1437
- try {
1438
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1439
- var _step2$value = _slicedToArray(_step2.value, 2),
1440
- key = _step2$value[0],
1441
- value = _step2$value[1];
1442
- var placeholder = "__CITE_".concat(value.index, "__");
1443
- processedContent = processedContent.replaceAll(key, placeholder);
1444
- value._displayIndex = displayIndex++;
1445
- value._placeholder = placeholder;
1446
- }
1447
-
1448
- // Phase 2: Replace placeholders with sequential display indices.
1449
- } catch (err) {
1450
- _iterator2.e(err);
1451
- } finally {
1452
- _iterator2.f();
1453
- }
1454
- var _iterator3 = _createForOfIteratorHelper(citedRefs),
1455
- _step3;
1456
- try {
1457
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1458
- var _step3$value = _slicedToArray(_step3.value, 2),
1459
- _value = _step3$value[1];
1460
- processedContent = processedContent.replaceAll(_value._placeholder, "<sup><strong>".concat(_value._displayIndex, "</strong></sup>"));
1461
- }
1462
-
1463
- // if we have multiple references, add a comma to ensure we don't concatenate numbers.
1464
- } catch (err) {
1465
- _iterator3.e(err);
1466
- } finally {
1467
- _iterator3.f();
1468
- }
1469
- processedContent = processedContent.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1470
- processedContent += '<br><br>';
1471
- var _iterator4 = _createForOfIteratorHelper(citedRefs),
1472
- _step4;
1473
- try {
1474
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1475
- var _step4$value = _slicedToArray(_step4.value, 2),
1476
- _key = _step4$value[0],
1477
- _value2 = _step4$value[1];
1478
- var label = _value2.text || _key;
1479
- processedContent += _value2.link ? "**".concat(_value2._displayIndex, "**. [").concat(label, "](").concat(_value2.link, ")<br>") : "**".concat(_value2._displayIndex, "**. ").concat(label, "<br>");
1480
- }
1481
- } catch (err) {
1482
- _iterator4.e(err);
1483
- } finally {
1484
- _iterator4.f();
1485
- }
1486
- }
1487
- }
1488
- message.content = processedContent;
1489
- 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);
1490
1352
  }
1491
1353
  this.addMessageInternal(message);
1492
1354
  this.hidePlaceholder();
1493
1355
  this.$nextTick(function () {
1494
1356
  // Render any pending charts once the DOM is updated
1495
1357
  renderChartsInMessage(message);
1496
- _this6.scrollToBottom();
1358
+ _this5.scrollToBottom();
1497
1359
  });
1498
1360
  },
1499
1361
  addMessages: function addMessages(messages) {
1500
- var _this7 = this;
1362
+ var _this6 = this;
1501
1363
  for (var i = 0; i < messages.length; i++) {
1502
1364
  this.addMessageInternal(messages[i]);
1503
1365
  }
1504
1366
  this.hidePlaceholder();
1505
1367
  this.$nextTick(function () {
1506
- _this7.scrollToBottom();
1368
+ _this6.scrollToBottom();
1507
1369
  });
1508
1370
  },
1509
1371
  hidePlaceholder: function hidePlaceholder() {
@@ -1580,7 +1442,7 @@ window.openAIChatManager = function () {
1580
1442
  this.prompt = '';
1581
1443
  },
1582
1444
  startRecording: function startRecording() {
1583
- var _this8 = this;
1445
+ var _this7 = this;
1584
1446
  if (this.isRecording || !this.connection) {
1585
1447
  return;
1586
1448
  }
@@ -1592,27 +1454,27 @@ window.openAIChatManager = function () {
1592
1454
  }
1593
1455
  }).then(function (stream) {
1594
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';
1595
- _this8.mediaRecorder = new MediaRecorder(stream, {
1457
+ _this7.mediaRecorder = new MediaRecorder(stream, {
1596
1458
  mimeType: mimeType,
1597
1459
  audioBitsPerSecond: 128000
1598
1460
  });
1599
- _this8.preRecordingPrompt = _this8.prompt;
1600
- _this8._audioInputSent = false;
1461
+ _this7.preRecordingPrompt = _this7.prompt;
1462
+ _this7._audioInputSent = false;
1601
1463
  var subject = new signalR.Subject();
1602
- var profileId = _this8.getProfileId();
1603
- var sessionId = _this8.getSessionId() || '';
1464
+ var profileId = _this7.getProfileId();
1465
+ var sessionId = _this7.getSessionId() || '';
1604
1466
  var pendingChunk = Promise.resolve();
1605
- _this8.mediaRecorder.addEventListener('dataavailable', function (e) {
1467
+ _this7.mediaRecorder.addEventListener('dataavailable', function (e) {
1606
1468
  if (e.data && e.data.size > 0) {
1607
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
1469
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7() {
1608
1470
  var data, uint8Array, binaryString, base64;
1609
- return _regenerator().w(function (_context4) {
1610
- while (1) switch (_context4.n) {
1471
+ return _regenerator().w(function (_context7) {
1472
+ while (1) switch (_context7.n) {
1611
1473
  case 0:
1612
- _context4.n = 1;
1474
+ _context7.n = 1;
1613
1475
  return e.data.arrayBuffer();
1614
1476
  case 1:
1615
- data = _context4.v;
1477
+ data = _context7.v;
1616
1478
  uint8Array = new Uint8Array(data);
1617
1479
  binaryString = uint8Array.reduce(function (str, _byte) {
1618
1480
  return str + String.fromCharCode(_byte);
@@ -1620,13 +1482,13 @@ window.openAIChatManager = function () {
1620
1482
  base64 = btoa(binaryString);
1621
1483
  subject.next(base64);
1622
1484
  case 2:
1623
- return _context4.a(2);
1485
+ return _context7.a(2);
1624
1486
  }
1625
- }, _callee4);
1487
+ }, _callee7);
1626
1488
  })));
1627
1489
  }
1628
1490
  });
1629
- _this8.mediaRecorder.addEventListener('stop', function () {
1491
+ _this7.mediaRecorder.addEventListener('stop', function () {
1630
1492
  stream.getTracks().forEach(function (track) {
1631
1493
  return track.stop();
1632
1494
  });
@@ -1635,10 +1497,10 @@ window.openAIChatManager = function () {
1635
1497
  });
1636
1498
  });
1637
1499
  var language = navigator.language || document.documentElement.lang || 'en-US';
1638
- _this8.connection.send("SendAudioStream", profileId, sessionId, subject, mimeType, language);
1639
- _this8.mediaRecorder.start(250);
1640
- _this8.isRecording = true;
1641
- _this8.updateMicButton();
1500
+ _this7.connection.send("SendAudioStream", profileId, sessionId, subject, mimeType, language);
1501
+ _this7.mediaRecorder.start(250);
1502
+ _this7.isRecording = true;
1503
+ _this7.updateMicButton();
1642
1504
  })["catch"](function (err) {
1643
1505
  console.error('Microphone access denied:', err);
1644
1506
  });
@@ -1664,14 +1526,14 @@ window.openAIChatManager = function () {
1664
1526
  }
1665
1527
  if (this.isRecording) {
1666
1528
  this.micButton.classList.add('stt-recording');
1667
- this.micButton.innerHTML = '<span class="fa-solid fa-stop"></span>';
1529
+ this.micButton.innerHTML = '<i class="fa-solid fa-stop"></i>';
1668
1530
  } else {
1669
1531
  this.micButton.classList.remove('stt-recording');
1670
- this.micButton.innerHTML = '<span class="fa-solid fa-microphone"></span>';
1532
+ this.micButton.innerHTML = '<i class="fa-solid fa-microphone"></i>';
1671
1533
  }
1672
1534
  },
1673
1535
  streamMessage: function streamMessage(profileId, trimmedPrompt, sessionProfileId) {
1674
- var _this9 = this;
1536
+ var _this8 = this;
1675
1537
  if (this.stream) {
1676
1538
  this.stream.dispose();
1677
1539
  this.stream = null;
@@ -1688,14 +1550,14 @@ window.openAIChatManager = function () {
1688
1550
  var currentSessionId = this.getSessionId();
1689
1551
  this.stream = this.connection.stream("SendMessage", profileId, trimmedPrompt, currentSessionId, sessionProfileId).subscribe({
1690
1552
  next: function next(chunk) {
1691
- var message = _this9.messages[messageIndex];
1553
+ var message = _this8.messages[messageIndex];
1692
1554
  if (!message) {
1693
1555
  if (chunk.sessionId && !currentSessionId) {
1694
- _this9.initializeSession(chunk.sessionId);
1556
+ _this8.initializeSession(chunk.sessionId);
1695
1557
  }
1696
- _this9.hideTypingIndicator();
1558
+ _this8.hideTypingIndicator();
1697
1559
  // Re-assign the index after hiding the typing indicator.
1698
- messageIndex = _this9.messages.length;
1560
+ messageIndex = _this8.messages.length;
1699
1561
  var newMessage = {
1700
1562
  id: chunk.messageId,
1701
1563
  role: "assistant",
@@ -1705,16 +1567,16 @@ window.openAIChatManager = function () {
1705
1567
  isStreaming: true,
1706
1568
  userRating: null
1707
1569
  };
1708
- _this9.messages.push(newMessage);
1570
+ _this8.messages.push(newMessage);
1709
1571
  message = newMessage;
1710
1572
  }
1711
1573
  if (chunk.title && (!message.title || message.title !== chunk.title)) {
1712
1574
  message.title = chunk.title;
1713
1575
  }
1714
1576
  if (chunk.references && _typeof(chunk.references) === "object" && Object.keys(chunk.references).length) {
1715
- 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++) {
1716
1578
  var _normalizeReference2;
1717
- var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i3], 2),
1579
+ var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i4], 2),
1718
1580
  key = _Object$entries2$_i[0],
1719
1581
  value = _Object$entries2$_i[1];
1720
1582
  references[key] = (_normalizeReference2 = normalizeReference(value)) !== null && _normalizeReference2 !== void 0 ? _normalizeReference2 : {};
@@ -1729,62 +1591,52 @@ window.openAIChatManager = function () {
1729
1591
  if (chunk.responseId) {
1730
1592
  lastResponseId = chunk.responseId;
1731
1593
  }
1732
- var processedContent = chunk.content;
1733
- for (var _i4 = 0, _Object$entries3 = Object.entries(references); _i4 < _Object$entries3.length; _i4++) {
1734
- var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i4], 2),
1735
- _key2 = _Object$entries3$_i[0],
1736
- _value3 = _Object$entries3$_i[1];
1737
- processedContent = processedContent.replaceAll(_key2, "<sup><strong>".concat(_value3.index, "</strong></sup>"));
1738
- }
1739
-
1740
- // Append processed content to the message.
1741
- // if we have multiple references, add a comma to ensure we don't concatenate numbers.
1742
- content += processedContent.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1594
+ content += chunk.content;
1743
1595
  }
1744
1596
 
1745
1597
  // Update the existing message
1746
- message.content = content;
1747
- message.htmlContent = parseMarkdownContent(content, message);
1748
- _this9.messages[messageIndex] = message;
1749
- _this9.$nextTick(function () {
1598
+ message.rawContent = content;
1599
+ updateMessagePresentation(message, references);
1600
+ _this8.messages[messageIndex] = message;
1601
+ _this8.$nextTick(function () {
1750
1602
  renderChartsInMessage(message);
1751
- _this9.scrollToBottom();
1603
+ _this8.scrollToBottom();
1752
1604
  });
1753
1605
  },
1754
1606
  complete: function complete() {
1755
- var _this9$stream;
1756
- _this9.processReferences(references, messageIndex);
1757
- _this9.streamingFinished();
1758
- var msg = _this9.messages[messageIndex];
1607
+ var _this8$stream;
1608
+ _this8.processReferences(references, messageIndex);
1609
+ _this8.streamingFinished();
1610
+ var msg = _this8.messages[messageIndex];
1759
1611
  if (msg) {
1760
1612
  msg.isStreaming = false;
1761
1613
  }
1762
1614
  if (!msg || !msg.content) {
1763
1615
  // No content received at all.
1764
- _this9.hideTypingIndicator();
1616
+ _this8.hideTypingIndicator();
1765
1617
  }
1766
1618
 
1767
1619
  // Trigger text-to-speech only in conversation mode.
1768
- if (_this9.isConversationMode && _this9.textToSpeechEnabled && msg && msg.content) {
1769
- _this9.synthesizeSpeech(msg.content);
1620
+ if (_this8.isConversationMode && _this8.textToSpeechEnabled && msg && msg.content) {
1621
+ _this8.synthesizeSpeech(msg.content);
1770
1622
  }
1771
- (_this9$stream = _this9.stream) === null || _this9$stream === void 0 || _this9$stream.dispose();
1772
- _this9.stream = null;
1623
+ (_this8$stream = _this8.stream) === null || _this8$stream === void 0 || _this8$stream.dispose();
1624
+ _this8.stream = null;
1773
1625
  },
1774
1626
  error: function error(err) {
1775
- var _this9$stream2;
1776
- _this9.processReferences(references, messageIndex);
1777
- _this9.streamingFinished();
1778
- var msg = _this9.messages[messageIndex];
1627
+ var _this8$stream2;
1628
+ _this8.processReferences(references, messageIndex);
1629
+ _this8.streamingFinished();
1630
+ var msg = _this8.messages[messageIndex];
1779
1631
  if (msg) {
1780
1632
  msg.isStreaming = false;
1781
1633
  }
1782
- _this9.hideTypingIndicator();
1783
- if (!_this9.isNavigatingAway) {
1784
- _this9.addMessage(_this9.getServiceDownMessage());
1634
+ _this8.hideTypingIndicator();
1635
+ if (!_this8.isNavigatingAway) {
1636
+ _this8.addMessage(_this8.getServiceDownMessage());
1785
1637
  }
1786
- (_this9$stream2 = _this9.stream) === null || _this9$stream2 === void 0 || _this9$stream2.dispose();
1787
- _this9.stream = null;
1638
+ (_this8$stream2 = _this8.stream) === null || _this8$stream2 === void 0 || _this8$stream2.dispose();
1639
+ _this8.stream = null;
1788
1640
  console.error("Stream error:", err);
1789
1641
  }
1790
1642
  });
@@ -1798,92 +1650,17 @@ window.openAIChatManager = function () {
1798
1650
  return newMessage;
1799
1651
  },
1800
1652
  processReferences: function processReferences(references, messageIndex) {
1801
- var _this0 = this;
1653
+ var _this9 = this;
1802
1654
  references = normalizeReferences(references);
1803
1655
  if (Object.keys(references).length) {
1656
+ var _ref15, _message$rawContent2;
1804
1657
  var message = this.messages[messageIndex];
1805
- var content = message.content || '';
1806
-
1807
- // Only include references that were actually cited in the response.
1808
- // Check both raw [doc:N] markers and already-rendered <sup> tags from streaming.
1809
- var citedRefs = Object.entries(references).filter(function (_ref1) {
1810
- var _ref10 = _slicedToArray(_ref1, 2),
1811
- key = _ref10[0],
1812
- value = _ref10[1];
1813
- return content.includes(key) || content.includes("<sup><strong>".concat(value.index, "</strong></sup>"));
1814
- });
1815
- if (!citedRefs.length) {
1816
- return;
1817
- }
1818
-
1819
- // Sort by original index so display indices follow a natural order.
1820
- citedRefs.sort(function (_ref11, _ref12) {
1821
- var _ref13 = _slicedToArray(_ref11, 2),
1822
- a = _ref13[1];
1823
- var _ref14 = _slicedToArray(_ref12, 2),
1824
- b = _ref14[1];
1825
- return a.index - b.index;
1826
- });
1827
-
1828
- // Phase 1: Replace all markers with unique placeholders to avoid collisions during remapping.
1829
- var processed = content.trim();
1830
- var displayIndex = 1;
1831
- var _iterator5 = _createForOfIteratorHelper(citedRefs),
1832
- _step5;
1833
- try {
1834
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1835
- var _step5$value = _slicedToArray(_step5.value, 2),
1836
- key = _step5$value[0],
1837
- value = _step5$value[1];
1838
- var placeholder = "__CITE_".concat(value.index, "__");
1839
- processed = processed.replaceAll(key, placeholder);
1840
- processed = processed.replaceAll("<sup><strong>".concat(value.index, "</strong></sup>"), placeholder);
1841
- value._displayIndex = displayIndex++;
1842
- value._placeholder = placeholder;
1843
- }
1844
-
1845
- // Phase 2: Replace placeholders with sequential display indices.
1846
- } catch (err) {
1847
- _iterator5.e(err);
1848
- } finally {
1849
- _iterator5.f();
1850
- }
1851
- var _iterator6 = _createForOfIteratorHelper(citedRefs),
1852
- _step6;
1853
- try {
1854
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1855
- var _step6$value = _slicedToArray(_step6.value, 2),
1856
- _value4 = _step6$value[1];
1857
- processed = processed.replaceAll(_value4._placeholder, "<sup><strong>".concat(_value4._displayIndex, "</strong></sup>"));
1858
- }
1859
- } catch (err) {
1860
- _iterator6.e(err);
1861
- } finally {
1862
- _iterator6.f();
1863
- }
1864
- processed = processed.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1865
- processed += '<br><br>';
1866
- var _iterator7 = _createForOfIteratorHelper(citedRefs),
1867
- _step7;
1868
- try {
1869
- for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
1870
- var _step7$value = _slicedToArray(_step7.value, 2),
1871
- _key3 = _step7$value[0],
1872
- _value5 = _step7$value[1];
1873
- var label = _value5.text || _key3;
1874
- processed += _value5.link ? "**".concat(_value5._displayIndex, "**. [").concat(label, "](").concat(_value5.link, ")<br>") : "**".concat(_value5._displayIndex, "**. ").concat(label, "<br>");
1875
- }
1876
- } catch (err) {
1877
- _iterator7.e(err);
1878
- } finally {
1879
- _iterator7.f();
1880
- }
1881
- message.content = processed;
1882
- 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);
1883
1660
  this.messages[messageIndex] = message;
1884
1661
  this.$nextTick(function () {
1885
1662
  renderChartsInMessage(message);
1886
- _this0.scrollToBottom();
1663
+ _this9.scrollToBottom();
1887
1664
  });
1888
1665
  }
1889
1666
  },
@@ -1934,15 +1711,15 @@ window.openAIChatManager = function () {
1934
1711
  this.stopAudio(false);
1935
1712
  },
1936
1713
  updateTtsPlaybackButtons: function updateTtsPlaybackButtons() {
1937
- var _this1 = this;
1714
+ var _this0 = this;
1938
1715
  if (!this.chatContainer) {
1939
1716
  return;
1940
1717
  }
1941
1718
  var buttons = this.chatContainer.querySelectorAll('[data-tts-message-index]');
1942
1719
  buttons.forEach(function (button) {
1943
1720
  var buttonIndex = Number(button.getAttribute('data-tts-message-index'));
1944
- var isPlaying = buttonIndex === _this1.ttsPlayingMessageIndex;
1945
- var iconHtml = isPlaying ? '<span class="fa-solid fa-circle-pause"></span>' : '<span class="fa-solid fa-circle-play"></span>';
1721
+ var isPlaying = buttonIndex === _this0.ttsPlayingMessageIndex;
1722
+ var iconHtml = isPlaying ? '<i class="fa-solid fa-circle-pause"></i>' : '<i class="fa-solid fa-circle-play"></i>';
1946
1723
  button.classList.toggle('tts-playing', isPlaying);
1947
1724
  button.setAttribute('title', isPlaying ? 'Pause audio' : 'Read aloud');
1948
1725
  button.replaceChildren(DOMPurify.sanitize(iconHtml, {
@@ -1951,7 +1728,7 @@ window.openAIChatManager = function () {
1951
1728
  });
1952
1729
  },
1953
1730
  synthesizeSpeech: function synthesizeSpeech(text, cacheIndex) {
1954
- var _this10 = this;
1731
+ var _this1 = this;
1955
1732
  if (!this.textToSpeechEnabled || !text || !this.connection) {
1956
1733
  return;
1957
1734
  }
@@ -1960,16 +1737,16 @@ window.openAIChatManager = function () {
1960
1737
  this._ttsCacheIndex = cacheIndex !== undefined ? cacheIndex : -1;
1961
1738
  this.connection.invoke("SynthesizeSpeech", this.getProfileId(), this.getSessionId(), text, this.ttsVoiceName)["catch"](function (err) {
1962
1739
  console.error("TTS synthesis error:", err);
1963
- _this10.isPlayingAudio = false;
1964
- _this10.ttsPlayingMessageIndex = -1;
1965
- _this10._ttsCacheIndex = -1;
1966
- _this10.$nextTick(function () {
1967
- return _this10.updateTtsPlaybackButtons();
1740
+ _this1.isPlayingAudio = false;
1741
+ _this1.ttsPlayingMessageIndex = -1;
1742
+ _this1._ttsCacheIndex = -1;
1743
+ _this1.$nextTick(function () {
1744
+ return _this1.updateTtsPlaybackButtons();
1968
1745
  });
1969
1746
  });
1970
1747
  },
1971
1748
  toggleMessageTts: function toggleMessageTts(message, index) {
1972
- var _this11 = this;
1749
+ var _this10 = this;
1973
1750
  if (this.ttsPlayingMessageIndex === index) {
1974
1751
  this.stopAudio();
1975
1752
  return;
@@ -1982,7 +1759,7 @@ window.openAIChatManager = function () {
1982
1759
  }));
1983
1760
  this.ttsPlayingMessageIndex = index;
1984
1761
  this.$nextTick(function () {
1985
- return _this11.updateTtsPlaybackButtons();
1762
+ return _this10.updateTtsPlaybackButtons();
1986
1763
  });
1987
1764
  if (this.ttsAudioCache[index]) {
1988
1765
  this.playAudioBlob(this.ttsAudioCache[index]);
@@ -1991,13 +1768,13 @@ window.openAIChatManager = function () {
1991
1768
  this.synthesizeSpeech(message.content, index);
1992
1769
  },
1993
1770
  playCollectedAudio: function playCollectedAudio() {
1994
- var _this12 = this;
1771
+ var _this11 = this;
1995
1772
  if (this.audioChunks.length === 0) {
1996
1773
  if (!this.currentAudioElement && this.audioPlayQueue.length === 0) {
1997
1774
  this.isPlayingAudio = false;
1998
1775
  this.ttsPlayingMessageIndex = -1;
1999
1776
  this.$nextTick(function () {
2000
- return _this12.updateTtsPlaybackButtons();
1777
+ return _this11.updateTtsPlaybackButtons();
2001
1778
  });
2002
1779
  }
2003
1780
  return;
@@ -2007,18 +1784,18 @@ window.openAIChatManager = function () {
2007
1784
  }, 0);
2008
1785
  var combined = new Uint8Array(totalLength);
2009
1786
  var offset = 0;
2010
- var _iterator8 = _createForOfIteratorHelper(this.audioChunks),
2011
- _step8;
1787
+ var _iterator5 = _createForOfIteratorHelper(this.audioChunks),
1788
+ _step5;
2012
1789
  try {
2013
- for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
2014
- var chunk = _step8.value;
1790
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1791
+ var chunk = _step5.value;
2015
1792
  combined.set(chunk, offset);
2016
1793
  offset += chunk.length;
2017
1794
  }
2018
1795
  } catch (err) {
2019
- _iterator8.e(err);
1796
+ _iterator5.e(err);
2020
1797
  } finally {
2021
- _iterator8.f();
1798
+ _iterator5.f();
2022
1799
  }
2023
1800
  this.audioChunks = [];
2024
1801
  var blob = new Blob([combined], {
@@ -2037,39 +1814,39 @@ window.openAIChatManager = function () {
2037
1814
  this.playAudioBlob(blob);
2038
1815
  },
2039
1816
  playAudioBlob: function playAudioBlob(blob) {
2040
- var _this13 = this;
1817
+ var _this12 = this;
2041
1818
  var url = URL.createObjectURL(blob);
2042
1819
  var audio = new Audio(url);
2043
1820
  this.currentAudioUrl = url;
2044
1821
  this.currentAudioElement = audio;
2045
1822
  this.isPlayingAudio = true;
2046
1823
  audio.addEventListener('ended', function () {
2047
- _this13.currentAudioElement = null;
2048
- _this13.currentAudioUrl = null;
1824
+ _this12.currentAudioElement = null;
1825
+ _this12.currentAudioUrl = null;
2049
1826
  URL.revokeObjectURL(url);
2050
- _this13.playNextInQueue();
1827
+ _this12.playNextInQueue();
2051
1828
  });
2052
1829
  audio.addEventListener('error', function () {
2053
- _this13.currentAudioElement = null;
2054
- _this13.currentAudioUrl = null;
1830
+ _this12.currentAudioElement = null;
1831
+ _this12.currentAudioUrl = null;
2055
1832
  URL.revokeObjectURL(url);
2056
- _this13.playNextInQueue();
1833
+ _this12.playNextInQueue();
2057
1834
  });
2058
1835
  audio.play()["catch"](function (err) {
2059
1836
  console.error("Audio playback error:", err);
2060
- _this13.currentAudioElement = null;
2061
- _this13.currentAudioUrl = null;
1837
+ _this12.currentAudioElement = null;
1838
+ _this12.currentAudioUrl = null;
2062
1839
  URL.revokeObjectURL(url);
2063
- _this13.audioPlayQueue = [];
2064
- _this13.isPlayingAudio = false;
2065
- _this13.ttsPlayingMessageIndex = -1;
2066
- _this13.$nextTick(function () {
2067
- return _this13.updateTtsPlaybackButtons();
1840
+ _this12.audioPlayQueue = [];
1841
+ _this12.isPlayingAudio = false;
1842
+ _this12.ttsPlayingMessageIndex = -1;
1843
+ _this12.$nextTick(function () {
1844
+ return _this12.updateTtsPlaybackButtons();
2068
1845
  });
2069
1846
  });
2070
1847
  },
2071
1848
  playNextInQueue: function playNextInQueue() {
2072
- var _this14 = this;
1849
+ var _this13 = this;
2073
1850
  if (this.audioPlayQueue.length > 0) {
2074
1851
  var nextBlob = this.audioPlayQueue.shift();
2075
1852
  this.playAudioBlob(nextBlob);
@@ -2077,13 +1854,13 @@ window.openAIChatManager = function () {
2077
1854
  this.isPlayingAudio = false;
2078
1855
  this.ttsPlayingMessageIndex = -1;
2079
1856
  this.$nextTick(function () {
2080
- return _this14.updateTtsPlaybackButtons();
1857
+ return _this13.updateTtsPlaybackButtons();
2081
1858
  });
2082
1859
  this.conversationModeOnAudioEnded();
2083
1860
  }
2084
1861
  },
2085
1862
  stopAudio: function stopAudio() {
2086
- var _this15 = this;
1863
+ var _this14 = this;
2087
1864
  if (this.currentAudioElement) {
2088
1865
  this.currentAudioElement.pause();
2089
1866
  this.currentAudioElement.currentTime = 0;
@@ -2098,7 +1875,7 @@ window.openAIChatManager = function () {
2098
1875
  this.isPlayingAudio = false;
2099
1876
  this.ttsPlayingMessageIndex = -1;
2100
1877
  this.$nextTick(function () {
2101
- return _this15.updateTtsPlaybackButtons();
1878
+ return _this14.updateTtsPlaybackButtons();
2102
1879
  });
2103
1880
  },
2104
1881
  toggleConversationMode: function toggleConversationMode() {
@@ -2109,7 +1886,7 @@ window.openAIChatManager = function () {
2109
1886
  }
2110
1887
  },
2111
1888
  startConversationMode: function startConversationMode() {
2112
- var _this16 = this;
1889
+ var _this15 = this;
2113
1890
  if (!this.conversationModeEnabled || this.isConversationMode || !this.connection) {
2114
1891
  return;
2115
1892
  }
@@ -2129,12 +1906,12 @@ window.openAIChatManager = function () {
2129
1906
  }
2130
1907
  }).then(function (stream) {
2131
1908
  var mimeType = MediaRecorder.isTypeSupported('audio/ogg;codecs=opus') ? 'audio/ogg;codecs=opus' : MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' : 'audio/webm';
2132
- _this16.mediaRecorder = new MediaRecorder(stream, {
1909
+ _this15.mediaRecorder = new MediaRecorder(stream, {
2133
1910
  mimeType: mimeType,
2134
1911
  audioBitsPerSecond: 128000
2135
1912
  });
2136
- _this16._conversationSubject = new signalR.Subject();
2137
- _this16._conversationStream = stream;
1913
+ _this15._conversationSubject = new signalR.Subject();
1914
+ _this15._conversationStream = stream;
2138
1915
 
2139
1916
  // Create an AnalyserNode for volume-based interrupt detection.
2140
1917
  // During TTS playback, detect when the user speaks above
@@ -2143,20 +1920,20 @@ window.openAIChatManager = function () {
2143
1920
  // speaker echo so the STT stream has no gaps.
2144
1921
  var AudioCtx = window.AudioContext || window.webkitAudioContext;
2145
1922
  if (AudioCtx) {
2146
- _this16._conversationAudioCtx = new AudioCtx();
2147
- _this16._conversationAnalyser = _this16._conversationAudioCtx.createAnalyser();
2148
- _this16._conversationAnalyser.fftSize = 256;
2149
- var micSource = _this16._conversationAudioCtx.createMediaStreamSource(stream);
2150
- micSource.connect(_this16._conversationAnalyser);
1923
+ _this15._conversationAudioCtx = new AudioCtx();
1924
+ _this15._conversationAnalyser = _this15._conversationAudioCtx.createAnalyser();
1925
+ _this15._conversationAnalyser.fftSize = 256;
1926
+ var micSource = _this15._conversationAudioCtx.createMediaStreamSource(stream);
1927
+ micSource.connect(_this15._conversationAnalyser);
2151
1928
  }
2152
1929
  var pendingChunk = Promise.resolve();
2153
- var analyser = _this16._conversationAnalyser;
1930
+ var analyser = _this15._conversationAnalyser;
2154
1931
  var interruptVolumeThreshold = 30;
2155
- _this16.mediaRecorder.addEventListener('dataavailable', function (e) {
1932
+ _this15.mediaRecorder.addEventListener('dataavailable', function (e) {
2156
1933
  if (e.data && e.data.size > 0) {
2157
1934
  // During TTS playback, check mic volume to detect
2158
1935
  // user interruption (speaking above threshold).
2159
- if (_this16.isPlayingAudio && analyser) {
1936
+ if (_this15.isPlayingAudio && analyser) {
2160
1937
  var freqData = new Uint8Array(analyser.frequencyBinCount);
2161
1938
  analyser.getByteFrequencyData(freqData);
2162
1939
  var sum = 0;
@@ -2166,61 +1943,61 @@ window.openAIChatManager = function () {
2166
1943
  var avg = sum / freqData.length;
2167
1944
  if (avg >= interruptVolumeThreshold) {
2168
1945
  // User is speaking — interrupt TTS playback.
2169
- _this16.stopAudio();
1946
+ _this15.stopAudio();
2170
1947
  }
2171
1948
  }
2172
1949
 
2173
1950
  // Always send audio to STT — browser echo cancellation
2174
1951
  // handles speaker echo; continuous audio avoids gaps
2175
1952
  // that increase recognition latency.
2176
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
1953
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
2177
1954
  var data, uint8Array, binaryString, base64;
2178
- return _regenerator().w(function (_context5) {
2179
- while (1) switch (_context5.n) {
1955
+ return _regenerator().w(function (_context8) {
1956
+ while (1) switch (_context8.n) {
2180
1957
  case 0:
2181
- _context5.n = 1;
1958
+ _context8.n = 1;
2182
1959
  return e.data.arrayBuffer();
2183
1960
  case 1:
2184
- data = _context5.v;
1961
+ data = _context8.v;
2185
1962
  uint8Array = new Uint8Array(data);
2186
1963
  binaryString = uint8Array.reduce(function (str, _byte2) {
2187
1964
  return str + String.fromCharCode(_byte2);
2188
1965
  }, '');
2189
1966
  base64 = btoa(binaryString);
2190
1967
  try {
2191
- _this16._conversationSubject.next(base64);
1968
+ _this15._conversationSubject.next(base64);
2192
1969
  } catch (err) {
2193
1970
  // Subject may have been completed already.
2194
1971
  }
2195
1972
  case 2:
2196
- return _context5.a(2);
1973
+ return _context8.a(2);
2197
1974
  }
2198
- }, _callee5);
1975
+ }, _callee8);
2199
1976
  })));
2200
1977
  }
2201
1978
  });
2202
- _this16.mediaRecorder.addEventListener('stop', function () {
1979
+ _this15.mediaRecorder.addEventListener('stop', function () {
2203
1980
  stream.getTracks().forEach(function (track) {
2204
1981
  return track.stop();
2205
1982
  });
2206
1983
  pendingChunk.then(function () {
2207
1984
  try {
2208
- _this16._conversationSubject.complete();
1985
+ _this15._conversationSubject.complete();
2209
1986
  } catch (err) {
2210
1987
  // Already completed.
2211
1988
  }
2212
1989
  });
2213
1990
  });
2214
- var profileId = _this16.getProfileId();
2215
- var sessionId = _this16.getSessionId() || '';
1991
+ var profileId = _this15.getProfileId();
1992
+ var sessionId = _this15.getSessionId() || '';
2216
1993
  var language = navigator.language || document.documentElement.lang || 'en-US';
2217
- _this16.connection.send("StartConversation", profileId, sessionId, _this16._conversationSubject, mimeType, language);
2218
- _this16.mediaRecorder.start(250);
2219
- _this16.isRecording = true;
1994
+ _this15.connection.send("StartConversation", profileId, sessionId, _this15._conversationSubject, mimeType, language);
1995
+ _this15.mediaRecorder.start(250);
1996
+ _this15.isRecording = true;
2220
1997
  })["catch"](function (err) {
2221
1998
  console.error('Microphone access denied:', err);
2222
- _this16.isConversationMode = false;
2223
- _this16.updateConversationButton();
1999
+ _this15.isConversationMode = false;
2000
+ _this15.updateConversationButton();
2224
2001
  });
2225
2002
  },
2226
2003
  stopConversationMode: function stopConversationMode() {
@@ -2347,7 +2124,7 @@ window.openAIChatManager = function () {
2347
2124
  return removedCount;
2348
2125
  },
2349
2126
  receiveNotification: function receiveNotification(notification) {
2350
- var _this17 = this;
2127
+ var _this16 = this;
2351
2128
  if (!notification || !notification.type) {
2352
2129
  return;
2353
2130
  }
@@ -2362,7 +2139,7 @@ window.openAIChatManager = function () {
2362
2139
  }
2363
2140
  this.scheduleNotificationDismiss(notification);
2364
2141
  this.$nextTick(function () {
2365
- _this17.scrollToBottom();
2142
+ _this16.scrollToBottom();
2366
2143
  });
2367
2144
  },
2368
2145
  updateNotification: function updateNotification(notification) {
@@ -2379,12 +2156,12 @@ window.openAIChatManager = function () {
2379
2156
  }
2380
2157
  },
2381
2158
  scheduleNotificationDismiss: function scheduleNotificationDismiss(notification) {
2382
- var _this18 = this;
2159
+ var _this17 = this;
2383
2160
  if (!notification || !notification.type || !notification.autoDismissMs || notification.autoDismissMs <= 0) {
2384
2161
  return;
2385
2162
  }
2386
2163
  this.notificationDismissTimers[notification.type] = setTimeout(function () {
2387
- _this18.removeNotification(notification.type);
2164
+ _this17.removeNotification(notification.type);
2388
2165
  }, notification.autoDismissMs);
2389
2166
  },
2390
2167
  clearNotificationDismiss: function clearNotificationDismiss(notificationType) {
@@ -2414,31 +2191,32 @@ window.openAIChatManager = function () {
2414
2191
  });
2415
2192
  },
2416
2193
  scrollToBottom: function scrollToBottom() {
2417
- var _this19 = this;
2194
+ var _this18 = this;
2418
2195
  if (!this.autoScroll) {
2419
2196
  return;
2420
2197
  }
2421
2198
  setTimeout(function () {
2422
- _this19.chatContainer.scrollTop = _this19.chatContainer.scrollHeight - _this19.chatContainer.clientHeight;
2199
+ _this18.chatContainer.scrollTop = _this18.chatContainer.scrollHeight - _this18.chatContainer.clientHeight;
2423
2200
  }, 50);
2424
2201
  },
2425
2202
  handleUserInput: function handleUserInput(event) {
2426
2203
  this.prompt = event.target.value;
2427
2204
  },
2428
2205
  getProfileId: function getProfileId() {
2429
- return this.inputElement.getAttribute('data-profile-id');
2206
+ return this.inputElement ? this.inputElement.getAttribute('data-profile-id') : null;
2430
2207
  },
2431
2208
  setSessionId: function setSessionId(sessionId) {
2209
+ if (!this.inputElement) {
2210
+ return;
2211
+ }
2432
2212
  this.inputElement.setAttribute('data-session-id', sessionId || '');
2433
2213
  },
2434
2214
  resetSession: function resetSession() {
2435
2215
  this.stopRecording();
2216
+ this.rejectPendingSessionRequest('Session was reset.');
2436
2217
  this.setSessionId('');
2437
2218
  this.isSessionStarted = false;
2438
2219
  this.sessionRating = null;
2439
- if (this.widgetIsInitialized) {
2440
- localStorage.removeItem(this.chatWidgetStateSession);
2441
- }
2442
2220
  this.messages = [];
2443
2221
  this.documents = [];
2444
2222
  if (!config.autoCreateSession) {
@@ -2447,6 +2225,9 @@ window.openAIChatManager = function () {
2447
2225
  if (config.autoCreateSession) {
2448
2226
  this.startNewSession();
2449
2227
  }
2228
+ if (widgetBehavior && typeof widgetBehavior.onSessionReset === 'function') {
2229
+ widgetBehavior.onSessionReset(this, config);
2230
+ }
2450
2231
  },
2451
2232
  startNewSession: function startNewSession() {
2452
2233
  if (!this.applyOrchestratorAvailability()) {
@@ -2456,16 +2237,94 @@ window.openAIChatManager = function () {
2456
2237
  if (!profileId || !this.connection) {
2457
2238
  return;
2458
2239
  }
2459
- this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2240
+ this.requestNewSession(profileId)["catch"](function (err) {
2460
2241
  return console.error(err);
2461
2242
  });
2462
2243
  },
2463
- initializeApp: function initializeApp() {
2244
+ ensureSessionForDocuments: function ensureSessionForDocuments(profileId) {
2245
+ var _this19 = this;
2246
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
2247
+ var sessionId;
2248
+ return _regenerator().w(function (_context9) {
2249
+ while (1) switch (_context9.n) {
2250
+ case 0:
2251
+ sessionId = _this19.getSessionId();
2252
+ if (!sessionId) {
2253
+ _context9.n = 1;
2254
+ break;
2255
+ }
2256
+ return _context9.a(2, sessionId);
2257
+ case 1:
2258
+ if (!(!profileId || !_this19.connection)) {
2259
+ _context9.n = 2;
2260
+ break;
2261
+ }
2262
+ return _context9.a(2, null);
2263
+ case 2:
2264
+ _context9.n = 3;
2265
+ return _this19.requestNewSession(profileId);
2266
+ case 3:
2267
+ return _context9.a(2, _context9.v);
2268
+ }
2269
+ }, _callee9);
2270
+ }))();
2271
+ },
2272
+ requestNewSession: function requestNewSession(profileId) {
2464
2273
  var _this20 = this;
2274
+ if (this.pendingSessionPromise) {
2275
+ return this.pendingSessionPromise;
2276
+ }
2277
+ if (!profileId || !this.connection) {
2278
+ return Promise.resolve(null);
2279
+ }
2280
+ this.pendingSessionPromise = new Promise(function (resolve, reject) {
2281
+ _this20.pendingSessionResolver = resolve;
2282
+ _this20.pendingSessionRejector = reject;
2283
+ _this20.pendingSessionTimeoutId = window.setTimeout(function () {
2284
+ _this20.rejectPendingSessionRequest('Timed out while creating a chat session.');
2285
+ }, 15000);
2286
+ });
2287
+ this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2288
+ _this20.rejectPendingSessionRequest(err);
2289
+ });
2290
+ return this.pendingSessionPromise;
2291
+ },
2292
+ resolvePendingSessionRequest: function resolvePendingSessionRequest(sessionId) {
2293
+ if (this.pendingSessionResolver) {
2294
+ this.pendingSessionResolver(sessionId);
2295
+ }
2296
+ this.clearPendingSessionRequest();
2297
+ },
2298
+ rejectPendingSessionRequest: function rejectPendingSessionRequest(error) {
2299
+ if (this.pendingSessionRejector) {
2300
+ this.pendingSessionRejector(error);
2301
+ }
2302
+ this.clearPendingSessionRequest();
2303
+ },
2304
+ clearPendingSessionRequest: function clearPendingSessionRequest() {
2305
+ if (this.pendingSessionTimeoutId) {
2306
+ window.clearTimeout(this.pendingSessionTimeoutId);
2307
+ }
2308
+ this.pendingSessionPromise = null;
2309
+ this.pendingSessionResolver = null;
2310
+ this.pendingSessionRejector = null;
2311
+ this.pendingSessionTimeoutId = null;
2312
+ },
2313
+ initializeApp: function initializeApp() {
2314
+ var _this21 = this;
2465
2315
  this.inputElement = document.querySelector(config.inputElementSelector);
2466
2316
  this.buttonElement = document.querySelector(config.sendButtonElementSelector);
2467
2317
  this.chatContainer = document.querySelector(config.chatContainerElementSelector);
2468
2318
  this.placeholder = document.querySelector(config.placeholderElementSelector);
2319
+ if (!this.inputElement || !this.buttonElement || !this.chatContainer || !this.placeholder) {
2320
+ console.error('AI chat app could not initialize because one or more required elements were not found.', {
2321
+ inputElementSelector: config.inputElementSelector,
2322
+ sendButtonElementSelector: config.sendButtonElementSelector,
2323
+ chatContainerElementSelector: config.chatContainerElementSelector,
2324
+ placeholderElementSelector: config.placeholderElementSelector
2325
+ });
2326
+ return false;
2327
+ }
2469
2328
  this.applyOrchestratorAvailability();
2470
2329
  var sessionId = this.getSessionId();
2471
2330
  if (!hasWidgetConfig && sessionId) {
@@ -2490,7 +2349,7 @@ window.openAIChatManager = function () {
2490
2349
  fileInput.accept = config.allowedExtensions;
2491
2350
  }
2492
2351
  fileInput.addEventListener('change', function (e) {
2493
- return _this20.handleFileInputChange(e);
2352
+ return _this21.handleFileInputChange(e);
2494
2353
  });
2495
2354
  this.documentBar.parentElement.appendChild(fileInput);
2496
2355
 
@@ -2498,13 +2357,13 @@ window.openAIChatManager = function () {
2498
2357
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
2499
2358
  if (inputArea) {
2500
2359
  inputArea.addEventListener('dragover', function (e) {
2501
- return _this20.handleDragOver(e);
2360
+ return _this21.handleDragOver(e);
2502
2361
  });
2503
2362
  inputArea.addEventListener('dragleave', function (e) {
2504
- return _this20.handleDragLeave(e);
2363
+ return _this21.handleDragLeave(e);
2505
2364
  });
2506
2365
  inputArea.addEventListener('drop', function (e) {
2507
- return _this20.handleDrop(e);
2366
+ return _this21.handleDrop(e);
2508
2367
  });
2509
2368
  }
2510
2369
  }
@@ -2512,55 +2371,55 @@ window.openAIChatManager = function () {
2512
2371
 
2513
2372
  // Pause auto-scroll when the user manually scrolls up during streaming.
2514
2373
  this.chatContainer.addEventListener('scroll', function () {
2515
- if (!_this20.stream) {
2374
+ if (!_this21.stream) {
2516
2375
  return;
2517
2376
  }
2518
2377
  var threshold = 30;
2519
- var atBottom = _this20.chatContainer.scrollHeight - _this20.chatContainer.clientHeight - _this20.chatContainer.scrollTop <= threshold;
2520
- _this20.autoScroll = atBottom;
2378
+ var atBottom = _this21.chatContainer.scrollHeight - _this21.chatContainer.clientHeight - _this21.chatContainer.scrollTop <= threshold;
2379
+ _this21.autoScroll = atBottom;
2521
2380
  });
2522
2381
  this.inputElement.addEventListener('keydown', function (event) {
2523
- if (_this20.stream != null) {
2382
+ if (_this21.stream != null) {
2524
2383
  return;
2525
2384
  }
2526
2385
  if (event.key === "Enter" && !event.shiftKey) {
2527
2386
  event.preventDefault();
2528
- _this20.buttonElement.click();
2387
+ _this21.buttonElement.click();
2529
2388
  }
2530
2389
  });
2531
2390
  this.inputElement.addEventListener('input', function (e) {
2532
- _this20.handleUserInput(e);
2391
+ _this21.handleUserInput(e);
2533
2392
  if (e.target.value.trim()) {
2534
- _this20.buttonElement.removeAttribute('disabled');
2393
+ _this21.buttonElement.removeAttribute('disabled');
2535
2394
  } else {
2536
- _this20.buttonElement.setAttribute('disabled', true);
2395
+ _this21.buttonElement.setAttribute('disabled', true);
2537
2396
  }
2538
2397
  });
2539
2398
  this.buttonElement.addEventListener('click', function () {
2540
- if (_this20.stream != null) {
2541
- _this20.stream.dispose();
2542
- _this20.stream = null;
2543
- _this20.streamingFinished();
2544
- _this20.hideTypingIndicator();
2399
+ if (_this21.stream != null) {
2400
+ _this21.stream.dispose();
2401
+ _this21.stream = null;
2402
+ _this21.streamingFinished();
2403
+ _this21.hideTypingIndicator();
2545
2404
 
2546
2405
  // Clean up: remove empty assistant message or stop streaming animation.
2547
- if (_this20.messages.length > 0) {
2548
- var lastMsg = _this20.messages[_this20.messages.length - 1];
2406
+ if (_this21.messages.length > 0) {
2407
+ var lastMsg = _this21.messages[_this21.messages.length - 1];
2549
2408
  if (lastMsg.role === 'assistant' && !lastMsg.content) {
2550
- _this20.messages.pop();
2409
+ _this21.messages.pop();
2551
2410
  } else if (lastMsg.isStreaming) {
2552
2411
  lastMsg.isStreaming = false;
2553
2412
  }
2554
2413
  }
2555
2414
  return;
2556
2415
  }
2557
- _this20.sendMessage();
2416
+ _this21.sendMessage();
2558
2417
  });
2559
2418
  var promptGenerators = document.getElementsByClassName('profile-generated-prompt');
2560
2419
  for (var i = 0; i < promptGenerators.length; i++) {
2561
2420
  promptGenerators[i].addEventListener('click', function (e) {
2562
2421
  e.preventDefault();
2563
- _this20.generatePrompt(e.target);
2422
+ _this21.generatePrompt(e.target);
2564
2423
  });
2565
2424
  }
2566
2425
  var chatSessions = document.getElementsByClassName('chat-session-history-item');
@@ -2572,8 +2431,8 @@ window.openAIChatManager = function () {
2572
2431
  console.error('an element with the class chat-session-history-item with no data-session-id set.');
2573
2432
  return;
2574
2433
  }
2575
- _this20.loadSession(sessionId);
2576
- _this20.showChatScreen();
2434
+ _this21.loadSession(sessionId);
2435
+ _this21.showChatScreen();
2577
2436
  });
2578
2437
  }
2579
2438
  for (var _i5 = 0; _i5 < config.messages.length; _i5++) {
@@ -2582,7 +2441,7 @@ window.openAIChatManager = function () {
2582
2441
 
2583
2442
  // Update feedback icons in the DOM after initial messages have rendered.
2584
2443
  this.$nextTick(function () {
2585
- _this20.refreshAllFeedbackIcons();
2444
+ _this21.refreshAllFeedbackIcons();
2586
2445
  });
2587
2446
 
2588
2447
  // Delegate click for code block copy buttons.
@@ -2600,9 +2459,9 @@ window.openAIChatManager = function () {
2600
2459
  if (codeEl) {
2601
2460
  navigator.clipboard.writeText(codeEl.textContent);
2602
2461
  var copiedText = config.codeCopiedText || 'Copied!';
2603
- btn.innerHTML = '<span class="fa-solid fa-check"></span> ' + copiedText;
2462
+ btn.innerHTML = '<i class="fa-solid fa-check"></i> ' + copiedText;
2604
2463
  setTimeout(function () {
2605
- btn.innerHTML = '<span class="fa-regular fa-copy"></span>';
2464
+ btn.innerHTML = '<i class="fa-regular fa-copy"></i>';
2606
2465
  }, 2000);
2607
2466
  }
2608
2467
  });
@@ -2614,7 +2473,7 @@ window.openAIChatManager = function () {
2614
2473
  if (this.micButton) {
2615
2474
  this.micButton.style.display = '';
2616
2475
  this.micButton.addEventListener('click', function () {
2617
- _this20.toggleRecording();
2476
+ _this21.toggleRecording();
2618
2477
  });
2619
2478
  }
2620
2479
  }
@@ -2624,10 +2483,11 @@ window.openAIChatManager = function () {
2624
2483
  this.conversationButton = document.querySelector(config.conversationButtonElementSelector);
2625
2484
  if (this.conversationButton) {
2626
2485
  this.conversationButton.addEventListener('click', function () {
2627
- _this20.toggleConversationMode();
2486
+ _this21.toggleConversationMode();
2628
2487
  });
2629
2488
  }
2630
2489
  }
2490
+ return true;
2631
2491
  },
2632
2492
  loadSession: function loadSession(sessionId) {
2633
2493
  this.connection.invoke("LoadSession", sessionId)["catch"](function (err) {
@@ -2642,6 +2502,9 @@ window.openAIChatManager = function () {
2642
2502
  },
2643
2503
  initializeSession: function initializeSession(sessionId, force) {
2644
2504
  if (this.isSessionStarted && !force) {
2505
+ if (sessionId && this.getSessionId() === sessionId) {
2506
+ this.resolvePendingSessionRequest(sessionId);
2507
+ }
2645
2508
  return;
2646
2509
  }
2647
2510
  this.fireEvent(new CustomEvent("initializingSessionOpenAIChat", {
@@ -2651,121 +2514,22 @@ window.openAIChatManager = function () {
2651
2514
  }));
2652
2515
  this.setSessionId(sessionId);
2653
2516
  this.isSessionStarted = true;
2654
- if (this.widgetIsInitialized) {
2655
- localStorage.setItem(this.chatWidgetStateSession, sessionId);
2656
- }
2657
- },
2658
- initializeWidget: function initializeWidget() {
2659
- var _this21 = this;
2660
- if (!config.widget.chatWidgetContainer) {
2661
- console.error('The widget chatWidgetContainer is required.');
2662
- return;
2663
- }
2664
- if (!config.widget.chatWidgetStateName) {
2665
- console.error('The widget chatWidgetStateName is required.');
2666
- return;
2667
- }
2668
- var chatWidgetContainer = document.querySelector(config.widget.chatWidgetContainer);
2669
- if (!chatWidgetContainer) {
2670
- return;
2671
- }
2672
- if (config.widget.chatHistorySection) {
2673
- this.chatHistorySection = document.querySelector(config.widget.chatHistorySection);
2674
- }
2675
- this.chatWidgetStateName = config.widget.chatWidgetStateName;
2676
- this.chatWidgetStateSession = config.widget.chatWidgetStateName + 'Session';
2677
- this.chatWidgetLayoutKey = config.widget.chatWidgetStateName + 'Layout';
2678
- this.widgetContainerElement = chatWidgetContainer;
2679
- this.widgetToggleButtonElement = config.widget.toggleButtonSelector ? document.querySelector(config.widget.toggleButtonSelector) : null;
2680
- this.widgetResetSizeButtonElement = config.widget.resetSizeButtonSelector ? document.querySelector(config.widget.resetSizeButtonSelector) : null;
2681
- this.widgetDefaultWidth = parsePixelValue(config.widget.defaultWidth) || parsePixelValue(window.getComputedStyle(chatWidgetContainer).width) || 380;
2682
- this.widgetDefaultHeight = parsePixelValue(config.widget.defaultHeight) || parsePixelValue(window.getComputedStyle(chatWidgetContainer).height) || 520;
2683
- this.widgetIsInitialized = true;
2684
- if (config.widget.enableResizing) {
2685
- chatWidgetContainer.classList.add('ai-chat-widget-resizable');
2686
- chatWidgetContainer.style.minWidth = (parsePixelValue(config.widget.minWidth) || 320) + 'px';
2687
- chatWidgetContainer.style.minHeight = (parsePixelValue(config.widget.minHeight) || 420) + 'px';
2688
- if (typeof ResizeObserver !== 'undefined') {
2689
- this.widgetResizeObserver = new ResizeObserver(function () {
2690
- _this21.persistWidgetPanelSize();
2691
- _this21.constrainWidgetElementsToViewport();
2692
- _this21.updateWidgetResetSizeButtonVisibility();
2693
- });
2694
- this.widgetResizeObserver.observe(chatWidgetContainer);
2695
- }
2696
- }
2697
- var dragHandleSelector = config.widget.dragHandleSelector || '.ai-chat-widget-header';
2698
- var dragHandle = chatWidgetContainer.querySelector(dragHandleSelector);
2699
- if (config.widget.enableDragging && dragHandle) {
2700
- dragHandle.classList.add('ai-chat-widget-drag-handle');
2701
- chatWidgetContainer.classList.add('ai-chat-widget-draggable');
2702
- this.attachDraggableWidgetElement(chatWidgetContainer, dragHandle, 'panel', false);
2703
- }
2704
- if (config.widget.enableDragging && this.widgetToggleButtonElement) {
2705
- this.widgetToggleButtonElement.classList.add('ai-chat-widget-draggable');
2706
- this.attachDraggableWidgetElement(this.widgetToggleButtonElement, this.widgetToggleButtonElement, 'toggle', true);
2707
- }
2708
- if (this.widgetResetSizeButtonElement) {
2709
- this.widgetResetSizeButtonElement.addEventListener('click', function (event) {
2710
- event.preventDefault();
2711
- _this21.resetWidgetSize();
2712
- });
2713
- }
2714
- this.restoreWidgetLayout();
2715
- if (!this.widgetViewportResizeHandler) {
2716
- this.widgetViewportResizeHandler = function () {
2717
- _this21.constrainWidgetElementsToViewport();
2718
- _this21.updateWidgetResetSizeButtonVisibility();
2719
- };
2720
- window.addEventListener('resize', this.widgetViewportResizeHandler);
2517
+ this.resolvePendingSessionRequest(sessionId);
2518
+ if (widgetBehavior && typeof widgetBehavior.onSessionInitialized === 'function') {
2519
+ widgetBehavior.onSessionInitialized(this, sessionId, config);
2721
2520
  }
2722
-
2723
- // Auto-load the last session so the user always sees previous chat history.
2724
- this.reloadCurrentSession();
2725
- if (config.autoCreateSession && !this.getSessionId()) {
2726
- this.startNewSession();
2727
- }
2728
- if (config.widget.showHistoryButton && this.chatHistorySection) {
2729
- var showHistoryButton = document.querySelector(config.widget.showHistoryButton);
2730
- if (showHistoryButton) {
2731
- showHistoryButton.addEventListener('click', function () {
2732
- _this21.chatHistorySection.classList.toggle('show');
2733
- });
2734
- }
2735
- if (config.widget.closeHistoryButton) {
2736
- var closeHistoryButton = document.querySelector(config.widget.closeHistoryButton);
2737
- if (closeHistoryButton) {
2738
- closeHistoryButton.addEventListener('click', function () {
2739
- _this21.showChatScreen();
2740
- });
2741
- }
2742
- }
2743
- }
2744
- if (config.widget.newChatButton) {
2745
- var newChatButton = document.querySelector(config.widget.newChatButton);
2746
- if (newChatButton) {
2747
- newChatButton.addEventListener('click', function () {
2748
- _this21.resetSession();
2749
- _this21.showChatScreen();
2750
- });
2751
- }
2752
- }
2753
- },
2754
- showChatScreen: function showChatScreen() {
2755
- if (!this.chatHistorySection) {
2756
- return;
2757
- }
2758
- this.chatHistorySection.classList.remove('show');
2759
2521
  },
2760
2522
  getSessionId: function getSessionId() {
2761
- var sessionId = this.inputElement.getAttribute('data-session-id');
2762
- if (!sessionId && this.widgetIsInitialized) {
2763
- sessionId = localStorage.getItem(this.chatWidgetStateSession);
2523
+ var sessionId = this.inputElement ? this.inputElement.getAttribute('data-session-id') : null;
2524
+ if (!sessionId && widgetBehavior && typeof widgetBehavior.resolveSessionId === 'function') {
2525
+ sessionId = widgetBehavior.resolveSessionId(this, config);
2764
2526
  }
2765
2527
  return sessionId;
2766
2528
  },
2767
2529
  copyResponse: function copyResponse(message) {
2768
- navigator.clipboard.writeText(message);
2530
+ var _ref17, _message$copyContent;
2531
+ 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 : '';
2532
+ navigator.clipboard.writeText(text);
2769
2533
  },
2770
2534
  updateFeedbackIcons: function updateFeedbackIcons(container, userRating) {
2771
2535
  if (!container) {
@@ -2844,12 +2608,18 @@ window.openAIChatManager = function () {
2844
2608
  documents: {
2845
2609
  handler: function handler() {
2846
2610
  this.renderDocumentBar();
2611
+ if (widgetBehavior && typeof widgetBehavior.onDocumentsChanged === 'function') {
2612
+ widgetBehavior.onDocumentsChanged(this, this.documents, config);
2613
+ }
2847
2614
  },
2848
2615
  deep: true
2849
2616
  },
2850
2617
  isUploading: function isUploading() {
2851
2618
  this.renderDocumentBar();
2852
2619
  },
2620
+ isDocumentOperationPending: function isDocumentOperationPending() {
2621
+ this.renderDocumentBar();
2622
+ },
2853
2623
  isPlayingAudio: function isPlayingAudio() {
2854
2624
  // Reserved for future use — volume-based interrupt detection
2855
2625
  // no longer mutes tracks; browser echo cancellation handles echo.
@@ -2876,21 +2646,26 @@ window.openAIChatManager = function () {
2876
2646
  },
2877
2647
  mounted: function mounted() {
2878
2648
  var _this22 = this;
2879
- _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
2880
- return _regenerator().w(function (_context6) {
2881
- while (1) switch (_context6.n) {
2649
+ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
2650
+ var isInitialized;
2651
+ return _regenerator().w(function (_context0) {
2652
+ while (1) switch (_context0.n) {
2882
2653
  case 0:
2883
- _context6.n = 1;
2654
+ _context0.n = 1;
2884
2655
  return _this22.startConnection();
2885
2656
  case 1:
2886
- _this22.initializeApp();
2887
- if (hasWidgetConfig) {
2888
- _this22.initializeWidget();
2657
+ isInitialized = _this22.initializeApp();
2658
+ if (isInitialized && hasWidgetConfig && widgetBehavior && typeof widgetBehavior.onMounted === 'function') {
2659
+ widgetBehavior.onMounted(_this22, config);
2889
2660
  }
2661
+ _this22.$nextTick(function () {
2662
+ refreshFontAwesomeIcons(_this22.$el);
2663
+ _this22.fontAwesomeObserver = observeFontAwesomeIcons(_this22.$el);
2664
+ });
2890
2665
  case 2:
2891
- return _context6.a(2);
2666
+ return _context0.a(2);
2892
2667
  }
2893
- }, _callee6);
2668
+ }, _callee0);
2894
2669
  }))();
2895
2670
  window.addEventListener('beforeunload', this.handleBeforeUnload);
2896
2671
  window.addEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
@@ -2898,6 +2673,10 @@ window.openAIChatManager = function () {
2898
2673
  beforeUnmount: function beforeUnmount() {
2899
2674
  window.removeEventListener('beforeunload', this.handleBeforeUnload);
2900
2675
  window.removeEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
2676
+ if (this.fontAwesomeObserver) {
2677
+ this.fontAwesomeObserver.disconnect();
2678
+ this.fontAwesomeObserver = null;
2679
+ }
2901
2680
  this.stopAudio(false);
2902
2681
  if (this.stream) {
2903
2682
  this.stream.dispose();
@@ -2906,9 +2685,16 @@ window.openAIChatManager = function () {
2906
2685
  if (this.connection) {
2907
2686
  this.connection.stop();
2908
2687
  }
2688
+ if (widgetBehavior && typeof widgetBehavior.onBeforeUnmount === 'function') {
2689
+ widgetBehavior.onBeforeUnmount(this, config);
2690
+ }
2909
2691
  },
2910
2692
  template: config.messageTemplate
2911
- }).mount(config.appElementSelector);
2693
+ };
2694
+ var app = Vue.createApp(appDefinition).mount(config.appElementSelector);
2695
+ if (widgetBehavior && typeof widgetBehavior.attach === 'function') {
2696
+ widgetBehavior.attach(app, config);
2697
+ }
2912
2698
  return app;
2913
2699
  };
2914
2700
  return {