@chat-js/cli 0.6.1 → 0.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.
Files changed (154) hide show
  1. package/dist/index.js +17065 -16667
  2. package/package.json +1 -1
  3. package/templates/chat-app/app/(auth)/login/page.tsx +3 -3
  4. package/templates/chat-app/app/(chat)/api/chat/route.ts +4 -60
  5. package/templates/chat-app/app/not-found.tsx +2 -2
  6. package/templates/chat-app/chat.config.ts +3 -0
  7. package/templates/chat-app/components/ai-elements/actions.tsx +44 -44
  8. package/templates/chat-app/components/ai-elements/artifact.tsx +92 -92
  9. package/templates/chat-app/components/ai-elements/code-block.tsx +143 -143
  10. package/templates/chat-app/components/ai-elements/context.tsx +313 -313
  11. package/templates/chat-app/components/ai-elements/conversation.tsx +65 -65
  12. package/templates/chat-app/components/ai-elements/extra/conversation-content-scroll-area.tsx +29 -29
  13. package/templates/chat-app/components/ai-elements/extra/mcp-tool-header.tsx +27 -27
  14. package/templates/chat-app/components/ai-elements/message.tsx +341 -344
  15. package/templates/chat-app/components/ai-elements/parseIncompleteMarkdown.tsx +122 -122
  16. package/templates/chat-app/components/ai-elements/prompt-input.tsx +1059 -1059
  17. package/templates/chat-app/components/ai-elements/reasoning.tsx +131 -131
  18. package/templates/chat-app/components/ai-elements/response.tsx +15 -12
  19. package/templates/chat-app/components/ai-elements/sandbox.tsx +84 -84
  20. package/templates/chat-app/components/ai-elements/shimmer.tsx +47 -47
  21. package/templates/chat-app/components/ai-elements/suggestion.tsx +33 -33
  22. package/templates/chat-app/components/ai-elements/tool.tsx +118 -118
  23. package/templates/chat-app/components/app-sidebar-history-conditional.tsx +3 -3
  24. package/templates/chat-app/components/app-sidebar.tsx +3 -3
  25. package/templates/chat-app/components/connectors-dropdown.tsx +6 -3
  26. package/templates/chat-app/components/deep-research-progress.tsx +1 -1
  27. package/templates/chat-app/components/header-breadcrumb.tsx +14 -11
  28. package/templates/chat-app/components/internal-link.tsx +73 -0
  29. package/templates/chat-app/components/login-form.tsx +5 -5
  30. package/templates/chat-app/components/message-parts.tsx +1 -71
  31. package/templates/chat-app/components/model-selector.tsx +3 -3
  32. package/templates/chat-app/components/new-chat-button.tsx +4 -4
  33. package/templates/chat-app/components/part/document-common.tsx +3 -3
  34. package/templates/chat-app/components/part/document-tool.tsx +3 -3
  35. package/templates/chat-app/components/part/message-annotations.tsx +2 -2
  36. package/templates/chat-app/components/part/tool-part.tsx +92 -0
  37. package/templates/chat-app/components/project-chat-item.tsx +2 -2
  38. package/templates/chat-app/components/research-progress.tsx +2 -2
  39. package/templates/chat-app/components/research-task.tsx +1 -1
  40. package/templates/chat-app/components/research-tasks.tsx +1 -1
  41. package/templates/chat-app/components/settings/connectors-settings.tsx +4 -4
  42. package/templates/chat-app/components/settings/mcp-details-page.tsx +5 -5
  43. package/templates/chat-app/components/settings/settings-nav.tsx +3 -3
  44. package/templates/chat-app/components/sidebar-chat-item.tsx +4 -12
  45. package/templates/chat-app/components/sidebar-project-item.tsx +4 -11
  46. package/templates/chat-app/components/sidebar-top-row.tsx +7 -7
  47. package/templates/chat-app/components/sidebar-user-nav.tsx +3 -3
  48. package/templates/chat-app/components/signup-form.tsx +8 -5
  49. package/templates/chat-app/components/source-badge.tsx +3 -9
  50. package/templates/chat-app/components/sources.tsx +1 -1
  51. package/templates/chat-app/components/ui/accordion.tsx +32 -32
  52. package/templates/chat-app/components/ui/alert-dialog.tsx +103 -103
  53. package/templates/chat-app/components/ui/alert.tsx +36 -36
  54. package/templates/chat-app/components/ui/avatar.tsx +28 -28
  55. package/templates/chat-app/components/ui/badge.tsx +22 -22
  56. package/templates/chat-app/components/ui/breadcrumb.tsx +72 -72
  57. package/templates/chat-app/components/ui/button-group.tsx +58 -58
  58. package/templates/chat-app/components/ui/button.tsx +45 -45
  59. package/templates/chat-app/components/ui/card.tsx +65 -65
  60. package/templates/chat-app/components/ui/checkbox.tsx +16 -16
  61. package/templates/chat-app/components/ui/collapsible.tsx +1 -1
  62. package/templates/chat-app/components/ui/command.tsx +137 -137
  63. package/templates/chat-app/components/ui/dialog.tsx +94 -94
  64. package/templates/chat-app/components/ui/drawer.tsx +68 -68
  65. package/templates/chat-app/components/ui/dropdown-menu.tsx +184 -184
  66. package/templates/chat-app/components/ui/empty.tsx +76 -76
  67. package/templates/chat-app/components/ui/extra/action-container.tsx +3 -3
  68. package/templates/chat-app/components/ui/extra/scroll-area-viewport-ref.tsx +24 -24
  69. package/templates/chat-app/components/ui/form.tsx +112 -112
  70. package/templates/chat-app/components/ui/hover-card.tsx +25 -25
  71. package/templates/chat-app/components/ui/input-group.tsx +126 -126
  72. package/templates/chat-app/components/ui/input.tsx +13 -13
  73. package/templates/chat-app/components/ui/label.tsx +12 -12
  74. package/templates/chat-app/components/ui/popover.tsx +25 -25
  75. package/templates/chat-app/components/ui/progress.tsx +19 -19
  76. package/templates/chat-app/components/ui/resizable.tsx +27 -27
  77. package/templates/chat-app/components/ui/scroll-area.tsx +30 -30
  78. package/templates/chat-app/components/ui/select.tsx +108 -108
  79. package/templates/chat-app/components/ui/separator.tsx +16 -16
  80. package/templates/chat-app/components/ui/sheet.tsx +91 -91
  81. package/templates/chat-app/components/ui/sidebar.tsx +615 -615
  82. package/templates/chat-app/components/ui/skeleton.tsx +7 -7
  83. package/templates/chat-app/components/ui/slider.tsx +50 -50
  84. package/templates/chat-app/components/ui/spinner.tsx +8 -8
  85. package/templates/chat-app/components/ui/switch.tsx +16 -16
  86. package/templates/chat-app/components/ui/table.tsx +71 -71
  87. package/templates/chat-app/components/ui/tabs.tsx +31 -31
  88. package/templates/chat-app/components/ui/textarea.tsx +10 -10
  89. package/templates/chat-app/components/ui/toggle.tsx +31 -31
  90. package/templates/chat-app/components/ui/tooltip.tsx +48 -48
  91. package/templates/chat-app/components/upgrade-cta/limit-display.tsx +7 -7
  92. package/templates/chat-app/components/upgrade-cta/login-cta-banner.tsx +3 -3
  93. package/templates/chat-app/components/upgrade-cta/login-prompt.tsx +3 -3
  94. package/templates/chat-app/hooks/use-mobile.ts +13 -13
  95. package/templates/chat-app/lib/ai/core-chat-agent.ts +25 -14
  96. package/templates/chat-app/lib/ai/eval-agent.ts +4 -5
  97. package/templates/chat-app/lib/ai/gateway-model-defaults.ts +24 -0
  98. package/templates/chat-app/lib/ai/installed-tools.ts +12 -0
  99. package/templates/chat-app/lib/ai/mcp/mcp-client.ts +2 -2
  100. package/templates/chat-app/lib/ai/models.generated.ts +4236 -4585
  101. package/templates/chat-app/lib/ai/tool-renderer-registry.ts +31 -0
  102. package/templates/chat-app/lib/ai/types.ts +15 -20
  103. package/templates/chat-app/lib/config-requirements.ts +11 -6
  104. package/templates/chat-app/lib/config-schema.ts +24 -0
  105. package/templates/chat-app/lib/stores/hooks-message-parts.ts +1 -1
  106. package/templates/chat-app/lib/utils.ts +157 -157
  107. package/templates/chat-app/package.json +1 -1
  108. package/templates/chat-app/scripts/check-env.ts +229 -2
  109. package/templates/chat-app/tools/chatjs/_shared/lib/tool-part.ts +5 -0
  110. package/templates/chat-app/{components/part/weather.tsx → tools/chatjs/get-weather/renderer.tsx} +24 -38
  111. package/templates/chat-app/{components/part/retrieve-url.tsx → tools/chatjs/retrieve-url/renderer.tsx} +20 -15
  112. package/templates/chat-app/{lib/ai/tools/retrieve-url.ts → tools/chatjs/retrieve-url/tool.ts} +46 -7
  113. package/templates/chat-app/tools/chatjs/tools.ts +16 -0
  114. package/templates/chat-app/tools/chatjs/ui.ts +17 -0
  115. package/templates/chat-app/tools/chatjs/word-count/renderer.tsx +50 -0
  116. package/templates/chat-app/tools/chatjs/word-count/tool.ts +30 -0
  117. package/templates/chat-app/{lib/ai/tools → tools/platform}/code-execution.ts +3 -5
  118. package/templates/chat-app/{lib/ai/tools → tools/platform}/deep-research/deep-research.ts +2 -3
  119. package/templates/chat-app/{lib/ai/tools → tools/platform}/deep-research/pipeline.ts +1 -1
  120. package/templates/chat-app/{lib/ai/tools → tools/platform}/deep-research/types.ts +1 -1
  121. package/templates/chat-app/{lib/ai/tools → tools/platform}/deep-research/utils.ts +7 -7
  122. package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/types.ts +1 -1
  123. package/templates/chat-app/{lib/ai/tools → tools/platform}/generate-video.ts +4 -6
  124. package/templates/chat-app/{lib/ai/tools → tools/platform}/read-document.ts +2 -2
  125. package/templates/chat-app/{lib/ai/tools → tools/platform}/steps/multi-query-web-search.ts +1 -1
  126. package/templates/chat-app/{lib/ai/tools → tools/platform}/steps/web-search.ts +1 -1
  127. package/templates/chat-app/{lib/ai/tools → tools/platform}/tools.ts +54 -30
  128. package/templates/chat-app/{lib/ai/tools → tools/platform}/web-search.ts +7 -5
  129. package/templates/electron/CHANGELOG.md +16 -2
  130. package/templates/electron/package.json +1 -1
  131. package/templates/chat-app/lib/ai/tools/tools-definitions.ts +0 -83
  132. /package/templates/chat-app/{lib/ai/tools/get-weather.ts → tools/chatjs/get-weather/tool.ts} +0 -0
  133. /package/templates/chat-app/{lib/ai/tools → tools/platform}/code-execution.javascript.ts +0 -0
  134. /package/templates/chat-app/{lib/ai/tools → tools/platform}/code-execution.python.ts +0 -0
  135. /package/templates/chat-app/{lib/ai/tools → tools/platform}/code-execution.shared.test.ts +0 -0
  136. /package/templates/chat-app/{lib/ai/tools → tools/platform}/code-execution.shared.ts +0 -0
  137. /package/templates/chat-app/{lib/ai/tools → tools/platform}/code-execution.types.ts +0 -0
  138. /package/templates/chat-app/{lib/ai/tools → tools/platform}/deep-research/configuration.ts +0 -0
  139. /package/templates/chat-app/{lib/ai/tools → tools/platform}/deep-research/prompts.ts +0 -0
  140. /package/templates/chat-app/{lib/ai/tools → tools/platform}/deep-research/researcher-agent.ts +0 -0
  141. /package/templates/chat-app/{lib/ai/tools → tools/platform}/deep-research/supervisor-agent.ts +0 -0
  142. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/code-guidelines.ts +0 -0
  143. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/create-code-document.ts +0 -0
  144. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/create-sheet-document.ts +0 -0
  145. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/create-text-document.ts +0 -0
  146. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/edit-code-document.ts +0 -0
  147. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/edit-sheet-document.ts +0 -0
  148. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/edit-text-document.ts +0 -0
  149. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/sheet-guidelines.ts +0 -0
  150. /package/templates/chat-app/{lib/ai/tools → tools/platform}/documents/text-guidelines.ts +0 -0
  151. /package/templates/chat-app/{lib/ai/tools → tools/platform}/generate-image.ts +0 -0
  152. /package/templates/chat-app/{lib/ai/tools → tools/platform}/research-updates-schema.ts +0 -0
  153. /package/templates/chat-app/{lib/ai/tools → tools/platform}/steps/search-utils.ts +0 -0
  154. /package/templates/chat-app/{lib/ai/tools → tools/platform}/types.ts +0 -0
