@flowengage/react-chatbot 7.0.0 → 7.0.2

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.
@@ -29340,8 +29340,8 @@ function bk() {
29340
29340
  });
29341
29341
  }
29342
29342
  function xk() {
29343
- let e = document.querySelector("main, [role='main'], article") || document.body;
29344
- return Array.from(e.querySelectorAll("h1, h2, h3")).filter((e) => !e.closest("#flowengage-root, .flowengage-shell, .flowengage-widget-root")).map((e) => e.textContent.replace(/\s+/g, " ").trim()).filter((e) => e.length > 2 && e.length < 200).slice(0, 12);
29343
+ let e = (e) => Array.from(e).filter((e) => !e.closest("#flowengage-root, .flowengage-shell, .flowengage-widget-root")).map((e) => e.textContent.replace(/\s+/g, " ").trim()).filter((e) => e.length > 2 && e.length < 200), t = e((document.querySelector("main, [role='main']") || document.body).querySelectorAll("h1, h2, h3"));
29344
+ return t.length || (t = e(document.body.querySelectorAll("h1, h2, h3"))), t.length || (t = e(document.body.querySelectorAll("h4, h5"))), [...new Set(t)].slice(0, 15);
29345
29345
  }
29346
29346
  function Sk(e) {
29347
29347
  let t = e.siteId || null, n = (e.apiBaseUrl || "").replace(/\/$/, ""), r = typeof e.getLastUserVoiceText == "function" ? e.getLastUserVoiceText : null, i = [], a = {
@@ -29401,13 +29401,13 @@ function Sk(e) {
29401
29401
  for (; Date.now() < t && !(typeof window < "u" && window.location.pathname === e);) await new Promise((e) => setTimeout(e, 80));
29402
29402
  let n = typeof window < "u" ? window.location.pathname : e, r = typeof window < "u" ? window.location.href : a, i = n === e, o = (n.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()) || "Home";
29403
29403
  $("fwh-navigate-mvp → SPA nav complete. target:", e, "actual:", n);
29404
- let s = [], c = Date.now() + 8e3;
29405
- for (; Date.now() < c && (await new Promise((e) => setTimeout(e, 250)), s = xk(), !(s.length >= 1)););
29404
+ let s = [], c = Date.now() + 12e3;
29405
+ for (; Date.now() < c && (await new Promise((e) => setTimeout(e, 300)), s = xk(), !(s.length >= 1)););
29406
29406
  bk(), $("fwh-navigate-mvp → page headings collected:", s);
29407
- let l = s.length ? s.join(" | ") : "none", u = s.length ? "Use ONLY these exact heading strings for fwh-highlight-mvp." : "No headings were collected from the live DOM use your knowledge base heading strings for this page to call fwh-highlight-mvp. Follow RULE 1: call each highlight BEFORE describing its section (transition → highlight → content).";
29408
- return i ? (wr(), `OK_NAVIGATE_SPA. Visitor is now on: ${r} (page: "${o}") | Section headings: ${l}. ${u} MANDATORY: call fwh-highlight-mvp for EVERY section before describing it never give a plain summary. Do NOT say "I have navigated you" or "I've taken you to" — start the highlighted walkthrough immediately.`) : (wr(), `OK_NAVIGATE_SPA. CURRENT PAGE IS: ${r} (page: "${o}") | Section headings: ${l}. ${u} MANDATORY: call fwh-highlight-mvp for EVERY section before describing it never give a plain summary. Describe THIS page only do not mention the page you tried to navigate to.`);
29407
+ let l = s.length ? s.join(" | ") : "none", u = s.length ? "Use ONLY these exact heading strings for fwh-highlight-mvp — never invent or abbreviate." : "No headings collected yet — call fwh-get-current-page-mvp immediately (no speech) to get the live headings before speaking or highlighting.";
29408
+ return i ? (wr(), `OK_NAVIGATE_SPA. Visitor is now on: ${r} (page: "${o}") | Section headings: ${l}. ${u} Speak 2-3 sentences about this page from your knowledge. Then ask: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP wait for their reply. Do NOT auto-highlight any sections.`) : (wr(), `OK_NAVIGATE_SPA. CURRENT PAGE IS: ${r} (page: "${o}") | Section headings: ${l}. ${u} Speak 2-3 sentences about this page from your knowledge. Then ask: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOPwait for their reply. Do NOT auto-highlight any sections.`);
29409
29409
  } catch {}
29410
- return "OK_NAVIGATE_RELOADING. Navigating to the page now; the voice session will resume automatically on the new page. When the session resumes, immediately introduce the new page and continue guiding the visitor do not wait for the user to speak first.";
29410
+ return "OK_NAVIGATE_RELOADING. Navigating to the page now; the voice session will resume automatically on the new page. When the session resumes, speak 2-3 sentences about the page, then ask: \"Would you like to know about a specific section, or should I give you a complete overview?\" Wait for the visitor's reply.";
29411
29411
  } catch (e) {
29412
29412
  let t = `Navigation error: ${e?.message || String(e)}`;
29413
29413
  return $("fwh-navigate-mvp ✖", t), CO("Navigation failed", {
@@ -29463,6 +29463,38 @@ function Sk(e) {
29463
29463
  return $("fwh-read-content-mvp ✖", e.message), `Could not read page content: ${e.message}`;
29464
29464
  }
29465
29465
  },
29466
+ flowengage_search: async (e) => {
29467
+ $("flowengage_search ▶", e);
29468
+ let r = mk(e), i = pickSearchQuery(r);
29469
+ if ($("flowengage_search · query:", i, "siteId:", t, "apiBase:", n || "(empty)"), !i) return $("flowengage_search ✖ missing query"), "Missing query parameter.";
29470
+ if (!t) return $("flowengage_search ✖ no siteId"), "Site is not configured for search.";
29471
+ if (!n) return $("flowengage_search ✖ no api base"), "API base URL is missing; cannot search.";
29472
+ CO(`Searching${i ? ` for "${i}"` : ""}…`, { spinner: !0 });
29473
+ try {
29474
+ let e = `${n}/api/site-tools/search`;
29475
+ $("flowengage_search → POST", e);
29476
+ let r = await fetch(e, {
29477
+ method: "POST",
29478
+ headers: { "Content-Type": "application/json" },
29479
+ body: JSON.stringify({
29480
+ siteId: t,
29481
+ query: i,
29482
+ currentUrl: typeof window < "u" ? window.location.href : ""
29483
+ })
29484
+ }), a = await r.json();
29485
+ if ($("flowengage_search · HTTP", r.status, "success:", a.success), !a.success) {
29486
+ let e = a.error || "Search failed.";
29487
+ return $("flowengage_search ✖", e), e;
29488
+ }
29489
+ let o = a.results || [];
29490
+ return $("flowengage_search ✓", `${o.length} result(s)`, o.slice(0, 3).map((e) => e?.url || e)), o.length ? `SEARCH_RESULTS: ${JSON.stringify(o)}. MANDATORY: Do NOT call fwh-navigate-mvp now. Speak the answer from these results in 2-3 sentences. Then ask the visitor if they want to go to a relevant page — e.g. "Would you like me to take you to that page?" Only navigate if they say yes. NAVIGATION RULE: When navigating to a specific article, case study, blog post, or detail page — always use the most specific URL from the results (e.g. /case-study/cgs-detail), never the generic listing page (e.g. /case-study). If multiple URLs are in the results, pick the one whose path most closely matches the topic.` : "SEARCH_RESULTS: No results found. Answer from your knowledge base.";
29491
+ } catch (e) {
29492
+ let t = `Search error: ${e.message || "network"}`;
29493
+ return $("flowengage_search ✖", t), t;
29494
+ } finally {
29495
+ wO(600);
29496
+ }
29497
+ },
29466
29498
  "fwh-page-content-mvp": async (e) => {
29467
29499
  $("fwh-page-content-mvp ▶", e);
29468
29500
  let r = mk(e), i = r?.url || r?.page_url || "";
@@ -29522,12 +29554,12 @@ function Sk(e) {
29522
29554
  "fwh-end-session-mvp": async () => ($("fwh-end-session-mvp ▶"), typeof e.requestEndSession == "function" && e.requestEndSession(), "Voice session is ending."),
29523
29555
  "fwh-get-current-page-mvp": async () => {
29524
29556
  if ($("fwh-get-current-page-mvp ▶"), typeof window > "u") return "Cannot determine current page (no browser context).";
29525
- let e = window.location.href, t = window.location.pathname, n = document.title || "", r = xk(), i = r.length ? r.join(" | ") : "none";
29557
+ let e = window.location.href, t = window.location.pathname, n = document.title || "", r = xk();
29526
29558
  return $("fwh-get-current-page-mvp ✓", {
29527
29559
  url: e,
29528
29560
  path: t,
29529
29561
  title: n
29530
- }), $("fwh-get-current-page-mvp → page headings collected:", r), `CURRENT_PAGE. URL: ${e} | Path: ${t} | Title: ${n} | Section headings: ${i}. Use ONLY these exact heading strings for fwh-highlight-mvp never invent or abbreviate section names.`;
29562
+ }), $("fwh-get-current-page-mvp → page headings collected:", r), r.length ? `CURRENT_PAGE. URL: ${e} | Title: ${n} | Headings in order: ${r.map((e, t) => `${t + 1}. "${e}"`).join(", ")}. *** DO NOT call this tool again — you now have everything you need. If the visitor requested a walkthrough: START IT NOW. Use the pattern: "[transition]." + fwh-highlight-mvp("exact heading") + "[description]." for EVERY section above. If no walkthrough was requested: give 1-2 sentences about the page and stop. ***` : `CURRENT_PAGE. URL: ${e} | Title: ${n} | No headings found on this page. Describe the page from your knowledge without calling this tool again.`;
29531
29563
  },
29532
29564
  "fwh-list-forms-mvp": async () => {
29533
29565
  let e = XO(), t = ZO();
@@ -29732,7 +29764,7 @@ function kk({ title: e }) {
29732
29764
  }
29733
29765
  function Ak(e, t) {
29734
29766
  let n = (t || "").trim();
29735
- 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;
29767
+ 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) || e === "bot" && (/\b(that'?s all|we'?re done)\b/i.test(n) || /\b(goodbye|bye)\b/i.test(n) || /\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))) : !1;
29736
29768
  }
29737
29769
  function jk({ orbColors: e, ...t }) {
29738
29770
  return /* @__PURE__ */ g(lO, {
@@ -30147,14 +30179,14 @@ function Pk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30147
30179
  }, x = (m.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()), S = "";
30148
30180
  h && h.includes("|") && (S = h.split("|").map((e) => e.trim()).filter(Boolean).reduce((e, t) => e.length <= t.length ? e : t));
30149
30181
  let T = S || x || "this page";
30150
- if (_) if (p) y.overrides = { agent: { firstMessage: `I've navigated you to the ${T} page. Let me walk you through what's here.` } }, console.log(`[FlowEngage] 🔄 Agent-nav resume: firstMessage set for "${T}" (${m})`);
30182
+ if (_) if (p) y.overrides = { agent: { firstMessage: `Here we are — I've taken you to the ${T} page.` } }, console.log(`[FlowEngage] 🔄 Agent-nav resume: firstMessage set for "${T}" (${m})`);
30151
30183
  else if (u) y.overrides = { agent: { firstMessage: "I'm still here. Go ahead!" } };
30152
30184
  else {
30153
30185
  let e = f || "";
30154
30186
  y.overrides = { agent: { firstMessage: g ? e ? `Hi, welcome to ${e}!` : "Hi, welcome!" : `Welcome to the ${T} page!` } }, g || console.log(`[FlowEngage] 🏠 Page-context override: "${T}" for ${m}`);
30155
30187
  }
30156
30188
  else u && (y.overrides = { agent: { firstMessage: "" } });
30157
- let oe = !1, me = p ? `NAVIGATION RESUME — Your intro has been spoken. NOW without waiting for the visitor to say anything call fwh-highlight-mvp for the first content section on this page, then speak one sentence about it. Continue with the top 3 sections only (highlight + one sentence each). Prior conversation context:\n${(i ? je(i) : null)?.transcript || ""}\n\n` : null, he = !1, ge = !p && !u ? "AUTO-START — Your greeting has been spoken. NOW — without waiting for the visitor to say anything call fwh-get-current-page-mvp, then immediately highlight the top 3 sections and give a one-sentence summary for each. Keep it brisk no filler, no questions until the walkthrough is done." : null, _e = await vD.startSession({
30189
+ let oe = !1, me = p ? "NAVIGATION COMPLETE — Your brief intro has been spoken. Now speak 2-3 sentences about this page from your knowledge. Then ask the visitor exactly this: \"Would you like to know about a specific section, or should I give you a complete overview?\" Then STOP wait for their reply. Do NOT auto-highlight or auto-walkthrough." : null, he = !1, ge = !p && !u ? "Your greeting has been spoken. Wait for the visitor to ask a question or tell you what they need. Do NOT auto-start a walkthrough or highlight any sectionslet the visitor lead." : null, _e = await vD.startSession({
30158
30190
  ...y,
30159
30191
  onConnect: ({ conversationId: e }) => {
30160
30192
  ie.current = e, ae.current = Date.now(), console.log("[FlowEngage] 🎙️ AI chat session connected:", e);
@@ -30173,7 +30205,7 @@ function Pk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30173
30205
  if (me && !oe) {
30174
30206
  oe = !0;
30175
30207
  try {
30176
- C.current?.sendUserMessage?.("continue with the tour");
30208
+ C.current?.sendContextualUpdate?.(me);
30177
30209
  } catch {}
30178
30210
  }
30179
30211
  if (ge && !he) {
@@ -30183,11 +30215,7 @@ function Pk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30183
30215
  } catch {}
30184
30216
  }
30185
30217
  de.current && clearTimeout(de.current), de.current = setTimeout(() => {
30186
- e || ce.current !== "speaking" && (fe.current || (de.current = null, ce.current = "listening", v("listening"), le.current && !te.current && (ue.current && clearTimeout(ue.current), ue.current = setTimeout(() => {
30187
- if (!e && ce.current === "listening" && !te.current) try {
30188
- C.current?.sendContextualUpdate?.("The visitor has been silent for a while. Ask one short, natural question to re-engage — for example: 'Is there anything specific you'd like to know more about?' or 'What else can I help you with today?' Keep it to one sentence.");
30189
- } catch {}
30190
- }, 4e3))));
30218
+ e || ce.current !== "speaking" && (fe.current || (de.current = null, ce.current = "listening", v("listening")));
30191
30219
  }, 1200);
30192
30220
  }
30193
30221
  },
@@ -30204,7 +30232,7 @@ function Pk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30204
30232
  e && Ae(i, e);
30205
30233
  } catch {}
30206
30234
  if (Ak(n, r)) {
30207
- pe("minimized");
30235
+ se.current = !0;
30208
30236
  return;
30209
30237
  }
30210
30238
  if (te.current && n === "bot" && /are you still there|still there\??|hello\?|anyone there|checking in|you there|are you available|is anyone|did you step away/i.test(r)) if (D.current += 1, D.current === 2) try {
@@ -30253,8 +30281,13 @@ function Pk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30253
30281
  try {
30254
30282
  r = await t["fwh-list-forms-mvp"]();
30255
30283
  } catch {}
30256
- let a = u && !p ? `RESUMING PRIOR SESSION — DO NOT GREET. The visitor is continuing the same conversation after a page reload. Do not introduce yourself or re-state your capabilities. Wait silently until the visitor speaks; if you must speak first, briefly acknowledge where you left off in one short sentence.\nPrior transcript:\n${n?.transcript || ""}\n\n` : "";
30257
- _e.sendContextualUpdate(`${a}Page: ${e}. SiteId: ${i || "unknown"}. Forms: ${r}. Voice: call end_voice_session or say you are ending the session to stop.`);
30284
+ let a = "none";
30285
+ if (typeof window < "u" && typeof document < "u") try {
30286
+ let e = "#flowengage-root, .flowengage-shell, .flowengage-widget-root", t = document.querySelector("main, [role='main']") || document.body, n = Array.from(t.querySelectorAll("h1, h2, h3")).filter((t) => !t.closest(e)).map((e) => e.textContent.replace(/\s+/g, " ").trim()).filter((e) => e.length > 2 && e.length < 200);
30287
+ n.length || (n = Array.from(document.body.querySelectorAll("h1, h2, h3")).filter((t) => !t.closest(e)).map((e) => e.textContent.replace(/\s+/g, " ").trim()).filter((e) => e.length > 2 && e.length < 200)), n.length && (a = [...new Set(n)].slice(0, 15).join(" | "));
30288
+ } catch {}
30289
+ let o = u && !p ? `RESUMING PRIOR SESSION — DO NOT GREET. The visitor is continuing the same conversation after a page reload. Do not introduce yourself or re-state your capabilities. Wait silently until the visitor speaks; if you must speak first, briefly acknowledge where you left off in one short sentence.\nPrior transcript:\n${n?.transcript || ""}\n\n` : "";
30290
+ _e.sendContextualUpdate(`${o}CURRENT PAGE: ${e} | Section headings: ${a}. SiteId: ${i || "unknown"}. Forms: ${r}. The visitor is ALREADY on this page — do NOT offer to navigate there. Voice: call end_voice_session or say you are ending the session to stop.`);
30258
30291
  } catch {}
30259
30292
  if (typeof window < "u") {
30260
30293
  let t = window.location.pathname, n = () => {
@@ -31499,6 +31532,10 @@ function Rk() {
31499
31532
  return;
31500
31533
  }
31501
31534
  if (i) {
31535
+ if ((typeof performance < "u" ? performance.getEntriesByType?.("navigation")?.[0]?.type ?? "navigate" : "navigate") === "reload") {
31536
+ ot("minimized_orb");
31537
+ return;
31538
+ }
31502
31539
  ce?.({ notifyChatInitiated: !0 }), ue?.(!0), ot("voice_mode");
31503
31540
  return;
31504
31541
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowengage/react-chatbot",
3
- "version": "7.0.0",
3
+ "version": "7.0.2",
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",