@wallavi/widget 1.6.1 → 1.6.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 CHANGED
@@ -21,13 +21,25 @@ type PickerPart = {
21
21
  }>;
22
22
  selectedValue?: string;
23
23
  };
24
+ type PlanStepState = {
25
+ index: number;
26
+ description: string;
27
+ status: "pending" | "executing" | "success" | "failed";
28
+ error?: string;
29
+ };
30
+ type PlanPart = {
31
+ type: "plan";
32
+ planId: string;
33
+ goal: string;
34
+ steps: PlanStepState[];
35
+ };
24
36
  type MessagePart = {
25
37
  type: "text";
26
38
  text: string;
27
39
  } | {
28
40
  type: "reasoning";
29
41
  text: string;
30
- } | ToolPart | PickerPart;
42
+ } | ToolPart | PickerPart | PlanPart;
31
43
  type Message = {
32
44
  id: string;
33
45
  role: "user" | "assistant";
package/dist/index.d.ts CHANGED
@@ -21,13 +21,25 @@ type PickerPart = {
21
21
  }>;
22
22
  selectedValue?: string;
23
23
  };
24
+ type PlanStepState = {
25
+ index: number;
26
+ description: string;
27
+ status: "pending" | "executing" | "success" | "failed";
28
+ error?: string;
29
+ };
30
+ type PlanPart = {
31
+ type: "plan";
32
+ planId: string;
33
+ goal: string;
34
+ steps: PlanStepState[];
35
+ };
24
36
  type MessagePart = {
25
37
  type: "text";
26
38
  text: string;
27
39
  } | {
28
40
  type: "reasoning";
29
41
  text: string;
30
- } | ToolPart | PickerPart;
42
+ } | ToolPart | PickerPart | PlanPart;
31
43
  type Message = {
32
44
  id: string;
33
45
  role: "user" | "assistant";
package/dist/index.js CHANGED
@@ -205,6 +205,30 @@ function useChat({
205
205
  });
206
206
  break;
207
207
  }
208
+ case "plan-created": {
209
+ msg.parts.push({
210
+ type: "plan",
211
+ planId: proto.planId,
212
+ goal: proto.goal,
213
+ steps: proto.steps.map((s) => ({ ...s, status: "pending" }))
214
+ });
215
+ break;
216
+ }
217
+ case "plan-step-update": {
218
+ const pIdx = msg.parts.findIndex(
219
+ (p) => p.type === "plan" && p.planId === proto.planId
220
+ );
221
+ if (pIdx !== -1) {
222
+ const prev2 = msg.parts[pIdx];
223
+ msg.parts[pIdx] = {
224
+ ...prev2,
225
+ steps: prev2.steps.map(
226
+ (s) => s.index === proto.stepIndex ? { ...s, status: proto.status, ...proto.error ? { error: proto.error } : {} } : s
227
+ )
228
+ };
229
+ }
230
+ break;
231
+ }
208
232
  }
209
233
  const copy = [...prev];
210
234
  copy[idx] = msg;
@@ -717,6 +741,60 @@ function SentAttachments({ attachments, contrastColor }) {
717
741
  )) })
718
742
  ] });
719
743
  }
