@crestapps/ai-chat-ui 1.0.0-preview.11 → 1.0.0-preview.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ai-chat.js CHANGED
@@ -404,6 +404,8 @@ window.openAIChatManager = function () {
404
404
  prompt: '',
405
405
  documents: config.existingDocuments || [],
406
406
  isUploading: false,
407
+ isDocumentOperationPending: false,
408
+ documentOperationQueue: null,
407
409
  uploadErrors: [],
408
410
  isDragOver: false,
409
411
  documentBar: null,
@@ -433,7 +435,11 @@ window.openAIChatManager = function () {
433
435
  conversationModeEnabled: config.chatMode === 'Conversation',
434
436
  conversationButton: null,
435
437
  isConversationMode: false,
436
- notificationDismissTimers: {}
438
+ notificationDismissTimers: {},
439
+ pendingSessionPromise: null,
440
+ pendingSessionResolver: null,
441
+ pendingSessionRejector: null,
442
+ pendingSessionTimeoutId: null
437
443
  };
438
444
  },
439
445
  computed: {
@@ -474,180 +480,272 @@ window.openAIChatManager = function () {
474
480
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
475
481
  if (inputArea) inputArea.classList.remove('ai-chat-drag-over');
476
482
  if (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
477
- this.uploadFiles(e.dataTransfer.files);
483
+ this.uploadFiles(Array.from(e.dataTransfer.files));
478
484
  }
479
485
  },
480
486
  triggerFileInput: function triggerFileInput() {
481
- if (!config.sessionDocumentsEnabled) return;
487
+ if (!config.sessionDocumentsEnabled || this.isDocumentOperationPending) return;
482
488
  var fileInput = document.getElementById('ai-chat-doc-input');
483
489
  if (fileInput) fileInput.click();
484
490
  },
485
491
  handleFileInputChange: function handleFileInputChange(e) {
486
- var files = e.target.files;
492
+ var files = e.target.files ? Array.from(e.target.files) : [];
487
493
  if (files && files.length > 0) {
488
494
  this.uploadFiles(files);
489
495
  }
490
496
  e.target.value = '';
491
497
  },
492
- uploadFiles: function uploadFiles(files) {
493
- var _this = this;
494
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
495
- var sessionId, profileId, formData, i, response, errorText, uploadError, result, j, _t;
498
+ queueDocumentOperation: function queueDocumentOperation(operation) {
499
+ var self = this;
500
+ var previousOperation = this.documentOperationQueue || Promise.resolve();
501
+ var nextOperation = previousOperation["catch"](function () {}).then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
496
502
  return _regenerator().w(function (_context) {
497
503
  while (1) switch (_context.p = _context.n) {
504
+ case 0:
505
+ self.isDocumentOperationPending = true;
506
+ _context.p = 1;
507
+ _context.n = 2;
508
+ return operation();
509
+ case 2:
510
+ return _context.a(2, _context.v);
511
+ case 3:
512
+ _context.p = 3;
513
+ self.isDocumentOperationPending = false;
514
+ return _context.f(3);
515
+ case 4:
516
+ return _context.a(2);
517
+ }
518
+ }, _callee, null, [[1,, 3, 4]]);
519
+ })));
520
+ this.documentOperationQueue = nextOperation["finally"](function () {
521
+ if (self.documentOperationQueue === nextOperation) {
522
+ self.documentOperationQueue = null;
523
+ }
524
+ });
525
+ return this.documentOperationQueue;
526
+ },
527
+ uploadFiles: function uploadFiles(files) {
528
+ var _this = this;
529
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
530
+ var filesToUpload;
531
+ return _regenerator().w(function (_context3) {
532
+ while (1) switch (_context3.n) {
498
533
  case 0:
499
534
  if (config.uploadDocumentUrl) {
500
- _context.n = 1;
535
+ _context3.n = 1;
501
536
  break;
502
537
  }
503
- return _context.a(2);
538
+ return _context3.a(2);
504
539
  case 1:
505
- sessionId = _this.getSessionId();
506
- profileId = _this.getProfileId();
507
- if (!(!sessionId && !profileId)) {
508
- _context.n = 2;
540
+ filesToUpload = Array.isArray(files) ? files.slice() : Array.from(files || []);
541
+ if (!(filesToUpload.length === 0)) {
542
+ _context3.n = 2;
509
543
  break;
510
544
  }
511
- console.warn('Cannot upload documents without a session or profile.');
512
- return _context.a(2);
545
+ return _context3.a(2);
513
546
  case 2:
514
- _this.isUploading = true;
515
- _this.uploadErrors = [];
516
- _this.renderDocumentBar();
517
- _context.p = 3;
518
- formData = new FormData();
519
- if (sessionId) {
520
- formData.append('sessionId', sessionId);
521
- } else {
522
- formData.append('profileId', profileId);
523
- }
524
- for (i = 0; i < files.length; i++) {
525
- formData.append('files', files[i]);
526
- }
527
- _context.n = 4;
528
- return fetch(config.uploadDocumentUrl, {
529
- method: 'POST',
530
- body: formData
531
- });
532
- case 4:
533
- response = _context.v;
534
- if (response.ok) {
535
- _context.n = 6;
536
- break;
537
- }
538
- _context.n = 5;
539
- return response.text();
540
- case 5:
541
- errorText = _context.v;
542
- uploadError = _this.extractReadableErrorMessage(errorText, 'Upload failed. Please try again.');
543
- console.error('Upload failed:', errorText);
544
- _this.uploadErrors = [{
545
- fileName: '',
546
- error: uploadError
547
- }];
548
- return _context.a(2);
549
- case 6:
550
- _context.n = 7;
551
- return response.json();
552
- case 7:
553
- result = _context.v;
554
- // If the server created a new session, initialize it.
555
- if (result.sessionId && !sessionId) {
556
- _this.initializeSession(result.sessionId);
557
- }
558
- if (result.uploaded && result.uploaded.length > 0) {
559
- for (j = 0; j < result.uploaded.length; j++) {
560
- _this.documents.push(result.uploaded[j]);
561
- }
562
- }
563
- if (result.failed && result.failed.length > 0) {
564
- _this.uploadErrors = result.failed;
565
- }
566
- _context.n = 9;
567
- break;
568
- case 8:
569
- _context.p = 8;
570
- _t = _context.v;
571
- console.error('Upload error:', _t);
572
- _this.uploadErrors = [{
573
- fileName: '',
574
- error: 'Upload failed. Please try again.'
575
- }];
576
- case 9:
577
- _context.p = 9;
578
- _this.isUploading = false;
579
- _this.renderDocumentBar();
580
- return _context.f(9);
581
- case 10:
582
- return _context.a(2);
547
+ return _context3.a(2, _this.queueDocumentOperation(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
548
+ var sessionId, profileId, formData, i, response, errorText, uploadError, result, _t, _t2;
549
+ return _regenerator().w(function (_context2) {
550
+ while (1) switch (_context2.p = _context2.n) {
551
+ case 0:
552
+ sessionId = _this.getSessionId();
553
+ profileId = _this.getProfileId();
554
+ if (sessionId) {
555
+ _context2.n = 4;
556
+ break;
557
+ }
558
+ _context2.p = 1;
559
+ _context2.n = 2;
560
+ return _this.ensureSessionForDocuments(profileId);
561
+ case 2:
562
+ sessionId = _context2.v;
563
+ _context2.n = 4;
564
+ break;
565
+ case 3:
566
+ _context2.p = 3;
567
+ _t = _context2.v;
568
+ console.error('Failed to create a chat session for document upload:', _t);
569
+ _this.uploadErrors = [{
570
+ fileName: '',
571
+ error: 'Could not create a chat session for the upload.'
572
+ }];
573
+ _this.renderDocumentBar();
574
+ return _context2.a(2);
575
+ case 4:
576
+ if (sessionId) {
577
+ _context2.n = 5;
578
+ break;
579
+ }
580
+ console.warn('Cannot upload documents without a session or profile.');
581
+ _this.uploadErrors = [{
582
+ fileName: '',
583
+ error: 'Could not create a chat session for the upload.'
584
+ }];
585
+ _this.renderDocumentBar();
586
+ return _context2.a(2);
587
+ case 5:
588
+ _this.isUploading = true;
589
+ _this.uploadErrors = [];
590
+ _this.renderDocumentBar();
591
+ _context2.p = 6;
592
+ formData = new FormData();
593
+ formData.append('sessionId', sessionId);
594
+ for (i = 0; i < filesToUpload.length; i++) {
595
+ formData.append('files', filesToUpload[i]);
596
+ }
597
+ _context2.n = 7;
598
+ return fetch(config.uploadDocumentUrl, {
599
+ method: 'POST',
600
+ body: formData
601
+ });
602
+ case 7:
603
+ response = _context2.v;
604
+ if (response.ok) {
605
+ _context2.n = 9;
606
+ break;
607
+ }
608
+ _context2.n = 8;
609
+ return response.text();
610
+ case 8:
611
+ errorText = _context2.v;
612
+ uploadError = _this.extractReadableErrorMessage(errorText, 'Upload failed. Please try again.');
613
+ console.error('Upload failed:', errorText);
614
+ _this.uploadErrors = [{
615
+ fileName: '',
616
+ error: uploadError
617
+ }];
618
+ return _context2.a(2);
619
+ case 9:
620
+ _context2.n = 10;
621
+ return response.json();
622
+ case 10:
623
+ result = _context2.v;
624
+ if (result.sessionId && result.sessionId !== _this.getSessionId()) {
625
+ _this.initializeSession(result.sessionId);
626
+ }
627
+ if (Array.isArray(result.documents)) {
628
+ _this.documents = result.documents;
629
+ } else if (result.uploaded && result.uploaded.length > 0) {
630
+ _this.documents = _this.documents.concat(result.uploaded);
631
+ }
632
+ if (result.failed && result.failed.length > 0) {
633
+ _this.uploadErrors = result.failed;
634
+ }
635
+ _context2.n = 12;
636
+ break;
637
+ case 11:
638
+ _context2.p = 11;
639
+ _t2 = _context2.v;
640
+ console.error('Upload error:', _t2);
641
+ _this.uploadErrors = [{
642
+ fileName: '',
643
+ error: 'Upload failed. Please try again.'
644
+ }];
645
+ if (_this.getSessionId()) {
646
+ _this.reloadCurrentSession();
647
+ }
648
+ case 12:
649
+ _context2.p = 12;
650
+ _this.isUploading = false;
651
+ _this.renderDocumentBar();
652
+ return _context2.f(12);
653
+ case 13:
654
+ return _context2.a(2);
655
+ }
656
+ }, _callee2, null, [[6, 11, 12, 13], [1, 3]]);
657
+ }))));
583
658
  }
584
- }, _callee, null, [[3, 8, 9, 10]]);
659
+ }, _callee3);
585
660
  }))();