@@ -5,172 +5,172 @@ import { BrainIcon, ChevronDownIcon } from "lucide-react";
5
5
  import type { ComponentProps } from "react";
6
6
  import { createContext, memo, useContext, useEffect, useState } from "react";
7
7
  import {
8
- Collapsible,
9
- CollapsibleContent,
10
- CollapsibleTrigger,
8
+ Collapsible,
9
+ CollapsibleContent,
10
+ CollapsibleTrigger,
11
11
  } from "@/components/ui/collapsible";
12
12
  import { cn } from "@/lib/utils";
13
13
  import { Response } from "./response";
14
14
  import { Shimmer } from "./shimmer";
15
15
 
16
16
  type ReasoningContextValue = {
17
- isStreaming: boolean;
18
- isOpen: boolean;
19
- setIsOpen: (open: boolean) => void;
20
- duration: number;
17
+ isStreaming: boolean;
18
+ isOpen: boolean;
19
+ setIsOpen: (open: boolean) => void;
20
+ duration: number;
21
21
  };
22
22
 
23
23
  const ReasoningContext = createContext<ReasoningContextValue | null>(null);
24
24
 
25
25
  const useReasoning = () => {
26
- const context = useContext(ReasoningContext);
27
- if (!context) {
28
- throw new Error("Reasoning components must be used within Reasoning");
29
- }
30
- return context;
26
+ const context = useContext(ReasoningContext);
27
+ if (!context) {
28
+ throw new Error("Reasoning components must be used within Reasoning");
29
+ }
30
+ return context;
31
31
  };