744
+ function PlanStepIcon({ status }) {
745
+ if (status === "executing") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 animate-spin text-primary" });
746
+ if (status === "success") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-3 w-3 text-emerald-500" });
747
+ if (status === "failed") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-3 w-3 text-destructive" });
748
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-3 rounded-full border-2 border-muted-foreground/30" });
749
+ }
750
+ function PlanCard({ part }) {
751
+ const successCount = part.steps.filter((s) => s.status === "success").length;
752
+ const hasExecuting = part.steps.some((s) => s.status === "executing");
753
+ const allDone = successCount === part.steps.length && part.steps.length > 0;
754
+ const anyFailed = part.steps.some((s) => s.status === "failed");
755
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border bg-background overflow-hidden text-xs w-full shadow-sm", children: [
756
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-2 bg-muted/50 border-b", children: [
757
+ hasExecuting ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 shrink-0 animate-spin text-primary/80" }) : allDone ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-3.5 w-3.5 shrink-0 text-emerald-500" }) : anyFailed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-3.5 w-3.5 shrink-0 text-destructive" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Zap, { className: "h-3.5 w-3.5 shrink-0 text-primary/70" }),
758
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground/80 truncate flex-1 leading-snug", children: part.goal }),
759
+ part.steps.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: [
760
+ successCount,
761
+ "/",
762
+ part.steps.length
763
+ ] })
764
+ ] }),
765
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-border/40", children: part.steps.map((step) => /* @__PURE__ */ jsxRuntime.jsxs(
766
+ "div",
767
+ {
768
+ className: cn(
769
+ "flex items-start gap-2.5 px-3 py-2 transition-colors duration-200",
770
+ step.status === "executing" && "bg-primary/5"
771
+ ),
772
+ children: [
773
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(PlanStepIcon, { status: step.status }) }),
774
+ /* @__PURE__ */ jsxRuntime.jsxs(
775
+ "span",
776
+ {
777
+ className: cn(
778
+ "leading-relaxed",
779
+ step.status === "pending" && "text-muted-foreground",
780
+ step.status === "executing" && "text-foreground font-medium",
781
+ step.status === "success" && "text-foreground/60 line-through decoration-foreground/20",
782
+ step.status === "failed" && "text-destructive"
783
+ ),
784
+ children: [
785
+ step.index + 1,
786
+ ". ",
787
+ step.description,
788
+ step.error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-destructive/70 text-[10px] mt-0.5 no-underline", children: step.error })
789
+ ]
790
+ }
791
+ )
792
+ ]
793
+ },
794
+ step.index
795
+ )) })
796
+ ] });
797
+ }
720
798
  function ThinkingDots() {
721
799
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
722
800
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
@@ -905,6 +983,7 @@ function MessageBubble({
905
983
  const reasoningPart = message.parts.find((p) => p.type === "reasoning");
906
984
  const toolParts = message.parts.filter((p) => p.type === "tool");
907
985
  const pickerParts = message.parts.filter((p) => p.type === "picker");
986
+ const planParts = message.parts.filter((p) => p.type === "plan");
908
987
  const contrastColor = getContrastColor(userColor);
909
988
  if (isUser) {
910
989
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -925,6 +1004,7 @@ function MessageBubble({
925
1004
  /* @__PURE__ */ jsxRuntime.jsx(Avatar2, { style: { width: 28, height: 28, marginTop: 2, border: "1px solid rgba(0,0,0,0.08)" }, children: profilePicture ? /* @__PURE__ */ jsxRuntime.jsx(AvatarImage2, { src: profilePicture, alt: agentName }) : /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback2, { style: { fontSize: 10, fontWeight: 600, backgroundColor: "var(--primary, #19191c)", color: "var(--primary-foreground, #fff)" }, children: agentName.slice(0, 2).toUpperCase() }) }),
926
1005
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5 min-w-0 max-w-[82%]", children: [
927
1006
  showThinking && reasoningPart && /* @__PURE__ */ jsxRuntime.jsx(ReasoningBlock, { text: reasoningPart.text }),
1007
+ planParts.map((p) => /* @__PURE__ */ jsxRuntime.jsx(PlanCard, { part: p }, p.planId)),
928
1008
  visibleToolParts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallBadge, { part: t }, t.toolCallId)),
929
1009
  pickerParts.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
930
1010
  PickerSelector,
@@ -1253,6 +1333,22 @@ function ChatWidget({
1253
1333
  chat.reset();
1254
1334
  onReset?.();
1255
1335
  };
1336
+ const isDark = theme === "dark";
1337
+ const cssVars = {
1338
+ colorScheme: theme,
1339
+ ["--background"]: isDark ? "240 10% 3.9%" : "0 0% 100%",
1340
+ ["--foreground"]: isDark ? "0 0% 98%" : "240 10% 3.9%",
1341
+ ["--muted"]: isDark ? "240 3.7% 15.9%" : "240 4.8% 95.9%",
1342
+ ["--muted-foreground"]: isDark ? "240 5% 64.9%" : "240 3.8% 46.1%",
1343
+ ["--accent"]: isDark ? "240 3.7% 15.9%" : "240 4.8% 95.9%",
1344
+ ["--accent-foreground"]: isDark ? "0 0% 98%" : "240 5.9% 10%",
1345
+ ["--border"]: isDark ? "240 3.7% 15.9%" : "240 5.9% 90%",
1346
+ ["--input"]: isDark ? "240 3.7% 15.9%" : "240 5.9% 90%",
1347
+ ["--primary"]: isDark ? "0 0% 98%" : "240 5.9% 10%",
1348
+ ["--primary-foreground"]: isDark ? "240 5.9% 10%" : "0 0% 98%",
1349
+ ["--ring"]: isDark ? "240 4.9% 83.9%" : "240 10% 3.9%",
1350
+ ["--radius"]: "0.5rem"
1351
+ };
1256
1352
  return /* @__PURE__ */ jsxRuntime.jsxs(
1257
1353
  "div",
1258
1354
  {
@@ -1261,7 +1357,7 @@ function ChatWidget({
1261
1357
  isDragOver && "ring-2 ring-inset ring-primary/60",
1262
1358
  className
1263
1359
  ),
1264
- style: { colorScheme: theme },
1360
+ style: cssVars,
1265
1361
  onDragOver: handleDragOver,
1266
1362
  onDragEnter: handleDragOver,
1267
1363
  onDragLeave: handleDragLeave,
package/dist/index.mjs CHANGED
@@ -179,6 +179,30 @@ function useChat({
179
179
  });
180
180
  break;
181
181
  }
182
+ case "plan-created": {
183
+ msg.parts.push({
184
+ type: "plan",
185
+ planId: proto.planId,
186
+ goal: proto.goal,
187
+ steps: proto.steps.map((s) => ({ ...s, status: "pending" }))
188
+ });
189
+ break;
190
+ }
191
+ case "plan-step-update": {
192
+ const pIdx = msg.parts.findIndex(
193
+ (p) => p.type === "plan" && p.planId === proto.planId
194
+ );
195
+ if (pIdx !== -1) {
196
+ const prev2 = msg.parts[pIdx];
197
+ msg.parts[pIdx] = {
198
+ ...prev2,
199
+ steps: prev2.steps.map(
200
+ (s) => s.index === proto.stepIndex ? { ...s, status: proto.status, ...proto.error ? { error: proto.error } : {} } : s
201
+ )
202
+ };
203
+ }
204
+ break;
205
+ }
182
206
  }
183
207
  const copy = [...prev];
184
208
  copy[idx] = msg;
@@ -691,6 +715,60 @@ function SentAttachments({ attachments, contrastColor }) {
691
715
  )) })
692
716
  ] });
