backend router and endpoint adapter: [AN] Messages <-> [OI]-compatible backends for AI agents
v1.0.1 — HTTP-прокси-адаптер, позволяющий работать агентам с Anthropic-совместимым API ([CC], QwenCode) через бэкенд LLM, который реализует [OI]-совместимый API (
/v1/chat/completions), но некорректно реализует протокол Anthropic Messages API.
[CC] / QwenCode ←--Anthropic API--> adapter (localhost:9999) ←--[OI] API--> LLM Backend
- [CC] — docs/claude_code.md: модель передаётся по имени в запросе, объявлять её заранее не нужно.
- QwenCode — docs/qwen-code.md: модели объявляются
заранее в
modelProviders, зато у каждой может быть своё контекстное окно. - Codex CLI — docs/codex.md: работает через Responses API
(
wire_api = "responses"), переключение модели командой/model <имя>. - Любой другой клиент — Anthropic Messages API (
/v1/messages) и [OI]-совместимые клиенты (/v1/chat/completions,/v1/responses), см. docs/routing.md.
- System messages. Бэкенд кластеризует system messages в конец диалога — адаптер собирает их в одно сообщение в начале.
- Format mismatch. Клиент отправляет запросы в формате Anthropic Messages API, а бэкенд ожидает [OI] Chat Completions. Адаптер выполняет двунаправленную конвертацию (сообщения, инструменты, tool choice).
- Model compatibility. Позволяет использовать модели Qwen (например
qwen3.6-35b-a3b) через [CC] и QwenCode. - Qwen tool_calls fallback. Модели Qwen иногда возвращают вызовы инструментов в текстовом формате с JSON внутри XML-подобных тегов — адаптер автоматически парсит этот формат.
- Прозрачное проксирование: ретраи/таймауты, конвертация Anthropic ↔ [OI] (в т.ч. стриминг SSE), маскирование секретов в логах. С v0.9.9 — адаптивный ретрай при
reasoning_budget_exhausted(HTTP 502): адаптер поднимаетmax_tokensи немедленно повторяет запрос, не отдавая ошибку клиенту (ADAPTER_REASONING_RETRY,ADAPTER_REASONING_MIN_TOKENS). Входные эндпоинты (v0.9.0): наряду с/v1/messagesадаптер принимает/v1/chat/completionsи/v1/responses; TARGET-переменные (ADAPTER_*_TARGET) задают режим обработки для каждого входа — прямое преобразование в указанный формат (конверсииmessages→completions,messages→messages— сортировка system,responses→responsesиresponses→completions— с поддержкой команды/model,completions→completions— дословная копия E→E),passthrough(дословная передача: тело и SSE-поток возвращаются как есть) или выключение входа (none). С v1.0.0 дефолты всех трёх входов —completions: из коробки работают [CC], [OI]-клиенты и Codex. - Логирование и наблюдаемость: консольные debug-блоки
[...]печатаются всегда (с обрезкой доADAPTER_LOG_TRIM;0— без обрезки); файловая запись per-session логов (session-*.log/*.jsonl,*.partsдампы) — поADAPTER_DEBUG_ENABLE=1в подпапкуlog/корня данныхADAPTER_DATA_ROOT(дефолт~/.ba, совпадает с домашней папкой--root), файлы несут полные строки без обрезки; per-session JSON/YAML-дампы всех логгируемых частей пишутся тем же флагом (v0.9.10), и тем же флагом в фоне (тихий периодADAPTER_ARTIFACT_DEBOUNCE) пересобирается дерево артефактов сессии — запрос прокси рендер не ждёт;.err-файлы инцидентов (v0.9.0) — при финальном ответе клиенту 4xx/5xx реального прокси-запроса пишутся в ту же директорию безусловно (полные запрос и ошибка, без обрезки по TRIM, внеADAPTER_DEBUG_ENABLE; redact по умолчанию). С v0.9.5.errфиксирует ошибки уровня адаптера, не дошедшие до бэкенда (отказы маршрутизации disabled/reject, 400 валидации модели, 501); с v0.9.7 право на блок определяется распознанным входным путём (_req_ctx.err_eligible) и не зависит отADAPTER_SESSIONS_TABLE, а покрытие расширено на500(необработанное исключение),501неподдерживаемых HTTP-методов и обрыв потока mid-stream (final_status=200, пометкаmid-stream abort). Счётчик «Ошибок» в таблице/sessions— ссылка на этот файл. - WEBUI (поднимается всегда, флага отключения нет):
/— статус-страница: шапка «Backend-Adapter Version <x.x.x>» с иконками-навигацией 🔃 (перепроверить бэкенды, POST/) / 🗂 (/sessions) / 📋 (/session) / 🔧 (/config), LLM-эндпоинты, таблица «Models in use» с live-счётчиками вызовов/токенов и колонкой Cost (по тарифамADAPTER_MODELS_TARIFFS; ставится live-поллингом через innerHTML —cost_htmlс сервера); действия строки — иконки-кнопки ⏪ (сбросить счётчики) / 🗑 (удалить строку); проверка бэкендов по кнопке-иконке 🔃 (перечитываетADAPTER_BACKEND_CONFIGбез рестарта);/sessions— таблица сессий агентов (v0.9.5): строки-кортежи(session, agent, model, backend, route)с колонкой входного эндпойнта, счётчиком ошибок-ссылкой на.err-файл (открывается в новом окне) и пер-сессионными выпадающими списками Log / TARGET (наследуют общие настройки, пока не заданы явно); действия строки — ⏪ (сбросить счётчики только этой строки) / 🗑 (удалить строку); ссылка 🗂 со статус-страницы открывается в новом окне, обратная ссылка «Статус 📊» — в текущем;/session— просмотр сессий (*.parts, дерево артефактов, hash8-алиасы; обратная ссылка «Статус 📊»);/config— переключение объёма debug-записи на лету (runtime-пул; обратная ссылка «Статус 📊»);/healthz,/health,/live,/ready— health-check для оркестрации;- Prometheus-экспортёр (
ADAPTER_EXPORTER_ENABLE=1, отдельный слушатель, дефолт127.0.0.1:9100).
- Мониторинг использования: таблица использованных моделей персистентна (
model-usage.yamlв подпапкеvar/корня данныхADAPTER_DATA_ROOT), счётчики строки обнуляются (⏪) и строка удаляется из таблицы и файла (🗑) по кнопкам/API (POST /api/model-usage/reset,/delete).
# 1. Клонировать репозиторий
git clone https://github.com/alekseybb197/backend-adapter.git
cd backend-adapter
# 2. Установить зависимости (единственная внешняя — PyYAML)
pip install -r requirements.txt
# 3. Скопировать и заполнить env-файл и YAML-конфиг бэкенда
cp docs/samples/sample.adapter.env adapter.env
cp docs/samples/sample.adapter.yaml adapter.yaml
# (в adapter.env: токен ADAPTER_BACKEND_KEY_LLM_SERVICE и пути)
# 4. Загрузить env-переменные
source adapter.env
# 5. Запустить адаптер
python3 backend-adapter.py
# 6. В другом терминале запустить клиент
claude # Claude Code — см. docs/claude_code.md
qwen # QwenCode — см. docs/qwen-code.mdВариант через домашнюю папку (v0.9.11–v0.9.13): вместо шагов 3-4 разметьте
домашнюю папку ~/.ba одной командой и запускайте с --root (дом и корень
данных совпадают — log/ и var/ лежат прямо в <root>):
python3 backend-adapter.py --install # создать ~/.ba со всеми конфигами
# или сразу с одним бэкендом (v0.9.13):
python3 backend-adapter.py --install --root ~/.ba \
--name demo --base https://llm.example.com --key ADAPTER_DEMO_KEY
$EDITOR ~/.ba/adapter.env # вписать токен бэкенда
python3 backend-adapter.py --check --root ~/.ba # проверить конфиги (exit 1 при ошибке типов)
python3 backend-adapter.py --root ~/.ba # запуск с настройками из домаПовторный --install не теряет прежние файлы: существующий файл уходит в
<файл>.bak, после чего перезаписывается свежим из шаблона.
Дом можно не указывать: без --root адаптер ищет его сам — сначала в
текущей папке, затем в ~/.ba (признак — adapter.env или
adapter.yaml); первый найденный становится домом. Явные переменные
окружения всегда побеждают.
Ключи CLI: --version/-v, --help/-h/-?, --root <путь>, --install,
--install --name/--base/--key (только вместе), --check (подробности —
docs/install.md §4.5).
Подробная инструкция: docs/install.md
| Файл | Описание |
|---|---|
| docs/install.md | Установка, конфигурация, systemd/launchd, troubleshooting |
| docs/claude_code.md | Настройка клиента [CC]: профиль, проектные настройки, статус-строка, модели и контекст |
| docs/qwen-code.md | Настройка клиента QwenCode: modelProviders, модели с разным контекстным окном, id сессии |
| docs/codex.md | Настройка клиента Codex CLI: Responses API, config.toml, переключение модели командой /model |
| docs/routing.md | Настройка входных эндпоинтов и маршрутизации (TARGET): принципы, реализованное, перспективы |
| docs/environment.md | Полный справочник всех env-переменных |
| docs/logging.md | Конфигурация логирования и trace |
| docs/sanitizing.md | Санитизация и маскирование секретов |
| docs/architecture.md | Архитектура, диаграмма компонентов, lifecycle запросов |
| docs/webui.md | WEBUI и API: страницы /, /sessions, /session, /config, /api/*, секция «Models in use» (live-счётчики) и таблица сессий с пер-сессионными настройками |
| docs/adr/ | Архитектурные решения (ADR): действующие решения, предложения, порядок принятия |
backend-adapter/
├── backend-adapter.py # Точка входа (__version__)
├── backend_adapter/ # Доменный пакет (38 модулей, включая __init__.py)
│ ├── config.py # Парсинг env, multi-backend YAML, фоновые проверки
│ ├── server.py # HTTP-сервер (три входа + TARGET-маршрутизация)
│ ├── routing.py # Входные эндпоинты/TARGET: decide() по TARGET
│ ├── convert.py # Конвертация сообщений/инструментов
│ ├── streaming.py # SSE streaming: конверсия + passthrough E→E relay
│ ├── tracer.py # JSONL trace-логирование
│ ├── session_log.py # Per-session логи с FIFO eviction
│ ├── session_registry.py # Таблица сессий (страница /sessions): строка-кортеж
│ ├── session_settings.py # Пер-сессионные переопределения Log/TARGET
│ ├── state_store.py # Перманентный runtime-пул (state.yaml, v0.9.6)
│ ├── env_validate.py # Строгая валидация env при старте (v0.9.6)
│ ├── env_check.py # Офлайн-диагностика --check: типы и устаревшие (v0.9.13)
│ ├── daemon.py # Detach (double fork)
│ ├── shutdown.py # Обработка Ctrl-C/SIGTERM
│ ├── logger.py # Консольные debug-логи (безусловны)
│ ├── redact.py # Маскирование секретов
│ ├── webserver.py # WEBUI-ядро (роутинг эндпойнтов, serve(), CLI)
│ ├── webui_status.py # WEBUI "/": статус-страница, usage-таблица, /api/*
│ ├── webui_sessions.py # WEBUI "/sessions": таблица сессий + /api/sessions/*
│ ├── webui_errors.py # WEBUI "/errors/<имя>": превью .err-файла сессии
│ ├── webui_ops.py # WEBUI health: /healthz /health /live /ready
│ ├── webui_config_api.py # WEBUI "/config": runtime-конфиг
│ ├── prometheus_exporter.py # Метрики /metrics (отдельный слушатель)
│ ├── session_viewer.py # WEBUI "/session": просмотр *.parts сессий
│ ├── model_usage.py # Персистентный учёт использованных моделей, тарифы
│ ├── probe_json.py # JSON-результат опроса списка моделей в var/
│ ├── cli.py # CLI-утилиты (runpy-трамплин команды backend-adapter)
│ ├── cli_args.py # Разбор argv: --version/--help/--root/--install/--check (v0.9.13)
│ ├── templates.py # Встроенные шаблоны дефолтов для --install (v0.9.12)
│ ├── artifact_tree*.py # Генерация дерева артефактов (8 модулей)
│ ├── artifact_refresh.py # Фоновая дебаунсная отрисовка артефактов (v0.9.10)
│ └── __init__.py # Lazy-прокси глобалов config/logger/tracer на старте
├── docs/ # Документация
│ ├── samples/ # Примеры конфигов: sample.adapter.env (env-файл),
│ │ # sample.adapter.yaml (YAML бэкендов),
│ │ # sample.tariffs.yaml (тарифы моделей),
│ │ # backend-adapter.service + com.user.backend-adapter.plist
│ │ # (шаблоны systemd/launchd для запуска из исходников)
│ ├── claude_code/ # Локальные настройки клиента [CC] (settings/statusline)
│ ├── qwen-code/ # Локальные настройки клиента QwenCode (settings)
│ └── codex/ # Локальные настройки клиента Codex CLI (config.toml)
├── molecule/ # molecule-тесты install.sh (Linux, ubuntu 24.04):
│ # install — установка/обновление бинарника;
│ # service — системный systemd, обновление и --delete
└── requirements.txt # Зависимости (единственная — PyYAML)