sagedesk 1.0.0 → 2.1.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 +281 -35
- package/dist/next/{SageDeskWidget-P3H2VJR5.js → SageDeskWidget-SJVE6QK3.js} +177 -32
- package/dist/next/SageDeskWidget-SJVE6QK3.js.map +1 -0
- package/dist/next/index.cjs +192 -35
- 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 +176 -31
- 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 +176 -31
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +376 -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 +340 -0
- package/dist/server/index.js.map +1 -0
- package/dist/vanilla/index.cjs +37 -9
- 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 +37 -9
- 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.cjs
CHANGED
|
@@ -121,17 +121,33 @@ function dotProduct(a, b) {
|
|
|
121
121
|
for (let i = 0; i < a.length; i++) dot += a[i] * b[i];
|
|
122
122
|
return dot;
|
|
123
123
|
}
|
|
124
|
+
function insertSorted(arr, item, maxLen) {
|
|
125
|
+
arr.push(item);
|
|
126
|
+
let i = arr.length - 1;
|
|
127
|
+
while (i > 0 && arr[i - 1].score < arr[i].score) {
|
|
128
|
+
const tmp = arr[i - 1];
|
|
129
|
+
arr[i - 1] = arr[i];
|
|
130
|
+
arr[i] = tmp;
|
|
131
|
+
i--;
|
|
132
|
+
}
|
|
133
|
+
if (arr.length > maxLen) arr.pop();
|
|
134
|
+
}
|
|
124
135
|
function search(queryVector, index, topK = 3, minScore = 0.42) {
|
|
125
136
|
const results = [];
|
|
126
137
|
for (const chunk of index) {
|
|
127
138
|
const score = dotProduct(queryVector, chunk.vector384);
|
|
128
139
|
if (score < minScore) continue;
|
|
129
140
|
if (results.length < topK) {
|
|
130
|
-
results
|
|
131
|
-
results.sort((a, b) => b.score - a.score);
|
|
141
|
+
insertSorted(results, { chunk, score }, topK);
|
|
132
142
|
} else if (score > results[topK - 1].score) {
|
|
133
143
|
results[topK - 1] = { chunk, score };
|
|
134
|
-
|
|
144
|
+
let i = topK - 1;
|
|
145
|
+
while (i > 0 && results[i - 1].score < results[i].score) {
|
|
146
|
+
const tmp = results[i - 1];
|
|
147
|
+
results[i - 1] = results[i];
|
|
148
|
+
results[i] = tmp;
|
|
149
|
+
i--;
|
|
150
|
+
}
|
|
135
151
|
}
|
|
136
152
|
}
|
|
137
153
|
return results;
|
|
@@ -142,15 +158,23 @@ function keywordSearch(query, index, topK = 3) {
|
|
|
142
158
|
const results = [];
|
|
143
159
|
for (const chunk of index) {
|
|
144
160
|
const chunkLower = chunk.textLower || chunk.text.toLowerCase();
|
|
145
|
-
|
|
161
|
+
let matchCount = 0;
|
|
162
|
+
for (const t of terms) {
|
|
163
|
+
if (chunkLower.includes(t)) matchCount++;
|
|
164
|
+
}
|
|
146
165
|
const score = matchCount / terms.length;
|
|
147
166
|
if (score <= 0) continue;
|
|
148
167
|
if (results.length < topK) {
|
|
149
|
-
results
|
|
150
|
-
results.sort((a, b) => b.score - a.score);
|
|
168
|
+
insertSorted(results, { chunk, score }, topK);
|
|
151
169
|
} else if (score > results[topK - 1].score) {
|
|
152
170
|
results[topK - 1] = { chunk, score };
|
|
153
|
-
|
|
171
|
+
let i = topK - 1;
|
|
172
|
+
while (i > 0 && results[i - 1].score < results[i].score) {
|
|
173
|
+
const tmp = results[i - 1];
|
|
174
|
+
results[i - 1] = results[i];
|
|
175
|
+
results[i] = tmp;
|
|
176
|
+
i--;
|
|
177
|
+
}
|
|
154
178
|
}
|
|
155
179
|
}
|
|
156
180
|
return results;
|
|
@@ -275,6 +299,17 @@ var init_fallback = __esm({
|
|
|
275
299
|
});
|
|
276
300
|
|
|
277
301
|
// src/react/useSageDesk.ts
|
|
302
|
+
function logFallbackWarning(reason) {
|
|
303
|
+
if (!reason) return;
|
|
304
|
+
const messages = {
|
|
305
|
+
"auth-error": "[sagedesk] Support service authentication failed. Showing relevant knowledge instead.",
|
|
306
|
+
"quota-exceeded": "[sagedesk] Support service quota exhausted. Showing relevant knowledge instead.",
|
|
307
|
+
"timeout": "[sagedesk] Support service took too long to respond. Showing relevant knowledge instead.",
|
|
308
|
+
"api-error": "[sagedesk] Support service error. Showing relevant knowledge instead.",
|
|
309
|
+
"malformed-response": "[sagedesk] Support service returned invalid response. Showing relevant knowledge instead."
|
|
310
|
+
};
|
|
311
|
+
console.warn(messages[reason] || "[sagedesk] Support service unavailable. Showing relevant knowledge instead.");
|
|
312
|
+
}
|
|
278
313
|
function reducer(state, action) {
|
|
279
314
|
switch (action.type) {
|
|
280
315
|
case "OPEN":
|
|
@@ -319,6 +354,11 @@ function useSageDesk(config) {
|
|
|
319
354
|
const startEngine = (0, import_react.useCallback)(async () => {
|
|
320
355
|
if (engineStartedRef.current) return;
|
|
321
356
|
engineStartedRef.current = true;
|
|
357
|
+
if (config.mode === "llm") {
|
|
358
|
+
setChips(config.agent.suggestedChips ?? []);
|
|
359
|
+
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "ready" } });
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
322
362
|
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "loading-index" } });
|
|
323
363
|
try {
|
|
324
364
|
indexRef.current = await fetchIndex(config.indexUrl);
|
|
@@ -345,7 +385,7 @@ function useSageDesk(config) {
|
|
|
345
385
|
embedderRef.current = new EmbedderRuntime();
|
|
346
386
|
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "degraded" } });
|
|
347
387
|
}
|
|
348
|
-
}, [config.indexUrl, config.agent.suggestedChips, addMessage]);
|
|
388
|
+
}, [config.mode, config.indexUrl, config.agent.suggestedChips, addMessage]);
|
|
349
389
|
const greetingShownRef = (0, import_react.useRef)(false);
|
|
350
390
|
const open = (0, import_react.useCallback)(() => {
|
|
351
391
|
dispatch({ type: "OPEN" });
|
|
@@ -388,8 +428,37 @@ function useSageDesk(config) {
|
|
|
388
428
|
}
|
|
389
429
|
let botText;
|
|
390
430
|
let isFallback = false;
|
|
391
|
-
let
|
|
392
|
-
|
|
431
|
+
let fallbackReason;
|
|
432
|
+
let retrievalMode = "keyword";
|
|
433
|
+
if (config.mode === "llm") {
|
|
434
|
+
if (!config.endpoint) {
|
|
435
|
+
console.warn('[sagedesk] LLM mode requires an "endpoint" prop.');
|
|
436
|
+
botText = getFallback(config.agent);
|
|
437
|
+
isFallback = true;
|
|
438
|
+
} else {
|
|
439
|
+
try {
|
|
440
|
+
const res = await fetch(config.endpoint, {
|
|
441
|
+
method: "POST",
|
|
442
|
+
headers: { "Content-Type": "application/json" },
|
|
443
|
+
body: JSON.stringify({ query: trimmed })
|
|
444
|
+
});
|
|
445
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
446
|
+
const data = await res.json();
|
|
447
|
+
if (data.isFallback || !data.answer) {
|
|
448
|
+
fallbackReason = data.fallbackReason;
|
|
449
|
+
logFallbackWarning(fallbackReason);
|
|
450
|
+
botText = getFallback(config.agent);
|
|
451
|
+
isFallback = true;
|
|
452
|
+
} else {
|
|
453
|
+
botText = data.answer;
|
|
454
|
+
}
|
|
455
|
+
} catch (err) {
|
|
456
|
+
console.warn("[sagedesk] Support service unavailable. Using cached knowledge instead.");
|
|
457
|
+
botText = getFallback(config.agent);
|
|
458
|
+
isFallback = true;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
} else if (!indexRef.current) {
|
|
393
462
|
botText = getFallback(config.agent);
|
|
394
463
|
isFallback = true;
|
|
395
464
|
} else {
|
|
@@ -400,7 +469,7 @@ function useSageDesk(config) {
|
|
|
400
469
|
embedderRef.current,
|
|
401
470
|
config.search
|
|
402
471
|
);
|
|
403
|
-
|
|
472
|
+
retrievalMode = res.mode;
|
|
404
473
|
if (res.results.length > 0) {
|
|
405
474
|
botText = buildAnswer(res.results);
|
|
406
475
|
} else {
|
|
@@ -413,11 +482,13 @@ function useSageDesk(config) {
|
|
|
413
482
|
isFallback = true;
|
|
414
483
|
}
|
|
415
484
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
485
|
+
if (config.mode !== "llm") {
|
|
486
|
+
const elapsed = Date.now() - typingStart;
|
|
487
|
+
const delayBase = retrievalMode === "keyword" || isFallback ? 800 : 3e3;
|
|
488
|
+
const minTypingMs = delayBase + Math.random() * 2e3;
|
|
489
|
+
const remaining = minTypingMs - elapsed;
|
|
490
|
+
if (remaining > 0) await new Promise((r) => setTimeout(r, remaining));
|
|
491
|
+
}
|
|
421
492
|
dispatch({ type: "SET_TYPING", payload: false });
|
|
422
493
|
addMessage({ role: "bot", text: botText, isFallback });
|
|
423
494
|
},
|
|
@@ -446,7 +517,6 @@ var init_useSageDesk = __esm({
|
|
|
446
517
|
import_react = require("react");
|
|
447
518
|
init_embedder();
|
|
448
519
|
init_retriever();
|
|
449
|
-
init_retriever();
|
|
450
520
|
init_renderer();
|
|
451
521
|
init_fallback();
|
|
452
522
|
initialState = {
|
|
@@ -460,6 +530,57 @@ var init_useSageDesk = __esm({
|
|
|
460
530
|
}
|
|
461
531
|
});
|
|
462
532
|
|
|
533
|
+
// src/react/markdownUtils.ts
|
|
534
|
+
function parseMarkdown(markdown) {
|
|
535
|
+
const html = import_marked.marked.parse(markdown);
|
|
536
|
+
const sanitized = import_dompurify.default.sanitize(html, PURIFY_CONFIG);
|
|
537
|
+
return sanitized;
|
|
538
|
+
}
|
|
539
|
+
var import_marked, import_dompurify, PURIFY_CONFIG;
|
|
540
|
+
var init_markdownUtils = __esm({
|
|
541
|
+
"src/react/markdownUtils.ts"() {
|
|
542
|
+
"use strict";
|
|
543
|
+
import_marked = require("marked");
|
|
544
|
+
import_dompurify = __toESM(require("dompurify"), 1);
|
|
545
|
+
import_marked.marked.setOptions({
|
|
546
|
+
breaks: true,
|
|
547
|
+
gfm: true,
|
|
548
|
+
pedantic: false
|
|
549
|
+
});
|
|
550
|
+
PURIFY_CONFIG = {
|
|
551
|
+
ALLOWED_TAGS: [
|
|
552
|
+
"p",
|
|
553
|
+
"br",
|
|
554
|
+
"strong",
|
|
555
|
+
"em",
|
|
556
|
+
"u",
|
|
557
|
+
"h1",
|
|
558
|
+
"h2",
|
|
559
|
+
"h3",
|
|
560
|
+
"h4",
|
|
561
|
+
"h5",
|
|
562
|
+
"h6",
|
|
563
|
+
"ul",
|
|
564
|
+
"ol",
|
|
565
|
+
"li",
|
|
566
|
+
"blockquote",
|
|
567
|
+
"code",
|
|
568
|
+
"pre",
|
|
569
|
+
"a",
|
|
570
|
+
"hr"
|
|
571
|
+
],
|
|
572
|
+
ALLOWED_ATTR: ["href", "title", "target", "rel"],
|
|
573
|
+
ALLOW_DATA_ATTR: false
|
|
574
|
+
};
|
|
575
|
+
import_dompurify.default.addHook("afterSanitizeAttributes", (node) => {
|
|
576
|
+
if (node.tagName.toLowerCase() === "a") {
|
|
577
|
+
node.setAttribute("target", "_blank");
|
|
578
|
+
node.setAttribute("rel", "noopener noreferrer");
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
|
|
463
584
|
// src/react/SageDeskWidget.tsx
|
|
464
585
|
var SageDeskWidget_exports = {};
|
|
465
586
|
__export(SageDeskWidget_exports, {
|
|
@@ -476,6 +597,7 @@ function injectStyles(theme) {
|
|
|
476
597
|
}
|
|
477
598
|
function ClassicMessageBubble({ msg, accent }) {
|
|
478
599
|
const isBot = msg.role === "bot";
|
|
600
|
+
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
479
601
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: isBot ? "flex-start" : "flex-end", gap: "4px" }, children: [
|
|
480
602
|
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" }),
|
|
481
603
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
|
|
@@ -488,10 +610,9 @@ function ClassicMessageBubble({ msg, accent }) {
|
|
|
488
610
|
color: isBot ? "#1a1a2e" : "#fff",
|
|
489
611
|
border: isBot ? "1px solid rgba(20,20,40,0.06)" : "none",
|
|
490
612
|
boxShadow: isBot ? "0 1px 2px rgba(20,20,40,0.04)" : `0 6px 16px -6px color-mix(in oklab, ${accent} 60%, transparent)`,
|
|
491
|
-
whiteSpace: "pre-wrap",
|
|
492
613
|
wordBreak: "break-word",
|
|
493
614
|
fontFamily: "inherit"
|
|
494
|
-
}, children: msg.text }),
|
|
615
|
+
}, 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 }) }),
|
|
495
616
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
|
|
496
617
|
fontSize: "11px",
|
|
497
618
|
color: "#a8a8b0",
|
|
@@ -521,6 +642,7 @@ function ClassicTypingIndicator() {
|
|
|
521
642
|
}
|
|
522
643
|
function LightMessageBubble({ msg, accent, agentName }) {
|
|
523
644
|
const isBot = msg.role === "bot";
|
|
645
|
+
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
524
646
|
if (isBot) {
|
|
525
647
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
|
|
526
648
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
|
|
@@ -537,7 +659,7 @@ function LightMessageBubble({ msg, accent, agentName }) {
|
|
|
537
659
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "11px", color: "#a8a89e", fontVariantNumeric: "tabular-nums", fontFamily: "inherit" }, children: "just now" })
|
|
538
660
|
] }),
|
|
539
661
|
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" }),
|
|
540
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: "14px", lineHeight: 1.55, color: "#2a2a36", fontFamily: "inherit",
|
|
662
|
+
/* @__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 } }) })
|
|
541
663
|
] })
|
|
542
664
|
] });
|
|
543
665
|
}
|
|
@@ -585,6 +707,7 @@ function LightTypingIndicator({ accent }) {
|
|
|
585
707
|
}
|
|
586
708
|
function DarkMessageBubble({ msg, accent }) {
|
|
587
709
|
const isBot = msg.role === "bot";
|
|
710
|
+
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
588
711
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
|
|
589
712
|
maxWidth: "85%",
|
|
590
713
|
padding: "12px 14px",
|
|
@@ -596,12 +719,11 @@ function DarkMessageBubble({ msg, accent }) {
|
|
|
596
719
|
color: isBot ? "rgba(255,255,255,0.92)" : "#fff",
|
|
597
720
|
alignSelf: isBot ? "flex-start" : "flex-end",
|
|
598
721
|
boxShadow: isBot ? "none" : `0 8px 20px -8px color-mix(in oklab, ${accent} 70%, transparent)`,
|
|
599
|
-
whiteSpace: "pre-wrap",
|
|
600
722
|
wordBreak: "break-word",
|
|
601
723
|
fontFamily: "inherit"
|
|
602
|
-
}, children: [
|
|
724
|
+
}, className: isBot ? "sd-r-markdown" : "", children: [
|
|
603
725
|
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" }),
|
|
604
|
-
msg.text
|
|
726
|
+
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 })
|
|
605
727
|
] });
|
|
606
728
|
}
|
|
607
729
|
function DarkTypingIndicator() {
|
|
@@ -1221,16 +1343,22 @@ function renderDark(p) {
|
|
|
1221
1343
|
] })
|
|
1222
1344
|
] });
|
|
1223
1345
|
}
|
|
1224
|
-
function SageDeskWidget({ indexUrl, agent, search: search2 }) {
|
|
1225
|
-
|
|
1346
|
+
function SageDeskWidget({ mode, indexUrl, endpoint, agent, search: search2 }) {
|
|
1347
|
+
const resolvedMode = mode ?? "local";
|
|
1348
|
+
if (!agent?.name) {
|
|
1349
|
+
throw new Error('[sagedesk] Required prop "agent.name" is missing.');
|
|
1350
|
+
}
|
|
1351
|
+
if (resolvedMode === "local" && !indexUrl) {
|
|
1226
1352
|
throw new Error(
|
|
1227
|
-
'[sagedesk] Required prop "indexUrl" is missing. Run `npx sagedesk build` and pass the output path, e.g. indexUrl="/support-index.json".'
|
|
1353
|
+
'[sagedesk] Required prop "indexUrl" is missing for local mode. Run `npx sagedesk build` and pass the output path, e.g. indexUrl="/support-index.json".'
|
|
1228
1354
|
);
|
|
1229
1355
|
}
|
|
1230
|
-
if (!
|
|
1231
|
-
throw new Error(
|
|
1356
|
+
if (resolvedMode === "llm" && !endpoint) {
|
|
1357
|
+
throw new Error(
|
|
1358
|
+
'[sagedesk] Required prop "endpoint" is missing for llm mode. Provide your backend route, e.g. endpoint="/api/sagedesk".'
|
|
1359
|
+
);
|
|
1232
1360
|
}
|
|
1233
|
-
const config = { indexUrl, agent, search: search2 };
|
|
1361
|
+
const config = { mode: resolvedMode, indexUrl, endpoint, agent, search: search2 };
|
|
1234
1362
|
const { state, chips, open, close, submit } = useSageDesk(config);
|
|
1235
1363
|
const theme = agent.theme ?? "classic";
|
|
1236
1364
|
const accent = agent.accentColor ?? "#534AB7";
|
|
@@ -1243,7 +1371,7 @@ function SageDeskWidget({ indexUrl, agent, search: search2 }) {
|
|
|
1243
1371
|
const triggerRef = (0, import_react2.useRef)(null);
|
|
1244
1372
|
const [mounted, setMounted] = (0, import_react2.useState)(false);
|
|
1245
1373
|
(0, import_react2.useEffect)(() => {
|
|
1246
|
-
if (!indexUrl.startsWith("/") && !indexUrl.startsWith("http")) {
|
|
1374
|
+
if (resolvedMode === "local" && indexUrl && !indexUrl.startsWith("/") && !indexUrl.startsWith("http")) {
|
|
1247
1375
|
console.warn(
|
|
1248
1376
|
`[sagedesk] indexUrl "${indexUrl}" looks like a relative path. It should start with "/" so it resolves correctly from any page.`
|
|
1249
1377
|
);
|
|
@@ -1285,7 +1413,7 @@ function SageDeskWidget({ indexUrl, agent, search: search2 }) {
|
|
|
1285
1413
|
[handleSubmit]
|
|
1286
1414
|
);
|
|
1287
1415
|
if (!mounted || typeof document === "undefined") return null;
|
|
1288
|
-
const showPoweredBy =
|
|
1416
|
+
const showPoweredBy = true;
|
|
1289
1417
|
const showChips = chips.length > 0;
|
|
1290
1418
|
const panelClass = isClosing ? "sd-r-closing" : state.isOpen ? "sd-r-opening" : "";
|
|
1291
1419
|
const props = {
|
|
@@ -1319,6 +1447,7 @@ var init_SageDeskWidget = __esm({
|
|
|
1319
1447
|
import_react2 = require("react");
|
|
1320
1448
|
import_react_dom = require("react-dom");
|
|
1321
1449
|
init_useSageDesk();
|
|
1450
|
+
init_markdownUtils();
|
|
1322
1451
|
import_jsx_runtime = require("react/jsx-runtime");
|
|
1323
1452
|
STYLE_ID = "sagedesk-widget-styles";
|
|
1324
1453
|
SHARED = `
|
|
@@ -1347,6 +1476,28 @@ var init_SageDeskWidget = __esm({
|
|
|
1347
1476
|
}
|
|
1348
1477
|
.sd-r-scrollable::-webkit-scrollbar { display: none !important; }
|
|
1349
1478
|
.sd-r-scrollable > * { flex-shrink: 0 !important; }
|
|
1479
|
+
.sd-r-markdown h1, .sd-r-markdown h2, .sd-r-markdown h3, .sd-r-markdown h4, .sd-r-markdown h5, .sd-r-markdown h6 {
|
|
1480
|
+
margin: 12px 0 8px 0 !important; font-weight: 600 !important; line-height: 1.3 !important;
|
|
1481
|
+
}
|
|
1482
|
+
.sd-r-markdown h1 { font-size: 1.3em !important; }
|
|
1483
|
+
.sd-r-markdown h2 { font-size: 1.2em !important; }
|
|
1484
|
+
.sd-r-markdown h3 { font-size: 1.1em !important; }
|
|
1485
|
+
.sd-r-markdown h4, .sd-r-markdown h5, .sd-r-markdown h6 { font-size: 1em !important; }
|
|
1486
|
+
.sd-r-markdown strong { font-weight: 600 !important; }
|
|
1487
|
+
.sd-r-markdown em { font-style: italic !important; }
|
|
1488
|
+
.sd-r-markdown u { text-decoration: underline !important; }
|
|
1489
|
+
.sd-r-markdown ul, .sd-r-markdown ol { margin: 8px 0 !important; padding-left: 20px !important; }
|
|
1490
|
+
.sd-r-markdown li { margin: 4px 0 !important; }
|
|
1491
|
+
.sd-r-markdown blockquote { margin: 8px 0 !important; padding-left: 12px !important; border-left: 3px solid currentColor !important; opacity: 0.8 !important; }
|
|
1492
|
+
.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; }
|
|
1493
|
+
.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; }
|
|
1494
|
+
.sd-r-markdown pre code { background: none !important; padding: 0 !important; }
|
|
1495
|
+
.sd-r-markdown hr { border: none !important; border-top: 1px solid currentColor !important; opacity: 0.3 !important; margin: 10px 0 !important; }
|
|
1496
|
+
.sd-r-markdown a { text-decoration: underline !important; opacity: 0.9 !important; }
|
|
1497
|
+
.sd-r-markdown a:hover { opacity: 1 !important; }
|
|
1498
|
+
.sd-r-markdown p { margin: 6px 0 !important; }
|
|
1499
|
+
.sd-r-markdown > *:first-child { margin-top: 0 !important; }
|
|
1500
|
+
.sd-r-markdown > *:last-child { margin-bottom: 0 !important; }
|
|
1350
1501
|
@media (max-width: 420px) {
|
|
1351
1502
|
.sd-r-panel {
|
|
1352
1503
|
bottom: 0 !important; right: 0 !important; left: 0 !important;
|
|
@@ -1424,7 +1575,7 @@ var init_SageDeskWidget = __esm({
|
|
|
1424
1575
|
{
|
|
1425
1576
|
href: "https://github.com/mzeeshanwahid/sagedesk",
|
|
1426
1577
|
target: "_blank",
|
|
1427
|
-
rel: "noopener
|
|
1578
|
+
rel: "noopener",
|
|
1428
1579
|
style: {
|
|
1429
1580
|
color: dark ? "rgba(255,255,255,0.7)" : "#5a5a64",
|
|
1430
1581
|
fontWeight: 500,
|
|
@@ -1457,17 +1608,23 @@ var LazyWidget = (0, import_react3.lazy)(
|
|
|
1457
1608
|
function SageDeskNext(props) {
|
|
1458
1609
|
const [mounted, setMounted] = (0, import_react3.useState)(false);
|
|
1459
1610
|
(0, import_react3.useEffect)(() => {
|
|
1460
|
-
|
|
1611
|
+
const mode = props.mode ?? "local";
|
|
1612
|
+
if (mode === "local" && !props.indexUrl) {
|
|
1461
1613
|
console.warn(
|
|
1462
1614
|
'[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/).'
|
|
1463
1615
|
);
|
|
1464
|
-
} else if (
|
|
1616
|
+
} else if (mode === "llm" && !props.endpoint) {
|
|
1617
|
+
console.warn(
|
|
1618
|
+
'[sagedesk] Missing required prop: endpoint for LLM mode. The widget will not load.\nProvide your backend route, e.g. endpoint="/api/sagedesk".'
|
|
1619
|
+
);
|
|
1620
|
+
}
|
|
1621
|
+
if (props.indexUrl && !props.indexUrl.startsWith("/") && !props.indexUrl.startsWith("http")) {
|
|
1465
1622
|
console.warn(
|
|
1466
1623
|
`[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.`
|
|
1467
1624
|
);
|
|
1468
1625
|
}
|
|
1469
1626
|
setMounted(true);
|
|
1470
|
-
}, []);
|
|
1627
|
+
}, [props.mode, props.indexUrl, props.endpoint]);
|
|
1471
1628
|
if (!mounted) return null;
|
|
1472
1629
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react3.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LazyWidget, { ...props }) });
|
|
1473
1630
|
}
|