The chatbot uses a single myProvider object defined in lib/ai/models.ts to manage all language and image models. Adding a new model means registering it in that provider and adding a display entry to the chatModels array — the model selector UI reads from that array automatically.
Install the provider package
The Vercel AI SDK publishes a package for each supported provider. Install the one you need.pnpm add @ai-sdk/anthropic
Set the provider’s API key as an environment variable (for example, ANTHROPIC_API_KEY). Check the provider’s SDK docs for the exact variable name.
Register the model in myProvider
Open lib/ai/models.ts. The existing provider looks like this:import { openai } from '@ai-sdk/openai';
import { fireworks } from '@ai-sdk/fireworks';
import {
customProvider,
extractReasoningMiddleware,
wrapLanguageModel,
} from 'ai';
export const DEFAULT_CHAT_MODEL: string = 'chat-model-small';
export const myProvider = customProvider({
languageModels: {
'chat-model-small': openai('gpt-4o-mini'),
'chat-model-large': openai('gpt-4o'),
'chat-model-reasoning': wrapLanguageModel({
model: fireworks('accounts/fireworks/models/deepseek-r1'),
middleware: extractReasoningMiddleware({ tagName: 'think' }),
}),
'title-model': openai('gpt-4-turbo'),
'artifact-model': openai('gpt-4o-mini'),
},
imageModels: {
'small-model': openai.image('dall-e-2'),
'large-model': openai.image('dall-e-3'),
},
});
To add Anthropic Claude, import the provider and add a new key to languageModels:import { openai } from '@ai-sdk/openai';
import { fireworks } from '@ai-sdk/fireworks';
import { anthropic } from '@ai-sdk/anthropic';
import {
customProvider,
extractReasoningMiddleware,
wrapLanguageModel,
} from 'ai';
export const DEFAULT_CHAT_MODEL: string = 'chat-model-small';
export const myProvider = customProvider({
languageModels: {
'chat-model-small': openai('gpt-4o-mini'),
'chat-model-large': openai('gpt-4o'),
'chat-model-reasoning': wrapLanguageModel({
model: fireworks('accounts/fireworks/models/deepseek-r1'),
middleware: extractReasoningMiddleware({ tagName: 'think' }),
}),
'chat-model-claude': anthropic('claude-3-5-sonnet-20241022'),
'title-model': openai('gpt-4-turbo'),
'artifact-model': openai('gpt-4o-mini'),
},
imageModels: {
'small-model': openai.image('dall-e-2'),
'large-model': openai.image('dall-e-3'),
},
});
The string key ('chat-model-claude') is the internal model ID used throughout the codebase. Choose a key that is unique within the languageModels object. Add a display entry to chatModels
Still in lib/ai/models.ts, add an object to the chatModels array. This is what the model selector dropdown renders.export const chatModels: Array<ChatModel> = [
{
id: 'chat-model-small',
name: 'Small model',
description: 'Small model for fast, lightweight tasks',
},
{
id: 'chat-model-large',
name: 'Large model',
description: 'Large model for complex, multi-step tasks',
},
{
id: 'chat-model-reasoning',
name: 'Reasoning model',
description: 'Uses advanced reasoning',
},
{
id: 'chat-model-claude',
name: 'Claude 3.5 Sonnet',
description: 'Anthropic model with strong instruction-following',
},
];
The id field must exactly match the key you added to myProvider.languageModels in the previous step. Verify the model selector
The ModelSelector component in components/model-selector.tsx reads from chatModels directly — no changes are needed there. Start the dev server and open a chat to confirm your new model appears in the dropdown.If you want the new model to be the default, update DEFAULT_CHAT_MODEL at the top of lib/ai/models.ts to match your new model’s id.
Special model configurations
Reasoning models
The built-in reasoning model wraps DeepSeek R1 with extractReasoningMiddleware to parse <think> tags from the response. You can apply the same middleware to any model that emits reasoning tokens:
import { extractReasoningMiddleware, wrapLanguageModel } from 'ai';
'chat-model-reasoning': wrapLanguageModel({
model: fireworks('accounts/fireworks/models/deepseek-r1'),
middleware: extractReasoningMiddleware({ tagName: 'think' }),
}),
Reasoning models receive only the regularPrompt system prompt, not the artifacts prompt. This is enforced in lib/ai/prompts.ts and app/(chat)/api/chat/route.ts. If your new model is a reasoning model, set experimental_activeTools to [] for that model ID in the chat route to disable tool calling.
Internal-only models
title-model and artifact-model are registered in myProvider but intentionally excluded from chatModels. They are used internally for title generation and artifact content generation respectively. You can follow the same pattern to add models that are not user-selectable.