586
661
  },
587
662
  removeDocument: function removeDocument(doc) {
588
663
  var _this2 = this;
589
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
590
- var sessionId, response, idx, errorText, removeError, _t2;
591
- return _regenerator().w(function (_context2) {
592
- while (1) switch (_context2.p = _context2.n) {
664
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
665
+ return _regenerator().w(function (_context5) {
666
+ while (1) switch (_context5.n) {
593
667
  case 0:
594
668
  if (config.removeDocumentUrl) {
595
- _context2.n = 1;
669
+ _context5.n = 1;
596
670
  break;
597
671
  }
598
- return _context2.a(2);
672
+ return _context5.a(2);
599
673
  case 1:
600
- _context2.p = 1;
601
- sessionId = _this2.getSessionId();
602
- _context2.n = 2;
603
- return fetch(config.removeDocumentUrl, {
604
- method: 'POST',
605
- headers: {
606
- 'Content-Type': 'application/json'
607
- },
608
- body: JSON.stringify({
609
- itemId: sessionId,
610
- documentId: doc.documentId
611
- })
612
- });
613
- case 2:
614
- response = _context2.v;
615
- if (!response.ok) {
616
- _context2.n = 3;
617
- break;
618
- }
619
- idx = _this2.documents.indexOf(doc);
620
- if (idx > -1) _this2.documents.splice(idx, 1);
621
- _context2.n = 5;
622
- break;
623
- case 3:
624
- _context2.n = 4;
625
- return response.text();
626
- case 4:
627
- errorText = _context2.v;
628
- removeError = _this2.extractReadableErrorMessage(errorText, 'Failed to remove document. Please try again.');
629
- console.error('Failed to remove document:', response.status, errorText);
630
- _this2.uploadErrors = [{
631
- fileName: doc.fileName || '',
632
- error: removeError
633
- }];
634
- _this2.renderDocumentBar();
635
- case 5:
636
- _context2.n = 7;
637
- break;
638
- case 6:
639
- _context2.p = 6;
640
- _t2 = _context2.v;
641
- console.error('Remove document error:', _t2);
642
- _this2.uploadErrors = [{
643
- fileName: doc.fileName || '',
644
- error: 'Failed to remove document. Please try again.'
645
- }];
646
- _this2.renderDocumentBar();
647
- case 7:
648
- return _context2.a(2);
674
+ return _context5.a(2, _this2.queueDocumentOperation(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
675
+ var sessionId, response, result, idx, errorText, removeError, _t3;
676
+ return _regenerator().w(function (_context4) {
677
+ while (1) switch (_context4.p = _context4.n) {
678
+ case 0:
679
+ _context4.p = 0;
680
+ sessionId = _this2.getSessionId();
681
+ _context4.n = 1;
682
+ return fetch(config.removeDocumentUrl, {
683
+ method: 'POST',
684
+ headers: {
685
+ 'Content-Type': 'application/json'
686
+ },
687
+ body: JSON.stringify({
688
+ itemId: sessionId,
689
+ documentId: doc.documentId
690
+ })
691
+ });
692
+ case 1:
693
+ response = _context4.v;
694
+ if (!response.ok) {
695
+ _context4.n = 3;
696
+ break;
697
+ }
698
+ _context4.n = 2;
699
+ return response.json();
700
+ case 2:
701
+ result = _context4.v;
702
+ if (Array.isArray(result.documents)) {
703
+ _this2.documents = result.documents;
704
+ } else {
705
+ idx = _this2.documents.indexOf(doc);
706
+ if (idx > -1) {
707
+ _this2.documents.splice(idx, 1);
708
+ }
709
+ }
710
+ _context4.n = 5;
711
+ break;
712
+ case 3:
713
+ _context4.n = 4;
714
+ return response.text();
715
+ case 4:
716
+ errorText = _context4.v;
717
+ removeError = _this2.extractReadableErrorMessage(errorText, 'Failed to remove document. Please try again.');
718
+ console.error('Failed to remove document:', response.status, errorText);
719
+ _this2.uploadErrors = [{
720
+ fileName: doc.fileName || '',
721
+ error: removeError
722
+ }];
723
+ if (sessionId) {
724
+ _this2.reloadCurrentSession();
725
+ }
726
+ _this2.renderDocumentBar();
727
+ case 5:
728
+ _context4.n = 7;
729
+ break;
730
+ case 6:
731
+ _context4.p = 6;
732
+ _t3 = _context4.v;
733
+ console.error('Remove document error:', _t3);
734
+ _this2.uploadErrors = [{
735
+ fileName: doc.fileName || '',
736
+ error: 'Failed to remove document. Please try again.'
737
+ }];
738
+ if (_this2.getSessionId()) {
739
+ _this2.reloadCurrentSession();
740
+ }
741
+ _this2.renderDocumentBar();
742
+ case 7:
743
+ return _context4.a(2);
744
+ }
745
+ }, _callee4, null, [[0, 6]]);
746
+ }))));
649
747
  }
650
- }, _callee2, null, [[1, 6]]);
748
+ }, _callee5);
651
749
  }))();
