@copilotz/chat-ui 0.6.3 → 0.6.5

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.cjs CHANGED
@@ -542,6 +542,8 @@ var CollapsibleContent2 = CollapsiblePrimitive.CollapsibleContent;
542
542
  // src/components/chat/AssistantActivity.tsx
543
543
  var import_lucide_react = require("lucide-react");
544
544
  var import_jsx_runtime7 = require("react/jsx-runtime");
545
+ var ROOT_SPACING_CLASS = "mb-4 w-full max-w-full min-w-0";
546
+ var ACTION_SLOT_CLASS = "inline-flex h-9 min-w-[132px] items-center justify-end px-2 text-xs";
545
547
  var interpolate = (template, replacements) => Object.entries(replacements).reduce(
546
548
  (output, [key, value]) => output.replaceAll(`{{${key}}}`, String(value ?? "")),
547
549
  template
@@ -569,45 +571,65 @@ var resolveSummaryLabel = (activity, labels) => {
569
571
  }
570
572
  return labels?.activityThinking || "Thinking...";
571
573
  };
572
- var getStatusIcon = (toolCall) => {
574
+ var getStatusBadge = (toolCall) => {
573
575
  if (toolCall.status === "failed") {
574
576
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { variant: "destructive", children: "failed" });
575
577
  }
576
578
  if (toolCall.status === "completed") {
577
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { variant: "secondary", className: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300", children: "done" });
579
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
580
+ Badge,
581
+ {
582
+ variant: "secondary",
583
+ className: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
584
+ children: "done"
585
+ }
586
+ );
578
587
  }
579
588
  if (toolCall.status === "running") {
580
589
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { variant: "secondary", className: "bg-primary/10 text-primary", children: "running" });
581
590
  }
582
591
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { variant: "secondary", children: "pending" });
583
592
  };
584
- var AssistantActivitySkeleton = (0, import_react.memo)(function AssistantActivitySkeleton2() {
585
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-border/50 bg-muted/20 px-3 py-2", children: [
586
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1.5", children: [
587
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/80 animate-pulse" }),
588
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/60 animate-pulse [animation-delay:120ms]" }),
589
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40 animate-pulse [animation-delay:240ms]" })
590
- ] }),
591
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-3 w-28 rounded-full bg-muted animate-pulse" })
592
- ] });
593
- });
594
- var AssistantActivitySummary = (0, import_react.memo)(function AssistantActivitySummary2({
593
+ var ActivitySummaryCard = (0, import_react.memo)(function ActivitySummaryCard2({
595
594
  activity,
596
595
  labels
597
596
  }) {
598
- const summaryLabel = (0, import_react.useMemo)(() => resolveSummaryLabel(activity, labels), [activity, labels]);
597
+ const label = (0, import_react.useMemo)(() => resolveSummaryLabel(activity, labels), [activity, labels]);
599
598
  const isActive = activity.isActive;
600
599
  const icon = activity.summary.kind === "using_tools" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.Wrench, { className: cn("h-4 w-4 shrink-0", isActive ? "text-primary" : "text-muted-foreground") }) : activity.summary.kind === "preparing_answer" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.Sparkles, { className: cn("h-4 w-4 shrink-0", isActive ? "text-primary" : "text-muted-foreground") }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.Brain, { className: cn("h-4 w-4 shrink-0", isActive ? "text-primary" : "text-muted-foreground") });
601
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cn(
602
- "flex w-full min-w-0 items-center gap-2 rounded-lg border px-3 py-2 text-sm transition-colors",
603
- isActive ? "border-primary/30 bg-primary/5 text-foreground" : "border-border/60 bg-muted/20 text-muted-foreground"
604
- ), children: [
605
- icon,
606
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "min-w-0 flex-1 truncate", children: summaryLabel }),
607
- isActive && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.LoaderCircle, { className: "h-4 w-4 shrink-0 animate-spin text-primary" })
600
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
601
+ "div",
602
+ {
603
+ className: cn(
604
+ "flex w-full min-w-0 items-center gap-2 rounded-lg border px-3 py-2 text-sm transition-colors",
605
+ isActive ? "border-primary/30 bg-primary/5 text-foreground" : "border-border/60 bg-muted/20 text-muted-foreground"
606
+ ),
607
+ children: [
608
+ icon,
609
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "min-w-0 flex-1 truncate", children: label }),
610
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.LoaderCircle, { className: "h-4 w-4 shrink-0 animate-spin text-primary" })
611
+ ]
612
+ }
613
+ );
614
+ });
615
+ var ActivitySummaryRow = (0, import_react.memo)(function ActivitySummaryRow2({
616
+ activity,
617
+ labels,
618
+ hasDetails,
619
+ open
620
+ }) {
621
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid w-full min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2", children: [
622
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ActivitySummaryCard, { activity, labels }) }),
623
+ hasDetails ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Button, { variant: "ghost", size: "sm", className: cn(ACTION_SLOT_CLASS, "shrink-0 text-muted-foreground"), children: [
624
+ open ? labels?.activityHideDetails || "Hide details" : labels?.activityShowDetails || "Show details",
625
+ open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.ChevronDown, { className: "ml-1 h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.ChevronRight, { className: "ml-1 h-3.5 w-3.5" })
626
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { "aria-hidden": "true", className: cn(ACTION_SLOT_CLASS, "pointer-events-none invisible shrink-0"), children: [
627
+ labels?.activityShowDetails || "Show details",
628
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.ChevronRight, { className: "ml-1 h-3.5 w-3.5" })
629
+ ] })
608
630
  ] });
