Files
classroomio/packages/ai-assistant/src/providers/index.ts
T

76 lines
2.6 KiB
TypeScript

import { createOpenAI } from '@ai-sdk/openai';
import { createAnthropic } from '@ai-sdk/anthropic';
import { createGoogleGenerativeAI } from '@ai-sdk/google';
import { createMoonshotAI } from '@ai-sdk/moonshotai';
import type { LanguageModel } from 'ai';
import { AIProvider, type AIProviderConfig } from '../types';
const DEFAULT_MODELS: Record<AIProvider, string> = {
[AIProvider.OPENAI]: 'gpt-5.4-mini',
[AIProvider.ANTHROPIC]: 'claude-sonnet-4-20250514',
[AIProvider.GOOGLE]: 'gemini-3.1-flash-lite',
[AIProvider.MOONSHOT]: 'kimi-k2.6'
};
const PROVIDER_API_KEY_ENV: Record<AIProvider, string> = {
[AIProvider.OPENAI]: 'OPENAI_API_KEY',
[AIProvider.ANTHROPIC]: 'ANTHROPIC_API_KEY',
[AIProvider.GOOGLE]: 'GOOGLE_API_KEY',
[AIProvider.MOONSHOT]: 'MOONSHOT_API_KEY'
};
/**
* Creates an AI SDK LanguageModel from provider configuration.
* Normalizes OpenAI, Anthropic, and Google into a single interface for streamText().
*/
export function createModel(config: AIProviderConfig): LanguageModel {
const modelName = config.model || DEFAULT_MODELS[config.provider];
switch (config.provider) {
case AIProvider.OPENAI: {
const openai = createOpenAI({ apiKey: config.apiKey });
return openai(modelName);
}
case AIProvider.ANTHROPIC: {
const anthropic = createAnthropic({ apiKey: config.apiKey });
return anthropic(modelName);
}
case AIProvider.GOOGLE: {
const google = createGoogleGenerativeAI({ apiKey: config.apiKey });
return google(modelName);
}
case AIProvider.MOONSHOT: {
const moonshot = createMoonshotAI({ apiKey: config.apiKey });
return moonshot(modelName);
}
default:
throw new Error(`Unsupported AI provider: ${config.provider}`);
}
}
/**
* Reads the API key for a specific provider from its dedicated env var.
* Returns null when the key is unset, so callers can decide whether to 503.
*/
export function getProviderConfigForProvider(provider: AIProvider): AIProviderConfig | null {
const apiKey = process.env[PROVIDER_API_KEY_ENV[provider]];
if (!apiKey) return null;
return { provider, apiKey };
}
/**
* Returns the first provider that has a key configured, in preference order.
* Used by routes that don't take an explicit model (status check, title generation).
*/
export function pickAnyConfiguredProvider(): AIProviderConfig | null {
const order: AIProvider[] = [AIProvider.GOOGLE, AIProvider.OPENAI, AIProvider.ANTHROPIC];
for (const provider of order) {
const config = getProviderConfigForProvider(provider);
if (config) return config;
}
return null;
}