@kroonen-ai/librebot-widget 1.6.2 → 1.6.3

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.
@@ -422,6 +422,45 @@ const getStyles = (primaryColor = '#14b8a6') => `
422
422
  40% { transform: scale(1); opacity: 1; }
423
423
  }
424
424
 
425
+ /* Sources display */
426
+ .librebot-sources {
427
+ display: flex;
428
+ flex-wrap: wrap;
429
+ align-items: center;
430
+ gap: 6px;
431
+ margin-top: 10px;
432
+ padding-top: 10px;
433
+ border-top: 1px solid var(--lb-border);
434
+ }
435
+
436
+ .librebot-sources-label {
437
+ font-size: 11px;
438
+ font-weight: 600;
439
+ color: var(--lb-text-secondary);
440
+ text-transform: uppercase;
441
+ letter-spacing: 0.5px;
442
+ }
443
+
444
+ .librebot-source-tag {
445
+ display: inline-flex;
446
+ align-items: center;
447
+ gap: 4px;
448
+ padding: 3px 8px;
449
+ background: rgba(0, 0, 0, 0.2);
450
+ border-radius: 12px;
451
+ font-size: 11px;
452
+ color: var(--lb-text-secondary);
453
+ }
454
+
455
+ .librebot-widget.light .librebot-source-tag {
456
+ background: rgba(0, 0, 0, 0.06);
457
+ }
458
+
459
+ .librebot-source-relevance {
460
+ color: var(--lb-primary);
461
+ font-weight: 500;
462
+ }
463
+
425
464
  .librebot-input-area {
426
465
  padding: 12px 16px;
427
466
  border-top: 1px solid var(--lb-border);
@@ -866,6 +905,7 @@ const WIDGET_TRANSLATIONS = {
866
905
  connectionError: 'Sorry, I had trouble connecting. Please try again.',
867
906
  streamingNotSupported: 'Sorry, streaming is not supported.',
868
907
  poweredBy: 'Powered by',
908
+ sourcesLabel: 'Sources:',
869
909
  bookingTitle: 'Book an Appointment',
870
910
  selectDate: 'Select a date',
871
911
  selectTime: 'Select a time',
@@ -891,6 +931,7 @@ const WIDGET_TRANSLATIONS = {
891
931
  connectionError: 'Désolé, j\'ai eu du mal à me connecter. Veuillez réessayer.',
892
932
  streamingNotSupported: 'Désolé, le streaming n\'est pas pris en charge.',
893
933
  poweredBy: 'Propulsé par',
934
+ sourcesLabel: 'Sources :',
894
935
  bookingTitle: 'Prendre rendez-vous',
895
936
  selectDate: 'Choisir une date',
896
937
  selectTime: 'Choisir une heure',
@@ -916,6 +957,7 @@ const WIDGET_TRANSLATIONS = {
916
957
  connectionError: 'Entschuldigung, ich hatte Verbindungsprobleme. Bitte versuchen Sie es erneut.',
917
958
  streamingNotSupported: 'Entschuldigung, Streaming wird nicht unterstützt.',
918
959
  poweredBy: 'Betrieben von',
960
+ sourcesLabel: 'Quellen:',
919
961
  bookingTitle: 'Termin buchen',
920
962
  selectDate: 'Datum auswählen',
921
963
  selectTime: 'Uhrzeit auswählen',
@@ -941,6 +983,7 @@ const WIDGET_TRANSLATIONS = {
941
983
  connectionError: 'Sorry, ik had moeite met verbinden. Probeer het opnieuw.',
942
984
  streamingNotSupported: 'Sorry, streaming wordt niet ondersteund.',
943
985
  poweredBy: 'Mogelijk gemaakt door',
986
+ sourcesLabel: 'Bronnen:',
944
987
  bookingTitle: 'Afspraak maken',
945
988
  selectDate: 'Selecteer een datum',
946
989
  selectTime: 'Selecteer een tijd',
@@ -966,6 +1009,7 @@ const WIDGET_TRANSLATIONS = {
966
1009
  connectionError: 'Lo siento, tuve problemas para conectarme. Por favor, inténtalo de nuevo.',
967
1010
  streamingNotSupported: 'Lo siento, el streaming no está soportado.',
968
1011
  poweredBy: 'Desarrollado por',
1012
+ sourcesLabel: 'Fuentes:',
969
1013
  bookingTitle: 'Reservar cita',
970
1014
  selectDate: 'Seleccionar fecha',
971
1015
  selectTime: 'Seleccionar hora',
@@ -991,6 +1035,7 @@ const WIDGET_TRANSLATIONS = {
991
1035
  connectionError: 'Desculpe, tive problemas para conectar. Por favor, tente novamente.',
992
1036
  streamingNotSupported: 'Desculpe, streaming não é suportado.',
993
1037
  poweredBy: 'Desenvolvido por',
1038
+ sourcesLabel: 'Fontes:',
994
1039
  bookingTitle: 'Agendar consulta',
995
1040
  selectDate: 'Selecionar data',
996
1041
  selectTime: 'Selecionar horário',
@@ -1016,6 +1061,7 @@ const WIDGET_TRANSLATIONS = {
1016
1061
  connectionError: '죄송합니다. 연결에 문제가 있습니다. 다시 시도해 주세요.',
1017
1062
  streamingNotSupported: '죄송합니다. 스트리밍이 지원되지 않습니다.',
1018
1063
  poweredBy: '제공:',
1064
+ sourcesLabel: '출처:',
1019
1065
  bookingTitle: '예약하기',
1020
1066
  selectDate: '날짜 선택',
1021
1067
  selectTime: '시간 선택',
@@ -1041,6 +1087,7 @@ const WIDGET_TRANSLATIONS = {
1041
1087
  connectionError: '申し訳ありません。接続に問題がありました。もう一度お試しください。',
1042
1088
  streamingNotSupported: '申し訳ありません。ストリーミングはサポートされていません。',
1043
1089
  poweredBy: '提供:',
1090
+ sourcesLabel: '出典:',
1044
1091
  bookingTitle: '予約する',
1045
1092
  selectDate: '日付を選択',
1046
1093
  selectTime: '時間を選択',
@@ -1066,6 +1113,7 @@ const WIDGET_TRANSLATIONS = {
1066
1113
  connectionError: '抱歉,连接出现问题。请重试。',
1067
1114
  streamingNotSupported: '抱歉,不支持流式传输。',
1068
1115
  poweredBy: '由以下提供支持:',
1116
+ sourcesLabel: '来源:',
1069
1117
  bookingTitle: '预约',
1070
1118
  selectDate: '选择日期',
1071
1119
  selectTime: '选择时间',
@@ -1091,6 +1139,7 @@ const WIDGET_TRANSLATIONS = {
1091
1139
  connectionError: 'क्षमा करें, कनेक्ट करने में समस्या हुई। कृपया पुनः प्रयास करें।',
1092
1140
  streamingNotSupported: 'क्षमा करें, स्ट्रीमिंग समर्थित नहीं है।',
1093
1141
  poweredBy: 'द्वारा संचालित',
1142
+ sourcesLabel: 'स्रोत:',
1094
1143
  bookingTitle: 'अपॉइंटमेंट बुक करें',
1095
1144
  selectDate: 'तिथि चुनें',
1096
1145
  selectTime: 'समय चुनें',
@@ -1116,6 +1165,7 @@ const WIDGET_TRANSLATIONS = {
1116
1165
  connectionError: 'عذراً، واجهت مشكلة في الاتصال. يرجى المحاولة مرة أخرى.',
1117
1166
  streamingNotSupported: 'عذراً، البث غير مدعوم.',
1118
1167
  poweredBy: 'مدعوم من',
1168
+ sourcesLabel: 'المصادر:',
1119
1169
  bookingTitle: 'حجز موعد',
1120
1170
  selectDate: 'اختر التاريخ',
1121
1171
  selectTime: 'اختر الوقت',
@@ -1142,6 +1192,7 @@ const WIDGET_TRANSLATIONS = {
1142
1192
  connectionError: 'দুঃখিত, সংযোগে সমস্যা হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন।',
1143
1193
  streamingNotSupported: 'দুঃখিত, স্ট্রিমিং সমর্থিত নয়।',
1144
1194
  poweredBy: 'দ্বারা চালিত',
1195
+ sourcesLabel: 'সূত্র:',
1145
1196
  bookingTitle: 'অ্যাপয়েন্টমেন্ট বুক করুন',
1146
1197
  selectDate: 'তারিখ নির্বাচন করুন',
1147
1198
  selectTime: 'সময় নির্বাচন করুন',
@@ -1168,6 +1219,7 @@ const WIDGET_TRANSLATIONS = {
1168
1219
  connectionError: 'Извините, возникла проблема с подключением. Пожалуйста, попробуйте снова.',
1169
1220
  streamingNotSupported: 'Извините, потоковая передача не поддерживается.',
1170
1221
  poweredBy: 'Работает на',
1222
+ sourcesLabel: 'Источники:',
1171
1223
  bookingTitle: 'Записаться на приём',
1172
1224
  selectDate: 'Выберите дату',
1173
1225
  selectTime: 'Выберите время',
@@ -1194,6 +1246,7 @@ const WIDGET_TRANSLATIONS = {
1194
1246
  connectionError: 'Maaf, ada masalah koneksi. Silakan coba lagi.',
1195
1247
  streamingNotSupported: 'Maaf, streaming tidak didukung.',
1196
1248
  poweredBy: 'Didukung oleh',
1249
+ sourcesLabel: 'Sumber:',
1197
1250
  bookingTitle: 'Buat Janji',
1198
1251
  selectDate: 'Pilih tanggal',
1199
1252
  selectTime: 'Pilih waktu',
@@ -1220,6 +1273,7 @@ const WIDGET_TRANSLATIONS = {
1220
1273
  connectionError: 'Xin lỗi, có vấn đề kết nối. Vui lòng thử lại.',
1221
1274
  streamingNotSupported: 'Xin lỗi, không hỗ trợ phát trực tuyến.',
1222
1275
  poweredBy: 'Được cung cấp bởi',
1276
+ sourcesLabel: 'Nguồn:',
1223
1277
  bookingTitle: 'Đặt lịch hẹn',
1224
1278
  selectDate: 'Chọn ngày',
1225
1279
  selectTime: 'Chọn giờ',
@@ -1246,6 +1300,7 @@ const WIDGET_TRANSLATIONS = {
1246
1300
  connectionError: 'Üzgünüm, bağlantı sorunu yaşadım. Lütfen tekrar deneyin.',
1247
1301
  streamingNotSupported: 'Üzgünüm, akış desteklenmiyor.',
1248
1302
  poweredBy: 'Tarafından desteklenmektedir',
1303
+ sourcesLabel: 'Kaynaklar:',
1249
1304
  bookingTitle: 'Randevu Al',
1250
1305
  selectDate: 'Tarih seçin',
1251
1306
  selectTime: 'Saat seçin',
@@ -1272,6 +1327,7 @@ const WIDGET_TRANSLATIONS = {
1272
1327
  connectionError: 'Mi dispiace, ho avuto problemi di connessione. Per favore riprova.',
1273
1328
  streamingNotSupported: 'Mi dispiace, lo streaming non è supportato.',
1274
1329
  poweredBy: 'Offerto da',
1330
+ sourcesLabel: 'Fonti:',
1275
1331
  bookingTitle: 'Prenota un Appuntamento',
1276
1332
  selectDate: 'Seleziona una data',
1277
1333
  selectTime: 'Seleziona un orario',
@@ -1298,6 +1354,7 @@ const WIDGET_TRANSLATIONS = {
1298
1354
  connectionError: 'ขออภัย มีปัญหาในการเชื่อมต่อ กรุณาลองอีกครั้ง',
1299
1355
  streamingNotSupported: 'ขออภัย ไม่รองรับการสตรีม',
1300
1356
  poweredBy: 'ขับเคลื่อนโดย',
1357
+ sourcesLabel: 'แหล่งที่มา:',
1301
1358
  bookingTitle: 'จองนัดหมาย',
1302
1359
  selectDate: 'เลือกวันที่',
1303
1360
  selectTime: 'เลือกเวลา',
@@ -1324,6 +1381,7 @@ const WIDGET_TRANSLATIONS = {
1324
1381
  connectionError: 'Przepraszam, miałem problem z połączeniem. Spróbuj ponownie.',
1325
1382
  streamingNotSupported: 'Przepraszam, streaming nie jest obsługiwany.',
1326
1383
  poweredBy: 'Obsługiwane przez',
1384
+ sourcesLabel: 'Źródła:',
1327
1385
  bookingTitle: 'Umów wizytę',
1328
1386
  selectDate: 'Wybierz datę',
1329
1387
  selectTime: 'Wybierz godzinę',
@@ -1350,6 +1408,7 @@ const WIDGET_TRANSLATIONS = {
1350
1408
  connectionError: 'Вибачте, виникла проблема з підключенням. Будь ласка, спробуйте ще раз.',
1351
1409
  streamingNotSupported: 'Вибачте, потокова передача не підтримується.',
1352
1410
  poweredBy: 'Працює на',
1411
+ sourcesLabel: 'Джерела:',
1353
1412
  bookingTitle: 'Записатися на прийом',
1354
1413
  selectDate: 'Оберіть дату',
1355
1414
  selectTime: 'Оберіть час',
@@ -1376,6 +1435,7 @@ const WIDGET_TRANSLATIONS = {
1376
1435
  connectionError: 'Maaf, ada masalah sambungan. Sila cuba lagi.',
1377
1436
  streamingNotSupported: 'Maaf, penstriman tidak disokong.',
1378
1437
  poweredBy: 'Dikuasakan oleh',
1438
+ sourcesLabel: 'Sumber:',
1379
1439
  bookingTitle: 'Buat Temujanji',
1380
1440
  selectDate: 'Pilih tarikh',
1381
1441
  selectTime: 'Pilih masa',
@@ -1402,6 +1462,7 @@ const WIDGET_TRANSLATIONS = {
1402
1462
  connectionError: 'Omlouvám se, měl jsem problém s připojením. Zkuste to prosím znovu.',
1403
1463
  streamingNotSupported: 'Omlouvám se, streamování není podporováno.',
1404
1464
  poweredBy: 'Využívá technologii',
1465
+ sourcesLabel: 'Zdroje:',
1405
1466
  bookingTitle: 'Rezervovat schůzku',
1406
1467
  selectDate: 'Vyberte datum',
1407
1468
  selectTime: 'Vyberte čas',
@@ -1428,6 +1489,7 @@ const WIDGET_TRANSLATIONS = {
1428
1489
  connectionError: 'Tyvärr hade jag problem med anslutningen. Försök igen.',
1429
1490
  streamingNotSupported: 'Tyvärr stöds inte streaming.',
1430
1491
  poweredBy: 'Drivs av',
1492
+ sourcesLabel: 'Källor:',
1431
1493
  bookingTitle: 'Boka tid',
1432
1494
  selectDate: 'Välj datum',
1433
1495
  selectTime: 'Välj tid',
@@ -1454,6 +1516,7 @@ const WIDGET_TRANSLATIONS = {
1454
1516
  connectionError: 'Beklager, jeg havde problemer med forbindelsen. Prøv venligst igen.',
1455
1517
  streamingNotSupported: 'Beklager, streaming understøttes ikke.',
1456
1518
  poweredBy: 'Drevet af',
1519
+ sourcesLabel: 'Kilder:',
1457
1520
  bookingTitle: 'Book en tid',
1458
1521
  selectDate: 'Vælg dato',
1459
1522
  selectTime: 'Vælg tidspunkt',
@@ -1480,6 +1543,7 @@ const WIDGET_TRANSLATIONS = {
1480
1543
  connectionError: 'Því miður átti ég í vandræðum með tengingu. Vinsamlegast reyndu aftur.',
1481
1544
  streamingNotSupported: 'Því miður er streymi ekki stutt.',
1482
1545
  poweredBy: 'Knúið af',
1546
+ sourcesLabel: 'Heimildir:',
1483
1547
  bookingTitle: 'Bóka tíma',
1484
1548
  selectDate: 'Veldu dagsetningu',
1485
1549
  selectTime: 'Veldu tíma',
@@ -1545,6 +1609,7 @@ class LibreBotWidget {
1545
1609
  welcomeMessage: '', // Will be set from translations
1546
1610
  streaming: true,
1547
1611
  whiteLabel: false,
1612
+ showSources: false,
1548
1613
  autoLoadConfig: true,
1549
1614
  lang: 'en',
1550
1615
  };
@@ -1617,6 +1682,8 @@ class LibreBotWidget {
1617
1682
  provided.streaming = userConfig.streaming;
1618
1683
  if (userConfig.whiteLabel !== defaults.whiteLabel)
1619
1684
  provided.whiteLabel = userConfig.whiteLabel;
1685
+ if (userConfig.showSources !== defaults.showSources)
1686
+ provided.showSources = userConfig.showSources;
1620
1687
  return provided;
1621
1688
  }
1622
1689
  init() {
@@ -1757,12 +1824,13 @@ class LibreBotWidget {
1757
1824
  this.isOpen = false;
1758
1825
  this.modal?.classList.remove('open');
1759
1826
  }
1760
- addMessage(role, content) {
1827
+ addMessage(role, content, sources) {
1761
1828
  const message = {
1762
1829
  id: `msg-${Date.now()}`,
1763
1830
  role,
1764
1831
  content,
1765
1832
  timestamp: new Date(),
1833
+ sources,
1766
1834
  };
1767
1835
  this.messages.push(message);
1768
1836
  this.renderMessage(message);
@@ -1773,9 +1841,38 @@ class LibreBotWidget {
1773
1841
  const el = document.createElement('div');
1774
1842
  el.className = `librebot-message ${message.role}`;
1775
1843
  el.innerHTML = this.formatMessage(message.content);
1844
+ // Add sources if showSources is enabled and message has sources
1845
+ if (this.config.showSources && message.sources && message.sources.length > 0 && message.role === 'assistant') {
1846
+ const sourcesEl = this.renderSources(message.sources);
1847
+ el.appendChild(sourcesEl);
1848
+ }
1776
1849
  this.messagesContainer.appendChild(el);
1777
1850
  this.scrollToBottom();
1778
1851
  }
1852
+ renderSources(sources) {
1853
+ const container = document.createElement('div');
1854
+ container.className = 'librebot-sources';
1855
+ const label = document.createElement('span');
1856
+ label.className = 'librebot-sources-label';
1857
+ label.textContent = this.translations.sourcesLabel || 'Sources:';
1858
+ container.appendChild(label);
1859
+ sources.forEach(source => {
1860
+ const tag = document.createElement('span');
1861
+ tag.className = 'librebot-source-tag';
1862
+ const relevancePercent = Math.round(source.relevance * 100);
1863
+ tag.innerHTML = `${this.escapeHtml(source.documentName)} <span class="librebot-source-relevance">(${relevancePercent}%)</span>`;
1864
+ container.appendChild(tag);
1865
+ });
1866
+ return container;
1867
+ }
1868
+ escapeHtml(text) {
1869
+ return text
1870
+ .replace(/&/g, '&amp;')
1871
+ .replace(/</g, '&lt;')
1872
+ .replace(/>/g, '&gt;')
1873
+ .replace(/"/g, '&quot;')
1874
+ .replace(/'/g, '&#039;');
1875
+ }
1779
1876
  formatMessage(content) {
1780
1877
  // Escape HTML to prevent XSS
1781
1878
  const escapeHtml = (text) => {
@@ -1879,7 +1976,7 @@ class LibreBotWidget {
1879
1976
  this.addMessage('assistant', `${this.translations.errorPrefix} ${response.error}`);
1880
1977
  }
1881
1978
  else {
1882
- this.addMessage('assistant', response.response);
1979
+ this.addMessage('assistant', response.response, response.sources);
1883
1980
  // Check for booking intent
1884
1981
  this.handleBookingIntent(response);
1885
1982
  }
@@ -1927,6 +2024,7 @@ class LibreBotWidget {
1927
2024
  const decoder = new TextDecoder();
1928
2025
  let fullContent = '';
1929
2026
  let bookingIntentData = null;
2027
+ let receivedSources = [];
1930
2028
  try {
1931
2029
  while (true) {
1932
2030
  const { done, value } = await reader.read();
@@ -1950,6 +2048,10 @@ class LibreBotWidget {
1950
2048
  if (parsed.sessionId) {
1951
2049
  this.saveSession(parsed.sessionId);
1952
2050
  }
2051
+ // Capture sources from metadata
2052
+ if (parsed.sources && Array.isArray(parsed.sources)) {
2053
+ receivedSources = parsed.sources;
2054
+ }
1953
2055
  // Check for booking intent in metadata
1954
2056
  if (parsed.booking_intent && parsed.booking_config) {
1955
2057
  bookingIntentData = parsed;
@@ -1965,12 +2067,18 @@ class LibreBotWidget {
1965
2067
  catch (error) {
1966
2068
  console.error('Stream reading error:', error);
1967
2069
  }
2070
+ // Add sources to message element if showSources is enabled
2071
+ if (this.config.showSources && receivedSources.length > 0) {
2072
+ const sourcesEl = this.renderSources(receivedSources);
2073
+ messageEl.appendChild(sourcesEl);
2074
+ }
1968
2075
  // Add to messages array
1969
2076
  this.messages.push({
1970
2077
  id: `msg-${Date.now()}`,
1971
2078
  role: 'assistant',
1972
2079
  content: fullContent,
1973
2080
  timestamp: new Date(),
2081
+ sources: receivedSources.length > 0 ? receivedSources : undefined,
1974
2082
  });
1975
2083
  // Handle booking intent if detected
1976
2084
  if (bookingIntentData) {