npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

llm-adapter-client

v0.1.0

Published

TypeScript client library for llm-adapter HTTP API

Readme

LLM Adapter Client for TypeScript

TypeScript клиентская библиотека для взаимодействия с LLM Adapter HTTP API.

Назначение

llm-adapter-client — это типобезопасный клиент для взаимодействия с сервисом llm-adapter, предоставляющий удобный программный интерфейс для отправки запросов к LLM (Large Language Models) через HTTP API.

Основные возможности:

  • ✅ Полная типизация TypeScript
  • ✅ Поддержка всех эндпоинтов llm-adapter API
  • ✅ Единообразная обработка ошибок
  • ✅ Конфигурируемые значения по умолчанию
  • ✅ Подмена HTTP-транспорта (fetch по умолчанию)
  • ✅ Работа в браузере и Node.js (18+)
  • ✅ Минимум зависимостей

Установка

npm install llm-adapter-client

или с yarn:

yarn add llm-adapter-client

Быстрый старт

import { createClient } from 'llm-adapter-client';

// Создание клиента
const client = createClient({
  baseUrl: 'http://localhost:8080/api/v1',
  defaults: {
    model: 'gemini-2.5-flash',
    temperature: 0.7,
    max_tokens: 2048,
  },
});

// Отправка запроса
const response = await client.query({
  prompt: 'Напиши короткое стихотворение про TypeScript',
  model: 'gemini-2.5-flash',
});

console.log(response.text);

Конфигурация

ClientConfig

Параметры конфигурации клиента:

interface ClientConfig {
  /** Базовый URL для llm-adapter (включая /api/v1) */
  baseUrl: string;
  
  /** Значения по умолчанию для LLM параметров */
  defaults?: {
    model?: string;
    temperature?: number;
    max_tokens?: number;
  };
  
  /** Общие HTTP-заголовки для всех запросов */
  headers?: Record<string, string>;
  
  /** Таймаут запросов в миллисекундах */
  timeout?: number;
  
  /** Кастомная реализация HTTP-транспорта */
  transport?: HttpTransport;
}

Примеры конфигурации

Минимальная конфигурация:

const client = createClient({
  baseUrl: 'http://localhost:8080/api/v1',
});

Полная конфигурация:

const client = createClient({
  baseUrl: 'http://localhost:8080/api/v1',
  defaults: {
    model: 'gemini-2.5-flash',
    temperature: 0.7,
    max_tokens: 2048,
  },
  headers: {
    'X-API-Key': process.env.API_KEY,
    'X-Request-ID': generateRequestId(),
  },
  timeout: 30000, // 30 секунд
});

API методы

chat()

Отправить сообщение в чат с историей диалога.

const response = await client.chat({
  message: 'Как дела?',
  history: [
    { role: 'user', content: 'Привет!' },
    { role: 'assistant', content: 'Здравствуй! Чем могу помочь?' },
  ],
  systemInstruction: 'Ты полезный ассистент',
});

console.log(response.text);

prompt()

Использовать зарегистрированный промпт с подстановкой параметров.

const response = await client.prompt({
  name: 'task_classification',
  parameters: {
    text: 'Пользователь хочет узнать погоду',
  },
  model: 'gemini-2.5-flash', // опционально
  temperature: 0.3, // опционально
});

console.log(response.text);

promptStructured()

Использовать промпт со структурированным выводом (JSON Schema).

С явной схемой в запросе:

const response = await client.promptStructured({
  name: 'extract_entities',
  parameters: {
    text: 'Асыл купил iPhone 15 в Алматы',
  },
  structured_output: {
    schema: {
      type: 'object',
      properties: {
        person: { type: 'string' },
        product: { type: 'string' },
        location: { type: 'string' },
      },
      required: ['person', 'product', 'location'],
    },
  },
});

console.log(response.json);
// { person: 'Асыл', product: 'iPhone 15', location: 'Алматы' }

Со схемой из YAML frontmatter промпта (structured_output опционален):

Если промпт содержит structured_output в YAML frontmatter, параметр structured_output в запросе можно не передавать:

// Промпт classify_task.md содержит structured_output в frontmatter
const response = await client.promptStructured({
  name: 'classify_task',
  parameters: {
    user_message: 'Привет!',
    dialog_history: '',
  },
  // structured_output не передаётся — используется из промпта
});

console.log(response.json);
// { task_type: 'CHIT_CHAT', goal: 'Приветствие', reasoning: '...' }

query()

Прямой запрос к LLM с текстовым промптом.

const response = await client.query({
  prompt: 'Объясни что такое замыкания в JavaScript',
  model: 'gemini-2.5-flash',
  temperature: 0.7,
  max_tokens: 1024,
});

console.log(response.text);

queryStructured()

Прямой запрос к LLM со структурированным выводом.

const response = await client.queryStructured({
  prompt: 'Извлеки из текста имя, возраст и город: "Меня зовут Мариана, мне 25 лет, живу в Алматы"',
  model: 'gemini-2.5-flash',
  structured_output: {
    schema: {
      type: 'object',
      properties: {
        name: { type: 'string' },
        age: { type: 'number' },
        city: { type: 'string' },
      },
      required: ['name', 'age', 'city'],
    },
  },
});

console.log(response.json);
// { name: 'Мариана', age: 25, city: 'Алматы' }

getPrompts()

Получить список доступных промптов.

const response = await client.getPrompts();

response.prompts?.forEach((prompt) => {
  console.log(`${prompt.name}: [${prompt.parameters?.join(', ')}]`);
});

Обработка ошибок

Клиент использует систему типизированных исключений для обработки ошибок.

