@chat-js/cli 0.1.4 → 0.2.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.js +391 -244
- package/package.json +1 -1
- package/templates/chat-app/.claude/skiller.toml +18 -0
- package/templates/chat-app/.claude/skills/chat-context/SKILL.md +6 -0
- package/templates/chat-app/.claude/skills/chat-context/chat-context.mdc +36 -0
- package/templates/chat-app/.claude/skills/lazy-prefetch-pattern/lazy-prefetch-pattern.mdc +27 -0
- package/templates/chat-app/.claude/skills/react/react.mdc +29 -0
- package/templates/chat-app/.claude/skills/trpc-patterns/trpc-patterns.mdc +77 -0
- package/templates/chat-app/.claude/skills/typescript/typescript.mdc +53 -0
- package/templates/chat-app/.claude/skills/ultracite/ultracite.mdc +129 -0
- package/templates/chat-app/.cursor/skills/chat-context/SKILL.md +37 -0
- package/templates/chat-app/.cursor/skills/lazy-prefetch-pattern/SKILL.md +26 -0
- package/templates/chat-app/.cursor/skills/react/SKILL.md +28 -0
- package/templates/chat-app/.cursor/skills/trpc-patterns/SKILL.md +76 -0
- package/templates/chat-app/.cursor/skills/typescript/SKILL.md +52 -0
- package/templates/chat-app/.cursor/skills/ultracite/SKILL.md +128 -0
- package/templates/chat-app/app/(chat)/actions.ts +1 -1
- package/templates/chat-app/app/(chat)/api/chat/[id]/stream/route.ts +6 -5
- package/templates/chat-app/app/(chat)/api/chat/route.ts +14 -15
- package/templates/chat-app/app/(chat)/chat-providers.tsx +2 -2
- package/templates/chat-app/app/(chat)/layout.tsx +7 -6
- package/templates/chat-app/app/api/cron/cleanup/route.ts +4 -3
- package/templates/chat-app/app/globals.css +22 -22
- package/templates/chat-app/app/layout.tsx +1 -1
- package/templates/chat-app/biome.jsonc +3 -3
- package/templates/chat-app/chat.config.ts +47 -20
- package/templates/chat-app/components/anonymous-session-init.tsx +4 -12
- package/templates/chat-app/components/artifact-actions.tsx +5 -5
- package/templates/chat-app/components/artifact-panel.tsx +6 -6
- package/templates/chat-app/components/assistant-message.tsx +1 -1
- package/templates/chat-app/components/chat/chat-layout.tsx +2 -2
- package/templates/chat-app/components/chat/chat-welcome.tsx +1 -0
- package/templates/chat-app/components/chat-features-definitions.ts +11 -8
- package/templates/chat-app/components/chat-menu-items.tsx +4 -4
- package/templates/chat-app/components/chat-sync.tsx +1 -1
- package/templates/chat-app/components/clone-chat-button.tsx +2 -2
- package/templates/chat-app/components/code-editor.tsx +5 -5
- package/templates/chat-app/components/connectors-dropdown.tsx +2 -2
- package/templates/chat-app/components/console.tsx +5 -5
- package/templates/chat-app/components/create-artifact.tsx +28 -28
- package/templates/chat-app/components/data-stream-provider.tsx +2 -2
- package/templates/chat-app/components/deep-research-progress.tsx +2 -2
- package/templates/chat-app/components/delete-chat-dialog.tsx +3 -3
- package/templates/chat-app/components/delete-project-dialog.tsx +3 -3
- package/templates/chat-app/components/diffview.tsx +3 -3
- package/templates/chat-app/components/favicon-group.tsx +7 -7
- package/templates/chat-app/components/header-breadcrumb.tsx +11 -11
- package/templates/chat-app/components/image-editor.tsx +5 -5
- package/templates/chat-app/components/image-modal.tsx +4 -4
- package/templates/chat-app/components/interactive-chart-impl.tsx +269 -0
- package/templates/chat-app/components/interactive-charts.tsx +18 -246
- package/templates/chat-app/components/lexical-chat-input.tsx +10 -10
- package/templates/chat-app/components/message-editor.tsx +3 -3
- package/templates/chat-app/components/message-parts.tsx +8 -3
- package/templates/chat-app/components/messages-pane.tsx +4 -4
- package/templates/chat-app/components/messages.tsx +5 -5
- package/templates/chat-app/components/model-selector.tsx +4 -1
- package/templates/chat-app/components/multimodal-input.tsx +14 -5
- package/templates/chat-app/components/part/code-execution.tsx +4 -1
- package/templates/chat-app/components/part/document-common.tsx +8 -8
- package/templates/chat-app/components/part/document-preview.tsx +34 -16
- package/templates/chat-app/components/part/document-tool.tsx +3 -3
- package/templates/chat-app/components/part/dynamic-tool.tsx +3 -3
- package/templates/chat-app/components/part/generate-video.tsx +54 -0
- package/templates/chat-app/components/part/message-reasoning.tsx +3 -3
- package/templates/chat-app/components/project-details-dialog.tsx +4 -4
- package/templates/chat-app/components/project-home.tsx +1 -0
- package/templates/chat-app/components/project-icon-picker.tsx +5 -5
- package/templates/chat-app/components/project-icon.tsx +4 -4
- package/templates/chat-app/components/project-menu-items.tsx +3 -3
- package/templates/chat-app/components/research-tasks.tsx +3 -3
- package/templates/chat-app/components/sandbox.tsx +4 -4
- package/templates/chat-app/components/search-chats-dialog.tsx +11 -11
- package/templates/chat-app/components/settings/connectors-settings.tsx +1 -1
- package/templates/chat-app/components/settings/settings-nav.tsx +1 -1
- package/templates/chat-app/components/sheet-editor.tsx +5 -5
- package/templates/chat-app/components/sidebar-chats-list.tsx +5 -5
- package/templates/chat-app/components/suggested-actions.tsx +3 -3
- package/templates/chat-app/components/text-editor.tsx +5 -5
- package/templates/chat-app/components/toolbar.tsx +6 -6
- package/templates/chat-app/components/upgrade-cta/login-cta-banner.tsx +5 -5
- package/templates/chat-app/components/upgrade-cta/login-prompt.tsx +4 -4
- package/templates/chat-app/components/upgrade-cta/share-menu-item.tsx +3 -3
- package/templates/chat-app/components/user-message.tsx +3 -3
- package/templates/chat-app/components/version-footer.tsx +4 -4
- package/templates/chat-app/hooks/chat-sync-hooks.ts +0 -55
- package/templates/chat-app/hooks/use-artifact.tsx +3 -3
- package/templates/chat-app/hooks/use-auto-focus.ts +37 -7
- package/templates/chat-app/hooks/use-media-query.tsx +2 -4
- package/templates/chat-app/lib/ai/active-gateway.ts +1 -1
- package/templates/chat-app/lib/ai/ai-gateway-models-schemas.ts +30 -6
- package/templates/chat-app/lib/ai/app-model-id.ts +1 -1
- package/templates/chat-app/lib/ai/app-models.ts +4 -4
- package/templates/chat-app/lib/ai/eval-agent.ts +5 -5
- package/templates/chat-app/lib/ai/followup-suggestions.ts +1 -1
- package/templates/chat-app/lib/ai/gateway-model-defaults.ts +131 -41
- package/templates/chat-app/lib/ai/gateways/gateway-provider.ts +10 -6
- package/templates/chat-app/lib/ai/gateways/openai-compatible-gateway.ts +9 -4
- package/templates/chat-app/lib/ai/gateways/openai-gateway.ts +9 -4
- package/templates/chat-app/lib/ai/gateways/openrouter-gateway.ts +17 -12
- package/templates/chat-app/lib/ai/gateways/registry.ts +9 -0
- package/templates/chat-app/lib/ai/gateways/vercel-gateway.ts +36 -4
- package/templates/chat-app/lib/ai/mcp/cache.ts +13 -13
- package/templates/chat-app/lib/ai/model-data.ts +21 -20
- package/templates/chat-app/lib/ai/models.generated.ts +4397 -3592
- package/templates/chat-app/lib/ai/models.ts +1 -1
- package/templates/chat-app/lib/ai/providers.ts +10 -0
- package/templates/chat-app/lib/ai/text-splitter.ts +3 -4
- package/templates/chat-app/lib/ai/to-model-data.ts +1 -0
- package/templates/chat-app/lib/ai/tools/code-execution.ts +122 -53
- package/templates/chat-app/lib/ai/tools/deep-research/configuration.ts +35 -32
- package/templates/chat-app/lib/ai/tools/deep-research/pipeline.ts +2 -2
- package/templates/chat-app/lib/ai/tools/deep-research/types.ts +9 -9
- package/templates/chat-app/lib/ai/tools/documents/types.ts +4 -4
- package/templates/chat-app/lib/ai/tools/generate-image.ts +42 -20
- package/templates/chat-app/lib/ai/tools/generate-video.ts +166 -0
- package/templates/chat-app/lib/ai/tools/get-weather.ts +20 -20
- package/templates/chat-app/lib/ai/tools/read-document.ts +3 -3
- package/templates/chat-app/lib/ai/tools/steps/multi-query-web-search.ts +11 -11
- package/templates/chat-app/lib/ai/tools/steps/web-search.ts +6 -6
- package/templates/chat-app/lib/ai/tools/tools-definitions.ts +10 -5
- package/templates/chat-app/lib/ai/tools/tools.ts +15 -6
- package/templates/chat-app/lib/ai/tools/types.ts +2 -2
- package/templates/chat-app/lib/ai/types.ts +22 -13
- package/templates/chat-app/lib/artifacts/code/client.tsx +5 -5
- package/templates/chat-app/lib/artifacts/sheet/client.tsx +2 -2
- package/templates/chat-app/lib/artifacts/text/client.tsx +18 -3
- package/templates/chat-app/lib/clone-messages.test.ts +6 -1
- package/templates/chat-app/lib/config-requirements.ts +19 -10
- package/templates/chat-app/lib/config-schema.ts +189 -103
- package/templates/chat-app/lib/config.ts +4 -4
- package/templates/chat-app/lib/credits/cost-accumulator.ts +11 -8
- package/templates/chat-app/lib/env-schema.ts +1 -1
- package/templates/chat-app/lib/features-config.ts +6 -6
- package/templates/chat-app/lib/stores/with-threads.ts +3 -3
- package/templates/chat-app/lib/thread-utils.ts +2 -2
- package/templates/chat-app/lib/types/anonymous.ts +4 -4
- package/templates/chat-app/lib/types/ui-chat.ts +7 -7
- package/templates/chat-app/lib/utils/download-assets.ts +3 -3
- package/templates/chat-app/lib/utils/rate-limit.ts +8 -8
- package/templates/chat-app/next.config.ts +0 -25
- package/templates/chat-app/package.json +15 -15
- package/templates/chat-app/playwright.config.ts +5 -5
- package/templates/chat-app/providers/chat-id-provider.tsx +5 -5
- package/templates/chat-app/providers/chat-input-provider.tsx +15 -15
- package/templates/chat-app/providers/chat-models-provider.tsx +3 -3
- package/templates/chat-app/providers/default-model-provider.tsx +5 -5
- package/templates/chat-app/providers/parse-chat-id-from-pathname.test.ts +16 -0
- package/templates/chat-app/providers/session-provider.tsx +2 -2
- package/templates/chat-app/scripts/check-env.ts +36 -4
- package/templates/chat-app/tests/artifacts.e2e.ts +7 -0
- package/templates/chat-app/tests/auth.setup.e2e.ts +10 -0
- package/templates/chat-app/tests/chat.e2e.ts +7 -0
- package/templates/chat-app/tests/reasoning.e2e.ts +7 -0
- package/templates/chat-app/tests/reasoning.setup.e2e.ts +10 -0
- package/templates/chat-app/trpc/routers/chat.router.ts +1 -1
- package/templates/chat-app/trpc/routers/mcp.router.ts +3 -3
- package/templates/chat-app/vitest.config.ts +7 -0
- package/templates/chat-app/next-env.d.ts +0 -6
- package/templates/chat-app/tsconfig.tsbuildinfo +0 -1
|
@@ -1,248 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { EChartsOption } from "echarts-for-react/lib/types";
|
|
3
|
-
import { motion } from "motion/react";
|
|
4
|
-
import { useTheme } from "next-themes";
|
|
1
|
+
import dynamic from "next/dynamic";
|
|
5
2
|
import { Card } from "@/components/ui/card";
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
x_scale?: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
function InteractiveChart({ chart }: { chart: BaseChart }) {
|
|
28
|
-
const { resolvedTheme } = useTheme();
|
|
29
|
-
// TOOD: Update for multitheme support
|
|
30
|
-
// const textColor = theme === 'dark' ? '#e5e5e5' : '#171717';
|
|
31
|
-
const textColor = "#e5e5e5";
|
|
32
|
-
// const gridColor =
|
|
33
|
-
// theme === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
|
|
34
|
-
const gridColor = "rgba(255, 255, 255, 0.1)";
|
|
35
|
-
// const tooltipBg = theme === 'dark' ? '#171717' : '#ffffff';
|
|
36
|
-
const tooltipBg = "#171717";
|
|
37
|
-
|
|
38
|
-
const sharedOptions: EChartsOption = {
|
|
39
|
-
backgroundColor: "transparent",
|
|
40
|
-
grid: {
|
|
41
|
-
top: 50,
|
|
42
|
-
right: 32,
|
|
43
|
-
bottom: 32,
|
|
44
|
-
left: 32,
|
|
45
|
-
containLabel: true,
|
|
46
|
-
},
|
|
47
|
-
legend: {
|
|
48
|
-
textStyle: { color: textColor },
|
|
49
|
-
top: 8,
|
|
50
|
-
icon: "circle",
|
|
51
|
-
itemWidth: 8,
|
|
52
|
-
itemHeight: 8,
|
|
53
|
-
itemGap: 16,
|
|
54
|
-
},
|
|
55
|
-
tooltip: {
|
|
56
|
-
trigger: "axis",
|
|
57
|
-
backgroundColor: tooltipBg,
|
|
58
|
-
borderWidth: 0,
|
|
59
|
-
padding: [6, 10],
|
|
60
|
-
className:
|
|
61
|
-
"echarts-tooltip rounded-lg! border! border-neutral-200! dark:border-neutral-800!",
|
|
62
|
-
textStyle: {
|
|
63
|
-
color: textColor,
|
|
64
|
-
fontSize: 13,
|
|
65
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const getChartOptions = (): EChartsOption => {
|
|
71
|
-
const defaultAxisOptions = {
|
|
72
|
-
axisLine: { show: true, lineStyle: { color: gridColor } },
|
|
73
|
-
axisTick: { show: false },
|
|
74
|
-
axisLabel: {
|
|
75
|
-
color: textColor,
|
|
76
|
-
margin: 8,
|
|
77
|
-
fontSize: 11,
|
|
78
|
-
hideOverlap: true,
|
|
79
|
-
},
|
|
80
|
-
nameTextStyle: {
|
|
81
|
-
color: textColor,
|
|
82
|
-
fontSize: 13,
|
|
83
|
-
padding: [0, 0, 0, 0],
|
|
84
|
-
},
|
|
85
|
-
splitLine: {
|
|
86
|
-
show: true,
|
|
87
|
-
lineStyle: { color: gridColor, type: "dashed" },
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
if (chart.type === "line" || chart.type === "scatter") {
|
|
92
|
-
const series = chart.elements.map((e, index) => ({
|
|
93
|
-
name: e.label,
|
|
94
|
-
type: chart.type,
|
|
95
|
-
data: e.points.map((p: [number | string, number]) => {
|
|
96
|
-
// Handle datetime x-axis
|
|
97
|
-
const x =
|
|
98
|
-
chart.x_scale === "datetime" ? new Date(p[0]).getTime() : p[0];
|
|
99
|
-
return [x, p[1]];
|
|
100
|
-
}),
|
|
101
|
-
smooth: true,
|
|
102
|
-
symbolSize: chart.type === "scatter" ? 10 : 0,
|
|
103
|
-
lineStyle: {
|
|
104
|
-
width: 2,
|
|
105
|
-
color: CHART_COLORS[index % CHART_COLORS.length],
|
|
106
|
-
},
|
|
107
|
-
itemStyle: {
|
|
108
|
-
color: CHART_COLORS[index % CHART_COLORS.length],
|
|
109
|
-
},
|
|
110
|
-
areaStyle:
|
|
111
|
-
chart.type === "line"
|
|
112
|
-
? {
|
|
113
|
-
color: {
|
|
114
|
-
type: "linear",
|
|
115
|
-
x: 0,
|
|
116
|
-
y: 0,
|
|
117
|
-
x2: 0,
|
|
118
|
-
y2: 1,
|
|
119
|
-
colorStops: [
|
|
120
|
-
{
|
|
121
|
-
offset: 0,
|
|
122
|
-
color: `${CHART_COLORS[index % CHART_COLORS.length]}15`, // 15 = 10% opacity
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
offset: 1,
|
|
126
|
-
color: "rgba(23, 23, 23, 0)",
|
|
127
|
-
// theme === 'dark'
|
|
128
|
-
// ? 'rgba(23, 23, 23, 0)'
|
|
129
|
-
// : 'rgba(255, 255, 255, 0)',
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
},
|
|
133
|
-
}
|
|
134
|
-
: undefined,
|
|
135
|
-
}));
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
...sharedOptions,
|
|
139
|
-
xAxis: {
|
|
140
|
-
type: chart.x_scale === "datetime" ? "time" : "value",
|
|
141
|
-
name: chart.x_label,
|
|
142
|
-
nameLocation: "middle",
|
|
143
|
-
nameGap: 40,
|
|
144
|
-
scale: true,
|
|
145
|
-
...defaultAxisOptions,
|
|
146
|
-
axisLabel: {
|
|
147
|
-
...defaultAxisOptions.axisLabel,
|
|
148
|
-
formatter:
|
|
149
|
-
chart.x_scale === "datetime"
|
|
150
|
-
? (value: number) => {
|
|
151
|
-
const date = new Date(value);
|
|
152
|
-
return date.toLocaleDateString("en-US", {
|
|
153
|
-
month: "short",
|
|
154
|
-
year: "numeric",
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
: undefined,
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
yAxis: {
|
|
161
|
-
type: "value",
|
|
162
|
-
name: chart.y_label,
|
|
163
|
-
nameLocation: "middle",
|
|
164
|
-
nameGap: 50,
|
|
165
|
-
position: "right",
|
|
166
|
-
scale: true,
|
|
167
|
-
...defaultAxisOptions,
|
|
168
|
-
},
|
|
169
|
-
series,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (chart.type === "bar") {
|
|
174
|
-
const data = chart.elements.reduce((acc: Record<string, any[]>, item) => {
|
|
175
|
-
const key = item.group;
|
|
176
|
-
if (!acc[key]) {
|
|
177
|
-
acc[key] = [];
|
|
178
|
-
}
|
|
179
|
-
acc[key].push(item);
|
|
180
|
-
return acc;
|
|
181
|
-
}, {});
|
|
182
|
-
|
|
183
|
-
const series = Object.entries(data).map(([group, elements], index) => ({
|
|
184
|
-
name: group,
|
|
185
|
-
type: "bar",
|
|
186
|
-
stack: "total",
|
|
187
|
-
data: elements?.map((e) => [e.label, e.value]),
|
|
188
|
-
itemStyle: {
|
|
189
|
-
color: CHART_COLORS[index % CHART_COLORS.length],
|
|
190
|
-
},
|
|
191
|
-
emphasis: {
|
|
192
|
-
itemStyle: {
|
|
193
|
-
shadowBlur: 10,
|
|
194
|
-
shadowColor: "rgba(0,0,0,0.3)",
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
}));
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
...sharedOptions,
|
|
201
|
-
xAxis: {
|
|
202
|
-
type: "category",
|
|
203
|
-
name: chart.x_label,
|
|
204
|
-
nameLocation: "middle",
|
|
205
|
-
nameGap: 40,
|
|
206
|
-
...defaultAxisOptions,
|
|
207
|
-
},
|
|
208
|
-
yAxis: {
|
|
209
|
-
type: "value",
|
|
210
|
-
name: chart.y_label,
|
|
211
|
-
nameLocation: "middle",
|
|
212
|
-
nameGap: 50,
|
|
213
|
-
position: "right",
|
|
214
|
-
...defaultAxisOptions,
|
|
215
|
-
},
|
|
216
|
-
series,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return sharedOptions;
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
return (
|
|
224
|
-
<motion.div
|
|
225
|
-
animate={{ opacity: 1, y: 0 }}
|
|
226
|
-
initial={{ opacity: 0, y: 20 }}
|
|
227
|
-
transition={{ duration: 0.5 }}
|
|
228
|
-
>
|
|
229
|
-
<Card className="overflow-hidden border-neutral-200 bg-white dark:border-neutral-800 dark:bg-neutral-900">
|
|
230
|
-
<div className="p-6">
|
|
231
|
-
{chart.title && (
|
|
232
|
-
<h3 className="mb-4 font-medium text-lg text-neutral-900 dark:text-neutral-100">
|
|
233
|
-
{chart.title}
|
|
234
|
-
</h3>
|
|
235
|
-
)}
|
|
236
|
-
<ReactECharts
|
|
237
|
-
notMerge={true}
|
|
238
|
-
option={getChartOptions()}
|
|
239
|
-
style={{ height: "400px", width: "100%" }}
|
|
240
|
-
theme={resolvedTheme === "dark" ? "dark" : undefined}
|
|
241
|
-
/>
|
|
242
|
-
</div>
|
|
243
|
-
</Card>
|
|
244
|
-
</motion.div>
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
export default InteractiveChart;
|
|
4
|
+
export type { BaseChart } from "./interactive-chart-impl";
|
|
5
|
+
|
|
6
|
+
const ChartSkeleton = () => (
|
|
7
|
+
<Card className="overflow-hidden border-neutral-200 bg-white dark:border-neutral-800 dark:bg-neutral-900">
|
|
8
|
+
<div className="flex h-[400px] items-center justify-center p-6">
|
|
9
|
+
<div className="size-8 animate-pulse rounded-md bg-muted" />
|
|
10
|
+
</div>
|
|
11
|
+
</Card>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export default dynamic(
|
|
15
|
+
() => import("./interactive-chart-impl").then((m) => m.default),
|
|
16
|
+
{
|
|
17
|
+
loading: () => <ChartSkeleton />,
|
|
18
|
+
ssr: false,
|
|
19
|
+
}
|
|
20
|
+
);
|
|
@@ -78,24 +78,24 @@ function EditorRefPlugin({
|
|
|
78
78
|
return null;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
focus: () => void;
|
|
81
|
+
interface LexicalChatInputRef {
|
|
83
82
|
clear: () => void;
|
|
83
|
+
focus: () => void;
|
|
84
84
|
getValue: () => string;
|
|
85
|
-
}
|
|
85
|
+
}
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
interface LexicalChatInputProps {
|
|
88
|
+
autoFocus?: boolean;
|
|
89
|
+
className?: string;
|
|
90
|
+
"data-testid"?: string;
|
|
88
91
|
initialValue?: string;
|
|
92
|
+
maxRows?: number;
|
|
93
|
+
onEnterSubmit?: (event: KeyboardEvent) => boolean;
|
|
89
94
|
onInputChange?: (value: string) => void;
|
|
90
95
|
onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;
|
|
91
96
|
onPaste?: (event: ClipboardEvent<HTMLDivElement>) => void;
|
|
92
|
-
onEnterSubmit?: (event: KeyboardEvent) => boolean;
|
|
93
97
|
placeholder?: string;
|
|
94
|
-
|
|
95
|
-
className?: string;
|
|
96
|
-
maxRows?: number;
|
|
97
|
-
"data-testid"?: string;
|
|
98
|
-
};
|
|
98
|
+
}
|
|
99
99
|
|
|
100
100
|
const theme = {
|
|
101
101
|
root: "lexical-root",
|
|
@@ -10,12 +10,12 @@ import {
|
|
|
10
10
|
import { ChatInputProvider } from "@/providers/chat-input-provider";
|
|
11
11
|
import { MultimodalInput } from "./multimodal-input";
|
|
12
12
|
|
|
13
|
-
export
|
|
13
|
+
export interface MessageEditorProps {
|
|
14
14
|
chatId: string;
|
|
15
15
|
message: ChatMessage;
|
|
16
|
-
setMode: Dispatch<SetStateAction<"view" | "edit">>;
|
|
17
16
|
parentMessageId: string | null;
|
|
18
|
-
|
|
17
|
+
setMode: Dispatch<SetStateAction<"view" | "edit">>;
|
|
18
|
+
}
|
|
19
19
|
|
|
20
20
|
function MessageEditorContent({
|
|
21
21
|
chatId,
|
|
@@ -19,6 +19,7 @@ import { DeepResearch } from "./part/deep-research";
|
|
|
19
19
|
import { DocumentTool } from "./part/document-tool";
|
|
20
20
|
import { DynamicToolPart } from "./part/dynamic-tool";
|
|
21
21
|
import { GenerateImage } from "./part/generate-image";
|
|
22
|
+
import { GenerateVideo } from "./part/generate-video";
|
|
22
23
|
import { ReasoningPart } from "./part/message-reasoning";
|
|
23
24
|
import { ReadDocument } from "./part/read-document";
|
|
24
25
|
|
|
@@ -27,11 +28,11 @@ import { TextMessagePart } from "./part/text-message-part";
|
|
|
27
28
|
import { Weather } from "./part/weather";
|
|
28
29
|
import { WebSearch } from "./part/web-search";
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
messageId: string;
|
|
31
|
+
interface MessagePartsProps {
|
|
32
32
|
isLoading: boolean;
|
|
33
33
|
isReadonly: boolean;
|
|
34
|
-
|
|
34
|
+
messageId: string;
|
|
35
|
+
}
|
|
35
36
|
|
|
36
37
|
function ToolPart({
|
|
37
38
|
part,
|
|
@@ -77,6 +78,10 @@ function ToolPart({
|
|
|
77
78
|
return <GenerateImage tool={part} />;
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
if (type === "tool-generateVideo") {
|
|
82
|
+
return <GenerateVideo tool={part} />;
|
|
83
|
+
}
|
|
84
|
+
|
|
80
85
|
if (type === "tool-deepResearch") {
|
|
81
86
|
return <DeepResearch messageId={messageId} part={part} />;
|
|
82
87
|
}
|
|
@@ -8,12 +8,12 @@ import { cn } from "@/lib/utils";
|
|
|
8
8
|
import { Messages } from "./messages";
|
|
9
9
|
import { MultimodalInput } from "./multimodal-input";
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
interface MessagesPaneProps {
|
|
12
12
|
chatId: string;
|
|
13
|
-
status: UseChatHelpers<ChatMessage>["status"];
|
|
14
|
-
isReadonly: boolean;
|
|
15
13
|
className?: string;
|
|
16
|
-
|
|
14
|
+
isReadonly: boolean;
|
|
15
|
+
status: UseChatHelpers<ChatMessage>["status"];
|
|
16
|
+
}
|
|
17
17
|
|
|
18
18
|
function PureMessagesPane({
|
|
19
19
|
chatId,
|
|
@@ -12,9 +12,9 @@ import { PreviewMessage } from "./message";
|
|
|
12
12
|
import { ResponseErrorMessage } from "./response-error-message";
|
|
13
13
|
import { ThinkingMessage } from "./thinking-message";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
interface PureMessagesInternalProps {
|
|
16
16
|
isReadonly: boolean;
|
|
17
|
-
}
|
|
17
|
+
}
|
|
18
18
|
|
|
19
19
|
const PureMessagesInternal = memo(
|
|
20
20
|
({ isReadonly }: PureMessagesInternalProps) => {
|
|
@@ -55,11 +55,11 @@ const PureMessagesInternal = memo(
|
|
|
55
55
|
}
|
|
56
56
|
);
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
interface MessagesProps {
|
|
59
|
+
className?: string;
|
|
59
60
|
isReadonly: boolean;
|
|
60
61
|
onModelChange?: (modelId: string) => void;
|
|
61
|
-
|
|
62
|
-
};
|
|
62
|
+
}
|
|
63
63
|
|
|
64
64
|
function PureMessages({ isReadonly, className }: MessagesProps) {
|
|
65
65
|
return (
|
|
@@ -168,7 +168,10 @@ function PureModelSelector({
|
|
|
168
168
|
const [featureFilters, setFeatureFilters] =
|
|
169
169
|
useState<FeatureFilter>(initialFilters);
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
interface ModelItem {
|
|
172
|
+
disabled: boolean;
|
|
173
|
+
model: AppModelDefinition;
|
|
174
|
+
}
|
|
172
175
|
|
|
173
176
|
const models = useMemo<ModelItem[]>(
|
|
174
177
|
() =>
|
|
@@ -83,6 +83,7 @@ function PureMultimodalInput({
|
|
|
83
83
|
chatId,
|
|
84
84
|
status,
|
|
85
85
|
className,
|
|
86
|
+
autoFocus = false,
|
|
86
87
|
isEditMode = false,
|
|
87
88
|
parentMessageId,
|
|
88
89
|
onSendMessage,
|
|
@@ -90,6 +91,7 @@ function PureMultimodalInput({
|
|
|
90
91
|
chatId: string;
|
|
91
92
|
status: UseChatHelpers<ChatMessage>["status"];
|
|
92
93
|
className?: string;
|
|
94
|
+
autoFocus?: boolean;
|
|
93
95
|
isEditMode?: boolean;
|
|
94
96
|
parentMessageId: string | null;
|
|
95
97
|
onSendMessage?: (message: ChatMessage) => void | Promise<void>;
|
|
@@ -150,7 +152,7 @@ function PureMultimodalInput({
|
|
|
150
152
|
|
|
151
153
|
// Helper function to auto-switch to PDF-compatible model
|
|
152
154
|
const switchToPdfCompatibleModel = useCallback(() => {
|
|
153
|
-
const pdfModel = config.
|
|
155
|
+
const pdfModel = config.ai.workflows.pdf;
|
|
154
156
|
const defaultPdfModelDef = getModelById(pdfModel);
|
|
155
157
|
if (defaultPdfModelDef) {
|
|
156
158
|
toast.success(`Switched to ${defaultPdfModelDef.name} (supports PDF)`);
|
|
@@ -161,7 +163,7 @@ function PureMultimodalInput({
|
|
|
161
163
|
|
|
162
164
|
// Helper function to auto-switch to image-compatible model
|
|
163
165
|
const switchToImageCompatibleModel = useCallback(() => {
|
|
164
|
-
const imageModel = config.
|
|
166
|
+
const imageModel = config.ai.workflows.chatImageCompatible;
|
|
165
167
|
const defaultImageModelDef = getModelById(imageModel);
|
|
166
168
|
if (defaultImageModelDef) {
|
|
167
169
|
toast.success(
|
|
@@ -642,7 +644,7 @@ function PureMultimodalInput({
|
|
|
642
644
|
/>
|
|
643
645
|
|
|
644
646
|
<LexicalChatInput
|
|
645
|
-
autoFocus
|
|
647
|
+
autoFocus={autoFocus}
|
|
646
648
|
className="max-h-[max(35svh,5rem)] min-h-[60px] overflow-y-scroll sm:min-h-[80px]"
|
|
647
649
|
data-testid="multimodal-input"
|
|
648
650
|
initialValue={getInitialInput()}
|
|
@@ -918,10 +920,12 @@ const ChatInputBottomControls = memo(PureChatInputBottomControls);
|
|
|
918
920
|
export const MultimodalInput = memo(
|
|
919
921
|
PureMultimodalInput,
|
|
920
922
|
(prevProps, nextProps) => {
|
|
921
|
-
// More specific equality checks to prevent unnecessary re-renders
|
|
922
923
|
if (prevProps.status !== nextProps.status) {
|
|
923
924
|
return false;
|
|
924
925
|
}
|
|
926
|
+
if (prevProps.autoFocus !== nextProps.autoFocus) {
|
|
927
|
+
return false;
|
|
928
|
+
}
|
|
925
929
|
if (prevProps.isEditMode !== nextProps.isEditMode) {
|
|
926
930
|
return false;
|
|
927
931
|
}
|
|
@@ -931,7 +935,12 @@ export const MultimodalInput = memo(
|
|
|
931
935
|
if (prevProps.className !== nextProps.className) {
|
|
932
936
|
return false;
|
|
933
937
|
}
|
|
934
|
-
|
|
938
|
+
if (prevProps.parentMessageId !== nextProps.parentMessageId) {
|
|
939
|
+
return false;
|
|
940
|
+
}
|
|
941
|
+
if (prevProps.onSendMessage !== nextProps.onSendMessage) {
|
|
942
|
+
return false;
|
|
943
|
+
}
|
|
935
944
|
return true;
|
|
936
945
|
}
|
|
937
946
|
);
|
|
@@ -19,7 +19,10 @@ function isBaseChart(input: unknown): input is BaseChart {
|
|
|
19
19
|
return hasType && hasTitle && hasElements;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
interface PngChart {
|
|
23
|
+
base64: string;
|
|
24
|
+
format: string;
|
|
25
|
+
}
|
|
23
26
|
|
|
24
27
|
function isPngChart(input: unknown): input is PngChart {
|
|
25
28
|
if (typeof input !== "object" || input === null) {
|
|
@@ -48,16 +48,16 @@ const getActionText = (
|
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
interface DocumentToolResultProps {
|
|
52
|
+
isReadonly: boolean;
|
|
53
|
+
messageId: string;
|
|
53
54
|
result: {
|
|
54
55
|
id: string;
|
|
55
56
|
title: string;
|
|
56
57
|
kind: ArtifactKind;
|
|
57
58
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
};
|
|
59
|
+
type: "create" | "update";
|
|
60
|
+
}
|
|
61
61
|
|
|
62
62
|
function PureDocumentToolResult({
|
|
63
63
|
type,
|
|
@@ -103,11 +103,11 @@ function PureDocumentToolResult({
|
|
|
103
103
|
|
|
104
104
|
export const DocumentToolResult = memo(PureDocumentToolResult, () => true);
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
type: "create" | "update";
|
|
106
|
+
interface DocumentToolCallProps {
|
|
108
107
|
args: { title?: string };
|
|
109
108
|
isReadonly: boolean;
|
|
110
|
-
|
|
109
|
+
type: "create" | "update";
|
|
110
|
+
}
|
|
111
111
|
|
|
112
112
|
function PureDocumentToolCall({
|
|
113
113
|
type,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import equal from "fast-deep-equal";
|
|
4
4
|
import { File, Loader2, Maximize, Pencil } from "lucide-react";
|
|
5
|
+
import dynamic from "next/dynamic";
|
|
5
6
|
import { type MouseEvent, memo, useCallback, useMemo, useRef } from "react";
|
|
6
7
|
import { useDocuments } from "@/hooks/chat-sync-hooks";
|
|
7
8
|
import { useArtifact } from "@/hooks/use-artifact";
|
|
@@ -9,33 +10,50 @@ import type { ArtifactKind } from "@/lib/artifacts/artifact-kind";
|
|
|
9
10
|
import type { Document } from "@/lib/db/schema";
|
|
10
11
|
import { cn } from "@/lib/utils";
|
|
11
12
|
import type { UIArtifact } from "../artifact-panel";
|
|
12
|
-
import { CodeEditor } from "../code-editor";
|
|
13
13
|
import { InlineDocumentSkeleton } from "../document-skeleton";
|
|
14
|
-
import { ImageEditor } from "../image-editor";
|
|
15
|
-
import { SpreadsheetEditor } from "../sheet-editor";
|
|
16
|
-
import { Editor } from "../text-editor";
|
|
17
14
|
import { DocumentToolCall, DocumentToolResult } from "./document-common";
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
const CodeEditor = dynamic(
|
|
17
|
+
() => import("../code-editor").then((m) => ({ default: m.CodeEditor })),
|
|
18
|
+
{ loading: () => <InlineDocumentSkeleton />, ssr: false }
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const Editor = dynamic(
|
|
22
|
+
() => import("../text-editor").then((m) => ({ default: m.Editor })),
|
|
23
|
+
{ loading: () => <InlineDocumentSkeleton />, ssr: false }
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const ImageEditor = dynamic(
|
|
27
|
+
() => import("../image-editor").then((m) => ({ default: m.ImageEditor })),
|
|
28
|
+
{ loading: () => <InlineDocumentSkeleton />, ssr: false }
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const SpreadsheetEditor = dynamic(
|
|
32
|
+
() =>
|
|
33
|
+
import("../sheet-editor").then((m) => ({ default: m.SpreadsheetEditor })),
|
|
34
|
+
{ loading: () => <InlineDocumentSkeleton />, ssr: false }
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
interface DocumentPreviewInput {
|
|
22
38
|
content: string;
|
|
23
|
-
|
|
39
|
+
kind: ArtifactKind;
|
|
40
|
+
title: string;
|
|
41
|
+
}
|
|
24
42
|
|
|
25
|
-
|
|
43
|
+
interface DocumentPreviewOutput {
|
|
26
44
|
documentId: string;
|
|
27
|
-
title: string;
|
|
28
45
|
kind: ArtifactKind;
|
|
29
|
-
|
|
46
|
+
title: string;
|
|
47
|
+
}
|
|
30
48
|
|
|
31
|
-
|
|
32
|
-
isReadonly: boolean;
|
|
33
|
-
output?: DocumentPreviewOutput;
|
|
49
|
+
interface DocumentPreviewProps {
|
|
34
50
|
input?: DocumentPreviewInput;
|
|
51
|
+
isLastArtifact?: boolean;
|
|
52
|
+
isReadonly: boolean;
|
|
35
53
|
messageId: string;
|
|
54
|
+
output?: DocumentPreviewOutput;
|
|
36
55
|
type?: "create" | "update";
|
|
37
|
-
|
|
38
|
-
};
|
|
56
|
+
}
|
|
39
57
|
|
|
40
58
|
export function DocumentPreview({
|
|
41
59
|
isReadonly,
|
|
@@ -16,11 +16,11 @@ type DocumentTool = Extract<
|
|
|
16
16
|
{ type: DocumentToolType }
|
|
17
17
|
>;
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
tool: DocumentTool;
|
|
19
|
+
interface DocumentToolComponentProps {
|
|
21
20
|
isReadonly: boolean;
|
|
22
21
|
messageId: string;
|
|
23
|
-
|
|
22
|
+
tool: DocumentTool;
|
|
23
|
+
}
|
|
24
24
|
|
|
25
25
|
function PureDocumentTool({
|
|
26
26
|
tool,
|
|
@@ -16,11 +16,11 @@ import { parseToolId } from "@/lib/ai/mcp-name-id";
|
|
|
16
16
|
import { useTRPC } from "@/trpc/react";
|
|
17
17
|
import { getGoogleFaviconUrl } from "../get-google-favicon-url";
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
messageId: string;
|
|
19
|
+
interface DynamicToolPartProps {
|
|
21
20
|
isReadonly: boolean;
|
|
21
|
+
messageId: string;
|
|
22
22
|
part: DynamicToolUIPart;
|
|
23
|
-
}
|
|
23
|
+
}
|
|
24
24
|
|
|
25
25
|
export function DynamicToolPart({ part }: DynamicToolPartProps) {
|
|
26
26
|
const trpc = useTRPC();
|