sagedesk 2.1.1 → 2.3.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 +17 -38
- package/dist/next/{SageDeskWidget-SJVE6QK3.js → SageDeskWidget-ZJJGXTTC.js} +66 -37
- package/dist/next/SageDeskWidget-ZJJGXTTC.js.map +1 -0
- package/dist/next/index.cjs +142 -114
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.js +1 -1
- package/dist/react/index.cjs +63 -35
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +65 -36
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +21 -120
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +13 -7
- package/dist/server/index.d.ts +13 -7
- package/dist/server/index.js +21 -110
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/next/SageDeskWidget-SJVE6QK3.js.map +0 -1
package/dist/react/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ __export(react_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(react_exports);
|
|
37
37
|
|
|
38
38
|
// src/react/SageDeskWidget.tsx
|
|
39
|
-
var import_react2 = require("react");
|
|
39
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
40
40
|
var import_react_dom = require("react-dom");
|
|
41
41
|
|
|
42
42
|
// src/react/useSageDesk.ts
|
|
@@ -295,6 +295,7 @@ function logFallbackWarning(reason) {
|
|
|
295
295
|
}
|
|
296
296
|
var initialState = {
|
|
297
297
|
messages: [],
|
|
298
|
+
userMessages: [],
|
|
298
299
|
isOpen: false,
|
|
299
300
|
isTyping: false,
|
|
300
301
|
engineStatus: "idle",
|
|
@@ -307,8 +308,11 @@ function reducer(state, action) {
|
|
|
307
308
|
return { ...state, isOpen: true };
|
|
308
309
|
case "CLOSE":
|
|
309
310
|
return { ...state, isOpen: false };
|
|
310
|
-
case "ADD_MESSAGE":
|
|
311
|
-
|
|
311
|
+
case "ADD_MESSAGE": {
|
|
312
|
+
const newMessages = [...state.messages, action.payload];
|
|
313
|
+
const newUserMessages = action.payload.role === "user" ? [...state.userMessages, action.payload] : state.userMessages;
|
|
314
|
+
return { ...state, messages: newMessages, userMessages: newUserMessages };
|
|
315
|
+
}
|
|
312
316
|
case "SET_TYPING":
|
|
313
317
|
return { ...state, isTyping: action.payload };
|
|
314
318
|
case "SET_ENGINE_STATUS":
|
|
@@ -331,6 +335,7 @@ function useSageDesk(config) {
|
|
|
331
335
|
const embedderRef = (0, import_react.useRef)(null);
|
|
332
336
|
const engineStartedRef = (0, import_react.useRef)(false);
|
|
333
337
|
const msgCounterRef = (0, import_react.useRef)(0);
|
|
338
|
+
const engineReadyCallbacksRef = (0, import_react.useRef)([]);
|
|
334
339
|
const [chips, setChips] = (0, import_react.useState)([]);
|
|
335
340
|
const makeId = () => `msg-${++msgCounterRef.current}`;
|
|
336
341
|
const addMessage = (0, import_react.useCallback)(
|
|
@@ -342,12 +347,27 @@ function useSageDesk(config) {
|
|
|
342
347
|
},
|
|
343
348
|
[]
|
|
344
349
|
);
|
|
350
|
+
const notifyEngineReady = (0, import_react.useCallback)(() => {
|
|
351
|
+
const callbacks = engineReadyCallbacksRef.current;
|
|
352
|
+
engineReadyCallbacksRef.current = [];
|
|
353
|
+
callbacks.forEach((cb) => cb());
|
|
354
|
+
}, []);
|
|
345
355
|
const startEngine = (0, import_react.useCallback)(async () => {
|
|
346
356
|
if (engineStartedRef.current) return;
|
|
347
357
|
engineStartedRef.current = true;
|
|
348
358
|
if (config.mode === "llm") {
|
|
349
359
|
setChips(config.agent.suggestedChips ?? []);
|
|
350
|
-
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "
|
|
360
|
+
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "loading-model" } });
|
|
361
|
+
try {
|
|
362
|
+
embedderRef.current = new EmbedderRuntime();
|
|
363
|
+
await embedderRef.current.load(config.agent.model);
|
|
364
|
+
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "ready" } });
|
|
365
|
+
notifyEngineReady();
|
|
366
|
+
} catch (err) {
|
|
367
|
+
console.warn("[sagedesk] WASM embedder failed to load - LLM mode will use fallback messages.", err);
|
|
368
|
+
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "error-model", error: String(err) } });
|
|
369
|
+
notifyEngineReady();
|
|
370
|
+
}
|
|
351
371
|
return;
|
|
352
372
|
}
|
|
353
373
|
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "loading-index" } });
|
|
@@ -359,6 +379,7 @@ function useSageDesk(config) {
|
|
|
359
379
|
type: "SET_ENGINE_STATUS",
|
|
360
380
|
payload: { status: "error-index", error: String(err) }
|
|
361
381
|
});
|
|
382
|
+
notifyEngineReady();
|
|
362
383
|
addMessage({
|
|
363
384
|
role: "bot",
|
|
364
385
|
text: "I'm having trouble loading right now. Please try again in a moment."
|
|
@@ -371,12 +392,14 @@ function useSageDesk(config) {
|
|
|
371
392
|
embedderRef.current = new EmbedderRuntime();
|
|
372
393
|
await embedderRef.current.load(config.agent.model);
|
|
373
394
|
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "ready" } });
|
|
395
|
+
notifyEngineReady();
|
|
374
396
|
} catch (err) {
|
|
375
397
|
console.warn("[sagedesk] WASM model failed to load, falling back to keyword search -", err);
|
|
376
398
|
embedderRef.current = new EmbedderRuntime();
|
|
377
399
|
dispatch({ type: "SET_ENGINE_STATUS", payload: { status: "degraded" } });
|
|
400
|
+
notifyEngineReady();
|
|
378
401
|
}
|
|
379
|
-
}, [config.mode, config.indexUrl, config.agent.suggestedChips, addMessage]);
|
|
402
|
+
}, [config.mode, config.indexUrl, config.agent.model, config.agent.suggestedChips, addMessage, notifyEngineReady]);
|
|
380
403
|
const greetingShownRef = (0, import_react.useRef)(false);
|
|
381
404
|
const open = (0, import_react.useCallback)(() => {
|
|
382
405
|
dispatch({ type: "OPEN" });
|
|
@@ -393,16 +416,12 @@ function useSageDesk(config) {
|
|
|
393
416
|
dispatch({ type: "CLOSE" });
|
|
394
417
|
}, []);
|
|
395
418
|
const waitForEngine = (0, import_react.useCallback)(() => {
|
|
419
|
+
const s = engineStatusRef.current;
|
|
420
|
+
if (s === "ready" || s === "degraded" || s === "error-index" || s === "error-model") {
|
|
421
|
+
return Promise.resolve();
|
|
422
|
+
}
|
|
396
423
|
return new Promise((resolve) => {
|
|
397
|
-
|
|
398
|
-
const s = engineStatusRef.current;
|
|
399
|
-
if (s === "ready" || s === "degraded" || s === "error-index" || s === "error-model") {
|
|
400
|
-
resolve();
|
|
401
|
-
} else {
|
|
402
|
-
setTimeout(check, 100);
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
check();
|
|
424
|
+
engineReadyCallbacksRef.current.push(resolve);
|
|
406
425
|
});
|
|
407
426
|
}, []);
|
|
408
427
|
const submit = (0, import_react.useCallback)(
|
|
@@ -426,12 +445,20 @@ function useSageDesk(config) {
|
|
|
426
445
|
console.warn('[sagedesk] LLM mode requires an "endpoint" prop.');
|
|
427
446
|
botText = getFallback(config.agent);
|
|
428
447
|
isFallback = true;
|
|
448
|
+
} else if (!embedderRef.current?.isReady) {
|
|
449
|
+
console.warn("[sagedesk] Embedder not ready - showing fallback.");
|
|
450
|
+
botText = getFallback(config.agent);
|
|
451
|
+
isFallback = true;
|
|
429
452
|
} else {
|
|
430
453
|
try {
|
|
454
|
+
const vector = await embedderRef.current.embed(trimmed);
|
|
431
455
|
const res = await fetch(config.endpoint, {
|
|
432
456
|
method: "POST",
|
|
433
457
|
headers: { "Content-Type": "application/json" },
|
|
434
|
-
body: JSON.stringify({
|
|
458
|
+
body: JSON.stringify({
|
|
459
|
+
query: trimmed,
|
|
460
|
+
queryVector: Array.from(vector)
|
|
461
|
+
})
|
|
435
462
|
});
|
|
436
463
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
437
464
|
const data = await res.json();
|
|
@@ -475,8 +502,8 @@ function useSageDesk(config) {
|
|
|
475
502
|
}
|
|
476
503
|
if (config.mode !== "llm") {
|
|
477
504
|
const elapsed = Date.now() - typingStart;
|
|
478
|
-
const delayBase = retrievalMode === "keyword" || isFallback ?
|
|
479
|
-
const minTypingMs = delayBase + Math.random() *
|
|
505
|
+
const delayBase = retrievalMode === "keyword" || isFallback ? 400 : 800;
|
|
506
|
+
const minTypingMs = delayBase + Math.random() * 400;
|
|
480
507
|
const remaining = minTypingMs - elapsed;
|
|
481
508
|
if (remaining > 0) await new Promise((r) => setTimeout(r, remaining));
|
|
482
509
|
}
|
|
@@ -494,11 +521,9 @@ function useSageDesk(config) {
|
|
|
494
521
|
return () => document.removeEventListener("keydown", handler);
|
|
495
522
|
}, [state.isOpen, close]);
|
|
496
523
|
const activeChips = (0, import_react.useMemo)(() => {
|
|
497
|
-
const askedTexts = new Set(
|
|
498
|
-
state.messages.filter((m) => m.role === "user").map((m) => m.text.toLowerCase().trim())
|
|
499
|
-
);
|
|
524
|
+
const askedTexts = new Set(state.userMessages.map((m) => m.text.toLowerCase().trim()));
|
|
500
525
|
return chips.filter((chip) => !askedTexts.has(chip.toLowerCase().trim()));
|
|
501
|
-
}, [chips, state.
|
|
526
|
+
}, [chips, state.userMessages]);
|
|
502
527
|
return { state, chips: activeChips, open, close, submit };
|
|
503
528
|
}
|
|
504
529
|
|
|
@@ -694,9 +719,9 @@ var PoweredBy = ({ dark = false }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx
|
|
|
694
719
|
}
|
|
695
720
|
)
|
|
696
721
|
] });
|
|
697
|
-
|
|
722
|
+
var ClassicMessageBubble = import_react2.default.memo(function ClassicMessageBubble2({ msg, accent }) {
|
|
698
723
|
const isBot = msg.role === "bot";
|
|
699
|
-
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
724
|
+
const renderedHtml = (0, import_react2.useMemo)(() => isBot ? parseMarkdown(msg.text) : msg.text, [isBot, msg.text]);
|
|
700
725
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: isBot ? "flex-start" : "flex-end", gap: "4px" }, children: [
|
|
701
726
|
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" }),
|
|
702
727
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
|
|
@@ -721,7 +746,7 @@ function ClassicMessageBubble({ msg, accent }) {
|
|
|
721
746
|
fontFamily: "inherit"
|
|
722
747
|
}, children: "just now" })
|
|
723
748
|
] });
|
|
724
|
-
}
|
|
749
|
+
});
|
|
725
750
|
function ClassicTypingIndicator() {
|
|
726
751
|
const dot = { width: 6, height: 6, borderRadius: "50%", background: "#c8c8ce", display: "inline-block" };
|
|
727
752
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-start", gap: "4px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
|
|
@@ -739,9 +764,9 @@ function ClassicTypingIndicator() {
|
|
|
739
764
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-3" })
|
|
740
765
|
] }) });
|
|
741
766
|
}
|
|
742
|
-
|
|
767
|
+
var LightMessageBubble = import_react2.default.memo(function LightMessageBubble2({ msg, accent, agentName }) {
|
|
743
768
|
const isBot = msg.role === "bot";
|
|
744
|
-
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
769
|
+
const renderedHtml = (0, import_react2.useMemo)(() => isBot ? parseMarkdown(msg.text) : msg.text, [isBot, msg.text]);
|
|
745
770
|
if (isBot) {
|
|
746
771
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
|
|
747
772
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
|
|
@@ -776,7 +801,7 @@ function LightMessageBubble({ msg, accent, agentName }) {
|
|
|
776
801
|
wordBreak: "break-word",
|
|
777
802
|
fontFamily: "inherit"
|
|
778
803
|
}, children: msg.text }) });
|
|
779
|
-
}
|
|
804
|
+
});
|
|
780
805
|
function LightTypingIndicator({ accent }) {
|
|
781
806
|
const dot = { width: 6, height: 6, borderRadius: "50%", background: "#c4c4be", display: "inline-block" };
|
|
782
807
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "10px" }, children: [
|
|
@@ -804,9 +829,9 @@ function LightTypingIndicator({ accent }) {
|
|
|
804
829
|
] })
|
|
805
830
|
] });
|
|
806
831
|
}
|
|
807
|
-
|
|
832
|
+
var DarkMessageBubble = import_react2.default.memo(function DarkMessageBubble2({ msg, accent }) {
|
|
808
833
|
const isBot = msg.role === "bot";
|
|
809
|
-
const renderedHtml = isBot ? parseMarkdown(msg.text) : msg.text;
|
|
834
|
+
const renderedHtml = (0, import_react2.useMemo)(() => isBot ? parseMarkdown(msg.text) : msg.text, [isBot, msg.text]);
|
|
810
835
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
|
|
811
836
|
maxWidth: "85%",
|
|
812
837
|
padding: "12px 14px",
|
|
@@ -824,7 +849,7 @@ function DarkMessageBubble({ msg, accent }) {
|
|
|
824
849
|
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" }),
|
|
825
850
|
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 })
|
|
826
851
|
] });
|
|
827
|
-
}
|
|
852
|
+
});
|
|
828
853
|
function DarkTypingIndicator() {
|
|
829
854
|
const dot = { width: 6, height: 6, borderRadius: "50%", background: "rgba(255,255,255,0.4)", display: "inline-block" };
|
|
830
855
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
|
|
@@ -843,7 +868,7 @@ function DarkTypingIndicator() {
|
|
|
843
868
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dot, className: "sd-r-dot-3" })
|
|
844
869
|
] });
|
|
845
870
|
}
|
|
846
|
-
function
|
|
871
|
+
function ClassicTheme(p) {
|
|
847
872
|
const {
|
|
848
873
|
agent,
|
|
849
874
|
state,
|
|
@@ -1032,7 +1057,7 @@ function renderClassic(p) {
|
|
|
1032
1057
|
] })
|
|
1033
1058
|
] });
|
|
1034
1059
|
}
|
|
1035
|
-
function
|
|
1060
|
+
function LightTheme(p) {
|
|
1036
1061
|
const {
|
|
1037
1062
|
agent,
|
|
1038
1063
|
state,
|
|
@@ -1220,7 +1245,7 @@ function renderLight(p) {
|
|
|
1220
1245
|
] })
|
|
1221
1246
|
] });
|
|
1222
1247
|
}
|
|
1223
|
-
function
|
|
1248
|
+
function DarkTheme(p) {
|
|
1224
1249
|
const {
|
|
1225
1250
|
agent,
|
|
1226
1251
|
state,
|
|
@@ -1457,7 +1482,10 @@ function SageDeskWidget({ mode, indexUrl, endpoint, agent, search: search2 }) {
|
|
|
1457
1482
|
'[sagedesk] Required prop "endpoint" is missing for llm mode. Provide your backend route, e.g. endpoint="/api/sagedesk".'
|
|
1458
1483
|
);
|
|
1459
1484
|
}
|
|
1460
|
-
const config =
|
|
1485
|
+
const config = (0, import_react2.useMemo)(
|
|
1486
|
+
() => ({ mode: resolvedMode, indexUrl, endpoint, agent, search: search2 }),
|
|
1487
|
+
[resolvedMode, indexUrl, endpoint, agent, search2]
|
|
1488
|
+
);
|
|
1461
1489
|
const { state, chips, open, close, submit } = useSageDesk(config);
|
|
1462
1490
|
const theme = agent.theme ?? "classic";
|
|
1463
1491
|
const accent = agent.accentColor ?? "#534AB7";
|
|
@@ -1536,7 +1564,7 @@ function SageDeskWidget({ mode, indexUrl, endpoint, agent, search: search2 }) {
|
|
|
1536
1564
|
open,
|
|
1537
1565
|
submit
|
|
1538
1566
|
};
|
|
1539
|
-
const content = theme === "dark" ?
|
|
1567
|
+
const content = theme === "dark" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DarkTheme, { ...props }) : theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LightTheme, { ...props }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClassicTheme, { ...props });
|
|
1540
1568
|
return (0, import_react_dom.createPortal)(content, document.body);
|
|
1541
1569
|
}
|
|
1542
1570
|
// Annotate the CommonJS export names for ESM import in node:
|