693
717
  }
718
+ function PlanStepIcon({ status }) {
719
+ if (status === "executing") return /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 animate-spin text-primary" });
720
+ if (status === "success") return /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3 text-emerald-500" });
721
+ if (status === "failed") return /* @__PURE__ */ jsx(AlertCircle, { className: "h-3 w-3 text-destructive" });
722
+ return /* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full border-2 border-muted-foreground/30" });
723
+ }
724
+ function PlanCard({ part }) {
725
+ const successCount = part.steps.filter((s) => s.status === "success").length;
726
+ const hasExecuting = part.steps.some((s) => s.status === "executing");
727
+ const allDone = successCount === part.steps.length && part.steps.length > 0;
728
+ const anyFailed = part.steps.some((s) => s.status === "failed");
729
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-background overflow-hidden text-xs w-full shadow-sm", children: [
730
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 bg-muted/50 border-b", children: [
731
+ hasExecuting ? /* @__PURE__ */ jsx(Loader2, { className: "h-3.5 w-3.5 shrink-0 animate-spin text-primary/80" }) : allDone ? /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3.5 w-3.5 shrink-0 text-emerald-500" }) : anyFailed ? /* @__PURE__ */ jsx(AlertCircle, { className: "h-3.5 w-3.5 shrink-0 text-destructive" }) : /* @__PURE__ */ jsx(Zap, { className: "h-3.5 w-3.5 shrink-0 text-primary/70" }),
732
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground/80 truncate flex-1 leading-snug", children: part.goal }),
733
+ part.steps.length > 0 && /* @__PURE__ */ jsxs("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: [
734
+ successCount,
735
+ "/",
736
+ part.steps.length
737
+ ] })
738
+ ] }),
739
+ /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/40", children: part.steps.map((step) => /* @__PURE__ */ jsxs(
740
+ "div",
741
+ {
742
+ className: cn(
743
+ "flex items-start gap-2.5 px-3 py-2 transition-colors duration-200",
744
+ step.status === "executing" && "bg-primary/5"
745
+ ),
746
+ children: [
747
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5 shrink-0", children: /* @__PURE__ */ jsx(PlanStepIcon, { status: step.status }) }),
748
+ /* @__PURE__ */ jsxs(
749
+ "span",
750
+ {
751
+ className: cn(
752
+ "leading-relaxed",
753
+ step.status === "pending" && "text-muted-foreground",
754
+ step.status === "executing" && "text-foreground font-medium",
755
+ step.status === "success" && "text-foreground/60 line-through decoration-foreground/20",
756
+ step.status === "failed" && "text-destructive"
757
+ ),
758
+ children: [
759
+ step.index + 1,
760
+ ". ",
761
+ step.description,
762
+ step.error && /* @__PURE__ */ jsx("span", { className: "block text-destructive/70 text-[10px] mt-0.5 no-underline", children: step.error })
763
+ ]
764
+ }
765
+ )
766
+ ]
767
+ },
768
+ step.index
769
+ )) })
770
+ ] });
771
+ }
694
772
  function ThinkingDots() {
695
773
  return /* @__PURE__ */ jsxs(Fragment, { children: [
696
774
  /* @__PURE__ */ jsx("style", { children: `
@@ -879,6 +957,7 @@ function MessageBubble({
879
957
  const reasoningPart = message.parts.find((p) => p.type === "reasoning");
880
958
  const toolParts = message.parts.filter((p) => p.type === "tool");
881
959
  const pickerParts = message.parts.filter((p) => p.type === "picker");
960
+ const planParts = message.parts.filter((p) => p.type === "plan");
882
961
  const contrastColor = getContrastColor(userColor);
883
962
  if (isUser) {
884
963
  return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
@@ -899,6 +978,7 @@ function MessageBubble({
899
978
  /* @__PURE__ */ jsx(Avatar2, { style: { width: 28, height: 28, marginTop: 2, border: "1px solid rgba(0,0,0,0.08)" }, children: profilePicture ? /* @__PURE__ */ jsx(AvatarImage2, { src: profilePicture, alt: agentName }) : /* @__PURE__ */ jsx(AvatarFallback2, { style: { fontSize: 10, fontWeight: 600, backgroundColor: "var(--primary, #19191c)", color: "var(--primary-foreground, #fff)" }, children: agentName.slice(0, 2).toUpperCase() }) }),
900
979
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 min-w-0 max-w-[82%]", children: [
901
980
  showThinking && reasoningPart && /* @__PURE__ */ jsx(ReasoningBlock, { text: reasoningPart.text }),
981
+ planParts.map((p) => /* @__PURE__ */ jsx(PlanCard, { part: p }, p.planId)),
902
982
  visibleToolParts.map((t) => /* @__PURE__ */ jsx(ToolCallBadge, { part: t }, t.toolCallId)),
903
983
  pickerParts.map((p) => /* @__PURE__ */ jsx(
904
984
  PickerSelector,
@@ -1227,6 +1307,22 @@ function ChatWidget({
1227
1307
  chat.reset();
1228
1308
  onReset?.();
1229
1309
  };
1310
+ const isDark = theme === "dark";
1311
+ const cssVars = {
1312
+ colorScheme: theme,
1313
+ ["--background"]: isDark ? "240 10% 3.9%" : "0 0% 100%",
1314
+ ["--foreground"]: isDark ? "0 0% 98%" : "240 10% 3.9%",
1315
+ ["--muted"]: isDark ? "240 3.7% 15.9%" : "240 4.8% 95.9%",
1316
+ ["--muted-foreground"]: isDark ? "240 5% 64.9%" : "240 3.8% 46.1%",
1317
+ ["--accent"]: isDark ? "240 3.7% 15.9%" : "240 4.8% 95.9%",
1318
+ ["--accent-foreground"]: isDark ? "0 0% 98%" : "240 5.9% 10%",
1319
+ ["--border"]: isDark ? "240 3.7% 15.9%" : "240 5.9% 90%",
1320
+ ["--input"]: isDark ? "240 3.7% 15.9%" : "240 5.9% 90%",
1321
+ ["--primary"]: isDark ? "0 0% 98%" : "240 5.9% 10%",
1322
+ ["--primary-foreground"]: isDark ? "240 5.9% 10%" : "0 0% 98%",
1323
+ ["--ring"]: isDark ? "240 4.9% 83.9%" : "240 10% 3.9%",
1324
+ ["--radius"]: "0.5rem"
1325
+ };
1230
1326
  return /* @__PURE__ */ jsxs(
1231
1327
  "div",
1232
1328
  {
@@ -1235,7 +1331,7 @@ function ChatWidget({
1235
1331
  isDragOver && "ring-2 ring-inset ring-primary/60",
1236
1332
  className
1237
1333
  ),
1238
- style: { colorScheme: theme },
1334
+ style: cssVars,
1239
1335
  onDragOver: handleDragOver,
1240
1336
  onDragEnter: handleDragOver,
1241
1337
  onDragLeave: handleDragLeave,
package/package.json CHANGED
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "private": false,
35
35
  "types": "./dist/index.d.ts",
36
- "version": "1.6.1",
36
+ "version": "1.6.3",
37
37
  "scripts": {
38
38
  "build": "tsup",
39
39
  "typecheck": "tsc --noEmit"