@chat-js/cli 0.4.0 → 0.6.1
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 +1548 -969
- package/package.json +4 -3
- package/templates/chat-app/app/(auth)/device-login/page.tsx +37 -0
- package/templates/chat-app/app/(auth)/login/page.tsx +26 -2
- package/templates/chat-app/app/(auth)/register/page.tsx +0 -12
- package/templates/chat-app/app/(chat)/api/chat/filter-reasoning-parts.ts +1 -1
- package/templates/chat-app/app/(chat)/api/chat/route.ts +13 -5
- package/templates/chat-app/app/(chat)/layout.tsx +4 -1
- package/templates/chat-app/app/api/trpc/[trpc]/route.ts +1 -0
- package/templates/chat-app/app/globals.css +9 -9
- package/templates/chat-app/app/layout.tsx +4 -2
- package/templates/chat-app/biome.jsonc +3 -3
- package/templates/chat-app/chat.config.ts +144 -141
- package/templates/chat-app/components/ai-elements/prompt-input.tsx +1 -1
- package/templates/chat-app/components/anonymous-session-init.tsx +10 -6
- package/templates/chat-app/components/artifact-actions.tsx +81 -18
- package/templates/chat-app/components/artifact-panel.tsx +142 -41
- package/templates/chat-app/components/attachment-list.tsx +1 -1
- package/templates/chat-app/components/{social-auth-providers.tsx → auth-providers.tsx} +49 -4
- package/templates/chat-app/components/chat/chat-welcome.tsx +3 -3
- package/templates/chat-app/components/chat-menu-items.tsx +1 -1
- package/templates/chat-app/components/chat-sync.tsx +3 -8
- package/templates/chat-app/components/console.tsx +9 -9
- package/templates/chat-app/components/context-usage.tsx +2 -2
- package/templates/chat-app/components/create-artifact.tsx +15 -5
- package/templates/chat-app/components/data-stream-handler.tsx +57 -16
- package/templates/chat-app/components/device-login-page.tsx +191 -0
- package/templates/chat-app/components/diffview.tsx +8 -2
- package/templates/chat-app/components/electron-auth-handler.tsx +184 -0
- package/templates/chat-app/components/electron-auth-ui.tsx +121 -0
- package/templates/chat-app/components/favicon-group.tsx +1 -1
- package/templates/chat-app/components/feedback-actions.tsx +1 -1
- package/templates/chat-app/components/greeting.tsx +1 -1
- package/templates/chat-app/components/interactive-chart-impl.tsx +3 -4
- package/templates/chat-app/components/interactive-charts.tsx +1 -1
- package/templates/chat-app/components/login-form.tsx +52 -10
- package/templates/chat-app/components/message-editor.tsx +4 -5
- package/templates/chat-app/components/model-selector.tsx +661 -655
- package/templates/chat-app/components/multimodal-input.tsx +13 -10
- package/templates/chat-app/components/parallel-response-cards.tsx +53 -35
- package/templates/chat-app/components/part/code-execution.tsx +8 -2
- package/templates/chat-app/components/part/document-common.tsx +1 -1
- package/templates/chat-app/components/part/document-preview.tsx +5 -5
- package/templates/chat-app/components/part/retrieve-url.tsx +12 -12
- package/templates/chat-app/components/part/text-message-part.tsx +13 -9
- package/templates/chat-app/components/project-chat-item.tsx +1 -1
- package/templates/chat-app/components/project-menu-items.tsx +1 -1
- package/templates/chat-app/components/research-task.tsx +1 -1
- package/templates/chat-app/components/research-tasks.tsx +1 -1
- package/templates/chat-app/components/retry-button.tsx +1 -1
- package/templates/chat-app/components/sandbox.tsx +1 -1
- package/templates/chat-app/components/sheet-editor.tsx +7 -7
- package/templates/chat-app/components/sidebar-chats-list.tsx +1 -1
- package/templates/chat-app/components/sidebar-toggle.tsx +15 -2
- package/templates/chat-app/components/sidebar-top-row.tsx +27 -12
- package/templates/chat-app/components/sidebar-user-nav.tsx +10 -1
- package/templates/chat-app/components/signup-form.tsx +49 -10
- package/templates/chat-app/components/sources.tsx +4 -4
- package/templates/chat-app/components/text-editor.tsx +5 -2
- package/templates/chat-app/components/toolbar.tsx +3 -3
- package/templates/chat-app/components/ui/sidebar.tsx +0 -1
- package/templates/chat-app/components/upgrade-cta/limit-display.tsx +1 -1
- package/templates/chat-app/components/user-message.tsx +135 -134
- package/templates/chat-app/electron.d.ts +41 -0
- package/templates/chat-app/evals/my-eval.eval.ts +3 -1
- package/templates/chat-app/hooks/use-artifact.tsx +13 -13
- package/templates/chat-app/lib/ai/gateways/provider-types.ts +19 -10
- package/templates/chat-app/lib/ai/stream-errors.test.ts +72 -0
- package/templates/chat-app/lib/ai/stream-errors.ts +94 -0
- package/templates/chat-app/lib/ai/tools/code-execution.javascript.ts +171 -0
- package/templates/chat-app/lib/ai/tools/code-execution.python.ts +336 -0
- package/templates/chat-app/lib/ai/tools/code-execution.shared.test.ts +71 -0
- package/templates/chat-app/lib/ai/tools/code-execution.shared.ts +59 -0
- package/templates/chat-app/lib/ai/tools/code-execution.ts +62 -391
- package/templates/chat-app/lib/ai/tools/code-execution.types.ts +24 -0
- package/templates/chat-app/lib/ai/tools/steps/multi-query-web-search.ts +3 -2
- package/templates/chat-app/lib/anonymous-session-client.ts +0 -3
- package/templates/chat-app/lib/artifacts/code/client.tsx +35 -5
- package/templates/chat-app/lib/artifacts/sheet/client.tsx +11 -3
- package/templates/chat-app/lib/auth-client.ts +23 -1
- package/templates/chat-app/lib/auth.ts +18 -1
- package/templates/chat-app/lib/blob.ts +1 -1
- package/templates/chat-app/lib/clone-messages.ts +1 -1
- package/templates/chat-app/lib/config-schema.ts +13 -1
- package/templates/chat-app/lib/constants.ts +3 -4
- package/templates/chat-app/lib/db/migrations/meta/0044_snapshot.json +42 -129
- package/templates/chat-app/lib/db/migrations/meta/_journal.json +1 -1
- package/templates/chat-app/lib/editor/config.ts +4 -4
- package/templates/chat-app/lib/electron-auth.ts +96 -0
- package/templates/chat-app/lib/env-schema.ts +33 -4
- package/templates/chat-app/lib/message-conversion.ts +1 -1
- package/templates/chat-app/lib/playwright-test-environment.ts +18 -0
- package/templates/chat-app/lib/social-auth.ts +5 -0
- package/templates/chat-app/lib/stores/hooks-threads.ts +2 -1
- package/templates/chat-app/lib/stores/with-threads.test.ts +1 -1
- package/templates/chat-app/lib/stores/with-threads.ts +5 -6
- package/templates/chat-app/lib/stores/with-tracing.ts +1 -1
- package/templates/chat-app/lib/thread-utils.ts +19 -21
- package/templates/chat-app/lib/utils/download-assets.ts +6 -7
- package/templates/chat-app/lib/utils/rate-limit.ts +9 -3
- package/templates/chat-app/package.json +22 -19
- package/templates/chat-app/playwright.config.ts +0 -19
- package/templates/chat-app/providers/chat-input-provider.tsx +1 -1
- package/templates/chat-app/proxy.ts +28 -3
- package/templates/chat-app/scripts/check-env.ts +10 -0
- package/templates/chat-app/trpc/server.tsx +7 -2
- package/templates/chat-app/tsconfig.json +2 -1
- package/templates/chat-app/vercel.json +0 -10
- package/templates/electron/CHANGELOG.md +7 -0
- package/templates/electron/README.md +54 -0
- package/templates/electron/entitlements.mac.plist +10 -0
- package/templates/electron/forge.config.ts +152 -0
- package/templates/electron/icon.png +0 -0
- package/templates/electron/package.json +53 -0
- package/templates/electron/scripts/generate-icons.test.js +37 -0
- package/templates/electron/scripts/generate-icons.ts +29 -0
- package/templates/electron/scripts/run-forge.cjs +28 -0
- package/templates/electron/scripts/write-branding.ts +18 -0
- package/templates/electron/src/config.ts +16 -0
- package/templates/electron/src/lib/auth-client.ts +64 -0
- package/templates/electron/src/main.ts +670 -0
- package/templates/electron/src/preload.d.ts +27 -0
- package/templates/electron/src/preload.ts +25 -0
- package/templates/electron/tsconfig.json +18 -0
|
@@ -29,9 +29,9 @@ import { useArtifact } from "@/hooks/use-artifact";
|
|
|
29
29
|
import { useIsMobile } from "@/hooks/use-mobile";
|
|
30
30
|
import type { AppModelId } from "@/lib/ai/app-model-id";
|
|
31
31
|
import {
|
|
32
|
-
expandSelectedModelValue,
|
|
33
32
|
type Attachment,
|
|
34
33
|
type ChatMessage,
|
|
34
|
+
expandSelectedModelValue,
|
|
35
35
|
type SelectedModelValue,
|
|
36
36
|
type UiToolName,
|
|
37
37
|
} from "@/lib/ai/types";
|
|
@@ -325,7 +325,9 @@ function PureMultimodalInput({
|
|
|
325
325
|
);
|
|
326
326
|
|
|
327
327
|
const getCurrentProjectId = useCallback(() => {
|
|
328
|
-
const projectMatch = window.location.pathname.match(
|
|
328
|
+
const projectMatch = window.location.pathname.match(
|
|
329
|
+
PROJECT_CHAT_ROUTE_REGEX
|
|
330
|
+
);
|
|
329
331
|
return projectMatch?.[1];
|
|
330
332
|
}, []);
|
|
331
333
|
|
|
@@ -499,7 +501,8 @@ function PureMultimodalInput({
|
|
|
499
501
|
trimMessagesInEditMode(parentMessageId);
|
|
500
502
|
}
|
|
501
503
|
|
|
502
|
-
const isParallelRequest =
|
|
504
|
+
const isParallelRequest =
|
|
505
|
+
parallelResponsesEnabled && requestedModelIds.length > 1;
|
|
503
506
|
const parallelGroupId = isParallelRequest ? generateUUID() : null;
|
|
504
507
|
const requestSpecs = isParallelRequest
|
|
505
508
|
? requestedModelIds.map(
|
|
@@ -576,13 +579,13 @@ function PureMultimodalInput({
|
|
|
576
579
|
});
|
|
577
580
|
}
|
|
578
581
|
|
|
579
|
-
|
|
582
|
+
runParallelSecondaryRequests({
|
|
580
583
|
message,
|
|
581
584
|
secondaryRequestSpecs: requestSpecs.slice(1),
|
|
582
585
|
}).catch((error) => {
|
|
583
586
|
console.error("Failed to complete parallel requests", error);
|
|
584
587
|
toast.error("Failed to complete all parallel responses");
|
|
585
|
-
|
|
588
|
+
invalidatePersistedMessages();
|
|
586
589
|
});
|
|
587
590
|
} else {
|
|
588
591
|
sendMessage(message);
|
|
@@ -833,10 +836,10 @@ function PureMultimodalInput({
|
|
|
833
836
|
<PromptInput
|
|
834
837
|
className={cn(
|
|
835
838
|
"@container relative transition-colors",
|
|
836
|
-
isDragActive && "border-
|
|
839
|
+
isDragActive && "border-primary bg-accent",
|
|
837
840
|
className
|
|
838
841
|
)}
|
|
839
|
-
inputGroupClassName="
|
|
842
|
+
inputGroupClassName="bg-muted dark:bg-muted"
|
|
840
843
|
{...getRootProps({ onError: undefined, onSubmit: undefined })}
|
|
841
844
|
onSubmit={(_message, event) => {
|
|
842
845
|
event.preventDefault();
|
|
@@ -852,8 +855,8 @@ function PureMultimodalInput({
|
|
|
852
855
|
<input {...getInputProps()} />
|
|
853
856
|
|
|
854
857
|
{isDragActive && attachmentsEnabled && (
|
|
855
|
-
<div className="absolute inset-0 z-10 flex items-center justify-center rounded-xl border-2 border-
|
|
856
|
-
<div className="font-medium text-
|
|
858
|
+
<div className="absolute inset-0 z-10 flex items-center justify-center rounded-xl border-2 border-primary border-dashed bg-accent/80">
|
|
859
|
+
<div className="font-medium text-primary">
|
|
857
860
|
Drop images or PDFs here to attach
|
|
858
861
|
</div>
|
|
859
862
|
</div>
|
|
@@ -1107,9 +1110,9 @@ function PureChatInputBottomControls({
|
|
|
1107
1110
|
)}
|
|
1108
1111
|
<ModelSelector
|
|
1109
1112
|
className="@[500px]:h-10 h-8 w-fit max-w-none shrink justify-start truncate @[500px]:px-3 px-2 @[500px]:text-sm text-xs"
|
|
1113
|
+
onModelSelectionChangeAction={onModelSelectionChange}
|
|
1110
1114
|
selectedModelId={selectedModelId}
|
|
1111
1115
|
selectedModelSelection={selectedModelSelection}
|
|
1112
|
-
onModelSelectionChangeAction={onModelSelectionChange}
|
|
1113
1116
|
/>
|
|
1114
1117
|
<ConnectorsDropdown />
|
|
1115
1118
|
<ResponsiveTools
|
|
@@ -5,6 +5,7 @@ import { LoaderCircle } from "lucide-react";
|
|
|
5
5
|
import { memo, useMemo } from "react";
|
|
6
6
|
import { Button } from "@/components/ui/button";
|
|
7
7
|
import { useNavigateToMessage } from "@/hooks/use-navigate-to-message";
|
|
8
|
+
import type { AppModelId } from "@/lib/ai/app-models";
|
|
8
9
|
import {
|
|
9
10
|
type ChatMessage,
|
|
10
11
|
expandSelectedModelValue,
|
|
@@ -15,11 +16,39 @@ import { cn } from "@/lib/utils";
|
|
|
15
16
|
import { useChatInput } from "@/providers/chat-input-provider";
|
|
16
17
|
import { useChatModels } from "@/providers/chat-models-provider";
|
|
17
18
|
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
function getEffectiveModelId(
|
|
20
|
+
message: {
|
|
21
|
+
metadata: { selectedModel: ChatMessage["metadata"]["selectedModel"] };
|
|
22
|
+
} | null,
|
|
23
|
+
fallbackModelId: AppModelId
|
|
24
|
+
): AppModelId | undefined {
|
|
25
|
+
return message?.metadata.selectedModel
|
|
26
|
+
? (getPrimarySelectedModelId(message.metadata.selectedModel) ?? undefined)
|
|
27
|
+
: fallbackModelId;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getModelOrderIndex(
|
|
31
|
+
modelId: AppModelId | undefined,
|
|
32
|
+
models: Array<{ id: string }>
|
|
33
|
+
): number {
|
|
34
|
+
if (!modelId) {
|
|
35
|
+
return Number.POSITIVE_INFINITY;
|
|
36
|
+
}
|
|
37
|
+
const index = models.findIndex((m) => m.id === modelId);
|
|
38
|
+
return index === -1 ? Number.POSITIVE_INFINITY : index;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getStatusLabel(isSelected: boolean, isStreaming: boolean): string {
|
|
42
|
+
if (isSelected) {
|
|
43
|
+
return "Selected";
|
|
44
|
+
}
|
|
45
|
+
if (isStreaming) {
|
|
46
|
+
return "Generating...";
|
|
47
|
+
}
|
|
48
|
+
return "Task completed";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function PureParallelResponseCards({ messageId }: { messageId: string }) {
|
|
23
52
|
const message = useMessageById<ChatMessage>(messageId);
|
|
24
53
|
const parallelGroupInfo = useParallelGroupInfo(messageId);
|
|
25
54
|
const navigateToMessage = useNavigateToMessage();
|
|
@@ -36,7 +65,9 @@ function PureParallelResponseCards({
|
|
|
36
65
|
return [];
|
|
37
66
|
}
|
|
38
67
|
|
|
39
|
-
const requestedModelIds = expandSelectedModelValue(
|
|
68
|
+
const requestedModelIds = expandSelectedModelValue(
|
|
69
|
+
message.metadata.selectedModel
|
|
70
|
+
);
|
|
40
71
|
|
|
41
72
|
return requestedModelIds.map((modelId, parallelIndex) => {
|
|
42
73
|
const actualMessage = parallelGroupInfo?.messages.find(
|
|
@@ -53,24 +84,14 @@ function PureParallelResponseCards({
|
|
|
53
84
|
|
|
54
85
|
const sortedCardSlots = useMemo(() => {
|
|
55
86
|
return [...cardSlots].sort((left, right) => {
|
|
56
|
-
const
|
|
57
|
-
left.message
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
right.message
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const leftIndex = leftModelId
|
|
66
|
-
? models.findIndex((m) => m.id === leftModelId)
|
|
67
|
-
: -1;
|
|
68
|
-
const rightIndex = rightModelId
|
|
69
|
-
? models.findIndex((m) => m.id === rightModelId)
|
|
70
|
-
: -1;
|
|
71
|
-
|
|
72
|
-
const leftOrder = leftIndex === -1 ? Infinity : leftIndex;
|
|
73
|
-
const rightOrder = rightIndex === -1 ? Infinity : rightIndex;
|
|
87
|
+
const leftOrder = getModelOrderIndex(
|
|
88
|
+
getEffectiveModelId(left.message, left.modelId),
|
|
89
|
+
models
|
|
90
|
+
);
|
|
91
|
+
const rightOrder = getModelOrderIndex(
|
|
92
|
+
getEffectiveModelId(right.message, right.modelId),
|
|
93
|
+
models
|
|
94
|
+
);
|
|
74
95
|
|
|
75
96
|
if (leftOrder !== rightOrder) {
|
|
76
97
|
return leftOrder - rightOrder;
|
|
@@ -105,20 +126,15 @@ function PureParallelResponseCards({
|
|
|
105
126
|
return (
|
|
106
127
|
<div className="mt-3 flex flex-wrap justify-end gap-2">
|
|
107
128
|
{sortedCardSlots.map((slot) => {
|
|
108
|
-
const modelId =
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const modelName = modelId ? getModelById(modelId)?.name ?? modelId : "Model";
|
|
129
|
+
const modelId = getEffectiveModelId(slot.message, slot.modelId);
|
|
130
|
+
const modelName = modelId
|
|
131
|
+
? (getModelById(modelId)?.name ?? modelId)
|
|
132
|
+
: "Model";
|
|
113
133
|
const isSelected = selectedParallelIndex === slot.parallelIndex;
|
|
114
134
|
const isStreaming = slot.message
|
|
115
135
|
? slot.message.metadata.activeStreamId !== null
|
|
116
136
|
: true;
|
|
117
|
-
const statusLabel = isSelected
|
|
118
|
-
? "Selected"
|
|
119
|
-
: isStreaming
|
|
120
|
-
? "Generating..."
|
|
121
|
-
: "Task completed";
|
|
137
|
+
const statusLabel = getStatusLabel(isSelected, isStreaming);
|
|
122
138
|
|
|
123
139
|
return (
|
|
124
140
|
<Button
|
|
@@ -141,7 +157,9 @@ function PureParallelResponseCards({
|
|
|
141
157
|
>
|
|
142
158
|
<span className="font-medium text-sm">{modelName}</span>
|
|
143
159
|
<span className="flex items-center gap-1 text-muted-foreground text-xs">
|
|
144
|
-
{isStreaming ?
|
|
160
|
+
{isStreaming ? (
|
|
161
|
+
<LoaderCircle className="size-3 animate-spin" />
|
|
162
|
+
) : null}
|
|
145
163
|
{statusLabel}
|
|
146
164
|
</span>
|
|
147
165
|
</Button>
|
|
@@ -33,7 +33,12 @@ function isPngChart(input: unknown): input is PngChart {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function CodeExecution({ tool }: { tool: CodeExecutionTool }) {
|
|
36
|
-
const args = tool.input ?? {
|
|
36
|
+
const args = tool.input ?? {
|
|
37
|
+
code: "",
|
|
38
|
+
title: "",
|
|
39
|
+
language: "python",
|
|
40
|
+
icon: "default",
|
|
41
|
+
};
|
|
37
42
|
const result = tool.state === "output-available" ? tool.output : null;
|
|
38
43
|
const chart: BaseChart | null =
|
|
39
44
|
result && isBaseChart(result.chart) ? result.chart : null;
|
|
@@ -41,11 +46,12 @@ export function CodeExecution({ tool }: { tool: CodeExecutionTool }) {
|
|
|
41
46
|
result && isPngChart(result.chart) ? result.chart : null;
|
|
42
47
|
const code = typeof args.code === "string" ? args.code : "";
|
|
43
48
|
const title = typeof args.title === "string" ? args.title : "";
|
|
49
|
+
const language = args.language === "javascript" ? "javascript" : "python";
|
|
44
50
|
return (
|
|
45
51
|
<div className="space-y-6">
|
|
46
52
|
<SandboxComposed
|
|
47
53
|
code={code}
|
|
48
|
-
language=
|
|
54
|
+
language={language}
|
|
49
55
|
output={result?.message}
|
|
50
56
|
state={tool.state}
|
|
51
57
|
title={title}
|
|
@@ -128,7 +128,7 @@ function PureDocumentToolCall({
|
|
|
128
128
|
type="button"
|
|
129
129
|
>
|
|
130
130
|
<div className="flex flex-row items-start gap-3">
|
|
131
|
-
<div className="mt-1 text-
|
|
131
|
+
<div className="mt-1 text-muted-foreground">
|
|
132
132
|
{(() => {
|
|
133
133
|
if (type === "create") {
|
|
134
134
|
return <File size={16} />;
|
|
@@ -155,7 +155,7 @@ const LoadingSkeleton = ({
|
|
|
155
155
|
artifactKind: ArtifactKind;
|
|
156
156
|
}) => (
|
|
157
157
|
<div className="w-full">
|
|
158
|
-
<div className="flex h-[57px] flex-row items-center justify-between gap-2 rounded-t-2xl border border-b-0 p-4
|
|
158
|
+
<div className="flex h-[57px] flex-row items-center justify-between gap-2 rounded-t-2xl border border-b-0 bg-muted p-4">
|
|
159
159
|
<div className="flex flex-row items-center gap-3">
|
|
160
160
|
<div className="text-muted-foreground">
|
|
161
161
|
<div className="size-4 animate-pulse rounded-md bg-muted-foreground/20" />
|
|
@@ -167,7 +167,7 @@ const LoadingSkeleton = ({
|
|
|
167
167
|
</div>
|
|
168
168
|
</div>
|
|
169
169
|
|
|
170
|
-
<div className="overflow-y-scroll rounded-b-2xl border border-t-0 bg-muted p-8 pt-4
|
|
170
|
+
<div className="overflow-y-scroll rounded-b-2xl border border-t-0 bg-muted p-8 pt-4">
|
|
171
171
|
<InlineDocumentSkeleton />
|
|
172
172
|
</div>
|
|
173
173
|
</div>
|
|
@@ -217,7 +217,7 @@ const PureHitboxLayer = ({
|
|
|
217
217
|
role="presentation"
|
|
218
218
|
>
|
|
219
219
|
<div className="flex w-full items-center justify-end p-4">
|
|
220
|
-
<div className="absolute top-[13px] right-[9px] rounded-md p-2 hover:bg-
|
|
220
|
+
<div className="absolute top-[13px] right-[9px] rounded-md p-2 hover:bg-accent">
|
|
221
221
|
<Maximize size={16} />
|
|
222
222
|
</div>
|
|
223
223
|
</div>
|
|
@@ -257,7 +257,7 @@ const PureDocumentHeader = ({
|
|
|
257
257
|
isStreaming: boolean;
|
|
258
258
|
type: "create" | "update";
|
|
259
259
|
}) => (
|
|
260
|
-
<div className="flex flex-row items-start justify-between gap-2 rounded-t-2xl border border-b-0 p-4 sm:items-center
|
|
260
|
+
<div className="flex flex-row items-start justify-between gap-2 rounded-t-2xl border border-b-0 bg-muted p-4 sm:items-center">
|
|
261
261
|
<div className="flex flex-row items-start gap-3 sm:items-center">
|
|
262
262
|
<div className="text-muted-foreground">
|
|
263
263
|
{(() => {
|
|
@@ -299,7 +299,7 @@ const DocumentContent = ({ document }: { document: Document }) => {
|
|
|
299
299
|
const { artifact } = useArtifact();
|
|
300
300
|
|
|
301
301
|
const containerClassName = cn(
|
|
302
|
-
"h-[257px] overflow-y-scroll rounded-b-2xl border border-t-0
|
|
302
|
+
"h-[257px] overflow-y-scroll rounded-b-2xl border border-t-0 bg-muted",
|
|
303
303
|
{
|
|
304
304
|
"p-4 sm:px-14 sm:py-16": document.kind === "text",
|
|
305
305
|
"p-0": document.kind === "code",
|
|
@@ -12,17 +12,17 @@ export type RetrieveUrlTool = Extract<
|
|
|
12
12
|
|
|
13
13
|
function LoadingState() {
|
|
14
14
|
return (
|
|
15
|
-
<div className="my-4 rounded-xl border border-
|
|
15
|
+
<div className="my-4 rounded-xl border border-border bg-card p-4">
|
|
16
16
|
<div className="flex items-center gap-4">
|
|
17
17
|
<div className="relative h-10 w-10">
|
|
18
18
|
<div className="absolute inset-0 animate-pulse rounded-full bg-primary/10" />
|
|
19
19
|
<Globe className="absolute inset-0 m-auto h-5 w-5 text-primary/70" />
|
|
20
20
|
</div>
|
|
21
21
|
<div className="flex-1 space-y-2">
|
|
22
|
-
<div className="h-4 w-36 animate-pulse rounded-md bg-
|
|
22
|
+
<div className="h-4 w-36 animate-pulse rounded-md bg-muted-foreground/20" />
|
|
23
23
|
<div className="space-y-1.5">
|
|
24
|
-
<div className="h-3 w-full animate-pulse rounded-md bg-
|
|
25
|
-
<div className="h-3 w-2/3 animate-pulse rounded-md bg-
|
|
24
|
+
<div className="h-3 w-full animate-pulse rounded-md bg-muted-foreground/15" />
|
|
25
|
+
<div className="h-3 w-2/3 animate-pulse rounded-md bg-muted-foreground/15" />
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
28
28
|
</div>
|
|
@@ -86,10 +86,10 @@ function RetrievedContentHeader({ firstItem }: { firstItem: unknown }) {
|
|
|
86
86
|
/>
|
|
87
87
|
</div>
|
|
88
88
|
<div className="min-w-0 flex-1 space-y-2">
|
|
89
|
-
<h2 className="truncate font-semibold text-
|
|
89
|
+
<h2 className="truncate font-semibold text-foreground text-lg tracking-tight">
|
|
90
90
|
{title}
|
|
91
91
|
</h2>
|
|
92
|
-
<p className="line-clamp-2 text-
|
|
92
|
+
<p className="line-clamp-2 text-muted-foreground text-sm">
|
|
93
93
|
{description}
|
|
94
94
|
</p>
|
|
95
95
|
<div className="flex items-center gap-3">
|
|
@@ -97,7 +97,7 @@ function RetrievedContentHeader({ firstItem }: { firstItem: unknown }) {
|
|
|
97
97
|
{language}
|
|
98
98
|
</span>
|
|
99
99
|
<a
|
|
100
|
-
className="inline-flex items-center gap-1.5 text-
|
|
100
|
+
className="inline-flex items-center gap-1.5 text-muted-foreground text-xs transition-colors hover:text-primary"
|
|
101
101
|
href={url || "#"}
|
|
102
102
|
rel="noopener noreferrer"
|
|
103
103
|
target="_blank"
|
|
@@ -116,16 +116,16 @@ function RetrievedContentDetails({ firstItem }: { firstItem: unknown }) {
|
|
|
116
116
|
const content = getItemProperty(firstItem, "content", "No content available");
|
|
117
117
|
|
|
118
118
|
return (
|
|
119
|
-
<div className="border-
|
|
119
|
+
<div className="border-border border-t">
|
|
120
120
|
<details className="group">
|
|
121
|
-
<summary className="flex w-full cursor-pointer items-center justify-between px-4 py-2 text-
|
|
121
|
+
<summary className="flex w-full cursor-pointer items-center justify-between px-4 py-2 text-muted-foreground text-sm transition-colors hover:bg-muted">
|
|
122
122
|
<div className="flex items-center gap-2">
|
|
123
|
-
<TextIcon className="h-4 w-4 text-
|
|
123
|
+
<TextIcon className="h-4 w-4 text-muted-foreground" />
|
|
124
124
|
<span>View content</span>
|
|
125
125
|
</div>
|
|
126
126
|
<ChevronDown className="h-4 w-4 transition-transform duration-200 group-open:rotate-180" />
|
|
127
127
|
</summary>
|
|
128
|
-
<div className="max-h-[50vh] overflow-y-auto bg-
|
|
128
|
+
<div className="max-h-[50vh] overflow-y-auto bg-muted/50 p-4">
|
|
129
129
|
<div className="prose prose-neutral dark:prose-invert prose-sm max-w-none">
|
|
130
130
|
<ReactMarkdown>{content}</ReactMarkdown>
|
|
131
131
|
</div>
|
|
@@ -173,7 +173,7 @@ export function RetrieveUrl({ tool }: { tool: RetrieveUrlTool }) {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
return (
|
|
176
|
-
<div className="my-4 overflow-hidden rounded-xl border border-
|
|
176
|
+
<div className="my-4 overflow-hidden rounded-xl border border-border bg-card">
|
|
177
177
|
<RetrievedContentHeader firstItem={firstItem} />
|
|
178
178
|
<RetrievedContentDetails firstItem={firstItem} />
|
|
179
179
|
</div>
|
|
@@ -4,13 +4,17 @@ import { memo } from "react";
|
|
|
4
4
|
import { Response } from "../ai-elements/response";
|
|
5
5
|
|
|
6
6
|
export const TextMessagePart = memo(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
({ text, isLoading }: { text: string; isLoading: boolean }) => (
|
|
8
|
+
<Response
|
|
9
|
+
animated={{
|
|
10
|
+
duration: 200, // milliseconds (default: 150)
|
|
11
|
+
stagger: 0,
|
|
12
|
+
}}
|
|
13
|
+
isAnimating={isLoading}
|
|
14
|
+
linkSafety={{ enabled: false }}
|
|
15
|
+
mode={isLoading ? "streaming" : "static"}
|
|
16
|
+
>
|
|
17
|
+
{text}
|
|
18
|
+
</Response>
|
|
19
|
+
)
|
|
16
20
|
);
|
|
@@ -75,7 +75,7 @@ export function ProjectChatItem({
|
|
|
75
75
|
<ShareMenuItem onShare={() => setShareDialogOpen(true)} />
|
|
76
76
|
|
|
77
77
|
<DropdownMenuItem
|
|
78
|
-
className="cursor-pointer text-destructive focus:bg-destructive/15 focus:text-destructive
|
|
78
|
+
className="cursor-pointer text-destructive focus:bg-destructive/15 focus:text-destructive"
|
|
79
79
|
onSelect={() => onDelete(chat.id)}
|
|
80
80
|
>
|
|
81
81
|
<Trash2 size={16} />
|
|
@@ -19,7 +19,7 @@ export function ProjectMenuItems({
|
|
|
19
19
|
<span>Rename</span>
|
|
20
20
|
</DropdownMenuItem>
|
|
21
21
|
<DropdownMenuItem
|
|
22
|
-
className="cursor-pointer text-destructive focus:bg-destructive/15 focus:text-destructive
|
|
22
|
+
className="cursor-pointer text-destructive focus:bg-destructive/15 focus:text-destructive"
|
|
23
23
|
onSelect={onDelete}
|
|
24
24
|
>
|
|
25
25
|
<Trash2 size={16} />
|
|
@@ -71,7 +71,7 @@ export const ResearchTask = ({
|
|
|
71
71
|
{update.type === "web" && update.status === "running" && (
|
|
72
72
|
<div className="py-2">
|
|
73
73
|
<div className="flex items-center gap-3">
|
|
74
|
-
<Loader2 className="size-4 animate-spin text-
|
|
74
|
+
<Loader2 className="size-4 animate-spin text-muted-foreground" />
|
|
75
75
|
<p className="text-xsize-neutral-500">Searching the web...</p>
|
|
76
76
|
</div>
|
|
77
77
|
</div>
|
|
@@ -11,7 +11,7 @@ export const ResearchTasks = ({ updates }: { updates: ResearchUpdate[] }) => (
|
|
|
11
11
|
{updates.map((update, index) => (
|
|
12
12
|
<StepWrapper
|
|
13
13
|
isLast={index === updates.length - 1}
|
|
14
|
-
key={
|
|
14
|
+
key={update.toolCallId}
|
|
15
15
|
update={update}
|
|
16
16
|
>
|
|
17
17
|
<ResearchTask
|
|
@@ -7,7 +7,7 @@ import { RefreshCcw } from "lucide-react";
|
|
|
7
7
|
import { useCallback } from "react";
|
|
8
8
|
import { toast } from "sonner";
|
|
9
9
|
import { Action } from "@/components/ai-elements/actions";
|
|
10
|
-
import {
|
|
10
|
+
import { type ChatMessage, getPrimarySelectedModelId } from "@/lib/ai/types";
|
|
11
11
|
|
|
12
12
|
export function RetryButton({
|
|
13
13
|
messageId,
|
|
@@ -38,7 +38,7 @@ export function SandboxComposed({
|
|
|
38
38
|
<SandboxHeader state={state} title={title} />
|
|
39
39
|
<SandboxContent>
|
|
40
40
|
<SandboxTabs onValueChange={setActiveTab} value={activeTab}>
|
|
41
|
-
<div className="flex items-center border-
|
|
41
|
+
<div className="flex items-center border-border border-b">
|
|
42
42
|
<SandboxTabsList>
|
|
43
43
|
<SandboxTabsTrigger value="code">Code</SandboxTabsTrigger>
|
|
44
44
|
<SandboxTabsTrigger value="output">Output</SandboxTabsTrigger>
|
|
@@ -57,8 +57,8 @@ const PureSpreadsheetEditor = ({
|
|
|
57
57
|
frozen: true,
|
|
58
58
|
width: 50,
|
|
59
59
|
renderCell: ({ rowIdx }: { rowIdx: number }) => rowIdx + 1,
|
|
60
|
-
cellClass: "border-t border-r
|
|
61
|
-
headerCellClass: "border-t border-r
|
|
60
|
+
cellClass: "border-t border-r bg-background text-foreground",
|
|
61
|
+
headerCellClass: "border-t border-r bg-muted text-foreground",
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
const dataColumns = Array.from({ length: MIN_COLS }, (_, i) => ({
|
|
@@ -66,10 +66,10 @@ const PureSpreadsheetEditor = ({
|
|
|
66
66
|
name: String.fromCharCode(65 + i),
|
|
67
67
|
renderEditCell: isReadonly ? undefined : textEditor,
|
|
68
68
|
width: 120,
|
|
69
|
-
cellClass: cn("border-t
|
|
69
|
+
cellClass: cn("border-t bg-background text-foreground", {
|
|
70
70
|
"border-l": i !== 0,
|
|
71
71
|
}),
|
|
72
|
-
headerCellClass: cn("border-t
|
|
72
|
+
headerCellClass: cn("border-t bg-muted text-foreground", {
|
|
73
73
|
"border-l": i !== 0,
|
|
74
74
|
}),
|
|
75
75
|
}));
|
|
@@ -80,7 +80,7 @@ const PureSpreadsheetEditor = ({
|
|
|
80
80
|
const initialRows = useMemo(
|
|
81
81
|
() =>
|
|
82
82
|
parseData.map((row, rowIndex) => {
|
|
83
|
-
const rowData:
|
|
83
|
+
const rowData: Record<string, string | number> = {
|
|
84
84
|
id: rowIndex,
|
|
85
85
|
rowNumber: rowIndex + 1,
|
|
86
86
|
};
|
|
@@ -100,9 +100,9 @@ const PureSpreadsheetEditor = ({
|
|
|
100
100
|
setLocalRows(initialRows);
|
|
101
101
|
}, [initialRows]);
|
|
102
102
|
|
|
103
|
-
const generateCsv = (data:
|
|
103
|
+
const generateCsv = (data: Array<Array<string | number>>) => unparse(data);
|
|
104
104
|
|
|
105
|
-
const handleRowsChange = (newRows:
|
|
105
|
+
const handleRowsChange = (newRows: Record<string, string | number>[]) => {
|
|
106
106
|
if (isReadonly) {
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
@@ -106,7 +106,7 @@ export function SidebarChatsList() {
|
|
|
106
106
|
|
|
107
107
|
if (chats.length === 0) {
|
|
108
108
|
return (
|
|
109
|
-
<div className="flex w-full flex-row items-center justify-center gap-2 px-2 py-4 text-
|
|
109
|
+
<div className="flex w-full flex-row items-center justify-center gap-2 px-2 py-4 text-muted-foreground text-sm">
|
|
110
110
|
Start chatting to see your conversation history!
|
|
111
111
|
</div>
|
|
112
112
|
);
|
|
@@ -11,14 +11,27 @@ import {
|
|
|
11
11
|
import { Button } from "./ui/button";
|
|
12
12
|
|
|
13
13
|
export function SidebarToggle({
|
|
14
|
-
className
|
|
14
|
+
className,
|
|
15
|
+
onClick,
|
|
16
|
+
...props
|
|
15
17
|
}: ComponentProps<typeof SidebarTrigger>) {
|
|
16
18
|
const { toggleSidebar } = useSidebar();
|
|
17
19
|
|
|
18
20
|
return (
|
|
19
21
|
<Tooltip>
|
|
20
22
|
<TooltipTrigger asChild>
|
|
21
|
-
<Button
|
|
23
|
+
<Button
|
|
24
|
+
{...props}
|
|
25
|
+
className={className}
|
|
26
|
+
onClick={(event) => {
|
|
27
|
+
onClick?.(event);
|
|
28
|
+
if (!event.defaultPrevented) {
|
|
29
|
+
toggleSidebar();
|
|
30
|
+
}
|
|
31
|
+
}}
|
|
32
|
+
size="icon"
|
|
33
|
+
variant="ghost"
|
|
34
|
+
>
|
|
22
35
|
<PanelLeft size={16} />
|
|
23
36
|
</Button>
|
|
24
37
|
</TooltipTrigger>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { PanelLeft } from "lucide-react";
|
|
3
4
|
import Image from "next/image";
|
|
4
5
|
import Link from "next/link";
|
|
5
6
|
import { SidebarToggle } from "@/components/sidebar-toggle";
|
|
@@ -8,16 +9,13 @@ import { config } from "@/lib/config";
|
|
|
8
9
|
import { useChatId } from "@/providers/chat-id-provider";
|
|
9
10
|
|
|
10
11
|
export function SidebarTopRow() {
|
|
11
|
-
const { setOpenMobile,
|
|
12
|
+
const { isMobile, openMobile, setOpenMobile, state, toggleSidebar } =
|
|
13
|
+
useSidebar();
|
|
12
14
|
const { refreshChatID } = useChatId();
|
|
13
|
-
const isExpanded =
|
|
15
|
+
const isExpanded = isMobile ? openMobile : state === "expanded";
|
|
14
16
|
|
|
15
17
|
return (
|
|
16
|
-
<div
|
|
17
|
-
className={`flex w-full items-center ${
|
|
18
|
-
isExpanded ? "justify-between gap-2" : "justify-start"
|
|
19
|
-
}`}
|
|
20
|
-
>
|
|
18
|
+
<div className="flex w-full items-center justify-between gap-2">
|
|
21
19
|
{isExpanded ? (
|
|
22
20
|
<Link
|
|
23
21
|
className="flex flex-row items-center gap-2"
|
|
@@ -30,16 +28,33 @@ export function SidebarTopRow() {
|
|
|
30
28
|
<span className="flex cursor-pointer items-center gap-2 rounded-md p-1 font-semibold text-lg hover:bg-muted">
|
|
31
29
|
<Image
|
|
32
30
|
alt={config.appName}
|
|
33
|
-
className="h-
|
|
34
|
-
height={
|
|
31
|
+
className="h-5 w-5"
|
|
32
|
+
height={20}
|
|
35
33
|
src="/icon.svg"
|
|
36
|
-
width={
|
|
34
|
+
width={20}
|
|
37
35
|
/>
|
|
38
36
|
{config.appName}
|
|
39
37
|
</span>
|
|
40
38
|
</Link>
|
|
41
|
-
) :
|
|
42
|
-
|
|
39
|
+
) : (
|
|
40
|
+
<button
|
|
41
|
+
aria-label="Expand sidebar"
|
|
42
|
+
className="group/logo relative flex size-8 items-center justify-center rounded-md hover:bg-muted"
|
|
43
|
+
onClick={toggleSidebar}
|
|
44
|
+
type="button"
|
|
45
|
+
>
|
|
46
|
+
<Image
|
|
47
|
+
alt={config.appName}
|
|
48
|
+
className="h-5 w-5 transition-opacity duration-150 group-hover/logo:opacity-0"
|
|
49
|
+
height={20}
|
|
50
|
+
src="/icon.svg"
|
|
51
|
+
width={20}
|
|
52
|
+
/>
|
|
53
|
+
<PanelLeft className="absolute size-4 opacity-0 transition-opacity duration-150 group-hover/logo:opacity-100" />
|
|
54
|
+
</button>
|
|
55
|
+
)}
|
|
56
|
+
|
|
57
|
+
{isExpanded && <SidebarToggle className="md:h-fit md:px-2" />}
|
|
43
58
|
</div>
|
|
44
59
|
);
|
|
45
60
|
}
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
} from "@/components/ui/sidebar";
|
|
31
31
|
import { useGetCredits } from "@/hooks/chat-sync-hooks";
|
|
32
32
|
import authClient from "@/lib/auth-client";
|
|
33
|
+
import { isElectronRenderer } from "@/lib/electron-auth";
|
|
33
34
|
import { cn } from "@/lib/utils";
|
|
34
35
|
import { useSession } from "@/providers/session-provider";
|
|
35
36
|
|
|
@@ -149,7 +150,15 @@ export function SidebarUserNav() {
|
|
|
149
150
|
<DropdownMenuSeparator />
|
|
150
151
|
<DropdownMenuItem
|
|
151
152
|
onClick={async () => {
|
|
152
|
-
|
|
153
|
+
if (
|
|
154
|
+
isElectronRenderer() &&
|
|
155
|
+
typeof window.signOut === "function"
|
|
156
|
+
) {
|
|
157
|
+
await window.signOut();
|
|
158
|
+
await window.electronAPI?.syncAuthSession?.();
|
|
159
|
+
} else {
|
|
160
|
+
await authClient.signOut();
|
|
161
|
+
}
|
|
153
162
|
window.location.href = "/";
|
|
154
163
|
}}
|
|
155
164
|
>
|