@copilotz/chat-ui 0.1.23 → 0.1.24

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.cts CHANGED
@@ -38,8 +38,6 @@ interface ChatMessage {
38
38
  id: string;
39
39
  role: 'user' | 'assistant' | 'system';
40
40
  content: string;
41
- /** Optional model reasoning stream (when the backend emits reasoning tokens separately). */
42
- reasoning?: string;
43
41
  timestamp: number;
44
42
  attachments?: MediaAttachment[];
45
43
  isStreaming?: boolean;
@@ -49,6 +47,10 @@ interface ChatMessage {
49
47
  editedAt?: number;
50
48
  toolCalls?: ToolCall[];
51
49
  metadata?: Record<string, any>;
50
+ /** Model reasoning/thinking content (displayed in a collapsible block) */
51
+ reasoning?: string;
52
+ /** Whether reasoning tokens are still being streamed */
53
+ isReasoningStreaming?: boolean;
52
54
  }
53
55
  interface ChatThread {
54
56
  id: string;
package/dist/index.d.ts CHANGED
@@ -38,8 +38,6 @@ interface ChatMessage {
38
38
  id: string;
39
39
  role: 'user' | 'assistant' | 'system';
40
40
  content: string;
41
- /** Optional model reasoning stream (when the backend emits reasoning tokens separately). */
42
- reasoning?: string;
43
41
  timestamp: number;
44
42
  attachments?: MediaAttachment[];
45
43
  isStreaming?: boolean;
@@ -49,6 +47,10 @@ interface ChatMessage {
49
47
  editedAt?: number;
50
48
  toolCalls?: ToolCall[];
51
49
  metadata?: Record<string, any>;
50
+ /** Model reasoning/thinking content (displayed in a collapsible block) */
51
+ reasoning?: string;
52
+ /** Whether reasoning tokens are still being streamed */
53
+ isReasoningStreaming?: boolean;
52
54
  }
53
55
  interface ChatThread {
54
56
  id: string;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/chat/ChatUI.tsx
2
- import { useState as useState8, useEffect as useEffect10, useRef as useRef7, useCallback as useCallback4, useMemo as useMemo4 } from "react";
2
+ import { useState as useState8, useEffect as useEffect10, useRef as useRef6, useCallback as useCallback4, useMemo as useMemo4 } from "react";
3
3
  import { useVirtualizer } from "@tanstack/react-virtual";
4
4
 
5
5
  // src/config/chatConfig.ts
@@ -245,7 +245,7 @@ var configUtils = {
245
245
  };
246
246
 
247
247
  // src/components/chat/Message.tsx
248
- import React, { useState, useMemo, useEffect, useRef, memo } from "react";
248
+ import React, { useState, useMemo, useEffect, memo } from "react";
249
249
  import ReactMarkdown from "react-markdown";
250
250
  import remarkGfm from "remark-gfm";
251
251
  import rehypeHighlight from "rehype-highlight";
@@ -554,7 +554,7 @@ import {
554
554
  Clock,
555
555
  ChevronRight,
556
556
  ChevronDown,
557
- BrainCircuit
557
+ Brain
558
558
  } from "lucide-react";
559
559
  import { Fragment, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
560
560
  var ThinkingIndicator = memo(function ThinkingIndicator2({ label = "Thinking..." }) {
@@ -585,88 +585,35 @@ var ThinkingIndicator = memo(function ThinkingIndicator2({ label = "Thinking..."
585
585
  /* @__PURE__ */ jsx7("span", { className: "text-sm text-muted-foreground animate-pulse", children: label })
586
586
  ] });
587
587
  });
588
- var ThinkingBlock = memo(function ThinkingBlock2({ content, isStreaming = false, label = "Thinking", chunkSize = 12e3 }) {
589
- const [open, setOpen] = useState(isStreaming);
590
- const [thinkingActive, setThinkingActive] = useState(false);
591
- const contentLenRef = useRef(0);
588
+ var ThinkingBlock = memo(function ThinkingBlock2({ reasoning, isStreaming = false, label = "Thinking..." }) {
589
+ const [isOpen, setIsOpen] = useState(isStreaming);
592
590
  useEffect(() => {
593
- if (!isStreaming) {
594
- setThinkingActive(false);
595
- contentLenRef.current = 0;
596
- return;
597
- }
598
- if (content.length > contentLenRef.current) {
599
- contentLenRef.current = content.length;
600
- setThinkingActive(true);
601
- }
602
- }, [content.length, isStreaming]);
603
- useEffect(() => {
604
- if (!thinkingActive || !isStreaming) return;
605
- const timer = setTimeout(() => setThinkingActive(false), 1e3);
606
- return () => clearTimeout(timer);
607
- }, [thinkingActive, isStreaming, content.length]);
608
- useEffect(() => {
609
- if (isStreaming && content.length > 0) setOpen(true);
610
- }, [isStreaming, content.length]);
611
- return /* @__PURE__ */ jsxs2("div", { className: "mb-3 relative rounded-lg overflow-hidden", children: [
612
- thinkingActive && /* @__PURE__ */ jsx7(
613
- "div",
614
- {
615
- className: "absolute inset-0 rounded-lg pointer-events-none",
616
- style: {
617
- padding: "1px",
618
- background: "linear-gradient(135deg, hsl(var(--primary) / 0.4), hsl(var(--muted-foreground) / 0.2), hsl(var(--primary) / 0.4))",
619
- backgroundSize: "200% 200%",
620
- animation: "thinking-shimmer 2s ease-in-out infinite"
621
- }
622
- }
623
- ),
591
+ if (isStreaming) setIsOpen(true);
592
+ }, [isStreaming]);
593
+ const finishedLabel = label.replace(/\.{3}$/, "");
594
+ return /* @__PURE__ */ jsxs2("div", { className: `mb-3 rounded-lg border ${isStreaming ? "border-primary/40 bg-primary/5" : "border-border/60 bg-muted/30"} overflow-hidden transition-colors duration-300`, children: [
624
595
  /* @__PURE__ */ jsxs2(
625
- "div",
596
+ "button",
626
597
  {
627
- className: `relative rounded-lg border bg-muted/30 ${thinkingActive ? "border-transparent" : "border-muted-foreground/20"}`,
628
- style: thinkingActive ? { margin: "1px" } : void 0,
598
+ type: "button",
599
+ className: "flex w-full items-center gap-2 px-3 py-2 text-left text-sm font-medium text-muted-foreground hover:text-foreground transition-colors",
600
+ onClick: () => setIsOpen(!isOpen),
629
601
  children: [
630
- /* @__PURE__ */ jsxs2(
631
- "button",
632
- {
633
- type: "button",
634
- className: "flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium text-muted-foreground hover:text-foreground/70 transition-colors",
635
- onClick: () => setOpen((v) => !v),
636
- children: [
637
- /* @__PURE__ */ jsx7(BrainCircuit, { className: `h-3.5 w-3.5 flex-shrink-0 ${thinkingActive ? "animate-pulse text-primary" : ""}` }),
638
- /* @__PURE__ */ jsxs2("span", { className: "flex-1", children: [
639
- label,
640
- thinkingActive && /* @__PURE__ */ jsxs2("span", { className: "ml-1 inline-flex gap-0.5", children: [
641
- /* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-current rounded-full animate-bounce", style: { animationDelay: "0ms" } }),
642
- /* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-current rounded-full animate-bounce", style: { animationDelay: "150ms" } }),
643
- /* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-current rounded-full animate-bounce", style: { animationDelay: "300ms" } })
644
- ] })
645
- ] }),
646
- open ? /* @__PURE__ */ jsx7(ChevronDown, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx7(ChevronRight, { className: "h-3 w-3" })
647
- ]
648
- }
649
- ),
650
- open && /* @__PURE__ */ jsx7("div", { className: "px-3 pb-3", children: /* @__PURE__ */ jsxs2("div", { className: "border-l-2 border-muted-foreground/20 pl-3", children: [
651
- /* @__PURE__ */ jsx7(
652
- PlainTextContent,
653
- {
654
- content,
655
- className: "text-xs text-muted-foreground/80 leading-5",
656
- chunkSize
657
- }
658
- ),
659
- thinkingActive && /* @__PURE__ */ jsx7("span", { className: "inline-block w-1.5 h-3 bg-muted-foreground/40 animate-pulse ml-0.5" })
660
- ] }) })
602
+ /* @__PURE__ */ jsx7(Brain, { className: `h-4 w-4 flex-shrink-0 ${isStreaming ? "text-primary animate-pulse" : "text-muted-foreground"}` }),
603
+ /* @__PURE__ */ jsx7("span", { className: "flex-1", children: isStreaming ? label : finishedLabel }),
604
+ isStreaming && /* @__PURE__ */ jsxs2("div", { className: "flex gap-0.5 mr-1", children: [
605
+ /* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-primary rounded-full animate-bounce", style: { animationDelay: "0ms" } }),
606
+ /* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-primary rounded-full animate-bounce", style: { animationDelay: "150ms" } }),
607
+ /* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-primary rounded-full animate-bounce", style: { animationDelay: "300ms" } })
608
+ ] }),
609
+ isOpen ? /* @__PURE__ */ jsx7(ChevronDown, { className: "h-3 w-3 flex-shrink-0" }) : /* @__PURE__ */ jsx7(ChevronRight, { className: "h-3 w-3 flex-shrink-0" })
661
610
  ]
662
611
  }
663
612
  ),
664
- /* @__PURE__ */ jsx7("style", { children: `
665
- @keyframes thinking-shimmer {
666
- 0%, 100% { background-position: 0% 50%; }
667
- 50% { background-position: 100% 50%; }
668
- }
669
- ` })
613
+ isOpen && /* @__PURE__ */ jsx7("div", { className: "px-3 pb-3 text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap break-words border-t border-border/40", children: /* @__PURE__ */ jsxs2("div", { className: "pt-2", children: [
614
+ reasoning,
615
+ isStreaming && /* @__PURE__ */ jsx7("span", { className: "inline-block w-1.5 h-3.5 bg-primary/60 animate-pulse ml-0.5" })
616
+ ] }) })
670
617
  ] });
671
618
  });
672
619
  var markdownComponents = {
@@ -735,7 +682,8 @@ var StreamingText = memo(function StreamingText2({
735
682
  className = "",
736
683
  renderMarkdown = true,
737
684
  plainTextChunkChars = 12e3,
738
- contentStyle
685
+ contentStyle,
686
+ hideThinkingIndicator = false
739
687
  }) {
740
688
  const hasContent = content.trim().length > 0;
741
689
  const enableSyntaxHighlight = renderMarkdown && !isStreaming && hasCodeBlocks(content);
@@ -763,10 +711,7 @@ var StreamingText = memo(function StreamingText2({
763
711
  chunkSize: plainTextChunkChars,
764
712
  style: contentStyle
765
713
  }
766
- ) : isStreaming ? (
767
- // Show thinking indicator while waiting for first token
768
- /* @__PURE__ */ jsx7(ThinkingIndicator, { label: thinkingLabel })
769
- ) : null,
714
+ ) : isStreaming && !hideThinkingIndicator ? /* @__PURE__ */ jsx7(ThinkingIndicator, { label: thinkingLabel }) : null,
770
715
  isStreaming && hasContent && /* @__PURE__ */ jsx7("span", { className: "inline-block w-2 h-4 bg-primary animate-pulse ml-1" })
771
716
  ] });
772
717
  });
@@ -1059,13 +1004,12 @@ var Message = memo(({
1059
1004
  ] })
1060
1005
  ] })
1061
1006
  ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
1062
- !messageIsUser && message.reasoning && message.reasoning.trim().length > 0 && /* @__PURE__ */ jsx7(
1007
+ !messageIsUser && message.reasoning && /* @__PURE__ */ jsx7(
1063
1008
  ThinkingBlock,
1064
1009
  {
1065
- content: message.reasoning,
1066
- isStreaming: message.isStreaming,
1067
- label: thinkingLabel,
1068
- chunkSize: normalizedChunkChars
1010
+ reasoning: message.reasoning,
1011
+ isStreaming: message.isReasoningStreaming,
1012
+ label: thinkingLabel
1069
1013
  }
1070
1014
  ),
1071
1015
  enableToolCallsDisplay && message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mb-3", children: /* @__PURE__ */ jsx7(ToolCallsDisplay, { toolCalls: message.toolCalls, label: toolUsedLabel }) }),
@@ -1077,7 +1021,8 @@ var Message = memo(({
1077
1021
  thinkingLabel,
1078
1022
  renderMarkdown: shouldRenderMarkdown,
1079
1023
  plainTextChunkChars: normalizedChunkChars,
1080
- contentStyle
1024
+ contentStyle,
1025
+ hideThinkingIndicator: !!message.reasoning
1081
1026
  }
1082
1027
  ),
1083
1028
  canCollapseMessage && /* @__PURE__ */ jsx7("div", { className: "mt-3", children: /* @__PURE__ */ jsx7(
@@ -1142,7 +1087,7 @@ var Message = memo(({
1142
1087
  }, arePropsEqual);
1143
1088
 
1144
1089
  // src/components/chat/Sidebar.tsx
1145
- import { useState as useState4, useRef as useRef5, useEffect as useEffect7 } from "react";
1090
+ import { useState as useState4, useRef as useRef4, useEffect as useEffect7 } from "react";
1146
1091
 
1147
1092
  // src/components/ui/input.tsx
1148
1093
  import { jsx as jsx8 } from "react/jsx-runtime";
@@ -2391,7 +2336,7 @@ var Sidebar2 = ({
2391
2336
  const [deleteThreadId, setDeleteThreadId] = useState4(null);
2392
2337
  const [editingThreadId, setEditingThreadId] = useState4(null);
2393
2338
  const [editTitle, setEditTitle] = useState4("");
2394
- const inputRef = useRef5(null);
2339
+ const inputRef = useRef4(null);
2395
2340
  const { setOpen } = useSidebar();
2396
2341
  useEffect7(() => {
2397
2342
  if (editingThreadId && inputRef.current) {
@@ -2810,7 +2755,7 @@ var ChatHeader = ({
2810
2755
  };
2811
2756
 
2812
2757
  // src/components/chat/ChatInput.tsx
2813
- import { useState as useState6, useRef as useRef6, useCallback as useCallback3, useEffect as useEffect9, memo as memo2 } from "react";
2758
+ import { useState as useState6, useRef as useRef5, useCallback as useCallback3, useEffect as useEffect9, memo as memo2 } from "react";
2814
2759
 
2815
2760
  // src/components/chat/UserContext.tsx
2816
2761
  import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useEffect as useEffect8, useMemo as useMemo3, useState as useState5 } from "react";
@@ -2954,7 +2899,7 @@ var FileUploadItem = memo2(function FileUploadItem2({ file, progress, onCancel }
2954
2899
  var AttachmentPreview = memo2(function AttachmentPreview2({ attachment, onRemove }) {
2955
2900
  const [isPlaying, setIsPlaying] = useState6(false);
2956
2901
  const [audioPlaybackSrc, setAudioPlaybackSrc] = useState6(attachment.dataUrl);
2957
- const audioRef = useRef6(null);
2902
+ const audioRef = useRef5(null);
2958
2903
  useEffect9(() => {
2959
2904
  if (attachment.kind !== "audio" || !attachment.dataUrl.startsWith("data:")) {
2960
2905
  setAudioPlaybackSrc(attachment.dataUrl);
@@ -3147,12 +3092,12 @@ var ChatInput = memo2(function ChatInput2({
3147
3092
  const { setContext } = useChatUserContext();
3148
3093
  const [recordingDuration, setRecordingDuration] = useState6(0);
3149
3094
  const [uploadProgress, setUploadProgress] = useState6(/* @__PURE__ */ new Map());
3150
- const textareaRef = useRef6(null);
3151
- const fileInputRef = useRef6(null);
3152
- const mediaRecorderRef = useRef6(null);
3153
- const recordingStartTime = useRef6(0);
3154
- const recordingInterval = useRef6(null);
3155
- const mediaStreamRef = useRef6(null);
3095
+ const textareaRef = useRef5(null);
3096
+ const fileInputRef = useRef5(null);
3097
+ const mediaRecorderRef = useRef5(null);
3098
+ const recordingStartTime = useRef5(0);
3099
+ const recordingInterval = useRef5(null);
3100
+ const mediaStreamRef = useRef5(null);
3156
3101
  useEffect9(() => {
3157
3102
  return () => {
3158
3103
  if (mediaStreamRef.current) {
@@ -3566,7 +3511,7 @@ import {
3566
3511
  Image as Image3,
3567
3512
  BadgeCheck,
3568
3513
  FileText as FileText2,
3569
- Brain,
3514
+ Brain as Brain2,
3570
3515
  Plus as Plus3,
3571
3516
  Trash2 as Trash23,
3572
3517
  Target,
@@ -3656,7 +3601,7 @@ var getMemoryCategoryIcon = (category) => {
3656
3601
  case "context":
3657
3602
  return /* @__PURE__ */ jsx23(Lightbulb, { className: iconClass });
3658
3603
  default:
3659
- return /* @__PURE__ */ jsx23(Brain, { className: iconClass });
3604
+ return /* @__PURE__ */ jsx23(Brain2, { className: iconClass });
3660
3605
  }
3661
3606
  };
3662
3607
  var getMemoryCategoryLabel = (category) => {
@@ -3801,7 +3746,7 @@ var UserProfile = ({
3801
3746
  /* @__PURE__ */ jsxs13("div", { className: "space-y-3", children: [
3802
3747
  /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between", children: [
3803
3748
  /* @__PURE__ */ jsxs13("h3", { className: "text-sm font-medium text-muted-foreground uppercase tracking-wider flex items-center gap-2", children: [
3804
- /* @__PURE__ */ jsx23(Brain, { className: "h-4 w-4" }),
3749
+ /* @__PURE__ */ jsx23(Brain2, { className: "h-4 w-4" }),
3805
3750
  labels.memories
3806
3751
  ] }),
3807
3752
  onAddMemory && /* @__PURE__ */ jsx23(
@@ -4016,18 +3961,18 @@ var ChatUI = ({
4016
3961
  setState((prev) => ({ ...prev, selectedThreadId: currentThreadId }));
4017
3962
  }
4018
3963
  }, [currentThreadId]);
4019
- const initialInputApplied = useRef7(false);
4020
- const initialInputConsumedRef = useRef7(false);
3964
+ const initialInputApplied = useRef6(false);
3965
+ const initialInputConsumedRef = useRef6(false);
4021
3966
  useEffect10(() => {
4022
3967
  if (initialInput && !initialInputApplied.current) {
4023
3968
  setInputValue(initialInput);
4024
3969
  initialInputApplied.current = true;
4025
3970
  }
4026
3971
  }, [initialInput]);
4027
- const scrollAreaRef = useRef7(null);
4028
- const stateRef = useRef7(state);
4029
- const inputValueRef = useRef7(inputValue);
4030
- const attachmentsRef = useRef7(attachments);
3972
+ const scrollAreaRef = useRef6(null);
3973
+ const stateRef = useRef6(state);
3974
+ const inputValueRef = useRef6(inputValue);
3975
+ const attachmentsRef = useRef6(attachments);
4031
3976
  useEffect10(() => {
4032
3977
  stateRef.current = state;
4033
3978
  }, [state]);
@@ -4076,7 +4021,7 @@ var ChatUI = ({
4076
4021
  return () => clearTimeout(t);
4077
4022
  }
4078
4023
  }, [state.showSidebar, isMobile, config.customComponent]);
4079
- const prevMessageCountRef = useRef7(0);
4024
+ const prevMessageCountRef = useRef6(0);
4080
4025
  useEffect10(() => {
4081
4026
  if (messages.length === 0) {
4082
4027
  prevMessageCountRef.current = 0;
@@ -4489,7 +4434,7 @@ var ChatUI = ({
4489
4434
  };
4490
4435
 
4491
4436
  // src/components/chat/ThreadManager.tsx
4492
- import { useState as useState9, useRef as useRef8, useEffect as useEffect11 } from "react";
4437
+ import { useState as useState9, useRef as useRef7, useEffect as useEffect11 } from "react";
4493
4438
  import {
4494
4439
  Plus as Plus4,
4495
4440
  MessageSquare as MessageSquare2,
@@ -4508,7 +4453,7 @@ import { Fragment as Fragment6, jsx as jsx25, jsxs as jsxs15 } from "react/jsx-r
4508
4453
  var ThreadItem = ({ thread, isActive, config, onSelect, onRename, onDelete, onArchive }) => {
4509
4454
  const [isEditing, setIsEditing] = useState9(false);
4510
4455
  const [editTitle, setEditTitle] = useState9(thread.title);
4511
- const inputRef = useRef8(null);
4456
+ const inputRef = useRef7(null);
4512
4457
  useEffect11(() => {
4513
4458
  if (isEditing && inputRef.current) {
4514
4459
  inputRef.current.focus();