652
750
  },
653
751
  formatFileSize: function formatFileSize(bytes) {
@@ -671,7 +769,7 @@ window.openAIChatManager = function () {
671
769
  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 || '') + '">';
672
770
  html += '<span class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></span> ';
673
771
  html += this.escapeHtml(name);
674
- html += ' <button type="button" class="btn-close btn-close-sm ms-1" style="font-size: 0.5rem;" data-doc-index="' + i + '" aria-label="Remove"></button>';
772
+ 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>';
675
773
  html += '</span>';
676
774
  }
677
775
  for (var m = 0; m < this.uploadErrors.length; m++) {
@@ -690,7 +788,7 @@ window.openAIChatManager = function () {
690
788
  html += '<span class="spinner-border spinner-border-sm" style="width: 0.7rem; height: 0.7rem;"></span> Uploading...';
691
789
  html += '</span>';
692
790
  }
693
- 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">';
791
+ 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' : '') + '>';
694
792
  html += '<span class="fa-solid fa-paperclip"></span>';
695
793
  if (this.documents.length === 0 && !this.isUploading) {
696
794
  html += ' <span>Attach files</span>';
@@ -713,6 +811,9 @@ window.openAIChatManager = function () {
713
811
  return function (e) {
714
812
  e.preventDefault();
715
813
  e.stopPropagation();
814
+ if (self.isDocumentOperationPending) {
815
+ return;
816
+ }
716
817
  var docToRemove = self.documents[idx];
717
818
  if (docToRemove) self.removeDocument(docToRemove);
718
819
  };
@@ -737,6 +838,9 @@ window.openAIChatManager = function () {
737
838
  if (addBtn) {
738
839
  addBtn.addEventListener('click', function (e) {
739
840
  e.preventDefault();
841
+ if (self.isDocumentOperationPending) {
842
+ return;
843
+ }
740
844
  self.triggerFileInput();
741
845
  });
742
846
  }
@@ -814,10 +918,10 @@ window.openAIChatManager = function () {
814
918
  },
815
919
  startConnection: function startConnection() {
816
920
  var _this3 = this;
817
- return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
818
- var _t3;
819
- return _regenerator().w(function (_context3) {
820
- while (1) switch (_context3.p = _context3.n) {
921
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
922
+ var _t4;
923
+ return _regenerator().w(function (_context6) {
924
+ while (1) switch (_context6.p = _context6.n) {
821
925
  case 0:
822
926
  _this3.connection = new signalR.HubConnectionBuilder().withUrl(config.signalRHubUrl).withAutomaticReconnect().build();
823
927
 
@@ -1021,20 +1125,20 @@ window.openAIChatManager = function () {
1021
1125
  console.warn("SignalR connection closed with error:", error.message || error);
1022
1126
  }
1023
1127
  });
1024
- _context3.p = 1;
1025
- _context3.n = 2;
1128
+ _context6.p = 1;
1129
+ _context6.n = 2;
1026
1130
  return _this3.connection.start();
1027
1131
  case 2:
1028
- _context3.n = 4;
1132
+ _context6.n = 4;
1029
1133
  break;
1030
1134
  case 3:
1031
- _context3.p = 3;
1032
- _t3 = _context3.v;
1033
- console.error("SignalR Connection Error: ", _t3);
1135
+ _context6.p = 3;
1136
+ _t4 = _context6.v;
1137
+ console.error("SignalR Connection Error: ", _t4);
1034
1138
  case 4:
1035
- return _context3.a(2);
1139
+ return _context6.a(2);
1036
1140
  }
1037
- }, _callee3, null, [[1, 3]]);
1141
+ }, _callee6, null, [[1, 3]]);
1038
1142
  }))();
1039
1143
  },
