Docs/Skills and code/src/

src/llm-client.js

Code46 lines2.3 KBsrc/

What the file says about itself

OpenAI-compatible adapter for local Ollama or another compatible endpoint.

/* OpenAI-compatible adapter for local Ollama or another compatible endpoint. */
import { config as appConfig } from "../config.js";

export function getLLMConfig() {
  return {
    baseUrl: process.env.LLM_BASE_URL ?? appConfig.qualification?.llm?.baseUrl ?? "http://localhost:11434/v1",
    model: process.env.LLM_MODEL ?? appConfig.qualification?.llm?.model ?? "gemma4",
    apiKey: process.env.LLM_API_KEY ?? appConfig.qualification?.llm?.apiKey ?? "local"
  };
}

export async function callLLM({ system, user, temperature = 0.1, maxTokens = 1200 }) {
  const settings = getLLMConfig();
  if (!settings.model) throw new Error("LLM model is not configured. Set LLM_MODEL or config.qualification.llm.model.");
  const url = `${settings.baseUrl.replace(/\/$/, "")}/chat/completions`;
  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json", Authorization: `Bearer ${settings.apiKey}` },
    body: JSON.stringify({ model: settings.model, temperature, max_tokens: maxTokens,
      messages: [{ role: "system", content: system }, { role: "user", content: user }] })
  });
  const body = await response.text();
  if (!response.ok) throw new Error(`LLM request failed (${response.status}): ${body.slice(0, 1200)}`);
  let parsed;
  try { parsed = JSON.parse(body); }
  catch { throw new Error(`LLM returned invalid transport JSON: ${body.slice(0, 1000)}`); }
  const content = parsed?.choices?.[0]?.message?.content;
  if (!content) throw new Error("LLM response contained no message content.");
  return { content, model: parsed.model ?? settings.model };
}

export function parseJsonObject(content) {
  const text = String(content ?? "").trim();
  try { return JSON.parse(text); } catch {}
  const fenced = text.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
  if (fenced) { try { return JSON.parse(fenced[1]); } catch {} }
  const startObject = text.indexOf("{");
  const endObject = text.lastIndexOf("}");
  const startArray = text.indexOf("[");
  const endArray = text.lastIndexOf("]");
  const start = startArray >= 0 && (startObject < 0 || startArray < startObject) ? startArray : startObject;
  const end = start === startArray ? endArray : endObject;
  if (start >= 0 && end > start) { try { return JSON.parse(text.slice(start, end + 1)); } catch {} }
  throw new Error("Could not parse structured JSON from LLM response.");
}

Shown as it is in the repository at build time (2026-11-03); the home directory appears as <home>. If this page and the file differ, the file is right. Back to the catalogue.