32
32
 
33
33
  export type ReasoningProps = ComponentProps<typeof Collapsible> & {
34
- isStreaming?: boolean;
35
- open?: boolean;
36
- defaultOpen?: boolean;
37
- onOpenChange?: (open: boolean) => void;
38
- duration?: number;
34
+ isStreaming?: boolean;
35
+ open?: boolean;
36
+ defaultOpen?: boolean;
37
+ onOpenChange?: (open: boolean) => void;
38
+ duration?: number;
39
39
  };
40
40
 
41
41
  const AUTO_CLOSE_DELAY = 1000;
42
42
  const MS_IN_S = 1000;
43
43
 
44
44
  export const Reasoning = memo(
45
- ({
46
- className,
47
- isStreaming = false,
48
- open,
49
- defaultOpen = true,
50
- onOpenChange,
51
- duration: durationProp,
52
- children,
53
- ...props
54
- }: ReasoningProps) => {
55
- const [isOpen, setIsOpen] = useControllableState({
56
- prop: open,
57
- defaultProp: defaultOpen,
58
- onChange: onOpenChange,
59
- });
60
- const [duration, setDuration] = useControllableState({
61
- prop: durationProp,
62
- defaultProp: 0,
63
- });
64
-
65
- const [hasAutoClosed, setHasAutoClosed] = useState(false);
66
- const [startTime, setStartTime] = useState<number | null>(null);
67
-
68
- // Track duration when streaming starts and ends
69
- useEffect(() => {
70
- if (isStreaming) {
71
- if (startTime === null) {
72
- setStartTime(Date.now());
73
- }
74
- } else if (startTime !== null) {
75
- setDuration(Math.ceil((Date.now() - startTime) / MS_IN_S));
76
- setStartTime(null);
77
- }
78
- }, [isStreaming, startTime, setDuration]);
79
-
80
- // Auto-open when streaming starts, auto-close when streaming ends (once only)
81
- useEffect(() => {
82
- if (defaultOpen && !isStreaming && isOpen && !hasAutoClosed) {
83
- // Add a small delay before closing to allow user to see the content
84
- const timer = setTimeout(() => {
85
- setIsOpen(false);
86
- setHasAutoClosed(true);
87
- }, AUTO_CLOSE_DELAY);
88
-
89
- return () => clearTimeout(timer);
90
- }
91
- }, [isStreaming, isOpen, defaultOpen, setIsOpen, hasAutoClosed]);
92
-
93
- const handleOpenChange = (newOpen: boolean) => {
94
- setIsOpen(newOpen);
95
- };
96
-
97
- return (
98
- <ReasoningContext.Provider
99
- value={{ isStreaming, isOpen, setIsOpen, duration }}
100
- >
101
- <Collapsible
102
- className={cn("not-prose mb-4", className)}
103
- onOpenChange={handleOpenChange}
104
- open={isOpen}
105
- {...props}
106
- >
107
- {children}
108
- </Collapsible>
109
- </ReasoningContext.Provider>
110
- );
111
- }
45
+ ({
46
+ className,
47
+ isStreaming = false,
48
+ open,
49
+ defaultOpen = true,
50
+ onOpenChange,
51
+ duration: durationProp,
52
+ children,
53
+ ...props
54
+ }: ReasoningProps) => {
55
+ const [isOpen, setIsOpen] = useControllableState({
56
+ prop: open,
57
+ defaultProp: defaultOpen,
58
+ onChange: onOpenChange,
59
+ });
60
+ const [duration, setDuration] = useControllableState({
61
+ prop: durationProp,
62
+ defaultProp: 0,
63
+ });
64
+
65
+ const [hasAutoClosed, setHasAutoClosed] = useState(false);
66
+ const [startTime, setStartTime] = useState<number | null>(null);
67
+
68
+ // Track duration when streaming starts and ends
69
+ useEffect(() => {
70
+ if (isStreaming) {
71
+ if (startTime === null) {
72
+ setStartTime(Date.now());
73
+ }
74
+ } else if (startTime !== null) {
75
+ setDuration(Math.ceil((Date.now() - startTime) / MS_IN_S));
76
+ setStartTime(null);
77
+ }
78
+ }, [isStreaming, startTime, setDuration]);
79
+
80
+ // Auto-open when streaming starts, auto-close when streaming ends (once only)
81
+ useEffect(() => {
82
+ if (defaultOpen && !isStreaming && isOpen && !hasAutoClosed) {
83
+ // Add a small delay before closing to allow user to see the content
84
+ const timer = setTimeout(() => {
85
+ setIsOpen(false);
86
+ setHasAutoClosed(true);
87
+ }, AUTO_CLOSE_DELAY);
88
+
89
+ return () => clearTimeout(timer);
90
+ }
91
+ }, [isStreaming, isOpen, defaultOpen, setIsOpen, hasAutoClosed]);
92
+
93
+ const handleOpenChange = (newOpen: boolean) => {
94
+ setIsOpen(newOpen);
95
+ };
96
+
97
+ return (
98
+ <ReasoningContext.Provider
99
+ value={{ isStreaming, isOpen, setIsOpen, duration }}
100
+ >
101
+ <Collapsible
102
+ className={cn("not-prose mb-4", className)}
103
+ onOpenChange={handleOpenChange}
104
+ open={isOpen}
105
+ {...props}
106
+ >
107
+ {children}
108
+ </Collapsible>
109
+ </ReasoningContext.Provider>
110
+ );
111
+ },
112
112
  );
