// Shared local-LLM client — Ollama on shadow-death (.128). // Single source of truth for host/model across the whole app. export const OLLAMA_HOST = process.env.OLLAMA_HOST || 'http://10.30.20.128:11434'; export const OLLAMA_MODEL = process.env.OLLAMA_MODEL || 'qwen3.8:latest'; export interface LocalModelOptions { formatJson?: boolean; numPredict?: number; temperature?: number; } export async function callLocalModel(prompt: string, opts: LocalModelOptions = {}): Promise { const body: Record = { model: OLLAMA_MODEL, messages: [{ role: 'user', content: prompt }], stream: false, keep_alive: '30m', options: { num_predict: opts.numPredict ?? 4096, temperature: opts.temperature ?? 0.2, think: false, num_ctx: 8192, }, }; if (opts.formatJson) body.format = 'json'; const res = await fetch(`${OLLAMA_HOST}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), signal: AbortSignal.timeout(180000), }); if (!res.ok) { throw new Error(`Ollama HTTP ${res.status} (${res.statusText})`); } const data = await res.json(); let content = data?.message?.content || ''; if (!content) content = data?.message?.thinking || ''; return (content || '').trim(); }