@eshal-bot/chat-widget 0.1.106 → 0.1.107

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.
@@ -1 +1 @@
1
- export{S as default}from"./chat-widget-index-Ccm0r0y5.esm.js";import"react";import"react-dom/client";import"react-dom";import"react/jsx-runtime";
1
+ export{S as default}from"./chat-widget-index-DhZDbyb2.esm.js";import"react";import"react-dom/client";import"react-dom";import"react/jsx-runtime";
@@ -8017,7 +8017,7 @@
8017
8017
  * @param {string} apiBaseUrl - Base URL for the API
8018
8018
  * @param {Function|undefined} getAuthToken - async fn returning a Bearer token (in-app JWT path), or undefined (Mode B proxy)
8019
8019
  */
8020
- const sendStreamingRequest = async (request, apiBaseUrl, getAuthToken) => {
8020
+ const sendStreamingRequest = async (request, apiBaseUrl, getAuthToken, signal) => {
8021
8021
  const headers = {
8022
8022
  'Content-Type': 'application/json',
8023
8023
  Accept: 'text/event-stream'
@@ -8031,12 +8031,14 @@
8031
8031
  headers['Authorization'] = "Bearer ".concat(token);
8032
8032
  }
8033
8033
  }
8034
- const response = await fetch("".concat(apiBaseUrl.replace(/\/$/, ''), "/api/v1/support"), {
8034
+ const response = await fetch("".concat(apiBaseUrl.replace(/\/$/, ''), "/api/v1/support"), _objectSpread2({
8035
8035
  method: 'POST',
8036
8036
  headers,
8037
8037
  credentials: 'include',
8038
8038
  body: JSON.stringify(request)
8039
- });
8039
+ }, signal ? {
8040
+ signal
8041
+ } : {}));
8040
8042
  if (!response.ok) {
8041
8043
  throw new Error("HTTP error! status: ".concat(response.status));
8042
8044
  }
@@ -8686,6 +8688,22 @@
8686
8688
  }
8687
8689
  }
8688
8690
  }
8691
+ } catch (err) {
8692
+ // EV-3045: the user pressed Stop (fetch aborted). The partial answer
8693
+ // stays on screen, finalized — NOT an error, NOT a retry (retrying a
8694
+ // deliberately-stopped answer re-asks the question the user killed).
8695
+ if (err && err.name === 'AbortError') {
8696
+ if (accumulatedText.current) {
8697
+ updateFinalMessage(setMessages, accumulatedText.current, {
8698
+ stoppedByUser: true
8699
+ });
8700
+ } else {
8701
+ // nothing arrived yet — just drop the skeleton bubble
8702
+ setMessages(prev => (prev || []).filter(msg => !msg.isProcessing));
8703
+ }
8704
+ return;
8705
+ }
8706
+ throw err;
8689
8707
  } finally {
8690
8708
  reader.releaseLock();
8691
8709
  }
@@ -9550,6 +9568,10 @@
9550
9568
  _setInputValue(next);
9551
9569
  }, []);
9552
9570
  const [isLoading, setIsLoading] = reactExports.useState(false);
9571
+ // EV-3045: aborts the in-flight streaming fetch when the user presses
9572
+ // Stop. A fresh controller is armed per streaming attempt; stale
9573
+ // controllers are inert (abort on an already-finished fetch is a no-op).
9574
+ const streamAbortRef = reactExports.useRef(null);
9553
9575
  const widgetRef = reactExports.useRef(null);
9554
9576
  const messageIdRef = reactExports.useRef(1);
9555
9577
 
@@ -10131,6 +10153,21 @@
10131
10153
  })];
10132
10154
  });
10133
10155
  }, [getNextMessageId]);
