@wallavi/widget 1.13.2 → 1.14.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/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +73 -16
- package/dist/index.mjs +73 -16
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -358,7 +358,10 @@ interface CommandPanelProps {
|
|
|
358
358
|
ragTopics?: RagTopicInfo[];
|
|
359
359
|
ragDocuments?: RagDocumentInfo[];
|
|
360
360
|
onSend: (text: string) => void;
|
|
361
|
-
onExecuteAction?: (
|
|
361
|
+
onExecuteAction?: (action: {
|
|
362
|
+
name: string;
|
|
363
|
+
steps: any[];
|
|
364
|
+
}) => void;
|
|
362
365
|
accentColor?: string;
|
|
363
366
|
isDark?: boolean;
|
|
364
367
|
watermark?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -358,7 +358,10 @@ interface CommandPanelProps {
|
|
|
358
358
|
ragTopics?: RagTopicInfo[];
|
|
359
359
|
ragDocuments?: RagDocumentInfo[];
|
|
360
360
|
onSend: (text: string) => void;
|
|
361
|
-
onExecuteAction?: (
|
|
361
|
+
onExecuteAction?: (action: {
|
|
362
|
+
name: string;
|
|
363
|
+
steps: any[];
|
|
364
|
+
}) => void;
|
|
362
365
|
accentColor?: string;
|
|
363
366
|
isDark?: boolean;
|
|
364
367
|
watermark?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -227,7 +227,7 @@ async function consumeStream(body, handler) {
|
|
|
227
227
|
function applyUiEventToMessages(prev, proto, msgId) {
|
|
228
228
|
let idx = prev.findIndex((m) => m.id === msgId);
|
|
229
229
|
if (idx === -1) {
|
|
230
|
-
if (proto.type === "finish" || proto.type === "debug-trace" || proto.type === "step-start" || proto.type === "step-end" || proto.type === "
|
|
230
|
+
if (proto.type === "finish" || proto.type === "debug-trace" || proto.type === "step-start" || proto.type === "step-end" || proto.type === "suggestions") {
|
|
231
231
|
return prev;
|
|
232
232
|
}
|
|
233
233
|
prev = [...prev, { id: msgId, role: "assistant", parts: [] }];
|
|
@@ -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);
|
|
@@ -846,10 +901,6 @@ function useChat({
|
|
|
846
901
|
}, [messages]);
|
|
847
902
|
const applyStreamEvent = react.useCallback(
|
|
848
903
|
(proto, msgId) => {
|
|
849
|
-
if (proto.type === "navigate") {
|
|
850
|
-
if (proto.path.startsWith("/")) onNavigateRef.current?.(proto.path);
|
|
851
|
-
return;
|
|
852
|
-
}
|
|
853
904
|
if (proto.type === "client-action") {
|
|
854
905
|
executeDeclarativeSteps(
|
|
855
906
|
proto.steps,
|
|
@@ -3631,7 +3682,7 @@ function CommandPanel({
|
|
|
3631
3682
|
const hasContent = hasActions || hasDocs || hasTopics;
|
|
3632
3683
|
if (!hasContent) return null;
|
|
3633
3684
|
const isSidebar = mode === "sidebar";
|
|
3634
|
-
const handleExecute = (
|
|
3685
|
+
const handleExecute = (action) => onExecuteAction?.(action);
|
|
3635
3686
|
if (isSidebar) {
|
|
3636
3687
|
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: [
|
|
3637
3688
|
/* @__PURE__ */ jsxRuntime.jsx(PageBadge, { pageTitle, pageUrl, locale }),
|
|
@@ -3644,7 +3695,7 @@ function CommandPanel({
|
|
|
3644
3695
|
action,
|
|
3645
3696
|
index: i,
|
|
3646
3697
|
accentColor,
|
|
3647
|
-
onExecute: () => handleExecute(action
|
|
3698
|
+
onExecute: () => handleExecute(action)
|
|
3648
3699
|
},
|
|
3649
3700
|
actionKeys[i]
|
|
3650
3701
|
)) })
|
|
@@ -3716,7 +3767,7 @@ function CommandPanel({
|
|
|
3716
3767
|
action,
|
|
3717
3768
|
index: i,
|
|
3718
3769
|
accentColor,
|
|
3719
|
-
onExecute: () => handleExecute(action
|
|
3770
|
+
onExecute: () => handleExecute(action)
|
|
3720
3771
|
},
|
|
3721
3772
|
actionKeys[i]
|
|
3722
3773
|
)) })
|
|
@@ -3936,12 +3987,18 @@ function ChatWidget({
|
|
|
3936
3987
|
const messagesList = isDefaultGreeting ? [getWidgetTranslation("defaultGreeting", locale)] : initialMessages;
|
|
3937
3988
|
const showSidebar = showCommandPanel && widgetLayout === "center" && isDesktop;
|
|
3938
3989
|
const showInlineCommandPanel = showCommandPanel && !showSidebar && chat.messages.length === 0 && (showQuickActions && clientActions.length > 0 || showRagTopics && ragTopics.length > 0 || showRagDocuments && ragDocuments.length > 0);
|
|
3939
|
-
const handleExecuteAction =
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3990
|
+
const handleExecuteAction = (action) => {
|
|
3991
|
+
const plan = planQuickAction(
|
|
3992
|
+
action.steps,
|
|
3993
|
+
resolvePageContext()?.params,
|
|
3994
|
+
userContext?.metadata
|
|
3995
|
+
);
|
|
3996
|
+
if (plan.kind === "run") {
|
|
3997
|
+
executeDeclarativeSteps(plan.steps, onNavigate, userMessageColor);
|
|
3998
|
+
} else {
|
|
3999
|
+
chat.send(action.name);
|
|
4000
|
+
}
|
|
4001
|
+
};
|
|
3945
4002
|
const [activeActionIndex, setActiveActionIndex] = react.useState(-1);
|
|
3946
4003
|
const query = chat.input.toLowerCase().trim();
|
|
3947
4004
|
const matchingActions = react.useMemo(() => {
|
|
@@ -3987,7 +4044,7 @@ function ChatWidget({
|
|
|
3987
4044
|
e.preventDefault();
|
|
3988
4045
|
const selectedAction = matchingActions[activeActionIndex];
|
|
3989
4046
|
if (selectedAction) {
|
|
3990
|
-
handleExecuteAction(selectedAction
|
|
4047
|
+
handleExecuteAction(selectedAction);
|
|
3991
4048
|
chat.setInput("");
|
|
3992
4049
|
}
|
|
3993
4050
|
} else if (e.key === "Escape") {
|
|
@@ -4222,7 +4279,7 @@ function ChatWidget({
|
|
|
4222
4279
|
"button",
|
|
4223
4280
|
{
|
|
4224
4281
|
onClick: () => {
|
|
4225
|
-
handleExecuteAction(action
|
|
4282
|
+
handleExecuteAction(action);
|
|
4226
4283
|
chat.setInput("");
|
|
4227
4284
|
},
|
|
4228
4285
|
className: cn(
|
package/dist/index.mjs
CHANGED
|
@@ -201,7 +201,7 @@ async function consumeStream(body, handler) {
|
|
|
201
201
|
function applyUiEventToMessages(prev, proto, msgId) {
|
|
202
202
|
let idx = prev.findIndex((m) => m.id === msgId);
|
|
203
203
|
if (idx === -1) {
|
|
204
|
-
if (proto.type === "finish" || proto.type === "debug-trace" || proto.type === "step-start" || proto.type === "step-end" || proto.type === "
|
|
204
|
+
if (proto.type === "finish" || proto.type === "debug-trace" || proto.type === "step-start" || proto.type === "step-end" || proto.type === "suggestions") {
|
|
205
205
|
return prev;
|
|
206
206
|
}
|
|
207
207
|
prev = [...prev, { id: msgId, role: "assistant", parts: [] }];
|
|
@@ -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);
|
|
@@ -820,10 +875,6 @@ function useChat({
|
|
|
820
875
|
}, [messages]);
|
|
821
876
|
const applyStreamEvent = useCallback(
|
|
822
877
|
(proto, msgId) => {
|
|
823
|
-
if (proto.type === "navigate") {
|
|
824
|
-
if (proto.path.startsWith("/")) onNavigateRef.current?.(proto.path);
|
|
825
|
-
return;
|
|
826
|
-
}
|
|
827
878
|
if (proto.type === "client-action") {
|
|
828
879
|
executeDeclarativeSteps(
|
|
829
880
|
proto.steps,
|
|
@@ -3605,7 +3656,7 @@ function CommandPanel({
|
|
|
3605
3656
|
const hasContent = hasActions || hasDocs || hasTopics;
|
|
3606
3657
|
if (!hasContent) return null;
|
|
3607
3658
|
const isSidebar = mode === "sidebar";
|
|
3608
|
-
const handleExecute = (
|
|
3659
|
+
const handleExecute = (action) => onExecuteAction?.(action);
|
|
3609
3660
|
if (isSidebar) {
|
|
3610
3661
|
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: [
|
|
3611
3662
|
/* @__PURE__ */ jsx(PageBadge, { pageTitle, pageUrl, locale }),
|
|
@@ -3618,7 +3669,7 @@ function CommandPanel({
|
|
|
3618
3669
|
action,
|
|
3619
3670
|
index: i,
|
|
3620
3671
|
accentColor,
|
|
3621
|
-
onExecute: () => handleExecute(action
|
|
3672
|
+
onExecute: () => handleExecute(action)
|
|
3622
3673
|
},
|
|
3623
3674
|
actionKeys[i]
|
|
3624
3675
|
)) })
|
|
@@ -3690,7 +3741,7 @@ function CommandPanel({
|
|
|
3690
3741
|
action,
|
|
3691
3742
|
index: i,
|
|
3692
3743
|
accentColor,
|
|
3693
|
-
onExecute: () => handleExecute(action
|
|
3744
|
+
onExecute: () => handleExecute(action)
|
|
3694
3745
|
},
|
|
3695
3746
|
actionKeys[i]
|
|
3696
3747
|
)) })
|
|
@@ -3910,12 +3961,18 @@ function ChatWidget({
|
|
|
3910
3961
|
const messagesList = isDefaultGreeting ? [getWidgetTranslation("defaultGreeting", locale)] : initialMessages;
|
|
3911
3962
|
const showSidebar = showCommandPanel && widgetLayout === "center" && isDesktop;
|
|
3912
3963
|
const showInlineCommandPanel = showCommandPanel && !showSidebar && chat.messages.length === 0 && (showQuickActions && clientActions.length > 0 || showRagTopics && ragTopics.length > 0 || showRagDocuments && ragDocuments.length > 0);
|
|
3913
|
-
const handleExecuteAction =
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3964
|
+
const handleExecuteAction = (action) => {
|
|
3965
|
+
const plan = planQuickAction(
|
|
3966
|
+
action.steps,
|
|
3967
|
+
resolvePageContext()?.params,
|
|
3968
|
+
userContext?.metadata
|
|
3969
|
+
);
|
|
3970
|
+
if (plan.kind === "run") {
|
|
3971
|
+
executeDeclarativeSteps(plan.steps, onNavigate, userMessageColor);
|
|
3972
|
+
} else {
|
|
3973
|
+
chat.send(action.name);
|
|
3974
|
+
}
|
|
3975
|
+
};
|
|
3919
3976
|
const [activeActionIndex, setActiveActionIndex] = useState(-1);
|
|
3920
3977
|
const query = chat.input.toLowerCase().trim();
|
|
3921
3978
|
const matchingActions = useMemo(() => {
|
|
@@ -3961,7 +4018,7 @@ function ChatWidget({
|
|
|
3961
4018
|
e.preventDefault();
|
|
3962
4019
|
const selectedAction = matchingActions[activeActionIndex];
|
|
3963
4020
|
if (selectedAction) {
|
|
3964
|
-
handleExecuteAction(selectedAction
|
|
4021
|
+
handleExecuteAction(selectedAction);
|
|
3965
4022
|
chat.setInput("");
|
|
3966
4023
|
}
|
|
3967
4024
|
} else if (e.key === "Escape") {
|
|
@@ -4196,7 +4253,7 @@ function ChatWidget({
|
|
|
4196
4253
|
"button",
|
|
4197
4254
|
{
|
|
4198
4255
|
onClick: () => {
|
|
4199
|
-
handleExecuteAction(action
|
|
4256
|
+
handleExecuteAction(action);
|
|
4200
4257
|
chat.setInput("");
|
|
4201
4258
|
},
|
|
4202
4259
|
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/typescript-config": "0.0.1",
|
|
26
|
+
"@wallavi/protocol": "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.
|
|
47
|
+
"version": "1.14.0",
|
|
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",
|