Beacon / src /llm.js
Ig0tU
beacon v1 — authenticated web proxy + AGENTS.md
770ac3d
Raw
History Blame Contribute Delete
2.39 kB
// LLM client — Ollama (default), Anthropic, or any OpenAI-compatible endpoint
// Configure via env:
// LLM_PROVIDER=ollama|anthropic|openai (default: ollama)
// LLM_BASE_URL=http://localhost:11434 (default for ollama)
// LLM_MODEL=llama3 (default)
// LLM_API_KEY=... (required for anthropic/openai)
const PROVIDER = process.env.LLM_PROVIDER || 'ollama'
const MODEL = process.env.LLM_MODEL || 'llama3'
const API_KEY = process.env.LLM_API_KEY
const BASE_URL = process.env.LLM_BASE_URL || 'http://localhost:11434'
export async function chat(messages) {
if (PROVIDER === 'anthropic') return anthropic(messages)
if (PROVIDER === 'openai') return openaiCompat(messages, BASE_URL || 'https://api.openai.com/v1')
return ollama(messages)
}
async function ollama(messages) {
const r = await fetch(`${BASE_URL}/api/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model: MODEL, messages, stream: false }),
})
if (!r.ok) throw new Error(`Ollama ${r.status}: ${await r.text()}`)
const data = await r.json()
return data.message.content
}
async function anthropic(messages) {
// Separate system message — Anthropic requires it at top level
const system = messages.find(m => m.role === 'system')?.content
const rest = messages.filter(m => m.role !== 'system')
const r = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': API_KEY,
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: MODEL || 'claude-sonnet-4-6',
max_tokens: 2048,
...(system && { system }),
messages: rest,
}),
})
if (!r.ok) throw new Error(`Anthropic ${r.status}: ${await r.text()}`)
const data = await r.json()
return data.content[0].text
}
async function openaiCompat(messages, base) {
const r = await fetch(`${base}/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(API_KEY && { Authorization: `Bearer ${API_KEY}` }),
},
body: JSON.stringify({ model: MODEL, messages, stream: false }),
})
if (!r.ok) throw new Error(`LLM ${r.status}: ${await r.text()}`)
const data = await r.json()
return data.choices[0].message.content
}