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

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.
Files changed (35) hide show
  1. package/dist/ai-chat-widget.js +962 -0
  2. package/dist/ai-chat-widget.js.map +1 -0
  3. package/dist/ai-chat-widget.min.js +2 -0
  4. package/dist/ai-chat-widget.min.js.map +1 -0
  5. package/dist/ai-chat.css +45 -14
  6. package/dist/ai-chat.css.map +1 -1
  7. package/dist/ai-chat.js +1076 -1019
  8. package/dist/ai-chat.js.map +1 -1
  9. package/dist/ai-chat.min.css +1 -1
  10. package/dist/ai-chat.min.js +1 -1
  11. package/dist/ai-chat.min.js.map +1 -1
  12. package/dist/chat-interaction-settings.js +297 -0
  13. package/dist/chat-interaction-settings.js.map +1 -0
  14. package/dist/chat-interaction-settings.min.js +2 -0
  15. package/dist/chat-interaction-settings.min.js.map +1 -0
  16. package/dist/chat-interaction.js +1224 -325
  17. package/dist/chat-interaction.js.map +1 -1
  18. package/dist/chat-interaction.min.js +1 -1
  19. package/dist/chat-interaction.min.js.map +1 -1
  20. package/dist/chat-widget.css +48 -26
  21. package/dist/chat-widget.css.map +1 -1
  22. package/dist/chat-widget.min.css +1 -1
  23. package/dist/document-drop-zone.css +10 -10
  24. package/dist/document-drop-zone.css.map +1 -1
  25. package/dist/document-drop-zone.js +92 -14
  26. package/dist/document-drop-zone.js.map +1 -1
  27. package/dist/document-drop-zone.min.css +1 -1
  28. package/dist/document-drop-zone.min.js +1 -1
  29. package/dist/document-drop-zone.min.js.map +1 -1
  30. package/dist/technical-name-generator.js +36 -8
  31. package/dist/technical-name-generator.js.map +1 -1
  32. package/dist/technical-name-generator.min.js +1 -1
  33. package/dist/technical-name-generator.min.js.map +1 -1
  34. package/package.json +9 -1
  35. package/README.md +0 -145
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; } }
@@ -19,7 +22,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
19
22
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
20
23
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
21
24
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
22
- window.openAIChatManager = function () {
25
+ window.coreAIChatManager = function () {
23
26
  // Defaults (can be overridden by instanceConfig)
24
27
  var defaultConfig = {
25
28
  // UI defaults for generated media
@@ -33,7 +36,9 @@ window.openAIChatManager = function () {
33
36
  thumbsUpTitle: 'Thumbs up',
34
37
  thumbsDownTitle: 'Thumbs down',
35
38
  copyTitle: 'Click here to copy response to clipboard.',
39
+ copiedTitle: 'Response copied to clipboard.',
36
40
  codeCopiedText: 'Copied!',
41
+ copyResetDelayMs: 2000,
37
42
  widget: {
38
43
  chatWidgetContainer: null,
39
44
  chatWidgetStateName: null,
@@ -52,8 +57,8 @@ window.openAIChatManager = function () {
52
57
  minWidth: 320,
53
58
  minHeight: 420
54
59
  },
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 "
60
+ messageTemplate: "\n <div class=\"ai-chat-messages\">\n <div v-for=\"(message, index) in messages\" :key=\"'msg-' + index\" class=\"ai-chat-message-item\">\n <div>\n <div v-if=\"message.role === 'user'\" class=\"ai-chat-msg-role ai-chat-msg-role-user\">{{ userLabel }}</div>\n <div v-else-if=\"message.role !== 'indicator'\" :class=\"getAssistantRoleClasses(message)\">\n <span :class=\"getAssistantIconClasses(message, index)\"><i :class=\"getAssistantIcon(message)\"></i></span>\n {{ getAssistantLabel(message) }}\n </div>\n <div class=\"ai-chat-message-body lh-base\">\n <h4 v-if=\"message.title\">{{ message.title }}</h4>\n <div v-html=\"message.htmlContent\"></div>\n <ol v-if=\"message.citationReferences && message.citationReferences.length\" class=\"ai-chat-citation-list\">\n <li v-for=\"citation in message.citationReferences\" :key=\"'citation-' + (citation.referenceKey || citation.displayIndex)\" class=\"ai-chat-citation-item\">\n <a v-if=\"citation.link\" :href=\"citation.link\" :target=\"citation.isDownload ? null : '_blank'\" :rel=\"citation.isDownload ? null : 'noopener noreferrer'\">{{ citation.label }}</a>\n <span v-else>{{ citation.label }}</span>\n </li>\n </ol>\n <span class=\"message-buttons-container\" v-if=\"!isIndicator(message)\">\n <template v-if=\"metricsEnabled && message.role === 'assistant'\">\n <span class=\"ai-chat-message-assistant-feedback\" :data-message-id=\"message.id\">\n <button type=\"button\" class=\"btn btn-sm btn-link text-success p-0 me-2 button-message-toolbox rate-up-btn\" @click=\"rateMessage(message, true, $event)\" :title=\"thumbsUpTitle\">\n <i class=\"fa-regular fa-thumbs-up\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-sm btn-link text-danger p-0 me-2 button-message-toolbox rate-down-btn\" @click=\"rateMessage(message, false, $event)\" :title=\"thumbsDownTitle\">\n <i class=\"fa-regular fa-thumbs-down\"></i>\n </button>\n </span>\n </template>\n <button type=\"button\" v-if=\"textToSpeechEnabled && !isConversationMode && message.role === 'assistant' && !message.isStreaming\" class=\"btn btn-sm btn-link text-secondary p-0 me-1 button-message-toolbox\" :class=\"{ 'tts-playing': ttsPlayingMessageIndex === index }\" :data-tts-message-index=\"index\" @click=\"toggleMessageTts(message, index)\" :title=\"ttsPlayingMessageIndex === index ? 'Pause audio' : 'Read aloud'\">\n <span :class=\"ttsPlayingMessageIndex === index ? 'fa-solid fa-circle-pause' : 'fa-solid fa-circle-play'\"></span>\n </button>\n <button type=\"button\" class=\"btn btn-sm btn-link p-0 button-message-toolbox ai-response-copy-btn\" :class=\"copiedMessageIndex === index ? 'text-success' : 'text-secondary'\" :data-copy-message-index=\"index\" @click=\"copyResponse(message, index, $event)\" :title=\"copiedMessageIndex === index ? copiedTitle : copyTitle\">\n <i :class=\"copiedMessageIndex === index ? 'fa-solid fa-check' : 'fa-solid fa-copy'\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n <div v-for=\"notification in notifications\" :key=\"'notif-' + notification.type\" class=\"ai-chat-notification\" :class=\"'ai-chat-notification-' + (notification.type || 'info') + ' ' + (notification.cssClass || '')\">\n <div class=\"ai-chat-notification-content\">\n <i v-if=\"notification.icon\" :class=\"notification.icon\" class=\"ai-chat-notification-icon\"></i>\n <span class=\"ai-chat-notification-text\">{{ notification.content }}</span>\n <button type=\"button\" v-if=\"notification.dismissible\" class=\"btn btn-sm btn-link p-0 ms-2 ai-chat-notification-dismiss\" @click=\"dismissNotification(notification.type)\" title=\"Dismiss\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div v-if=\"notification.actions && notification.actions.length\" class=\"ai-chat-notification-actions\">\n <button type=\"button\" v-for=\"action in notification.actions\" :key=\"action.name\" class=\"btn btn-sm\" :class=\"action.cssClass || 'btn-outline-secondary'\" @click=\"handleNotificationAction(notification.type, action.name)\">\n <i v-if=\"action.icon\" :class=\"action.icon\" class=\"me-1\"></i>\n {{ action.label }}\n </button>\n </div>\n </div>\n </div>\n ",
61
+ 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
62
  };
58
63
 
59
64
  // Sanitize URLs to prevent javascript: protocol injection.
@@ -72,6 +77,42 @@ window.openAIChatManager = function () {
72
77
  span.textContent = text;
73
78
  return span.innerHTML;
74
79
  }
80
+ function containsFontAwesomePlaceholders(root) {
81
+ if (!root || root.nodeType !== 1) {
82
+ return false;
83
+ }
84
+ var selector = 'i[class*="fa-"],i.fa,i.fas,i.far,i.fab';
85
+ if (typeof root.matches === 'function' && root.matches(selector)) {
86
+ return true;
87
+ }
88
+ return typeof root.querySelector === 'function' && !!root.querySelector(selector);
89
+ }
90
+ function refreshFontAwesomeIcons(root) {
91
+ var fontAwesome = window.FontAwesome;
92
+ if (!containsFontAwesomePlaceholders(root) || !fontAwesome || !fontAwesome.dom || typeof fontAwesome.dom.i2svg !== 'function') {
93
+ return;
94
+ }
95
+ fontAwesome.dom.i2svg({
96
+ node: root
97
+ });
98
+ }
99
+ function observeFontAwesomeIcons(root) {
100
+ if (!root || typeof MutationObserver === 'undefined') {
101
+ return null;
102
+ }
103
+ var observer = new MutationObserver(function (mutations) {
104
+ mutations.forEach(function (mutation) {
105
+ mutation.addedNodes.forEach(function (node) {
106
+ refreshFontAwesomeIcons(node);
107
+ });
108
+ });
109
+ });
110
+ observer.observe(root, {
111
+ childList: true,
112
+ subtree: true
113
+ });
114
+ return observer;
115
+ }
75
116
  function parsePixelValue(value) {
76
117
  if (typeof value === 'number' && Number.isFinite(value)) {
77
118
  return value;
@@ -86,16 +127,31 @@ window.openAIChatManager = function () {
86
127
  return Math.min(Math.max(value, min), max);
87
128
  }
88
129
  function normalizeReference(reference) {
89
- var _ref, _normalized$index, _ref2, _normalized$text, _ref3, _normalized$link;
130
+ var _ref, _normalized$index, _ref2, _normalized$text, _ref3, _normalized$title, _ref4, _normalized$link, _ref5, _normalized$reference, _normalized$isGenerat;
90
131
  if (!reference || _typeof(reference) !== 'object') {
91
132
  return null;
92
133
  }
93
134
  var normalized = Object.assign({}, reference);
94
135
  normalized.index = (_ref = (_normalized$index = normalized.index) !== null && _normalized$index !== void 0 ? _normalized$index : normalized.Index) !== null && _ref !== void 0 ? _ref : 0;
95
136
  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;
137
+ normalized.title = (_ref3 = (_normalized$title = normalized.title) !== null && _normalized$title !== void 0 ? _normalized$title : normalized.Title) !== null && _ref3 !== void 0 ? _ref3 : null;
138
+ normalized.link = sanitizeUrl((_ref4 = (_normalized$link = normalized.link) !== null && _normalized$link !== void 0 ? _normalized$link : normalized.Link) !== null && _ref4 !== void 0 ? _ref4 : null);
139
+ normalized.referenceType = (_ref5 = (_normalized$reference = normalized.referenceType) !== null && _normalized$reference !== void 0 ? _normalized$reference : normalized.ReferenceType) !== null && _ref5 !== void 0 ? _ref5 : null;
140
+ normalized.isGenerated = ((_normalized$isGenerat = normalized.isGenerated) !== null && _normalized$isGenerat !== void 0 ? _normalized$isGenerat : normalized.IsGenerated) === true;
97
141
  return normalized;
98
142
  }
143
+ function isDownloadCitationReference(reference) {
144
+ if (!reference || _typeof(reference) !== 'object') {
145
+ return false;
146
+ }
147
+ if (typeof reference.referenceType === 'string' && reference.referenceType.toLowerCase() === 'document') {
148
+ return true;
149
+ }
150
+ if (typeof reference.link === 'string' && /\/ai\/documents\/.+\/download(?:$|\?)/i.test(reference.link)) {
151
+ return true;
152
+ }
153
+ return false;
154
+ }
99
155
  function normalizeReferences(references) {
100
156
  if (!references || _typeof(references) !== 'object') {
101
157
  return {};
@@ -110,6 +166,164 @@ window.openAIChatManager = function () {
110
166
  }
111
167
  return normalized;
112
168
  }
169
+ function getCitationLabel(reference, key) {
170
+ return reference.title || reference.text || key;
171
+ }
172
+ function buildCitationDisplay(content, references) {
173
+ var processedContent = (content || '').trim();
174
+ var messageReferences = normalizeReferences(references);
175
+ var referenceEntries = Object.entries(messageReferences);
176
+ if (!referenceEntries.length) {
177
+ return {
178
+ content: processedContent,
179
+ citations: []
180
+ };
181
+ }
182
+ var citedRefs = referenceEntries.filter(function (_ref6) {
183
+ var _ref7 = _slicedToArray(_ref6, 1),
184
+ key = _ref7[0];
185
+ return processedContent.includes(key);
186
+ });
187
+ var generatedRefs = referenceEntries.filter(function (_ref8) {
188
+ var _ref9 = _slicedToArray(_ref8, 2),
189
+ key = _ref9[0],
190
+ value = _ref9[1];
191
+ return value.isGenerated && !processedContent.includes(key);
192
+ });
193
+ if (!citedRefs.length && !generatedRefs.length) {
194
+ return {
195
+ content: processedContent,
196
+ citations: []
197
+ };
198
+ }
199
+ citedRefs.sort(function (_ref0, _ref1) {
200
+ var _ref10 = _slicedToArray(_ref0, 2),
201
+ a = _ref10[1];
202
+ var _ref11 = _slicedToArray(_ref1, 2),
203
+ b = _ref11[1];
204
+ return a.index - b.index;
205
+ });
206
+ generatedRefs.sort(function (_ref12, _ref13) {
207
+ var _ref14 = _slicedToArray(_ref12, 2),
208
+ a = _ref14[1];
209
+ var _ref15 = _slicedToArray(_ref13, 2),
210
+ b = _ref15[1];
211
+ return a.index - b.index;
212
+ });
213
+ var citations = [];
214
+ var displayIndex = 1;
215
+ var _iterator = _createForOfIteratorHelper(citedRefs),
216
+ _step;
217
+ try {
218
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
219
+ var _step$value = _slicedToArray(_step.value, 2),
220
+ key = _step$value[0],
221
+ value = _step$value[1];
222
+ var placeholder = "__CITE_".concat(displayIndex, "_").concat(value.index || displayIndex, "__");
223
+ processedContent = processedContent.replaceAll(key, placeholder);
224
+ citations.push({
225
+ referenceKey: key,
226
+ displayIndex: displayIndex,
227
+ label: getCitationLabel(value, key),
228
+ link: value.link || null,
229
+ isDownload: isDownloadCitationReference(value),
230
+ placeholder: placeholder
231
+ });
232
+ displayIndex++;
233
+ }
234
+ } catch (err) {
235
+ _iterator.e(err);
236
+ } finally {
237
+ _iterator.f();
238
+ }
239
+ for (var _i2 = 0, _citations = citations; _i2 < _citations.length; _i2++) {
240
+ var citation = _citations[_i2];
241
+ processedContent = processedContent.replaceAll(citation.placeholder, "<sup>".concat(citation.displayIndex, "</sup>"));
242
+ }
243
+ processedContent = processedContent.replaceAll('</sup><sup>', '</sup><sup>,</sup><sup>');
244
+
245
+ // Generated files (such as exported tabular data) are always offered as a download even when
246
+ // the model does not cite them inline, so the user never loses access to the produced file.
247
+ var _iterator2 = _createForOfIteratorHelper(generatedRefs),
248
+ _step2;
249
+ try {
250
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
251
+ var _step2$value = _slicedToArray(_step2.value, 2),
252
+ _key = _step2$value[0],
253
+ _value = _step2$value[1];
254
+ citations.push({
255
+ referenceKey: _key,
256
+ displayIndex: displayIndex,
257
+ label: getCitationLabel(_value, _key),
258
+ link: _value.link || null,
259
+ isDownload: true,
260
+ placeholder: null
261
+ });
262
+ displayIndex++;
263
+ }
264
+ } catch (err) {
265
+ _iterator2.e(err);
266
+ } finally {
267
+ _iterator2.f();
268
+ }
269
+ return {
270
+ content: processedContent,
271
+ citations: citations.map(function (_ref16) {
272
+ var placeholder = _ref16.placeholder,
273
+ citation = _objectWithoutProperties(_ref16, _excluded);
274
+ return citation;
275
+ })
276
+ };
277
+ }
278
+ function buildCopyContent(content, citations) {
279
+ var copyContent = (content || '').trim();
280
+ if (!copyContent || !Array.isArray(citations) || citations.length === 0) {
281
+ return copyContent;
282
+ }
283
+ var _iterator3 = _createForOfIteratorHelper(citations),
284
+ _step3;
285
+ try {
286
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
287
+ var citation = _step3.value;
288
+ copyContent = copyContent.replaceAll(citation.referenceKey, "[".concat(citation.displayIndex, "]"));
289
+ }
290
+ } catch (err) {
291
+ _iterator3.e(err);
292
+ } finally {
293
+ _iterator3.f();
294
+ }
295
+ copyContent += '\n\nReferences:\n';
296
+ var _iterator4 = _createForOfIteratorHelper(citations),
297
+ _step4;
298
+ try {
299
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
300
+ var _citation = _step4.value;
301
+ copyContent += "".concat(_citation.displayIndex, ". ").concat(_citation.label);
302
+ if (_citation.link) {
303
+ copyContent += " - ".concat(_citation.link);
304
+ }
305
+ copyContent += '\n';
306
+ }
307
+ } catch (err) {
308
+ _iterator4.e(err);
309
+ } finally {
310
+ _iterator4.f();
311
+ }
312
+ return copyContent.trimEnd();
313
+ }
314
+ function updateMessagePresentation(message, references) {
315
+ var messageReferences = normalizeReferences(references !== null && references !== void 0 ? references : message.references);
316
+ var rawContent = typeof message.rawContent === 'string' ? message.rawContent : typeof message.content === 'string' ? message.content : '';
317
+ var citationDisplay = buildCitationDisplay(rawContent, messageReferences);
318
+ message.rawContent = rawContent;
319
+ message.content = rawContent;
320
+ message.displayContent = citationDisplay.content;
321
+ message.references = messageReferences;
322
+ message.citationReferences = citationDisplay.citations;
323
+ message.copyContent = buildCopyContent(rawContent, citationDisplay.citations);
324
+ message.htmlContent = parseMarkdownContent(citationDisplay.content, message);
325
+ return message;
326
+ }
113
327
  var renderer = new marked.Renderer();
114
328
 
115
329
  // Modify the link rendering to open in a new tab
@@ -140,7 +354,7 @@ window.openAIChatManager = function () {
140
354
  highlighted = escapeHtmlEntities(code);
141
355
  }
142
356
  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>");
357
+ 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
358
  };
145
359
 
146
360
  // Custom image renderer for generated images with thumbnail styling and download button.
@@ -150,7 +364,7 @@ window.openAIChatManager = function () {
150
364
  if (!src) return '';
151
365
  var alt = data.text || defaultConfig.generatedImageAltText;
152
366
  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>");
367
+ 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
368
  };
155
369
 
156
370
  // Chart counter for unique IDs
@@ -164,7 +378,7 @@ window.openAIChatManager = function () {
164
378
  // its DOM update to render charts it didn't create itself.
165
379
  window.__chartConfigs = window.__chartConfigs || {};
166
380
  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>";
381
+ 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
382
  }
169
383
 
170
384
  // Register [chart:{...json...}] as a native marked block extension so the
@@ -275,17 +489,17 @@ window.openAIChatManager = function () {
275
489
  // Defer to requestAnimationFrame so the browser has fully laid out the
276
490
  // canvas elements before Chart.js reads their dimensions.
277
491
  requestAnimationFrame(function () {
278
- var _iterator = _createForOfIteratorHelper(charts),
279
- _step;
492
+ var _iterator5 = _createForOfIteratorHelper(charts),
493
+ _step5;
280
494
  try {
281
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
282
- var c = _step.value;
495
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
496
+ var c = _step5.value;
283
497
  renderChartOnCanvas(c.chartId, c.config);
284
498
  }
285
499
  } catch (err) {
286
- _iterator.e(err);
500
+ _iterator5.e(err);
287
501
  } finally {
288
- _iterator.f();
502
+ _iterator5.f();
289
503
  }
290
504
  });
291
505
  }
@@ -338,8 +552,8 @@ window.openAIChatManager = function () {
338
552
  return;
339
553
  }
340
554
  requestAnimationFrame(function () {
341
- for (var _i2 = 0, _Object$keys = Object.keys(configs); _i2 < _Object$keys.length; _i2++) {
342
- var chartId = _Object$keys[_i2];
555
+ for (var _i3 = 0, _Object$keys = Object.keys(configs); _i3 < _Object$keys.length; _i3++) {
556
+ var chartId = _Object$keys[_i3];
343
557
  renderChartOnCanvas(chartId, configs[chartId]);
344
558
  }
345
559
  });
@@ -359,10 +573,23 @@ window.openAIChatManager = function () {
359
573
  ADD_ATTR: ['target']
360
574
  });
361
575
  }