10156
+
10157
+ // EV-3045: Stop control. Aborting the fetch is the cancellation signal —
10158
+ // the server tears the generator down on disconnect (cancelling the ADK
10159
+ // run, tool calls and delegation), and persists the partial answer to
10160
+ // history with a "stopped" marker. Client-side, processStream finalizes
10161
+ // the partial bubble on AbortError.
10162
+ const stopGeneration = reactExports.useCallback(() => {
10163
+ try {
10164
+ if (streamAbortRef.current) {
10165
+ streamAbortRef.current.abort();
10166
+ }
10167
+ } catch (_unused9) {
10168
+ /* aborting a finished fetch is a no-op */
10169
+ }
10170
+ }, []);
10134
10171
  const sendMessage = reactExports.useCallback(async (rawText, fieldType, opts) => {
10135
10172
  const trimmed = String(rawText !== null && rawText !== void 0 ? rawText : '').trim();
10136
10173
  const attachmentsPayload = Array.isArray(opts === null || opts === void 0 ? void 0 : opts.attachments) ? opts.attachments : [];
@@ -10357,7 +10394,7 @@
10357
10394
  } = await reader.read();
10358
10395
  if (done) break;
10359
10396
  }
10360
- } catch (_unused9) {
10397
+ } catch (_unused0) {
10361
10398
  /* persistence is best-effort; the human reply still arrives via SSE */
10362
10399
  }
10363
10400
  updateActivity(organizationId);
@@ -10369,7 +10406,10 @@
10369
10406
  let lastErr;
