@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
70 lines (69 loc) • 3.14 kB
JavaScript
import { ProviderError } from "../types/index.js";
import { classifyProviderError, DEFAULT_ERROR_RULES, } from "../utils/errorClassifier.js";
import { logger } from "../utils/logger.js";
import { redactUrlCredentials } from "../utils/logSanitize.js";
import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
import { buildLocalUnreachableErrorRule } from "./localRuntimeOpenAICompat.js";
const LLAMACPP_DEFAULT_BASE_URL = "http://localhost:8080/v1";
const LLAMACPP_PLACEHOLDER_KEY = "llamacpp";
const getLlamaCppBaseURL = () => {
return process.env.LLAMACPP_BASE_URL || LLAMACPP_DEFAULT_BASE_URL;
};
/**
* llama.cpp Provider — direct HTTP, no AI SDK.
*
* Wraps a llama-server process (https://github.com/ggerganov/llama.cpp) that
* exposes an OpenAI-compatible API at http://localhost:8080/v1 by default.
* llama-server hosts ONE model loaded at startup; /v1/models returns just that.
* All request/stream/tool-loop orchestration lives in
* `OpenAIChatCompletionsProvider`; this class only declares configuration
* and provider-specific error mapping.
*
* @see https://github.com/ggerganov/llama.cpp
*/
export class LlamaCppProvider extends OpenAIChatCompletionsProvider {
constructor(modelName, sdk, _region, credentials) {
const baseURL = credentials?.baseURL?.trim() || getLlamaCppBaseURL();
// llama-server doesn't authenticate, but the base class requires an
// apiKey. Allow override via credentials/env for users who run
// llama-server behind an auth-proxying reverse-proxy.
const apiKey = credentials?.apiKey?.trim() ||
process.env.LLAMACPP_API_KEY ||
LLAMACPP_PLACEHOLDER_KEY;
super("llamacpp", modelName, sdk, { baseURL, apiKey });
logger.debug("llama.cpp Provider initialized", {
modelName: this.modelName,
providerName: this.providerName,
baseURL: redactUrlCredentials(this.config.baseURL),
});
}
async validateConfiguration() {
return this.probeModelsEndpoint(this.getAuthHeaders());
}
getProviderName() {
return "llamacpp";
}
getDefaultModel() {
return process.env.LLAMACPP_MODEL || "";
}
getFallbackModelName() {
return "loaded-model";
}
getFallbackModels() {
return ["loaded-model"];
}
formatProviderError(error) {
const rules = [
buildLocalUnreachableErrorRule(error, () => `llama.cpp server not reachable at ${redactUrlCredentials(this.config.baseURL)}. ` +
"Start it with: ./llama-server -m model.gguf --port 8080"),
{
match: (ctx) => ctx.statusCode === 400 ||
(ctx.statusCode === undefined && /\b400\b/.test(ctx.message)),
errorClass: ProviderError,
message: "llama.cpp rejected the request. Common cause: model doesn't support tools (start llama-server with --jinja for tool support).",
},
...DEFAULT_ERROR_RULES,
];
return classifyProviderError(error, rules, this.providerName, this.modelName);
}
}