113
113
 
114
114
  export type ReasoningTriggerProps = ComponentProps<typeof CollapsibleTrigger>;
115
115
 
116
116
  const getThinkingMessage = (isStreaming: boolean, duration?: number) => {
117
- if (isStreaming) {
118
- return <Shimmer duration={1}>Thinking...</Shimmer>;
119
- }
120
- if (duration === undefined || duration === 0) {
121
- return <p>Thought for a few seconds</p>;
122
- }
123
- return <p>Thought for {duration} seconds</p>;
117
+ if (isStreaming) {
118
+ return <Shimmer duration={1}>Thinking...</Shimmer>;
119
+ }
120
+ if (duration === undefined || duration === 0) {
121
+ return <p>Thought for a few seconds</p>;
122
+ }
123
+ return <p>Thought for {duration} seconds</p>;
124
124
  };
125
125
 
126
126
  export const ReasoningTrigger = memo(
127
- ({ className, children, ...props }: ReasoningTriggerProps) => {
128
- const { isStreaming, isOpen, duration } = useReasoning();
129
-
130
- return (
131
- <CollapsibleTrigger
132
- className={cn(
133
- "flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",
134
- className
135
- )}
136
- {...props}
137
- >
138
- {children ?? (
139
- <>
140
- <BrainIcon className="size-4" />
141
- {getThinkingMessage(isStreaming, duration)}
142
- <ChevronDownIcon
143
- className={cn(
144
- "size-4 transition-transform",
145
- isOpen ? "rotate-180" : "rotate-0"
146
- )}
147
- />
148
- </>
149
- )}
150
- </CollapsibleTrigger>
151
- );
152
- }
127
+ ({ className, children, ...props }: ReasoningTriggerProps) => {
128
+ const { isStreaming, isOpen, duration } = useReasoning();
129
+
130
+ return (
131
+ <CollapsibleTrigger
132
+ className={cn(
133
+ "flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",
134
+ className,
135
+ )}
136
+ {...props}
137
+ >
138
+ {children ?? (
139
+ <>
140
+ <BrainIcon className="size-4" />
141
+ {getThinkingMessage(isStreaming, duration)}
142
+ <ChevronDownIcon
143
+ className={cn(
144
+ "size-4 transition-transform",
145
+ isOpen ? "rotate-180" : "rotate-0",
146
+ )}
147
+ />
148
+ </>
149
+ )}
150
+ </CollapsibleTrigger>
151
+ );
152
+ },
153
153
  );
