Provider abstraction
Hard-coding one provider is fine for a hackathon. The moment your company has an OpenAI contract or wants to try Claude for a specific task, the flat import becomes a liability. Extract model selection into a getModel helper behind an env var and the whole codebase stops caring which provider is active.
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
import { createOpenAI } from '@ai-sdk/openai';
export function getModel() {
const provider = process.env.LLM_PROVIDER ?? 'openrouter';
if (provider === 'openai') {
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY ?? '',
});
return openai.chat(process.env.OPENAI_MODEL ?? 'gpt-4o-mini');
}
const openrouter = createOpenRouter({
apiKey: process.env.OPENROUTER_API_KEY ?? '',
});
return openrouter.chat(
process.env.OPENROUTER_MODEL ?? 'google/gemma-3-12b-it',
);
}One helper reads LLM_PROVIDER and returns a ready model. The route handler, tools, and generators all import getModel. Swapping providers is one env var away.
import { getModel } from '@/lib/get-model';
export async function POST(req: Request) {
// ... validation as before
const result = streamText({
model: getModel(),
system: SYSTEM_PROMPT,
messages: convertToModelMessages(parsed.data.messages),
tools: agentTools,
maxSteps: 5,
});
return result.toUIMessageStreamResponse();
}Route handler no longer knows about OpenRouter or OpenAI. It just asks for a model and streams. Every caller in the codebase does the same thing.
Provider abstraction
One feature flag switches the whole app. No file outside lib/get-model.ts knows which provider is active.