sagedesk 1.0.0 → 2.0.0
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.
- package/README.md +277 -35
- package/dist/next/{SageDeskWidget-P3H2VJR5.js → SageDeskWidget-R3XJ5OUY.js} +149 -25
- package/dist/next/SageDeskWidget-R3XJ5OUY.js.map +1 -0
- package/dist/next/index.cjs +164 -27
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +10 -3
- package/dist/next/index.d.ts +10 -3
- package/dist/next/index.js +10 -4
- package/dist/next/index.js.map +1 -1
- package/dist/react/index.cjs +148 -24
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +14 -5
- package/dist/react/index.d.ts +14 -5
- package/dist/react/index.js +148 -24
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +348 -0
- package/dist/server/index.cjs.map +1 -0
- package/dist/server/index.d.cts +62 -0
- package/dist/server/index.d.ts +62 -0
- package/dist/server/index.js +312 -0
- package/dist/server/index.js.map +1 -0
- package/dist/vanilla/index.cjs +6 -2
- package/dist/vanilla/index.cjs.map +1 -1
- package/dist/vanilla/index.d.cts +4 -2
- package/dist/vanilla/index.d.ts +4 -2
- package/dist/vanilla/index.js +6 -2
- package/dist/vanilla/index.js.map +1 -1
- package/package.json +10 -3
- package/dist/next/SageDeskWidget-P3H2VJR5.js.map +0 -1
package/dist/next/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { useState, useEffect, Suspense, lazy } from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
var LazyWidget = lazy(
|
|
7
|
-
() => import("./SageDeskWidget-
|
|
7
|
+
() => import("./SageDeskWidget-R3XJ5OUY.js").then((mod) => ({ default: mod.SageDeskWidget })).catch((err) => {
|
|
8
8
|
console.warn("[sagedesk] Failed to load widget bundle:", err);
|
|
9
9
|
const Empty = () => null;
|
|
10
10
|
return { default: Empty };
|
|
@@ -13,17 +13,23 @@ var LazyWidget = lazy(
|
|
|
13
13
|
function SageDeskNext(props) {
|
|
14
14
|
const [mounted, setMounted] = useState(false);
|
|
15
15
|
useEffect(() => {
|
|
16
|
-
|
|
16
|
+
const mode = props.mode ?? "local";
|
|
17
|
+
if (mode === "local" && !props.indexUrl) {
|
|
17
18
|
console.warn(
|
|
18
19
|
'[sagedesk] Missing required prop: indexUrl. The widget will not load.\nMake sure you ran `npx sagedesk build` and are passing indexUrl="/support-index.json" (or wherever you placed the output file in public/).'
|
|
19
20
|
);
|
|
20
|
-
} else if (
|
|
21
|
+
} else if (mode === "llm" && !props.endpoint) {
|
|
22
|
+
console.warn(
|
|
23
|
+
'[sagedesk] Missing required prop: endpoint for LLM mode. The widget will not load.\nProvide your backend route, e.g. endpoint="/api/sagedesk".'
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
if (props.indexUrl && !props.indexUrl.startsWith("/") && !props.indexUrl.startsWith("http")) {
|
|
21
27
|
console.warn(
|
|
22
28
|
`[sagedesk] indexUrl "${props.indexUrl}" looks like a relative path. It should start with "/" (e.g. "/support-index.json") so it resolves correctly from any page.`
|
|
23
29
|
);
|
|
24
30
|
}
|
|
25
31
|
setMounted(true);
|
|
26
|
-
}, []);
|
|
32
|
+
}, [props.mode, props.indexUrl, props.endpoint]);
|
|
27
33
|
if (!mounted) return null;
|
|
28
34
|
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(LazyWidget, { ...props }) });
|
|
29
35
|
}
|
package/dist/next/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/next/SageDeskNext.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect, Suspense, lazy } from 'react';\nimport type { SageDeskWidgetProps } from '../react/SageDeskWidget.js';\n\nconst LazyWidget = lazy(() =>\n import('../react/SageDeskWidget.js')\n .then((mod) => ({ default: mod.SageDeskWidget }))\n .catch((err) => {\n console.warn('[sagedesk] Failed to load widget bundle:', err);\n const Empty = () => null;\n return { default: Empty };\n })\n);\n\nexport function SageDeskNext(props: SageDeskWidgetProps) {\n // useState + useEffect ensures server render and initial client hydration\n // both return null (no mismatch). The widget appears only after hydration.\n // Using typeof window directly in render body causes a hydration mismatch\n // in Next.js App Router because 'use client' components still SSR.\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n if (!props.indexUrl) {\n console.warn(\n '[sagedesk] Missing required prop: indexUrl. The widget will not load.\\n' +\n 'Make sure you ran `npx sagedesk build` and are passing indexUrl=\"/support-index.json\" (or wherever you placed the output file in public/).'\n );\n } else if (!props.indexUrl.startsWith('/') && !props.indexUrl.startsWith('http')) {\n console.warn(\n `[sagedesk] indexUrl \"${props.indexUrl}\" looks like a relative path. ` +\n 'It should start with \"/\" (e.g. \"/support-index.json\") so it resolves correctly from any page.'\n );\n }\n setMounted(true);\n }, []);\n\n if (!mounted) return null;\n\n return (\n <Suspense fallback={null}>\n <LazyWidget {...props} />\n </Suspense>\n );\n}\n"],"mappings":";;;AAEA,SAAS,UAAU,WAAW,UAAU,YAAY;
|
|
1
|
+
{"version":3,"sources":["../../src/next/SageDeskNext.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect, Suspense, lazy } from 'react';\nimport type { SageDeskWidgetProps } from '../react/SageDeskWidget.js';\n\nconst LazyWidget = lazy(() =>\n import('../react/SageDeskWidget.js')\n .then((mod) => ({ default: mod.SageDeskWidget }))\n .catch((err) => {\n console.warn('[sagedesk] Failed to load widget bundle:', err);\n const Empty = () => null;\n return { default: Empty };\n })\n);\n\nexport function SageDeskNext(props: SageDeskWidgetProps) {\n // useState + useEffect ensures server render and initial client hydration\n // both return null (no mismatch). The widget appears only after hydration.\n // Using typeof window directly in render body causes a hydration mismatch\n // in Next.js App Router because 'use client' components still SSR.\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n const mode = props.mode ?? 'local';\n\n if (mode === 'local' && !props.indexUrl) {\n console.warn(\n '[sagedesk] Missing required prop: indexUrl. The widget will not load.\\n' +\n 'Make sure you ran `npx sagedesk build` and are passing indexUrl=\"/support-index.json\" (or wherever you placed the output file in public/).'\n );\n } else if (mode === 'llm' && !props.endpoint) {\n console.warn(\n '[sagedesk] Missing required prop: endpoint for LLM mode. The widget will not load.\\n' +\n 'Provide your backend route, e.g. endpoint=\"/api/sagedesk\".'\n );\n }\n\n if (props.indexUrl && !props.indexUrl.startsWith('/') && !props.indexUrl.startsWith('http')) {\n console.warn(\n `[sagedesk] indexUrl \"${props.indexUrl}\" looks like a relative path. ` +\n 'It should start with \"/\" (e.g. \"/support-index.json\") so it resolves correctly from any page.'\n );\n }\n setMounted(true);\n }, [props.mode, props.indexUrl, props.endpoint]);\n\n if (!mounted) return null;\n\n return (\n <Suspense fallback={null}>\n <LazyWidget {...props} />\n </Suspense>\n );\n}\n"],"mappings":";;;AAEA,SAAS,UAAU,WAAW,UAAU,YAAY;AAgD9C;AA7CN,IAAM,aAAa;AAAA,EAAK,MACtB,OAAO,8BAA4B,EAChC,KAAK,CAAC,SAAS,EAAE,SAAS,IAAI,eAAe,EAAE,EAC/C,MAAM,CAAC,QAAQ;AACd,YAAQ,KAAK,4CAA4C,GAAG;AAC5D,UAAM,QAAQ,MAAM;AACpB,WAAO,EAAE,SAAS,MAAM;AAAA,EAC1B,CAAC;AACL;AAEO,SAAS,aAAa,OAA4B;AAKvD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,YAAU,MAAM;AACd,UAAM,OAAO,MAAM,QAAQ;AAE3B,QAAI,SAAS,WAAW,CAAC,MAAM,UAAU;AACvC,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF,WAAW,SAAS,SAAS,CAAC,MAAM,UAAU;AAC5C,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF;AAEA,QAAI,MAAM,YAAY,CAAC,MAAM,SAAS,WAAW,GAAG,KAAK,CAAC,MAAM,SAAS,WAAW,MAAM,GAAG;AAC3F,cAAQ;AAAA,QACN,wBAAwB,MAAM,QAAQ;AAAA,MAExC;AAAA,IACF;AACA,eAAW,IAAI;AAAA,EACjB,GAAG,CAAC,MAAM,MAAM,MAAM,UAAU,MAAM,QAAQ,CAAC;AAE/C,MAAI,CAAC,QAAS,QAAO;AAErB,SACE,oBAAC,YAAS,UAAU,MAClB,8BAAC,cAAY,GAAG,OAAO,GACzB;AAEJ;","names":[]}
|
package/dist/react/index.cjs
CHANGED
|
@@ -258,6 +258,17 @@ function getFallback(config) {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
// src/react/useSageDesk.ts
|
|
261
|
+
function logFallbackWarning(reason) {
|
|
262
|
+
if (!reason) return;
|
|
263
|
+
const messages = {
|
|
264
|
+
"auth-error": "[sagedesk] Support service authentication failed. Showing relevant knowledge instead.",
|
|
265
|
+
"quota-exceeded": "[sagedesk] Support service quota exhausted. Showing relevant knowledge instead.",
|
|
266
|
+
"timeout": "[sagedesk] Support service took too long to respond. Showing relevant knowledge instead.",
|
|
267
|
+
"api-error": "[sagedesk] Support service error. Showing relevant knowledge instead.",
|
|
268
|
+
"malformed-response": "[sagedesk] Support service returned invalid response. Showing relevant knowledge instead."
|
|
269
|
+
};
|
|
270
|
+
console.warn(messages[reason] || "[sagedesk] Support service unavailable. Showing relevant knowledge instead.");
|
|
271
|
+
}
|
|
261
272
|
var initialState = {
|
|
262
273
|
messages: [],
|
|
263
274
|
isOpen: false,
|
|
@@ -310,6 +321,11 @@ function useSageDesk(config) {
|
|
|
310
321
|
const startEngine = (0, import_react.useCallback)(async () => {
|
|
311
322
|
if (engineStartedRef.current) return;
|
|
312
323
|
engineStartedRef.current = true;
|
|
324
|
+
if (config.mode === "llm") {
|
|
325
|
+
setChips(config.agent.suggestedChips ?? []);
|
|
326
|
+
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "ready" } });
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
313
329
|
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "loading-index" } });
|
|
314
330
|
try {
|
|
315
331
|
indexRef.current = await fetchIndex(config.indexUrl);
|
|
@@ -336,7 +352,7 @@ function useSageDesk(config) {
|
|
|
336
352
|
embedderRef.current = new EmbedderRuntime();
|
|
337
353
|
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "degraded" } });
|
|
338
354
|
}
|
|
339
|
-
}, [config.indexUrl, config.agent.suggestedChips, addMessage]);
|
|
355
|
+
}, [config.mode, config.indexUrl, config.agent.suggestedChips, addMessage]);
|
|
340
356
|
const greetingShownRef = (0, import_react.useRef)(false);
|
|
341
357
|
const open = (0, import_react.useCallback)(() => {
|
|
342
358
|
dispatch({ type: "OPEN" });
|
|
@@ -379,8 +395,37 @@ function useSageDesk(config) {
|
|
|
379
395
|
}
|
|
380
396
|
let botText;
|
|
381
397
|
let isFallback = false;
|
|
382
|
-
let
|
|
383
|
-
|
|
398
|
+
let fallbackReason;
|
|
399
|
+
let retrievalMode = "keyword";
|
|
400
|
+
if (config.mode === "llm") {
|
|
401
|
+
if (!config.endpoint) {
|
|
402
|
+
console.warn('[sagedesk] LLM mode requires an "endpoint" prop.');
|
|
403
|
+
botText = getFallback(config.agent);
|
|
404
|
+
isFallback = true;
|
|
405
|
+
} else {
|
|
406
|
+
try {
|
|
407
|
+
const res = await fetch(config.endpoint, {
|
|
408
|
+
method: "POST",
|
|
409
|
+
headers: { "Content-Type": "application/json" },
|
|
410
|
+
body: JSON.stringify({ query: trimmed })
|
|
411
|
+
});
|
|
412
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
413
|
+
const data = await res.json();
|
|
414
|
+
if (data.isFallback || !data.answer) {
|
|
415
|
+
fallbackReason = data.fallbackReason;
|
|
416
|
+
logFallbackWarning(fallbackReason);
|
|
417
|
+
botText = getFallback(config.agent);
|
|
418
|
+
isFallback = true;
|
|
419
|
+
} else {
|
|
420
|
+
botText = data.answer;
|
|
421
|
+
}
|
|
422
|
+
} catch (err) {
|
|
423
|
+
console.warn("[sagedesk] Support service unavailable. Using cached knowledge instead.");
|
|
424
|
+
botText = getFallback(config.agent);
|
|
425
|
+
isFallback = true;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
} else if (!indexRef.current) {
|
|
384
429
|
botText = getFallback(config.agent);
|
|
385
430
|
isFallback = true;
|
|
386
431
|
} else {
|
|
@@ -391,7 +436,7 @@ function useSageDesk(config) {
|
|
|
391
436
|
embedderRef.current,
|
|
392
437
|
config.search
|
|
393
438
|
);
|
|
394
|
-
|
|
439
|
+
retrievalMode = res.mode;
|
|
395
440
|
if (res.results.length > 0) {
|
|
396
441
|
botText = buildAnswer(res.results);
|
|
397
442
|
} else {
|
|
@@ -404,11 +449,13 @@ function useSageDesk(config) {
|
|
|
404
449
|
isFallback = true;
|
|
405
450
|
}
|
|
406
451
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
452
|
+
if (config.mode !== "llm") {
|
|
453
|
+
const elapsed = Date.now() - typingStart;
|
|
454
|
+
const delayBase = retrievalMode === "keyword" || isFallback ? 800 : 3e3;
|
|
455
|
+
const minTypingMs = delayBase + Math.random() * 2e3;
|
|
456
|
+
const remaining = minTypingMs - elapsed;
|
|
457
|
+
if (remaining > 0) await new Promise((r) => setTimeout(r, remaining));
|
|
458
|
+
}
|
|
412
459
|
dispatch({ type: "SET_TYPING", payload: false });
|
|
413
460
|
addMessage({ role: "bot", text: botText, isFallback });
|
|
414
461
|
},
|
|
@@ -431,6 +478,54 @@ function useSageDesk(config) {
|
|
|
431
478
|
return { state, chips: activeChips, open, close, submit };
|
|
432
479
|
}
|
|
433
480
|
|
|
481
|
+
// src/react/markdownUtils.ts
|
|
482
|
+
var import_marked = require("marked");
|
|
483
|
+
var import_dompurify = __toESM(require("dompurify"), 1);
|
|
484
|
+
import_marked.marked.setOptions({
|
|
485
|
+
breaks: true,
|
|
486
|
+
gfm: true,
|
|
487
|
+
pedantic: false
|
|
488
|
+
});
|
|
489
|
+
var PURIFY_CONFIG = {
|
|
490
|
+
ALLOWED_TAGS: [
|
|
491
|
+
"p",
|
|
492
|
+
"br",
|
|
493
|
+
"strong",
|
|
494
|
+
"em",
|
|
495
|
+
"u",
|
|
496
|
+
"h1",
|
|
497
|
+
"h2",
|
|
498
|
+
"h3",
|
|
499
|
+
"h4",
|
|
500
|
+
"h5",
|
|
501
|
+
"h6",
|
|
502
|
+
"ul",
|
|
503
|
+
"ol",
|
|
504
|
+
"li",
|
|
505
|
+
"blockquote",
|
|
506
|
+
"code",
|
|
507
|
+
"pre",
|
|
508
|
+
"a",
|
|
509
|
+
"hr"
|
|
510
|
+
],
|
|
511
|
+
ALLOWED_ATTR: ["href", "title", "target", "rel"],
|
|
512
|
+
ALLOW_DATA_ATTR: false
|
|
513
|
+
};
|
|
514
|
+
var HOOK_ALLOWLIST = ["a"];
|
|
515
|
+
import_dompurify.default.addHook("afterSanitizeAttributes", (node) => {
|
|
516
|
+
if (HOOK_ALLOWLIST.includes(node.tagName.toLowerCase())) {
|
|
517
|
+
if (node.tagName.toLowerCase() === "a") {
|
|
518
|
+
node.setAttribute("target", "_blank");
|
|
519
|
+
node.setAttribute("rel", "noopener noreferrer");
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
function parseMarkdown(markdown) {
|
|
524
|
+
const html = import_marked.marked.parse(markdown);
|
|
525
|
+
const sanitized = import_dompurify.default.sanitize(html, PURIFY_CONFIG);
|
|
526
|
+
return sanitized;
|
|
527
|
+
}
|
|
528
|
+
|
|
434
529
|
// src/react/SageDeskWidget.tsx
|
|
435
530
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
436
531
|
var STYLE_ID = "sagedesk-widget-styles";
|
|
@@ -460,6 +555,28 @@ var SHARED = `
|
|
|
460
555
|
}
|
|
461
556
|
.sd-r-scrollable::-webkit-scrollbar { display: none !important; }
|
|
462
557
|
.sd-r-scrollable > * { flex-shrink: 0 !important; }
|
|
558
|
+
.sd-r-markdown h1, .sd-r-markdown h2, .sd-r-markdown h3, .sd-r-markdown h4, .sd-r-markdown h5, .sd-r-markdown h6 {
|
|
559
|
+
margin: 12px 0 8px 0 !important; font-weight: 600 !important; line-height: 1.3 !important;
|
|
560
|
+
}
|
|
561
|
+
.sd-r-markdown h1 { font-size: 1.3em !important; }
|
|
562
|
+
.sd-r-markdown h2 { font-size: 1.2em !important; }
|
|
563
|
+
.sd-r-markdown h3 { font-size: 1.1em !important; }
|
|
564
|
+
.sd-r-markdown h4, .sd-r-markdown h5, .sd-r-markdown h6 { font-size: 1em !important; }
|
|
565
|
+
.sd-r-markdown strong { font-weight: 600 !important; }
|
|
566
|
+
.sd-r-markdown em { font-style: italic !important; }
|
|
567
|
+
.sd-r-markdown u { text-decoration: underline !important; }
|
|
568
|
+
.sd-r-markdown ul, .sd-r-markdown ol { margin: 8px 0 !important; padding-left: 20px !important; }
|
|
569
|
+
.sd-r-markdown li { margin: 4px 0 !important; }
|
|
570
|
+
.sd-r-markdown blockquote { margin: 8px 0 !important; padding-left: 12px !important; border-left: 3px solid currentColor !important; opacity: 0.8 !important; }
|
|
571
|
+
.sd-r-markdown code { font-family: 'Monaco', 'Courier New', monospace !important; font-size: 0.9em !important; padding: 2px 4px !important; background: rgba(0,0,0,0.05) !important; border-radius: 3px !important; }
|
|
572
|
+
.sd-r-markdown pre { background: rgba(0,0,0,0.05) !important; padding: 8px 10px !important; border-radius: 6px !important; overflow-x: auto !important; margin: 8px 0 !important; }
|
|
573
|
+
.sd-r-markdown pre code { background: none !important; padding: 0 !important; }
|
|
574
|
+
.sd-r-markdown hr { border: none !important; border-top: 1px solid currentColor !important; opacity: 0.3 !important; margin: 10px 0 !important; }
|
|
575
|
+
.sd-r-markdown a { text-decoration: underline !important; opacity: 0.9 !important; }
|
|
576
|
+
.sd-r-markdown a:hover { opacity: 1 !important; }
|
|
577
|
+
.sd-r-markdown p { margin: 6px 0 !important; }
|
|
578
|
+
.sd-r-markdown > *:first-child { margin-top: 0 !important; }
|
|
579
|
+
.sd-r-markdown > *:last-child { margin-bottom: 0 !important; }
|
|
463
580
|
@media (max-width: 420px) {
|
|
464
581
|
.sd-r-panel {
|
|
465
582
|
bottom: 0 !important; right: 0 !important; left: 0 !important;
|
|
@@ -546,7 +663,7 @@ var PoweredBy = ({ dark = false }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx
|
|
|
546
663
|
{
|
|
547
664
|
href: "https://github.com/mzeeshanwahid/sagedesk",
|
|
548
665
|
target: "_blank",
|
|
549
|
-
rel: "noopener
|
|
666
|
+
rel: "noopener",
|
|
550
667
|
style: {
|
|
551
668
|
color: dark ? "rgba(255,255,255,0.7)" : "#5a5a64",
|
|
552
669
|
fontWeight: 500,
|
|
@@ -558,6 +675,7 @@ var PoweredBy = ({ dark = false }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx
|
|
|
558
675
|
] });
|
|
559
676
|
function ClassicMessageBubble({ msg, accent }) {
|
|
560
677
|
const isBot = msg.role === "bot";
|
|
678
|
+
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
561
679
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: isBot ? "flex-start" : "flex-end", gap: "4px" }, children: [
|
|
562
680
|
msg.isFallback && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: "11px", fontWeight: 500, color: "#9b9aa3", margin: 0, padding: "0 4px", fontFamily: "inherit" }, children: "Not sure about that one" }),
|
|
563
681
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
|
|
@@ -570,10 +688,9 @@ function ClassicMessageBubble({ msg, accent }) {
|
|
|
570
688
|
color: isBot ? "#1a1a2e" : "#fff",
|
|
571
689
|
border: isBot ? "1px solid rgba(20,20,40,0.06)" : "none",
|
|
572
690
|
boxShadow: isBot ? "0 1px 2px rgba(20,20,40,0.04)" : `0 6px 16px -6px color-mix(in oklab, ${accent} 60%, transparent)`,
|
|
573
|
-
whiteSpace: "pre-wrap",
|
|
574
691
|
wordBreak: "break-word",
|
|
575
692
|
fontFamily: "inherit"
|
|
576
|
-
}, children: msg.text }),
|
|
693
|
+
}, className: "sd-r-markdown", children: isBot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { dangerouslySetInnerHTML: { __html: renderedHtml } }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { whiteSpace: "pre-wrap" }, children: msg.text }) }),
|
|
577
694
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
|
|
578
695
|
fontSize: "11px",
|
|
579
696
|
color: "#a8a8b0",
|
|
@@ -603,6 +720,7 @@ function ClassicTypingIndicator() {
|
|
|
603
720
|
}
|
|
604
721
|
function LightMessageBubble({ msg, accent, agentName }) {
|
|
605
722
|
const isBot = msg.role === "bot";
|
|
723
|
+
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
606
724
|
if (isBot) {
|
|
607
725
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
|
|
608
726
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
|
|
@@ -619,7 +737,7 @@ function LightMessageBubble({ msg, accent, agentName }) {
|
|
|
619
737
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "11px", color: "#a8a89e", fontVariantNumeric: "tabular-nums", fontFamily: "inherit" }, children: "just now" })
|
|
620
738
|
] }),
|
|
621
739
|
msg.isFallback && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: "11px", color: "#9b9aa3", margin: "0 0 4px", fontFamily: "inherit" }, children: "Not sure about that one" }),
|
|
622
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "14px", lineHeight: 1.55, color: "#2a2a36", fontFamily: "inherit",
|
|
740
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "14px", lineHeight: 1.55, color: "#2a2a36", fontFamily: "inherit", wordBreak: "break-word" }, className: "sd-r-markdown", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { dangerouslySetInnerHTML: { __html: renderedHtml } }) })
|
|
623
741
|
] })
|
|
624
742
|
] });
|
|
625
743
|
}
|
|
@@ -667,6 +785,7 @@ function LightTypingIndicator({ accent }) {
|
|
|
667
785
|
}
|
|
668
786
|
function DarkMessageBubble({ msg, accent }) {
|
|
669
787
|
const isBot = msg.role === "bot";
|
|
788
|
+
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
670
789
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
|
|
671
790
|
maxWidth: "85%",
|
|
672
791
|
padding: "12px 14px",
|
|
@@ -678,12 +797,11 @@ function DarkMessageBubble({ msg, accent }) {
|
|
|
678
797
|
color: isBot ? "rgba(255,255,255,0.92)" : "#fff",
|
|
679
798
|
alignSelf: isBot ? "flex-start" : "flex-end",
|
|
680
799
|
boxShadow: isBot ? "none" : `0 8px 20px -8px color-mix(in oklab, ${accent} 70%, transparent)`,
|
|
681
|
-
whiteSpace: "pre-wrap",
|
|
682
800
|
wordBreak: "break-word",
|
|
683
801
|
fontFamily: "inherit"
|
|
684
|
-
}, children: [
|
|
802
|
+
}, className: isBot ? "sd-r-markdown" : "", children: [
|
|
685
803
|
msg.isFallback && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "11px", color: "rgba(255,255,255,0.5)", display: "block", marginBottom: "4px" }, children: "Not sure about that one" }),
|
|
686
|
-
msg.text
|
|
804
|
+
isBot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { dangerouslySetInnerHTML: { __html: renderedHtml } }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { whiteSpace: "pre-wrap" }, children: msg.text })
|
|
687
805
|
] });
|
|
688
806
|
}
|
|
689
807
|
function DarkTypingIndicator() {
|
|
@@ -1303,16 +1421,22 @@ function renderDark(p) {
|
|
|
1303
1421
|
] })
|
|
1304
1422
|
] });
|
|
1305
1423
|
}
|
|
1306
|
-
function SageDeskWidget({ indexUrl, agent, search: search2 }) {
|
|
1307
|
-
|
|
1424
|
+
function SageDeskWidget({ mode, indexUrl, endpoint, agent, search: search2 }) {
|
|
1425
|
+
const resolvedMode = mode ?? "local";
|
|
1426
|
+
if (!agent?.name) {
|
|
1427
|
+
throw new Error('[sagedesk] Required prop "agent.name" is missing.');
|
|
1428
|
+
}
|
|
1429
|
+
if (resolvedMode === "local" && !indexUrl) {
|
|
1308
1430
|
throw new Error(
|
|
1309
|
-
'[sagedesk] Required prop "indexUrl" is missing. Run `npx sagedesk build` and pass the output path, e.g. indexUrl="/support-index.json".'
|
|
1431
|
+
'[sagedesk] Required prop "indexUrl" is missing for local mode. Run `npx sagedesk build` and pass the output path, e.g. indexUrl="/support-index.json".'
|
|
1310
1432
|
);
|
|
1311
1433
|
}
|
|
1312
|
-
if (!
|
|
1313
|
-
throw new Error(
|
|
1434
|
+
if (resolvedMode === "llm" && !endpoint) {
|
|
1435
|
+
throw new Error(
|
|
1436
|
+
'[sagedesk] Required prop "endpoint" is missing for llm mode. Provide your backend route, e.g. endpoint="/api/sagedesk".'
|
|
1437
|
+
);
|
|
1314
1438
|
}
|
|
1315
|
-
const config = { indexUrl, agent, search: search2 };
|
|
1439
|
+
const config = { mode: resolvedMode, indexUrl, endpoint, agent, search: search2 };
|
|
1316
1440
|
const { state, chips, open, close, submit } = useSageDesk(config);
|
|
1317
1441
|
const theme = agent.theme ?? "classic";
|
|
1318
1442
|
const accent = agent.accentColor ?? "#534AB7";
|
|
@@ -1325,7 +1449,7 @@ function SageDeskWidget({ indexUrl, agent, search: search2 }) {
|
|
|
1325
1449
|
const triggerRef = (0, import_react2.useRef)(null);
|
|
1326
1450
|
const [mounted, setMounted] = (0, import_react2.useState)(false);
|
|
1327
1451
|
(0, import_react2.useEffect)(() => {
|
|
1328
|
-
if (!indexUrl.startsWith("/") && !indexUrl.startsWith("http")) {
|
|
1452
|
+
if (resolvedMode === "local" && indexUrl && !indexUrl.startsWith("/") && !indexUrl.startsWith("http")) {
|
|
1329
1453
|
console.warn(
|
|
1330
1454
|
`[sagedesk] indexUrl "${indexUrl}" looks like a relative path. It should start with "/" so it resolves correctly from any page.`
|
|
1331
1455
|
);
|
|
@@ -1367,7 +1491,7 @@ function SageDeskWidget({ indexUrl, agent, search: search2 }) {
|
|
|
1367
1491
|
[handleSubmit]
|
|
1368
1492
|
);
|
|
1369
1493
|
if (!mounted || typeof document === "undefined") return null;
|
|
1370
|
-
const showPoweredBy =
|
|
1494
|
+
const showPoweredBy = true;
|
|
1371
1495
|
const showChips = chips.length > 0;
|
|
1372
1496
|
const panelClass = isClosing ? "sd-r-closing" : state.isOpen ? "sd-r-opening" : "";
|
|
1373
1497
|
const props = {
|