diff --git a/src/lib/llm/router.test.ts b/src/lib/llm/router.test.ts index 91904a9f..c6faaf4a 100644 --- a/src/lib/llm/router.test.ts +++ b/src/lib/llm/router.test.ts @@ -6,7 +6,10 @@ beforeEach(() => { vi.useFakeTimers(); vi.setSystemTime(new Date('2026-05-12T00:00:00Z')); }); -afterEach(() => vi.useRealTimers()); +afterEach(() => { + __setLlmProvider(null); + vi.useRealTimers(); +}); const schema = z.object({ ok: z.boolean(), answer: z.string() }); @@ -69,4 +72,11 @@ describe('llmCall', () => { expect(r.ok).toBe(true); if (r.ok) expect(r.data.answer).toBe('yo'); }); + + it('falls back to default provider or returns unavailable when override is cleared', async () => { + __setLlmProvider(null); + const r = await llmCall({ prompt: 'noop', schema }); + expect(r.ok).toBe(false); + if (!r.ok) expect(r.error.code).toBe('llm_unavailable'); + }); }); diff --git a/src/lib/llm/router.ts b/src/lib/llm/router.ts index 33cbcaf6..ab6137be 100644 --- a/src/lib/llm/router.ts +++ b/src/lib/llm/router.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import Groq from 'groq-sdk'; import type { Result } from '../result'; import { ok, err } from '../result'; @@ -25,6 +26,24 @@ type LlmCallArgs = { schema: z.ZodType; }; +const groqApiKey = process.env.GROQ_API_KEY; + +const groqProvider: LlmProvider = { + name: 'groq', + complete: async (prompt: string) => { + if (!groqApiKey) { + throw new Error('GROQ_API_KEY is not set'); + } + const groq = new Groq({ apiKey: groqApiKey }); + const completion = await groq.chat.completions.create({ + messages: [{ role: 'user', content: prompt }], + model: 'llama3-8b-8192', + }); + return completion.choices[0]?.message?.content ?? ''; + }, + isHealthy: () => !!groqApiKey, +}; + let providerOverride: LlmProvider | null = null; export function __setLlmProvider(p: LlmProvider | null): void { @@ -32,7 +51,7 @@ export function __setLlmProvider(p: LlmProvider | null): void { } function pickProvider(): LlmProvider | null { - return providerOverride; + return providerOverride || (groqApiKey ? groqProvider : null); } function extractJson(raw: string): string {