154
154
 
155
155
  export type ReasoningContentProps = ComponentProps<
156
- typeof CollapsibleContent
156
+ typeof CollapsibleContent
157
157
  > & {
158
- children: string;
158
+ children: string;
159
159
  };
160
160
 
161
161
  export const ReasoningContent = memo(
162
- ({ className, children, ...props }: ReasoningContentProps) => (
163
- <CollapsibleContent
164
- className={cn(
165
- "mt-4 text-sm",
166
- "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
167
- className
168
- )}
169
- {...props}
170
- >
171
- <Response className="grid gap-2">{children}</Response>
172
- </CollapsibleContent>
173
- )
162
+ ({ className, children, ...props }: ReasoningContentProps) => (
163
+ <CollapsibleContent
164
+ className={cn(
165
+ "mt-4 text-sm",
166
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
167
+ className,
168
+ )}
169
+ {...props}
170
+ >
171
+ <Response className="grid gap-2">{children}</Response>
172
+ </CollapsibleContent>
173
+ ),
174
174
  );
175
175
 
176
176
  Reasoning.displayName = "Reasoning";
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
 
3
- import { cn } from "@/lib/utils";
4
3
  import { code } from "@streamdown/code";
5
4
  import { math } from "@streamdown/math";
6
5
  import { mermaid } from "@streamdown/mermaid";
