| 1 | import type { DelegateParams, DelegateResult } from './types'; |
| 2 | |
| 3 | const BASE = process.env.ZPM_OLLAMA_URL || 'http://REDACTED-IP:11434'; |
| 4 | const DEFAULT_MODEL = process.env.ZPM_OLLAMA_DEFAULT || 'mistral-nemo:12b'; |
| 5 | |
| 6 | export async function ollamaAdapter(p: DelegateParams): Promise<DelegateResult> { |
| 7 | const start = Date.now(); |
| 8 | const model = p.ollamaModel || DEFAULT_MODEL; |
| 9 | const messages: Array<{ role: string; content: string }> = []; |
| 10 | const sys = p.context ? `You are a helpful worker. Relevant context:\n${p.context}` : 'You are a helpful worker.'; |
| 11 | messages.push({ role: 'system', content: sys }); |
| 12 | messages.push({ role: 'user', content: p.task }); |
| 13 | const ctrl = new AbortController(); |
| 14 | const timer = setTimeout(() => ctrl.abort(), p.timeoutMs ?? 120_000); |
| 15 | try { |
| 16 | const res = await fetch(`${BASE}/api/chat`, { |
| 17 | method: 'POST', |
| 18 | headers: { 'content-type': 'application/json' }, |
| 19 | body: JSON.stringify({ model, messages, stream: false, options: { think: false } }), |
| 20 | signal: ctrl.signal, |
| 21 | }); |
| 22 | if (!res.ok) { |
| 23 | const t = await res.text(); |
| 24 | return { ok: false, output: '', artifacts: [], error: `ollama ${res.status}: ${t.slice(0, 300)}`, durationMs: Date.now() - start }; |
| 25 | } |
| 26 | const j = (await res.json()) as { message?: { content?: string } }; |
| 27 | const out = j.message?.content?.trim() ?? ''; |
| 28 | return { ok: out.length > 0, output: out, artifacts: [], error: out ? undefined : 'empty response', durationMs: Date.now() - start }; |
| 29 | } catch (e) { |
| 30 | return { ok: false, output: '', artifacts: [], error: (e as Error).message, durationMs: Date.now() - start }; |
| 31 | } finally { |
| 32 | clearTimeout(timer); |
| 33 | } |
| 34 | } |