576
+ function compactObject(source) {
577
+ if (!source || _typeof(source) !== 'object') {
578
+ return {};
579
+ }
580
+ return Object.fromEntries(Object.entries(source).filter(function (_ref17) {
581
+ var _ref18 = _slicedToArray(_ref17, 2),
582
+ value = _ref18[1];
583
+ return value !== undefined;
584
+ }));
585
+ }
362
586
  var initialize = function initialize(instanceConfig) {
363
- var config = Object.assign({}, defaultConfig, instanceConfig);
364
- config.widget = Object.assign({}, defaultConfig.widget || {}, instanceConfig && instanceConfig.widget ? instanceConfig.widget : {});
365
- var hasWidgetConfig = !!(instanceConfig && instanceConfig.widget && instanceConfig.widget.chatWidgetContainer && instanceConfig.widget.chatWidgetStateName);
587
+ var normalizedInstanceConfig = compactObject(instanceConfig);
588
+ var normalizedWidgetConfig = compactObject(normalizedInstanceConfig.widget);
589
+ var config = Object.assign({}, defaultConfig, normalizedInstanceConfig);
590
+ config.widget = Object.assign({}, defaultConfig.widget || {}, normalizedWidgetConfig);
591
+ var hasWidgetConfig = !!(normalizedWidgetConfig.chatWidgetContainer && normalizedWidgetConfig.chatWidgetStateName);
592
+ var widgetBehavior = window.coreAIChatWidgetBehavior || null;
366
593
  // Keep defaultConfig in sync so renderers use overridden values
367
594
  defaultConfig = config;
368
595
  if (!config.signalRHubUrl) {
@@ -385,7 +612,7 @@ window.openAIChatManager = function () {
385
612
  console.error('The sendButtonElementSelector is required.');
386
613
  return;
387
614
  }
388
- var app = Vue.createApp({
615
+ var appDefinition = {
389
616
  data: function data() {
390
617
  return {
391
618
  inputElement: null,
@@ -394,18 +621,6 @@ window.openAIChatManager = function () {
394
621
  placeholder: null,
395
622
  isSessionStarted: false,
396
623
  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
624
  isStreaming: false,
410
625
  isNavigatingAway: false,
411
626
  autoScroll: true,
@@ -415,6 +630,8 @@ window.openAIChatManager = function () {
415
630
  prompt: '',
416
631
  documents: config.existingDocuments || [],
417
632
  isUploading: false,
633
+ isDocumentOperationPending: false,
634
+ documentOperationQueue: null,
418
635
  uploadErrors: [],
419
636
  isDragOver: false,
420
637
  documentBar: null,
@@ -424,6 +641,7 @@ window.openAIChatManager = function () {
424
641
  thumbsUpTitle: config.thumbsUpTitle,
425
642
  thumbsDownTitle: config.thumbsDownTitle,
426
643
  copyTitle: config.copyTitle,
644
+ copiedTitle: config.copiedTitle,
427
645
  isRecording: false,
428
646
  mediaRecorder: null,
429
647
  preRecordingPrompt: '',
@@ -444,7 +662,14 @@ window.openAIChatManager = function () {
444
662
  conversationModeEnabled: config.chatMode === 'Conversation',
445
663
  conversationButton: null,
446
664
  isConversationMode: false,
447
- notificationDismissTimers: {}
665
+ notificationDismissTimers: {},
666
+ pendingSessionPromise: null,
667
+ pendingSessionResolver: null,
668
+ pendingSessionRejector: null,
669
+ pendingSessionTimeoutId: null,
670
+ copiedMessageIndex: -1,
671
+ copyResetTimeoutId: null,
672
+ activeCopyButton: null
448
673
  };
449
674
  },
450
675
  computed: {
@@ -461,336 +686,6 @@ window.openAIChatManager = function () {
461
686
  handleBeforeUnload: function handleBeforeUnload() {
462
687
  this.isNavigatingAway = true;
463
688
  },
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
689
  handleDragOver: function handleDragOver(e) {
795
690
  if (!config.sessionDocumentsEnabled) return;
796
691
  e.preventDefault();
@@ -815,180 +710,272 @@ window.openAIChatManager = function () {
815
710
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
816
711
  if (inputArea) inputArea.classList.remove('ai-chat-drag-over');
817
712
  if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
818
- this.uploadFiles(e.dataTransfer.files);
713
+ this.uploadFiles(Array.from(e.dataTransfer.files));
819
714
  }
820
715
  },
821
716
  triggerFileInput: function triggerFileInput() {
822
- if (!config.sessionDocumentsEnabled) return;
717
+ if (!config.sessionDocumentsEnabled || this.isDocumentOperationPending) return;
823
718
  var fileInput = document.getElementById('ai-chat-doc-input');
824
719
  if (fileInput) fileInput.click();
825
720
  },
826
721
  handleFileInputChange: function handleFileInputChange(e) {
827
- var files = e.target.files;
722
+ var files = e.target.files ? Array.from(e.target.files) : [];
828
723
  if (files && files.length > 0) {
829
724
  this.uploadFiles(files);
830
725
  }
831
726
  e.target.value = '';
832
727
  },
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;
728
+ queueDocumentOperation: function queueDocumentOperation(operation) {
729
+ var self = this;
730
+ var previousOperation = this.documentOperationQueue || Promise.resolve();
731
+ var nextOperation = previousOperation["catch"](function () {}).then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
837
732
  return _regenerator().w(function (_context) {
838
733
  while (1) switch (_context.p = _context.n) {
734
+ case 0:
735
+ self.isDocumentOperationPending = true;
736
+ _context.p = 1;
737
+ _context.n = 2;
738
+ return operation();
739
+ case 2:
740
+ return _context.a(2, _context.v);
741
+ case 3:
742
+ _context.p = 3;
743
+ self.isDocumentOperationPending = false;
744
+ return _context.f(3);
745
+ case 4:
746
+ return _context.a(2);
747
+ }
748
+ }, _callee, null, [[1,, 3, 4]]);
749
+ })));
750
+ this.documentOperationQueue = nextOperation["finally"](function () {
751
+ if (self.documentOperationQueue === nextOperation) {
752
+ self.documentOperationQueue = null;
753
+ }
754
+ });
755
+ return this.documentOperationQueue;
756
+ },
757
+ uploadFiles: function uploadFiles(files) {
758
+ var _this = this;
759
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
760
+ var filesToUpload;
761
+ return _regenerator().w(function (_context3) {
762
+ while (1) switch (_context3.n) {
839
763
  case 0:
840
764
  if (config.uploadDocumentUrl) {
841
- _context.n = 1;
765
+ _context3.n = 1;
842
766
  break;
843
767
  }
844
- return _context.a(2);
768
+ return _context3.a(2);
845
769
  case 1:
846
- sessionId = _this2.getSessionId();
847
- profileId = _this2.getProfileId();
848
- if (!(!sessionId && !profileId)) {
849
- _context.n = 2;
770
+ filesToUpload = Array.isArray(files) ? files.slice() : Array.from(files || []);
771
+ if (!(filesToUpload.length === 0)) {
772
+ _context3.n = 2;
850
773
  break;
851
774
  }
852
- console.warn('Cannot upload documents without a session or profile.');
853
- return _context.a(2);
775
+ return _context3.a(2);
854
776
  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);
777
+ return _context3.a(2, _this.queueDocumentOperation(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
778
+ var sessionId, profileId, formData, i, response, errorText, uploadError, result, _t, _t2;
779
+ return _regenerator().w(function (_context2) {
780
+ while (1) switch (_context2.p = _context2.n) {
781
+ case 0:
782
+ sessionId = _this.getSessionId();
783
+ profileId = _this.getProfileId();
784
+ if (sessionId) {
785
+ _context2.n = 4;
786
+ break;
787
+ }
788
+ _context2.p = 1;
789
+ _context2.n = 2;
790
+ return _this.ensureSessionForDocuments(profileId);
791
+ case 2:
792
+ sessionId = _context2.v;
793
+ _context2.n = 4;
794
+ break;
795
+ case 3:
796
+ _context2.p = 3;
797
+ _t = _context2.v;
798
+ console.error('Failed to create a chat session for document upload:', _t);
799
+ _this.uploadErrors = [{
800
+ fileName: '',
801
+ error: 'Could not create a chat session for the upload.'
802
+ }];
803
+ _this.renderDocumentBar();
804
+ return _context2.a(2);
805
+ case 4:
806
+ if (sessionId) {
807
+ _context2.n = 5;
808
+ break;
809
+ }
810
+ console.warn('Cannot upload documents without a session or profile.');
811
+ _this.uploadErrors = [{
812
+ fileName: '',
813
+ error: 'Could not create a chat session for the upload.'
814
+ }];
815
+ _this.renderDocumentBar();
816
+ return _context2.a(2);
817
+ case 5:
818
+ _this.isUploading = true;
819
+ _this.uploadErrors = [];
820
+ _this.renderDocumentBar();
821
+ _context2.p = 6;
822
+ formData = new FormData();
823
+ formData.append('sessionId', sessionId);
824
+ for (i = 0; i < filesToUpload.length; i++) {
825
+ formData.append('files', filesToUpload[i]);
826
+ }
827
+ _context2.n = 7;
828
+ return fetch(config.uploadDocumentUrl, {
829
+ method: 'POST',
830
+ body: formData
831
+ });
832
+ case 7:
833
+ response = _context2.v;
834
+ if (response.ok) {
835
+ _context2.n = 9;
836
+ break;
837
+ }
838
+ _context2.n = 8;
839
+ return response.text();
840
+ case 8:
841
+ errorText = _context2.v;
842
+ uploadError = _this.extractReadableErrorMessage(errorText, 'Upload failed. Please try again.');
843
+ console.error('Upload failed:', errorText);
844
+ _this.uploadErrors = [{
845
+ fileName: '',
846
+ error: uploadError
847
+ }];
848
+ return _context2.a(2);
849
+ case 9:
850
+ _context2.n = 10;
851
+ return response.json();
852
+ case 10:
853
+ result = _context2.v;
854
+ if (result.sessionId && result.sessionId !== _this.getSessionId()) {
855
+ _this.initializeSession(result.sessionId);
856
+ }
857
+ if (Array.isArray(result.documents)) {
858
+ _this.documents = result.documents;
859
+ } else if (result.uploaded && result.uploaded.length > 0) {
860
+ _this.documents = _this.documents.concat(result.uploaded);
861
+ }
862
+ if (result.failed && result.failed.length > 0) {
863
+ _this.uploadErrors = result.failed;
864
+ }
865
+ _context2.n = 12;
866
+ break;
867
+ case 11:
868
+ _context2.p = 11;
869
+ _t2 = _context2.v;
870
+ console.error('Upload error:', _t2);
871
+ _this.uploadErrors = [{
872
+ fileName: '',
873
+ error: 'Upload failed. Please try again.'
874
+ }];
875
+ if (_this.getSessionId()) {
876
+ _this.reloadCurrentSession();
877
+ }
878
+ case 12:
879
+ _context2.p = 12;
880
+ _this.isUploading = false;
881
+ _this.renderDocumentBar();
882
+ return _context2.f(12);
883
+ case 13:
884
+ return _context2.a(2);
885
+ }
886
+ }, _callee2, null, [[6, 11, 12, 13], [1, 3]]);
887
+ }))));
924
888
  }
925
- }, _callee, null, [[3, 8, 9, 10]]);
889
+ }, _callee3);
926
890
  }))();