7
6
  import { type ComponentProps, memo } from "react";
8
7
  import { Streamdown } from "streamdown";
8
+ import { cn } from "@/lib/utils";
9
9
  import "streamdown/styles.css";
10
10
 
11
11
  const plugins = { code, mermaid, math };
@@ -13,17 +13,20 @@ const plugins = { code, mermaid, math };
13
13
  type ResponseProps = ComponentProps<typeof Streamdown>;
14
14
 
15
15
  export const Response = memo(
16
- ({ className, ...props }: ResponseProps) => (
17
- <Streamdown
18
- className={cn(
19
- "size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
20
- className
21
- )}
22
- plugins={plugins}
23
- {...props}
24
- />
25
- ),
26
- (prevProps, nextProps) => prevProps.children === nextProps.children && prevProps.isAnimating === nextProps.isAnimating && prevProps.mode === nextProps.mode
16
+ ({ className, ...props }: ResponseProps) => (
17
+ <Streamdown
18
+ className={cn(
19
+ "size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
20
+ className,
21
+ )}
22
+ plugins={plugins}
23
+ {...props}
24
+ />
25
+ ),
26
+ (prevProps, nextProps) =>
27
+ prevProps.children === nextProps.children &&
28
+ prevProps.isAnimating === nextProps.isAnimating &&
29
+ prevProps.mode === nextProps.mode,
27
30
  );
