Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions apps/builder/__tests__/ai-agent-action-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,28 @@ describe("AI agent action schemas", () => {

expect(result.success).toBe(false)
})

test("rejects retired model ids from new or edited AI agent settings", () => {
const oldModels = [
{ provider: "gemini", model: "gemini-2.5-pro" },
{ provider: "openai", model: "gpt-5.2-chat-latest" },
{ provider: "claude", model: "claude-3-5-haiku-20241022" },
{ provider: "deepseek", model: "deepseek-chat" },
]

for (const model of oldModels) {
const result = createAIAgentRequest.safeParse({
name: "Support",
prompt: "Answer customer questions.",
messages: [],
models: [model],
temperature: 0.4,
maxOutputTokens: 2048,
tools: [],
isDefault: false,
})

expect(result.success).toBe(false)
}
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ export function AIMcpServersCreate({
return (
<Dialog onOpenChange={setIsOpen} open={isOpen}>
{trigger}
<DialogContent className={"max-h-screen max-w-lg overflow-y-scroll"}>
<DialogContent className="max-h-[90vh] w-[92vw] overflow-y-auto sm:max-w-4xl">
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
</DialogHeader>
Expand Down
47 changes: 45 additions & 2 deletions packages/ai/__tests__/model-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,30 @@ describe("AI model catalog", () => {
}
})

test("does not accept retired or malformed native Claude model ids", () => {
const retiredOrMalformedIds = [
"claude-3-5-sonnet-20241022",
"claude-3-5-haiku-20241022",
"claude-3-opus-20240229",
"claude-3-sonnet-20240229",
"claude-3-haiku-20240307",
"claude-opus-4.6",
"claude-4.5-haiku-20251001",
"claude-4.5-sonnet-20250929",
"claude-4.5-opus-20251101",
]

const exposedValues = [
...claudeModelOptions,
...claudeAnalyzeImageModelOptions,
].map((option) => option.value)

for (const modelId of retiredOrMalformedIds) {
expect(claudeModels.safeParse(modelId).success).toBe(false)
expect(exposedValues).not.toContain(modelId)
}
})

test("does not expose known stale model ids in OpenRouter pickers", () => {
const exposedValues = [
...openrouterModelOptions,
Expand All @@ -81,8 +105,27 @@ describe("AI model catalog", () => {
expect(
normalizeAIModelId("openrouter", "anthropic/claude-3-5-sonnet"),
).toBe("anthropic/claude-sonnet-4.5")
expect(normalizeAIModelId("deepseek", "deepseek-chat")).toBe(
"deepseek-v4-flash",
expect(() => normalizeAIModelId("deepseek", "deepseek-chat")).toThrow(
"requires a mode-aware migration",
)
})

test("normalizes every safely migratable persisted model id", () => {
const migrations = [
["claude", "claude-3-5-sonnet-20241022", "claude-sonnet-4-6"],
["claude", "claude-3-5-haiku-20241022", "claude-haiku-4-5-20251001"],
["claude", "claude-3-opus-20240229", "claude-opus-4-8"],
["gemini", "gemini-3-flash", "gemini-3.5-flash"],
["gemini", "gemini-2.5-flash-lite", "gemini-3.5-flash"],
["gemini", "gemini-2.5-flash", "gemini-3.5-flash"],
["gemini", "gemini-2.5-pro", "gemini-3.5-flash"],
["gemini", "gemini-3.1-flash-image-preview", "gemini-3.1-flash-image"],
["openrouter", "google/gemini-2.5-pro-preview", "google/gemini-2.5-pro"],
] as const

for (const [provider, legacyId, canonicalId] of migrations) {
expect(normalizeAIModelId(provider, legacyId)).toBe(canonicalId)
expect(normalizeAIModelId(provider, canonicalId)).toBe(canonicalId)
}
})
})
9 changes: 0 additions & 9 deletions packages/ai/src/models/claude.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
import { z } from "zod"

export const claudeModels = z.enum([
"claude-3-5-sonnet-20241022",
"claude-3-5-haiku-20241022",
"claude-3-opus-20240229",
"claude-3-sonnet-20240229",
"claude-3-haiku-20240307",
"claude-opus-4.6",
"claude-fable-5",
"claude-opus-4-8",
"claude-opus-4-6",
"claude-sonnet-4-6",
"claude-haiku-4-5-20251001",
"claude-sonnet-4-5-20250929",
"claude-opus-4-5-20251101",
"claude-4.5-haiku-20251001",
"claude-4.5-sonnet-20250929",
"claude-4.5-opus-20251101",
])
export type ClaudeModel = z.infer<typeof claudeModels>

Expand Down
18 changes: 1 addition & 17 deletions packages/ai/src/models/deepseek.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import { z } from "zod"

// DeepSeek keeps `deepseek-chat` and `deepseek-reasoner` as legacy aliases.
// Prefer the explicit V4 ids for new configs, but keep aliases for compatibility
// with existing integrations and agents.
export const deepseekModels = z.enum([
"deepseek-v4-flash",
"deepseek-v4-pro",
"deepseek-chat",
"deepseek-reasoner",
])
export const deepseekModels = z.enum(["deepseek-v4-flash", "deepseek-v4-pro"])
export type DeepSeekModel = z.infer<typeof deepseekModels>

export const deepseekModelOptions: { label: string; value: DeepSeekModel }[] = [
Expand All @@ -20,12 +12,4 @@ export const deepseekModelOptions: { label: string; value: DeepSeekModel }[] = [
label: "DeepSeek V4 Pro",
value: deepseekModels.enum["deepseek-v4-pro"],
},
{
label: "DeepSeek Chat (Legacy)",
value: deepseekModels.enum["deepseek-chat"],
},
{
label: "DeepSeek Reasoner (Legacy)",
value: deepseekModels.enum["deepseek-reasoner"],
},
]
48 changes: 3 additions & 45 deletions packages/ai/src/models/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@ export const geminiEmbeddingModels = z.enum(["gemini-embedding-001"])
export type GeminiEmbeddingModel = z.infer<typeof geminiEmbeddingModels>

export const geminiModels = z.enum([
"gemini-3-pro-image-preview",
"gemini-3.5-flash",
"gemini-3.1-flash-lite",
"gemini-2.5-flash-lite",
"gemini-2.5-flash",
"gemini-2.5-pro",
"gemini-2.0-flash-thinking-exp",
"gemini-3-flash",
"gemini-3.1-pro-preview",
])
export type GeminiModel = z.infer<typeof geminiModels>
Expand All @@ -28,26 +22,10 @@ export const geminiAnalyzeImageModelOptions: {
label: "Gemini 3.1 Flash Lite",
value: geminiModels.enum["gemini-3.1-flash-lite"],
},
{
label: "Gemini 3 Flash",
value: geminiModels.enum["gemini-3-flash"],
},
{
label: "Gemini 3.1 Pro Preview",
value: geminiModels.enum["gemini-3.1-pro-preview"],
},
{
label: "Gemini 2.5 Flash-Lite",
value: geminiModels.enum["gemini-2.5-flash-lite"],
},
{
label: "Gemini 2.5 Flash",
value: geminiModels.enum["gemini-2.5-flash"],
},
{
label: "Gemini 2.5 Pro",
value: geminiModels.enum["gemini-2.5-pro"],
},
]

export const geminiModelOptions: { label: string; value: GeminiModel }[] = [
Expand All @@ -63,37 +41,17 @@ export const geminiModelOptions: { label: string; value: GeminiModel }[] = [
label: "Gemini 3.1 Flash Lite",
value: geminiModels.enum["gemini-3.1-flash-lite"],
},
{
label: "Gemini 3 Flash",
value: geminiModels.enum["gemini-3-flash"],
},
{
label: "Gemini 2.5 Flash Lite",
value: geminiModels.enum["gemini-2.5-flash-lite"],
},
{
label: "Gemini 2.5 Flash",
value: geminiModels.enum["gemini-2.5-flash"],
},
{
label: "Gemini 2.5 Pro",
value: geminiModels.enum["gemini-2.5-pro"],
},
{
label: "Gemini 2.0 Flash Thinking",
value: geminiModels.enum["gemini-2.0-flash-thinking-exp"],
},
]

export const geminiImageModels = z.enum(["gemini-3.1-flash-image-preview"])
export const geminiImageModels = z.enum(["gemini-3.1-flash-image"])
export type GeminiImageModel = z.infer<typeof geminiImageModels>

export const geminiImageModelOptions: {
label: string
value: GeminiImageModel
}[] = [
{
label: "Imagen 3",
value: geminiImageModels.enum["gemini-3.1-flash-image-preview"],
label: "Gemini 3.1 Flash Image",
value: geminiImageModels.enum["gemini-3.1-flash-image"],
},
]
44 changes: 0 additions & 44 deletions packages/ai/src/models/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,15 @@ export const openaiModels = z.enum([
"gpt-4.1-nano",
"gpt-4.1",
"gpt-4",
"gpt-4o-audio-preview",
"gpt-4o-mini",
"gpt-4o",
"gpt-5-chat-latest",
"gpt-5-codex",
"gpt-5-mini",
"gpt-5-nano",
"gpt-5-pro",
"gpt-5.1-chat-latest",
"gpt-5.1-codex-mini",
"gpt-5.1-codex",
"gpt-5.1",
"gpt-5.2-chat-latest",
"gpt-5.2-pro",
"gpt-5.2",
"gpt-5",
"gpt-5.5-pro",
"gpt-5.5",
"gpt-5.4-pro",
"gpt-5.4",
Expand All @@ -39,10 +31,6 @@ export const openaiAnalyzeImageModelOptions: {
label: string
value: OpenAIModel
}[] = [
{
label: "GPT-5.5 Pro",
value: openaiModels.enum["gpt-5.5-pro"],
},
{
label: "GPT-5.5",
value: openaiModels.enum["gpt-5.5"],
Expand Down Expand Up @@ -98,10 +86,6 @@ export const openaiAnalyzeImageModelOptions: {
]

export const openaiModelOptions: { label: string; value: OpenAIModel }[] = [
{
label: "GPT-5.5 Pro",
value: openaiModels.enum["gpt-5.5-pro"],
},
{
label: "GPT-5.5",
value: openaiModels.enum["gpt-5.5"],
Expand All @@ -126,26 +110,10 @@ export const openaiModelOptions: { label: string; value: OpenAIModel }[] = [
label: "GPT-5.2 Pro",
value: openaiModels.enum["gpt-5.2-pro"],
},
{
label: "GPT-5.2 Chat Latest",
value: openaiModels.enum["gpt-5.2-chat-latest"],
},
{
label: "GPT-5.2",
value: openaiModels.enum["gpt-5.2"],
},
{
label: "GPT-5.1 Codex Mini",
value: openaiModels.enum["gpt-5.1-codex-mini"],
},
{
label: "GPT-5.1 Codex",
value: openaiModels.enum["gpt-5.1-codex"],
},
{
label: "GPT-5.1 Chat Latest",
value: openaiModels.enum["gpt-5.1-chat-latest"],
},
{
label: "GPT-5.1",
value: openaiModels.enum["gpt-5.1"],
Expand All @@ -166,14 +134,6 @@ export const openaiModelOptions: { label: string; value: OpenAIModel }[] = [
label: "GPT-5 Nano",
value: openaiModels.enum["gpt-5-nano"],
},
{
label: "GPT-5 Codex",
value: openaiModels.enum["gpt-5-codex"],
},
{
label: "GPT-5 Chat Latest",
value: openaiModels.enum["gpt-5-chat-latest"],
},
{
label: "GPT-4.1",
value: openaiModels.enum["gpt-4.1"],
Expand All @@ -194,10 +154,6 @@ export const openaiModelOptions: { label: string; value: OpenAIModel }[] = [
label: "GPT-4o Mini",
value: openaiModels.enum["gpt-4o-mini"],
},
{
label: "GPT-4o Audio Preview",
value: openaiModels.enum["gpt-4o-audio-preview"],
},
{
label: "GPT-4",
value: openaiModels.enum["gpt-4"],
Expand Down
12 changes: 0 additions & 12 deletions packages/ai/src/models/openrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const openrouterModels = z.enum([
"openai/gpt-5.2-chat",
"openai/gpt-5.2",
"openai/gpt-5.1",
"openai/gpt-5.1-chat",
"openai/gpt-5-pro",
"openai/gpt-5",
"openai/gpt-5-mini",
Expand All @@ -24,28 +23,21 @@ export const openrouterModels = z.enum([
"openai/gpt-4o-mini",
"anthropic/claude-fable-5",
"anthropic/claude-opus-4.8",
"anthropic/claude-opus-4.8-fast",
"anthropic/claude-opus-4.6",
"anthropic/claude-sonnet-4.6",
"anthropic/claude-opus-4.5",
"anthropic/claude-sonnet-4.5",
"anthropic/claude-haiku-4.5",
"anthropic/claude-3-5-sonnet",
"anthropic/claude-3-5-haiku",
"google/gemini-3.5-flash",
"google/gemini-3.1-pro-preview",
"google/gemini-3.1-flash-lite",
"google/gemini-3-flash-preview",
"google/gemini-2.0-flash",
"google/gemini-2.5-flash-lite",
"google/gemini-2.5-flash",
"google/gemini-2.5-pro",
"google/gemini-2.5-pro-preview",
"meta-llama/llama-4-maverick",
"meta-llama/llama-4-scout",
"meta-llama/llama-3.3-70b-instruct",
"meta-llama/llama-3.2-90b-vision-instruct",
"meta-llama/llama-3.2-11b-vision-instruct",
"deepseek/deepseek-v4-pro",
"deepseek/deepseek-v4-flash",
"deepseek/deepseek-v3.2",
Expand Down Expand Up @@ -130,10 +122,6 @@ export const openrouterAnalyzeImageModelOptions: AiChatModelOption[] = [
{ label: "Gemini 3.1 Flash Lite", value: "google/gemini-3.1-flash-lite" },
{ label: "Gemini 2.5 Flash", value: "google/gemini-2.5-flash" },
{ label: "Gemini 2.5 Pro", value: "google/gemini-2.5-pro" },
{
label: "Llama 3.2 11B Vision",
value: "meta-llama/llama-3.2-11b-vision-instruct",
},
{ label: "Qwen3 VL 32B", value: "qwen/qwen3-vl-32b-instruct" },
]

Expand Down
Loading