llmverify
Version:
AI Output Verification Toolkit — Local-first LLM safety, hallucination detection, PII redaction, prompt injection defense, and runtime monitoring. Zero telemetry. OWASP LLM Top 10 aligned.
109 lines • 10.2 kB
JavaScript
;
/**
* Local Adapter
*
* Adapter for local LLM inference (llama.cpp, vLLM, Ollama, etc.)
*
* @module adapters/providers/local
* @author Haiec
* @license MIT
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildLocalAdapter = buildLocalAdapter;
const types_1 = require("../types");
/**
* Builds a local adapter.
*
* @param config - Adapter configuration
* @returns LLM client for local inference
*
* @example
* // Simple function
* const llm = buildLocalAdapter({
* provider: 'local',
* client: async (prompt) => await myLocalModel(prompt)
* });
*
* @example
* // With Ollama
* import ollama from 'ollama';
* const llm = buildLocalAdapter({
* provider: 'local',
* client: async (prompt, opts) => {
* const response = await ollama.generate({
* model: opts?.model ?? 'llama3',
* prompt
* });
* return response.response;
* },
* defaultModel: 'llama3'
* });
*
* @example
* // With llama.cpp server
* const llm = buildLocalAdapter({
* provider: 'local',
* client: async (prompt) => {
* const res = await fetch('http://localhost:8080/completion', {
* method: 'POST',
* body: JSON.stringify({ prompt })
* });
* const data = await res.json();
* return data.content;
* }
* });
*/
function buildLocalAdapter(config) {
if (typeof config.client !== 'function') {
throw new types_1.AdapterConfigError('local', 'Local adapter requires client as a function: (prompt: string, options?) => Promise<string | { text, tokens }>');
}
const fn = config.client;
const defaultModel = config.defaultModel ?? 'local';
return {
provider: 'local',
providerName: config.providerName ?? 'Local Model',
async generate(request) {
// Build prompt with system instruction if provided
let prompt = request.prompt;
if (request.system) {
prompt = `${request.system}\n\n${request.prompt}`;
}
const result = await fn(prompt, {
model: request.model || defaultModel,
temperature: request.temperature,
maxTokens: request.maxTokens
});
// Handle both string and object responses
let text;
let tokens;
if (typeof result === 'string') {
text = result;
tokens = estimateTokens(text);
}
else {
text = result.text;
tokens = result.tokens ?? estimateTokens(text);
}
return {
text,
tokens,
model: request.model || defaultModel,
finishReason: 'stop',
raw: null
};
},
async healthCheck() {
try {
const result = await fn('test', { maxTokens: 1 });
return typeof result === 'string' ? result.length > 0 : result.text.length > 0;
}
catch {
return false;
}
}
};
}
function estimateTokens(text) {
return Math.ceil(text.split(/\s+/).length * 1.3);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYWRhcHRlcnMvcHJvdmlkZXJzL2xvY2FsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7R0FRRzs7QUF1REgsOENBMERDO0FBL0dELG9DQUFpRztBQVdqRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Q0c7QUFDSCxTQUFnQixpQkFBaUIsQ0FBQyxNQUFxQjtJQUNyRCxJQUFJLE9BQU8sTUFBTSxDQUFDLE1BQU0sS0FBSyxVQUFVLEVBQUUsQ0FBQztRQUN4QyxNQUFNLElBQUksMEJBQWtCLENBQzFCLE9BQU8sRUFDUCwrR0FBK0csQ0FDaEgsQ0FBQztJQUNKLENBQUM7SUFFRCxNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsTUFBMEIsQ0FBQztJQUM3QyxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsWUFBWSxJQUFJLE9BQU8sQ0FBQztJQUVwRCxPQUFPO1FBQ0wsUUFBUSxFQUFFLE9BQU87UUFDakIsWUFBWSxFQUFFLE1BQU0sQ0FBQyxZQUFZLElBQUksYUFBYTtRQUVsRCxLQUFLLENBQUMsUUFBUSxDQUFDLE9BQW1CO1lBQ2hDLG1EQUFtRDtZQUNuRCxJQUFJLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO1lBQzVCLElBQUksT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNuQixNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsTUFBTSxPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNwRCxDQUFDO1lBRUQsTUFBTSxNQUFNLEdBQUcsTUFBTSxFQUFFLENBQUMsTUFBTSxFQUFFO2dCQUM5QixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssSUFBSSxZQUFZO2dCQUNwQyxXQUFXLEVBQUUsT0FBTyxDQUFDLFdBQVc7Z0JBQ2hDLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUzthQUM3QixDQUFDLENBQUM7WUFFSCwwQ0FBMEM7WUFDMUMsSUFBSSxJQUFZLENBQUM7WUFDakIsSUFBSSxNQUFjLENBQUM7WUFFbkIsSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDL0IsSUFBSSxHQUFHLE1BQU0sQ0FBQztnQkFDZCxNQUFNLEdBQUcsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2hDLENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQztnQkFDbkIsTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2pELENBQUM7WUFFRCxPQUFPO2dCQUNMLElBQUk7Z0JBQ0osTUFBTTtnQkFDTixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssSUFBSSxZQUFZO2dCQUNwQyxZQUFZLEVBQUUsTUFBTTtnQkFDcEIsR0FBRyxFQUFFLElBQUk7YUFDVixDQUFDO1FBQ0osQ0FBQztRQUVELEtBQUssQ0FBQyxXQUFXO1lBQ2YsSUFBSSxDQUFDO2dCQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLFNBQVMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNsRCxPQUFPLE9BQU8sTUFBTSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztZQUNqRixDQUFDO1lBQUMsTUFBTSxDQUFDO2dCQUNQLE9BQU8sS0FBSyxDQUFDO1lBQ2YsQ0FBQztRQUNILENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsY0FBYyxDQUFDLElBQVk7SUFDbEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDO0FBQ25ELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIExvY2FsIEFkYXB0ZXJcbiAqIFxuICogQWRhcHRlciBmb3IgbG9jYWwgTExNIGluZmVyZW5jZSAobGxhbWEuY3BwLCB2TExNLCBPbGxhbWEsIGV0Yy4pXG4gKiBcbiAqIEBtb2R1bGUgYWRhcHRlcnMvcHJvdmlkZXJzL2xvY2FsXG4gKiBAYXV0aG9yIEhhaWVjXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG5pbXBvcnQgeyBMbG1DbGllbnQsIExsbVJlcXVlc3QsIExsbVJlc3BvbnNlLCBBZGFwdGVyQ29uZmlnLCBBZGFwdGVyQ29uZmlnRXJyb3IgfSBmcm9tICcuLi90eXBlcyc7XG5cbi8qKlxuICogTG9jYWwgaW5mZXJlbmNlIGZ1bmN0aW9uIHR5cGUuXG4gKi9cbnR5cGUgTG9jYWxJbmZlcmVuY2VGbiA9IChwcm9tcHQ6IHN0cmluZywgb3B0aW9ucz86IHtcbiAgbW9kZWw/OiBzdHJpbmc7XG4gIHRlbXBlcmF0dXJlPzogbnVtYmVyO1xuICBtYXhUb2tlbnM/OiBudW1iZXI7XG59KSA9PiBQcm9taXNlPHN0cmluZyB8IHsgdGV4dDogc3RyaW5nOyB0b2tlbnM/OiBudW1iZXIgfT47XG5cbi8qKlxuICogQnVpbGRzIGEgbG9jYWwgYWRhcHRlci5cbiAqIFxuICogQHBhcmFtIGNvbmZpZyAtIEFkYXB0ZXIgY29uZmlndXJhdGlvblxuICogQHJldHVybnMgTExNIGNsaWVudCBmb3IgbG9jYWwgaW5mZXJlbmNlXG4gKiBcbiAqIEBleGFtcGxlXG4gKiAvLyBTaW1wbGUgZnVuY3Rpb25cbiAqIGNvbnN0IGxsbSA9IGJ1aWxkTG9jYWxBZGFwdGVyKHtcbiAqICAgcHJvdmlkZXI6ICdsb2NhbCcsXG4gKiAgIGNsaWVudDogYXN5bmMgKHByb21wdCkgPT4gYXdhaXQgbXlMb2NhbE1vZGVsKHByb21wdClcbiAqIH0pO1xuICogXG4gKiBAZXhhbXBsZVxuICogLy8gV2l0aCBPbGxhbWFcbiAqIGltcG9ydCBvbGxhbWEgZnJvbSAnb2xsYW1hJztcbiAqIGNvbnN0IGxsbSA9IGJ1aWxkTG9jYWxBZGFwdGVyKHtcbiAqICAgcHJvdmlkZXI6ICdsb2NhbCcsXG4gKiAgIGNsaWVudDogYXN5bmMgKHByb21wdCwgb3B0cykgPT4ge1xuICogICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgb2xsYW1hLmdlbmVyYXRlKHtcbiAqICAgICAgIG1vZGVsOiBvcHRzPy5tb2RlbCA/PyAnbGxhbWEzJyxcbiAqICAgICAgIHByb21wdFxuICogICAgIH0pO1xuICogICAgIHJldHVybiByZXNwb25zZS5yZXNwb25zZTtcbiAqICAgfSxcbiAqICAgZGVmYXVsdE1vZGVsOiAnbGxhbWEzJ1xuICogfSk7XG4gKiBcbiAqIEBleGFtcGxlXG4gKiAvLyBXaXRoIGxsYW1hLmNwcCBzZXJ2ZXJcbiAqIGNvbnN0IGxsbSA9IGJ1aWxkTG9jYWxBZGFwdGVyKHtcbiAqICAgcHJvdmlkZXI6ICdsb2NhbCcsXG4gKiAgIGNsaWVudDogYXN5bmMgKHByb21wdCkgPT4ge1xuICogICAgIGNvbnN0IHJlcyA9IGF3YWl0IGZldGNoKCdodHRwOi8vbG9jYWxob3N0OjgwODAvY29tcGxldGlvbicsIHtcbiAqICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICogICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBwcm9tcHQgfSlcbiAqICAgICB9KTtcbiAqICAgICBjb25zdCBkYXRhID0gYXdhaXQgcmVzLmpzb24oKTtcbiAqICAgICByZXR1cm4gZGF0YS5jb250ZW50O1xuICogICB9XG4gKiB9KTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkTG9jYWxBZGFwdGVyKGNvbmZpZzogQWRhcHRlckNvbmZpZyk6IExsbUNsaWVudCB7XG4gIGlmICh0eXBlb2YgY29uZmlnLmNsaWVudCAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBBZGFwdGVyQ29uZmlnRXJyb3IoXG4gICAgICAnbG9jYWwnLFxuICAgICAgJ0xvY2FsIGFkYXB0ZXIgcmVxdWlyZXMgY2xpZW50IGFzIGEgZnVuY3Rpb246IChwcm9tcHQ6IHN0cmluZywgb3B0aW9ucz8pID0+IFByb21pc2U8c3RyaW5nIHwgeyB0ZXh0LCB0b2tlbnMgfT4nXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IGZuID0gY29uZmlnLmNsaWVudCBhcyBMb2NhbEluZmVyZW5jZUZuO1xuICBjb25zdCBkZWZhdWx0TW9kZWwgPSBjb25maWcuZGVmYXVsdE1vZGVsID8/ICdsb2NhbCc7XG5cbiAgcmV0dXJuIHtcbiAgICBwcm92aWRlcjogJ2xvY2FsJyxcbiAgICBwcm92aWRlck5hbWU6IGNvbmZpZy5wcm92aWRlck5hbWUgPz8gJ0xvY2FsIE1vZGVsJyxcblxuICAgIGFzeW5jIGdlbmVyYXRlKHJlcXVlc3Q6IExsbVJlcXVlc3QpOiBQcm9taXNlPExsbVJlc3BvbnNlPiB7XG4gICAgICAvLyBCdWlsZCBwcm9tcHQgd2l0aCBzeXN0ZW0gaW5zdHJ1Y3Rpb24gaWYgcHJvdmlkZWRcbiAgICAgIGxldCBwcm9tcHQgPSByZXF1ZXN0LnByb21wdDtcbiAgICAgIGlmIChyZXF1ZXN0LnN5c3RlbSkge1xuICAgICAgICBwcm9tcHQgPSBgJHtyZXF1ZXN0LnN5c3RlbX1cXG5cXG4ke3JlcXVlc3QucHJvbXB0fWA7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZuKHByb21wdCwge1xuICAgICAgICBtb2RlbDogcmVxdWVzdC5tb2RlbCB8fCBkZWZhdWx0TW9kZWwsXG4gICAgICAgIHRlbXBlcmF0dXJlOiByZXF1ZXN0LnRlbXBlcmF0dXJlLFxuICAgICAgICBtYXhUb2tlbnM6IHJlcXVlc3QubWF4VG9rZW5zXG4gICAgICB9KTtcblxuICAgICAgLy8gSGFuZGxlIGJvdGggc3RyaW5nIGFuZCBvYmplY3QgcmVzcG9uc2VzXG4gICAgICBsZXQgdGV4dDogc3RyaW5nO1xuICAgICAgbGV0IHRva2VuczogbnVtYmVyO1xuXG4gICAgICBpZiAodHlwZW9mIHJlc3VsdCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgdGV4dCA9IHJlc3VsdDtcbiAgICAgICAgdG9rZW5zID0gZXN0aW1hdGVUb2tlbnModGV4dCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0ZXh0ID0gcmVzdWx0LnRleHQ7XG4gICAgICAgIHRva2VucyA9IHJlc3VsdC50b2tlbnMgPz8gZXN0aW1hdGVUb2tlbnModGV4dCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRleHQsXG4gICAgICAgIHRva2VucyxcbiAgICAgICAgbW9kZWw6IHJlcXVlc3QubW9kZWwgfHwgZGVmYXVsdE1vZGVsLFxuICAgICAgICBmaW5pc2hSZWFzb246ICdzdG9wJyxcbiAgICAgICAgcmF3OiBudWxsXG4gICAgICB9O1xuICAgIH0sXG5cbiAgICBhc3luYyBoZWFsdGhDaGVjaygpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZuKCd0ZXN0JywgeyBtYXhUb2tlbnM6IDEgfSk7XG4gICAgICAgIHJldHVybiB0eXBlb2YgcmVzdWx0ID09PSAnc3RyaW5nJyA/IHJlc3VsdC5sZW5ndGggPiAwIDogcmVzdWx0LnRleHQubGVuZ3RoID4gMDtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICB9O1xufVxuXG5mdW5jdGlvbiBlc3RpbWF0ZVRva2Vucyh0ZXh0OiBzdHJpbmcpOiBudW1iZXIge1xuICByZXR1cm4gTWF0aC5jZWlsKHRleHQuc3BsaXQoL1xccysvKS5sZW5ndGggKiAxLjMpO1xufVxuIl19