28
31
 
29
32
  Response.displayName = "Response";
@@ -4,9 +4,9 @@ import type { ToolUIPart } from "ai";
4
4
  import { ChevronDownIcon, Code } from "lucide-react";
5
5
  import type { ComponentProps } from "react";
6
6
  import {
7
- Collapsible,
8
- CollapsibleContent,
9
- CollapsibleTrigger,
7
+ Collapsible,
8
+ CollapsibleContent,
9
+ CollapsibleTrigger,
10
10
  } from "@/components/ui/collapsible";
11
11
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
12
12
  import { cn } from "@/lib/utils";
@@ -16,138 +16,138 @@ import { getStatusBadge } from "./tool";
16
16
  export type SandboxRootProps = ComponentProps<typeof Collapsible>;
17
17
 
18
18
  export const Sandbox = ({ className, ...props }: SandboxRootProps) => (
19
- <Collapsible
20
- className={cn("not-prose group mb-4 w-full rounded-md border", className)}
21
- defaultOpen
22
- {...props}
23
- />
19
+ <Collapsible
20
+ className={cn("not-prose group mb-4 w-full rounded-md border", className)}
21
+ defaultOpen
22
+ {...props}
23
+ />
24
24
  );
25
25
 
26
26
  export type SandboxHeaderProps = {
27
- title?: string;
28
- state: ToolUIPart["state"];
29
- className?: string;
27
+ title?: string;
28
+ state: ToolUIPart["state"];
29
+ className?: string;
30
30
  };
31
31
 
32
32
  export const SandboxHeader = ({
33
- className,
34
- title,
35
- state,
36
- ...props
33
+ className,
34
+ title,
35
+ state,
36
+ ...props
37
37
  }: SandboxHeaderProps) => (
38
- <CollapsibleTrigger
39
- className={cn(
40
- "flex w-full items-center justify-between gap-4 p-3",
41
- className
42
- )}
43
- {...props}
44
- >
45
- <div className="flex items-center gap-2">
46
- <Code className="size-4 text-muted-foreground" />
47
- <span className="font-medium text-sm">{title}</span>
48
- {getStatusBadge(state)}
49
- </div>
50
- <ChevronDownIcon className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
51
- </CollapsibleTrigger>
38
+ <CollapsibleTrigger
39
+ className={cn(
40
+ "flex w-full items-center justify-between gap-4 p-3",
41
+ className,
42
+ )}
43
+ {...props}
44
+ >
45
+ <div className="flex items-center gap-2">
46
+ <Code className="size-4 text-muted-foreground" />
47
+ <span className="font-medium text-sm">{title}</span>
48
+ {getStatusBadge(state)}
49
+ </div>
50
+ <ChevronDownIcon className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
51
+ </CollapsibleTrigger>
52
52
  );
53
53
 
54
54
  export type SandboxContentProps = ComponentProps<typeof CollapsibleContent>;
55
55
 
56
56
  export const SandboxContent = ({
57
- className,
58
- ...props
57
+ className,
58
+ ...props
59
59
  }: SandboxContentProps) => (
60
- <CollapsibleContent
61
- className={cn(
62
- "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
63
- className
64
- )}
65
- {...props}
66
- />
60
+ <CollapsibleContent
61
+ className={cn(
62
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
63
+ className,
64
+ )}
65
+ {...props}
66
+ />
67
67
  );
68
68
 
69
69
  export type SandboxTabsProps = ComponentProps<typeof Tabs>;
70
70
 
71
71
  export const SandboxTabs = ({ className, ...props }: SandboxTabsProps) => (
72
- <Tabs className={cn("w-full", className)} {...props} />
72
+ <Tabs className={cn("w-full", className)} {...props} />
73
73
  );
74
74
 
75
75
  export type SandboxTabsBarProps = ComponentProps<"div">;
76
76
 