609
631
  });
610
- var AssistantActivityDetails = (0, import_react.memo)(function AssistantActivityDetails2({
632
+ var ActivityDetails = (0, import_react.memo)(function ActivityDetails2({
611
633
  activity
612
634
  }) {
613
635
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-3 pt-3", children: [
@@ -620,7 +642,7 @@ var AssistantActivityDetails = (0, import_react.memo)(function AssistantActivity
620
642
  activity.toolCalls.map((toolCall) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Card, { className: "border-border/60 bg-background/70", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(CardContent, { className: "space-y-2 px-3 py-3", children: [
621
643
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between gap-3", children: [
622
644
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "truncate text-sm font-medium", children: toolCall.name }) }),
623
- getStatusIcon(toolCall)
645
+ getStatusBadge(toolCall)
624
646
  ] }),
625
647
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-2", children: [
626
648
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
@@ -636,6 +658,16 @@ var AssistantActivityDetails = (0, import_react.memo)(function AssistantActivity
636
658
  ] })
637
659
  ] });
638
660
  });
661
+ var ActivitySkeleton = (0, import_react.memo)(function ActivitySkeleton2() {
662
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: ROOT_SPACING_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex w-full min-w-0 items-center gap-3 rounded-lg border border-border/50 bg-muted/20 px-3 py-2", children: [
663
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1.5", children: [
664
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/80 animate-pulse" }),
665
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/60 animate-pulse [animation-delay:120ms]" }),
666
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-block h-2 w-2 rounded-full bg-primary/40 animate-pulse [animation-delay:240ms]" })
667
+ ] }),
668
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "h-3 w-28 rounded-full bg-muted animate-pulse" })
669
+ ] }) });
670
+ });
639
671
  var AssistantActivity = (0, import_react.memo)(function AssistantActivity2({
640
672
  activity,
641
673
  displayMode,
@@ -643,30 +675,41 @@ var AssistantActivity = (0, import_react.memo)(function AssistantActivity2({
643
675
  }) {
644
676
  if (!activity) return null;
645
677
  if (displayMode === "hidden") {
646
- return activity.isActive ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AssistantActivitySkeleton, {}) : null;
678
+ return activity.isActive ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ActivitySkeleton, {}) : null;
647
679
  }
648
680
  if (displayMode === "summary") {
649
- if (!activity.isActive && activity.isComplete) return null;
650
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mb-4 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AssistantActivitySummary, { activity, labels }) });
681
+ if (!activity.isActive && activity.isComplete) {
682
+ return null;
683
+ }
684
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: ROOT_SPACING_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ActivitySummaryCard, { activity, labels }) });
651
685
  }
