docs(tasks): add llm-web-proxy spec (web-LLM provider for pi+Claude Code) + omniroute tuning wiki
This commit is contained in:
@@ -1,9 +1,21 @@
|
||||
# Admin Task Board
|
||||
_Updated: 2026-08-22 — 🟢 **[sched-pipelines-local-stack] ЗАКРЫТА** (ритуал закрытия, решение vitya): мок-кампания финализирована ранее (0.1.0 published оба воркера, повторные раны noop, 0.2.0-кейс проверен симуляцией и откачен; фикс #7 httpGet fetch-Response контракта принят). Реальный деплой apilki — за отмашкой юзера (в «Спроси user'а»); VDS-миграция — таска sched-vds-deploy (paused). Wiki: +2 концепта в shared (verdaccio-token-buildkit-secret, msys-no-pathconv-docker-windows).
|
||||
_Updated: 2026-08-22 — ⚪ **[llm-web-proxy] заведена** (спека .tasks/llm-web-proxy.md: кастомный web-LLM провайдер для pi + Claude Code — web-чаты, эмуляция тулов, без оверкилла omniroute; делать в следующей сессии). 🟢 **[sched-pipelines-local-stack] ЗАКРЫТА** (ритуал закрытия, решение vitya): мок-кампания финализирована ранее (0.1.0 published оба воркера, повторные раны noop, 0.2.0-кейс проверен симуляцией и откачен; фикс #7 httpGet fetch-Response контракта принят). Реальный деплой apilki — за отмашкой юзера (в «Спроси user'а»); VDS-миграция — таска sched-vds-deploy (paused). Wiki: +2 концепта в shared (verdaccio-token-buildkit-secret, msys-no-pathconv-docker-windows).
|
||||
_Updated: 2026-08-21 — 🟢 **[sched-fnf-daemon-image-storage] F&F ЗАКРЫТ: 7/7 + фиксы F1/F2/N1/N2 ПРИНЯТЫ** (их письмо 23:40Z, commit e755b52, daemon 0.10.1). Ретест затронутых поверхностей на `registry.kzntsv.site/sched-daemon:0.10.1` (digest 269093a08f6e…): F1 — 0.10.1 стартует против исправленного `deploy/tasks.json` (schedules); F2 — рецепт из доков (BuildKit secret + npmMinimalAgeGate:0) собран 1-в-1, history 0 JWT, storage-mongo 0.4.0, +смоук ступени 4 (коллекции, ран); N2 — баннер `storage=custom module=./my-storage.mjs` (тест пинит module=); N1 — нота MSYS_NO_PATHCONV в доках. Регресс 1/2/3/5 на 0.10.1 — тексты фейлов идентичны. Акцепт: `sched/.agents/inbox/2026-08-21T23-41-30Z-admin.md`.
|
||||
_Updated: 2026-08-21 — 🟢 **[sched-fnf-daemon-image-storage] F&F 7/7 PASS** (их письмо 23:12Z, таска sched 🟢 done). Образ `registry.kzntsv.site/sched-daemon:0.10.0` из опубликованного `@sched/daemon` + storage-композиция: 1) sqlite-дефолт баннер `storage=sqlite db=…` + раны в sqlite; 2) XOR `--storage mongo --db x.db` → точный отказ; 3) env fail-fast ДО старта (`MONGO_URL is not set`); 4) mongo-композицию собрал САМ (BuildKit secret, `@sched/storage-mongo@0.4.0` из verdaccio) → коллекции sched_tasks/runs/schedules + ран в mongo, баннер `storage=mongo db=…`; 5) missing-адаптер → хинт `add @sched/storage-mysql to your image`; 6) BYO `./my-storage.mjs` (MemoryStorage-порт пинового референса) → `storage=custom`, негатив без createStorage → точная ошибка контракта; 7) креды в connstring → весь лог = 1 строка баннера, 0 утечек. Находки: **F1** `deploy/tasks.json` (монтируется docker-compose.dev.yml, док. в 13.self-hosting) на старом ключе `schedule` → daemon 0.10.0 fatal (док. `docker compose up` не стартует); **F2** рецепт производного образа в 13.self-hosting без `ARG VERDACCIO_TOKEN` → YN0041 anonymous-auth при сборке 1-в-1 по докам; при фиксе через --build-arg токен оседает в image history (видно в их `schedd-mongo:0.10.0`; моя secret-сборка — 0 вхождений). N1: на винде git-bash нужен `MSYS_NO_PATHCONV=1` (иначе /app/… → `C:/Program Files/Git/…`). N2: BYO-баннер `db=default`. Репорт: `sched/.agents/inbox/2026-08-21T23-27-41Z-admin.md`. Стенд: `.tmp/fnf-daemon-image/` (gitignored), mongo-стенд возвращён в исходное.
|
||||
_Updated: 2026-08-20 — 🟡 **[sched-pipelines-local-stack]** schedd **0.9.0 применён + cancel-тест ЗЕЛЁНЫЙ**. **Мок-publish: режект #7 ozon** — фиксы #1-#6 приняты: npm ✅ create ✅ clone ✅ commit ✅ push fast-forward ✅ (2-й ран), release-409 ветка добавлена. 7-й баг: 409-ветка падает на стенде — `GET existing → 200` throw, т.к. прод httpGetFn=fetch отдаёт Response (.body=ReadableStream), а тест мокал `{body:{id:42}}` — разрыв тест/прод #2 (как режект #2, только httpGet). Gitea реально отдаёт id:114. Письмо 00:05Z. Ждём фикс #7.
|
||||
|
||||
## ⚪ [llm-web-proxy] — кастомный web-LLM провайдер для pi + Claude Code (web-чаты, эмуляция тулов, без оверкилла omniroute)
|
||||
|
||||
**Status:** ready
|
||||
**Where I stopped:** (not started) — дизайн готов: .tasks/llm-web-proxy.md (спека) + .wiki/concepts/omniroute-combo-deepseek-web-tuning.md (диагноз). Существующий llm-router-failover-proxy (порт 8787) НЕ подходит — это пасsthrough для API, без web-протокола/эмуляции тулов//v1-messages.
|
||||
**Next action:** вытащить из docker-контейнера omniroute (`/app/open-sse/`): executors/deepseek-web.ts + translators (deepseekWebTools.ts, webTools.ts, claude-to-openai.ts, openai-to-claude.ts); собрать скелет src/server.js (`/v1/chat/completions` + `/v1/messages` + `/health`) с round-robin и логированием (req/tool-prompt/raw-reply/parse/upstream/session/stream/failover).
|
||||
**Branch:** master
|
||||
**Weight:** needs-claude
|
||||
**Notify:** OpeItcLoc03/admin
|
||||
<!-- created-by: vitya@.admin / 2026-08-22 / trigger: сессия настройки omniroute web-комбо; делать в следующей сессии -->
|
||||
|
||||
---
|
||||
|
||||
## 🟢 [sched-pipelines-local-stack] — локальный стенд: sched daemon + ym/ozon воркеры + browser/ntfy/alert-bridge, потом VDS
|
||||
**Status:** done
|
||||
**Closing note:** ЗАКРЫТА 2026-08-22 (ритуал закрытия, решение vitya). Мок-кампания финализирована ранее: оба воркера publish 0.1.0, повторные раны noop, кейс «спека→0.2.0» проверен симуляцией и откачен; фикс #7 (httpGet fetch-Response контракт) принят. Реальный деплой (npmjs + github.com) — отдельное решение юзера, в «Спроси user'а» handoff'а; VDS-миграция — таска sched-vds-deploy (paused).
|
||||
|
||||
105
.tasks/llm-web-proxy.md
Normal file
105
.tasks/llm-web-proxy.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# llm-web-proxy
|
||||
|
||||
## Goal
|
||||
|
||||
Кастомный LLM-провайдер (локальный, Windows) для pi и Claude Code: **web-чаты вместо API**. Основа — код omniroute (executor'ы + трансляторы), вытащенный и завёрнутый в минимальный сервер. Решает боль текущих комбо omniroute: quality validation режет стримы, 503 chat_admission_busy, оверкилл Next.js+sqlite+дашборд ради 2 комбо.
|
||||
|
||||
Заказчик: vitya. Сессия дизайна 2026-08-22 (.wiki/concepts/omniroute-combo-deepseek-web-tuning.md).
|
||||
|
||||
## Почему (контекст)
|
||||
|
||||
- pi ходит в omniroute (localhost:20128) → combo `deepseek-v4-flash-web` / `deepseek-v4-pro-web` → провайдер `deepseek-web` (chat.deepseek.com через userToken, 3 аккаунта: megan/yulia/vitya).
|
||||
- Веб-чат DeepSeek **не имеет нативного function calling** — omniroute эмулирует: `tools[]` → текстовый контракт `<tool>{"name":"...","arguments":{...}}</tool>` в промпт → парсит ответ обратно в `tool_calls`.
|
||||
- Существующий `llm-router-failover-proxy` (служба, порт 8787) — **не подходит**: пасsthrough для API-провайдеров (routerai/официальный DS), нет web-протокола, нет эмуляции тулов, нет `/v1/messages`.
|
||||
- Диагноз вылетов в omniroute: (1) `system_message` override режет скилы pi, (2) `tool_filter_regex` режет тулы, (3) search-режим генерит DEEP_SEARCH-мусор, (4) quality validation (`isStreamingUpstreamError`) режет стрим на `type:error`, (5) 503 = capacity веб-чата. Всё, кроме 503, — следствие оверкилла; в кастомном провайдере этих слоёв просто не будет.
|
||||
|
||||
## Архитектура
|
||||
|
||||
```
|
||||
pi ── /v1/chat/completions (OpenAI) ──┐
|
||||
Claude Code ── /v1/messages (Anthropic) ──┴──▶ llm-web-proxy (localhost:8788)
|
||||
│ 1. detect format (openai | claude)
|
||||
│ 2. round-robin: combo → account (конфиг)
|
||||
│ 3. web executor: auth(PoW) → session → SSE
|
||||
│ 4. эмуляция тулов: <tool>-контракт → tool_calls
|
||||
│ 5. ретраи/cooldown на 429/5xx/timeout
|
||||
▼
|
||||
chat.deepseek.com (и др. web-чаты)
|
||||
```
|
||||
|
||||
### Комбо (конфиг, один на провайдера — НЕ смешивать)
|
||||
|
||||
- `deepseek-flash-web` → deepseek-web аккаунты (megan/yulia/vitya), модель `deepseek-v4-flash-think` (search ВЫКЛЮЧЕН — он ломал тулы)
|
||||
- `deepseek-pro-web` → те же аккаунты, `deepseek-v4-pro`
|
||||
- позже: `qwen-web`, `gemini-web`, `kimi-web`, `grok-web` — отдельные комбо, свои executors
|
||||
|
||||
## Что берём из omniroute (готовое, работает)
|
||||
|
||||
Из docker-контейнера `omniroute` (`/app/`), образ `diegosouzapw/omniroute:latest`:
|
||||
|
||||
1. `open-sse/executors/deepseek-web.ts` (1147 строк) — auth userToken→accessToken, PoW-челлендж, создание/переиспользование сессий, SSE-парсинг фрагментов (THINK/ANSWER), эмуляция тулов. **Взять целиком**, удалить лишнее (persistSession уже есть).
|
||||
2. `open-sse/translator/deepseekWebTools.ts` (486 строк) + `open-sse/translator/webTools.ts` — парсеры зоопарка `<tool>`-форматов. Взять целиком.
|
||||
3. `open-sse/translator/request/claude-to-openai.ts` + `open-sse/translator/response/openai-to-claude.ts` — конвертация Anthropic ⇄ OpenAI (для Claude Code).
|
||||
4. Зависимости: `@omniroute/open-sse` имеет свои импорты — вытаскивать вместе с нужными модулями (`streamHelpers`, `tokenAccounting` и т.п.) либо скопировать файлы в свой пакет и починить импорты. **Решение исполнителя**, но НЕ переписывать логику.
|
||||
|
||||
## Что пишем сами (мало)
|
||||
|
||||
- `src/server.js` — HTTP: `POST /v1/chat/completions` (OpenAI) + `POST /v1/messages` (Anthropic, с SSE keepalive `event: ping` — Claude Code рвёт соединение при долгом промпте) + `GET /health`.
|
||||
- `src/router.js` — round-robin по аккаунтам + cooldown/circuit (паттерн llm-router-proxy `src/router.js` — уже написан, работает).
|
||||
- `config/web-providers.json` — комбо → аккаунты → модель. Ключи НЕ в конфиге: userToken'ы из `~/.pi/agent/auth.json` или отдельного файла (формат на усмотрение, gitignore).
|
||||
- **Логирование — первоклассное требование** (см. ниже).
|
||||
|
||||
## Логирование (обязательно, для диагностики агентом)
|
||||
|
||||
Файл-лог, **одна строка = одно событие**, grep-парсится: `[TS] [TAG] event=... key=value`.
|
||||
|
||||
| Событие | Что пишем | Зачем |
|
||||
|---|---|---|
|
||||
| `req` | alias, аккаунт, модель, msgs, tools, stream | какой аккаунт крутит round-robin |
|
||||
| `tool-prompt` | tools=N, bytes контракта | контракт раздулся → модель теряет формат |
|
||||
| `raw-reply` | **первые ~500 символов сырого ответа модели** | видно `<tool>`-блоки, DEEP_SEARCH-мусор, reasoning, пустоту — корень 90% проблем |
|
||||
| `parse` | calls=N, имена тулов, аргументы валидны | парсер нашёл/потерял вызовы, `arguments:{}` |
|
||||
| `upstream` | статус, код (401/429/503), PoW, таймаут, ретрай N | лимиты, баны |
|
||||
| `session` | created/reused/deleted, persist | эффективность persistSession |
|
||||
| `stream` | complete/truncated/error, байты, длительность | обрыв стрима |
|
||||
| `failover` | упавший апстрим → куда ушёл | round-robin честен |
|
||||
|
||||
Правила: тела user-сообщений НЕ логируем (только размеры); `raw-reply` обрезанный; ротация (`.1`, `.2`); пишем в stdout + файл (winsw).
|
||||
|
||||
## Требования
|
||||
|
||||
1. **OpenAI-совместимый** `/v1/chat/completions` — pi подключается одним провайдером в `~/.pi/agent/models.json`.
|
||||
2. **Anthropic-совместимый** `/v1/messages` — Claude Code подключается через `ANTHROPIC_BASE_URL=http://127.0.0.1:8788` (+ свой API-ключ, любой).
|
||||
3. **Tool-calls работают** в обоих форматах: несколько последовательных инструмент-раундов (как pi вызывает тулы; Claude Code — `tool_use` блоки).
|
||||
4. **thinking/reasoning** deepseek не ломается (reasoning_content для pi, `thinking`-блоки для Claude Code).
|
||||
5. **Failover**: 429/5xx/таймаут/сеть → следующий аккаунт в комбо; cooldown + circuit-breaker на упавший аккаунт.
|
||||
6. **persistSession: true** — переиспользование сессии (меньше 503 chat_admission_busy).
|
||||
7. **БЕЗ quality validation** — этого слоя в omniroute нет (это и была боль).
|
||||
8. **Логирование** — по спеке выше; агент должен по логу восстанавливать цепочку запроса.
|
||||
9. **Конфиг** — JSON: комбо → упорядоченные аккаунты (baseUrl/executor, userToken-ref, model, timeout), router-параметры.
|
||||
10. **Тесты**: TDD — round-robin, failover, парсинг `<tool>` (валид/зоопарк форматов), claude⇄openai конвертация, стриминг.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [ ] pi → `/v1/chat/completions` (model=deepseek-flash-web): стриминг, tool-calls в несколько раундов, reasoning не ломается.
|
||||
- [ ] Claude Code → `/v1/messages`: подключается, тулы (`tool_use`) работают, SSE keepalive не даёт оборвать соединение.
|
||||
- [ ] Failover доказан тестом: аккаунт недоступен (503/таймаут) → запрос обслуживает следующий; cooldown работает.
|
||||
- [ ] Лог: по `raw-reply` + `parse` видно каждый tool-call модели; тела пользователя отсутствуют.
|
||||
- [ ] Инструкция pi-интеграции (models.json) + Claude Code (env) + запуск/остановка (winsw-сервис, паттерн llm-router).
|
||||
- [ ] Деплой: локально, Windows, winsw-сервис `llm-web-proxy`, живой smoke.
|
||||
|
||||
## Деплой
|
||||
|
||||
Локально на Windows: Node-процесс + winsw-сервис (паттерн agents-task-runner / llm-router уже обкатан). Ключи не уходят с машины. Порт 8788 (не конфликтует с llm-router :8787).
|
||||
|
||||
## Обязательные скилы — вызвать до начала работы
|
||||
|
||||
- invoke `tdd-criteria` — до написания кода
|
||||
- invoke `using-tasks` — статус задачи
|
||||
- invoke `project-discipline` — коммиты/пуши
|
||||
- invoke `using-wiki` после закрытия — обновить концепт
|
||||
|
||||
**TDD:** да — failover/приоритет/парсинг/конвертация это чистые юнит-кейсы; тест-харнесс обязателен (мок-апстрим).
|
||||
**Разрешения:** интерны: да | автопуш: да
|
||||
**Weight:** needs-claude
|
||||
**Notify:** OpeItcLoc03/admin
|
||||
Reference in New Issue
Block a user