10370
10407
  for (let attempt = 0; attempt <= STREAM_RETRY_DELAYS_MS.length; attempt += 1) {
10371
10408
  try {
10372
- const stream = await sendStreamingRequest(chatRequest, apiBaseUrl, getAuthToken);
10409
+ // EV-3045: one controller per attempt — the Stop button aborts
10410
+ // exactly the attempt that is streaming.
10411
+ streamAbortRef.current = new AbortController();
10412
+ const stream = await sendStreamingRequest(chatRequest, apiBaseUrl, getAuthToken, streamAbortRef.current.signal);
10373
10413
  await processStream(stream, setMessages);
10374
10414
  updateActivity(organizationId);
10375
10415
  return {
@@ -10377,6 +10417,17 @@
10377
10417
  };
10378
10418
  } catch (err) {
10379
10419
  lastErr = err;
10420
+ // EV-3045: a user Stop that aborted BEFORE any bytes arrived
10421
+ // rejects the fetch itself with AbortError (processStream's
10422
+ // own AbortError handling covers mid-stream aborts). Treat as
10423
+ // a successful, deliberate end — never retry a stopped turn.
10424
+ if (err && err.name === 'AbortError') {
10425
+ setMessages(prev => (prev || []).filter(msg => !msg.isProcessing));
10426
+ return {
10427
+ success: true,
10428
+ stopped: true
10429
+ };
10430
+ }
10380
10431
  if (err instanceof IncompleteStreamError && attempt < STREAM_RETRY_DELAYS_MS.length) {
10381
10432
  // Drop the half-rendered assistant bubble before retrying so
10382
10433
  // the next attempt doesn't paint into a stale skeleton.
@@ -11757,6 +11808,7 @@
11757
11808
  // Actions
11758
11809
  setInputValue,
11759
11810
  handleSend,
11811
+ stopGeneration,
11760
11812
  handleQuickQuestion,
11761
11813
  sendMessage,
11762
11814
  toggleChat,
@@ -11907,7 +11959,7 @@
11907
11959
  * See the LICENSE file in the root directory of this source tree.
11908
11960
  */
11909
11961
 
11910
- const __iconNode$h = [["path", {
11962
+ const __iconNode$i = [["path", {
11911
11963
  d: "M2 10v3",
11912
11964
  key: "1fnikh"
11913
11965
  }], ["path", {
@@ -11926,7 +11978,7 @@
11926
11978
  d: "M22 10v3",
11927
11979
  key: "154ddg"
11928
11980
  }]];
11929
- const AudioLines = createLucideIcon("audio-lines", __iconNode$h);
11981
+ const AudioLines = createLucideIcon("audio-lines", __iconNode$i);
11930
11982
 
11931
11983
  /**
11932
11984
  * @license lucide-react v0.575.0 - ISC
@@ -11935,11 +11987,11 @@
11935
11987
  * See the LICENSE file in the root directory of this source tree.
11936
11988
  */
11937
11989
 
11938
- const __iconNode$g = [["path", {
11990
+ const __iconNode$h = [["path", {
11939
11991
  d: "m15 18-6-6 6-6",
11940
11992
  key: "1wnfg3"
11941
11993
  }]];
11942
- const ChevronLeft = createLucideIcon("chevron-left", __iconNode$g);
11994
+ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$h);
11943
11995
 
11944
11996
  /**
11945
11997
  * @license lucide-react v0.575.0 - ISC
@@ -11948,11 +12000,11 @@
11948
12000
  * See the LICENSE file in the root directory of this source tree.
11949
12001
  */
11950
12002
 
11951
- const __iconNode$f = [["path", {
12003
+ const __iconNode$g = [["path", {
11952
12004
  d: "m9 18 6-6-6-6",
11953
12005
  key: "mthhwq"
11954
12006
  }]];
11955
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$f);
12007
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$g);
11956
12008
 
11957
12009
  /**
11958
12010
  * @license lucide-react v0.575.0 - ISC
@@ -11961,7 +12013,7 @@
11961
12013
  * See the LICENSE file in the root directory of this source tree.
11962
12014
  */
11963
12015
 
11964
- const __iconNode$e = [["circle", {
12016
+ const __iconNode$f = [["circle", {
11965
12017
  cx: "12",
11966
12018
  cy: "12",
11967
12019
  r: "10",
@@ -11979,7 +12031,7 @@
11979
12031
  y2: "16",
11980
12032
  key: "4dfq90"
11981
12033
  }]];
11982
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$e);
12034
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$f);
11983
12035
 
11984
12036
  /**
11985
12037
  * @license lucide-react v0.575.0 - ISC
@@ -11988,7 +12040,7 @@
11988
12040
  * See the LICENSE file in the root directory of this source tree.
11989
12041
  */
11990
12042
 
11991
- const __iconNode$d = [["rect", {
12043
+ const __iconNode$e = [["rect", {
11992
12044
  width: "14",
11993
12045
  height: "14",
11994
12046
  x: "8",
@@ -12000,7 +12052,7 @@
12000
12052
  d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",
12001
12053
  key: "zix9uf"
12002
12054
  }]];
12003
- const Copy = createLucideIcon("copy", __iconNode$d);
12055
+ const Copy = createLucideIcon("copy", __iconNode$e);
12004
12056
 
12005
12057
  /**
12006
12058
  * @license lucide-react v0.575.0 - ISC
@@ -12009,7 +12061,7 @@
12009
12061
  * See the LICENSE file in the root directory of this source tree.
12010
12062
  */
12011
12063
 
12012
- const __iconNode$c = [["circle", {
12064
+ const __iconNode$d = [["circle", {
12013
12065
  cx: "12",
12014
12066
  cy: "12",
12015
12067
  r: "1",
@@ -12025,7 +12077,7 @@
12025
12077
  r: "1",
12026
12078
  key: "1pcz8c"
12027
12079
  }]];
12028
- const Ellipsis = createLucideIcon("ellipsis", __iconNode$c);
12080
+ const Ellipsis = createLucideIcon("ellipsis", __iconNode$d);
12029
12081
 
12030
12082
  /**
12031
12083
  * @license lucide-react v0.575.0 - ISC
@@ -12034,7 +12086,7 @@
12034
12086
  * See the LICENSE file in the root directory of this source tree.
12035
12087
  */
12036
12088
 
12037
- const __iconNode$b = [["path", {
12089
+ const __iconNode$c = [["path", {
12038
12090
  d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
12039
12091
  key: "1oefj6"
12040
12092
  }], ["path", {
@@ -12050,7 +12102,7 @@
12050
12102
  d: "M16 17H8",
12051
12103
  key: "z1uh3a"
12052
12104
  }]];
12053
- const FileText = createLucideIcon("file-text", __iconNode$b);
12105
+ const FileText = createLucideIcon("file-text", __iconNode$c);
12054
12106
 
12055
12107
  /**
12056
12108
  * @license lucide-react v0.575.0 - ISC
@@ -12059,11 +12111,11 @@
12059
12111
  * See the LICENSE file in the root directory of this source tree.
12060
12112
  */
12061
12113
 
12062
- const __iconNode$a = [["path", {
12114
+ const __iconNode$b = [["path", {
12063
12115
  d: "M21 12a9 9 0 1 1-6.219-8.56",
12064
12116
  key: "13zald"
12065
12117
  }]];
12066
- const LoaderCircle = createLucideIcon("loader-circle", __iconNode$a);
12118
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$b);
12067
12119
 
12068
12120
  /**
12069
12121
  * @license lucide-react v0.575.0 - ISC
@@ -12072,11 +12124,11 @@
12072
12124
  * See the LICENSE file in the root directory of this source tree.
12073
12125
  */
12074
12126
 
12075
- const __iconNode$9 = [["path", {
12127
+ const __iconNode$a = [["path", {
12076
12128
  d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",
12077
12129
  key: "1sd12s"
12078
12130
  }]];
12079
- const MessageCircle = createLucideIcon("message-circle", __iconNode$9);
12131
+ const MessageCircle = createLucideIcon("message-circle", __iconNode$a);
12080
12132
 
12081
12133
  /**
12082
12134
  * @license lucide-react v0.575.0 - ISC
@@ -12085,11 +12137,11 @@
12085
12137
  * See the LICENSE file in the root directory of this source tree.
12086
12138
  */
12087
12139
 
12088
- const __iconNode$8 = [["path", {
12140
+ const __iconNode$9 = [["path", {
12089
12141
  d: "M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",
12090
12142
  key: "kfwtm"
12091
12143
  }]];
12092
- const Moon = createLucideIcon("moon", __iconNode$8);
12144
+ const Moon = createLucideIcon("moon", __iconNode$9);
12093
12145
 
12094
12146
  /**
12095
12147
  * @license lucide-react v0.575.0 - ISC
@@ -12098,11 +12150,11 @@
12098
12150
  * See the LICENSE file in the root directory of this source tree.
12099
12151
  */
12100
12152
 
12101
- const __iconNode$7 = [["path", {
12153
+ const __iconNode$8 = [["path", {
12102
12154
  d: "m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551",
12103
12155
  key: "1miecu"
12104
12156
  }]];
12105
- const Paperclip = createLucideIcon("paperclip", __iconNode$7);
12157
+ const Paperclip = createLucideIcon("paperclip", __iconNode$8);
12106
12158
 
12107
12159
  /**
12108
12160
  * @license lucide-react v0.575.0 - ISC
@@ -12111,14 +12163,14 @@
12111
12163
  * See the LICENSE file in the root directory of this source tree.
12112
12164
  */
12113
12165
 
12114
- const __iconNode$6 = [["path", {
12166
+ const __iconNode$7 = [["path", {
12115
12167
  d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
12116
12168
  key: "1357e3"
12117
12169
  }], ["path", {
12118
12170
  d: "M3 3v5h5",
12119
12171
  key: "1xhq8a"
12120
12172
  }]];
12121
- const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$6);
12173
+ const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$7);
12122
12174
 
12123
12175
  /**
12124
12176
  * @license lucide-react v0.575.0 - ISC
@@ -12127,14 +12179,31 @@
12127
12179
  * See the LICENSE file in the root directory of this source tree.
12128
12180
  */
12129
12181
 
12130
- const __iconNode$5 = [["path", {
12182
+ const __iconNode$6 = [["path", {
12131
12183
  d: "M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",
12132
12184
  key: "1ffxy3"
12133
12185
  }], ["path", {
12134
12186
  d: "m21.854 2.147-10.94 10.939",
12135
12187
  key: "12cjpa"
12136
12188
  }]];
12137
- const Send = createLucideIcon("send", __iconNode$5);
12189
+ const Send = createLucideIcon("send", __iconNode$6);
12190
+
12191
+ /**
12192
+ * @license lucide-react v0.575.0 - ISC
12193
+ *
12194
+ * This source code is licensed under the ISC license.
12195
+ * See the LICENSE file in the root directory of this source tree.
12196
+ */
12197
+
12198
+ const __iconNode$5 = [["rect", {
12199
+ width: "18",
12200
+ height: "18",
12201
+ x: "3",
12202
+ y: "3",
12203
+ rx: "2",
12204
+ key: "afitv7"
12205
+ }]];
12206
+ const Square = createLucideIcon("square", __iconNode$5);
12138
12207
 
12139
12208
  /**
12140
12209
  * @license lucide-react v0.575.0 - ISC
@@ -12345,6 +12414,9 @@
12345
12414
  scrollLeft: "Scroll left",
12346
12415
  scrollRight: "Scroll right",
12347
12416
  sendMessage: "Send message",
12417
+ // EV-3045: Stop control aria-label. EN-only for now — translate() falls
12418
+ // back to EN for locales without the key.
12419
+ stopGenerating: "Stop generating",
12348
12420
  startVoiceInput: "Start voice input",
12349
12421
  stopVoiceInput: "Stop voice input",
12350
12422
  voiceSessionLive: "Voice session live - speak or type to converse.",
@@ -17332,6 +17404,9 @@
17332
17404
  };
17333
17405
  const ChatInput = _ref2 => {
17334
17406
  let {
17407
+ // EV-3045: called when the user presses Stop while a reply is streaming;
17408
+ // the send button swaps to a stop button for the duration of the turn.
17409
+ onStopGeneration,
17335
17410
  inputValue,
17336
17411
  setInputValue,
17337
17412
  onSend,
@@ -17849,7 +17924,25 @@
17849
17924
  })]
17850
17925
  })]
17851
17926
  }), document.body)]
17852
- }), /*#__PURE__*/jsxRuntimeExports.jsx("button", {
17927
+ }), isLoading && !isVoiceSessionActive && typeof onStopGeneration === "function" ?
17928
+ /*#__PURE__*/
17929
+ // EV-3045: Stop replaces Send while a reply streams — the
17930
+ // convention every benchmark assistant uses. Always enabled;
17931
+ // the partial answer stays on screen and in history.
17932
+ jsxRuntimeExports.jsx("button", {
17933
+ onClick: onStopGeneration,
17934
+ className: "h-10 w-10 flex-shrink-0 rounded-xl transition-all duration-200 flex items-center justify-center shadow-md scale-100",
17935
+ style: {
17936
+ backgroundColor: primaryColor,
17937
+ color: "white",
17938
+ border: "none"
17939
+ },
17940
+ "aria-label": t("stopGenerating"),
17941
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(Square, {
17942
+ className: "w-3.5 h-3.5",
17943
+ fill: "currentColor"
17944
+ })
17945
+ }) : /*#__PURE__*/jsxRuntimeExports.jsx("button", {
17853
17946
  onClick: isVoiceSessionActive && onBidiSubmit ? onBidiSubmit : sendWithAttachments,
17854
17947
  disabled: csatVisible || isDisabled || isVoiceSessionActive && voiceStatus !== "connected",
17855
17948
  className: "h-10 w-10 flex-shrink-0 rounded-xl transition-all duration-200 flex items-center justify-center shadow-md disabled:opacity-40 disabled:cursor-not-allowed disabled:shadow-none ".concat(inputValue.trim() ? "scale-100" : "scale-95"),
@@ -19032,6 +19125,7 @@
19032
19125
  isOpen,
19033
19126
  isMinimized,
19034
19127
  isDark,
19128
+ onStopGeneration,
19035
19129
  primaryColor,
19036
19130
  textColor,
19037
19131
  conciergeName,
@@ -19885,6 +19979,7 @@
19885
19979
  })]
19886
19980
  })
19887
19981
  }), !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(ChatInput, {
19982
+ onStopGeneration: onStopGeneration,
19888
19983
  inputValue: inputValue,
19889
19984
  setInputValue: setInputValue,
19890
19985
  onSend: onSend,
@@ -20424,6 +20519,7 @@
20424
20519
  widgetRef,
20425
20520
  setInputValue,
20426
20521
  handleSend,
20522
+ stopGeneration,
20427
20523
  handleQuickQuestion,
20428
20524
  sendMessage,
20429
20525
  toggleChat,
@@ -20607,6 +20703,7 @@
20607
20703
  inputValue: inputValue,
20608
20704
  setInputValue: setInputValue,
20609
20705
  onSend: handleSend,
20706
+ onStopGeneration: stopGeneration,
20610
20707
  onDirectSend: sendMessage,
20611
20708
  onToggleTheme: toggleTheme,
20612
20709
  onMinimize: toggleMinimize,