The Vercel AI Chatbot integrates with multiple AI model providers through Vercel AI Gateway, offering a unified interface for accessing models from Anthropic, OpenAI, Google, and xAI.
Available models
The chatbot supports a curated list of top-performing models across different providers:
Anthropic
OpenAI
Google
xAI
Reasoning
{
id : "anthropic/claude-haiku-4.5" ,
name : "Claude Haiku 4.5" ,
provider : "anthropic" ,
description : "Fast and affordable, great for everyday tasks" ,
}
{
id : "openai/gpt-4.1-mini" ,
name : "GPT-4.1 Mini" ,
provider : "openai" ,
description : "Fast and cost-effective for simple tasks" ,
},
{
id : "openai/gpt-5-mini" ,
name : "GPT-5 Mini" ,
provider : "openai" ,
description : "Most capable OpenAI model" ,
}
{
id : "google/gemini-2.5-flash-lite" ,
name : "Gemini 2.5 Flash Lite" ,
provider : "google" ,
description : "Ultra fast and affordable" ,
},
{
id : "google/gemini-3-pro-preview" ,
name : "Gemini 3 Pro" ,
provider : "google" ,
description : "Most capable Google model" ,
}
{
id : "xai/grok-4.1-fast-non-reasoning" ,
name : "Grok 4.1 Fast" ,
provider : "xai" ,
description : "Fast with 30K context" ,
}
{
id : "anthropic/claude-3.7-sonnet-thinking" ,
name : "Claude 3.7 Sonnet" ,
provider : "reasoning" ,
description : "Extended thinking for complex problems" ,
},
{
id : "xai/grok-code-fast-1-thinking" ,
name : "Grok Code Fast" ,
provider : "reasoning" ,
description : "Reasoning optimized for code" ,
}
Model configuration
Define your available models in lib/ai/models.ts:
export const DEFAULT_CHAT_MODEL = "openai/gpt-4.1-mini" ;
export type ChatModel = {
id : string ;
name : string ;
provider : string ;
description : string ;
};
export const chatModels : ChatModel [] = [
// Anthropic
{
id: "anthropic/claude-haiku-4.5" ,
name: "Claude Haiku 4.5" ,
provider: "anthropic" ,
description: "Fast and affordable, great for everyday tasks" ,
},
// OpenAI
{
id: "openai/gpt-4.1-mini" ,
name: "GPT-4.1 Mini" ,
provider: "openai" ,
description: "Fast and cost-effective for simple tasks" ,
},
// Add more models...
];
// Group models by provider for UI
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 []>
);
AI Gateway integration
The getLanguageModel function provides a unified interface to all models through Vercel AI Gateway:
import { gateway } from "@ai-sdk/gateway" ;
import { wrapLanguageModel , extractReasoningMiddleware } from "ai" ;
export function getLanguageModel ( modelId : string ) {
const isReasoningModel =
modelId . endsWith ( "-thinking" ) ||
( modelId . includes ( "reasoning" ) && ! modelId . includes ( "non-reasoning" ));
if ( isReasoningModel ) {
const gatewayModelId = modelId . replace ( /-thinking $ / , "" );
return wrapLanguageModel ({
model: gateway . languageModel ( gatewayModelId ),
middleware: extractReasoningMiddleware ({ tagName: "thinking" }),
});
}
return gateway . languageModel ( modelId );
}
Specialized models
Different models are used for specific tasks:
export function getTitleModel () {
return gateway . languageModel ( "google/gemini-2.5-flash-lite" );
}
export function getArtifactModel () {
return gateway . languageModel ( "anthropic/claude-haiku-4.5" );
}
Using models in the chat API
The chat API route uses the selected model to generate responses:
app/(chat)/api/chat/route.ts
import { streamText } from "ai" ;
import { getLanguageModel } from "@/lib/ai/providers" ;
export async function POST ( request : Request ) {
const { selectedChatModel , message } = await request . json ();
// Validate model ID
if ( ! allowedModelIds . has ( selectedChatModel )) {
return new ChatbotError ( "bad_request:api" ). toResponse ();
}
const isReasoningModel =
selectedChatModel . endsWith ( "-thinking" ) ||
( selectedChatModel . includes ( "reasoning" ) &&
! selectedChatModel . includes ( "non-reasoning" ));
const result = streamText ({
model: getLanguageModel ( selectedChatModel ),
system: systemPrompt ({ selectedChatModel , requestHints }),
messages: modelMessages ,
experimental_activeTools: isReasoningModel
? []
: [
"getWeather" ,
"createDocument" ,
"updateDocument" ,
"requestSuggestions" ,
],
providerOptions: isReasoningModel
? {
anthropic: {
thinking: { type: "enabled" , budgetTokens: 10_000 },
},
}
: undefined ,
});
return result . toUIMessageStream ({ sendReasoning: isReasoningModel });
}
Reasoning models
Reasoning models support extended thinking for complex problems:
Extended thinking Models can use additional compute for complex reasoning tasks
Reasoning visibility The reasoning process is visible to users in real-time
Configuring reasoning
Reasoning models use special configuration:
app/(chat)/api/chat/route.ts
const isReasoningModel =
selectedChatModel . endsWith ( "-thinking" ) ||
( selectedChatModel . includes ( "reasoning" ) &&
! selectedChatModel . includes ( "non-reasoning" ));
const result = streamText ({
model: getLanguageModel ( selectedChatModel ),
providerOptions: isReasoningModel
? {
anthropic: {
thinking: {
type: "enabled" ,
budgetTokens: 10_000 ,
},
},
}
: undefined ,
});
The reasoning middleware extracts thinking tags from the response:
import { wrapLanguageModel , extractReasoningMiddleware } from "ai" ;
if ( isReasoningModel ) {
return wrapLanguageModel ({
model: gateway . languageModel ( gatewayModelId ),
middleware: extractReasoningMiddleware ({ tagName: "thinking" }),
});
}
Model selector UI
The model selector component allows users to switch between models:
components/multimodal-input.tsx
import {
ModelSelector ,
ModelSelectorTrigger ,
ModelSelectorContent ,
ModelSelectorList ,
ModelSelectorGroup ,
ModelSelectorItem ,
} from "@/components/ai-elements/model-selector" ;
function ModelSelectorCompact ({ selectedModelId , onModelChange }) {
const selectedModel =
chatModels . find (( m ) => m . id === selectedModelId ) ??
chatModels . find (( m ) => m . id === DEFAULT_CHAT_MODEL );
return (
< ModelSelector >
< ModelSelectorTrigger >
< ModelSelectorLogo provider = { provider } />
< ModelSelectorName > { selectedModel . name } </ ModelSelectorName >
</ ModelSelectorTrigger >
< ModelSelectorContent >
< ModelSelectorInput placeholder = "Search models..." />
< ModelSelectorList >
{ Object . entries ( modelsByProvider ). map (
([ providerKey , providerModels ]) => (
< ModelSelectorGroup heading = { providerKey } >
{ providerModels . map (( model ) => (
< ModelSelectorItem
value = { model . id }
onSelect = { () => {
onModelChange ?.( model . id );
setCookie ( "chat-model" , model . id );
} }
>
< ModelSelectorLogo provider = { logoProvider } />
< ModelSelectorName > { model . name } </ ModelSelectorName >
</ ModelSelectorItem >
)) }
</ ModelSelectorGroup >
)
) }
</ ModelSelectorList >
</ ModelSelectorContent >
</ ModelSelector >
);
}
Model persistence
The selected model is persisted in a cookie:
components/multimodal-input.tsx
function setCookie ( name : string , value : string ) {
const maxAge = 60 * 60 * 24 * 365 ; // 1 year
document . cookie = ` ${ name } = ${ encodeURIComponent ( value ) } ; path=/; max-age= ${ maxAge } ` ;
}
AI Gateway requires a valid credit card on file to service requests. Users receive free credits upon activation.
Environment configuration
No additional environment variables are needed beyond the standard Vercel deployment. AI Gateway is automatically configured for Vercel deployments.
Testing environment
For testing, you can use mock models:
import { customProvider } from "ai" ;
import { isTestEnvironment } from "@/lib/constants" ;
export const myProvider = isTestEnvironment
? customProvider ({
languageModels: {
"chat-model" : chatModel ,
"chat-model-reasoning" : reasoningModel ,
"title-model" : titleModel ,
"artifact-model" : artifactModel ,
},
})
: null ;
Chat interface Learn how models are used in the chat
Artifacts Understand artifact generation with specialized models