@crestapps/ai-chat-ui 1.0.0-preview.14 → 1.0.0-preview.153

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 +158 -12
  2. package/dist/ai-chat-widget.js.map +1 -1
  3. package/dist/ai-chat-widget.min.js +1 -1
  4. package/dist/ai-chat-widget.min.js.map +1 -1
  5. package/dist/ai-chat.css +67 -17
  6. package/dist/ai-chat.css.map +1 -1
  7. package/dist/ai-chat.js +683 -328
  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 +1198 -338
  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 +86 -35
  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 +5 -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-message-heading ai-chat-message-heading-user\">\n <span class=\"ai-chat-msg-role ai-chat-msg-role-user\">{{ userLabel }}</span>\n </div>\n <div v-else-if=\"message.role !== 'indicator'\" class=\"ai-chat-message-heading ai-chat-message-heading-assistant\">\n <div :class=\"getAssistantRoleClasses(message)\">\n <span :class=\"getAssistantIconClasses(message, index)\"><i :class=\"getAssistantIcon(message)\"></i></span>\n <span class=\"ai-chat-message-role-label\">{{ getAssistantLabel(message) }}</span>\n </div>\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-message-heading ai-chat-message-heading-assistant\">\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 <span class=\"ai-chat-message-role-label\">Assistant</span>\n </div>\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,11 +573,31 @@ 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
+ }
586
+ function resolveIndicatorTemplate(template, assistantLabel) {
587
+ if (!template) {
588
+ return template;
589
+ }
590
+ var encodedAssistantLabel = escapeHtmlEntities(assistantLabel || 'Assistant');
591
+ return template.replace(/\{\{\s*assistantLabel\s*\}\}/g, encodedAssistantLabel);
592
+ }
362
593
  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);
366
- var widgetBehavior = window.openAIChatWidgetBehavior || null;
594
+ var normalizedInstanceConfig = compactObject(instanceConfig);
595
+ var normalizedWidgetConfig = compactObject(normalizedInstanceConfig.widget);
596
+ var config = Object.assign({}, defaultConfig, normalizedInstanceConfig);
597
+ config.widget = Object.assign({}, defaultConfig.widget || {}, normalizedWidgetConfig);
598
+ config.indicatorTemplate = resolveIndicatorTemplate(config.indicatorTemplate, config.assistantLabel);
599
+ var hasWidgetConfig = !!(normalizedWidgetConfig.chatWidgetContainer && normalizedWidgetConfig.chatWidgetStateName);
600
+ var widgetBehavior = window.coreAIChatWidgetBehavior || null;
367
601
  // Keep defaultConfig in sync so renderers use overridden values
368
602
  defaultConfig = config;
369
603
  if (!config.signalRHubUrl) {
@@ -415,6 +649,7 @@ window.openAIChatManager = function () {
415
649
  thumbsUpTitle: config.thumbsUpTitle,
416
650
  thumbsDownTitle: config.thumbsDownTitle,
417
651
  copyTitle: config.copyTitle,
652
+ copiedTitle: config.copiedTitle,
418
653
  isRecording: false,
419
654
  mediaRecorder: null,
420
655
  preRecordingPrompt: '',
@@ -439,7 +674,10 @@ window.openAIChatManager = function () {
439
674
  pendingSessionPromise: null,
440
675
  pendingSessionResolver: null,
441
676
  pendingSessionRejector: null,
442
- pendingSessionTimeoutId: null
677
+ pendingSessionTimeoutId: null,
678
+ copiedMessageIndex: -1,
679
+ copyResetTimeoutId: null,
680
+ activeCopyButton: null
443
681
  };
444
682
  },
445
683
  computed: {
@@ -767,7 +1005,7 @@ window.openAIChatManager = function () {
767
1005
  var name = doc.fileName || 'Document';
768
1006
  if (name.length > 20) name = name.substring(0, 17) + '...';
769
1007
  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 || '') + '">';
770
- html += '<span class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></span> ';
1008
+ html += '<i class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></i> ';
771
1009
  html += this.escapeHtml(name);
772
1010
  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>';
773
1011
  html += '</span>';
@@ -778,7 +1016,7 @@ window.openAIChatManager = function () {
778
1016
  var errorMsg = failedItem.error || 'Upload failed';
779
1017
  if (failedName.length > 15) failedName = failedName.substring(0, 12) + '...';
780
1018
  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) + '">';
781
- html += '<span class="fa-solid fa-circle-exclamation" style="font-size: 0.7rem;"></span> ';
1019
+ html += '<i class="fa-solid fa-circle-exclamation" style="font-size: 0.7rem;"></i> ';
782
1020
  html += this.escapeHtml(failedName);
783
1021
  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>';
784
1022
  html += '</span>';
@@ -789,7 +1027,7 @@ window.openAIChatManager = function () {
789
1027
  html += '</span>';
790
1028
  }
791
1029
  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' : '') + '>';
792
- html += '<span class="fa-solid fa-paperclip"></span>';
1030
+ html += '<i class="fa-solid fa-paperclip"></i>';
793
1031
  if (this.documents.length === 0 && !this.isUploading) {
794
1032
  html += ' <span>Attach files</span>';
795
1033
  }
@@ -948,10 +1186,12 @@ window.openAIChatManager = function () {
948
1186
  });
949
1187
 
950
1188
  // When the session is new (no messages) and an initial prompt is configured,
951
- // automatically send it as the first user message to trigger an AI response.
1189
+ // display it as the first assistant message without invoking the AI.
952
1190
  if (_this3.messages.length === 0 && config.initialPrompt) {
953
- _this3.prompt = config.initialPrompt;
954
- _this3.sendMessage();
1191
+ _this3.addMessage({
1192
+ role: 'assistant',
1193
+ content: config.initialPrompt
1194
+ });
955
1195
  }
956
1196
  });
