AI configuration
Models, provider chain, embeddings, and client storage
Source: src/lib/ai/providers.ts, src/lib/ai/with-fallback.ts, src/lib/ai/generate.ts, src/lib/ai/embed.ts.
Provider IDs
const AI_PROVIDER_IDS = ["openai", "gemini"] as const;
type AiProvider = "openai" | "gemini";Provider config
| Key | label | chatLabel | chatModel | embedModel | dimensions |
|---|---|---|---|---|---|
gemini | Gemini | Gemini 2.5 Flash | gemini-2.5-flash | text-embedding-004 | 768 |
openai | OpenAI | GPT-5 Nano | gpt-5-nano | text-embedding-3-small | 768 |
export const EMBEDDING_DIMENSIONS = 768;
export const DEFAULT_AI_PROVIDER: AiProvider = "openai";
export const AI_PROVIDER_STORAGE_KEY = "command-inbox-ai-provider-v2";Client storage
User provider preference persists in localStorage under command-inbox-ai-provider-v2.
Client-safe helpers live in src/lib/ai/alternate-provider.ts (no server-only imports).
Provider chain
getProviderChain(preferred: AiProvider): AiProvider[]
Returns [preferred, alternate] — typically ["openai", "gemini"] or reversed if user selected Gemini.
withProviderFallback() wraps async AI calls:
- Execute with primary provider
- On rate limit / quota / retryable error → retry with fallback
- Propagate error if both fail
Chat generation
Uses Vercel AI SDK generateText / streamText with model instances from @ai-sdk/openai and @ai-sdk/google.
Embeddings
embedText(text, provider) returns 768-dim vector.
Stored on classifications.embedding with embedding_provider column tracking source.
Re-embed: src/lib/embeddings/reembed-inbox.ts — batch updates all user classifications when provider switches.
Rate limiting
src/lib/ai/rate-limit.ts — in-memory sliding window for burst protection during development.
Draft fallback
src/lib/ai/drafts.ts — when AI generation fails, returns template HTML with source: "template".
Server-only boundary
These modules import server-only:
src/lib/env.tssrc/lib/ai/models.tssrc/lib/ai/generate.tssrc/lib/ai/embed.ts
Client components must use API routes or alternate-provider.ts helpers.
Env dependency
assertPhase2Env() // requires GOOGLE_GENERATIVE_AI_API_KEY || OPENAI_API_KEYparseAiProvider
parseAiProvider(value: unknown, fallback = DEFAULT_AI_PROVIDER): AiProviderSafely parses user/API input; invalid values fall back to openai.