From 98b1e28e1e2f4449eb299d777a825f5cb3af46bf Mon Sep 17 00:00:00 2001 From: vitya Date: Sun, 16 Aug 2026 17:58:09 +0300 Subject: [PATCH] meta(tasks): register [llm-router-failover-proxy] for pi (deepseek-flash/pro aliases, free-first failover) --- .tasks/STATUS.md | 12 ++++++ .tasks/llm-router-failover-proxy.md | 61 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 .tasks/llm-router-failover-proxy.md diff --git a/.tasks/STATUS.md b/.tasks/STATUS.md index 9e7818f..27090a7 100644 --- a/.tasks/STATUS.md +++ b/.tasks/STATUS.md @@ -1,4 +1,5 @@ # Admin Task Board +_Updated: 2026-08-16 (15) — ⚪ **[llm-router-failover-proxy] заведена** (по запросу vitya через snolla). LLM-роутер/failover-прокси для pi: алиасы deepseek-flash/deepseek-pro поверх 3 free-роутеров (teamorouter/orcarouter/anymodel) + официальный DeepSeek платным fallback'ом. Приоритет free → провайдерский → платный. Деплой — решение админа (рекомендация заказчика: локально winsw). Спека: `.tasks/llm-router-failover-proxy.md` + письмо в инбокс._ _Updated: 2026-08-16 (14) — 🟢 **[sched-fnf-04-embedded-alerts] ACCEPTED — F&F цикл закрыт.** Приёмка №4 (14:40Z): замечаний нет. Итоги sched: 6 багов/пробелов → 6 фич (exports-map 0.1.2, @sched/ui serve 0.1.1 + токен-бокс, validateConfig 0.12.2, ntfy basic 0.12.2, pollTimeoutMs 0.1.4). Версии: core 0.12.2 / daemon 0.1.4 / ui 0.1.1 / mcp 0.1.1, сьют 363 ✓. У них дальше: storage-сплит (по фидбеку) + полировка доков; раунд 2 согласован: docs-review после storage-сплита + полировки (пинг от sched, формат делал/ожидал/получил/раздел, фокусы: quick-start все пути, 07.storage, 10.cli, 13.ui) _Updated: 2026-08-16 (13) — 🟢 **[sched-fnf-03-async-poll] ACCEPTED + 🟡 [sched-fnf-04-embedded-alerts] DONE (репорт отправлен).** Приёмка №3 (14:31Z): pollTimeoutMs проброшен в daemon (0.1.4, +pollIntervalMs, CLI --poll-timeout), доки 10.cli.md/05.protocol.md. №4 embedded (финальная): createEngine+internal runner+sqlite+syncTasks в одном скрипте — реальная проверка свежести бэкапов kreknin по SSH (vds-kzntsv 12.4h / books-vds 11.4h → succeeded; порог 1h → failed «STALE backups»); retry 3x (a1 fail → a2 fail → a3 succeed, triggerTask не ретраится — доки честны); createAlerts ntfy **basic auth работает** («[sched] backup-freshness failed» в топике). Цикл F&F закрыт, замечаний нет. Репорт: `victor/sched/.agents/inbox/2026-08-16T14-36-01Z-admin-fnf-04-report.md`._ _Updated: 2026-08-16 (12) — 🟢 **[sched-fnf-02-docker-runner] ACCEPTED + 🟡 [sched-fnf-03-async-poll] DONE (репорт отправлен).** Приёмка №2 (14:24Z): оба замечания стали фичами — validateConfig-хук (allowlist на load, abort при старте, core 0.12.2) + ntfy basic auth (user+password в createAlerts, daemon 0.1.3), сьют 362 ✓. №3 async/poll: свой воркер (:8293) envelope accepted+poll — happy path queued→running(50)→succeeded (progress 100, 3.5s), timeout-кейс hung → failed «poll timeout after 15000ms» (через createEngine, т.к. daemon не пробрасывает pollTimeoutMs — замечание в репорт). Фиксы №2 подтверждены (abort на load + ntfy basic в коде). Репорт: `victor/sched/.agents/inbox/2026-08-16T14-27-54Z-admin-fnf-03-report.md`._ @@ -145,6 +146,17 @@ _Updated: 2026-05-25 (`iis-migration-to-ruvds` 🟢 closed Phase 1 per user deci --- +## ⚪ [llm-router-failover-proxy] — LLM-роутер/failover-прокси для pi (deepseek-flash/pro алиасы) +**Status:** ⚪ ready — заведена 2026-08-16 по запросу vitya (письмо `.agents/inbox/2026-08-16T14-57-25Z-snolla.md`). +**Where I stopped:** (not started) — контекст и требования: `.tasks/llm-router-failover-proxy.md` (upstreams-таблица, ключи в `~/.pi/agent/auth.json`, priority free→paid, passthrough SSE/tools/thinking). +**Next action:** прочитать спеку `.tasks/llm-router-failover-proxy.md` + письмо из инбокса → invoke `tdd-criteria` → выбрать стек и деплой (рекомендация: Node + winsw локально) → реализовать → принять решение по деплою → live-smoke через pi → отчитаться в `victor/snolla` inbox. +**Branch:** n/a (новый проект) +**Weight:** needs-claude +**Notify:** victor/snolla + + +--- + ## ⚪ [kreknin-self-backup] — второй таргет для приёмника бэкапов (на потом) **Status:** ⚪ backlog — заведена 2026-06-12 по итогам backup-gap аудита, user: «на потом». **Where I stopped:** kreknin (`195.19.90.188`, `/volume1` 7 ТБ) — единственный приёмник всех 4 пайплайнов, сам не бэкапится → SPOF всей estate. Направление: второй облачный таргет (Backblaze B2 / Synology Hyper Backup, client-side encryption) для critical-subset (`*/latest` ~30 ГБ + `.hbk` vault). diff --git a/.tasks/llm-router-failover-proxy.md b/.tasks/llm-router-failover-proxy.md new file mode 100644 index 0000000..ad7f3ba --- /dev/null +++ b/.tasks/llm-router-failover-proxy.md @@ -0,0 +1,61 @@ +# llm-router-failover-proxy + +## Goal + +LLM-роутер / failover-прокси для pi (кодинг-агент на Windows-воркстейшне vitya). Группирует все deepseek-v4-flash модели из разных роутеров в один алиас (`deepseek-flash`), отдельно deepseek-v4-pro (`deepseek-pro`). Приоритет: **free-модели первыми**, затем по приоритету провайдеров, официальный DeepSeek API (платный) — последним fallback'ом. При ошибке апстрима (429/5xx/таймаут/сеть) — автоматический переход к следующему. + +Заказчик: vitya (через snolla-сессию). **Решение, куда деплоить — за админом** (см. «Деплой»). + +## Контекст + +Потребитель один — pi на машине vitya (`~/.pi/`). Сейчас модели прописаны вручную в `~/.pi/agent/models.json` (4 провайдера, ключи в `~/.pi/agent/auth.json`): + +| Провайдер | baseUrl | deepseek-v4-flash | deepseek-v4-pro | +|---|---|---|---| +| teamorouter | https://api.teamorouter.com/v1 | `deepseek-v4-flash-free` (free) | `deepseek-v4-pro-free` (free) | +| orcarouter | https://api.orcarouter.ai/v1 | `deepseek/deepseek-v4-flash-free` (free) | `deepseek/deepseek-v4-pro-free` (free) | +| anymodel | https://anymodel.org/v1 | `am/deepseek-v4-flash` (free) | `am/deepseek-v4-pro` (free) | +| routerai | https://routerai.ru/api/v1 | — | — | +| deepseek (официальный) | https://api.deepseek.com | `deepseek-chat` (платный) | `deepseek-reasoner` (платный) | + +- Ключи всех апстримов уже лежат в `~/.pi/agent/auth.json` (формат: `{ "": { "type": "api_key", "key": "..." } }`). Конфиг прокси может ссылаться на них или держать свои копии — на усмотрение админа (ключи не публиковать, gitignore). +- Все free-модели — это deepseek-v4-flash/pro у разных посредников. Официальный DeepSeek API платный — **последний** в цепочке (fallback, когда все free лежат). +- Ранее обсуждено (рекомендация, НЕ приказ): деплой локально на Windows как winsw-сервис (паттерн agents-task-runner уже обкатан), Node-прокси без docker/WSL2. **Решение за админом.** + +## Требования + +1. **OpenAI-совместимый эндпоинт** (`/v1/chat/completions`, openai-completions API). pi подключается одной записью в `~/.pi/agent/models.json` (провайдер + алиасы). +2. **Алиасы моделей**: `deepseek-flash` → пул flash-апстримов, `deepseek-pro` → пул pro-апстримов. +3. **Приоритет выбора**: free-апстримы (teamorouter → orcarouter → anymodel, порядок конфига) → платный официальный DeepSeek → (остальные провайдеры, если появятся). +4. **Failover**: на 429 / 5xx / таймаут / сетевую ошибку — retry к следующему апстриму в порядке приоритета. Желательно: cooldown для упавших апстримов (не долбить мёртвый), опционально circuit-breaker. +5. **Прозрачный passthrough**: SSE-стриминг, tool-calls (pi использует активно, много раундов), thinking-блоки deepseek (reasoning) — всё должно доезжать без искажений. Модель в ответе — какую реально использовал. +6. **Логика по умолчанию**: если все free живы — платный апстрим не вызывается (экономия). +7. **Конфиг** — файл (YAML/JSON): алиас → упорядоченный список апстримов (baseUrl, key-ref, model-id, free/paid флаг, таймауты). +8. **Учёт**: лог, какой апстрим обслужил запрос + usage. Cost-трекинг не обязателен (модели free), но знать, что сработал платный fallback — обязательно. +9. **Тесты**: TDD (см. ниже). + +## Acceptance + +- [ ] pi подключается к прокси одной записью в `~/.pi/agent/models.json`; `/model` (или `pi --list-models`) показывает `deepseek-flash` / `deepseek-pro`. +- [ ] Стриминг работает: ответ идёт потоком (не цельным blob). +- [ ] Tool-calls работают: несколько последовательных инструмент-раундов (типа как pi вызывает tools). +- [ ] Failover доказан тестом: верхний апстрим недоступен → запрос обслуживает следующий; при живых free — платный НЕ вызывается. +- [ ] Thinking/reasoning-контент deepseek не ломается (хотя бы smoke: ответ не пустой, без мусора). +- [ ] Инструкция для pi-интеграции (что писать в models.json) + как запускать/останавливать прокси (сервис/скрипт). +- [ ] Деплой выполнен (локально или VDS — решение админа) и живой smoke пройден. + +## Деплой (решение за админом) + +Рекомендация заказчика: **локально** на Windows (Node-процесс, winsw-сервис — паттерн agents-task-runner; ключи не уходят на сервер; потребитель один — pi на этой машине; docker/WSL2 на Windows — боль). Если админ видит причину иначе (VDS, доступ с других устройств, Portainer-стек) — обосновать и сделать. Ключи апстримов на VDS — только если деплой туда, тогда по правилам админа (pass / env, не в git). + +## Обязательные скилы — вызвать до начала работы + +- invoke `tdd-criteria` — до написания кода +- invoke `using-tasks` — управление статусом задачи +- invoke `project-discipline` — коммиты/пуши +- invoke `using-wiki` после закрытия — заингесть `.wiki/concepts/llm-router-failover-proxy.md` (архитектура, решения, runbook) + +**TDD:** да — failover/приоритет/стриминг это чистые юнит-кейсы; тест-харнесс обязателен (мок-апстримы). +**Разрешения:** интерны: да | автопуш: да +**Weight:** needs-claude +**Notify:** victor/snolla