Skip to content

Commit a3706ef

Browse files
committed
migrate
1 parent 7d776d1 commit a3706ef

File tree

21 files changed

+3763
-1208
lines changed

21 files changed

+3763
-1208
lines changed

apps/www/src/registry/app/api/ai/command/route.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
import type { NextRequest } from 'next/server';
66

77
import {
8+
LanguageModel,
89
type UIMessageStreamWriter,
910
createUIMessageStream,
1011
createUIMessageStreamResponse,
@@ -26,9 +27,10 @@ import {
2627
getEditPrompt,
2728
getGeneratePrompt,
2829
} from './prompts';
30+
import { createGateway } from '@ai-sdk/gateway';
2931

3032
export async function POST(req: NextRequest) {
31-
const { apiKey: key, ctx, messages: messagesRaw } = await req.json();
33+
const { apiKey: key, ctx, messages: messagesRaw, model } = await req.json();
3234

3335
const { children, selection, toolName: toolNameParam } = ctx;
3436

@@ -49,6 +51,10 @@ export async function POST(req: NextRequest) {
4951

5052
const isSelecting = editor.api.isExpanded();
5153

54+
const gatewayProvider = createGateway({
55+
apiKey,
56+
});
57+
5258
try {
5359
const stream = createUIMessageStream<ChatMessage>({
5460
execute: async ({ writer }) => {
@@ -59,7 +65,7 @@ export async function POST(req: NextRequest) {
5965
enum: isSelecting
6066
? ['generate', 'edit', 'comment']
6167
: ['generate', 'comment'],
62-
model: 'google/gemini-2.5-flash',
68+
model: gatewayProvider(model || 'google/gemini-2.5-flash'),
6369
output: 'enum',
6470
prompt: getChooseToolPrompt(messagesRaw),
6571
});
@@ -74,11 +80,15 @@ export async function POST(req: NextRequest) {
7480

7581
const stream = streamText({
7682
experimental_transform: markdownJoinerTransform(),
77-
model: 'google/gemini-2.5-flash',
83+
model: gatewayProvider(model || 'openai/gpt-4o-mini'),
7884
// Not used
7985
prompt: '',
8086
tools: {
81-
comment: getCommentTool(editor, { messagesRaw, writer }),
87+
comment: getCommentTool(editor, {
88+
messagesRaw,
89+
writer,
90+
model: gatewayProvider(model || 'google/gemini-2.5-flash'),
91+
}),
8292
},
8393
prepareStep: async (step) => {
8494
if (toolName === 'comment') {
@@ -120,7 +130,7 @@ export async function POST(req: NextRequest) {
120130
role: 'user',
121131
},
122132
],
123-
model: 'openai/gpt-4o-mini',
133+
model: gatewayProvider(model || 'openai/gpt-4o-mini'),
124134
};
125135
}
126136
},
@@ -144,14 +154,19 @@ const getCommentTool = (
144154
{
145155
messagesRaw,
146156
writer,
147-
}: { messagesRaw: ChatMessage[]; writer: UIMessageStreamWriter<ChatMessage> }
157+
model,
158+
}: {
159+
messagesRaw: ChatMessage[];
160+
writer: UIMessageStreamWriter<ChatMessage>;
161+
model: LanguageModel;
162+
}
148163
) => {
149164
return tool({
150165
description: 'Comment on the content',
151166
inputSchema: z.object({}),
152167
execute: async () => {
153168
const { elementStream } = streamObject({
154-
model: 'google/gemini-2.5-flash',
169+
model,
155170
output: 'array',
156171
prompt: getCommentPrompt(editor, {
157172
messages: messagesRaw,
@@ -182,7 +197,7 @@ const getCommentTool = (
182197
id: commentDataId,
183198
data: {
184199
comment: comment,
185-
status: 'streaming'
200+
status: 'streaming',
186201
},
187202
type: 'data-comment',
188203
});
@@ -192,10 +207,10 @@ const getCommentTool = (
192207
id: nanoid(),
193208
data: {
194209
comment: null,
195-
status: 'finished'
210+
status: 'finished',
196211
},
197212
type: 'data-comment',
198-
});
213+
});
199214
},
200215
});
201216
};

apps/www/src/registry/components/editor/settings-dialog.tsx

Lines changed: 172 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,186 @@ import {
4040
PopoverTrigger,
4141
} from '@/components/ui/popover';
4242
import { cn } from '@/lib/utils';
43-
import { aiChatPlugin } from '@/registry/components/editor/plugins/ai-kit';
43+
import { aiChatPlugin } from './plugins/ai-kit';
4444

4545
interface Model {
4646
label: string;
4747
value: string;
4848
}
4949

5050
export const models: Model[] = [
51-
{ label: 'gpt-4o-mini', value: 'gpt-4o-mini' },
52-
{ label: 'gpt-4o', value: 'gpt-4o' },
53-
{ label: 'gpt-4-turbo', value: 'gpt-4-turbo' },
54-
{ label: 'gpt-4', value: 'gpt-4' },
55-
{ label: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' },
56-
{ label: 'gpt-3.5-turbo-instruct', value: 'gpt-3.5-turbo-instruct' },
51+
// OpenAI Models
52+
{ label: 'GPT-3.5 Turbo', value: 'openai/gpt-3.5-turbo' },
53+
{ label: 'GPT-3.5 Turbo Instruct', value: 'openai/gpt-3.5-turbo-instruct' },
54+
{ label: 'GPT-4 Turbo', value: 'openai/gpt-4-turbo' },
55+
{ label: 'GPT-4.1', value: 'openai/gpt-4.1' },
56+
{ label: 'GPT-4.1 Mini', value: 'openai/gpt-4.1-mini' },
57+
{ label: 'GPT-4.1 Nano', value: 'openai/gpt-4.1-nano' },
58+
{ label: 'GPT-4o', value: 'openai/gpt-4o' },
59+
{ label: 'GPT-4o Mini', value: 'openai/gpt-4o-mini' },
60+
{ label: 'GPT-5', value: 'openai/gpt-5' },
61+
{ label: 'GPT-5 Codex', value: 'openai/gpt-5-codex' },
62+
{ label: 'GPT-5 Mini', value: 'openai/gpt-5-mini' },
63+
{ label: 'GPT-5 Nano', value: 'openai/gpt-5-nano' },
64+
{ label: 'GPT-OSS 120B', value: 'openai/gpt-oss-120b' },
65+
{ label: 'GPT-OSS 20B', value: 'openai/gpt-oss-20b' },
66+
{ label: 'O1', value: 'openai/o1' },
67+
{ label: 'O3', value: 'openai/o3' },
68+
{ label: 'O3 Mini', value: 'openai/o3-mini' },
69+
{ label: 'O4 Mini', value: 'openai/o4-mini' },
70+
71+
// Google Models
72+
{ label: 'Gemini 2.0 Flash', value: 'google/gemini-2.0-flash' },
73+
{ label: 'Gemini 2.0 Flash Lite', value: 'google/gemini-2.0-flash-lite' },
74+
{ label: 'Gemini 2.5 Flash', value: 'google/gemini-2.5-flash' },
75+
{
76+
label: 'Gemini 2.5 Flash Image Preview',
77+
value: 'google/gemini-2.5-flash-image-preview',
78+
},
79+
{ label: 'Gemini 2.5 Flash Lite', value: 'google/gemini-2.5-flash-lite' },
80+
{ label: 'Gemini 2.5 Pro', value: 'google/gemini-2.5-pro' },
81+
{ label: 'Gemma 2 9B', value: 'google/gemma-2-9b' },
82+
83+
// Alibaba Models
84+
{ label: 'Qwen 3 14B', value: 'alibaba/qwen-3-14b' },
85+
{ label: 'Qwen 3 235B', value: 'alibaba/qwen-3-235b' },
86+
{ label: 'Qwen 3 30B', value: 'alibaba/qwen-3-30b' },
87+
{ label: 'Qwen 3 32B', value: 'alibaba/qwen-3-32b' },
88+
{ label: 'Qwen3 Coder', value: 'alibaba/qwen3-coder' },
89+
{ label: 'Qwen3 Coder Plus', value: 'alibaba/qwen3-coder-plus' },
90+
{ label: 'Qwen3 Max', value: 'alibaba/qwen3-max' },
91+
{ label: 'Qwen3 Max Preview', value: 'alibaba/qwen3-max-preview' },
92+
{
93+
label: 'Qwen3 Next 80B A3B Instruct',
94+
value: 'alibaba/qwen3-next-80b-a3b-instruct',
95+
},
96+
{
97+
label: 'Qwen3 Next 80B A3B Thinking',
98+
value: 'alibaba/qwen3-next-80b-a3b-thinking',
99+
},
100+
{ label: 'Qwen3 VL Instruct', value: 'alibaba/qwen3-vl-instruct' },
101+
{ label: 'Qwen3 VL Thinking', value: 'alibaba/qwen3-vl-thinking' },
102+
103+
// Amazon Models
104+
{ label: 'Nova Lite', value: 'amazon/nova-lite' },
105+
{ label: 'Nova Micro', value: 'amazon/nova-micro' },
106+
{ label: 'Nova Pro', value: 'amazon/nova-pro' },
107+
108+
// Anthropic Models
109+
{ label: 'Claude 3 Haiku', value: 'anthropic/claude-3-haiku' },
110+
{ label: 'Claude 3 Opus', value: 'anthropic/claude-3-opus' },
111+
{ label: 'Claude 3.5 Haiku', value: 'anthropic/claude-3.5-haiku' },
112+
{ label: 'Claude 3.5 Sonnet', value: 'anthropic/claude-3.5-sonnet' },
113+
{ label: 'Claude 3.7 Sonnet', value: 'anthropic/claude-3.7-sonnet' },
114+
{ label: 'Claude Opus 4', value: 'anthropic/claude-opus-4' },
115+
{ label: 'Claude Opus 4.1', value: 'anthropic/claude-opus-4.1' },
116+
{ label: 'Claude Sonnet 4', value: 'anthropic/claude-sonnet-4' },
117+
118+
// Cohere Models
119+
{ label: 'Command A', value: 'cohere/command-a' },
120+
{ label: 'Command R', value: 'cohere/command-r' },
121+
{ label: 'Command R Plus', value: 'cohere/command-r-plus' },
122+
123+
// DeepSeek Models
124+
{ label: 'DeepSeek R1', value: 'deepseek/deepseek-r1' },
125+
{
126+
label: 'DeepSeek R1 Distill Llama 70B',
127+
value: 'deepseek/deepseek-r1-distill-llama-70b',
128+
},
129+
{ label: 'DeepSeek V3', value: 'deepseek/deepseek-v3' },
130+
{ label: 'DeepSeek V3.1', value: 'deepseek/deepseek-v3.1' },
131+
{ label: 'DeepSeek V3.1 Base', value: 'deepseek/deepseek-v3.1-base' },
132+
{ label: 'DeepSeek V3.1 Terminus', value: 'deepseek/deepseek-v3.1-terminus' },
133+
{ label: 'DeepSeek V3.2 Exp', value: 'deepseek/deepseek-v3.2-exp' },
134+
{
135+
label: 'DeepSeek V3.2 Exp Thinking',
136+
value: 'deepseek/deepseek-v3.2-exp-thinking',
137+
},
138+
139+
// Inception Models
140+
{ label: 'Mercury Coder Small', value: 'inception/mercury-coder-small' },
141+
142+
// Meituan Models
143+
{ label: 'LongCat Flash Chat', value: 'meituan/longcat-flash-chat' },
144+
{ label: 'LongCat Flash Thinking', value: 'meituan/longcat-flash-thinking' },
145+
146+
// Meta Models
147+
{ label: 'Llama 3 70B', value: 'meta/llama-3-70b' },
148+
{ label: 'Llama 3 8B', value: 'meta/llama-3-8b' },
149+
{ label: 'Llama 3.1 70B', value: 'meta/llama-3.1-70b' },
150+
{ label: 'Llama 3.1 8B', value: 'meta/llama-3.1-8b' },
151+
{ label: 'Llama 3.2 11B', value: 'meta/llama-3.2-11b' },
152+
{ label: 'Llama 3.2 1B', value: 'meta/llama-3.2-1b' },
153+
{ label: 'Llama 3.2 3B', value: 'meta/llama-3.2-3b' },
154+
{ label: 'Llama 3.2 90B', value: 'meta/llama-3.2-90b' },
155+
{ label: 'Llama 3.3 70B', value: 'meta/llama-3.3-70b' },
156+
{ label: 'Llama 4 Maverick', value: 'meta/llama-4-maverick' },
157+
{ label: 'Llama 4 Scout', value: 'meta/llama-4-scout' },
158+
159+
// Mistral Models
160+
{ label: 'Codestral', value: 'mistral/codestral' },
161+
{ label: 'Devstral Small', value: 'mistral/devstral-small' },
162+
{ label: 'Magistral Medium', value: 'mistral/magistral-medium' },
163+
{ label: 'Magistral Small', value: 'mistral/magistral-small' },
164+
{ label: 'Ministral 3B', value: 'mistral/ministral-3b' },
165+
{ label: 'Ministral 8B', value: 'mistral/ministral-8b' },
166+
{ label: 'Mistral Large', value: 'mistral/mistral-large' },
167+
{ label: 'Mistral Medium', value: 'mistral/mistral-medium' },
168+
{ label: 'Mistral Small', value: 'mistral/mistral-small' },
169+
{ label: 'Mixtral 8x22B Instruct', value: 'mistral/mixtral-8x22b-instruct' },
170+
{ label: 'Pixtral 12B', value: 'mistral/pixtral-12b' },
171+
{ label: 'Pixtral Large', value: 'mistral/pixtral-large' },
172+
173+
// MoonshotAI Models
174+
{ label: 'Kimi K2', value: 'moonshotai/kimi-k2' },
175+
{ label: 'Kimi K2 0905', value: 'moonshotai/kimi-k2-0905' },
176+
{ label: 'Kimi K2 Turbo', value: 'moonshotai/kimi-k2-turbo' },
177+
178+
// Morph Models
179+
{ label: 'Morph V3 Fast', value: 'morph/morph-v3-fast' },
180+
{ label: 'Morph V3 Large', value: 'morph/morph-v3-large' },
181+
182+
// Perplexity Models
183+
{ label: 'Sonar', value: 'perplexity/sonar' },
184+
{ label: 'Sonar Pro', value: 'perplexity/sonar-pro' },
185+
{ label: 'Sonar Reasoning', value: 'perplexity/sonar-reasoning' },
186+
{ label: 'Sonar Reasoning Pro', value: 'perplexity/sonar-reasoning-pro' },
187+
188+
// Stealth Models
189+
{ label: 'Sonoma Dusk Alpha', value: 'stealth/sonoma-dusk-alpha' },
190+
{ label: 'Sonoma Sky Alpha', value: 'stealth/sonoma-sky-alpha' },
191+
192+
// Vercel Models
193+
{ label: 'v0 1.0 MD', value: 'vercel/v0-1.0-md' },
194+
{ label: 'v0 1.5 MD', value: 'vercel/v0-1.5-md' },
195+
196+
// xAI Models
197+
{ label: 'Grok 2', value: 'xai/grok-2' },
198+
{ label: 'Grok 2 Vision', value: 'xai/grok-2-vision' },
199+
{ label: 'Grok 3', value: 'xai/grok-3' },
200+
{ label: 'Grok 3 Fast', value: 'xai/grok-3-fast' },
201+
{ label: 'Grok 3 Mini', value: 'xai/grok-3-mini' },
202+
{ label: 'Grok 3 Mini Fast', value: 'xai/grok-3-mini-fast' },
203+
{ label: 'Grok 4', value: 'xai/grok-4' },
204+
{ label: 'Grok Code Fast 1', value: 'xai/grok-code-fast-1' },
205+
{
206+
label: 'Grok 4 Fast Non-Reasoning',
207+
value: 'xai/grok-4-fast-non-reasoning',
208+
},
209+
{ label: 'Grok 4 Fast Reasoning', value: 'xai/grok-4-fast-reasoning' },
210+
211+
// ZAI Models
212+
{ label: 'GLM 4.5', value: 'zai/glm-4.5' },
213+
{ label: 'GLM 4.5 Air', value: 'zai/glm-4.5-air' },
214+
{ label: 'GLM 4.5V', value: 'zai/glm-4.5v' },
57215
];
58216

59217
export function SettingsDialog() {
60218
const editor = useEditorRef();
61219

62-
const [tempModel, setTempModel] = React.useState(models[0]);
220+
const [tempModel, setTempModel] = React.useState(models[7]);
63221
const [tempKeys, setTempKeys] = React.useState<Record<string, string>>({
64-
openai: '',
222+
aiGatewayApiKey: '',
65223
uploadthing: '',
66224
});
67225
const [showKey, setShowKey] = React.useState<Record<string, boolean>>({});
@@ -78,7 +236,7 @@ export function SettingsDialog() {
78236
...chatOptions,
79237
body: {
80238
...chatOptions.body,
81-
apiKey: tempKeys.openai,
239+
apiKey: tempKeys.aiGatewayApiKey,
82240
model: tempModel.value,
83241
},
84242
});
@@ -92,7 +250,7 @@ export function SettingsDialog() {
92250
...completeOptions,
93251
body: {
94252
...completeOptions.body,
95-
apiKey: tempKeys.openai,
253+
apiKey: tempKeys.aiGatewayApiKey,
96254
model: tempModel.value,
97255
},
98256
});
@@ -120,8 +278,8 @@ export function SettingsDialog() {
120278
<a
121279
className="flex items-center"
122280
href={
123-
service === 'openai'
124-
? 'https://platform.openai.com/api-keys'
281+
service === 'aiGatewayApiKey'
282+
? 'https://vercel.com/docs/ai-gateway'
125283
: 'https://uploadthing.com/dashboard'
126284
}
127285
rel="noopener noreferrer"
@@ -197,7 +355,7 @@ export function SettingsDialog() {
197355
</div>
198356

199357
<div className="space-y-4">
200-
{renderApiKeyInput('openai', 'OpenAI API key')}
358+
{renderApiKeyInput('aiGatewayApiKey', 'AI Gateway API Key')}
201359

202360
<div className="group relative">
203361
<label

apps/www/src/registry/components/editor/use-chat.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,19 @@ export const useChat = () => {
5555
api: options.api || '/api/ai/command',
5656
// Mock the API response. Remove it when you implement the route /api/ai/command
5757
fetch: async (input, init) => {
58-
const res = await fetch(input, init);
58+
const bodyOptions = editor.getOptions(aiChatPlugin).chatOptions?.body;
59+
60+
const initBody = JSON.parse(init?.body as string);
61+
62+
const body = {
63+
...initBody,
64+
...bodyOptions,
65+
};
66+
67+
const res = await fetch(input, {
68+
...init,
69+
body: JSON.stringify(body),
70+
});
5971

6072
if (!res.ok) {
6173
let sample: 'comment' | 'markdown' | 'mdx' | null = null;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
OPENAI_API_KEY=
1+
AI_GATEWAY_API_KEY=
22
UPLOADTHING_TOKEN=

0 commit comments

Comments
 (0)