652
686
  const hasDetails = Boolean(activity.reasoning) || Boolean(activity.toolCalls?.length);
653
- const defaultOpen = activity.isActive && hasDetails;
654
- const [open, setOpen] = (0, import_react.useState)(defaultOpen);
687
+ const [open, setOpen] = (0, import_react.useState)(activity.isActive && hasDetails);
655
688
  (0, import_react.useEffect)(() => {
656
689
  if (activity.isActive && hasDetails) {
657
690
  setOpen(true);
658
691
  }
659
692
  }, [activity.isActive, hasDetails]);
660
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mb-4 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Collapsible, { open, onOpenChange: setOpen, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-2", children: [
661
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-2", children: [
662
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "min-w-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AssistantActivitySummary, { activity, labels }) }),
663
- hasDetails && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Button, { variant: "ghost", size: "sm", className: "h-9 shrink-0 px-2 text-xs text-muted-foreground", children: [
664
- open ? labels?.activityHideDetails || "Hide details" : labels?.activityShowDetails || "Show details",
665
- open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.ChevronDown, { className: "ml-1 h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.ChevronRight, { className: "ml-1 h-3.5 w-3.5" })
666
- ] }) })
667
- ] }),
668
- hasDetails && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapsibleContent2, { className: "overflow-hidden rounded-lg border border-border/60 bg-muted/10 px-3", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AssistantActivityDetails, { activity }) })
669
- ] }) }) });
693
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
694
+ Collapsible,
695
+ {
696
+ open: hasDetails ? open : false,
697
+ onOpenChange: hasDetails ? setOpen : void 0,
698
+ className: ROOT_SPACING_CLASS,
699
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-2", children: [
700
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
701
+ ActivitySummaryRow,
702
+ {
703
+ activity,
704
+ labels,
705
+ hasDetails,
706
+ open
707
+ }
708
+ ),
709
+ hasDetails && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CollapsibleContent2, { className: "w-full overflow-hidden rounded-lg border border-border/60 bg-muted/10 px-3", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ActivityDetails, { activity }) })
710
+ ] })
711
+ }
712
+ );
670
713
  });
671
714
 
672
715
  // src/components/chat/Message.tsx
@@ -5004,6 +5047,25 @@ function getMessageSpeakerKey(message) {
5004
5047
  }
5005
5048
  return message.role;
5006
5049
  }
5050
+ function getAssistantSpeakerTokens(message) {
5051
+ if (!message || message.role !== "assistant") return [];
5052
+ const rawTokens = [message.senderAgentId, message.senderName].filter((value) => typeof value === "string" && value.trim().length > 0).map((value) => value.trim().toLowerCase());
5053
+ if (rawTokens.length > 0) {
5054
+ return Array.from(new Set(rawTokens));
5055
+ }
5056
+ return ["assistant"];
5057
+ }
5058
+ function canGroupMessages(previous, next) {
5059
+ if (previous.role !== next.role) {
5060
+ return false;
5061
+ }
5062
+ if (previous.role !== "assistant") {
5063
+ return getMessageSpeakerKey(previous) === getMessageSpeakerKey(next);
5064
+ }
5065
+ const previousTokens = getAssistantSpeakerTokens(previous);
5066
+ const nextTokens = getAssistantSpeakerTokens(next);
5067
+ return previousTokens.some((token) => nextTokens.includes(token));
5068
+ }
5007
5069
  var mergeToolCalls = (activities) => {
5008
5070
  const merged = /* @__PURE__ */ new Map();
5009
5071
  for (const activity of activities) {
@@ -5069,7 +5131,7 @@ var groupMessagesForRender = (messages) => {
5069
5131
  for (let index = 1; index < messages.length; index++) {
5070
5132
  const previous = currentGroup[currentGroup.length - 1];
5071
5133
  const next = messages[index];
5072
- if (previous.role === next.role && getMessageSpeakerKey(previous) === getMessageSpeakerKey(next)) {
5134
+ if (canGroupMessages(previous, next)) {
5073
5135
  currentGroup.push(next);
5074
5136
  continue;
5075
5137
  }