Типы ошибок

  • NetworkError — сетевые ошибки (нет соединения, таймаут)
  • ValidationError — ошибки валидации (HTTP 400)
  • NotFoundError — ресурс не найден (HTTP 404, промпт не существует)
  • LLMError — бизнес-ошибки LLM (когда response.error заполнен)
  • ServerError — ошибки сервера (HTTP 5xx)
  • LLMAdapterError — базовый класс для всех ошибок

Пример обработки

import {
  ValidationError,
  NotFoundError,
  NetworkError,
  LLMError,
} from 'llm-adapter-client';

try {
  const response = await client.prompt({
    name: 'my_prompt',
    parameters: { text: 'Hello' },
  });
  console.log(response.text);
} catch (error) {
  if (error instanceof NotFoundError) {
    console.error('Промпт не найден:', error.message);
  } else if (error instanceof ValidationError) {
    console.error('Ошибка валидации:', error.message);
  } else if (error instanceof NetworkError) {
    console.error('Сетевая ошибка:', error.message);
  } else if (error instanceof LLMError) {
    console.error('Ошибка LLM:', error.message);
  } else {
    console.error('Неизвестная ошибка:', error);
  }
}

Доступ к деталям ошибки

Все ошибки содержат дополнительную информацию:

try {
  await client.query({ prompt: 'test', model: 'unknown' });
} catch (error) {
  if (error instanceof LLMAdapterError) {
    console.log('HTTP статус:', error.status);
    console.log('Оригинальный ответ:', error.originalResponse);
    console.log('Сообщение:', error.message);
  }
}

Кастомный HTTP-транспорт

Вы можете подменить реализацию HTTP-клиента, передав свой транспорт:

import { HttpTransport, HttpTransportOptions, HttpTransportResponse } from 'llm-adapter-client';
import axios from 'axios';

class AxiosTransport implements HttpTransport {
  constructor(private baseUrl: string) {}

  async request<T>(options: HttpTransportOptions): Promise<HttpTransportResponse<T>> {
    const response = await axios({
      method: options.method,
      url: `${this.baseUrl}${options.path}`,
      headers: options.headers,
      data: options.body,
      timeout: options.timeout,
    });

    return {
      status: response.status,
      data: response.data as T,
      headers: response.headers as Record<string, string>,
    };
  }
}

const client = createClient({
  baseUrl: 'http://localhost:8080/api/v1',
  transport: new AxiosTransport('http://localhost:8080/api/v1'),
});

Использование defaults

Параметры model, temperature и max_tokens можно задать на уровне клиента и переопределить при вызове:

const client = createClient({
  baseUrl: 'http://localhost:8080/api/v1',
  defaults: {
    model: 'gemini-2.5-flash',
    temperature: 0.7,
    max_tokens: 2048,
  },
});

// Использует defaults
await client.query({ prompt: 'Hello' });

// Переопределяет температуру
await client.query({
  prompt: 'Hello',
  temperature: 1.0, // переопределено
});

// Переопределяет модель и max_tokens
await client.prompt({
  name: 'my_prompt',
  model: 'gemini-1.5-pro', // переопределено
  max_tokens: 4096, // переопределено
});

Примеры использования

Чат-бот с историей

const history: ChatMessage[] = [];

async function sendMessage(userMessage: string) {
  const response = await client.chat({
    message: userMessage,
    history,
    systemInstruction: 'Ты дружелюбный помощник',
  });

  // Обновляем историю
  history.push({ role: 'user', content: userMessage });
  history.push({ role: 'assistant', content: response.text || '' });

  return response.text;
}

await sendMessage('Привет!');
await sendMessage('Как дела?');

Классификация задач

async function classifyTask(userText: string) {
  const response = await client.promptStructured({
    name: 'task_classification',
    parameters: { text: userText },
    structured_output: {
      schema: {
        type: 'object',
        properties: {
          category: {
            type: 'string',
            enum: ['QUESTION', 'COMMAND', 'CHIT_CHAT', 'OTHER'],
          },
          confidence: { type: 'number' },
        },
        required: ['category', 'confidence'],
      },
    },
  });

  return response.json as { category: string; confidence: number };
}

const result = await classifyTask('Какая сегодня погода в Алматы?');
console.log(result); // { category: 'QUESTION', confidence: 0.95 }

Извлечение структурированных данных

async function extractContactInfo(text: string) {
  const response = await client.queryStructured({
    prompt: `Извлеки контактную информацию из текста: "${text}"`,
    model: 'gemini-2.5-flash',
    structured_output: {
      schema: {
        type: 'object',
        properties: {
          name: { type: 'string' },
          email: { type: 'string' },
          phone: { type: 'string' },
        },
      },
    },
  });

  return response.json;
}

const contacts = await extractContactInfo(
  'Свяжитесь с Асылом Шабаевым: [email protected], +7 777 123-45-67'
);

// Другой пример с извлечением данных
const personInfo = await client.queryStructured({
  prompt: 'Извлеки информацию о человеке: "Алексей Другой работает в Талдыкоргане, ему 40 лет"',
  model: 'gemini-2.5-flash',
  structured_output: {
    schema: {
      type: 'object',
      properties: {
        name: { type: 'string' },
        surname: { type: 'string' },
        age: { type: 'number' },
        city: { type: 'string' },
      },
      required: ['name', 'surname', 'age', 'city'],
    },
  },
});

console.log(personInfo.json);
// { name: 'Алексей', surname: 'Другой', age: 30, city: 'Талдыкорган' }

Swagger документация

Полная спецификация API доступна в Swagger документации проекта LLM Adapter.

Требования

  • Node.js >= 18.0.0 (для нативного fetch)
  • TypeScript >= 5.0 (опционально, для разработки)

Лицензия

MIT