@flowengage/react-chatbot 1.0.7 → 1.0.8

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.
@@ -2715,44 +2715,21 @@ function vn({ siteId: e, config: t, children: n, language: r = "en" }) {
2715
2715
  Fe(e), e && (ct.current = !1);
2716
2716
  }
2717
2717
  }, At = async (e) => {
2718
- if (console.log("[FlowEngage:voice-sync] onMessageSync called", {
2719
- hasSynced: ct.current,
2720
- messageCount: e?.length ?? 0,
2721
- hasChatId: !!v,
2722
- hasApi: !!w.current
2723
- }), ct.current) {
2724
- console.warn("[FlowEngage:voice-sync] SKIPPED — hasSyncedRef is already true (duplicate call)");
2725
- return;
2726
- }
2727
- if (ct.current = !0, !w.current || !v || !e?.length) {
2728
- console.warn("[FlowEngage:voice-sync] SKIPPED — missing data:", {
2729
- api: !!w.current,
2730
- chatId: v || "(empty)",
2731
- messages: e?.length ?? 0
2732
- }), Fe(!1);
2733
- return;
2734
- }
2735
- console.log("[FlowEngage:voice-sync] Syncing", e.length, "messages for chatId:", v);
2736
- try {
2737
- let t = await w.current.syncVoice(v, e);
2738
- if (console.log("[FlowEngage:voice-sync] syncVoice response:", {
2739
- success: t?.success,
2740
- count: t?.count,
2741
- chatHistoryLength: t?.chat_history?.length ?? 0
2742
- }), t?.chat_history?.length) b(pn(t.chat_history)), console.log("[FlowEngage:voice-sync] ✓ setChatHistory with", t.chat_history.length, "messages");
2743
- else if (t?.success) {
2744
- console.log("[FlowEngage:voice-sync] No chat_history in response, falling back to loadHistory");
2745
- try {
2718
+ if (!ct.current) {
2719
+ if (ct.current = !0, !w.current || !v || !e?.length) {
2720
+ Fe(!1);
2721
+ return;
2722
+ }
2723
+ try {
2724
+ let t = await w.current.syncVoice(v, e);
2725
+ if (t?.chat_history?.length) b(pn(t.chat_history));
2726
+ else if (t?.success) try {
2746
2727
  let e = await w.current.loadHistory(v, r);
2747
- console.log("[FlowEngage:voice-sync] loadHistory response:", { chatHistoryLength: e?.chat_history?.length ?? 0 }), e?.chat_history?.length && (b(pn(e.chat_history)), console.log("[FlowEngage:voice-sync] ✓ setChatHistory via loadHistory fallback"));
2748
- } catch (e) {
2749
- console.error("[FlowEngage:voice-sync] loadHistory fallback failed:", e);
2750
- }
2751
- } else console.warn("[FlowEngage:voice-sync] syncVoice returned no success and no chat_history:", t);
2752
- } catch (e) {
2753
- console.error("[FlowEngage:voice-sync] ✖ syncVoice API failed:", e);
2754
- } finally {
2755
- console.log("[FlowEngage:voice-sync] Setting isVoiceMode → false"), Fe(!1);
2728
+ e?.chat_history?.length && b(pn(e.chat_history));
2729
+ } catch {}
2730
+ } catch {} finally {
2731
+ Fe(!1);
2732
+ }
2756
2733
  }
2757
2734
  }, E = async () => {
2758
2735
  if (!(!w.current || !v)) {
@@ -22549,6 +22526,30 @@ function Og(e) {
22549
22526
  })) : [];
22550
22527
  }
