@flowengage/react-chatbot 6.0.18 → 6.0.19

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.
@@ -3357,7 +3357,10 @@ function Rr({ siteId: e, config: t, children: n, language: r = "en" }) {
3357
3357
  }), await Rt({
3358
3358
  ...r,
3359
3359
  callId: r.callId || O.callId
3360
- })), await k.current.acceptCall(O.callId, y), mt.current = O.callId, Je(O.callId), Xe((e) => e === "connected" || j.current ? "connected" : "connecting"), Ue(null), w(!0);
3360
+ })), await k.current.acceptCall(O.callId, y), at.current?.emit("call:accepted", {
3361
+ callId: O.callId,
3362
+ chatId: y
3363
+ }), mt.current = O.callId, Je(O.callId), Xe((e) => e === "connected" || j.current ? "connected" : "connecting"), Ue(null), w(!0);
3361
3364
  } catch (e) {
3362
3365
  if (ht.current = null, Pt("accept_call_failed"), e?.status === 404 || e?.status === 409 || e?.status === 422) {
3363
3366
  nt(Pr(e, "This visitor call is no longer available."));
@@ -3380,9 +3383,14 @@ function Rr({ siteId: e, config: t, children: n, language: r = "en" }) {
3380
3383
  Pt("reject_call_without_server_context");
3381
3384
  return;
3382
3385
  }
3383
- Mt(), jt();
3386
+ let e = O.callId;
3387
+ Mt(), jt(), at.current?.emit("call:rejected", {
3388
+ callId: e,
3389
+ chatId: y,
3390
+ reason: "visitor_declined"
3391
+ });
3384
3392
  try {
3385
- await k.current.rejectCall(O.callId, y);
3393
+ await k.current.rejectCall(e, y);
3386
3394
  } catch (e) {
3387
3395
  nt(Pr(e, "We couldn't decline the call cleanly."));
3388
3396
  } finally {
@@ -29412,6 +29420,11 @@ function Ck(e) {
29412
29420
  flowengage_highlight: async (e) => {
29413
29421
  $("flowengage_highlight ▶", e);
29414
29422
  let t = mk(e), n = t?.section_id || t?.sectionId, r = t?.section_text || t?.sectionText;
29423
+ if (typeof window < "u" && window.__fe_user_nav_during_speech) {
29424
+ let e = window.__fe_user_nav_during_speech, t = window.location.pathname;
29425
+ if (e.toPath === t && Date.now() - e.ts < 3e4) return window.__fe_user_nav_during_speech = null, $("flowengage_highlight ✖ blocked — user navigated during speech", e), `NAV_CHANGED: The visitor navigated from "${e.fromPageName}" to "${e.toPageName}" while you were speaking. DO NOT highlight anything yet. Ask the visitor: "I see you've navigated to the ${e.toPageName} page — do you want me to continue what I was explaining, or shall I guide you through this page?" Only call flowengage_highlight after the visitor confirms they want to explore this page.`;
29426
+ window.__fe_user_nav_during_speech = null;
29427
+ }
29415
29428
  xk();
29416
29429
  let i = hr(n || null, r || null);
29417
29430
  if (!i && r) {
@@ -30132,7 +30145,7 @@ function Fk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30132
30145
  let v = {
30133
30146
  clientTools: t,
30134
30147
  connectionType: "websocket",
30135
- minSpeechDurationMs: 100,
30148
+ minSpeechDurationMs: 50,
30136
30149
  ..._ ? { signedUrl: _ } : { agentId: r }
30137
30150
  }, b = (p.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()), x = "";
30138
30151
  m && m.includes("|") && (x = m.split("|").map((e) => e.trim()).filter(Boolean).reduce((e, t) => e.length <= t.length ? e : t));
@@ -30243,13 +30256,25 @@ function Fk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30243
30256
  t = n;
30244
30257
  return;
30245
30258
  }
30259
+ let r = t;
30246
30260
  t = n;
30247
- let r = window.location.href, i = typeof document < "u" ? document.title : "", a = typeof document < "u" ? Array.from(document.querySelectorAll("h1, h2, h3, h4")).filter((e) => !e.closest("#flowengage-root, .flowengage-shell")).map((e) => ({
30261
+ let i = window.location.href, a = typeof document < "u" ? document.title : "", o = typeof document < "u" ? Array.from(document.querySelectorAll("h1, h2, h3, h4")).filter((e) => !e.closest("#flowengage-root, .flowengage-shell")).map((e) => ({
30248
30262
  tag: e.tagName,
30249
30263
  text: e.textContent.trim()
30250
30264
  })).filter((e) => e.text.length > 0 && e.text.length < 200).slice(0, 20) : [];
30251
30265
  try {
30252
- S.current?.sendContextualUpdate?.(`PAGE CHANGED — visitor navigated manually. Current URL is now: ${r}. Page title: "${i}". Sections on this page: ${JSON.stringify(a)}. When the visitor asks about "this page", "current page", or "what page am I on", refer to this new URL — not any previously mentioned page.`);
30266
+ SD();
30267
+ } catch {}
30268
+ let s = (e) => (e.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()) || "Home", c = s(r), l = s(n);
30269
+ typeof window < "u" && (window.__fe_user_nav_during_speech = {
30270
+ fromPath: r,
30271
+ toPath: n,
30272
+ fromPageName: c,
30273
+ toPageName: l,
30274
+ ts: Date.now()
30275
+ });
30276
+ try {
30277
+ S.current?.sendContextualUpdate?.(`IMPORTANT — VISITOR NAVIGATED WHILE YOU WERE SPEAKING. You were explaining "${c}". The visitor has now moved to "${l}" (${i}). Page title: "${a}". Sections on this page: ${JSON.stringify(o)}. STOP your current explanation immediately. Say exactly: "I see you've navigated to the ${l} page — do you want me to continue what I was explaining, or would you like to know about this page?" If the visitor says "continue": resume your explanation verbally BUT do NOT call flowengage_highlight — you are no longer on the page you were describing so highlights would be wrong. If they want to learn about this new page: proceed with flowengage_highlight on sections of "${l}". Do NOT highlight anything until the visitor answers this question.`);
30253
30278
  } catch {}
30254
30279
  };
30255
30280
  c = window.history.pushState.bind(window.history), window.history.pushState = (...e) => {
@@ -30269,7 +30294,7 @@ function Fk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30269
30294
  if (i) try {
30270
30295
  He(i);
30271
30296
  } catch {}
30272
- Ar(), le.current &&= (clearTimeout(le.current), null), ue.current &&= (clearTimeout(ue.current), null), ce.current = !1, de.current = !1, se.current = "idle", c && typeof window < "u" && (window.history.pushState = c), d && typeof window < "u" && window.removeEventListener("popstate", d);
30297
+ typeof window < "u" && (window.__fe_user_nav_during_speech = null), Ar(), le.current &&= (clearTimeout(le.current), null), ue.current &&= (clearTimeout(ue.current), null), ce.current = !1, de.current = !1, se.current = "idle", c && typeof window < "u" && (window.history.pushState = c), d && typeof window < "u" && window.removeEventListener("popstate", d);
30273
30298
  let t = o || S.current, n = E.current, r = ie.current;
30274
30299
  if (t?.endSession?.().catch(() => {}), n && s && a) {
30275
30300
  let e = r ? Math.round((Date.now() - r) / 1e3) : 0, t = JSON.stringify({
@@ -30367,97 +30392,138 @@ function Fk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30367
30392
  gap: "12px",
30368
30393
  alignItems: "center"
30369
30394
  },
30370
- children: [/* @__PURE__ */ g("button", {
30371
- onClick: async () => {
30372
- if (S.current) try {
30373
- if (v) {
30374
- oe.current = 0, await S.current.setMicMuted?.(!1), y(!1);
30375
- try {
30376
- S.current.sendContextualUpdate?.("The visitor has unmuted. Resume normal interaction and wait for them to speak.");
30377
- } catch {}
30378
- } else {
30379
- oe.current = 0, await S.current.setMicMuted?.(!0), y(!0);
30380
- try {
30381
- S.current.sendContextualUpdate?.("The visitor has muted their microphone. Do NOT speak, ask if they are there, or prompt them in any way. Stay completely silent until they unmute.");
30382
- } catch {}
30383
- }
30384
- } catch {}
30385
- },
30386
- title: v ? "Unmute" : "Mute",
30387
- style: {
30388
- width: "24px",
30389
- height: "24px",
30390
- borderRadius: "50%",
30391
- background: v ? "#7f1d1d" : "#1f2937",
30392
- border: v ? "1.5px solid #ef4444" : "1.5px solid #4b5563",
30393
- display: "flex",
30394
- alignItems: "center",
30395
- justifyContent: "center",
30396
- cursor: "pointer",
30397
- color: v ? "#f87171" : "white",
30398
- transition: "all 0.2s ease",
30399
- boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30400
- padding: 0,
30401
- flexShrink: 0
30402
- },
30403
- children: v ? /* @__PURE__ */ _("svg", {
30404
- width: "16",
30405
- height: "16",
30406
- viewBox: "0 0 24 24",
30407
- fill: "none",
30408
- stroke: "currentColor",
30409
- strokeWidth: "2",
30410
- strokeLinecap: "round",
30411
- strokeLinejoin: "round",
30412
- children: [
30413
- /* @__PURE__ */ g("line", {
30414
- x1: "1",
30415
- y1: "1",
30416
- x2: "23",
30417
- y2: "23"
30418
- }),
30419
- /* @__PURE__ */ g("path", { d: "M9 9v3a3 3 0 005.12 2.12M15 9.34V4a3 3 0 00-5.94-.6" }),
30420
- /* @__PURE__ */ g("path", { d: "M17 16.95A7 7 0 015 12v-2m14 0v2a7 7 0 01-.11 1.23" }),
30421
- /* @__PURE__ */ g("line", {
30422
- x1: "12",
30423
- y1: "19",
30424
- x2: "12",
30425
- y2: "23"
30426
- }),
30427
- /* @__PURE__ */ g("line", {
30428
- x1: "8",
30429
- y1: "23",
30430
- x2: "16",
30431
- y2: "23"
30395
+ children: [
30396
+ f === "speaking" && /* @__PURE__ */ _("button", {
30397
+ onClick: () => {
30398
+ if (S.current) try {
30399
+ S.current.sendUserMessage?.("stop");
30400
+ } catch {}
30401
+ },
30402
+ title: "Stop agent",
30403
+ style: {
30404
+ height: "24px",
30405
+ borderRadius: "999px",
30406
+ background: "rgba(239,68,68,0.15)",
30407
+ border: "1.5px solid #ef4444",
30408
+ display: "flex",
30409
+ alignItems: "center",
30410
+ gap: "4px",
30411
+ padding: "0 8px",
30412
+ cursor: "pointer",
30413
+ color: "#f87171",
30414
+ fontSize: "11px",
30415
+ fontWeight: 600,
30416
+ transition: "all 0.2s ease",
30417
+ boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30418
+ flexShrink: 0
30419
+ },
30420
+ children: [/* @__PURE__ */ g("svg", {
30421
+ width: "10",
30422
+ height: "10",
30423
+ viewBox: "0 0 24 24",
30424
+ fill: "currentColor",
30425
+ children: /* @__PURE__ */ g("rect", {
30426
+ x: "4",
30427
+ y: "4",
30428
+ width: "16",
30429
+ height: "16",
30430
+ rx: "2"
30432
30431
  })
30433
- ]
30434
- }) : /* @__PURE__ */ g(CD, {
30435
- size: 16,
30436
- color: "currentColor"
30437
- })
30438
- }), /* @__PURE__ */ g("button", {
30439
- onClick: () => x((e) => !e),
30440
- style: {
30441
- width: "24px",
30442
- height: "24px",
30443
- borderRadius: "50%",
30444
- background: "#1f2937",
30445
- border: "1.5px solid #4b5563",
30446
- display: "flex",
30447
- alignItems: "center",
30448
- justifyContent: "center",
30449
- cursor: "pointer",
30450
- color: "white",
30451
- transition: "background 0.2s ease",
30452
- boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30453
- padding: 0,
30454
- flexShrink: 0
30455
- },
30456
- children: /* @__PURE__ */ g(jD, {
30457
- size: 16,
30458
- color: "currentColor"
30432
+ }), "Stop"]
30433
+ }),
30434
+ /* @__PURE__ */ g("button", {
30435
+ onClick: async () => {
30436
+ if (S.current) try {
30437
+ if (v) {
30438
+ oe.current = 0, await S.current.setMicMuted?.(!1), y(!1);
30439
+ try {
30440
+ S.current.sendContextualUpdate?.("The visitor has unmuted. Resume normal interaction and wait for them to speak.");
30441
+ } catch {}
30442
+ } else {
30443
+ oe.current = 0, await S.current.setMicMuted?.(!0), y(!0);
30444
+ try {
30445
+ S.current.sendContextualUpdate?.("The visitor has muted their microphone. Do NOT speak, ask if they are there, or prompt them in any way. Stay completely silent until they unmute.");
30446
+ } catch {}
30447
+ }
30448
+ } catch {}
30449
+ },
30450
+ title: v ? "Unmute" : "Mute",
30451
+ style: {
30452
+ width: "24px",
30453
+ height: "24px",
30454
+ borderRadius: "50%",
30455
+ background: v ? "#7f1d1d" : "#1f2937",
30456
+ border: v ? "1.5px solid #ef4444" : "1.5px solid #4b5563",
30457
+ display: "flex",
30458
+ alignItems: "center",
30459
+ justifyContent: "center",
30460
+ cursor: "pointer",
30461
+ color: v ? "#f87171" : "white",
30462
+ transition: "all 0.2s ease",
30463
+ boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30464
+ padding: 0,
30465
+ flexShrink: 0
30466
+ },
30467
+ children: v ? /* @__PURE__ */ _("svg", {
30468
+ width: "16",
30469
+ height: "16",
30470
+ viewBox: "0 0 24 24",
30471
+ fill: "none",
30472
+ stroke: "currentColor",
30473
+ strokeWidth: "2",
30474
+ strokeLinecap: "round",
30475
+ strokeLinejoin: "round",
30476
+ children: [
30477
+ /* @__PURE__ */ g("line", {
30478
+ x1: "1",
30479
+ y1: "1",
30480
+ x2: "23",
30481
+ y2: "23"
30482
+ }),
30483
+ /* @__PURE__ */ g("path", { d: "M9 9v3a3 3 0 005.12 2.12M15 9.34V4a3 3 0 00-5.94-.6" }),
30484
+ /* @__PURE__ */ g("path", { d: "M17 16.95A7 7 0 015 12v-2m14 0v2a7 7 0 01-.11 1.23" }),
30485
+ /* @__PURE__ */ g("line", {
30486
+ x1: "12",
30487
+ y1: "19",
30488
+ x2: "12",
30489
+ y2: "23"
30490
+ }),
30491
+ /* @__PURE__ */ g("line", {
30492
+ x1: "8",
30493
+ y1: "23",
30494
+ x2: "16",
30495
+ y2: "23"
30496
+ })
30497
+ ]
30498
+ }) : /* @__PURE__ */ g(CD, {
30499
+ size: 16,
30500
+ color: "currentColor"
30501
+ })
30502
+ }),
30503
+ /* @__PURE__ */ g("button", {
30504
+ onClick: () => x((e) => !e),
30505
+ style: {
30506
+ width: "24px",
30507
+ height: "24px",
30508
+ borderRadius: "50%",
30509
+ background: "#1f2937",
30510
+ border: "1.5px solid #4b5563",
30511
+ display: "flex",
30512
+ alignItems: "center",
30513
+ justifyContent: "center",
30514
+ cursor: "pointer",
30515
+ color: "white",
30516
+ transition: "background 0.2s ease",
30517
+ boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30518
+ padding: 0,
30519
+ flexShrink: 0
30520
+ },
30521
+ children: /* @__PURE__ */ g(jD, {
30522
+ size: 16,
30523
+ color: "currentColor"
30524
+ })
30459
30525
  })
30460
- })]
30526
+ ]
30461
30527
  }),
30462
30528
  b && /* @__PURE__ */ _("div", {
30463
30529
  style: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowengage/react-chatbot",
3
- "version": "6.0.18",
3
+ "version": "6.0.19",
4
4
  "description": "Embeddable AI chat widget for React — powered by FlowEngage. Drop it in with a single siteId.",
5
5
  "keywords": [
6
6
  "chatbot",