@wallavi/widget 1.13.1 → 1.13.3
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/dist/index.d.mts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +72 -12
- package/dist/index.mjs +72 -12
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -174,8 +174,10 @@ interface ChatWidgetConfig {
|
|
|
174
174
|
showThinking?: boolean;
|
|
175
175
|
regenerateMessage?: boolean;
|
|
176
176
|
/**
|
|
177
|
-
* Persist
|
|
178
|
-
*
|
|
177
|
+
* Persist the conversation so it survives page reloads and navigations.
|
|
178
|
+
* The storage key is `wallavi_<agentId>_<userId>` when `userContext.userId`
|
|
179
|
+
* is set, otherwise `wallavi_<agentId>`. Messages go in sessionStorage under
|
|
180
|
+
* `<key>_msgs` and the threadId in localStorage under `<key>_tid`.
|
|
179
181
|
*/
|
|
180
182
|
persist?: boolean;
|
|
181
183
|
onNavigate?: (path: string) => void;
|
|
@@ -356,7 +358,10 @@ interface CommandPanelProps {
|
|
|
356
358
|
ragTopics?: RagTopicInfo[];
|
|
357
359
|
ragDocuments?: RagDocumentInfo[];
|
|
358
360
|
onSend: (text: string) => void;
|
|
359
|
-
onExecuteAction?: (
|
|
361
|
+
onExecuteAction?: (action: {
|
|
362
|
+
name: string;
|
|
363
|
+
steps: any[];
|
|
364
|
+
}) => void;
|
|
360
365
|
accentColor?: string;
|
|
361
366
|
isDark?: boolean;
|
|
362
367
|
watermark?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -174,8 +174,10 @@ interface ChatWidgetConfig {
|
|
|
174
174
|
showThinking?: boolean;
|
|
175
175
|
regenerateMessage?: boolean;
|
|
176
176
|
/**
|
|
177
|
-
* Persist
|
|
178
|
-
*
|
|
177
|
+
* Persist the conversation so it survives page reloads and navigations.
|
|
178
|
+
* The storage key is `wallavi_<agentId>_<userId>` when `userContext.userId`
|
|
179
|
+
* is set, otherwise `wallavi_<agentId>`. Messages go in sessionStorage under
|
|
180
|
+
* `<key>_msgs` and the threadId in localStorage under `<key>_tid`.
|
|
179
181
|
*/
|
|
180
182
|
persist?: boolean;
|
|
181
183
|
onNavigate?: (path: string) => void;
|
|
@@ -356,7 +358,10 @@ interface CommandPanelProps {
|
|
|
356
358
|
ragTopics?: RagTopicInfo[];
|
|
357
359
|
ragDocuments?: RagDocumentInfo[];
|
|
358
360
|
onSend: (text: string) => void;
|
|
359
|
-
onExecuteAction?: (
|
|
361
|
+
onExecuteAction?: (action: {
|
|
362
|
+
name: string;
|
|
363
|
+
steps: any[];
|
|
364
|
+
}) => void;
|
|
360
365
|
accentColor?: string;
|
|
361
366
|
isDark?: boolean;
|
|
362
367
|
watermark?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -351,6 +351,55 @@ function applyUiEventToMessages(prev, proto, msgId) {
|
|
|
351
351
|
return copy;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
+
// src/core/quick-action.ts
|
|
355
|
+
var BRACES = /\{\{(?:toolInput\.)?([a-zA-Z0-9_]+)\}\}|\{([a-zA-Z0-9_]+)\}/g;
|
|
356
|
+
var ROUTE = /\{\{(?:toolInput\.)?([a-zA-Z0-9_]+)\}\}|\{([a-zA-Z0-9_]+)\}|\[([a-zA-Z0-9_]+)\]|(?<=^|\/):([a-zA-Z0-9_]+)(?=[/?#]|$)/g;
|
|
357
|
+
function fill(text, pattern, sources, missing) {
|
|
358
|
+
return text.replace(pattern, (match, ...groups) => {
|
|
359
|
+
const key = groups.find((g) => typeof g === "string");
|
|
360
|
+
if (!key) return match;
|
|
361
|
+
for (const source of sources) {
|
|
362
|
+
const value = source?.[key];
|
|
363
|
+
if (typeof value === "string" && value !== "") return value;
|
|
364
|
+
if (typeof value === "number") return String(value);
|
|
365
|
+
}
|
|
366
|
+
missing?.add(key);
|
|
367
|
+
return match;
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
function fillPayload(value, sources) {
|
|
371
|
+
if (typeof value === "string") return fill(value, BRACES, sources);
|
|
372
|
+
if (Array.isArray(value)) return value.map((v) => fillPayload(v, sources));
|
|
373
|
+
if (value && typeof value === "object") {
|
|
374
|
+
return Object.fromEntries(
|
|
375
|
+
Object.entries(value).map(([k, v]) => [k, fillPayload(v, sources)])
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
return value;
|
|
379
|
+
}
|
|
380
|
+
function planQuickAction(steps, pageParams, metadata) {
|
|
381
|
+
const sources = [pageParams, metadata];
|
|
382
|
+
const missing = /* @__PURE__ */ new Set();
|
|
383
|
+
const filled = steps.map((original) => {
|
|
384
|
+
const step = original;
|
|
385
|
+
const out = { ...step };
|
|
386
|
+
if (typeof step.value === "string") {
|
|
387
|
+
out.value = step.action === "navigate" ? fill(step.value, ROUTE, sources, missing) : fill(step.value, BRACES, sources);
|
|
388
|
+
}
|
|
389
|
+
if (typeof step.selector === "string") {
|
|
390
|
+
out.selector = fill(step.selector, BRACES, sources);
|
|
391
|
+
}
|
|
392
|
+
if (step.payload !== void 0) {
|
|
393
|
+
out.payload = fillPayload(step.payload, sources);
|
|
394
|
+
}
|
|
395
|
+
return out;
|
|
396
|
+
});
|
|
397
|
+
return missing.size > 0 ? { kind: "ask_agent", missing: [...missing] } : { kind: "run", steps: filled };
|
|
398
|
+
}
|
|
399
|
+
function hasRoutePlaceholder(url) {
|
|
400
|
+
return new RegExp(ROUTE.source).test(url);
|
|
401
|
+
}
|
|
402
|
+
|
|
354
403
|
// src/core/declarative-actions.ts
|
|
355
404
|
function sanitizeSelector(selector) {
|
|
356
405
|
if (!selector || typeof selector !== "string") return null;
|
|
@@ -625,6 +674,12 @@ async function executeDeclarativeSteps(steps, onNavigate, copilotColor) {
|
|
|
625
674
|
}
|
|
626
675
|
case "navigate": {
|
|
627
676
|
const url = sanitizeUrl(step.value);
|
|
677
|
+
if (url && hasRoutePlaceholder(url)) {
|
|
678
|
+
console.warn(
|
|
679
|
+
"[Wallavi Widget] Blocked navigate with unfilled route params"
|
|
680
|
+
);
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
628
683
|
if (url) {
|
|
629
684
|
if (onNavigate) {
|
|
630
685
|
onNavigate(url);
|
|
@@ -1102,7 +1157,6 @@ function useChat({
|
|
|
1102
1157
|
if (persistKey) {
|
|
1103
1158
|
try {
|
|
1104
1159
|
sessionStorage.removeItem(`${persistKey}_msgs`);
|
|
1105
|
-
sessionStorage.removeItem(`${persistKey}_tid`);
|
|
1106
1160
|
localStorage.removeItem(`${persistKey}_tid`);
|
|
1107
1161
|
} catch {
|
|
1108
1162
|
}
|
|
@@ -3632,7 +3686,7 @@ function CommandPanel({
|
|
|
3632
3686
|
const hasContent = hasActions || hasDocs || hasTopics;
|
|
3633
3687
|
if (!hasContent) return null;
|
|
3634
3688
|
const isSidebar = mode === "sidebar";
|
|
3635
|
-
const handleExecute = (
|
|
3689
|
+
const handleExecute = (action) => onExecuteAction?.(action);
|
|
3636
3690
|
if (isSidebar) {
|
|
3637
3691
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ww-w-[300px] ww-shrink-0 ww-border-l ww-border-border ww-bg-muted/50 ww-flex ww-flex-col ww-h-full ww-overflow-hidden ww-animate-in ww-fade-in ww-slide-in-from-right-2 ww-duration-300", children: [
|
|
3638
3692
|
/* @__PURE__ */ jsxRuntime.jsx(PageBadge, { pageTitle, pageUrl, locale }),
|
|
@@ -3645,7 +3699,7 @@ function CommandPanel({
|
|
|
3645
3699
|
action,
|
|
3646
3700
|
index: i,
|
|
3647
3701
|
accentColor,
|
|
3648
|
-
onExecute: () => handleExecute(action
|
|
3702
|
+
onExecute: () => handleExecute(action)
|
|
3649
3703
|
},
|
|
3650
3704
|
actionKeys[i]
|
|
3651
3705
|
)) })
|
|
@@ -3717,7 +3771,7 @@ function CommandPanel({
|
|
|
3717
3771
|
action,
|
|
3718
3772
|
index: i,
|
|
3719
3773
|
accentColor,
|
|
3720
|
-
onExecute: () => handleExecute(action
|
|
3774
|
+
onExecute: () => handleExecute(action)
|
|
3721
3775
|
},
|
|
3722
3776
|
actionKeys[i]
|
|
3723
3777
|
)) })
|
|
@@ -3937,12 +3991,18 @@ function ChatWidget({
|
|
|
3937
3991
|
const messagesList = isDefaultGreeting ? [getWidgetTranslation("defaultGreeting", locale)] : initialMessages;
|
|
3938
3992
|
const showSidebar = showCommandPanel && widgetLayout === "center" && isDesktop;
|
|
3939
3993
|
const showInlineCommandPanel = showCommandPanel && !showSidebar && chat.messages.length === 0 && (showQuickActions && clientActions.length > 0 || showRagTopics && ragTopics.length > 0 || showRagDocuments && ragDocuments.length > 0);
|
|
3940
|
-
const handleExecuteAction =
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3994
|
+
const handleExecuteAction = (action) => {
|
|
3995
|
+
const plan = planQuickAction(
|
|
3996
|
+
action.steps,
|
|
3997
|
+
resolvePageContext()?.params,
|
|
3998
|
+
userContext?.metadata
|
|
3999
|
+
);
|
|
4000
|
+
if (plan.kind === "run") {
|
|
4001
|
+
executeDeclarativeSteps(plan.steps, onNavigate, userMessageColor);
|
|
4002
|
+
} else {
|
|
4003
|
+
chat.send(action.name);
|
|
4004
|
+
}
|
|
4005
|
+
};
|
|
3946
4006
|
const [activeActionIndex, setActiveActionIndex] = react.useState(-1);
|
|
3947
4007
|
const query = chat.input.toLowerCase().trim();
|
|
3948
4008
|
const matchingActions = react.useMemo(() => {
|
|
@@ -3988,7 +4048,7 @@ function ChatWidget({
|
|
|
3988
4048
|
e.preventDefault();
|
|
3989
4049
|
const selectedAction = matchingActions[activeActionIndex];
|
|
3990
4050
|
if (selectedAction) {
|
|
3991
|
-
handleExecuteAction(selectedAction
|
|
4051
|
+
handleExecuteAction(selectedAction);
|
|
3992
4052
|
chat.setInput("");
|
|
3993
4053
|
}
|
|
3994
4054
|
} else if (e.key === "Escape") {
|
|
@@ -4223,7 +4283,7 @@ function ChatWidget({
|
|
|
4223
4283
|
"button",
|
|
4224
4284
|
{
|
|
4225
4285
|
onClick: () => {
|
|
4226
|
-
handleExecuteAction(action
|
|
4286
|
+
handleExecuteAction(action);
|
|
4227
4287
|
chat.setInput("");
|
|
4228
4288
|
},
|
|
4229
4289
|
className: cn(
|
package/dist/index.mjs
CHANGED
|
@@ -325,6 +325,55 @@ function applyUiEventToMessages(prev, proto, msgId) {
|
|
|
325
325
|
return copy;
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
// src/core/quick-action.ts
|
|
329
|
+
var BRACES = /\{\{(?:toolInput\.)?([a-zA-Z0-9_]+)\}\}|\{([a-zA-Z0-9_]+)\}/g;
|
|
330
|
+
var ROUTE = /\{\{(?:toolInput\.)?([a-zA-Z0-9_]+)\}\}|\{([a-zA-Z0-9_]+)\}|\[([a-zA-Z0-9_]+)\]|(?<=^|\/):([a-zA-Z0-9_]+)(?=[/?#]|$)/g;
|
|
331
|
+
function fill(text, pattern, sources, missing) {
|
|
332
|
+
return text.replace(pattern, (match, ...groups) => {
|
|
333
|
+
const key = groups.find((g) => typeof g === "string");
|
|
334
|
+
if (!key) return match;
|
|
335
|
+
for (const source of sources) {
|
|
336
|
+
const value = source?.[key];
|
|
337
|
+
if (typeof value === "string" && value !== "") return value;
|
|
338
|
+
if (typeof value === "number") return String(value);
|
|
339
|
+
}
|
|
340
|
+
missing?.add(key);
|
|
341
|
+
return match;
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
function fillPayload(value, sources) {
|
|
345
|
+
if (typeof value === "string") return fill(value, BRACES, sources);
|
|
346
|
+
if (Array.isArray(value)) return value.map((v) => fillPayload(v, sources));
|
|
347
|
+
if (value && typeof value === "object") {
|
|
348
|
+
return Object.fromEntries(
|
|
349
|
+
Object.entries(value).map(([k, v]) => [k, fillPayload(v, sources)])
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
return value;
|
|
353
|
+
}
|
|
354
|
+
function planQuickAction(steps, pageParams, metadata) {
|
|
355
|
+
const sources = [pageParams, metadata];
|
|
356
|
+
const missing = /* @__PURE__ */ new Set();
|
|
357
|
+
const filled = steps.map((original) => {
|
|
358
|
+
const step = original;
|
|
359
|
+
const out = { ...step };
|
|
360
|
+
if (typeof step.value === "string") {
|
|
361
|
+
out.value = step.action === "navigate" ? fill(step.value, ROUTE, sources, missing) : fill(step.value, BRACES, sources);
|
|
362
|
+
}
|
|
363
|
+
if (typeof step.selector === "string") {
|
|
364
|
+
out.selector = fill(step.selector, BRACES, sources);
|
|
365
|
+
}
|
|
366
|
+
if (step.payload !== void 0) {
|
|
367
|
+
out.payload = fillPayload(step.payload, sources);
|
|
368
|
+
}
|
|
369
|
+
return out;
|
|
370
|
+
});
|
|
371
|
+
return missing.size > 0 ? { kind: "ask_agent", missing: [...missing] } : { kind: "run", steps: filled };
|
|
372
|
+
}
|
|
373
|
+
function hasRoutePlaceholder(url) {
|
|
374
|
+
return new RegExp(ROUTE.source).test(url);
|
|
375
|
+
}
|
|
376
|
+
|
|
328
377
|
// src/core/declarative-actions.ts
|
|
329
378
|
function sanitizeSelector(selector) {
|
|
330
379
|
if (!selector || typeof selector !== "string") return null;
|
|
@@ -599,6 +648,12 @@ async function executeDeclarativeSteps(steps, onNavigate, copilotColor) {
|
|
|
599
648
|
}
|
|
600
649
|
case "navigate": {
|
|
601
650
|
const url = sanitizeUrl(step.value);
|
|
651
|
+
if (url && hasRoutePlaceholder(url)) {
|
|
652
|
+
console.warn(
|
|
653
|
+
"[Wallavi Widget] Blocked navigate with unfilled route params"
|
|
654
|
+
);
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
602
657
|
if (url) {
|
|
603
658
|
if (onNavigate) {
|
|
604
659
|
onNavigate(url);
|
|
@@ -1076,7 +1131,6 @@ function useChat({
|
|
|
1076
1131
|
if (persistKey) {
|
|
1077
1132
|
try {
|
|
1078
1133
|
sessionStorage.removeItem(`${persistKey}_msgs`);
|
|
1079
|
-
sessionStorage.removeItem(`${persistKey}_tid`);
|
|
1080
1134
|
localStorage.removeItem(`${persistKey}_tid`);
|
|
1081
1135
|
} catch {
|
|
1082
1136
|
}
|
|
@@ -3606,7 +3660,7 @@ function CommandPanel({
|
|
|
3606
3660
|
const hasContent = hasActions || hasDocs || hasTopics;
|
|
3607
3661
|
if (!hasContent) return null;
|
|
3608
3662
|
const isSidebar = mode === "sidebar";
|
|
3609
|
-
const handleExecute = (
|
|
3663
|
+
const handleExecute = (action) => onExecuteAction?.(action);
|
|
3610
3664
|
if (isSidebar) {
|
|
3611
3665
|
return /* @__PURE__ */ jsxs("div", { className: "ww-w-[300px] ww-shrink-0 ww-border-l ww-border-border ww-bg-muted/50 ww-flex ww-flex-col ww-h-full ww-overflow-hidden ww-animate-in ww-fade-in ww-slide-in-from-right-2 ww-duration-300", children: [
|
|
3612
3666
|
/* @__PURE__ */ jsx(PageBadge, { pageTitle, pageUrl, locale }),
|
|
@@ -3619,7 +3673,7 @@ function CommandPanel({
|
|
|
3619
3673
|
action,
|
|
3620
3674
|
index: i,
|
|
3621
3675
|
accentColor,
|
|
3622
|
-
onExecute: () => handleExecute(action
|
|
3676
|
+
onExecute: () => handleExecute(action)
|
|
3623
3677
|
},
|
|
3624
3678
|
actionKeys[i]
|
|
3625
3679
|
)) })
|
|
@@ -3691,7 +3745,7 @@ function CommandPanel({
|
|
|
3691
3745
|
action,
|
|
3692
3746
|
index: i,
|
|
3693
3747
|
accentColor,
|
|
3694
|
-
onExecute: () => handleExecute(action
|
|
3748
|
+
onExecute: () => handleExecute(action)
|
|
3695
3749
|
},
|
|
3696
3750
|
actionKeys[i]
|
|
3697
3751
|
)) })
|
|
@@ -3911,12 +3965,18 @@ function ChatWidget({
|
|
|
3911
3965
|
const messagesList = isDefaultGreeting ? [getWidgetTranslation("defaultGreeting", locale)] : initialMessages;
|
|
3912
3966
|
const showSidebar = showCommandPanel && widgetLayout === "center" && isDesktop;
|
|
3913
3967
|
const showInlineCommandPanel = showCommandPanel && !showSidebar && chat.messages.length === 0 && (showQuickActions && clientActions.length > 0 || showRagTopics && ragTopics.length > 0 || showRagDocuments && ragDocuments.length > 0);
|
|
3914
|
-
const handleExecuteAction =
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3968
|
+
const handleExecuteAction = (action) => {
|
|
3969
|
+
const plan = planQuickAction(
|
|
3970
|
+
action.steps,
|
|
3971
|
+
resolvePageContext()?.params,
|
|
3972
|
+
userContext?.metadata
|
|
3973
|
+
);
|
|
3974
|
+
if (plan.kind === "run") {
|
|
3975
|
+
executeDeclarativeSteps(plan.steps, onNavigate, userMessageColor);
|
|
3976
|
+
} else {
|
|
3977
|
+
chat.send(action.name);
|
|
3978
|
+
}
|
|
3979
|
+
};
|
|
3920
3980
|
const [activeActionIndex, setActiveActionIndex] = useState(-1);
|
|
3921
3981
|
const query = chat.input.toLowerCase().trim();
|
|
3922
3982
|
const matchingActions = useMemo(() => {
|
|
@@ -3962,7 +4022,7 @@ function ChatWidget({
|
|
|
3962
4022
|
e.preventDefault();
|
|
3963
4023
|
const selectedAction = matchingActions[activeActionIndex];
|
|
3964
4024
|
if (selectedAction) {
|
|
3965
|
-
handleExecuteAction(selectedAction
|
|
4025
|
+
handleExecuteAction(selectedAction);
|
|
3966
4026
|
chat.setInput("");
|
|
3967
4027
|
}
|
|
3968
4028
|
} else if (e.key === "Escape") {
|
|
@@ -4197,7 +4257,7 @@ function ChatWidget({
|
|
|
4197
4257
|
"button",
|
|
4198
4258
|
{
|
|
4199
4259
|
onClick: () => {
|
|
4200
|
-
handleExecuteAction(action
|
|
4260
|
+
handleExecuteAction(action);
|
|
4201
4261
|
chat.setInput("");
|
|
4202
4262
|
},
|
|
4203
4263
|
className: cn(
|
package/package.json
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"tsup": "^8.3.5",
|
|
23
23
|
"tsx": "^4.19.2",
|
|
24
24
|
"typescript": "^5.7.3",
|
|
25
|
-
"@wallavi/
|
|
26
|
-
"@wallavi/
|
|
25
|
+
"@wallavi/protocol": "0.0.1",
|
|
26
|
+
"@wallavi/typescript-config": "0.0.1"
|
|
27
27
|
},
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"private": false,
|
|
46
46
|
"types": "./dist/index.d.ts",
|
|
47
|
-
"version": "1.13.
|
|
47
|
+
"version": "1.13.3",
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "tsup && pnpm build:css",
|
|
50
50
|
"build:css": "tailwindcss -i ./src/styles.css -o ./dist/styles.css --config tailwind.config.cjs --minify",
|