From a2dabd527f0e7b3c0c788533d2b10f0f05a54fc0 Mon Sep 17 00:00:00 2001 From: Christopher Mayor Date: Mon, 27 Apr 2026 13:42:00 -0700 Subject: [PATCH] feat: support OpenRouter/custom LLM providers via env vars Add LLM_API_KEY, LLM_BASE_URL, LLM_MODEL env vars so any OpenAI-compatible API (OpenRouter, etc.) can be used as the LLM backend without code changes. --- src/lib/llm/providers/index.ts | 2 +- src/lib/llm/providers/openai.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/lib/llm/providers/index.ts b/src/lib/llm/providers/index.ts index 0d46526..1fcc946 100644 --- a/src/lib/llm/providers/index.ts +++ b/src/lib/llm/providers/index.ts @@ -13,9 +13,9 @@ export interface Provider { } export function getActiveProvider(): Provider { + const hasOpenAI = !!process.env.OPENAI_API_KEY || !!process.env.LLM_API_KEY; const hasTavily = !!process.env.TAVILY_API_KEY; const hasPerplexity = !!process.env.PERPLEXITY_API_KEY; - const hasOpenAI = !!process.env.OPENAI_API_KEY; if (hasTavily && hasPerplexity) { console.log("[llm] Using provider: Tavily search + Perplexity synthesis"); diff --git a/src/lib/llm/providers/openai.ts b/src/lib/llm/providers/openai.ts index 05256d8..2e6a989 100644 --- a/src/lib/llm/providers/openai.ts +++ b/src/lib/llm/providers/openai.ts @@ -8,10 +8,16 @@ import type { import type { SearchResult } from "./tavily"; let _client: OpenAI | null = null; +const MODEL = process.env.LLM_MODEL || "gpt-4o-mini"; function getClient(): OpenAI { if (!_client) { - _client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); + const baseURL = process.env.LLM_BASE_URL || undefined; + const apiKey = process.env.OPENAI_API_KEY || process.env.LLM_API_KEY; + if (!apiKey) { + throw new Error("No API key configured. Set OPENAI_API_KEY or LLM_API_KEY."); + } + _client = new OpenAI({ apiKey, baseURL }); } return _client; } @@ -112,7 +118,7 @@ Provide a comprehensive comparison with scores, pros/cons, and a recommendation. for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) { try { const response = await getClient().chat.completions.create({ - model: "gpt-4o-mini", + model: MODEL, messages: [ { role: "system", content: SYSTEM_PROMPT }, { role: "user", content: userPrompt }, @@ -179,7 +185,7 @@ Use the web research data above to provide factual, data-driven insights. Refere for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) { try { const response = await getClient().chat.completions.create({ - model: "gpt-4o-mini", + model: MODEL, messages: [ { role: "system", content: SYSTEM_PROMPT }, {