1040
1144
  addMessageInternal: function addMessageInternal(message) {
@@ -1070,18 +1174,18 @@ window.openAIChatManager = function () {
1070
1174
  message.references = normalizeReferences(message.references);
1071
1175
  if (message.references && _typeof(message.references) === "object" && Object.keys(message.references).length) {
1072
1176
  // Only include references that were actually cited in the response.
1073
- var citedRefs = Object.entries(message.references).filter(function (_ref4) {
1074
- var _ref5 = _slicedToArray(_ref4, 1),
1075
- key = _ref5[0];
1177
+ var citedRefs = Object.entries(message.references).filter(function (_ref7) {
1178
+ var _ref8 = _slicedToArray(_ref7, 1),
1179
+ key = _ref8[0];
1076
1180
  return processedContent.includes(key);
1077
1181
  });
1078
1182
  if (citedRefs.length) {
1079
1183
  // Sort by original index so display indices follow a natural order.
1080
- citedRefs.sort(function (_ref6, _ref7) {
1081
- var _ref8 = _slicedToArray(_ref6, 2),
1082
- a = _ref8[1];
1083
- var _ref9 = _slicedToArray(_ref7, 2),
1084
- b = _ref9[1];
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];
1085
1189
  return a.index - b.index;
1086
1190
  });
1087
1191
 
@@ -1259,15 +1363,15 @@ window.openAIChatManager = function () {
1259
1363
  var pendingChunk = Promise.resolve();
1260
1364
  _this7.mediaRecorder.addEventListener('dataavailable', function (e) {
1261
1365
  if (e.data && e.data.size > 0) {
1262
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
1366
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7() {
1263
1367
  var data, uint8Array, binaryString, base64;
1264
- return _regenerator().w(function (_context4) {
1265
- while (1) switch (_context4.n) {
1368
+ return _regenerator().w(function (_context7) {
1369
+ while (1) switch (_context7.n) {
1266
1370
  case 0:
1267
- _context4.n = 1;
1371
+ _context7.n = 1;
1268
1372
  return e.data.arrayBuffer();
1269
1373
  case 1:
1270
- data = _context4.v;
1374
+ data = _context7.v;
1271
1375
  uint8Array = new Uint8Array(data);
1272
1376
  binaryString = uint8Array.reduce(function (str, _byte) {
1273
1377
  return str + String.fromCharCode(_byte);
@@ -1275,9 +1379,9 @@ window.openAIChatManager = function () {
1275
1379
  base64 = btoa(binaryString);
1276
1380
  subject.next(base64);
1277
1381
  case 2:
1278
- return _context4.a(2);
1382
+ return _context7.a(2);
1279
1383
  }
1280
- }, _callee4);
1384
+ }, _callee7);
1281
1385
  })));
1282
1386
  }
1283
1387
  });
@@ -1461,10 +1565,10 @@ window.openAIChatManager = function () {
1461
1565
 
1462
1566
  // Only include references that were actually cited in the response.
1463
1567
  // Check both raw [doc:N] markers and already-rendered <sup> tags from streaming.
1464
- var citedRefs = Object.entries(references).filter(function (_ref1) {
1465
- var _ref10 = _slicedToArray(_ref1, 2),
1466
- key = _ref10[0],
1467
- value = _ref10[1];
1568
+ var citedRefs = Object.entries(references).filter(function (_ref12) {
1569
+ var _ref13 = _slicedToArray(_ref12, 2),
1570
+ key = _ref13[0],
1571
+ value = _ref13[1];
1468
1572
  return content.includes(key) || content.includes("<sup><strong>".concat(value.index, "</strong></sup>"));
1469
1573
  });
1470
1574
  if (!citedRefs.length) {
@@ -1472,11 +1576,11 @@ window.openAIChatManager = function () {
1472
1576
  }
1473
1577
 
1474
1578
  // Sort by original index so display indices follow a natural order.
1475
- citedRefs.sort(function (_ref11, _ref12) {
1476
- var _ref13 = _slicedToArray(_ref11, 2),
1477
- a = _ref13[1];
1478
- var _ref14 = _slicedToArray(_ref12, 2),
1479
- b = _ref14[1];
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];
1480
1584
  return a.index - b.index;
1481
1585
  });
1482
1586
 
@@ -1828,15 +1932,15 @@ window.openAIChatManager = function () {
1828
1932
  // Always send audio to STT — browser echo cancellation
1829
1933
  // handles speaker echo; continuous audio avoids gaps
1830
1934
  // that increase recognition latency.
1831
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
1935
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
1832
1936
  var data, uint8Array, binaryString, base64;
1833
- return _regenerator().w(function (_context5) {
1834
- while (1) switch (_context5.n) {
1937
+ return _regenerator().w(function (_context8) {
1938
+ while (1) switch (_context8.n) {
1835
1939
  case 0:
1836
- _context5.n = 1;
1940
+ _context8.n = 1;
1837
1941
  return e.data.arrayBuffer();
1838
1942
  case 1:
1839
- data = _context5.v;
1943
+ data = _context8.v;
1840
1944
  uint8Array = new Uint8Array(data);
1841
1945
  binaryString = uint8Array.reduce(function (str, _byte2) {
1842
1946
  return str + String.fromCharCode(_byte2);
@@ -1848,9 +1952,9 @@ window.openAIChatManager = function () {
1848
1952
  // Subject may have been completed already.
1849
1953
  }
1850
1954
  case 2:
1851
- return _context5.a(2);
1955
+ return _context8.a(2);
1852
1956
  }
1853
- }, _callee5);
1957
+ }, _callee8);
1854
1958
  })));
1855
1959
  }
1856
1960
  });
@@ -2081,13 +2185,17 @@ window.openAIChatManager = function () {
2081
2185
  this.prompt = event.target.value;
2082
2186
  },
2083
2187
  getProfileId: function getProfileId() {
2084
- return this.inputElement.getAttribute('data-profile-id');
2188
+ return this.inputElement ? this.inputElement.getAttribute('data-profile-id') : null;
2085
2189
  },
2086
2190
  setSessionId: function setSessionId(sessionId) {
2191
+ if (!this.inputElement) {
2192
+ return;
2193
+ }
2087
2194
  this.inputElement.setAttribute('data-session-id', sessionId || '');
2088
2195
  },
2089
2196
  resetSession: function resetSession() {
2090
2197
  this.stopRecording();
2198
+ this.rejectPendingSessionRequest('Session was reset.');
2091
2199
  this.setSessionId('');
2092
2200
  this.isSessionStarted = false;
2093
2201
  this.sessionRating = null;
@@ -2111,16 +2219,94 @@ window.openAIChatManager = function () {
2111
2219
  if (!profileId || !this.connection) {
2112
2220
  return;
2113
2221
  }
2114
- this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2222
+ this.requestNewSession(profileId)["catch"](function (err) {
2115
2223
  return console.error(err);
2116
2224
  });
2117
2225
  },
2118
- initializeApp: function initializeApp() {
2226
+ ensureSessionForDocuments: function ensureSessionForDocuments(profileId) {
2119
2227
  var _this19 = this;
2228
+ return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
2229
+ var sessionId;
2230
+ return _regenerator().w(function (_context9) {
2231
+ while (1) switch (_context9.n) {
2232
+ case 0:
2233
+ sessionId = _this19.getSessionId();
2234
+ if (!sessionId) {
2235
+ _context9.n = 1;
2236
+ break;
2237
+ }
2238
+ return _context9.a(2, sessionId);
2239
+ case 1:
2240
+ if (!(!profileId || !_this19.connection)) {
2241
+ _context9.n = 2;
2242
+ break;
2243
+ }
2244
+ return _context9.a(2, null);
2245
+ case 2:
2246
+ _context9.n = 3;
2247
+ return _this19.requestNewSession(profileId);
2248
+ case 3:
2249
+ return _context9.a(2, _context9.v);
2250
+ }
2251
+ }, _callee9);
2252
+ }))();
2253
+ },
2254
+ requestNewSession: function requestNewSession(profileId) {
2255
+ var _this20 = this;
2256
+ if (this.pendingSessionPromise) {
2257
+ return this.pendingSessionPromise;
2258
+ }
2259
+ if (!profileId || !this.connection) {
2260
+ return Promise.resolve(null);
2261
+ }
2262
+ 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.');
2267
+ }, 15000);
2268
+ });
2269
+ this.connection.invoke("StartSession", profileId, null)["catch"](function (err) {
2270
+ _this20.rejectPendingSessionRequest(err);
2271
+ });
2272
+ return this.pendingSessionPromise;
2273
+ },
2274
+ resolvePendingSessionRequest: function resolvePendingSessionRequest(sessionId) {
2275
+ if (this.pendingSessionResolver) {
2276
+ this.pendingSessionResolver(sessionId);
2277
+ }
2278
+ this.clearPendingSessionRequest();
2279
+ },
2280
+ rejectPendingSessionRequest: function rejectPendingSessionRequest(error) {
2281
+ if (this.pendingSessionRejector) {
2282
+ this.pendingSessionRejector(error);
2283
+ }
2284
+ this.clearPendingSessionRequest();
2285
+ },
2286
+ clearPendingSessionRequest: function clearPendingSessionRequest() {
2287
+ if (this.pendingSessionTimeoutId) {
2288
+ window.clearTimeout(this.pendingSessionTimeoutId);
2289
+ }
2290
+ this.pendingSessionPromise = null;
2291
+ this.pendingSessionResolver = null;
2292
+ this.pendingSessionRejector = null;
2293
+ this.pendingSessionTimeoutId = null;
2294
+ },
2295
+ initializeApp: function initializeApp() {
2296
+ var _this21 = this;
2120
2297
  this.inputElement = document.querySelector(config.inputElementSelector);
2121
2298
  this.buttonElement = document.querySelector(config.sendButtonElementSelector);
2122
2299
  this.chatContainer = document.querySelector(config.chatContainerElementSelector);
2123
2300
  this.placeholder = document.querySelector(config.placeholderElementSelector);
2301
+ if (!this.inputElement || !this.buttonElement || !this.chatContainer || !this.placeholder) {
2302
+ console.error('AI chat app could not initialize because one or more required elements were not found.', {
2303
+ inputElementSelector: config.inputElementSelector,
2304
+ sendButtonElementSelector: config.sendButtonElementSelector,
2305
+ chatContainerElementSelector: config.chatContainerElementSelector,
2306
+ placeholderElementSelector: config.placeholderElementSelector
2307
+ });
2308
+ return false;
2309
+ }
2124
2310
  this.applyOrchestratorAvailability();
2125
2311
  var sessionId = this.getSessionId();
2126
2312
  if (!hasWidgetConfig && sessionId) {
@@ -2145,7 +2331,7 @@ window.openAIChatManager = function () {
2145
2331
  fileInput.accept = config.allowedExtensions;
2146
2332
  }
2147
2333
  fileInput.addEventListener('change', function (e) {
2148
- return _this19.handleFileInputChange(e);
2334
+ return _this21.handleFileInputChange(e);
2149
2335
  });
2150
2336
  this.documentBar.parentElement.appendChild(fileInput);
2151
2337
 
@@ -2153,13 +2339,13 @@ window.openAIChatManager = function () {
2153
2339
  var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
2154
2340
  if (inputArea) {
2155
2341
  inputArea.addEventListener('dragover', function (e) {
2156
- return _this19.handleDragOver(e);
2342
+ return _this21.handleDragOver(e);
2157
2343
  });
2158
2344
  inputArea.addEventListener('dragleave', function (e) {
2159
- return _this19.handleDragLeave(e);
2345
+ return _this21.handleDragLeave(e);
2160
2346
  });
2161
2347
  inputArea.addEventListener('drop', function (e) {
2162
- return _this19.handleDrop(e);
2348
+ return _this21.handleDrop(e);
2163
2349
  });
2164
2350
  }
2165
2351
  }
@@ -2167,55 +2353,55 @@ window.openAIChatManager = function () {
2167
2353
 
2168
2354
  // Pause auto-scroll when the user manually scrolls up during streaming.
2169
2355
  this.chatContainer.addEventListener('scroll', function () {
2170
- if (!_this19.stream) {
2356
+ if (!_this21.stream) {
2171
2357
  return;
2172
2358
  }
2173
2359
  var threshold = 30;
2174
- var atBottom = _this19.chatContainer.scrollHeight - _this19.chatContainer.clientHeight - _this19.chatContainer.scrollTop <= threshold;
2175
- _this19.autoScroll = atBottom;
2360
+ var atBottom = _this21.chatContainer.scrollHeight - _this21.chatContainer.clientHeight - _this21.chatContainer.scrollTop <= threshold;
2361
+ _this21.autoScroll = atBottom;
2176
2362
  });
2177
2363
  this.inputElement.addEventListener('keydown', function (event) {
2178
- if (_this19.stream != null) {
2364
+ if (_this21.stream != null) {
2179
2365
  return;
2180
2366
  }
2181
2367
  if (event.key === "Enter" && !event.shiftKey) {
2182
2368
  event.preventDefault();
2183
- _this19.buttonElement.click();
2369
+ _this21.buttonElement.click();
2184
2370
  }
2185
2371
  });
2186
2372
  this.inputElement.addEventListener('input', function (e) {
2187
- _this19.handleUserInput(e);
2373
+ _this21.handleUserInput(e);
2188
2374
  if (e.target.value.trim()) {
2189
- _this19.buttonElement.removeAttribute('disabled');
2375
+ _this21.buttonElement.removeAttribute('disabled');
2190
2376
  } else {
2191
- _this19.buttonElement.setAttribute('disabled', true);
2377
+ _this21.buttonElement.setAttribute('disabled', true);
2192
2378
  }
2193
2379
  });
2194
2380
  this.buttonElement.addEventListener('click', function () {
2195
- if (_this19.stream != null) {
2196
- _this19.stream.dispose();
2197
- _this19.stream = null;
2198
- _this19.streamingFinished();
2199
- _this19.hideTypingIndicator();
2381
+ if (_this21.stream != null) {
2382
+ _this21.stream.dispose();
2383
+ _this21.stream = null;
2384
+ _this21.streamingFinished();
2385
+ _this21.hideTypingIndicator();
2200
2386
 
2201
2387
  // Clean up: remove empty assistant message or stop streaming animation.
2202
- if (_this19.messages.length > 0) {
2203
- var lastMsg = _this19.messages[_this19.messages.length - 1];
2388
+ if (_this21.messages.length > 0) {
2389
+ var lastMsg = _this21.messages[_this21.messages.length - 1];
2204
2390
  if (lastMsg.role === 'assistant' && !lastMsg.content) {
2205
- _this19.messages.pop();
2391
+ _this21.messages.pop();
2206
2392
  } else if (lastMsg.isStreaming) {
2207
2393
  lastMsg.isStreaming = false;
2208
2394
  }
2209
2395
  }
2210
2396
  return;
2211
2397
  }
2212
- _this19.sendMessage();
2398
+ _this21.sendMessage();
2213
2399
  });
2214
2400
  var promptGenerators = document.getElementsByClassName('profile-generated-prompt');
2215
2401
  for (var i = 0; i < promptGenerators.length; i++) {
2216
2402
  promptGenerators[i].addEventListener('click', function (e) {
2217
2403
  e.preventDefault();
2218
- _this19.generatePrompt(e.target);
2404
+ _this21.generatePrompt(e.target);
2219
2405
  });
2220
2406
  }
2221
2407
  var chatSessions = document.getElementsByClassName('chat-session-history-item');
@@ -2227,8 +2413,8 @@ window.openAIChatManager = function () {
2227
2413
  console.error('an element with the class chat-session-history-item with no data-session-id set.');
2228
2414
  return;
2229
2415
  }
2230
- _this19.loadSession(sessionId);
2231
- _this19.showChatScreen();
2416
+ _this21.loadSession(sessionId);
2417
+ _this21.showChatScreen();
2232
2418
  });
2233
2419
  }
2234
2420
  for (var _i5 = 0; _i5 < config.messages.length; _i5++) {
@@ -2237,7 +2423,7 @@ window.openAIChatManager = function () {
2237
2423
 
2238
2424
  // Update feedback icons in the DOM after initial messages have rendered.
2239
2425
  this.$nextTick(function () {
2240
- _this19.refreshAllFeedbackIcons();
2426
+ _this21.refreshAllFeedbackIcons();
2241
2427
  });
2242
2428
 
2243
2429
  // Delegate click for code block copy buttons.
@@ -2269,7 +2455,7 @@ window.openAIChatManager = function () {
2269
2455
  if (this.micButton) {
2270
2456
  this.micButton.style.display = '';
2271
2457
  this.micButton.addEventListener('click', function () {
2272
- _this19.toggleRecording();
2458
+ _this21.toggleRecording();
2273
2459
  });
2274
2460
  }
2275
2461
  }
@@ -2279,10 +2465,11 @@ window.openAIChatManager = function () {
2279
2465
  this.conversationButton = document.querySelector(config.conversationButtonElementSelector);
2280
2466
  if (this.conversationButton) {
2281
2467
  this.conversationButton.addEventListener('click', function () {
2282
- _this19.toggleConversationMode();
2468
+ _this21.toggleConversationMode();
2283
2469
  });
2284
2470
  }
2285
2471
  }
2472
+ return true;
2286
2473
  },
2287
2474
  loadSession: function loadSession(sessionId) {
2288
2475
  this.connection.invoke("LoadSession", sessionId)["catch"](function (err) {
@@ -2297,6 +2484,9 @@ window.openAIChatManager = function () {
2297
2484
  },
2298
2485
  initializeSession: function initializeSession(sessionId, force) {
2299
2486
  if (this.isSessionStarted && !force) {
2487
+ if (sessionId && this.getSessionId() === sessionId) {
2488
+ this.resolvePendingSessionRequest(sessionId);
2489
+ }
2300
2490
  return;
2301
2491
  }
2302
2492
  this.fireEvent(new CustomEvent("initializingSessionOpenAIChat", {
@@ -2306,12 +2496,13 @@ window.openAIChatManager = function () {
2306
2496
  }));
2307
2497
  this.setSessionId(sessionId);
2308
2498
  this.isSessionStarted = true;
2499
+ this.resolvePendingSessionRequest(sessionId);
2309
2500
  if (widgetBehavior && typeof widgetBehavior.onSessionInitialized === 'function') {
2310
2501
  widgetBehavior.onSessionInitialized(this, sessionId, config);
2311
2502
  }
2312
2503
  },
2313
2504
  getSessionId: function getSessionId() {
2314
- var sessionId = this.inputElement.getAttribute('data-session-id');
2505
+ var sessionId = this.inputElement ? this.inputElement.getAttribute('data-session-id') : null;
2315
2506
  if (!sessionId && widgetBehavior && typeof widgetBehavior.resolveSessionId === 'function') {
2316
2507
  sessionId = widgetBehavior.resolveSessionId(this, config);
2317
2508
  }
@@ -2406,6 +2597,9 @@ window.openAIChatManager = function () {
2406
2597
  isUploading: function isUploading() {
2407
2598
  this.renderDocumentBar();
2408
2599
  },
2600
+ isDocumentOperationPending: function isDocumentOperationPending() {
2601
+ this.renderDocumentBar();
2602
+ },
2409
2603
  isPlayingAudio: function isPlayingAudio() {
2410
2604
  // Reserved for future use — volume-based interrupt detection
2411
2605
  // no longer mutes tracks; browser echo cancellation handles echo.
@@ -2431,22 +2625,23 @@ window.openAIChatManager = function () {
2431
2625
  }
2432
2626
  },
2433
2627
  mounted: function mounted() {
2434
- var _this20 = this;
2435
- _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
2436
- return _regenerator().w(function (_context6) {
2437
- while (1) switch (_context6.n) {
2628
+ var _this22 = this;
2629
+ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
2630
+ var isInitialized;
2631
+ return _regenerator().w(function (_context0) {
2632
+ while (1) switch (_context0.n) {
2438
2633
  case 0:
2439
- _context6.n = 1;
2440
- return _this20.startConnection();
2634
+ _context0.n = 1;
2635
+ return _this22.startConnection();
2441
2636
  case 1:
2442
- _this20.initializeApp();
2443
- if (hasWidgetConfig && widgetBehavior && typeof widgetBehavior.onMounted === 'function') {
2444
- widgetBehavior.onMounted(_this20, config);
2637
+ isInitialized = _this22.initializeApp();
2638
+ if (isInitialized && hasWidgetConfig && widgetBehavior && typeof widgetBehavior.onMounted === 'function') {
2639
+ widgetBehavior.onMounted(_this22, config);
2445
2640
  }
2446
2641
  case 2:
2447
- return _context6.a(2);
2642
+ return _context0.a(2);
2448
2643
  }
2449
- }, _callee6);
2644
+ }, _callee0);
2450
2645
  }))();
2451
2646
  window.addEventListener('beforeunload', this.handleBeforeUnload);
2452
2647
  window.addEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);