77
77
  export const SandboxTabsBar = ({
78
- className,
79
- ...props
78
+ className,
79
+ ...props
80
80
  }: SandboxTabsBarProps) => (
81
- <div
82
- className={cn(
83
- "flex w-full items-center border-border border-t border-b",
84
- className
85
- )}
86
- {...props}
87
- />
81
+ <div
82
+ className={cn(
83
+ "flex w-full items-center border-border border-t border-b",
84
+ className,
85
+ )}
86
+ {...props}
87
+ />
88
88
  );
89
89
 
90
90
  export type SandboxTabsListProps = ComponentProps<typeof TabsList>;
91
91
 
92
92
  export const SandboxTabsList = ({
93
- className,
94
- ...props
93
+ className,
94
+ ...props
95
95
  }: SandboxTabsListProps) => (
96
- <TabsList
97
- className={cn("h-auto rounded-none border-0 bg-transparent p-0", className)}
98
- {...props}
99
- />
96
+ <TabsList
97
+ className={cn("h-auto rounded-none border-0 bg-transparent p-0", className)}
98
+ {...props}
99
+ />
100
100
  );
101
101
 
102
102
  export type SandboxTabsTriggerProps = ComponentProps<typeof TabsTrigger>;
103
103
 
104
104
  export const SandboxTabsTrigger = ({
105
- className,
106
- ...props
105
+ className,
106
+ ...props
107
107
  }: SandboxTabsTriggerProps) => (
108
- <TabsTrigger
109
- className={cn(
110
- "rounded-none border-0 border-transparent border-b-2 px-4 py-2 font-medium text-muted-foreground text-sm transition-colors data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none",
111
- className
112
- )}
113
- {...props}
114
- />
108
+ <TabsTrigger
109
+ className={cn(
110
+ "rounded-none border-0 border-transparent border-b-2 px-4 py-2 font-medium text-muted-foreground text-sm transition-colors data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none",
111
+ className,
112
+ )}
113
+ {...props}
114
+ />
115
115
  );
116
116
 
117
117
  export type SandboxTabContentProps = ComponentProps<typeof TabsContent>;
118
118
 
119
119
  export const SandboxTabContent = ({
120
- className,
121
- ...props
120
+ className,
121
+ ...props
122
122
  }: SandboxTabContentProps) => (
123
- <TabsContent className={cn("mt-0 text-sm", className)} {...props} />
123
+ <TabsContent className={cn("mt-0 text-sm", className)} {...props} />
124
124
  );
125
125
 
126
126
  export type SandboxCodeProps = ComponentProps<typeof CodeBlock>;
127
127
 
128
128
  export const SandboxCode = ({ className, ...props }: SandboxCodeProps) => (
129
- <CodeBlock className={cn("min-h-10 border-0", className)} {...props}>
130
- <CodeBlockCopyButton
131
- className="opacity-0 transition-opacity duration-200 group-hover:opacity-100"
132
- size="sm"
133
- />
134
- </CodeBlock>
129
+ <CodeBlock className={cn("min-h-10 border-0", className)} {...props}>
130
+ <CodeBlockCopyButton
131
+ className="opacity-0 transition-opacity duration-200 group-hover:opacity-100"
132
+ size="sm"
133
+ />
134
+ </CodeBlock>
135
135
  );
136
136
 
137
137
  export type SandboxOutputProps = Omit<
138
- ComponentProps<typeof CodeBlock>,
139
- "language"
138
+ ComponentProps<typeof CodeBlock>,
139
+ "language"
140
140
  >;
141
141
 
142
142
  export const SandboxOutput = ({ className, ...props }: SandboxOutputProps) => (
143
- <CodeBlock
144
- className={cn("min-h-10 border-0", className)}
145
- language="log"
146
- {...props}
147
- >
148
- <CodeBlockCopyButton
149
- className="opacity-0 transition-opacity duration-200 group-hover:opacity-100"
150
- size="sm"
151
- />
152
- </CodeBlock>
143
+ <CodeBlock
144
+ className={cn("min-h-10 border-0", className)}
145
+ language="log"
146
+ {...props}
147
+ >
148
+ <CodeBlockCopyButton
149
+ className="opacity-0 transition-opacity duration-200 group-hover:opacity-100"
150
+ size="sm"
151
+ />
152
+ </CodeBlock>
153
153
  );