22551
22528
  function kg(e) {
22529
+ if (!e || typeof e != "string") return e;
22530
+ let t = e.trim();
22531
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t) ? t : (t = t.replace(/\s+at\s+the\s+rate\s*(of)?\s+/gi, "@"), t = t.replace(/\s+at\s+/gi, "@"), t = t.replace(/\s+dot\s+/gi, "."), t = t.replace(/\s+/g, ""), t = t.replace(/\.{2,}/g, ".").replace(/\.$/, ""), t);
22532
+ }
22533
+ function Ag(e) {
22534
+ if (!e || typeof e != "string") return e;
22535
+ let t = {
22536
+ zero: "0",
22537
+ one: "1",
22538
+ two: "2",
22539
+ three: "3",
22540
+ four: "4",
22541
+ five: "5",
22542
+ six: "6",
22543
+ seven: "7",
22544
+ eight: "8",
22545
+ nine: "9",
22546
+ oh: "0",
22547
+ o: "0"
22548
+ }, n = e.toLowerCase().trim();
22549
+ for (let [e, r] of Object.entries(t)) n = n.replace(RegExp(`\\b${e}\\b`, "g"), r);
22550
+ return n = n.replace(/[^\d+]/g, ""), n;
22551
+ }
22552
+ function jg(e) {
22552
22553
  if (!e || typeof e != "string") return [];
22553
22554
  let t = e.trim();
22554
22555
  if (!t || /\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i.test(t)) return [];
@@ -22567,7 +22568,7 @@ function kg(e) {
22567
22568
  }
22568
22569
  return [];
22569
22570
  }
22570
- function Ag(e) {
22571
+ function Mg(e) {
22571
22572
  if (!e || typeof e != "string") return [];
22572
22573
  let t = e.trim();
22573
22574
  if (!t) return [];
@@ -22579,15 +22580,19 @@ function Ag(e) {
22579
22580
  field_key: e,
22580
22581
  value: i
22581
22582
  }));
