chatbot-template/lib/ai/models.ts

181 lines
4.4 KiB
TypeScript

export const DEFAULT_CHAT_MODEL = "moonshotai/kimi-k2.5";
export const titleModel = {
id: "mistral/mistral-small",
name: "Mistral Small",
provider: "mistral",
description: "Fast model for title generation",
gatewayOrder: ["mistral"],
};
export type ModelCapabilities = {
tools: boolean;
vision: boolean;
reasoning: boolean;
};
export type ChatModel = {
id: string;
name: string;
provider: string;
description: string;
gatewayOrder?: string[];
reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high";
};
export const chatModels: ChatModel[] = [
{
id: "deepseek/deepseek-v3.2",
name: "DeepSeek V3.2",
provider: "deepseek",
description: "Fast and capable model with tool use",
gatewayOrder: ["bedrock", "deepinfra"],
},
{
id: "mistral/codestral",
name: "Codestral",
provider: "mistral",
description: "Code-focused model with tool use",
gatewayOrder: ["mistral"],
},
{
id: "mistral/mistral-small",
name: "Mistral Small",
provider: "mistral",
description: "Fast vision model with tool use",
gatewayOrder: ["mistral"],
},
{
id: "moonshotai/kimi-k2.5",
name: "Kimi K2.5",
provider: "moonshotai",
description: "Moonshot AI flagship model",
gatewayOrder: ["fireworks", "bedrock"],
},
{
id: "openai/gpt-oss-20b",
name: "GPT OSS 20B",
provider: "openai",
description: "Compact reasoning model",
gatewayOrder: ["groq", "bedrock"],
reasoningEffort: "low",
},
{
id: "openai/gpt-oss-120b",
name: "GPT OSS 120B",
provider: "openai",
description: "Open-source 120B parameter model",
gatewayOrder: ["fireworks", "bedrock"],
reasoningEffort: "low",
},
{
id: "xai/grok-4.1-fast-non-reasoning",
name: "Grok 4.1 Fast",
provider: "xai",
description: "Fast non-reasoning model with tool use",
gatewayOrder: ["xai"],
},
];
export async function getCapabilities(): Promise<
Record<string, ModelCapabilities>
> {
const results = await Promise.all(
chatModels.map(async (model) => {
try {
const res = await fetch(
`https://ai-gateway.vercel.sh/v1/models/${model.id}/endpoints`,
{ next: { revalidate: 86_400 } }
);
if (!res.ok) {
return [model.id, { tools: false, vision: false, reasoning: false }];
}
const json = await res.json();
const endpoints = json.data?.endpoints ?? [];
const params = new Set(
endpoints.flatMap(
(e: { supported_parameters?: string[] }) =>
e.supported_parameters ?? []
)
);
const inputModalities = new Set(
json.data?.architecture?.input_modalities ?? []
);
return [
model.id,
{
tools: params.has("tools"),
vision: inputModalities.has("image"),
reasoning: params.has("reasoning"),
},
];
} catch {
return [model.id, { tools: false, vision: false, reasoning: false }];
}
})
);
return Object.fromEntries(results);
}
export const isDemo = process.env.IS_DEMO === "1";
type GatewayModel = {
id: string;
name: string;
type?: string;
tags?: string[];
};
export type GatewayModelWithCapabilities = ChatModel & {
capabilities: ModelCapabilities;
};
export async function getAllGatewayModels(): Promise<
GatewayModelWithCapabilities[]
> {
try {
const res = await fetch("https://ai-gateway.vercel.sh/v1/models", {
next: { revalidate: 86_400 },
});
if (!res.ok) {
return [];
}
const json = await res.json();
return (json.data ?? [])
.filter((m: GatewayModel) => m.type === "language")
.map((m: GatewayModel) => ({
id: m.id,
name: m.name,
provider: m.id.split("/")[0],
description: "",
capabilities: {
tools: m.tags?.includes("tool-use") ?? false,
vision: m.tags?.includes("vision") ?? false,
reasoning: m.tags?.includes("reasoning") ?? false,
},
}));
} catch {
return [];
}
}
export function getActiveModels(): ChatModel[] {
return chatModels;
}
export const allowedModelIds = new Set(chatModels.map((m) => m.id));
export const modelsByProvider = chatModels.reduce(
(acc, model) => {
if (!acc[model.provider]) {
acc[model.provider] = [];
}
acc[model.provider].push(model);
return acc;
},
{} as Record<string, ChatModel[]>
);