diff --git a/src/app/api/settings/ai/route.ts b/src/app/api/settings/ai/route.ts
index 12c5fa3..ac27c46 100644
--- a/src/app/api/settings/ai/route.ts
+++ b/src/app/api/settings/ai/route.ts
@@ -7,7 +7,7 @@ import { eq } from 'drizzle-orm';
import { requirePermission } from '@/lib/auth/rbac';
import type { AIProvider } from '@/lib/ai/providers';
-const VALID_PROVIDERS = new Set
(['anthropic', 'openai', 'ollama']);
+const VALID_PROVIDERS = new Set(['anthropic', 'openai', 'openrouter', 'ollama']);
export async function GET() {
const auth = await requirePermission('settings:manage');
diff --git a/src/app/api/settings/api-keys/route.ts b/src/app/api/settings/api-keys/route.ts
index 54533f2..9b80da1 100644
--- a/src/app/api/settings/api-keys/route.ts
+++ b/src/app/api/settings/api-keys/route.ts
@@ -9,7 +9,7 @@ import { encrypt, keyHint } from '@/lib/crypto';
import { logAuditEvent } from '@/lib/auth/audit';
import type { AIProvider } from '@/lib/ai/providers';
-const VALID_PROVIDERS = new Set(['anthropic', 'openai', 'ollama']);
+const VALID_PROVIDERS = new Set(['anthropic', 'openai', 'openrouter', 'ollama']);
export async function GET() {
const auth = await requirePermission('settings:manage');
diff --git a/src/lib/ai/providers/index.ts b/src/lib/ai/providers/index.ts
index 85e49f9..036f2d9 100644
--- a/src/lib/ai/providers/index.ts
+++ b/src/lib/ai/providers/index.ts
@@ -1,5 +1,5 @@
// AI Provider abstraction via Vercel AI SDK v6
-// Supports: Anthropic, OpenAI, Ollama — selected via AI_PROVIDER env var or tenant settings
+// Supports: Anthropic, OpenAI, OpenRouter, Ollama — selected via AI_PROVIDER env var or tenant settings
// Per-tenant API keys are loaded from tenant_api_keys (AES-256-GCM encrypted)
import { createAnthropic, anthropic } from '@ai-sdk/anthropic';
@@ -10,17 +10,19 @@ import { tenants, tenantApiKeys } from '@/lib/db/schema';
import { eq, and } from 'drizzle-orm';
import { decrypt } from '@/lib/crypto';
-export type AIProvider = 'anthropic' | 'openai' | 'ollama';
+export type AIProvider = 'anthropic' | 'openai' | 'openrouter' | 'ollama';
const DEFAULT_MODELS: Record = {
anthropic: 'claude-sonnet-4-20250514',
openai: 'gpt-4o',
+ openrouter: 'anthropic/claude-sonnet-4',
ollama: 'llama3',
};
export function getProvider(): AIProvider {
const p = process.env.AI_PROVIDER;
if (p === 'openai') return 'openai';
+ if (p === 'openrouter') return 'openrouter';
if (p === 'ollama') return 'ollama';
return 'anthropic';
}
@@ -45,6 +47,13 @@ function buildModel(
}
return openai(modelId);
}
+ case 'openrouter': {
+ const openrouter = createOpenAI({
+ baseURL: 'https://openrouter.ai/api/v1',
+ apiKey: options?.apiKey ?? process.env.OPENROUTER_API_KEY ?? '',
+ });
+ return openrouter(modelId);
+ }
case 'ollama': {
const baseURL = options?.ollamaUrl ?? process.env.OLLAMA_URL ?? 'http://localhost:11434';
const ollama = createOpenAI({
@@ -97,7 +106,7 @@ export async function getModelForTenant(tenantId: string): Promise<{ model: Lang
.limit(1);
const s = tenant?.settings as Record | undefined;
- const provider: AIProvider = (['anthropic', 'openai', 'ollama'].includes(s?.aiProvider ?? '') ? s!.aiProvider : getProvider()) as AIProvider;
+ const provider: AIProvider = (['anthropic', 'openai', 'openrouter', 'ollama'].includes(s?.aiProvider ?? '') ? s!.aiProvider : getProvider()) as AIProvider;
let modelId: string;
if (provider === 'ollama') {
diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts
index c7c6b5d..ed22700 100644
--- a/src/lib/db/schema.ts
+++ b/src/lib/db/schema.ts
@@ -977,6 +977,7 @@ export const documents = pgTable(
export const apiKeyProviderEnum = pgEnum("api_key_provider", [
"anthropic",
"openai",
+ "openrouter",
"ollama",
]);