22582
- }, o = t.match(/^\s*([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\s*$/i);
22583
- if (o) return a("Email Address", o[1]), n;
22584
- let s = t.match(/\b(?:please\s+)?(?:enter|type|put)\s+(.+?)\s+in(?:to)?\s+(?:the\s+)?(?:full\s*name|full\s*name\s*field|name\s*field)\b/i);
22585
- if (s && a("Full Name", s[1]), s = t.match(/\bfull\s*name,?\s*(?:please\s+)?(?:enter|type|put)\s+(.+?)(?:\.|$|!|\?)/i), s && a("Full Name", s[1]), s = t.match(/\bfull\s*name\s*(?:is|:|please\s+enter|-)\s*(.+?)(?:\.|$|(?=\s+(?:and|my\s+email|email|message))\b)/i), s && a("Full Name", s[1]), s = t.match(/\b(.+?)\s+for\s+(?:the\s+)?full\s*name\b/i), s) {
22586
- let e = s[1].trim();
22583
+ }, o = kg(t), s = i.test(o), c = o.match(/^\s*([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\s*$/i);
22584
+ if (c) return a("Email Address", c[1]), n;
22585
+ if (!i.test(t) && s) {
22586
+ let e = o.match(i);
22587
+ if (e) return a("Email Address", e[1]), n;
22588
+ }
22589
+ let l = t.match(/\b(?:please\s+)?(?:enter|type|put)\s+(.+?)\s+in(?:to)?\s+(?:the\s+)?(?:full\s*name|full\s*name\s*field|name\s*field)\b/i);
22590
+ if (l && a("Full Name", l[1]), l = t.match(/\bfull\s*name,?\s*(?:please\s+)?(?:enter|type|put)\s+(.+?)(?:\.|$|!|\?)/i), l && a("Full Name", l[1]), l = t.match(/\bfull\s*name\s*(?:is|:|please\s+enter|-)\s*(.+?)(?:\.|$|(?=\s+(?:and|my\s+email|email|message))\b)/i), l && a("Full Name", l[1]), l = t.match(/\b(.+?)\s+for\s+(?:the\s+)?full\s*name\b/i), l) {
22591
+ let e = l[1].trim();
22587
22592
  e.length > 1 && e.length < 120 && !/@/.test(e) && a("Full Name", e);
22588
22593
  }
22589
- if (s = t.match(/\b(?:email|e-mail)(?:\s*address)?\s*(?:is|:|please\s+use|enter|-)\s*([^\s@]+@[^\s@]+\.[^\s,]+)/i), s && a("Email Address", s[1]), s = t.match(/\b(?:enter|type|put)\s+([^\s@]+@[^\s@]+\.[^\s,]+)\s+in(?:to)?\s+(?:the\s+)?(?:email|e-mail)/i), s && a("Email Address", s[1]), s = t.match(/\b(?:message|comment)\s*(?:is|:|please\s+enter|-)\s*(.+)$/is), s) {
22590
- let e = s[1].trim();
22594
+ if (l = t.match(/\b(?:email|e-mail)(?:\s*address)?\s*(?:is|:|please\s+use|enter|-)\s*([^\s@]+@[^\s@]+\.[^\s,]+)/i), l && a("Email Address", l[1]), l = t.match(/\b(?:enter|type|put)\s+([^\s@]+@[^\s@]+\.[^\s,]+)\s+in(?:to)?\s+(?:the\s+)?(?:email|e-mail)/i), l && a("Email Address", l[1]), l = t.match(/\b(?:message|comment)\s*(?:is|:|please\s+enter|-)\s*(.+)$/is), l) {
22595
+ let e = l[1].trim();
22591
22596
  e.length > 0 && a("Message", e);
22592
22597
  }
22593
22598
  if (!n.some((e) => /email/i.test(String(e.field_key)))) {
@@ -22603,17 +22608,17 @@ function Ag(e) {
22603
22608
  }
22604
22609
  return n;
22605
22610
  }
22606
- function jg(e) {
22611
+ function Ng(e) {
22607
22612
  if (!e || typeof e != "object") return null;
22608
22613
  let t = e.url ?? e.target_url ?? e.page_url ?? e.pageUrl ?? e.link ?? e.href ?? e.path;
22609
22614
  return t == null ? null : String(t).trim() || null;
22610
22615
  }
22611
- function Mg(e) {
22616
+ function Pg(e) {
22612
22617
  if (!e || typeof e != "object") return null;
22613
22618
  let t = e.query ?? e.q ?? e.search ?? e.text ?? e.keywords;
22614
22619
  return t == null ? null : String(t).trim() || null;
22615
22620
  }
22616
- function Ng(e) {
22621
+ function Fg(e) {
22617
22622
  let t = e.ownerDocument?.defaultView || window, n = e.tagName === "TEXTAREA" ? t.HTMLTextAreaElement.prototype : t.HTMLInputElement.prototype, r = Object.getOwnPropertyDescriptor(n, "value");
22618
22623
  return (e, t) => {
22619
22624
  try {
@@ -22622,7 +22627,7 @@ function Ng(e) {
22622
22627
  r?.set ? r.set.call(e, t) : e.value = t;
22623
22628
  };
22624
22629
  }
22625
- async function Pg(e, t, n) {
22630
+ async function Ig(e, t, n) {
22626
22631
  if (!n?.skipScroll) try {
22627
22632
  e.scrollIntoView({
22628
22633
  behavior: "smooth",
@@ -22661,7 +22666,7 @@ async function Pg(e, t, n) {
22661
22666
  "on"
22662
22667
  ].includes(String(t).toLowerCase().trim()), e.dispatchEvent(new Event("input", a)), e.dispatchEvent(new Event("change", a)), Gh(e), !0;
22663
22668
  let o = String(t);
22664
- r === "INPUT" || r === "TEXTAREA" ? await eg(e, o, Ng(e)) : (e.value = o, e.dispatchEvent(new Event("input", a)), e.dispatchEvent(new Event("change", a))), e.dispatchEvent(new Event("change", a)), e.dispatchEvent(new Event("blur", a));
22669
+ r === "INPUT" || r === "TEXTAREA" ? await eg(e, o, Fg(e)) : (e.value = o, e.dispatchEvent(new Event("input", a)), e.dispatchEvent(new Event("change", a))), e.dispatchEvent(new Event("change", a)), e.dispatchEvent(new Event("blur", a));
22665
22670
  try {
22666
22671
  e.focus({ preventScroll: !0 });
22667
22672
  } catch {}
@@ -22677,11 +22682,11 @@ async function Pg(e, t, n) {
22677
22682
  } catch {}
22678
22683
  return !0;
22679
22684
  }
22680
- function Fg(e) {
22685
+ function Lg(e) {
22681
22686
  let t = e.siteId || null, n = (e.apiBaseUrl || "").replace(/\/$/, ""), r = typeof e.getLastUserVoiceText == "function" ? e.getLastUserVoiceText : null, i = [], a = {
22682
22687
  navigate_to_page: async (n) => {
22683
22688
  $("navigate_to_page ▶ raw parameters:", n);
22684
- let r = Dg(n), i = jg(r), a = r.section_text ?? r.sectionText ?? r.section;
22689
+ let r = Dg(n), i = Ng(r), a = r.section_text ?? r.sectionText ?? r.section;
22685
22690
  if ($("navigate_to_page · coerced:", {
22686
22691
  url: i,
22687
22692
  sectionText: a
@@ -22705,8 +22710,16 @@ function Fg(e) {
22705
22710
  found: !!e
22706
22711
  });
22707
22712
  }
22708
- let e = `OK_NAVIGATION ${i}`;
22709
- return $("navigate_to_page ✓", e), e;
22713
+ let e = "";
22714
+ try {
22715
+ let t = lg(), n = ug();
22716
+ if (t.length > 0) {
22717
+ let r = t.map((e) => e.label || e.placeholder || e.name || e.id).filter(Boolean).join(", "), i = n.map((e) => e.text).filter(Boolean).join(", ");
22718
+ e = ` This page has a form with fields: [${r}]` + (i ? ` and buttons: [${i}].` : ".") + " Call list_page_forms then start filling.";
22719
+ }
22720
+ } catch {}
22721
+ let t = `OK_NAVIGATION ${i}${e}`;
22722
+ return $("navigate_to_page ✓", t), t;
22710
22723
  } catch (e) {
22711
22724
  Hh(), Lh(200);
22712
22725
  let t = `Navigation error: ${e?.message || String(e)}`;
@@ -22720,7 +22733,7 @@ function Fg(e) {
22720
22733
  },
22721
22734
  search_site_content: async (e) => {
22722
22735
  $("search_site_content ▶", e);
22723
- let r = Mg(Dg(e));
22736
+ let r = Pg(Dg(e));
22724
22737
  if ($("search_site_content · query:", r, "siteId:", t, "apiBase:", n || "(empty)"), Ih("Searching site content…", { spinner: !0 }), !r) return Lh(), $("search_site_content ✖ missing query"), "Missing query parameter.";
22725
22738
  if (!t) return Lh(), $("search_site_content ✖ no siteId"), "Site is not configured for search.";
22726
22739
  if (!n) return Lh(), $("search_site_content ✖ no api base"), "API base URL is missing; cannot search.";
@@ -22766,8 +22779,8 @@ function Fg(e) {
22766
22779
  $("fill_form_fields ▶ raw:", e);
22767
22780
  let t = Og(e);
22768
22781
  if (!t.length && r) {
22769
- let e = r(), n = kg(e);
22770
- n.length ? $("fill_form_fields · inferred URL from last user utterance (model omitted usable fields):", n) : (n = Ag(e), n.length && $("fill_form_fields · inferred contact fields from last user utterance (empty tool params):", n)), n.length && (t = n);
22782
+ let e = r(), n = jg(e);
22783
+ n.length ? $("fill_form_fields · inferred URL from last user utterance (model omitted usable fields):", n) : (n = Mg(e), n.length && $("fill_form_fields · inferred contact fields from last user utterance (empty tool params):", n)), n.length && (t = n);
22771
22784
  }
22772
22785
  if ($("fill_form_fields · normalized fields:", t), !t.length) return "No fields provided. Call list_page_forms for field_key strings, then fill_form_fields with { \"fields\": [ { \"field_key\": \"<label or placeholder from list>\", \"value\": \"<user value>\" } ] }. Never use empty {}. Pass the value the user just said (email, message, name, URL) in fields.";
22773
22786
  t.length > 1 && Ih(`Filling ${t.length} fields…`);
@@ -22775,17 +22788,18 @@ function Fg(e) {
22775
22788
  for (let e of t) {
22776
22789
  let t = e?.field_key ?? e?.fieldKey, r = e?.value;
22777
22790
  if (t == null || r == null) continue;
22778
- Ih(`Filling ${t}…`), $("fill_form_fields · processing field:", t, "=", r);
22779
- let a = cg();
22780
- $("fill_form_fields · visible inputs count:", a.length);
22781
- let o = xg(a, String(t), r);
22782
- if (o.length) {
22783
- for (let e = 0; e < o.length; e++) await Pg(o[e], r, { skipScroll: e > 0 }), await new Promise((e) => setTimeout(e, 80));
22784
- i = o, n.push(String(t));
22791
+ let a = String(t).toLowerCase();
22792
+ /email|e-mail|mail/.test(a) ? r = kg(r) : /phone|mobile|tel|cell/.test(a) && (r = Ag(r)), Ih(`Filling ${t}…`), $("fill_form_fields · processing field:", t, "=", r);
22793
+ let o = cg();
22794
+ $("fill_form_fields · visible inputs count:", o.length);
22795
+ let s = xg(o, String(t), r);
22796
+ if (s.length) {
22797
+ for (let e = 0; e < s.length; e++) await Ig(s[e], r, { skipScroll: e > 0 }), await new Promise((e) => setTimeout(e, 80));
22798
+ i = s, n.push(String(t));
22785
22799
  continue;
22786
22800
  }
22787
- let s = wg(a, String(t));
22788
- s ||= hg(a, String(t)), s ||= gg(a, String(t), r), s ? (await Pg(s, r), i = [s], n.push(String(t))) : $("fill_form_fields · no match for field:", t);
22801
+ let c = wg(o, String(t));
22802
+ c ||= hg(o, String(t)), c ||= gg(o, String(t), r), c ? (await Ig(c, r), i = [c], n.push(String(t))) : $("fill_form_fields · no match for field:", t);
22789
22803
  }
22790
22804
  Lh(400);
22791
22805
  try {
@@ -22854,7 +22868,7 @@ function Fg(e) {
22854
22868
  }
22855
22869
  //#endregion
22856
22870
  //#region src/utils/wrapVoiceToolsForLogging.js
22857
- function Ig(e) {
22871
+ function Rg(e) {
22858
22872
  return !e || typeof e != "object" ? e : Object.fromEntries(Object.entries(e).map(([e, t]) => [e, async (n) => {
22859
22873
  let r = Zt();
22860
22874
  r ? console.log("[FlowEngage:voice-tool] ▶", e, n) : console.info(`[FlowEngage] voice tool » ${e}`);
@@ -22864,28 +22878,27 @@ function Ig(e) {
22864
22878
  }
22865
22879
  //#endregion
22866
22880
  //#region src/components/VoiceInterface.jsx
22867
- var Lg = {
22881
+ var zg = {
22868
22882
  idle: "rgba(99,102,241,0.18)",
22869
22883
  listening: "rgba(16,185,129,0.25)",
22870
22884
  speaking: "rgba(245,158,11,0.25)",
22871
22885
  error: "rgba(239,68,68,0.2)"
22872
- }, Rg = {
22886
+ }, Bg = {
22873
22887
  idle: "#6366f1",
22874
22888
  listening: "#10b981",
22875
22889
  speaking: "#f59e0b",
22876
22890
  error: "#ef4444"
22877
22891
  };
22878
- function zg(e, t) {
22892
+ function Vg(e, t) {
22879
22893
  let n = (t || "").trim();
22880
22894
  return n ? !!(/\b(let'?s|let us)\s+(end|stop|finish|wrap up|close)\s+(the\s+)?(voice\s+)?(session|call|chat)\b/i.test(n) || /\bend\s+(this\s+)?(the\s+)?(voice\s+)?(session|call|chat)\b/i.test(n) || /\b(hang\s+up|disconnect)\b/i.test(n) || /\b(that'?s all|we'?re done)\b/i.test(n) || e === "bot" && (/\b(I'?ll|I will|Let me|I can|I'?m going to)\s+(end|close)\s+(the\s+)?(voice\s+)?(session|call)\b/i.test(n) || /\b(ending|closing)\s+(the\s+)?(voice\s+)?session\b|\bvoice\s+session\s+(is\s+)?(now\s+)?(ended|over|closing)\b/i.test(n) || /\b(session|call)\s+(is\s+)?(now\s+)?(ended|over)\b/i.test(n) || /\bwe\s+can\s+end\s+(the\s+)?(session|call)?\s*(here|now)\b/i.test(n) || /\b(wrapping\s+up|signing\s+off)\b/i.test(n)) || /^(goodbye|bye|that'?s all|we'?re done|hang up|disconnect)\b/i.test(n)) : !1;
22881
22895
  }
22882
- function Bg({ agentId: e, chatId: t, siteId: r, apiBaseUrl: a, onEnd: c, historyRef: d, hasSyncedRef: f, onMessageSync: p, onStartSync: m }) {
22896
+ function Hg({ agentId: e, chatId: t, siteId: r, apiBaseUrl: a, onEnd: c, historyRef: d, hasSyncedRef: f, onMessageSync: p, onStartSync: m }) {
22883
22897
  let [h, g] = s("idle"), [ee, te] = s(null), [_, ne] = s(!1), re = o(null), ie = o(null), ae = o(""), oe = o(async () => {}), se = o(!1), v = n(async () => {
22884
- console.log("[FlowEngage:voice-sync] handleEnd called — historyRef has", d.current?.length ?? 0, "messages");
22885
22898
  try {
22886
22899
  await re.current?.endSession?.();
22887
22900
  } catch {}
22888
- re.current = null, ne(!1), g("idle"), se.current = !1, typeof p == "function" ? (console.log("[FlowEngage:voice-sync] Calling onMessageSync with", d.current?.length ?? 0, "messages:", d.current), await p(d.current), console.log("[FlowEngage:voice-sync] onMessageSync completed")) : console.warn("[FlowEngage:voice-sync] onMessageSync is NOT a function — transcript will be lost!"), typeof c == "function" && c();
22901
+ re.current = null, ne(!1), g("idle"), se.current = !1, typeof p == "function" && await p(d.current), typeof c == "function" && c();
22889
22902
  }, [
22890
22903
  d,
22891
22904
  p,
@@ -22897,7 +22910,7 @@ function Bg({ agentId: e, chatId: t, siteId: r, apiBaseUrl: a, onEnd: c, history
22897
22910
  try {
22898
22911
  if (await navigator.mediaDevices.getUserMedia({ audio: !0 }), t) return;
22899
22912
  d.current = [], ae.current = "", se.current = !1;
22900
- let i = Ig(Fg({
22913
+ let i = Rg(Lg({
22901
22914
  siteId: r || null,
22902
22915
  apiBaseUrl: a || null,
22903
22916
  getLastUserVoiceText: () => ae.current,
@@ -22924,7 +22937,7 @@ function Bg({ agentId: e, chatId: t, siteId: r, apiBaseUrl: a, onEnd: c, history
22924
22937
  message: r,
22925
22938
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
22926
22939
  };
22927
- n === "user" && (ae.current = r), d.current = [...d.current, i], console.log(`[FlowEngage:voice-sync] onMessage [${n}]: "${r.slice(0, 80)}" — historyRef now has ${d.current.length} entries`), zg(n, r) && queueMicrotask(() => {
22940
+ n === "user" && (ae.current = r), d.current = [...d.current, i], Vg(n, r) && queueMicrotask(() => {
22928
22941
  se.current || (se.current = !0, oe.current?.());
22929
22942
  });
22930
22943
  },
@@ -22932,7 +22945,7 @@ function Bg({ agentId: e, chatId: t, siteId: r, apiBaseUrl: a, onEnd: c, history
22932
22945
  t || (console.error("[VoiceInterface] ElevenLabs error", e), g("error"), te("Voice session encountered an error."));
22933
22946
  },
22934
22947
  onDisconnect: () => {
22935
- t || (console.warn("[FlowEngage:voice-sync] ⚠ session DISCONNECTED — historyRef has", d.current?.length ?? 0, "messages that may NOT be synced (onDisconnect does not call onMessageSync)"), ne(!1), g("idle"));
22948
+ t || (console.log("[VoiceInterface] session disconnected"), ne(!1), g("idle"));
22936
22949
  }
22937
22950
  });
22938
22951
  if (t) {
@@ -22947,7 +22960,12 @@ function Bg({ agentId: e, chatId: t, siteId: r, apiBaseUrl: a, onEnd: c, history
22947
22960
  } catch {
22948
22961
  t = "[]";
22949
22962
  }
22950
- o.sendContextualUpdate(`Current page URL: ${e}. Site ID: ${r || "unknown"}. Page fields/buttons JSON: ${t}. Navigation: search_site_content then navigate_to_page with section_text when relevant — no permission ask. Forms: use fill_form_fields then click_page_button (e.g. Conduct Audit) when the user wants to submit. Voice: if the user wants to end the voice session, call end_voice_session or confirm and end; you may also say you are ending the voice session.`);
22963
+ let n = "";
22964
+ try {
22965
+ let e = await i.search_site_content({ query: "pages" }), t = typeof e == "string" ? JSON.parse(e) : e;
22966
+ Array.isArray(t) && t.length && (n = ` Site pages available: ${t.map((e) => `${e.title || ""} (${e.url || ""})`).join(", ")}.`);
22967
+ } catch {}
22968
+ o.sendContextualUpdate(`Current page URL: ${e}. Site ID: ${r || "unknown"}. Page fields/buttons JSON: ${t}.${n} Navigation: when the user wants to go to any page (contact, pricing, about, services, etc.), call search_site_content then navigate_to_page immediately — never ask permission. After navigating to a page with a form, call list_page_forms and proactively start helping the user fill it. Forms: use fill_form_fields then click_page_button (e.g. Conduct Audit, Send Message) when the user wants to submit. Fill each field immediately after the user answers — never skip ahead. Voice: if the user wants to end the voice session, call end_voice_session or confirm and end.`);
22951
22969
  } catch {}
22952
22970
  typeof m == "function" && m();
22953
22971
  } catch (e) {
@@ -22963,7 +22981,7 @@ function Bg({ agentId: e, chatId: t, siteId: r, apiBaseUrl: a, onEnd: c, history
22963
22981
  d,
22964
22982
  m
22965
22983
  ]);
22966
- let ce = h === "listening" || h === "speaking", le = Rg[h] || Rg.idle, ue = Lg[h] || Lg.idle;
22984
+ let ce = h === "listening" || h === "speaking", le = Bg[h] || Bg.idle, ue = zg[h] || zg.idle;
22967
22985
  return /* @__PURE__ */ u("div", {
22968
22986
  ref: ie,
22969
22987
  style: {
@@ -23069,7 +23087,7 @@ function Bg({ agentId: e, chatId: t, siteId: r, apiBaseUrl: a, onEnd: c, history
23069
23087
  }
23070
23088
  //#endregion
23071
23089
  //#region src/components/FlowEngageWidget.jsx
23072
- var Vg = [
23090
+ var Ug = [
23073
23091
  {
23074
23092
  key: "become_client",
23075
23093
  label: "Become a Client"
@@ -23090,7 +23108,7 @@ var Vg = [
23090
23108
  key: "looking_for_job",
23091
23109
  label: "Looking for a Job"
23092
23110
  }
23093
- ], Hg = () => /* @__PURE__ */ l("div", {
23111
+ ], Wg = () => /* @__PURE__ */ l("div", {
23094
23112
  style: {
23095
23113
  display: "flex",
23096
23114
  marginBottom: "12px",
@@ -23121,7 +23139,7 @@ var Vg = [
23121
23139
  } }, e)), /* @__PURE__ */ l("style", { children: "\n @keyframes fe-dot-bounce {\n 0%, 80%, 100% { transform: translateY(0); opacity: 0.5; }\n 40% { transform: translateY(-5px); opacity: 1; }\n }\n " })]
23122
23140
  })
23123
23141
  });
23124
- function Ug() {
23142
+ function Gg() {
23125
23143
  let { status: e, runtimeConfig: t, resolvedConfig: n, chatId: r, chatHistory: o, isOpen: c, activeScreen: d, isHumanHandled: f, agentName: p, agentHeadshot: m, visitorEmail: h, isAgentTyping: g, isAiTyping: ee, isLoading: te, isVoiceMode: _, isRateLimited: ne, rateLimitMessage: re, isConversationEnded: ie, incomingCall: ae, activeCallId: oe, callConnectionState: se, callConnectedAt: v, isCallMuted: ce, webRTCError: le, language: ue, historyRef: y, onMessageSync: b, endConversation: de, acceptCall: fe, rejectCall: pe, endWebRTCCall: me, toggleCallMute: he, dismissCallError: ge, captureVisitorEmail: _e, openWidget: ve, closeWidget: ye, sendMessage: be, setVoiceMode: xe, startTyping: Se, stopTyping: Ce, updateTypingDraft: we } = Xt(), [Te, Ee] = s(""), [De, Oe] = s(null), [ke, Ae] = s(null), [je, Me] = s(null), [Ne, Pe] = s(0), [x, Fe] = s(h || ""), [Ie, Le] = s("");
23126
23144
  i(() => {
23127
23145
  try {
@@ -23149,7 +23167,7 @@ function Ug() {
23149
23167
  outline: "none",
23150
23168
  fontFamily: "ui-sans-serif, system-ui, sans-serif",
23151
23169
  ...c ? {} : Ue
23152
- }, Ge = S.recommendations?.[ue] || Re.recommendations?.[ue] || Vg, Ke = S.greetings?.[ue] || Re.greetings?.[ue], qe = ze.chatButtonText || "Chat with us", Je = ze.headerName || t?.websiteName || "OpenSense Labs", C = ze.logoUrl || null, w = ze.hideWatermark || !1, T = Re.elevenLabsAgentId || t?.elevenLabsAgentId || null, Ye = t?.siteId || n?.siteId || null, Xe = t?.apiBaseUrl || "", Ze = ze.fallbackAgentName || "Agent", Qe = ze.botLabel || "AI", $e = m && String(m).trim() || t?.ownerProfileImageUrl && String(t.ownerProfileImageUrl).trim() || null, et = ae?.agentName || p || Ze, tt = o.some((e) => e.sender === "user"), nt = a(() => {
23170
+ }, Ge = S.recommendations?.[ue] || Re.recommendations?.[ue] || Ug, Ke = S.greetings?.[ue] || Re.greetings?.[ue], qe = ze.chatButtonText || "Chat with us", Je = ze.headerName || t?.websiteName || "OpenSense Labs", C = ze.logoUrl || null, w = ze.hideWatermark || !1, T = Re.elevenLabsAgentId || t?.elevenLabsAgentId || null, Ye = t?.siteId || n?.siteId || null, Xe = t?.apiBaseUrl || "", Ze = ze.fallbackAgentName || "Agent", Qe = ze.botLabel || "AI", $e = m && String(m).trim() || t?.ownerProfileImageUrl && String(t.ownerProfileImageUrl).trim() || null, et = ae?.agentName || p || Ze, tt = o.some((e) => e.sender === "user"), nt = a(() => {
23153
23171
  let e = o.findIndex((e) => e.sender === "user");
23154
23172
  return e === -1 ? !1 : o.slice(e + 1).some((e) => e.sender === "bot" || e.sender === "ai" || e.sender === "agent");
23155
23173
  }, [o]), rt = !h && tt && nt;
@@ -23277,7 +23295,7 @@ function Ug() {
23277
23295
  flexDirection: "column"
23278
23296
  },
23279
23297
  className: "fe-screen-fade-in",
23280
- children: /* @__PURE__ */ l(Bg, {
23298
+ children: /* @__PURE__ */ l(Hg, {
23281
23299
  agentId: T,
23282
23300
  chatId: r,
23283
23301
  siteId: Ye,
@@ -23310,7 +23328,7 @@ function Ug() {
23310
23328
  isAiTyping: ee,
23311
23329
  isAgentTyping: g,
23312
23330
  setReplyContext: Me,
23313
- TypingDots: Hg,
23331
+ TypingDots: Wg,
23314
23332
  primaryColor: Ve,
23315
23333
  agentHeadshot: $e,
23316
23334
  agentDisplayName: p || Ze
@@ -23389,4 +23407,4 @@ function Ug() {
23389
23407
  }) : null;
23390
23408
  }
23391
23409
  //#endregion
23392
- export { vn as FlowEngageProvider, Ug as FlowEngageWidget, Xt as useFlowEngage };
23410
+ export { vn as FlowEngageProvider, Gg as FlowEngageWidget, Xt as useFlowEngage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowengage/react-chatbot",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
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",