OpenAI-совместимый прокси перед Polza.ai. Принимает стандартные запросы от IDE/CLI (которые не умеют задавать кастомные параметры), дописывает в них Polza-специфичные поля — provider selection — и прозрачно форвардит на https://polza.ai/api/v1.
- Быстрый старт
- Использование в IDE/CLI
- Проксируемые эндпоинты
- Конфигурация
- Инъекции
- Переменные окружения
- Логи и безопасность
- Запуск и диагностика
- Структура проекта
npm install
cp config.example.json config.json
# отредактируй config.json — как минимум polzaApiKey, если не хочешь передавать ключ от клиента
npm startЕсли config.json нет — npm start запустит интерактивный мастер настройки и создаст его в текущей директории.
По умолчанию прокси слушает http://127.0.0.1:8787. При старте печатает зелёный ASCII-баннер с версией, адресом и апстримом.
- Node.js ≥ 20 (см.
engines.nodeвpackage.json) - Один npm-пакет:
fastify(больше ничего не тянется)
В настройках клиента укажи:
- Base URL:
http://127.0.0.1:8787/v1(илиhttp://127.0.0.1:8787— прокси нормализует префикс/v1сам) - API key: твой Polza-ключ, либо любой placeholder если
polzaApiKeyзадан вconfig.json
Если клиент прислал свой Authorization — он передаётся на апстрим без изменений. polzaApiKey из конфига подставляется только когда клиентского ключа нет.
Прокси форвардит любой путь /* и /v1/*. JSON-тела парсятся, на выбранных путях в них докидываются поля из inject; всё остальное (multipart, бинарные аплоады) форвардится как есть.
| Путь | Метод | Тип тела | Инъекция |
|---|---|---|---|
/v1/chat/completions |
POST | JSON | ✅ да |
/v1/completions |
POST | JSON | ✅ да |
/v1/responses |
POST | JSON | ✅ да |
/v1/media |
POST | multipart/form-data | — (форвард as-is) |
/v1/audio/transcriptions |
POST | multipart/form-data | — (форвард as-is) |
/v1/audio/speech |
POST | JSON → аудио-ответ | — |
/v1/embeddings |
POST | JSON | — |
/v1/models и прочее |
любой | — | — |
Список путей для инъекции вшит в src/config.js (INJECT_PATHS) и не настраивается через конфиг. Инъекция применяется только к JSON-телам — multipart-запросы проходят через прокси нетронутыми.
Также прокси добавляет собственный GET /health → {"ok": true}.
config.json ищется в следующем порядке:
- Путь из переменной окружения
POLZA_PROXY_CONFIG. ./config.jsonв текущей рабочей директории (cwd).
Если файл не найден и stdin — TTY, запускается мастер настройки и создаёт файл в cwd. Без TTY процесс завершается с понятной ошибкой.
{
"port": 8787,
"host": "127.0.0.1",
"polzaApiKey": "",
"inject": {
"provider": {
"order": ["OpenAI", "Anthropic"],
"allow_fallbacks": true
}
}
}| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
port |
integer 1–65535 |
8787 |
Порт локального прокси. При занятом — процесс падает с понятной ошибкой. |
host |
string | "127.0.0.1" |
Интерфейс. Поставь "0.0.0.0" чтобы слушать все. |
polzaApiKey |
string | "" |
Fallback API-ключ. Используется, если клиент не прислал Authorization. |
inject |
object | {} |
Поля, дописываемые в JSON-тело на INJECT_PATHS. Клиентское значение никогда не перетирается. Подробнее → Инъекции. |
Захардкожено в src/config.js и не меняется через конфиг: UPSTREAM_BASE_URL и INJECT_PATHS. Чтобы поменять — правь исходник.
Инъекция срабатывает только для POST на эндпоинты из INJECT_PATHS (/chat/completions, /completions, /responses). На остальное (audio, embeddings, media, models) тело не трогается.
Главный принцип: если клиент уже задал поле — оно не перетирается. Прокси только дописывает недостающее.
{
"inject": {
"provider": {
"order": ["OpenAI", "Anthropic"],
"allow_fallbacks": true
}
}
}Варианты: order, only, allow_fallbacks, и т. д. — как в доке Polza.
| Переменная | Назначение |
|---|---|
POLZA_PROXY_CONFIG |
Путь к config.json. Переопределяет поиск в cwd. |
POLZA_API_KEY |
Fallback-ключ, если в config.json пустой polzaApiKey. Приоритет: файл → env → пусто. |
LOG_LEVEL |
Уровень pino-логгера (trace/debug/info/warn/error). По умолчанию info. |
DEBUG_BODIES |
1/true/yes — логировать исходящие тела запросов и голову ответа/стрима. Полезно для отладки инъекций. |
NO_COLOR |
Любое значение — отключает цвета в баннере и предупреждениях. |
COLORTERM |
truecolor / 24bit → баннер использует 24-битный зелёный #39FF14; иначе — 256-цветный bright green (ANSI 82). |
- Заголовки
Authorization,X-API-Key,Cookieв pino-логах заменяются на[redacted]. Ключ в stdout не светится. - Тела запросов/ответов Fastify по умолчанию не логирует. Включи
DEBUG_BODIES=1только на время отладки. - Hop-by-hop заголовки (
connection,keep-alive,transfer-encoding,content-length,accept-encodingи прочие) не прокидываются ни в запрос к апстриму, ни в ответ клиенту. - SSE (
text/event-stream,stream: true) форвардится как есть — прокси не буферизует стрим. bodyLimit: 50 MiB. Тела сContent-Type, отличным отapplication/json(например,multipart/form-dataдля/v1/audio/transcriptionsи/v1/media), форвардятся как бинарный буфер без попытки парсинга.
При успешном старте — зелёный ASCII-баннер + строка:
version: <X.Y.Z> | listening on http://<host>:<port> | upstream: https://polza.ai/api/v1
Версия читается из package.json.
⚠ No API key configured(жёлтый warning) — ни вconfig.polzaApiKey, ни вPOLZA_API_KEYнет ключа. Прокси запустится, но запросы без клиентскогоAuthorizationполучат 401 от апстрима.Port <N> is already in use— понятная ошибка с путём доconfig.jsonвместо стектрейса.Invalid port ...— некорректное значениеportв конфиге (не integer или вне1..65535).Config file not found ... stdin is not a TTY— конфига нет и wizard не может быть запущен (например, в CI). Создайconfig.jsonили задайPOLZA_PROXY_CONFIG.
curl http://127.0.0.1:8787/health
# {"ok":true}- Принимает запрос на любом пути (
/*и/v1/*). - Нормализует путь: срезает префикс
/v1, отделяет query string. - Для
POSTнаINJECT_PATHS:- Применяет
applyInjections: каждую пару[key, value]изconfig.injectкладёт в body, если клиент не задал её сам.
- Применяет
- Строит заголовки для апстрима: копирует клиентские (кроме hop-by-hop), подставляет
Authorization: Bearer <polzaApiKey>если клиент свой не прислал. - Выполняет
fetchкUPSTREAM_BASE_URL + путь. - Форвардит статус, заголовки и body (стримом для SSE, иначе — просто
Readable.fromWeb). - Ошибки
fetchпревращаются в502с телом{"error":{"message":"Upstream request failed","detail":"..."}}.
src/
server.js — HTTP-сервер Fastify, роутинг, инъекции, форвардинг
config.js — загрузка config.json, валидация, константы UPSTREAM_BASE_URL и INJECT_PATHS
wizard.js — интерактивный мастер первого запуска (readline)
banner.js — ASCII-баннер + определение цветовой поддержки терминала
config.example.json — минимальный шаблон конфига
| Команда | Что делает |
|---|---|
npm start |
Запуск: node src/server.js |
npm run dev |
То же с --watch — авто-рестарт при изменении src/** |