927
891
  },
928
892
  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) {
893
+ var _this2 = this;
894
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
895
+ return _regenerator().w(function (_context5) {
896
+ while (1) switch (_context5.n) {
934
897
  case 0:
935
898
  if (config.removeDocumentUrl) {
936
- _context2.n = 1;
899
+ _context5.n = 1;
937
900
  break;
938
901
  }
939
- return _context2.a(2);
902
+ return _context5.a(2);
940
903
  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);
904
+ return _context5.a(2, _this2.queueDocumentOperation(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
905
+ var sessionId, response, result, idx, errorText, removeError, _t3;
906
+ return _regenerator().w(function (_context4) {
907
+ while (1) switch (_context4.p = _context4.n) {
908
+ case 0:
909
+ _context4.p = 0;
910
+ sessionId = _this2.getSessionId();
911
+ _context4.n = 1;
912
+ return fetch(config.removeDocumentUrl, {
913
+ method: 'POST',
914
+ headers: {
915
+ 'Content-Type': 'application/json'
916
+ },
917
+ body: JSON.stringify({
918
+ itemId: sessionId,
919
+ documentId: doc.documentId
920
+ })
921
+ });
922
+ case 1:
923
+ response = _context4.v;
924
+ if (!response.ok) {
925
+ _context4.n = 3;
926
+ break;
927
+ }
928
+ _context4.n = 2;
929
+ return response.json();
930
+ case 2:
931
+ result = _context4.v;
932
+ if (Array.isArray(result.documents)) {
933
+ _this2.documents = result.documents;
934
+ } else {
935
+ idx = _this2.documents.indexOf(doc);
936
+ if (idx > -1) {
937
+ _this2.documents.splice(idx, 1);
938
+ }
939
+ }
940
+ _context4.n = 5;
941
+ break;
942
+ case 3:
943
+ _context4.n = 4;
944
+ return response.text();
945
+ case 4:
946
+ errorText = _context4.v;
947
+ removeError = _this2.extractReadableErrorMessage(errorText, 'Failed to remove document. Please try again.');
948
+ console.error('Failed to remove document:', response.status, errorText);
949
+ _this2.uploadErrors = [{
950
+ fileName: doc.fileName || '',
951
+ error: removeError
952
+ }];
953
+ if (sessionId) {
954
+ _this2.reloadCurrentSession();
955
+ }
956
+ _this2.renderDocumentBar();
957
+ case 5:
958
+ _context4.n = 7;
959
+ break;
960
+ case 6:
961
+ _context4.p = 6;
962
+ _t3 = _context4.v;
963
+ console.error('Remove document error:', _t3);
964
+ _this2.uploadErrors = [{
965
+ fileName: doc.fileName || '',
966
+ error: 'Failed to remove document. Please try again.'
967
+ }];
968
+ if (_this2.getSessionId()) {
969
+ _this2.reloadCurrentSession();
970
+ }
971
+ _this2.renderDocumentBar();
972
+ case 7:
973
+ return _context4.a(2);
974
+ }
975
+ }, _callee4, null, [[0, 6]]);
976
+ }))));
990
977
  }
991
- }, _callee2, null, [[1, 6]]);
978
+ }, _callee5);
992
979
  }))();
993
980
  },