957
1197
  _this3.connection.on("ReceiveError", function (error) {
@@ -959,8 +1199,29 @@ window.openAIChatManager = function () {
959
1199
  if (_this3.isRecording) {
960
1200
  _this3.stopRecording();
961
1201
  }
1202
+
1203
+ // A server-side error (for example a session-start rate-limit rejection) ends the
1204
+ // in-flight request. Reject any pending new-session promise so the UI stops waiting
1205
+ // until it times out, and clear the typing indicator that a send may have shown.
1206
+ _this3.rejectPendingSessionRequest(error);
1207
+ _this3.hideTypingIndicator();
962
1208
  if (widgetBehavior && typeof widgetBehavior.handleReceiveError === 'function') {
963
1209
  widgetBehavior.handleReceiveError(_this3, error, config);
1210
+ } else if (!_this3.isNavigatingAway) {
1211
+ // Surface the message to the user instead of failing silently.
1212
+ _this3.addMessage(_this3.getErrorMessage(error));
1213
+ }
1214
+ });
1215
+ _this3.connection.on("ReceiveSessionStartRejected", function (reason) {
1216
+ // A rate-limit rejection is a definitive "wait and retry", not a recoverable
1217
+ // session/connection error. Unblock any pending new-session request, clear the
1218
+ // typing indicator, and show the message for every host (main app and widget)
1219
+ // without triggering the widget's clear-and-retry recovery, which would wipe the
1220
+ // visitor's state and fire another throttled StartSession.
1221
+ _this3.rejectPendingSessionRequest(reason);
1222
+ _this3.hideTypingIndicator();
1223
+ if (!_this3.isNavigatingAway) {
1224
+ _this3.addMessage(_this3.getErrorMessage(reason));
964
1225
  }
965
1226
  });
966
1227
  _this3.connection.on("MessageRated", function (messageId, userRating) {
@@ -1034,7 +1295,7 @@ window.openAIChatManager = function () {
1034
1295
  _this3.scrollToBottom();
1035
1296
  }
1036
1297
  });
1037
- _this3.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, appearance) {
1298
+ _this3.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, references, appearance) {
1038
1299
  if (!_this3._conversationAssistantMessage) {
1039
1300
  _this3.stopAudio();
1040
1301
  _this3.hideTypingIndicator();
@@ -1053,7 +1314,8 @@ window.openAIChatManager = function () {
1053
1314
  htmlContent: "",
1054
1315
  isStreaming: true,
1055
1316
  userRating: null,
1056
- appearance: _this3.normalizeAssistantAppearance(appearance)
1317
+ appearance: _this3.normalizeAssistantAppearance(appearance),
1318
+ references: {}
1057
1319
  };
1058
1320
  _this3.messages.push(newMessage);
1059
1321
  _this3._conversationAssistantMessage = {
@@ -1067,19 +1329,22 @@ window.openAIChatManager = function () {
1067
1329
  if (!msg.appearance) {
1068
1330
  msg.appearance = _this3.normalizeAssistantAppearance(appearance);
1069
1331
  }
1070
- msg.content = _this3._conversationAssistantMessage.content;
1071
- msg.htmlContent = parseMarkdownContent(msg.content, msg);
1332
+ msg.rawContent = _this3._conversationAssistantMessage.content;
1333
+ msg.references = normalizeReferences(Object.assign({}, msg.references || {}, references || {}));
1334
+ updateMessagePresentation(msg, msg.references);
1072
1335
  _this3.$nextTick(function () {
1073
1336
  renderChartsInMessage(msg);
1074
1337
  _this3.scrollToBottom();
1075
1338
  });
1076
1339
  }
1077
1340
  });
1078
- _this3.connection.on("ReceiveConversationAssistantComplete", function (sessionId, messageId) {
1341
+ _this3.connection.on("ReceiveConversationAssistantComplete", function (sessionId, messageId, references) {
1079
1342
  if (_this3._conversationAssistantMessage) {
1080
1343
  var msg = _this3.messages[_this3._conversationAssistantMessage.index];
1081
1344
  if (msg) {
1082
1345
  msg.isStreaming = false;
1346
+ msg.references = normalizeReferences(Object.assign({}, msg.references || {}, references || {}));
1347
+ updateMessagePresentation(msg, msg.references);
1083
1348
  }
1084
1349
  _this3._conversationAssistantMessage = null;
1085
1350
  }
@@ -1113,8 +1378,6 @@ window.openAIChatManager = function () {
1113
1378
  console.info("SignalR: reconnected.");
1114
1379
  if (_this3.isSessionStarted) {
1115
1380
  _this3.reloadCurrentSession();
1116
- } else if (config.autoCreateSession) {
1117
- _this3.startNewSession();
1118
1381
  }
1119
1382
  });
1120
1383
  _this3.connection.onclose(function (error) {
@@ -1149,14 +1412,14 @@ window.openAIChatManager = function () {
1149
1412
  if (message.content && !message.htmlContent) {
1150
1413
  message.htmlContent = parseMarkdownContent(message.content, message);
1151
1414
  }
1152
- this.fireEvent(new CustomEvent("addingOpenAIPromotMessage", {
1415
+ this.fireEvent(new CustomEvent("addingCoreAIPromotMessage", {
1153
1416
  detail: {
1154
1417
  message: message
1155
1418
  }
1156
1419
  }));
1157
1420
  this.messages.push(message);
1158
1421
  this.$nextTick(function () {
1159
- _this4.fireEvent(new CustomEvent("addedOpenAIPromotMessage", {
1422
+ _this4.fireEvent(new CustomEvent("addedCoreAIPromotMessage", {
1160
1423
  detail: {
1161
1424
  message: message
1162
1425
  }
@@ -1170,82 +1433,9 @@ window.openAIChatManager = function () {
1170
1433
  message.userRating = null;
1171
1434
  }
1172
1435
  if (message.content) {
1173
- var processedContent = message.content.trim();
1174
- message.references = normalizeReferences(message.references);
1175
- if (message.references && _typeof(message.references) === "object" && Object.keys(message.references).length) {
1176
- // Only include references that were actually cited in the response.
1177
- var citedRefs = Object.entries(message.references).filter(function (_ref7) {
1178
- var _ref8 = _slicedToArray(_ref7, 1),
1179
- key = _ref8[0];
1180
- return processedContent.includes(key);
1181
- });
1182
- if (citedRefs.length) {
1183
- // Sort by original index so display indices follow a natural order.
1184
- citedRefs.sort(function (_ref9, _ref0) {
1185
- var _ref1 = _slicedToArray(_ref9, 2),
1186
- a = _ref1[1];
1187
- var _ref10 = _slicedToArray(_ref0, 2),
1188
- b = _ref10[1];
1189
- return a.index - b.index;
1190
- });
1191
-
1192
- // Phase 1: Replace all markers with unique placeholders.
1193
- var displayIndex = 1;
1194
- var _iterator2 = _createForOfIteratorHelper(citedRefs),
1195
- _step2;
1196
- try {
1197
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1198
- var _step2$value = _slicedToArray(_step2.value, 2),
1199
- key = _step2$value[0],
1200
- value = _step2$value[1];
1201
- var placeholder = "__CITE_".concat(value.index, "__");
1202
- processedContent = processedContent.replaceAll(key, placeholder);
1203
- value._displayIndex = displayIndex++;
1204
- value._placeholder = placeholder;
1205
- }
1206
-
1207
- // Phase 2: Replace placeholders with sequential display indices.
1208
- } catch (err) {
1209
- _iterator2.e(err);
1210
- } finally {
1211
- _iterator2.f();
1212
- }
1213
- var _iterator3 = _createForOfIteratorHelper(citedRefs),
1214
- _step3;
1215
- try {
1216
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1217
- var _step3$value = _slicedToArray(_step3.value, 2),
1218
- _value = _step3$value[1];
1219
- processedContent = processedContent.replaceAll(_value._placeholder, "<sup><strong>".concat(_value._displayIndex, "</strong></sup>"));
1220
- }
1221
-
1222
- // if we have multiple references, add a comma to ensure we don't concatenate numbers.
1223
- } catch (err) {
1224
- _iterator3.e(err);
1225
- } finally {
1226
- _iterator3.f();
1227
- }
1228
- processedContent = processedContent.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1229
- processedContent += '<br><br>';
1230
- var _iterator4 = _createForOfIteratorHelper(citedRefs),
1231
- _step4;
1232
- try {
1233
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1234
- var _step4$value = _slicedToArray(_step4.value, 2),
1235
- _key = _step4$value[0],
1236
- _value2 = _step4$value[1];
1237
- var label = _value2.text || _key;
1238
- processedContent += _value2.link ? "**".concat(_value2._displayIndex, "**. [").concat(label, "](").concat(_value2.link, ")<br>") : "**".concat(_value2._displayIndex, "**. ").concat(label, "<br>");
1239
- }
1240
- } catch (err) {
1241
- _iterator4.e(err);
1242
- } finally {
1243
- _iterator4.f();
1244
- }
1245
- }
1246
- }
1247
- message.content = processedContent;
1248
- message.htmlContent = parseMarkdownContent(processedContent, message);
1436
+ var _message$rawContent;
1437
+ message.rawContent = (_message$rawContent = message.rawContent) !== null && _message$rawContent !== void 0 ? _message$rawContent : message.content;
1438
+ updateMessagePresentation(message, message.references);
1249
1439
  }
1250
1440
  this.addMessageInternal(message);
1251
1441
  this.hidePlaceholder();
@@ -1423,10 +1613,10 @@ window.openAIChatManager = function () {
1423
1613
  }
1424
1614
  if (this.isRecording) {
1425
1615
  this.micButton.classList.add('stt-recording');
1426
- this.micButton.innerHTML = '<span class="fa-solid fa-stop"></span>';
1616
+ this.micButton.innerHTML = '<i class="fa-solid fa-stop"></i>';
1427
1617
  } else {
1428
1618
  this.micButton.classList.remove('stt-recording');
1429
- this.micButton.innerHTML = '<span class="fa-solid fa-microphone"></span>';
1619
+ this.micButton.innerHTML = '<i class="fa-solid fa-microphone"></i>';
1430
1620
  }
1431
1621
  },
1432
1622
  streamMessage: function streamMessage(profileId, trimmedPrompt, sessionProfileId) {
@@ -1471,9 +1661,9 @@ window.openAIChatManager = function () {
1471
1661
  message.title = chunk.title;
1472
1662
  }
1473
1663
  if (chunk.references && _typeof(chunk.references) === "object" && Object.keys(chunk.references).length) {
1474
- for (var _i3 = 0, _Object$entries2 = Object.entries(chunk.references); _i3 < _Object$entries2.length; _i3++) {
1664
+ for (var _i4 = 0, _Object$entries2 = Object.entries(chunk.references); _i4 < _Object$entries2.length; _i4++) {
1475
1665
  var _normalizeReference2;
1476
- var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i3], 2),
1666
+ var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i4], 2),
1477
1667
  key = _Object$entries2$_i[0],
1478
1668
  value = _Object$entries2$_i[1];
1479
1669
  references[key] = (_normalizeReference2 = normalizeReference(value)) !== null && _normalizeReference2 !== void 0 ? _normalizeReference2 : {};
@@ -1488,22 +1678,12 @@ window.openAIChatManager = function () {
1488
1678
  if (chunk.responseId) {
1489
1679
  lastResponseId = chunk.responseId;
1490
1680
  }
1491
- var processedContent = chunk.content;
1492
- for (var _i4 = 0, _Object$entries3 = Object.entries(references); _i4 < _Object$entries3.length; _i4++) {
1493
- var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i4], 2),
1494
- _key2 = _Object$entries3$_i[0],
1495
- _value3 = _Object$entries3$_i[1];
1496
- processedContent = processedContent.replaceAll(_key2, "<sup><strong>".concat(_value3.index, "</strong></sup>"));
1497
- }
1498
-
1499
- // Append processed content to the message.
1500
- // if we have multiple references, add a comma to ensure we don't concatenate numbers.
1501
- content += processedContent.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1681
+ content += chunk.content;
1502
1682
  }
1503
1683
 
1504
1684
  // Update the existing message
1505
- message.content = content;
1506
- message.htmlContent = parseMarkdownContent(content, message);
1685
+ message.rawContent = content;
1686
+ updateMessagePresentation(message, references);
1507
1687
  _this8.messages[messageIndex] = message;
1508
1688
  _this8.$nextTick(function () {
1509
1689
  renderChartsInMessage(message);
@@ -1556,89 +1736,22 @@ window.openAIChatManager = function () {
1556
1736
  };
1557
1737
  return newMessage;
1558
1738
  },
1739
+ getErrorMessage: function getErrorMessage(error) {
1740
+ var content = typeof error === 'string' && error.trim() ? error : "Something went wrong. Please try again.";
1741
+ return {
1742
+ role: "assistant",
1743
+ content: content,
1744
+ htmlContent: ""
1745
+ };
1746
+ },
1559
1747
  processReferences: function processReferences(references, messageIndex) {
1560
1748
  var _this9 = this;
1561
1749
  references = normalizeReferences(references);
1562
1750
  if (Object.keys(references).length) {
1751
+ var _ref23, _message$rawContent2;
1563
1752
  var message = this.messages[messageIndex];
1564
- var content = message.content || '';
1565
-
1566
- // Only include references that were actually cited in the response.
1567
- // Check both raw [doc:N] markers and already-rendered <sup> tags from streaming.
1568
- var citedRefs = Object.entries(references).filter(function (_ref12) {
1569
- var _ref13 = _slicedToArray(_ref12, 2),
1570
- key = _ref13[0],
1571
- value = _ref13[1];
1572
- return content.includes(key) || content.includes("<sup><strong>".concat(value.index, "</strong></sup>"));
1573
- });
1574
- if (!citedRefs.length) {
1575
- return;
1576
- }
1577
-
1578
- // Sort by original index so display indices follow a natural order.
1579
- citedRefs.sort(function (_ref14, _ref15) {
1580
- var _ref16 = _slicedToArray(_ref14, 2),
1581
- a = _ref16[1];
1582
- var _ref17 = _slicedToArray(_ref15, 2),
1583
- b = _ref17[1];
1584
- return a.index - b.index;
1585
- });
1586
-
1587
- // Phase 1: Replace all markers with unique placeholders to avoid collisions during remapping.
1588
- var processed = content.trim();
1589
- var displayIndex = 1;
1590
- var _iterator5 = _createForOfIteratorHelper(citedRefs),
1591
- _step5;
1592
- try {
1593
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
1594
- var _step5$value = _slicedToArray(_step5.value, 2),
1595
- key = _step5$value[0],
1596
- value = _step5$value[1];
1597
- var placeholder = "__CITE_".concat(value.index, "__");
1598
- processed = processed.replaceAll(key, placeholder);
1599
- processed = processed.replaceAll("<sup><strong>".concat(value.index, "</strong></sup>"), placeholder);
1600
- value._displayIndex = displayIndex++;
1601
- value._placeholder = placeholder;
1602
- }
1603
-
1604
- // Phase 2: Replace placeholders with sequential display indices.
1605
- } catch (err) {
1606
- _iterator5.e(err);
1607
- } finally {
1608
- _iterator5.f();
1609
- }
1610
- var _iterator6 = _createForOfIteratorHelper(citedRefs),
1611
- _step6;
1612
- try {
1613
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1614
- var _step6$value = _slicedToArray(_step6.value, 2),
1615
- _value4 = _step6$value[1];
1616
- processed = processed.replaceAll(_value4._placeholder, "<sup><strong>".concat(_value4._displayIndex, "</strong></sup>"));
1617
- }
1618
- } catch (err) {
1619
- _iterator6.e(err);
1620
- } finally {
1621
- _iterator6.f();
1622
- }
1623
- processed = processed.replaceAll('</strong></sup><sup>', '</strong></sup><sup>,</sup><sup>');
1624
- processed += '<br><br>';
1625
- var _iterator7 = _createForOfIteratorHelper(citedRefs),
1626
- _step7;
1627
- try {
1628
- for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
1629
- var _step7$value = _slicedToArray(_step7.value, 2),
1630
- _key3 = _step7$value[0],
1631
- _value5 = _step7$value[1];
1632
- var label = _value5.text || _key3;
1633
- processed += _value5.link ? "**".concat(_value5._displayIndex, "**. [").concat(label, "](").concat(_value5.link, ")<br>") : "**".concat(_value5._displayIndex, "**. ").concat(label, "<br>");
1634
- }
1635
- } catch (err) {
1636
- _iterator7.e(err);
1637
- } finally {
1638
- _iterator7.f();
1639
- }
1640
- message.content = processed;
1641
- message.htmlContent = parseMarkdownContent(processed, message);
1753
+ message.rawContent = (_ref23 = (_message$rawContent2 = message.rawContent) !== null && _message$rawContent2 !== void 0 ? _message$rawContent2 : message.content) !== null && _ref23 !== void 0 ? _ref23 : '';
1754
+ updateMessagePresentation(message, references);
1642
1755
  this.messages[messageIndex] = message;
1643
1756
  this.$nextTick(function () {
1644
1757
  renderChartsInMessage(message);
@@ -1701,16 +1814,42 @@ window.openAIChatManager = function () {
1701
1814
  buttons.forEach(function (button) {
1702
1815
  var buttonIndex = Number(button.getAttribute('data-tts-message-index'));
1703
1816
  var isPlaying = buttonIndex === _this0.ttsPlayingMessageIndex;
1704
- var iconHtml = isPlaying ? '<span class="fa-solid fa-circle-pause"></span>' : '<span class="fa-solid fa-circle-play"></span>';
1705
1817
  button.classList.toggle('tts-playing', isPlaying);
1706
1818
  button.setAttribute('title', isPlaying ? 'Pause audio' : 'Read aloud');
1819
+ });
1820
+ },
1821
+ updateCopyButtons: function updateCopyButtons() {
1822
+ var _this1 = this;
1823
+ if (!this.chatContainer) {
1824
+ return;
1825
+ }
1826
+ var buttons = this.chatContainer.querySelectorAll('[data-copy-message-index]');
1827
+ buttons.forEach(function (button) {
1828
+ var buttonIndex = Number(button.getAttribute('data-copy-message-index'));
1829
+ var isCopied = buttonIndex === _this1.copiedMessageIndex;
1830
+ var iconHtml = isCopied ? '<i class="fa-solid fa-check"></i>' : '<i class="fa-solid fa-copy"></i>';
1831
+ button.classList.toggle('text-success', isCopied);
1832
+ button.classList.toggle('text-secondary', !isCopied);
1833
+ button.setAttribute('title', isCopied ? _this1.copiedTitle : _this1.copyTitle);
1707
1834
  button.replaceChildren(DOMPurify.sanitize(iconHtml, {
1708
1835
  RETURN_DOM_FRAGMENT: true
1709
1836
  }));
1710
1837
  });
1711
1838
  },
1839
+ setCopyButtonState: function setCopyButtonState(button, isCopied) {
1840
+ if (!button) {
1841
+ return;
1842
+ }
1843
+ var iconHtml = isCopied ? '<i class="fa-solid fa-check"></i>' : '<i class="fa-solid fa-copy"></i>';
1844
+ button.classList.toggle('text-success', isCopied);
1845
+ button.classList.toggle('text-secondary', !isCopied);
1846
+ button.setAttribute('title', isCopied ? this.copiedTitle : this.copyTitle);
1847
+ button.replaceChildren(DOMPurify.sanitize(iconHtml, {
1848
+ RETURN_DOM_FRAGMENT: true
1849
+ }));
1850
+ },
1712
1851
  synthesizeSpeech: function synthesizeSpeech(text, cacheIndex) {
1713
- var _this1 = this;
1852
+ var _this10 = this;
1714
1853
  if (!this.textToSpeechEnabled || !text || !this.connection) {
1715
1854
  return;
1716
1855
  }
@@ -1719,16 +1858,16 @@ window.openAIChatManager = function () {
1719
1858
  this._ttsCacheIndex = cacheIndex !== undefined ? cacheIndex : -1;
1720
1859
  this.connection.invoke("SynthesizeSpeech", this.getProfileId(), this.getSessionId(), text, this.ttsVoiceName)["catch"](function (err) {
1721
1860
  console.error("TTS synthesis error:", err);
1722
- _this1.isPlayingAudio = false;
1723
- _this1.ttsPlayingMessageIndex = -1;
1724
- _this1._ttsCacheIndex = -1;
1725
- _this1.$nextTick(function () {
1726
- return _this1.updateTtsPlaybackButtons();
1861
+ _this10.isPlayingAudio = false;
1862
+ _this10.ttsPlayingMessageIndex = -1;
1863
+ _this10._ttsCacheIndex = -1;
1864
+ _this10.$nextTick(function () {
1865
+ return _this10.updateTtsPlaybackButtons();
1727
1866
  });
1728
1867
  });
1729
1868
  },
1730
1869
  toggleMessageTts: function toggleMessageTts(message, index) {
1731
- var _this10 = this;
1870
+ var _this11 = this;
1732
1871
  if (this.ttsPlayingMessageIndex === index) {
1733
1872
  this.stopAudio();
1734
1873
  return;
@@ -1741,7 +1880,7 @@ window.openAIChatManager = function () {
1741
1880
  }));
1742
1881
  this.ttsPlayingMessageIndex = index;
1743
1882
  this.$nextTick(function () {
1744
- return _this10.updateTtsPlaybackButtons();
1883
+ return _this11.updateTtsPlaybackButtons();
1745
1884
  });
1746
1885
  if (this.ttsAudioCache[index]) {
1747
1886
  this.playAudioBlob(this.ttsAudioCache[index]);
@@ -1750,13 +1889,13 @@ window.openAIChatManager = function () {
1750
1889
  this.synthesizeSpeech(message.content, index);
1751
1890
  },
1752
1891
  playCollectedAudio: function playCollectedAudio() {
1753
- var _this11 = this;
1892
+ var _this12 = this;
1754
1893
  if (this.audioChunks.length === 0) {
1755
1894
  if (!this.currentAudioElement && this.audioPlayQueue.length === 0) {
1756
1895
  this.isPlayingAudio = false;
1757
1896
  this.ttsPlayingMessageIndex = -1;
1758
1897
  this.$nextTick(function () {
1759
- return _this11.updateTtsPlaybackButtons();
1898
+ return _this12.updateTtsPlaybackButtons();
1760
1899
  });
1761
1900
  }
1762
1901
  return;
@@ -1766,18 +1905,18 @@ window.openAIChatManager = function () {
1766
1905
  }, 0);
1767
1906
  var combined = new Uint8Array(totalLength);
1768
1907
  var offset = 0;
1769
- var _iterator8 = _createForOfIteratorHelper(this.audioChunks),
1770
- _step8;
1908
+ var _iterator6 = _createForOfIteratorHelper(this.audioChunks),
1909
+ _step6;
1771
1910
  try {
1772
- for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
1773
- var chunk = _step8.value;
1911
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
1912
+ var chunk = _step6.value;
1774
1913
  combined.set(chunk, offset);
1775
1914
  offset += chunk.length;
1776
1915
  }
1777
1916
  } catch (err) {
1778
- _iterator8.e(err);
1917
+ _iterator6.e(err);
1779
1918
  } finally {
1780
- _iterator8.f();
1919
+ _iterator6.f();
1781
1920
  }
1782
1921
  this.audioChunks = [];
1783
1922
  var blob = new Blob([combined], {
@@ -1796,39 +1935,39 @@ window.openAIChatManager = function () {
1796
1935
  this.playAudioBlob(blob);
1797
1936
  },
1798
1937
  playAudioBlob: function playAudioBlob(blob) {
1799
- var _this12 = this;
1938
+ var _this13 = this;
1800
1939
  var url = URL.createObjectURL(blob);
1801
1940
  var audio = new Audio(url);
1802
1941
  this.currentAudioUrl = url;
1803
1942
  this.currentAudioElement = audio;
1804
1943
  this.isPlayingAudio = true;
1805
1944
  audio.addEventListener('ended', function () {
1806
- _this12.currentAudioElement = null;
1807
- _this12.currentAudioUrl = null;
1945
+ _this13.currentAudioElement = null;
1946
+ _this13.currentAudioUrl = null;
1808
1947
  URL.revokeObjectURL(url);
1809
- _this12.playNextInQueue();
1948
+ _this13.playNextInQueue();
1810
1949
  });
1811
1950
  audio.addEventListener('error', function () {
1812
- _this12.currentAudioElement = null;
1813
- _this12.currentAudioUrl = null;
1951
+ _this13.currentAudioElement = null;
1952
+ _this13.currentAudioUrl = null;
1814
1953
  URL.revokeObjectURL(url);
1815
- _this12.playNextInQueue();
1954
+ _this13.playNextInQueue();
1816
1955
  });
1817
1956
  audio.play()["catch"](function (err) {
1818
1957
  console.error("Audio playback error:", err);
1819
- _this12.currentAudioElement = null;
1820
- _this12.currentAudioUrl = null;
1958
+ _this13.currentAudioElement = null;
1959
+ _this13.currentAudioUrl = null;
1821
1960
  URL.revokeObjectURL(url);
1822
- _this12.audioPlayQueue = [];
1823
- _this12.isPlayingAudio = false;
1824
- _this12.ttsPlayingMessageIndex = -1;
1825
- _this12.$nextTick(function () {
1826
- return _this12.updateTtsPlaybackButtons();
1961
+ _this13.audioPlayQueue = [];
1962
+ _this13.isPlayingAudio = false;
1963
+ _this13.ttsPlayingMessageIndex = -1;
1964
+ _this13.$nextTick(function () {
1965
+ return _this13.updateTtsPlaybackButtons();
1827
1966
  });
1828
1967
  });
1829
1968
  },
1830
1969
  playNextInQueue: function playNextInQueue() {
1831
- var _this13 = this;
1970
+ var _this14 = this;
1832
1971
  if (this.audioPlayQueue.length > 0) {
1833
1972
  var nextBlob = this.audioPlayQueue.shift();
1834
1973
  this.playAudioBlob(nextBlob);
@@ -1836,13 +1975,13 @@ window.openAIChatManager = function () {
1836
1975
  this.isPlayingAudio = false;
1837
1976
  this.ttsPlayingMessageIndex = -1;
1838
1977
  this.$nextTick(function () {
1839
- return _this13.updateTtsPlaybackButtons();
1978
+ return _this14.updateTtsPlaybackButtons();
1840
1979
  });
1841
1980
  this.conversationModeOnAudioEnded();
1842
1981
  }
1843
1982
  },
1844
1983
  stopAudio: function stopAudio() {
1845
- var _this14 = this;
1984
+ var _this15 = this;
1846
1985
  if (this.currentAudioElement) {
1847
1986
  this.currentAudioElement.pause();
1848
1987
  this.currentAudioElement.currentTime = 0;
@@ -1857,7 +1996,7 @@ window.openAIChatManager = function () {
1857
1996
  this.isPlayingAudio = false;
1858
1997
  this.ttsPlayingMessageIndex = -1;
1859
1998
  this.$nextTick(function () {
1860
- return _this14.updateTtsPlaybackButtons();
1999
+ return _this15.updateTtsPlaybackButtons();
1861
2000
  });
1862
2001
  },
1863
2002
  toggleConversationMode: function toggleConversationMode() {
@@ -1868,7 +2007,7 @@ window.openAIChatManager = function () {
1868
2007
  }
1869
2008
  },
1870
2009
  startConversationMode: function startConversationMode() {
1871
- var _this15 = this;
2010
+ var _this16 = this;
1872
2011
  if (!this.conversationModeEnabled || this.isConversationMode || !this.connection) {
1873
2012
  return;
1874
2013
  }
@@ -1888,12 +2027,12 @@ window.openAIChatManager = function () {
1888
2027
  }
1889
2028
  }).then(function (stream) {
1890
2029
  var mimeType = MediaRecorder.isTypeSupported('audio/ogg;codecs=opus') ? 'audio/ogg;codecs=opus' : MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' : 'audio/webm';
1891
- _this15.mediaRecorder = new MediaRecorder(stream, {
2030
+ _this16.mediaRecorder = new MediaRecorder(stream, {
1892
2031
  mimeType: mimeType,
1893
2032
  audioBitsPerSecond: 128000
1894
2033
  });
1895
- _this15._conversationSubject = new signalR.Subject();
1896
- _this15._conversationStream = stream;
2034
+ _this16._conversationSubject = new signalR.Subject();
2035
+ _this16._conversationStream = stream;
1897
2036
 
1898
2037
  // Create an AnalyserNode for volume-based interrupt detection.
1899
2038
  // During TTS playback, detect when the user speaks above
@@ -1902,20 +2041,20 @@ window.openAIChatManager = function () {
1902
2041
  // speaker echo so the STT stream has no gaps.
1903
2042
  var AudioCtx = window.AudioContext || window.webkitAudioContext;
1904
2043
  if (AudioCtx) {
1905
- _this15._conversationAudioCtx = new AudioCtx();
1906
- _this15._conversationAnalyser = _this15._conversationAudioCtx.createAnalyser();
1907
- _this15._conversationAnalyser.fftSize = 256;
1908
- var micSource = _this15._conversationAudioCtx.createMediaStreamSource(stream);
1909
- micSource.connect(_this15._conversationAnalyser);
2044
+ _this16._conversationAudioCtx = new AudioCtx();
2045
+ _this16._conversationAnalyser = _this16._conversationAudioCtx.createAnalyser();
2046
+ _this16._conversationAnalyser.fftSize = 256;
2047
+ var micSource = _this16._conversationAudioCtx.createMediaStreamSource(stream);
2048
+ micSource.connect(_this16._conversationAnalyser);
1910
2049
  }
1911
2050
  var pendingChunk = Promise.resolve();
1912
- var analyser = _this15._conversationAnalyser;
2051
+ var analyser = _this16._conversationAnalyser;
1913
2052
  var interruptVolumeThreshold = 30;
1914
- _this15.mediaRecorder.addEventListener('dataavailable', function (e) {
2053
+ _this16.mediaRecorder.addEventListener('dataavailable', function (e) {
1915
2054
  if (e.data && e.data.size > 0) {
1916
2055
  // During TTS playback, check mic volume to detect
1917
2056
  // user interruption (speaking above threshold).
1918
- if (_this15.isPlayingAudio && analyser) {
2057
+ if (_this16.isPlayingAudio && analyser) {
1919
2058
  var freqData = new Uint8Array(analyser.frequencyBinCount);
1920
2059
  analyser.getByteFrequencyData(freqData);
1921
2060
  var sum = 0;
@@ -1925,7 +2064,7 @@ window.openAIChatManager = function () {
1925
2064
  var avg = sum / freqData.length;
1926
2065
  if (avg >= interruptVolumeThreshold) {
1927
2066
  // User is speaking — interrupt TTS playback.
1928
- _this15.stopAudio();
2067
+ _this16.stopAudio();
1929
2068
  }
1930
2069
  }
1931
2070
 
@@ -1947,7 +2086,7 @@ window.openAIChatManager = function () {
1947
2086
  }, '');
1948
2087
  base64 = btoa(binaryString);
1949
2088
  try {
1950
- _this15._conversationSubject.next(base64);
2089
+ _this16._conversationSubject.next(base64);
1951
2090
  } catch (err) {
1952
2091
  // Subject may have been completed already.
1953
2092
  }
@@ -1958,28 +2097,28 @@ window.openAIChatManager = function () {
1958
2097
  })));
1959
2098
  }
1960
2099
  });
1961
- _this15.mediaRecorder.addEventListener('stop', function () {
2100
+ _this16.mediaRecorder.addEventListener('stop', function () {
1962
2101
  stream.getTracks().forEach(function (track) {
1963
2102
  return track.stop();
1964
2103
  });
1965
2104
  pendingChunk.then(function () {
1966
2105
  try {
1967
- _this15._conversationSubject.complete();
2106
+ _this16._conversationSubject.complete();
1968
2107
  } catch (err) {
1969
2108
  // Already completed.
1970
2109
  }
1971
2110
  });
1972
2111
  });
1973
- var profileId = _this15.getProfileId();
1974
- var sessionId = _this15.getSessionId() || '';
2112
+ var profileId = _this16.getProfileId();
2113
+ var sessionId = _this16.getSessionId() || '';
1975
2114
  var language = navigator.language || document.documentElement.lang || 'en-US';
1976
- _this15.connection.send("StartConversation", profileId, sessionId, _this15._conversationSubject, mimeType, language);
1977
- _this15.mediaRecorder.start(250);
1978
- _this15.isRecording = true;
2115
+ _this16.connection.send("StartConversation", profileId, sessionId, _this16._conversationSubject, mimeType, language);
2116
+ _this16.mediaRecorder.start(250);
2117
+ _this16.isRecording = true;
1979
2118
  })["catch"](function (err) {
1980
2119
  console.error('Microphone access denied:', err);
1981
- _this15.isConversationMode = false;
1982
- _this15.updateConversationButton();
2120
+ _this16.isConversationMode = false;
2121
+ _this16.updateConversationButton();
1983
2122
  });
1984
2123
  },
1985
2124
  stopConversationMode: function stopConversationMode() {
@@ -2106,7 +2245,7 @@ window.openAIChatManager = function () {
2106
2245
  return removedCount;
2107
2246
  },
2108
2247
  receiveNotification: function receiveNotification(notification) {
2109
- var _this16 = this;
2248
+ var _this17 = this;
2110
2249
  if (!notification || !notification.type) {
2111
2250
  return;
2112
2251
  }
@@ -2121,7 +2260,7 @@ window.openAIChatManager = function () {
2121
2260
  }
2122
2261
  this.scheduleNotificationDismiss(notification);
2123
2262
  this.$nextTick(function () {
2124
- _this16.scrollToBottom();
2263
+ _this17.scrollToBottom();
2125
2264
  });
2126
2265
  },
2127
2266
  updateNotification: function updateNotification(notification) {
@@ -2138,12 +2277,12 @@ window.openAIChatManager = function () {
2138
2277
  }
2139
2278
  },
2140
2279
  scheduleNotificationDismiss: function scheduleNotificationDismiss(notification) {
2141
- var _this17 = this;
2280
+ var _this18 = this;
2142
2281
  if (!notification || !notification.type || !notification.autoDismissMs || notification.autoDismissMs <= 0) {
2143
2282
  return;
2144
2283
  }
2145
2284
  this.notificationDismissTimers[notification.type] = setTimeout(function () {
2146
- _this17.removeNotification(notification.type);
2285
+ _this18.removeNotification(notification.type);
2147
2286
  }, notification.autoDismissMs);
2148
2287
  },
2149
2288
  clearNotificationDismiss: function clearNotificationDismiss(notificationType) {
@@ -2173,12 +2312,12 @@ window.openAIChatManager = function () {
2173
2312
  });
2174
2313
  },
2175
2314
  scrollToBottom: function scrollToBottom() {
2176
- var _this18 = this;
2315
+ var _this19 = this;
2177
2316
  if (!this.autoScroll) {
2178
2317
  return;
2179
2318
  }
2180
2319
  setTimeout(function () {
2181
- _this18.chatContainer.scrollTop = _this18.chatContainer.scrollHeight - _this18.chatContainer.clientHeight;
2320
+ _this19.chatContainer.scrollTop = _this19.chatContainer.scrollHeight - _this19.chatContainer.clientHeight;
2182
2321
  }, 50);
2183
2322
  },
2184
2323
  handleUserInput: function handleUserInput(event) {
@@ -2201,12 +2340,17 @@ window.openAIChatManager = function () {
2201
2340
  this.sessionRating = null;
2202
2341
  this.messages = [];
2203
2342
  this.documents = [];
2204
- if (!config.autoCreateSession) {
2343
+
2344
+ // When an initial prompt is configured, show it as the first
2345
+ // assistant message instead of the generic placeholder.
2346
+ if (config.initialPrompt) {
2347
+ this.addMessage({
2348
+ role: 'assistant',
2349
+ content: config.initialPrompt
2350
+ });
2351
+ } else {
2205
2352
  this.showPlaceholder();
2206
2353
  }
2207
- if (config.autoCreateSession) {
2208
- this.startNewSession();
2209
- }
2210
2354
  if (widgetBehavior && typeof widgetBehavior.onSessionReset === 'function') {
2211
2355
  widgetBehavior.onSessionReset(this, config);
2212
2356
  }
@@ -2224,27 +2368,27 @@ window.openAIChatManager = function () {
2224
2368
  });
2225
2369
  },
2226
2370
  ensureSessionForDocuments: function ensureSessionForDocuments(profileId) {
2227
- var _this19 = this;
2371
+ var _this20 = this;
2228
2372
  return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
2229
2373
  var sessionId;
2230
2374
  return _regenerator().w(function (_context9) {
2231
2375
  while (1) switch (_context9.n) {
2232
2376
  case 0:
2233
- sessionId = _this19.getSessionId();
2377
+ sessionId = _this20.getSessionId();
2234
2378
  if (!sessionId) {
2235
2379
  _context9.n = 1;
2236
2380
  break;
2237
2381
  }
2238
2382
  return _context9.a(2, sessionId);
2239
2383
  case 1:
2240
- if (!(!profileId || !_this19.connection)) {
2384
+ if (!(!profileId || !_this20.connection)) {
2241
2385
  _context9.n = 2;
2242
2386
  break;
2243
2387
  }
2244
2388
  return _context9.a(2, null);
2245
2389
  case 2:
2246
2390
  _context9.n = 3;
2247
- return _this19.requestNewSession(profileId);
2391
+ return _this20.requestNewSession(profileId);
2248
2392
  case 3:
2249
2393
  return _context9.a(2, _context9.v);
2250
2394
  }
@@ -2252,7 +2396,7 @@ window.openAIChatManager = function () {
2252
2396
  }))();
2253
2397
  },
2254
2398
  requestNewSession: function requestNewSession(profileId) {
2255
- var _this20 = this;
2399
+ var _this21 = this;
2256
2400
  if (this.pendingSessionPromise) {
2257
2401
  return this.pendingSessionPromise;
2258
2402
  }
@@ -2260,14 +2404,14 @@ window.openAIChatManager = function () {
2260
2404
  return Promise.resolve(null);
2261
2405
  }
2262
2406
  this.pendingSessionPromise = new Promise(function (resolve, reject) {
2263
- _this20.pendingSessionResolver = resolve;
2264
- _this20.pendingSessionRejector = reject;
2265
- _this20.pendingSessionTimeoutId = window.setTimeout(function () {
2266
- _this20.rejectPendingSessionRequest('Timed out while creating a chat session.');
2407
+ _this21.pendingSessionResolver = resolve;
2408
+ _this21.pendingSessionRejector = reject;
2409
+ _this21.pendingSessionTimeoutId = window.setTimeout(function () {
2410
+ _this21.rejectPendingSessionRequest('Timed out while creating a chat session.');
2267
2411
  }, 15000);
2268
2412
  });
2269
2413
  this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2270
- _this20.rejectPendingSessionRequest(err);
2414
+ _this21.rejectPendingSessionRequest(err);
2271
2415
  });
2272
2416
  return this.pendingSessionPromise;
2273
2417
  },
@@ -2293,7 +2437,7 @@ window.openAIChatManager = function () {
2293
2437
  this.pendingSessionTimeoutId = null;
2294
2438
  },
2295
2439
  initializeApp: function initializeApp() {
2296
- var _this21 = this;
2440
+ var _this22 = this;
2297
2441
  this.inputElement = document.querySelector(config.inputElementSelector);
2298
2442
  this.buttonElement = document.querySelector(config.sendButtonElementSelector);
2299
2443
  this.chatContainer = document.querySelector(config.chatContainerElementSelector);
@@ -2311,8 +2455,6 @@ window.openAIChatManager = function () {
2311
2455
  var sessionId = this.getSessionId();
2312
2456
  if (!hasWidgetConfig && sessionId) {
2313
2457
  this.loadSession(sessionId);
2314
- } else if (this.isOrchestratorAvailable() && config.autoCreateSession && !hasWidgetConfig && !sessionId) {
2315
- this.startNewSession();
2316
2458
  }
2317
2459
 
2318
2460
  // Initialize document bar if enabled.
@@ -2331,7 +2473,7 @@ window.openAIChatManager = function () {
2331
2473
  fileInput.accept = config.allowedExtensions;
2332
2474
  }
2333
2475
  fileInput.addEventListener('change', function (e) {
2334
- return _this21.handleFileInputChange(e);
2476
+ return _this22.handleFileInputChange(e);
2335
2477
  });
2336
2478
  this.documentBar.parentElement.appendChild(fileInput);
2337
2479
 
@@ -2339,13 +2481,13 @@ window.openAIChatManager = function () {
2339
2481
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
2340
2482
  if (inputArea) {
2341
2483
  inputArea.addEventListener('dragover', function (e) {
2342
- return _this21.handleDragOver(e);
2484
+ return _this22.handleDragOver(e);
2343
2485
  });
2344
2486
  inputArea.addEventListener('dragleave', function (e) {
2345
- return _this21.handleDragLeave(e);
2487
+ return _this22.handleDragLeave(e);
2346
2488
  });
2347
2489
  inputArea.addEventListener('drop', function (e) {
2348
- return _this21.handleDrop(e);
2490
+ return _this22.handleDrop(e);
2349
2491
  });
2350
2492
  }
2351
2493
  }
@@ -2353,55 +2495,55 @@ window.openAIChatManager = function () {
2353
2495
 
2354
2496
  // Pause auto-scroll when the user manually scrolls up during streaming.
2355
2497
  this.chatContainer.addEventListener('scroll', function () {
2356
- if (!_this21.stream) {
2498
+ if (!_this22.stream) {
2357
2499
  return;
2358
2500
  }
2359
2501
  var threshold = 30;
2360
- var atBottom = _this21.chatContainer.scrollHeight - _this21.chatContainer.clientHeight - _this21.chatContainer.scrollTop <= threshold;
2361
- _this21.autoScroll = atBottom;
2502
+ var atBottom = _this22.chatContainer.scrollHeight - _this22.chatContainer.clientHeight - _this22.chatContainer.scrollTop <= threshold;
2503
+ _this22.autoScroll = atBottom;
2362
2504
  });
2363
2505
  this.inputElement.addEventListener('keydown', function (event) {
2364
- if (_this21.stream != null) {
2506
+ if (_this22.stream != null) {
2365
2507
  return;
2366
2508
  }
2367
2509
  if (event.key === "Enter" && !event.shiftKey) {
2368
2510
  event.preventDefault();
2369
- _this21.buttonElement.click();
2511
+ _this22.buttonElement.click();
2370
2512
  }
2371
2513
  });
2372
2514
  this.inputElement.addEventListener('input', function (e) {
2373
- _this21.handleUserInput(e);
2515
+ _this22.handleUserInput(e);
2374
2516
  if (e.target.value.trim()) {
2375
- _this21.buttonElement.removeAttribute('disabled');
2517
+ _this22.buttonElement.removeAttribute('disabled');
2376
2518
  } else {
2377
- _this21.buttonElement.setAttribute('disabled', true);
2519
+ _this22.buttonElement.setAttribute('disabled', true);
2378
2520
  }
2379
2521
  });
2380
2522
  this.buttonElement.addEventListener('click', function () {
2381
- if (_this21.stream != null) {
2382
- _this21.stream.dispose();
2383
- _this21.stream = null;
2384
- _this21.streamingFinished();
2385
- _this21.hideTypingIndicator();
2523
+ if (_this22.stream != null) {
2524
+ _this22.stream.dispose();
2525
+ _this22.stream = null;
2526
+ _this22.streamingFinished();
2527
+ _this22.hideTypingIndicator();
2386
2528
 
2387
2529
  // Clean up: remove empty assistant message or stop streaming animation.
2388
- if (_this21.messages.length > 0) {
2389
- var lastMsg = _this21.messages[_this21.messages.length - 1];
2530
+ if (_this22.messages.length > 0) {
2531
+ var lastMsg = _this22.messages[_this22.messages.length - 1];
2390
2532
  if (lastMsg.role === 'assistant' && !lastMsg.content) {
2391
- _this21.messages.pop();
2533
+ _this22.messages.pop();
2392
2534
  } else if (lastMsg.isStreaming) {
2393
2535
  lastMsg.isStreaming = false;
2394
2536
  }
2395
2537
  }
2396
2538
  return;
2397
2539
  }
2398
- _this21.sendMessage();
2540
+ _this22.sendMessage();
2399
2541
  });
2400
2542
  var promptGenerators = document.getElementsByClassName('profile-generated-prompt');
2401
2543
  for (var i = 0; i < promptGenerators.length; i++) {
2402
2544
  promptGenerators[i].addEventListener('click', function (e) {
2403
2545
  e.preventDefault();
2404
- _this21.generatePrompt(e.target);
2546
+ _this22.generatePrompt(e.target);
2405
2547
  });
2406
2548
  }
2407
2549
  var chatSessions = document.getElementsByClassName('chat-session-history-item');
@@ -2413,17 +2555,27 @@ window.openAIChatManager = function () {
2413
2555
  console.error('an element with the class chat-session-history-item with no data-session-id set.');
2414
2556
  return;
2415
2557
  }
2416
- _this21.loadSession(sessionId);
2417
- _this21.showChatScreen();
2558
+ _this22.loadSession(sessionId);
2559
+ _this22.showChatScreen();
2418
2560
  });
2419
2561
  }
2420
- for (var _i5 = 0; _i5 < config.messages.length; _i5++) {
2421
- this.addMessage(config.messages[_i5]);
2562
+ var initialMessages = Array.isArray(config.messages) ? config.messages : [];
2563
+ for (var _i5 = 0; _i5 < initialMessages.length; _i5++) {
2564
+ this.addMessage(initialMessages[_i5]);
2565
+ }
2566
+
2567
+ // When no messages were loaded and an initial prompt is configured,
2568
+ // display it as the first assistant message without invoking the AI.
2569
+ if (this.messages.length === 0 && config.initialPrompt) {
2570
+ this.addMessage({
2571
+ role: 'assistant',
2572
+ content: config.initialPrompt
2573
+ });
2422
2574
  }
2423
2575
 
2424
2576
  // Update feedback icons in the DOM after initial messages have rendered.
2425
2577
  this.$nextTick(function () {
2426
- _this21.refreshAllFeedbackIcons();
2578
+ _this22.refreshAllFeedbackIcons();
2427
2579
  });
2428
2580
 
2429
2581
  // Delegate click for code block copy buttons.
@@ -2441,9 +2593,9 @@ window.openAIChatManager = function () {
2441
2593
  if (codeEl) {
2442
2594
  navigator.clipboard.writeText(codeEl.textContent);
2443
2595
  var copiedText = config.codeCopiedText || 'Copied!';
2444
- btn.innerHTML = '<span class="fa-solid fa-check"></span> ' + copiedText;
2596
+ btn.innerHTML = '<i class="fa-solid fa-check"></i> ' + copiedText;
2445
2597
  setTimeout(function () {
2446
- btn.innerHTML = '<span class="fa-regular fa-copy"></span>';
2598
+ btn.innerHTML = '<i class="fa-regular fa-copy"></i>';
2447
2599
  }, 2000);
2448
2600
  }
2449
2601
  });
@@ -2455,7 +2607,7 @@ window.openAIChatManager = function () {
2455
2607
  if (this.micButton) {
2456
2608
  this.micButton.style.display = '';
2457
2609
  this.micButton.addEventListener('click', function () {
2458
- _this21.toggleRecording();
2610
+ _this22.toggleRecording();
2459
2611
  });
2460
2612
  }
2461
2613
  }
@@ -2465,7 +2617,7 @@ window.openAIChatManager = function () {
2465
2617
  this.conversationButton = document.querySelector(config.conversationButtonElementSelector);
2466
2618
  if (this.conversationButton) {
2467
2619
  this.conversationButton.addEventListener('click', function () {
2468
- _this21.toggleConversationMode();
2620
+ _this22.toggleConversationMode();
2469
2621
  });
2470
2622
  }
2471
2623
  }
@@ -2489,7 +2641,7 @@ window.openAIChatManager = function () {
2489
2641
  }
2490
2642
  return;
2491
2643
  }
2492
- this.fireEvent(new CustomEvent("initializingSessionOpenAIChat", {
2644
+ this.fireEvent(new CustomEvent("initializingSessionCoreAIChat", {
2493
2645
  detail: {
2494
2646
  sessionId: sessionId
2495
2647
  }
@@ -2500,6 +2652,13 @@ window.openAIChatManager = function () {
2500
2652
  if (widgetBehavior && typeof widgetBehavior.onSessionInitialized === 'function') {
2501
2653
  widgetBehavior.onSessionInitialized(this, sessionId, config);
2502
2654
  }
2655
+
2656
+ // For non-widget pages, update the browser URL so that a page
2657
+ // refresh reloads the correct session instead of starting fresh.
2658
+ if (!hasWidgetConfig && sessionId && config.sessionUrlTemplate && typeof history !== 'undefined' && history.replaceState) {
2659
+ var sessionUrl = config.sessionUrlTemplate.replace('{sessionId}', encodeURIComponent(sessionId));
2660
+ history.replaceState(null, '', sessionUrl);
2661
+ }
2503
2662
  },
2504
2663
  getSessionId: function getSessionId() {
2505
2664
  var sessionId = this.inputElement ? this.inputElement.getAttribute('data-session-id') : null;
@@ -2508,8 +2667,45 @@ window.openAIChatManager = function () {
2508
2667
  }
2509
2668
  return sessionId;
2510
2669
  },
2511
- copyResponse: function copyResponse(message) {
2512
- navigator.clipboard.writeText(message);
2670
+ clearCopiedMessageState: function clearCopiedMessageState() {
2671
+ if (this.copyResetTimeoutId) {
2672
+ window.clearTimeout(this.copyResetTimeoutId);
2673
+ this.copyResetTimeoutId = null;
2674
+ }
2675
+ if (this.activeCopyButton) {
2676
+ this.setCopyButtonState(this.activeCopyButton, false);
2677
+ this.activeCopyButton = null;
2678
+ }
2679
+ this.copiedMessageIndex = -1;
2680
+ },
2681
+ copyResponse: function copyResponse(message, index, event) {
2682
+ var _ref25,
2683
+ _message$copyContent,
2684
+ _event$target,
2685
+ _event$target$closest,
2686
+ _this23 = this;
2687
+ 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 : '';
2688
+ 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;
2689
+ navigator.clipboard.writeText(text).then(function () {
2690
+ _this23.clearCopiedMessageState();
2691
+ _this23.copiedMessageIndex = typeof index === 'number' ? index : -1;
2692
+ _this23.activeCopyButton = button;
2693
+ if (button) {
2694
+ _this23.setCopyButtonState(button, true);
2695
+ } else {
2696
+ _this23.$nextTick(function () {
2697
+ return _this23.updateCopyButtons();
2698
+ });
2699
+ }
2700
+ _this23.copyResetTimeoutId = window.setTimeout(function () {
2701
+ _this23.clearCopiedMessageState();
2702
+ _this23.$nextTick(function () {
2703
+ return _this23.updateCopyButtons();
2704
+ });
2705
+ }, Number(config.copyResetDelayMs) || 2000);
2706
+ })["catch"](function (err) {
2707
+ return console.error('Failed to copy response:', err);
2708
+ });
2513
2709
  },
2514
2710
  updateFeedbackIcons: function updateFeedbackIcons(container, userRating) {
2515
2711
  if (!container) {
@@ -2604,6 +2800,12 @@ window.openAIChatManager = function () {
2604
2800
  // Reserved for future use — volume-based interrupt detection
2605
2801
  // no longer mutes tracks; browser echo cancellation handles echo.
2606
2802
  },
2803
+ copiedMessageIndex: function copiedMessageIndex() {
2804
+ var _this24 = this;
2805
+ this.$nextTick(function () {
2806
+ return _this24.updateCopyButtons();
2807
+ });
2808
+ },
2607
2809
  isConversationMode: function isConversationMode(active) {
2608
2810
  // Hide/show mic button.
2609
2811
  if (this.micButton) {
@@ -2625,19 +2827,24 @@ window.openAIChatManager = function () {
2625
2827
  }
2626
2828
  },
2627
2829
  mounted: function mounted() {
2628
- var _this22 = this;
2830
+ var _this25 = this;
2629
2831
  _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
2630
2832
  var isInitialized;
2631
2833
  return _regenerator().w(function (_context0) {
2632
2834
  while (1) switch (_context0.n) {
2633
2835
  case 0:
2634
2836
  _context0.n = 1;
2635
- return _this22.startConnection();
2837
+ return _this25.startConnection();
2636
2838
  case 1:
2637
- isInitialized = _this22.initializeApp();
2839
+ isInitialized = _this25.initializeApp();
2638
2840
  if (isInitialized && hasWidgetConfig && widgetBehavior && typeof widgetBehavior.onMounted === 'function') {
2639
- widgetBehavior.onMounted(_this22, config);
2841
+ widgetBehavior.onMounted(_this25, config);
2640
2842
  }
2843
+ _this25.$nextTick(function () {
2844
+ _this25.updateCopyButtons();
2845
+ refreshFontAwesomeIcons(_this25.$el);
2846
+ _this25.fontAwesomeObserver = observeFontAwesomeIcons(_this25.$el);
2847
+ });
2641
2848
  case 2:
2642
2849
  return _context0.a(2);
2643
2850
  }
@@ -2649,6 +2856,11 @@ window.openAIChatManager = function () {
2649
2856
  beforeUnmount: function beforeUnmount() {
2650
2857
  window.removeEventListener('beforeunload', this.handleBeforeUnload);
2651
2858
  window.removeEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
2859
+ if (this.fontAwesomeObserver) {
2860
+ this.fontAwesomeObserver.disconnect();
2861
+ this.fontAwesomeObserver = null;
2862
+ }
2863
+ this.clearCopiedMessageState();
2652
2864
  this.stopAudio(false);
2653
2865
  if (this.stream) {
2654
2866
  this.stream.dispose();
@@ -2669,8 +2881,151 @@ window.openAIChatManager = function () {
2669
2881
  }
2670
2882
  return app;
2671
2883
  };
2884
+ var autoInitializeSelector = '[data-coreai-chat-config],[data-coreai-chat-app-element-selector]';
2885
+ function getAttributeValue(element, attributeName) {
2886
+ var value = element.getAttribute(attributeName);
2887
+ return value === null || value === '' ? null : value;
2888
+ }
2889
+ function parseBooleanAttributeValue(value) {
2890
+ if (value === null || value === undefined) {
2891
+ return null;
2892
+ }
2893
+ if (typeof value === 'boolean') {
2894
+ return value;
2895
+ }
2896
+ var normalized = String(value).trim().toLowerCase();
2897
+ if (normalized === 'true') {
2898
+ return true;
2899
+ }
2900
+ if (normalized === 'false') {
2901
+ return false;
2902
+ }
2903
+ return null;
2904
+ }
2905
+ function parseJsonAttribute(element, attributeName, description) {
2906
+ var rawValue = getAttributeValue(element, attributeName);
2907
+ if (!rawValue) {
2908
+ return null;
2909
+ }
2910
+ try {
2911
+ return JSON.parse(rawValue);
2912
+ } catch (error) {
2913
+ console.error('Failed to parse ' + description + ' JSON.', error);
2914
+ return null;
2915
+ }
2916
+ }
2917
+ function buildConfigFromDataAttributes(element, options) {
2918
+ var _parseJsonAttribute, _parseJsonAttribute2;
2919
+ var settings = options || {};
2920
+ if (element.hasAttribute('data-coreai-chat-widget-container-selector') && settings.allowWidgetHost !== true) {
2921
+ return null;
2922
+ }
2923
+ var appElementSelector = getAttributeValue(element, 'data-coreai-chat-app-element-selector');
2924
+ if (!appElementSelector) {
2925
+ return null;
2926
+ }
2927
+ var config = {
2928
+ signalRHubUrl: getAttributeValue(element, 'data-coreai-chat-signalr-hub-url'),
2929
+ appElementSelector: appElementSelector,
2930
+ chatContainerElementSelector: getAttributeValue(element, 'data-coreai-chat-container-element-selector'),
2931
+ inputElementSelector: getAttributeValue(element, 'data-coreai-chat-input-element-selector'),
2932
+ sendButtonElementSelector: getAttributeValue(element, 'data-coreai-chat-send-button-element-selector'),
2933
+ placeholderElementSelector: getAttributeValue(element, 'data-coreai-chat-placeholder-element-selector'),
2934
+ messages: (_parseJsonAttribute = parseJsonAttribute(element, 'data-coreai-chat-messages', 'CoreAI chat messages')) !== null && _parseJsonAttribute !== void 0 ? _parseJsonAttribute : undefined,
2935
+ chatMode: getAttributeValue(element, 'data-coreai-chat-mode'),
2936
+ micButtonElementSelector: getAttributeValue(element, 'data-coreai-chat-mic-button-element-selector'),
2937
+ conversationButtonElementSelector: getAttributeValue(element, 'data-coreai-chat-conversation-button-element-selector'),
2938
+ ttsVoiceName: getAttributeValue(element, 'data-coreai-chat-tts-voice-name'),
2939
+ documentBarSelector: getAttributeValue(element, 'data-coreai-chat-document-bar-selector'),
2940
+ uploadDocumentUrl: getAttributeValue(element, 'data-coreai-chat-upload-document-url'),
2941
+ removeDocumentUrl: getAttributeValue(element, 'data-coreai-chat-remove-document-url'),
2942
+ allowedExtensions: getAttributeValue(element, 'data-coreai-chat-allowed-extensions'),
2943
+ supportedExtensionsText: getAttributeValue(element, 'data-coreai-chat-supported-extensions-text'),
2944
+ existingDocuments: (_parseJsonAttribute2 = parseJsonAttribute(element, 'data-coreai-chat-existing-documents', 'CoreAI chat existing documents')) !== null && _parseJsonAttribute2 !== void 0 ? _parseJsonAttribute2 : undefined,
2945
+ initialPrompt: getAttributeValue(element, 'data-coreai-chat-initial-prompt'),
2946
+ sessionUrlTemplate: getAttributeValue(element, 'data-coreai-chat-session-url-template'),
2947
+ userLabel: getAttributeValue(element, 'data-coreai-chat-user-label'),
2948
+ assistantLabel: getAttributeValue(element, 'data-coreai-chat-assistant-label'),
2949
+ copyTitle: getAttributeValue(element, 'data-coreai-chat-copy-title'),
2950
+ copiedTitle: getAttributeValue(element, 'data-coreai-chat-copied-title')
2951
+ };
2952
+ var booleanAttributes = {
2953
+ metricsEnabled: 'data-coreai-chat-metrics-enabled',
2954
+ textToSpeechEnabled: 'data-coreai-chat-text-to-speech-enabled',
2955
+ sessionDocumentsEnabled: 'data-coreai-chat-session-documents-enabled',
2956
+ singleResponseMode: 'data-coreai-chat-single-response-mode'
2957
+ };
2958
+ Object.keys(booleanAttributes).forEach(function (key) {
2959
+ var parsed = parseBooleanAttributeValue(getAttributeValue(element, booleanAttributes[key]));
2960
+ if (parsed !== null) {
2961
+ config[key] = parsed;
2962
+ }
2963
+ });
2964
+ return compactObject(config);
2965
+ }
2966
+ function buildConfigFromElement(element, options) {
2967
+ var jsonConfig = parseJsonAttribute(element, 'data-coreai-chat-config', 'CoreAI chat config');
2968
+ var attributeConfig = buildConfigFromDataAttributes(element, options);
2969
+ if (!jsonConfig && !attributeConfig) {
2970
+ return null;
2971
+ }
2972
+ return Object.assign({}, jsonConfig || {}, attributeConfig || {});
2973
+ }
2974
+ function initializeFromElement(element) {
2975
+ if (!element || element.dataset.coreAiChatInitialized === 'true') {
2976
+ return element ? element.__coreAIChatApp || null : null;
2977
+ }
2978
+ var config = buildConfigFromElement(element);
2979
+ if (!config) {
2980
+ return null;
2981
+ }
2982
+ var app = initialize(config);
2983
+ if (!app) {
2984
+ return null;
2985
+ }
2986
+ element.dataset.coreAiChatInitialized = 'true';
2987
+ element.__coreAIChatApp = app;
2988
+ return app;
2989
+ }
2990
+ function scanForAutoInitialization(root) {
2991
+ if (!root || typeof root.querySelectorAll !== 'function') {
2992
+ return;
2993
+ }
2994
+ if (typeof root.matches === 'function' && root.matches(autoInitializeSelector)) {
2995
+ initializeFromElement(root);
2996
+ }
2997
+ root.querySelectorAll(autoInitializeSelector).forEach(initializeFromElement);
2998
+ }
2999
+ function startAutoInitialization() {
3000
+ scanForAutoInitialization(document);
3001
+ if (typeof MutationObserver === 'undefined') {
3002
+ return;
3003
+ }
3004
+ var observer = new MutationObserver(function (mutations) {
3005
+ mutations.forEach(function (mutation) {
3006
+ mutation.addedNodes.forEach(function (node) {
3007
+ if (node && node.nodeType === 1) {
3008
+ scanForAutoInitialization(node);
3009
+ }
3010
+ });
3011
+ });
3012
+ });
3013
+ observer.observe(document.body, {
3014
+ childList: true,
3015
+ subtree: true
3016
+ });
3017
+ }
3018
+ if (document.readyState === 'loading') {
3019
+ document.addEventListener('DOMContentLoaded', startAutoInitialization, {
3020
+ once: true
3021
+ });
3022
+ } else {
3023
+ startAutoInitialization();
3024
+ }
2672
3025
  return {
2673
- initialize: initialize
3026
+ initialize: initialize,
3027
+ initializeFromElement: initializeFromElement,
3028
+ buildConfigFromElement: buildConfigFromElement
2674
3029
  };
2675
3030
  }();
2676
3031