994
981
  formatFileSize: function formatFileSize(bytes) {
@@ -1010,9 +997,9 @@ window.openAIChatManager = function () {
1010
997
  var name = doc.fileName || 'Document';
1011
998
  if (name.length > 20) name = name.substring(0, 17) + '...';
1012
999
  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> ';
1000
+ html += '<i class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></i> ';
1014
1001
  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>';
1002
+ 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
1003
  html += '</span>';
1017
1004
  }
1018
1005
  for (var m = 0; m < this.uploadErrors.length; m++) {
@@ -1021,7 +1008,7 @@ window.openAIChatManager = function () {
1021
1008
  var errorMsg = failedItem.error || 'Upload failed';
1022
1009
  if (failedName.length > 15) failedName = failedName.substring(0, 12) + '...';
1023
1010
  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> ';
1011
+ html += '<i class="fa-solid fa-circle-exclamation" style="font-size: 0.7rem;"></i> ';
1025
1012
  html += this.escapeHtml(failedName);
1026
1013
  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
1014
  html += '</span>';
@@ -1031,8 +1018,8 @@ window.openAIChatManager = function () {
1031
1018
  html += '<span class="spinner-border spinner-border-sm" style="width: 0.7rem; height: 0.7rem;"></span> Uploading...';
1032
1019
  html += '</span>';
1033
1020
  }
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>';
1021
+ 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' : '') + '>';
1022
+ html += '<i class="fa-solid fa-paperclip"></i>';
1036
1023
  if (this.documents.length === 0 && !this.isUploading) {
1037
1024
  html += ' <span>Attach files</span>';
1038
1025
  }
@@ -1054,6 +1041,9 @@ window.openAIChatManager = function () {
1054
1041
  return function (e) {
1055
1042
  e.preventDefault();
1056
1043
  e.stopPropagation();
1044
+ if (self.isDocumentOperationPending) {
1045
+ return;
1046
+ }
1057
1047
  var docToRemove = self.documents[idx];
1058
1048
  if (docToRemove) self.removeDocument(docToRemove);
1059
1049
  };
@@ -1078,6 +1068,9 @@ window.openAIChatManager = function () {
1078
1068
  if (addBtn) {
1079
1069
  addBtn.addEventListener('click', function (e) {
1080
1070
  e.preventDefault();
1071
+ if (self.isDocumentOperationPending) {
1072
+ return;
1073
+ }
1081
1074
  self.triggerFileInput();
1082
1075
  });
1083
1076
  }
@@ -1154,139 +1147,135 @@ window.openAIChatManager = function () {
1154
1147
  return !!message && message.isStreaming && index === this.lastAssistantIndex && !(appearance && appearance.disableStreamingAnimation);
1155
1148
  },
1156
1149
  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) {
1150
+ var _this3 = this;
1151
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
1152
+ var _t4;
1153
+ return _regenerator().w(function (_context6) {
1154
+ while (1) switch (_context6.p = _context6.n) {
1162
1155
  case 0:
1163
- _this4.connection = new signalR.HubConnectionBuilder().withUrl(config.signalRHubUrl).withAutomaticReconnect().build();
1156
+ _this3.connection = new signalR.HubConnectionBuilder().withUrl(config.signalRHubUrl).withAutomaticReconnect().build();
1164
1157
 
1165
1158
  // Allow long-running operations (e.g., multi-step MCP tool calls)
1166
1159
  // without the client disconnecting prematurely.
1167
- _this4.connection.serverTimeoutInMilliseconds = 600000;
1168
- _this4.connection.keepAliveIntervalInMilliseconds = 15000;
1169
- _this4.connection.on("LoadSession", function (data) {
1160
+ _this3.connection.serverTimeoutInMilliseconds = 600000;
1161
+ _this3.connection.keepAliveIntervalInMilliseconds = 15000;
1162
+ _this3.connection.on("LoadSession", function (data) {
1170
1163
  var _data$messages;
1171
- _this4.initializeSession(data.sessionId, true);
1172
- _this4.messages = [];
1173
- _this4.documents = data.documents || [];
1164
+ _this3.initializeSession(data.sessionId, true);
1165
+ _this3.messages = [];
1166
+ _this3.documents = data.documents || [];
1167
+ _this3.uploadErrors = [];
1174
1168
  ((_data$messages = data.messages) !== null && _data$messages !== void 0 ? _data$messages : []).forEach(function (msg) {
1175
- _this4.addMessage(msg);
1176
- _this4.$nextTick(function () {
1169
+ _this3.addMessage(msg);
1170
+ _this3.$nextTick(function () {
1177
1171
  renderChartsInMessage(msg);
1178
1172
  });
1179
1173
  });
1180
1174
 
1181
1175
  // Update feedback icons in the DOM after all messages have rendered.
1182
- _this4.$nextTick(function () {
1183
- _this4.refreshAllFeedbackIcons();
1176
+ _this3.$nextTick(function () {
1177
+ _this3.refreshAllFeedbackIcons();
1184
1178
  });
1185
1179
 
1186
1180
  // When the session is new (no messages) and an initial prompt is configured,
1187
1181
  // 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();
1182
+ if (_this3.messages.length === 0 && config.initialPrompt) {
1183
+ _this3.prompt = config.initialPrompt;
1184
+ _this3.sendMessage();
1191
1185
  }
1192
1186
  });
1193
- _this4.connection.on("ReceiveError", function (error) {
1187
+ _this3.connection.on("ReceiveError", function (error) {
1194
1188
  console.error("SignalR Error: ", error);
1195
- if (_this4.isRecording) {
1196
- _this4.stopRecording();
1189
+ if (_this3.isRecording) {
1190
+ _this3.stopRecording();
1197
1191
  }
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();
1192
+ if (widgetBehavior && typeof widgetBehavior.handleReceiveError === 'function') {
1193
+ widgetBehavior.handleReceiveError(_this3, error, config);
1205
1194
  }
1206
1195
  });
1207
- _this4.connection.on("MessageRated", function (messageId, userRating) {
1208
- var msg = _this4.messages.find(function (m) {
1196
+ _this3.connection.on("MessageRated", function (messageId, userRating) {
1197
+ var msg = _this3.messages.find(function (m) {
1209
1198
  return m.id === messageId;
1210
1199
  });
1211
1200
  if (msg) {
1212
1201
  msg.userRating = userRating;
1213
1202
  }
1214
1203
  });
1215
- _this4.connection.on("ReceiveTranscript", function (sessionId, text, isFinal) {
1216
- if (_this4.isConversationMode) {
1204
+ _this3.connection.on("ReceiveTranscript", function (sessionId, text, isFinal) {
1205
+ if (_this3.isConversationMode) {
1217
1206
  if (!isFinal && text) {
1218
- _this4._conversationPartialTranscript = text;
1207
+ _this3._conversationPartialTranscript = text;
1219
1208
  var escaped = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1220
1209
  var html = '<p class="ai-partial-transcript">' + escaped + '</p>';
1221
1210
 
1222
1211
  // Show partial transcript as a live user message.
1223
- if (!_this4._conversationPartialMessage) {
1224
- _this4.hidePlaceholder();
1225
- _this4._conversationPartialMessage = {
1212
+ if (!_this3._conversationPartialMessage) {
1213
+ _this3.hidePlaceholder();
1214
+ _this3._conversationPartialMessage = {
1226
1215
  role: 'user',
1227
1216
  content: text,
1228
1217
  htmlContent: html,
1229
1218
  isPartial: true
1230
1219
  };
1231
- _this4.messages.push(_this4._conversationPartialMessage);
1220
+ _this3.messages.push(_this3._conversationPartialMessage);
1232
1221
  } else {
1233
- _this4._conversationPartialMessage.content = text;
1234
- _this4._conversationPartialMessage.htmlContent = html;
1222
+ _this3._conversationPartialMessage.content = text;
1223
+ _this3._conversationPartialMessage.htmlContent = html;
1235
1224
  }
1236
- _this4.scrollToBottom();
1225
+ _this3.scrollToBottom();
1237
1226
  }
1238
1227
  return;
1239
1228
  }
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'));
1229
+ if (text && !_this3._audioInputSent) {
1230
+ _this3.prompt = _this3.preRecordingPrompt + text;
1231
+ if (_this3.inputElement) {
1232
+ _this3.inputElement.value = _this3.prompt;
1233
+ _this3.inputElement.dispatchEvent(new Event('input'));
1245
1234
  }
1246
1235
  }
1247
1236
  });
1248
- _this4.connection.on("ReceiveConversationUserMessage", function (sessionId, text) {
1237
+ _this3.connection.on("ReceiveConversationUserMessage", function (sessionId, text) {
1249
1238
  if (text) {
1250
- _this4.stopAudio();
1239
+ _this3.stopAudio();
1251
1240
 
1252
1241
  // If there's an interrupted assistant message still streaming,
1253
1242
  // mark it as done to stop the spinner animation.
1254
- if (_this4._conversationAssistantMessage) {
1255
- var oldMsg = _this4.messages[_this4._conversationAssistantMessage.index];
1243
+ if (_this3._conversationAssistantMessage) {
1244
+ var oldMsg = _this3.messages[_this3._conversationAssistantMessage.index];
1256
1245
  if (oldMsg) {
1257
1246
  oldMsg.isStreaming = false;
1258
1247
  }
1259
- _this4._conversationAssistantMessage = null;
1248
+ _this3._conversationAssistantMessage = null;
1260
1249
  }
1261
1250
 
1262
1251
  // Replace the partial transcript message with the final one.
1263
- if (_this4._conversationPartialMessage) {
1252
+ if (_this3._conversationPartialMessage) {
1264
1253
  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;
1254
+ _this3._conversationPartialMessage.content = text;
1255
+ _this3._conversationPartialMessage.htmlContent = '<p>' + escaped + '</p>';
1256
+ _this3._conversationPartialMessage.isPartial = false;
1257
+ _this3._conversationPartialMessage = null;
1269
1258
  } else {
1270
- _this4.addMessage({
1259
+ _this3.addMessage({
1271
1260
  role: 'user',
1272
1261
  content: text
1273
1262
  });
1274
1263
  }
1275
- _this4.scrollToBottom();
1264
+ _this3.scrollToBottom();
1276
1265
  }
1277
1266
  });
1278
- _this4.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, appearance) {
1279
- if (!_this4._conversationAssistantMessage) {
1280
- _this4.stopAudio();
1281
- _this4.hideTypingIndicator();
1267
+ _this3.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, references, appearance) {
1268
+ if (!_this3._conversationAssistantMessage) {
1269
+ _this3.stopAudio();
1270
+ _this3.hideTypingIndicator();
1282
1271
 
1283
1272
  // 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;
1273
+ for (var j = 0; j < _this3.messages.length; j++) {
1274
+ if (_this3.messages[j].isStreaming) {
1275
+ _this3.messages[j].isStreaming = false;
1287
1276
  }
1288
1277
  }
1289
- var msgIndex = _this4.messages.length;
1278
+ var msgIndex = _this3.messages.length;
1290
1279
  var newMessage = {
1291
1280
  id: messageId,
1292
1281
  role: "assistant",
@@ -1294,110 +1283,114 @@ window.openAIChatManager = function () {
1294
1283
  htmlContent: "",
1295
1284
  isStreaming: true,
1296
1285
  userRating: null,
1297
- appearance: _this4.normalizeAssistantAppearance(appearance)
1286
+ appearance: _this3.normalizeAssistantAppearance(appearance),
1287
+ references: {}
1298
1288
  };
1299
- _this4.messages.push(newMessage);
1300
- _this4._conversationAssistantMessage = {
1289
+ _this3.messages.push(newMessage);
1290
+ _this3._conversationAssistantMessage = {
1301
1291
  index: msgIndex,
1302
1292
  content: ''
1303
1293
  };
1304
1294
  }
1305
- _this4._conversationAssistantMessage.content += token;
1306
- var msg = _this4.messages[_this4._conversationAssistantMessage.index];
1295
+ _this3._conversationAssistantMessage.content += token;
1296
+ var msg = _this3.messages[_this3._conversationAssistantMessage.index];
1307
1297
  if (msg) {
1308
1298
  if (!msg.appearance) {
1309
- msg.appearance = _this4.normalizeAssistantAppearance(appearance);
1299
+ msg.appearance = _this3.normalizeAssistantAppearance(appearance);
1310
1300
  }
1311
- msg.content = _this4._conversationAssistantMessage.content;
1312
- msg.htmlContent = parseMarkdownContent(msg.content, msg);
1313
- _this4.$nextTick(function () {
1301
+ msg.rawContent = _this3._conversationAssistantMessage.content;
1302
+ msg.references = normalizeReferences(Object.assign({}, msg.references || {}, references || {}));
1303
+ updateMessagePresentation(msg, msg.references);
1304
+ _this3.$nextTick(function () {
1314
1305
  renderChartsInMessage(msg);
1315
- _this4.scrollToBottom();
1306
+ _this3.scrollToBottom();
1316
1307
  });
1317
1308
  }
1318
1309
  });
1319
- _this4.connection.on("ReceiveConversationAssistantComplete", function (sessionId, messageId) {
1320
- if (_this4._conversationAssistantMessage) {
1321
- var msg = _this4.messages[_this4._conversationAssistantMessage.index];
1310
+ _this3.connection.on("ReceiveConversationAssistantComplete", function (sessionId, messageId, references) {
1311
+ if (_this3._conversationAssistantMessage) {
1312
+ var msg = _this3.messages[_this3._conversationAssistantMessage.index];
1322
1313
  if (msg) {
1323
1314
  msg.isStreaming = false;
1315
+ msg.references = normalizeReferences(Object.assign({}, msg.references || {}, references || {}));
1316
+ updateMessagePresentation(msg, msg.references);
1324
1317
  }
1325
- _this4._conversationAssistantMessage = null;
1318
+ _this3._conversationAssistantMessage = null;
1326
1319
  }
1327
1320
  });
1328
- _this4.connection.on("ReceiveAudioChunk", function (sessionId, base64Audio, contentType) {
1321
+ _this3.connection.on("ReceiveAudioChunk", function (sessionId, base64Audio, contentType) {
1329
1322
  if (base64Audio) {
1330
1323
  var binaryString = atob(base64Audio);
1331
1324
  var bytes = new Uint8Array(binaryString.length);
1332
1325
  for (var i = 0; i < binaryString.length; i++) {
1333
1326
  bytes[i] = binaryString.charCodeAt(i);
1334
1327
  }
1335
- _this4.audioChunks.push(bytes);
1328
+ _this3.audioChunks.push(bytes);
1336
1329
  }
1337
1330
  });
1338
- _this4.connection.on("ReceiveAudioComplete", function (sessionId) {
1339
- _this4.playCollectedAudio();
1331
+ _this3.connection.on("ReceiveAudioComplete", function (sessionId) {
1332
+ _this3.playCollectedAudio();
1340
1333
  });
1341
- _this4.connection.on("ReceiveNotification", function (notification) {
1342
- _this4.receiveNotification(notification);
1334
+ _this3.connection.on("ReceiveNotification", function (notification) {
1335
+ _this3.receiveNotification(notification);
1343
1336
  });
1344
- _this4.connection.on("UpdateNotification", function (notification) {
1345
- _this4.updateNotification(notification);
1337
+ _this3.connection.on("UpdateNotification", function (notification) {
1338
+ _this3.updateNotification(notification);
1346
1339
  });
1347
- _this4.connection.on("RemoveNotification", function (notificationType) {
1348
- _this4.removeNotification(notificationType);
1340
+ _this3.connection.on("RemoveNotification", function (notificationType) {
1341
+ _this3.removeNotification(notificationType);
1349
1342
  });
1350
- _this4.connection.onreconnecting(function () {
1343
+ _this3.connection.onreconnecting(function () {
1351
1344
  console.warn("SignalR: reconnecting...");
1352
1345
  });
1353
- _this4.connection.onreconnected(function () {
1346
+ _this3.connection.onreconnected(function () {
1354
1347
  console.info("SignalR: reconnected.");
1355
- if (_this4.isSessionStarted) {
1356
- _this4.reloadCurrentSession();
1348
+ if (_this3.isSessionStarted) {
1349
+ _this3.reloadCurrentSession();
1357
1350
  } else if (config.autoCreateSession) {
1358
- _this4.startNewSession();
1351
+ _this3.startNewSession();
1359
1352
  }
1360
1353
  });
1361
- _this4.connection.onclose(function (error) {
1362
- if (_this4.isNavigatingAway) {
1354
+ _this3.connection.onclose(function (error) {
1355
+ if (_this3.isNavigatingAway) {
1363
1356
  return;
1364
1357
  }
1365
1358
  if (error) {
1366
1359
  console.warn("SignalR connection closed with error:", error.message || error);
1367
1360
  }
1368
1361
  });
1369
- _context3.p = 1;
1370
- _context3.n = 2;
1371
- return _this4.connection.start();
1362
+ _context6.p = 1;
1363
+ _context6.n = 2;
1364
+ return _this3.connection.start();
1372
1365
  case 2:
1373
- _context3.n = 4;
1366
+ _context6.n = 4;
1374
1367
  break;
1375
1368
  case 3:
1376
- _context3.p = 3;
1377
- _t3 = _context3.v;
1378
- console.error("SignalR Connection Error: ", _t3);
1369
+ _context6.p = 3;
1370
+ _t4 = _context6.v;
1371
+ console.error("SignalR Connection Error: ", _t4);
1379
1372
  case 4:
1380
- return _context3.a(2);
1373
+ return _context6.a(2);
1381
1374
  }
1382
- }, _callee3, null, [[1, 3]]);
1375
+ }, _callee6, null, [[1, 3]]);
1383
1376
  }))();
1384
1377
  },
1385
1378
  addMessageInternal: function addMessageInternal(message) {
1386
- var _this5 = this;
1379
+ var _this4 = this;
1387
1380
  if (message.role === 'assistant') {
1388
1381
  message.appearance = this.normalizeAssistantAppearance(message.appearance);
1389
1382
  }
1390
1383
  if (message.content && !message.htmlContent) {
1391
1384
  message.htmlContent = parseMarkdownContent(message.content, message);
1392
1385
  }
1393
- this.fireEvent(new CustomEvent("addingOpenAIPromotMessage", {
1386
+ this.fireEvent(new CustomEvent("addingCoreAIPromotMessage", {
1394
1387
  detail: {
1395
1388
  message: message
1396
1389
  }
1397
1390
  }));
1398
1391
  this.messages.push(message);
1399
1392
  this.$nextTick(function () {
1400
- _this5.fireEvent(new CustomEvent("addedOpenAIPromotMessage", {
1393
+ _this4.fireEvent(new CustomEvent("addedCoreAIPromotMessage", {
1401
1394
  detail: {
1402
1395
  message: message
1403
1396
  }
@@ -1405,105 +1398,32 @@ window.openAIChatManager = function () {
1405
1398
  });
1406
1399
  },
1407
1400
  addMessage: function addMessage(message) {
1408
- var _this6 = this;
1401
+ var _this5 = this;
1409
1402
  // Ensure userRating is always defined for Vue reactivity.
1410
1403
  if (message.userRating === undefined) {
1411
1404
  message.userRating = null;
1412
1405
  }
1413
1406
  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);
1407
+ var _message$rawContent;
1408
+ message.rawContent = (_message$rawContent = message.rawContent) !== null && _message$rawContent !== void 0 ? _message$rawContent : message.content;
1409
+ updateMessagePresentation(message, message.references);
1490
1410
  }
1491
1411
  this.addMessageInternal(message);
1492
1412
  this.hidePlaceholder();
1493
1413
  this.$nextTick(function () {
1494
1414
  // Render any pending charts once the DOM is updated
1495
1415
  renderChartsInMessage(message);
1496
- _this6.scrollToBottom();
1416
+ _this5.scrollToBottom();
1497
1417
  });
1498
1418
  },
1499
1419
  addMessages: function addMessages(messages) {
1500
- var _this7 = this;
1420
+ var _this6 = this;
1501
1421
  for (var i = 0; i < messages.length; i++) {
1502
1422
  this.addMessageInternal(messages[i]);
1503
1423
  }
1504
1424
  this.hidePlaceholder();
1505
1425
  this.$nextTick(function () {
1506
- _this7.scrollToBottom();
1426
+ _this6.scrollToBottom();
1507
1427
  });
1508
1428
  },
1509
1429
  hidePlaceholder: function hidePlaceholder() {
@@ -1580,7 +1500,7 @@ window.openAIChatManager = function () {
1580
1500
  this.prompt = '';
1581
1501
  },
1582
1502
  startRecording: function startRecording() {
1583
- var _this8 = this;
1503
+ var _this7 = this;
1584
1504
  if (this.isRecording || !this.connection) {
1585
1505
  return;
1586
1506
  }
@@ -1592,27 +1512,27 @@ window.openAIChatManager = function () {
1592
1512
  }
1593
1513
  }).then(function (stream) {
1594
1514
  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, {
1515
+ _this7.mediaRecorder = new MediaRecorder(stream, {
1596
1516
  mimeType: mimeType,
1597
1517
  audioBitsPerSecond: 128000
1598
1518
  });
1599
- _this8.preRecordingPrompt = _this8.prompt;
1600
- _this8._audioInputSent = false;
1519
+ _this7.preRecordingPrompt = _this7.prompt;
1520
+ _this7._audioInputSent = false;
1601
1521
  var subject = new signalR.Subject();
1602
- var profileId = _this8.getProfileId();
1603
- var sessionId = _this8.getSessionId() || '';
1522
+ var profileId = _this7.getProfileId();
1523
+ var sessionId = _this7.getSessionId() || '';
1604
1524
  var pendingChunk = Promise.resolve();
1605
- _this8.mediaRecorder.addEventListener('dataavailable', function (e) {
1525
+ _this7.mediaRecorder.addEventListener('dataavailable', function (e) {
1606
1526
  if (e.data && e.data.size > 0) {
1607
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
1527
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7() {
1608
1528
  var data, uint8Array, binaryString, base64;
1609
- return _regenerator().w(function (_context4) {
1610
- while (1) switch (_context4.n) {
1529
+ return _regenerator().w(function (_context7) {
1530
+ while (1) switch (_context7.n) {
1611
1531
  case 0:
1612
- _context4.n = 1;
1532
+ _context7.n = 1;
1613
1533
  return e.data.arrayBuffer();
1614
1534
  case 1:
1615
- data = _context4.v;
1535
+ data = _context7.v;
1616
1536
  uint8Array = new Uint8Array(data);
1617
1537
  binaryString = uint8Array.reduce(function (str, _byte) {
1618
1538
  return str + String.fromCharCode(_byte);
@@ -1620,13 +1540,13 @@ window.openAIChatManager = function () {
1620
1540
  base64 = btoa(binaryString);
1621
1541
  subject.next(base64);
1622
1542
  case 2:
1623
- return _context4.a(2);
1543
+ return _context7.a(2);
1624
1544
  }
1625
- }, _callee4);
1545
+ }, _callee7);
1626
1546
  })));
1627
1547
  }
1628
1548
  });
1629
- _this8.mediaRecorder.addEventListener('stop', function () {
1549
+ _this7.mediaRecorder.addEventListener('stop', function () {
1630
1550
  stream.getTracks().forEach(function (track) {
1631
1551
  return track.stop();
1632
1552
  });
@@ -1635,10 +1555,10 @@ window.openAIChatManager = function () {
1635
1555
  });
1636
1556
  });
1637
1557
  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();
1558
+ _this7.connection.send("SendAudioStream", profileId, sessionId, subject, mimeType, language);
1559
+ _this7.mediaRecorder.start(250);
1560
+ _this7.isRecording = true;
1561
+ _this7.updateMicButton();
1642
1562
  })["catch"](function (err) {
1643
1563
  console.error('Microphone access denied:', err);
1644
1564
  });
@@ -1664,14 +1584,14 @@ window.openAIChatManager = function () {
1664
1584
  }
1665
1585
  if (this.isRecording) {
1666
1586
  this.micButton.classList.add('stt-recording');
1667
- this.micButton.innerHTML = '<span class="fa-solid fa-stop"></span>';
1587
+ this.micButton.innerHTML = '<i class="fa-solid fa-stop"></i>';
1668
1588
  } else {
1669
1589
  this.micButton.classList.remove('stt-recording');
1670
- this.micButton.innerHTML = '<span class="fa-solid fa-microphone"></span>';
1590
+ this.micButton.innerHTML = '<i class="fa-solid fa-microphone"></i>';
1671
1591
  }
1672
1592
  },
1673
1593
  streamMessage: function streamMessage(profileId, trimmedPrompt, sessionProfileId) {
1674
- var _this9 = this;
1594
+ var _this8 = this;
1675
1595
  if (this.stream) {
1676
1596
  this.stream.dispose();
1677
1597
  this.stream = null;
@@ -1688,14 +1608,14 @@ window.openAIChatManager = function () {
1688
1608
  var currentSessionId = this.getSessionId();
1689
1609
  this.stream = this.connection.stream("SendMessage", profileId, trimmedPrompt, currentSessionId, sessionProfileId).subscribe({
1690
1610
  next: function next(chunk) {
1691
- var message = _this9.messages[messageIndex];
1611
+ var message = _this8.messages[messageIndex];
1692
1612
  if (!message) {
1693
1613
  if (chunk.sessionId && !currentSessionId) {
1694
- _this9.initializeSession(chunk.sessionId);
1614
+ _this8.initializeSession(chunk.sessionId);
1695
1615
  }
1696
- _this9.hideTypingIndicator();
1616
+ _this8.hideTypingIndicator();
1697
1617
  // Re-assign the index after hiding the typing indicator.
1698
- messageIndex = _this9.messages.length;
1618
+ messageIndex = _this8.messages.length;
1699
1619
  var newMessage = {
1700
1620
  id: chunk.messageId,
1701
1621
  role: "assistant",
@@ -1705,16 +1625,16 @@ window.openAIChatManager = function () {
1705
1625
  isStreaming: true,
1706
1626
  userRating: null
1707
1627
  };
1708
- _this9.messages.push(newMessage);
1628
+ _this8.messages.push(newMessage);
1709
1629
  message = newMessage;
1710
1630
  }
1711
1631
  if (chunk.title && (!message.title || message.title !== chunk.title)) {
1712
1632
  message.title = chunk.title;
1713
1633
  }
1714
1634
  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++) {
1635
+ for (var _i4 = 0, _Object$entries2 = Object.entries(chunk.references); _i4 < _Object$entries2.length; _i4++) {
1716
1636
  var _normalizeReference2;
1717
- var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i3], 2),
1637
+ var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i4], 2),
1718
1638
  key = _Object$entries2$_i[0],
1719
1639
  value = _Object$entries2$_i[1];
1720
1640
  references[key] = (_normalizeReference2 = normalizeReference(value)) !== null && _normalizeReference2 !== void 0 ? _normalizeReference2 : {};
@@ -1729,62 +1649,52 @@ window.openAIChatManager = function () {
1729
1649
  if (chunk.responseId) {
1730
1650
  lastResponseId = chunk.responseId;
1731
1651
  }
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>');
1652
+ content += chunk.content;
1743
1653
  }
1744
1654
 
1745
1655
  // Update the existing message
1746
- message.content = content;
1747
- message.htmlContent = parseMarkdownContent(content, message);
1748
- _this9.messages[messageIndex] = message;
1749
- _this9.$nextTick(function () {
1656
+ message.rawContent = content;
1657
+ updateMessagePresentation(message, references);
1658
+ _this8.messages[messageIndex] = message;
1659
+ _this8.$nextTick(function () {
1750
1660
  renderChartsInMessage(message);
1751
- _this9.scrollToBottom();
1661
+ _this8.scrollToBottom();
1752
1662
  });
1753
1663
  },
1754
1664
  complete: function complete() {
1755
- var _this9$stream;
1756
- _this9.processReferences(references, messageIndex);
1757
- _this9.streamingFinished();
1758
- var msg = _this9.messages[messageIndex];
1665
+ var _this8$stream;
1666
+ _this8.processReferences(references, messageIndex);
1667
+ _this8.streamingFinished();
1668
+ var msg = _this8.messages[messageIndex];
1759
1669
  if (msg) {
1760
1670
  msg.isStreaming = false;
1761
1671
  }
1762
1672
  if (!msg || !msg.content) {
1763
1673
  // No content received at all.
1764
- _this9.hideTypingIndicator();
1674
+ _this8.hideTypingIndicator();
1765
1675
  }
1766
1676
 
1767
1677
  // Trigger text-to-speech only in conversation mode.
1768
- if (_this9.isConversationMode && _this9.textToSpeechEnabled && msg && msg.content) {
1769
- _this9.synthesizeSpeech(msg.content);
1678
+ if (_this8.isConversationMode && _this8.textToSpeechEnabled && msg && msg.content) {
1679
+ _this8.synthesizeSpeech(msg.content);
1770
1680
  }
1771
- (_this9$stream = _this9.stream) === null || _this9$stream === void 0 || _this9$stream.dispose();
1772
- _this9.stream = null;
1681
+ (_this8$stream = _this8.stream) === null || _this8$stream === void 0 || _this8$stream.dispose();
1682
+ _this8.stream = null;
1773
1683
  },
1774
1684
  error: function error(err) {
1775
- var _this9$stream2;
1776
- _this9.processReferences(references, messageIndex);
1777
- _this9.streamingFinished();
1778
- var msg = _this9.messages[messageIndex];
1685
+ var _this8$stream2;
1686
+ _this8.processReferences(references, messageIndex);
1687
+ _this8.streamingFinished();
1688
+ var msg = _this8.messages[messageIndex];
1779
1689
  if (msg) {
1780
1690
  msg.isStreaming = false;
1781
1691
  }
1782
- _this9.hideTypingIndicator();
1783
- if (!_this9.isNavigatingAway) {
1784
- _this9.addMessage(_this9.getServiceDownMessage());
1692
+ _this8.hideTypingIndicator();
1693
+ if (!_this8.isNavigatingAway) {
1694
+ _this8.addMessage(_this8.getServiceDownMessage());
1785
1695
  }
1786
- (_this9$stream2 = _this9.stream) === null || _this9$stream2 === void 0 || _this9$stream2.dispose();
1787
- _this9.stream = null;
1696
+ (_this8$stream2 = _this8.stream) === null || _this8$stream2 === void 0 || _this8$stream2.dispose();
1697
+ _this8.stream = null;
1788
1698
  console.error("Stream error:", err);
1789
1699
  }
1790
1700
  });
@@ -1798,92 +1708,17 @@ window.openAIChatManager = function () {
1798
1708
  return newMessage;
1799
1709
  },
1800
1710
  processReferences: function processReferences(references, messageIndex) {
1801
- var _this0 = this;
1711
+ var _this9 = this;
1802
1712
  references = normalizeReferences(references);
1803
1713
  if (Object.keys(references).length) {
1714
+ var _ref23, _message$rawContent2;
1804
1715
  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);
1716
+ message.rawContent = (_ref23 = (_message$rawContent2 = message.rawContent) !== null && _message$rawContent2 !== void 0 ? _message$rawContent2 : message.content) !== null && _ref23 !== void 0 ? _ref23 : '';
1717
+ updateMessagePresentation(message, references);
1883
1718
  this.messages[messageIndex] = message;
1884
1719
  this.$nextTick(function () {
1885
1720
  renderChartsInMessage(message);
1886
- _this0.scrollToBottom();
1721
+ _this9.scrollToBottom();
1887
1722
  });
1888
1723
  }
1889
1724
  },
@@ -1934,22 +1769,48 @@ window.openAIChatManager = function () {
1934
1769
  this.stopAudio(false);
1935
1770
  },
1936
1771
  updateTtsPlaybackButtons: function updateTtsPlaybackButtons() {
1937
- var _this1 = this;
1772
+ var _this0 = this;
1938
1773
  if (!this.chatContainer) {
1939
1774
  return;
1940
1775
  }
1941
1776
  var buttons = this.chatContainer.querySelectorAll('[data-tts-message-index]');
1942
1777
  buttons.forEach(function (button) {
1943
1778
  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>';
1779
+ var isPlaying = buttonIndex === _this0.ttsPlayingMessageIndex;
1946
1780
  button.classList.toggle('tts-playing', isPlaying);
1947
1781
  button.setAttribute('title', isPlaying ? 'Pause audio' : 'Read aloud');
1782
+ });
1783
+ },
1784
+ updateCopyButtons: function updateCopyButtons() {
1785
+ var _this1 = this;
1786
+ if (!this.chatContainer) {
1787
+ return;
1788
+ }
1789
+ var buttons = this.chatContainer.querySelectorAll('[data-copy-message-index]');
1790
+ buttons.forEach(function (button) {
1791
+ var buttonIndex = Number(button.getAttribute('data-copy-message-index'));
1792
+ var isCopied = buttonIndex === _this1.copiedMessageIndex;
1793
+ var iconHtml = isCopied ? '<i class="fa-solid fa-check"></i>' : '<i class="fa-solid fa-copy"></i>';
1794
+ button.classList.toggle('text-success', isCopied);
1795
+ button.classList.toggle('text-secondary', !isCopied);
1796
+ button.setAttribute('title', isCopied ? _this1.copiedTitle : _this1.copyTitle);
1948
1797
  button.replaceChildren(DOMPurify.sanitize(iconHtml, {
1949
1798
  RETURN_DOM_FRAGMENT: true
1950
1799
  }));
1951
1800
  });
1952
1801
  },
1802
+ setCopyButtonState: function setCopyButtonState(button, isCopied) {
1803
+ if (!button) {
1804
+ return;
1805
+ }
1806
+ var iconHtml = isCopied ? '<i class="fa-solid fa-check"></i>' : '<i class="fa-solid fa-copy"></i>';
1807
+ button.classList.toggle('text-success', isCopied);
1808
+ button.classList.toggle('text-secondary', !isCopied);
1809
+ button.setAttribute('title', isCopied ? this.copiedTitle : this.copyTitle);
1810
+ button.replaceChildren(DOMPurify.sanitize(iconHtml, {
1811
+ RETURN_DOM_FRAGMENT: true
1812
+ }));
1813
+ },
1953
1814
  synthesizeSpeech: function synthesizeSpeech(text, cacheIndex) {
1954
1815
  var _this10 = this;
1955
1816
  if (!this.textToSpeechEnabled || !text || !this.connection) {
@@ -2007,18 +1868,18 @@ window.openAIChatManager = function () {
2007
1868
  }, 0);
2008
1869
  var combined = new Uint8Array(totalLength);
2009
1870
  var offset = 0;
2010
- var _iterator8 = _createForOfIteratorHelper(this.audioChunks),
2011
- _step8;
1871
+ var _iterator6 = _createForOfIteratorHelper(this.audioChunks),
1872
+ _step6;
2012
1873
  try {
2013
- for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
2014
- var chunk = _step8.value;
1874
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1875
+ var chunk = _step6.value;
2015
1876
  combined.set(chunk, offset);
2016
1877
  offset += chunk.length;
2017
1878
  }
2018
1879
  } catch (err) {
2019
- _iterator8.e(err);
1880
+ _iterator6.e(err);
2020
1881
  } finally {
2021
- _iterator8.f();
1882
+ _iterator6.f();
2022
1883
  }
2023
1884
  this.audioChunks = [];
2024
1885
  var blob = new Blob([combined], {
@@ -2173,15 +2034,15 @@ window.openAIChatManager = function () {
2173
2034
  // Always send audio to STT — browser echo cancellation
2174
2035
  // handles speaker echo; continuous audio avoids gaps
2175
2036
  // that increase recognition latency.
2176
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
2037
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
2177
2038
  var data, uint8Array, binaryString, base64;
2178
- return _regenerator().w(function (_context5) {
2179
- while (1) switch (_context5.n) {
2039
+ return _regenerator().w(function (_context8) {
2040
+ while (1) switch (_context8.n) {
2180
2041
  case 0:
2181
- _context5.n = 1;
2042
+ _context8.n = 1;
2182
2043
  return e.data.arrayBuffer();
2183
2044
  case 1:
2184
- data = _context5.v;
2045
+ data = _context8.v;
2185
2046
  uint8Array = new Uint8Array(data);
2186
2047
  binaryString = uint8Array.reduce(function (str, _byte2) {
2187
2048
  return str + String.fromCharCode(_byte2);
@@ -2193,9 +2054,9 @@ window.openAIChatManager = function () {
2193
2054
  // Subject may have been completed already.
2194
2055
  }
2195
2056
  case 2:
2196
- return _context5.a(2);
2057
+ return _context8.a(2);
2197
2058
  }
2198
- }, _callee5);
2059
+ }, _callee8);
2199
2060
  })));
2200
2061
  }
2201
2062
  });
@@ -2426,19 +2287,20 @@ window.openAIChatManager = function () {
2426
2287
  this.prompt = event.target.value;
2427
2288
  },
2428
2289
  getProfileId: function getProfileId() {
2429
- return this.inputElement.getAttribute('data-profile-id');
2290
+ return this.inputElement ? this.inputElement.getAttribute('data-profile-id') : null;
2430
2291
  },
2431
2292
  setSessionId: function setSessionId(sessionId) {
2293
+ if (!this.inputElement) {
2294
+ return;
2295
+ }
2432
2296
  this.inputElement.setAttribute('data-session-id', sessionId || '');
2433
2297
  },
2434
2298
  resetSession: function resetSession() {
2435
2299
  this.stopRecording();
2300
+ this.rejectPendingSessionRequest('Session was reset.');
2436
2301
  this.setSessionId('');
2437
2302
  this.isSessionStarted = false;
2438
2303
  this.sessionRating = null;
2439
- if (this.widgetIsInitialized) {
2440
- localStorage.removeItem(this.chatWidgetStateSession);
2441
- }
2442
2304
  this.messages = [];
2443
2305
  this.documents = [];
2444
2306
  if (!config.autoCreateSession) {
@@ -2447,6 +2309,9 @@ window.openAIChatManager = function () {
2447
2309
  if (config.autoCreateSession) {
2448
2310
  this.startNewSession();
2449
2311
  }
2312
+ if (widgetBehavior && typeof widgetBehavior.onSessionReset === 'function') {
2313
+ widgetBehavior.onSessionReset(this, config);
2314
+ }
2450
2315
  },
2451
2316
  startNewSession: function startNewSession() {
2452
2317
  if (!this.applyOrchestratorAvailability()) {
@@ -2456,16 +2321,94 @@ window.openAIChatManager = function () {
2456
2321
  if (!profileId || !this.connection) {
2457
2322
  return;
2458
2323
  }
2459
- this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2324
+ this.requestNewSession(profileId)["catch"](function (err) {
2460
2325
  return console.error(err);
2461
2326
  });
2462
2327
  },
2463
- initializeApp: function initializeApp() {
2328
+ ensureSessionForDocuments: function ensureSessionForDocuments(profileId) {
2464
2329
  var _this20 = this;
2330
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
2331
+ var sessionId;
2332
+ return _regenerator().w(function (_context9) {
2333
+ while (1) switch (_context9.n) {
2334
+ case 0:
2335
+ sessionId = _this20.getSessionId();
2336
+ if (!sessionId) {
2337
+ _context9.n = 1;
2338
+ break;
2339
+ }
2340
+ return _context9.a(2, sessionId);
2341
+ case 1:
2342
+ if (!(!profileId || !_this20.connection)) {
2343
+ _context9.n = 2;
2344
+ break;
2345
+ }
2346
+ return _context9.a(2, null);
2347
+ case 2:
2348
+ _context9.n = 3;
2349
+ return _this20.requestNewSession(profileId);
2350
+ case 3:
2351
+ return _context9.a(2, _context9.v);
2352
+ }
2353
+ }, _callee9);
2354
+ }))();
2355
+ },
2356
+ requestNewSession: function requestNewSession(profileId) {
2357
+ var _this21 = this;
2358
+ if (this.pendingSessionPromise) {
2359
+ return this.pendingSessionPromise;
2360
+ }
2361
+ if (!profileId || !this.connection) {
2362
+ return Promise.resolve(null);
2363
+ }
2364
+ this.pendingSessionPromise = new Promise(function (resolve, reject) {
2365
+ _this21.pendingSessionResolver = resolve;
2366
+ _this21.pendingSessionRejector = reject;
2367
+ _this21.pendingSessionTimeoutId = window.setTimeout(function () {
2368
+ _this21.rejectPendingSessionRequest('Timed out while creating a chat session.');
2369
+ }, 15000);
2370
+ });
2371
+ this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2372
+ _this21.rejectPendingSessionRequest(err);
2373
+ });
2374
+ return this.pendingSessionPromise;
2375
+ },
2376
+ resolvePendingSessionRequest: function resolvePendingSessionRequest(sessionId) {
2377
+ if (this.pendingSessionResolver) {
2378
+ this.pendingSessionResolver(sessionId);
2379
+ }
2380
+ this.clearPendingSessionRequest();
2381
+ },
2382
+ rejectPendingSessionRequest: function rejectPendingSessionRequest(error) {
2383
+ if (this.pendingSessionRejector) {
2384
+ this.pendingSessionRejector(error);
2385
+ }
2386
+ this.clearPendingSessionRequest();
2387
+ },
2388
+ clearPendingSessionRequest: function clearPendingSessionRequest() {
2389
+ if (this.pendingSessionTimeoutId) {
2390
+ window.clearTimeout(this.pendingSessionTimeoutId);
2391
+ }
2392
+ this.pendingSessionPromise = null;
2393
+ this.pendingSessionResolver = null;
2394
+ this.pendingSessionRejector = null;
2395
+ this.pendingSessionTimeoutId = null;
2396
+ },
2397
+ initializeApp: function initializeApp() {
2398
+ var _this22 = this;
2465
2399
  this.inputElement = document.querySelector(config.inputElementSelector);
2466
2400
  this.buttonElement = document.querySelector(config.sendButtonElementSelector);
2467
2401
  this.chatContainer = document.querySelector(config.chatContainerElementSelector);
2468
2402
  this.placeholder = document.querySelector(config.placeholderElementSelector);
2403
+ if (!this.inputElement || !this.buttonElement || !this.chatContainer || !this.placeholder) {
2404
+ console.error('AI chat app could not initialize because one or more required elements were not found.', {
2405
+ inputElementSelector: config.inputElementSelector,
2406
+ sendButtonElementSelector: config.sendButtonElementSelector,
2407
+ chatContainerElementSelector: config.chatContainerElementSelector,
2408
+ placeholderElementSelector: config.placeholderElementSelector
2409
+ });
2410
+ return false;
2411
+ }
2469
2412
  this.applyOrchestratorAvailability();
2470
2413
  var sessionId = this.getSessionId();
2471
2414
  if (!hasWidgetConfig && sessionId) {
@@ -2490,7 +2433,7 @@ window.openAIChatManager = function () {
2490
2433
  fileInput.accept = config.allowedExtensions;
2491
2434
  }
2492
2435
  fileInput.addEventListener('change', function (e) {
2493
- return _this20.handleFileInputChange(e);
2436
+ return _this22.handleFileInputChange(e);
2494
2437
  });
2495
2438
  this.documentBar.parentElement.appendChild(fileInput);
2496
2439
 
@@ -2498,13 +2441,13 @@ window.openAIChatManager = function () {
2498
2441
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
2499
2442
  if (inputArea) {
2500
2443
  inputArea.addEventListener('dragover', function (e) {
2501
- return _this20.handleDragOver(e);
2444
+ return _this22.handleDragOver(e);
2502
2445
  });
2503
2446
  inputArea.addEventListener('dragleave', function (e) {
2504
- return _this20.handleDragLeave(e);
2447
+ return _this22.handleDragLeave(e);
2505
2448
  });
2506
2449
  inputArea.addEventListener('drop', function (e) {
2507
- return _this20.handleDrop(e);
2450
+ return _this22.handleDrop(e);
2508
2451
  });
2509
2452
  }
2510
2453
  }
@@ -2512,55 +2455,55 @@ window.openAIChatManager = function () {
2512
2455
 
2513
2456
  // Pause auto-scroll when the user manually scrolls up during streaming.
2514
2457
  this.chatContainer.addEventListener('scroll', function () {
2515
- if (!_this20.stream) {
2458
+ if (!_this22.stream) {
2516
2459
  return;
2517
2460
  }
2518
2461
  var threshold = 30;
2519
- var atBottom = _this20.chatContainer.scrollHeight - _this20.chatContainer.clientHeight - _this20.chatContainer.scrollTop <= threshold;
2520
- _this20.autoScroll = atBottom;
2462
+ var atBottom = _this22.chatContainer.scrollHeight - _this22.chatContainer.clientHeight - _this22.chatContainer.scrollTop <= threshold;
2463
+ _this22.autoScroll = atBottom;
2521
2464
  });
2522
2465
  this.inputElement.addEventListener('keydown', function (event) {
2523
- if (_this20.stream != null) {
2466
+ if (_this22.stream != null) {
2524
2467
  return;
2525
2468
  }
2526
2469
  if (event.key === "Enter" && !event.shiftKey) {
2527
2470
  event.preventDefault();
2528
- _this20.buttonElement.click();
2471
+ _this22.buttonElement.click();
2529
2472
  }
2530
2473
  });
2531
2474
  this.inputElement.addEventListener('input', function (e) {
2532
- _this20.handleUserInput(e);
2475
+ _this22.handleUserInput(e);
2533
2476
  if (e.target.value.trim()) {
2534
- _this20.buttonElement.removeAttribute('disabled');
2477
+ _this22.buttonElement.removeAttribute('disabled');
2535
2478
  } else {
2536
- _this20.buttonElement.setAttribute('disabled', true);
2479
+ _this22.buttonElement.setAttribute('disabled', true);
2537
2480
  }
2538
2481
  });
2539
2482
  this.buttonElement.addEventListener('click', function () {
2540
- if (_this20.stream != null) {
2541
- _this20.stream.dispose();
2542
- _this20.stream = null;
2543
- _this20.streamingFinished();
2544
- _this20.hideTypingIndicator();
2483
+ if (_this22.stream != null) {
2484
+ _this22.stream.dispose();
2485
+ _this22.stream = null;
2486
+ _this22.streamingFinished();
2487
+ _this22.hideTypingIndicator();
2545
2488
 
2546
2489
  // 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];
2490
+ if (_this22.messages.length > 0) {
2491
+ var lastMsg = _this22.messages[_this22.messages.length - 1];
2549
2492
  if (lastMsg.role === 'assistant' && !lastMsg.content) {
2550
- _this20.messages.pop();
2493
+ _this22.messages.pop();
2551
2494
  } else if (lastMsg.isStreaming) {
2552
2495
  lastMsg.isStreaming = false;
2553
2496
  }
2554
2497
  }
2555
2498
  return;
2556
2499
  }
2557
- _this20.sendMessage();
2500
+ _this22.sendMessage();
2558
2501
  });
2559
2502
  var promptGenerators = document.getElementsByClassName('profile-generated-prompt');
2560
2503
  for (var i = 0; i < promptGenerators.length; i++) {
2561
2504
  promptGenerators[i].addEventListener('click', function (e) {
2562
2505
  e.preventDefault();
2563
- _this20.generatePrompt(e.target);
2506
+ _this22.generatePrompt(e.target);
2564
2507
  });
2565
2508
  }
2566
2509
  var chatSessions = document.getElementsByClassName('chat-session-history-item');
@@ -2572,17 +2515,18 @@ window.openAIChatManager = function () {
2572
2515
  console.error('an element with the class chat-session-history-item with no data-session-id set.');
2573
2516
  return;
2574
2517
  }
2575
- _this20.loadSession(sessionId);
2576
- _this20.showChatScreen();
2518
+ _this22.loadSession(sessionId);
2519
+ _this22.showChatScreen();
2577
2520
  });
2578
2521
  }
2579
- for (var _i5 = 0; _i5 < config.messages.length; _i5++) {
2580
- this.addMessage(config.messages[_i5]);
2522
+ var initialMessages = Array.isArray(config.messages) ? config.messages : [];
2523
+ for (var _i5 = 0; _i5 < initialMessages.length; _i5++) {
2524
+ this.addMessage(initialMessages[_i5]);
2581
2525
  }
2582
2526
 
2583
2527
  // Update feedback icons in the DOM after initial messages have rendered.
2584
2528
  this.$nextTick(function () {
2585
- _this20.refreshAllFeedbackIcons();
2529
+ _this22.refreshAllFeedbackIcons();
2586
2530
  });
2587
2531
 
2588
2532
  // Delegate click for code block copy buttons.
@@ -2600,9 +2544,9 @@ window.openAIChatManager = function () {
2600
2544
  if (codeEl) {
2601
2545
  navigator.clipboard.writeText(codeEl.textContent);
2602
2546
  var copiedText = config.codeCopiedText || 'Copied!';
2603
- btn.innerHTML = '<span class="fa-solid fa-check"></span> ' + copiedText;
2547
+ btn.innerHTML = '<i class="fa-solid fa-check"></i> ' + copiedText;
2604
2548
  setTimeout(function () {
2605
- btn.innerHTML = '<span class="fa-regular fa-copy"></span>';
2549
+ btn.innerHTML = '<i class="fa-regular fa-copy"></i>';
2606
2550
  }, 2000);
2607
2551
  }
2608
2552
  });
@@ -2614,7 +2558,7 @@ window.openAIChatManager = function () {
2614
2558
  if (this.micButton) {
2615
2559
  this.micButton.style.display = '';
2616
2560
  this.micButton.addEventListener('click', function () {
2617
- _this20.toggleRecording();
2561
+ _this22.toggleRecording();
2618
2562
  });
2619
2563
  }
2620
2564
  }
@@ -2624,10 +2568,11 @@ window.openAIChatManager = function () {
2624
2568
  this.conversationButton = document.querySelector(config.conversationButtonElementSelector);
2625
2569
  if (this.conversationButton) {
2626
2570
  this.conversationButton.addEventListener('click', function () {
2627
- _this20.toggleConversationMode();
2571
+ _this22.toggleConversationMode();
2628
2572
  });
2629
2573
  }
2630
2574
  }
2575
+ return true;
2631
2576
  },
2632
2577
  loadSession: function loadSession(sessionId) {
2633
2578
  this.connection.invoke("LoadSession", sessionId)["catch"](function (err) {
@@ -2642,130 +2587,69 @@ window.openAIChatManager = function () {
2642
2587
  },
2643
2588
  initializeSession: function initializeSession(sessionId, force) {
2644
2589
  if (this.isSessionStarted && !force) {
2590
+ if (sessionId && this.getSessionId() === sessionId) {
2591
+ this.resolvePendingSessionRequest(sessionId);
2592
+ }
2645
2593
  return;
2646
2594
  }
2647
- this.fireEvent(new CustomEvent("initializingSessionOpenAIChat", {
2595
+ this.fireEvent(new CustomEvent("initializingSessionCoreAIChat", {
2648
2596
  detail: {
2649
2597
  sessionId: sessionId
2650
2598
  }
2651
2599
  }));
2652
2600
  this.setSessionId(sessionId);
2653
2601
  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);
2721
- }
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;
2602
+ this.resolvePendingSessionRequest(sessionId);
2603
+ if (widgetBehavior && typeof widgetBehavior.onSessionInitialized === 'function') {
2604
+ widgetBehavior.onSessionInitialized(this, sessionId, config);
2757
2605
  }
2758
- this.chatHistorySection.classList.remove('show');
2759
2606
  },
2760
2607
  getSessionId: function getSessionId() {
2761
- var sessionId = this.inputElement.getAttribute('data-session-id');
2762
- if (!sessionId && this.widgetIsInitialized) {
2763
- sessionId = localStorage.getItem(this.chatWidgetStateSession);
2608
+ var sessionId = this.inputElement ? this.inputElement.getAttribute('data-session-id') : null;
2609
+ if (!sessionId && widgetBehavior && typeof widgetBehavior.resolveSessionId === 'function') {
2610
+ sessionId = widgetBehavior.resolveSessionId(this, config);
2764
2611
  }
2765
2612
  return sessionId;
2766
2613
  },
2767
- copyResponse: function copyResponse(message) {
2768
- navigator.clipboard.writeText(message);
2614
+ clearCopiedMessageState: function clearCopiedMessageState() {
2615
+ if (this.copyResetTimeoutId) {
2616
+ window.clearTimeout(this.copyResetTimeoutId);
2617
+ this.copyResetTimeoutId = null;
2618
+ }
2619
+ if (this.activeCopyButton) {
2620
+ this.setCopyButtonState(this.activeCopyButton, false);
2621
+ this.activeCopyButton = null;
2622
+ }
2623
+ this.copiedMessageIndex = -1;
2624
+ },
2625
+ copyResponse: function copyResponse(message, index, event) {
2626
+ var _ref25,
2627
+ _message$copyContent,
2628
+ _event$target,
2629
+ _event$target$closest,
2630
+ _this23 = this;
2631
+ var text = message && _typeof(message) === 'object' ? (_ref25 = (_message$copyContent = message.copyContent) !== null && _message$copyContent !== void 0 ? _message$copyContent : message.content) !== null && _ref25 !== void 0 ? _ref25 : '' : message !== null && message !== void 0 ? message : '';
2632
+ var button = (event === null || event === void 0 ? void 0 : event.currentTarget) || (event === null || event === void 0 || (_event$target = event.target) === null || _event$target === void 0 || (_event$target$closest = _event$target.closest) === null || _event$target$closest === void 0 ? void 0 : _event$target$closest.call(_event$target, '[data-copy-message-index]')) || null;
2633
+ navigator.clipboard.writeText(text).then(function () {
2634
+ _this23.clearCopiedMessageState();
2635
+ _this23.copiedMessageIndex = typeof index === 'number' ? index : -1;
2636
+ _this23.activeCopyButton = button;
2637
+ if (button) {
2638
+ _this23.setCopyButtonState(button, true);
2639
+ } else {
2640
+ _this23.$nextTick(function () {
2641
+ return _this23.updateCopyButtons();
2642
+ });
2643
+ }
2644
+ _this23.copyResetTimeoutId = window.setTimeout(function () {
2645
+ _this23.clearCopiedMessageState();
2646
+ _this23.$nextTick(function () {
2647
+ return _this23.updateCopyButtons();
2648
+ });
2649
+ }, Number(config.copyResetDelayMs) || 2000);
2650
+ })["catch"](function (err) {
2651
+ return console.error('Failed to copy response:', err);
2652
+ });
2769
2653
  },
2770
2654
  updateFeedbackIcons: function updateFeedbackIcons(container, userRating) {
2771
2655
  if (!container) {
@@ -2844,16 +2728,28 @@ window.openAIChatManager = function () {
2844
2728
  documents: {
2845
2729
  handler: function handler() {
2846
2730
  this.renderDocumentBar();
2731
+ if (widgetBehavior && typeof widgetBehavior.onDocumentsChanged === 'function') {
2732
+ widgetBehavior.onDocumentsChanged(this, this.documents, config);
2733
+ }
2847
2734
  },
2848
2735
  deep: true
2849
2736
  },
2850
2737
  isUploading: function isUploading() {
2851
2738
  this.renderDocumentBar();
2852
2739
  },
2740
+ isDocumentOperationPending: function isDocumentOperationPending() {
2741
+ this.renderDocumentBar();
2742
+ },
2853
2743
  isPlayingAudio: function isPlayingAudio() {
2854
2744
  // Reserved for future use — volume-based interrupt detection
2855
2745
  // no longer mutes tracks; browser echo cancellation handles echo.
2856
2746
  },
2747
+ copiedMessageIndex: function copiedMessageIndex() {
2748
+ var _this24 = this;
2749
+ this.$nextTick(function () {
2750
+ return _this24.updateCopyButtons();
2751
+ });
2752
+ },
2857
2753
  isConversationMode: function isConversationMode(active) {
2858
2754
  // Hide/show mic button.
2859
2755
  if (this.micButton) {
@@ -2875,22 +2771,28 @@ window.openAIChatManager = function () {
2875
2771
  }
2876
2772
  },
2877
2773
  mounted: function mounted() {
2878
- var _this22 = this;
2879
- _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
2880
- return _regenerator().w(function (_context6) {
2881
- while (1) switch (_context6.n) {
2774
+ var _this25 = this;
2775
+ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
2776
+ var isInitialized;
2777
+ return _regenerator().w(function (_context0) {
2778
+ while (1) switch (_context0.n) {
2882
2779
  case 0:
2883
- _context6.n = 1;
2884
- return _this22.startConnection();
2780
+ _context0.n = 1;
2781
+ return _this25.startConnection();
2885
2782
  case 1:
2886
- _this22.initializeApp();
2887
- if (hasWidgetConfig) {
2888
- _this22.initializeWidget();
2783
+ isInitialized = _this25.initializeApp();
2784
+ if (isInitialized && hasWidgetConfig && widgetBehavior && typeof widgetBehavior.onMounted === 'function') {
2785
+ widgetBehavior.onMounted(_this25, config);
2889
2786
  }
2787
+ _this25.$nextTick(function () {
2788
+ _this25.updateCopyButtons();
2789
+ refreshFontAwesomeIcons(_this25.$el);
2790
+ _this25.fontAwesomeObserver = observeFontAwesomeIcons(_this25.$el);
2791
+ });
2890
2792
  case 2:
2891
- return _context6.a(2);
2793
+ return _context0.a(2);
2892
2794
  }
2893
- }, _callee6);
2795
+ }, _callee0);
2894
2796
  }))();
2895
2797
  window.addEventListener('beforeunload', this.handleBeforeUnload);
2896
2798
  window.addEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
@@ -2898,6 +2800,11 @@ window.openAIChatManager = function () {
2898
2800
  beforeUnmount: function beforeUnmount() {
2899
2801
  window.removeEventListener('beforeunload', this.handleBeforeUnload);
2900
2802
  window.removeEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
2803
+ if (this.fontAwesomeObserver) {
2804
+ this.fontAwesomeObserver.disconnect();
2805
+ this.fontAwesomeObserver = null;
2806
+ }
2807
+ this.clearCopiedMessageState();
2901
2808
  this.stopAudio(false);
2902
2809
  if (this.stream) {
2903
2810
  this.stream.dispose();
@@ -2906,13 +2813,163 @@ window.openAIChatManager = function () {
2906
2813
  if (this.connection) {
2907
2814
  this.connection.stop();
2908
2815
  }
2816
+ if (widgetBehavior && typeof widgetBehavior.onBeforeUnmount === 'function') {
2817
+ widgetBehavior.onBeforeUnmount(this, config);
2818
+ }
2909
2819
  },
2910
2820
  template: config.messageTemplate
2911
- }).mount(config.appElementSelector);
2821
+ };
2822
+ var app = Vue.createApp(appDefinition).mount(config.appElementSelector);
2823
+ if (widgetBehavior && typeof widgetBehavior.attach === 'function') {
2824
+ widgetBehavior.attach(app, config);
2825
+ }
2912
2826
  return app;
2913
2827
  };
2828
+ var autoInitializeSelector = '[data-coreai-chat-config],[data-coreai-chat-app-element-selector]';
2829
+ function getAttributeValue(element, attributeName) {
2830
+ var value = element.getAttribute(attributeName);
2831
+ return value === null || value === '' ? null : value;
2832
+ }
2833
+ function parseBooleanAttributeValue(value) {
2834
+ if (value === null || value === undefined) {
2835
+ return null;
2836
+ }
2837
+ if (typeof value === 'boolean') {
2838
+ return value;
2839
+ }
2840
+ var normalized = String(value).trim().toLowerCase();
2841
+ if (normalized === 'true') {
2842
+ return true;
2843
+ }
2844
+ if (normalized === 'false') {
2845
+ return false;
2846
+ }
2847
+ return null;
2848
+ }
2849
+ function parseJsonAttribute(element, attributeName, description) {
2850
+ var rawValue = getAttributeValue(element, attributeName);
2851
+ if (!rawValue) {
2852
+ return null;
2853
+ }
2854
+ try {
2855
+ return JSON.parse(rawValue);
2856
+ } catch (error) {
2857
+ console.error('Failed to parse ' + description + ' JSON.', error);
2858
+ return null;
2859
+ }
2860
+ }
2861
+ function buildConfigFromDataAttributes(element, options) {
2862
+ var _parseJsonAttribute, _parseJsonAttribute2;
2863
+ var settings = options || {};
2864
+ if (element.hasAttribute('data-coreai-chat-widget-container-selector') && settings.allowWidgetHost !== true) {
2865
+ return null;
2866
+ }
2867
+ var appElementSelector = getAttributeValue(element, 'data-coreai-chat-app-element-selector');
2868
+ if (!appElementSelector) {
2869
+ return null;
2870
+ }
2871
+ var config = {
2872
+ signalRHubUrl: getAttributeValue(element, 'data-coreai-chat-signalr-hub-url'),
2873
+ appElementSelector: appElementSelector,
2874
+ chatContainerElementSelector: getAttributeValue(element, 'data-coreai-chat-container-element-selector'),
2875
+ inputElementSelector: getAttributeValue(element, 'data-coreai-chat-input-element-selector'),
2876
+ sendButtonElementSelector: getAttributeValue(element, 'data-coreai-chat-send-button-element-selector'),
2877
+ placeholderElementSelector: getAttributeValue(element, 'data-coreai-chat-placeholder-element-selector'),
2878
+ messages: (_parseJsonAttribute = parseJsonAttribute(element, 'data-coreai-chat-messages', 'CoreAI chat messages')) !== null && _parseJsonAttribute !== void 0 ? _parseJsonAttribute : undefined,
2879
+ chatMode: getAttributeValue(element, 'data-coreai-chat-mode'),
2880
+ micButtonElementSelector: getAttributeValue(element, 'data-coreai-chat-mic-button-element-selector'),
2881
+ conversationButtonElementSelector: getAttributeValue(element, 'data-coreai-chat-conversation-button-element-selector'),
2882
+ ttsVoiceName: getAttributeValue(element, 'data-coreai-chat-tts-voice-name'),
2883
+ documentBarSelector: getAttributeValue(element, 'data-coreai-chat-document-bar-selector'),
2884
+ uploadDocumentUrl: getAttributeValue(element, 'data-coreai-chat-upload-document-url'),
2885
+ removeDocumentUrl: getAttributeValue(element, 'data-coreai-chat-remove-document-url'),
2886
+ allowedExtensions: getAttributeValue(element, 'data-coreai-chat-allowed-extensions'),
2887
+ supportedExtensionsText: getAttributeValue(element, 'data-coreai-chat-supported-extensions-text'),
2888
+ existingDocuments: (_parseJsonAttribute2 = parseJsonAttribute(element, 'data-coreai-chat-existing-documents', 'CoreAI chat existing documents')) !== null && _parseJsonAttribute2 !== void 0 ? _parseJsonAttribute2 : undefined,
2889
+ initialPrompt: getAttributeValue(element, 'data-coreai-chat-initial-prompt'),
2890
+ userLabel: getAttributeValue(element, 'data-coreai-chat-user-label'),
2891
+ assistantLabel: getAttributeValue(element, 'data-coreai-chat-assistant-label'),
2892
+ copyTitle: getAttributeValue(element, 'data-coreai-chat-copy-title'),
2893
+ copiedTitle: getAttributeValue(element, 'data-coreai-chat-copied-title')
2894
+ };
2895
+ var booleanAttributes = {
2896
+ metricsEnabled: 'data-coreai-chat-metrics-enabled',
2897
+ textToSpeechEnabled: 'data-coreai-chat-text-to-speech-enabled',
2898
+ sessionDocumentsEnabled: 'data-coreai-chat-session-documents-enabled',
2899
+ autoCreateSession: 'data-coreai-chat-auto-create-session',
2900
+ singleResponseMode: 'data-coreai-chat-single-response-mode'
2901
+ };
2902
+ Object.keys(booleanAttributes).forEach(function (key) {
2903
+ var parsed = parseBooleanAttributeValue(getAttributeValue(element, booleanAttributes[key]));
2904
+ if (parsed !== null) {
2905
+ config[key] = parsed;
2906
+ }
2907
+ });
2908
+ return compactObject(config);
2909
+ }
2910
+ function buildConfigFromElement(element, options) {
2911
+ var jsonConfig = parseJsonAttribute(element, 'data-coreai-chat-config', 'CoreAI chat config');
2912
+ var attributeConfig = buildConfigFromDataAttributes(element, options);
2913
+ if (!jsonConfig && !attributeConfig) {
2914
+ return null;
2915
+ }
2916
+ return Object.assign({}, jsonConfig || {}, attributeConfig || {});
2917
+ }
2918
+ function initializeFromElement(element) {
2919
+ if (!element || element.dataset.coreAiChatInitialized === 'true') {
2920
+ return element ? element.__coreAIChatApp || null : null;
2921
+ }
2922
+ var config = buildConfigFromElement(element);
2923
+ if (!config) {
2924
+ return null;
2925
+ }
2926
+ var app = initialize(config);
2927
+ if (!app) {
2928
+ return null;
2929
+ }
2930
+ element.dataset.coreAiChatInitialized = 'true';
2931
+ element.__coreAIChatApp = app;
2932
+ return app;
2933
+ }
2934
+ function scanForAutoInitialization(root) {
2935
+ if (!root || typeof root.querySelectorAll !== 'function') {
2936
+ return;
2937
+ }
2938
+ if (typeof root.matches === 'function' && root.matches(autoInitializeSelector)) {
2939
+ initializeFromElement(root);
2940
+ }
2941
+ root.querySelectorAll(autoInitializeSelector).forEach(initializeFromElement);
2942
+ }
2943
+ function startAutoInitialization() {
2944
+ scanForAutoInitialization(document);
2945
+ if (typeof MutationObserver === 'undefined') {
2946
+ return;
2947
+ }
2948
+ var observer = new MutationObserver(function (mutations) {
2949
+ mutations.forEach(function (mutation) {
2950
+ mutation.addedNodes.forEach(function (node) {
2951
+ if (node && node.nodeType === 1) {
2952
+ scanForAutoInitialization(node);
2953
+ }
2954
+ });
2955
+ });
2956
+ });
2957
+ observer.observe(document.body, {
2958
+ childList: true,
2959
+ subtree: true
2960
+ });
2961
+ }
2962
+ if (document.readyState === 'loading') {
2963
+ document.addEventListener('DOMContentLoaded', startAutoInitialization, {
2964
+ once: true
2965
+ });
2966
+ } else {
2967
+ startAutoInitialization();
2968
+ }
2914
2969
  return {
2915
- initialize: initialize
2970
+ initialize: initialize,
2971
+ initializeFromElement: initializeFromElement,
2972
+ buildConfigFromElement: buildConfigFromElement
2916
2973
  };
2917
2974
  }();
2918
2975