docs(agents): задания A32 и A34 — восстановление подключения аккаунтов, OpenRouter и NVIDIA, удаление десктопа
Проверка кандидата A28-A31 в браузере вскрыла блокирующую регрессию: при
переписывании клиента в A29 функции удалили, а вызовы в разметке оставили.
Консоль на живой сборке:
openAddAccountWizard is not defined «+ Добавить аккаунт» не работает
checkUpdates is not defined падает при каждой загрузке
handleNodeAccountChange не сменить аккаунт у агента
handleNodeModelChange не сменить модель
handleRefreshProviderModels не обновить список моделей
Подключить аккаунт в новой сборке невозможно, назначить агенту тоже. При этом
startDeviceAuth и startRedirectAuth в коде остались, но не вызываются ниоткуда.
A34 собирает в один порядок: восстановление подключения (блокирует остальное),
адаптеры OpenRouter и NVIDIA с несколькими аккаунтами, интерфейс автопоиска
локальных серверов поверх готовой серверной части, и удаление десктопа по A32.
Задание опирается на ветку review/a28-a31-fixes, где лежат исправления
ревьюера, и перечисляет их отдельным разделом, чтобы не переделывались.
A32 добавлен в репозиторий: он был написан ранее, но остался только локально.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7e83c38340
commit
1b03f03ea5
2 changed files with 314 additions and 0 deletions
137
agents/inbox/2026-08-25-A32-remove-desktop.md
Normal file
137
agents/inbox/2026-08-25-A32-remove-desktop.md
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# Задание A32: удаление десктопного приложения
|
||||
|
||||
## Дата поступления
|
||||
2026-08-25
|
||||
|
||||
## База
|
||||
Проверочный HEAD на момент выдачи: **`c35bc48`**.
|
||||
|
||||
## Ветка
|
||||
`antigravity/remove-desktop`
|
||||
|
||||
## Когда выполнять
|
||||
|
||||
**После A29 и A30.** Оба работают в веб-слое, и удалять десктоп раньше, чем веб доберёт остаток паритета, нельзя. Пункт P0-1 — проверка этого паритета, и он выполняется первым.
|
||||
|
||||
Два прохода: **Flash** реализует, **Pro** проводит аудит.
|
||||
|
||||
---
|
||||
|
||||
## Порядок работы с git
|
||||
|
||||
```
|
||||
cd <каталог репозитория>; git fetch origin --prune; git status
|
||||
git checkout main; git pull --ff-only origin main
|
||||
git checkout -b antigravity/remove-desktop
|
||||
git commit -m "..." <- сначала коммит
|
||||
git push -u origin antigravity/remove-desktop
|
||||
```
|
||||
|
||||
В `main` напрямую не пушить.
|
||||
|
||||
---
|
||||
|
||||
## Задача
|
||||
|
||||
Владелец решил перейти на веб полностью: «десктоп надо вообще вырезать и удалить, он не нужен». Решение принято давно, но удаление ни разу не назначалось: в заданиях стояло «десктоп не трогать, он выводится из обращения», и это защищало его от правок, а не убирало.
|
||||
|
||||
## Что осталось — снято исполнением на `c35bc48`
|
||||
|
||||
```
|
||||
src/antigravity_provider/router/ui/ 20 файлов, ~6 910 строк
|
||||
hermes_hub_app.py ~1 345 строк, CustomTkinter
|
||||
cli_commands.py:481 команда запуска десктопа
|
||||
```
|
||||
|
||||
Виндовый установщик:
|
||||
|
||||
```
|
||||
HermesHubSetup.cs:288-289 копирует HermesHub.exe в каталог установки и в hermes home
|
||||
HermesHubSetup.cs:575 создаёт ярлык «Hermes Hub (Desktop).lnk» рядом с «Hermes Hub (Web).lnk»
|
||||
HermesHubSetup.cs:140 проверка зависимостей ТРЕБУЕТ customtkinter, иначе установка не считается успешной
|
||||
HermesHubSetup.cs:188 ставит customtkinter и pillow в venv
|
||||
pyproject.toml:40 customtkinter>=6.0.0 в зависимостях
|
||||
```
|
||||
|
||||
Линуксовый установщик десктоп уже не ставит: там только `fastapi uvicorn pydantic psutil pyyaml`, а `.desktop` ведёт на веб-лаунчер. **Сервер фактически уже без десктопа.**
|
||||
|
||||
Последствия, не сводящиеся к лишнему весу: на Windows GUI-библиотека ставится ради программы, которой не пользуются, и её отсутствие ломает установку. Два ярлыка в меню «Пуск» — прямой путь снова открыть старое окно вместо веба; у владельца это уже случалось, он жаловался, что «открывается старая программа и тормозит при передвижении окна».
|
||||
|
||||
## P0-1. Сначала паритет, потом удаление
|
||||
|
||||
**Выполняется первым и является условием остального.**
|
||||
|
||||
Составить список того, что десктоп умеет, и сверить с вебом по каждому пункту. Особое внимание тому, что исторически жило только в десктопе:
|
||||
|
||||
- мастер подключения аккаунтов (`router/ui/add_account_wizard.py`) — в вебе есть свой, но состав шагов сверить;
|
||||
- вход Antigravity и Claude по ссылке — сделан в вебе, проверить на всех провайдерах;
|
||||
- каталог моделей (`router/ui/model_catalog.py`);
|
||||
- граф маршрутизации (`router/ui/routing_graph.py`);
|
||||
- всё из `router/ui/views/`.
|
||||
|
||||
**Результат — таблица «умение → где в вебе → проверено».** Непокрытое умение удалять нельзя: сначала оно появляется в вебе, и только потом удаляется десктоп. Если что-то не покрыто, а A29 и A30 его не закрывают, — назвать это в отчёте и остановиться, а не удалять молча.
|
||||
|
||||
## P0-2. Удаление кода
|
||||
|
||||
После пройденного P0-1:
|
||||
|
||||
1. `src/antigravity_provider/router/ui/**` целиком.
|
||||
2. `hermes_hub_app.py`.
|
||||
3. Команду запуска десктопа из `cli_commands.py` и проверку `customtkinter` там же.
|
||||
4. Тесты, проверявшие десктоп. **Тесты, проверяющие общую логику, не выбрасывать** — перенести на веб-поверхность, если они там применимы.
|
||||
|
||||
Осторожно: часть общего кода могла переехать в `router/ui/` исторически. Перед удалением проверить, не импортирует ли что-то из веба или из маршрутизатора модули оттуда. Импорт, обёрнутый в `except ImportError`, — отдельная опасность: он не даст ошибки, просто тихо отключит функцию. Такое в проекте уже было и стоило раунда.
|
||||
|
||||
## P0-3. Зависимости и установщики
|
||||
|
||||
1. `customtkinter` и `pillow` убрать из `pyproject.toml`, из установки в `HermesHubSetup.cs` и из проверки зависимостей. **Проверить, не нужен ли `pillow` чему-то ещё** — он используется не только GUI.
|
||||
2. Копирование `HermesHub.exe` убрать; сам `launcher/HermesHub.cs` и `launcher/HermesHub.exe` удалить.
|
||||
3. Ярлык «Hermes Hub (Desktop)» убрать. Оставшийся ярлык переименовать в просто «Hermes Hub» — скобка «(Web)» теряет смысл, когда вариант один.
|
||||
4. **Удаление старой установки должно убирать и старый ярлык.** Иначе у владельца в меню «Пуск» останется ярлык на несуществующую программу — это хуже, чем два рабочих.
|
||||
|
||||
## P0-4. Проверка на живой установке
|
||||
|
||||
Мало собрать — надо поставить.
|
||||
|
||||
1. Собрать оба установщика, поставить на Windows, убедиться: ярлык один, он открывает веб, `customtkinter` не требуется, установка проходит без него.
|
||||
2. Проверить обновление **поверх старой установки** с десктопом: старые файлы и ярлык убираются, учётные данные и настройки уцелевают.
|
||||
3. Линуксовый установщик не сломан.
|
||||
|
||||
Пункт 2 обязателен: у владельца на трёх машинах стоит версия с десктопом, и обновление пойдёт именно поверх неё.
|
||||
|
||||
## P0-5. Аудит вторым проходом
|
||||
|
||||
1. **Таблица паритета из P0-1 проверена выборочно**, а не принята на слово.
|
||||
2. **Тихие импорты.** Поиском убедиться, что не осталось `from ...router.ui` под `except ImportError`.
|
||||
3. **Установить и запустить**, а не только собрать.
|
||||
4. **Обновление поверх старой установки** проверено на самом деле.
|
||||
5. **Побочные изменения** объяснить.
|
||||
6. **Пропущенный пункт назвать пропущенным.**
|
||||
|
||||
---
|
||||
|
||||
## Ограничения
|
||||
|
||||
- Ничего, кроме десктопа, не удалять. Общая логика, маршрутизатор, адаптеры, обновлятор остаются.
|
||||
- Веб-слой не переписывать: он зона A29 и A30.
|
||||
- Правило честности без исключений.
|
||||
- Тег `v0.1.1` не создавать.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
1. Ветка в `origin`, `git status` чист.
|
||||
2. Таблица паритета приложена; непокрытых умений нет либо они названы, и удаление по ним не проводилось.
|
||||
3. `router/ui/**` и `hermes_hub_app.py` удалены; `from ...router.ui` в коде не встречается.
|
||||
4. `customtkinter` отсутствует в зависимостях, в установке и в проверке; установка проходит без него.
|
||||
5. Ярлык один, ведёт на веб; ярлык на десктоп удаляется при обновлении поверх старой установки.
|
||||
6. Обновление поверх версии с десктопом проверено: аккаунты, настройки и цепочки ролей уцелели.
|
||||
7. Линуксовый установщик работает.
|
||||
8. `ruff check .` чисто; релизный гейт не ухудшен.
|
||||
9. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, `X passed / Y skipped / Z failed`. На `main` сейчас **451 passed, 2 skipped**.
|
||||
|
||||
## Главное
|
||||
|
||||
Владелец работает только в вебе. Десктоп тянет за собой GUI-зависимость, второй ярлык и восемь тысяч строк, которые никто не открывает, — и время от времени запускается вместо веба.
|
||||
|
||||
## Порядок сдачи
|
||||
Передать точный `FINAL_COMMIT_SHA`.
|
||||
177
agents/inbox/2026-08-30-A34-restore-wizard-providers-desktop.md
Normal file
177
agents/inbox/2026-08-30-A34-restore-wizard-providers-desktop.md
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# Задание A34: восстановить подключение аккаунтов, добавить OpenRouter и NVIDIA, удалить десктоп
|
||||
|
||||
## Дата поступления
|
||||
2026-08-30
|
||||
|
||||
## База
|
||||
|
||||
Работать **поверх ветки ревьюера** `review/a28-a31-fixes` (`529192b`), а не поверх `main` и не поверх своей прошлой ветки. В ней уже лежат A28–A31, слитые с `main`, плюс исправления ревьюера.
|
||||
|
||||
```
|
||||
git fetch origin --prune
|
||||
git checkout -b antigravity/a34-restore-and-providers origin/review/a28-a31-fixes
|
||||
```
|
||||
|
||||
В `main` напрямую не пушить. В конце — push, `git log --oneline -1`, `git status` чистый.
|
||||
|
||||
## Порядок исполнения
|
||||
|
||||
Два прохода: **Flash** реализует, **Pro** проводит аудит. Пункт **P0-6** написан для аудитора.
|
||||
|
||||
Пункты выполняются **по порядку**. P0-1 блокирует всё остальное: пока нельзя подключить аккаунт, ни новых провайдеров, ни автопоиска проверить не на чем.
|
||||
|
||||
---
|
||||
|
||||
## Что уже сделано ревьюером — не переделывать
|
||||
|
||||
Снято исполнением на кандидате A28–A31 и исправлено в `529192b`:
|
||||
|
||||
1. **Дублирование ролей.** `RoleRegistry.migrate_legacy_roles` существовала, но не вызывалась ниоткуда; интерфейс показывал 19 агентов вместо 13, шесть пар неотличимы по названию. Миграция подключена, порядок обработки исправлен, цепочки владельца сохраняются. Проверено на его живой конфигурации: 19 → 13, цепочки совпадают.
|
||||
2. **Сохранённый workflow** мигрируется вместе с ролями, иначе рёбра ссылались на исчезнувших агентов.
|
||||
3. **Поиск локальных серверов** — новый модуль `router/local_discovery.py` и действие `discover_local_models`. Серверная часть готова и проверена; **не хватает только интерфейса** (P0-3).
|
||||
4. **Глобальный мьютекс Antigravity** снят ранее (`7e83c38`): три параллельных вызова занимали 3.01 с, стали 1.00 с. Возвращать нельзя, есть тест.
|
||||
5. **CORS** закрыт по умолчанию (`c35bc48`). Список источников — настройка `web_api_allowed_origins`.
|
||||
|
||||
---
|
||||
|
||||
## P0-1. Восстановить подключение аккаунтов — блокирующее
|
||||
|
||||
При переписывании клиента в A29 **функции удалили, а вызовы оставили**. Проверено в браузере на живом кандидате, консоль:
|
||||
|
||||
```
|
||||
openAddAccountWizard is not defined ← «+ Добавить аккаунт» ничего не делает
|
||||
checkUpdates is not defined ← падает при каждой загрузке страницы
|
||||
```
|
||||
|
||||
Полный список повисших обработчиков — определений 0, вызовы есть:
|
||||
|
||||
```
|
||||
openAddAccountWizard нельзя подключить аккаунт
|
||||
handleNodeAccountChange нельзя сменить аккаунт у агента в «Обзоре»
|
||||
handleNodeModelChange нельзя сменить модель
|
||||
handleRefreshProviderModels нельзя обновить список моделей
|
||||
checkUpdates проверка обновлений падает на загрузке
|
||||
```
|
||||
|
||||
При этом `startDeviceAuth` и `startRedirectAuth` **в коде остались и работают**, но не вызываются ниоткуда — стали мёртвыми. Их надо не писать заново, а связать с восстановленным мастером.
|
||||
|
||||
Требуется вернуть работоспособность каждому пункту списка. Действия на сервере существуют и менять их не нужно:
|
||||
|
||||
```
|
||||
add_account, start_device_auth, poll_device_auth,
|
||||
start_redirect_auth, submit_redirect_callback, poll_redirect_auth,
|
||||
assign_role, set_model, refresh_models, check_updates
|
||||
```
|
||||
|
||||
Что мастер обязан уметь, по провайдерам:
|
||||
|
||||
- **Grok, OpenAI Codex** — код устройства. Адрес и код приходят **от провайдера**, подставлять свои нельзя.
|
||||
- **Antigravity, Claude** — вход по ссылке с возвратом. Ссылку можно открыть **на любой машине**. Принимается и полный адрес возврата, и один только код. При работе с другой машины показывается готовая команда проброса порта возврата.
|
||||
- **Локальный сервер** — адрес и необязательный ключ, плюс автопоиск из P0-3.
|
||||
- **Выбор слота обязателен и делается владельцем.** Автоподбор ошибается: `find_free_slot` определяет занятость по файлу учётных данных, а `agy` на Windows держит их в keyring, поэтому все слоты выглядят свободными и всегда возвращается первый. Вход затирал бы работающий аккаунт. В списке слотов видно, какие заняты и кем, и участвует ли слот в маршрутизации.
|
||||
|
||||
**Проверять исполнением, а не глазами.** Откройте страницу, нажмите каждую кнопку, посмотрите консоль. Ни одного `ReferenceError` при загрузке и при работе.
|
||||
|
||||
## P0-2. OpenRouter и NVIDIA, аккаунтов по несколько
|
||||
|
||||
Владелец подключил их в Hermes напрямую, мимо хаба: «главный кодекс стоит, подключил себе нвидеа и опенроутер и грок». Хаб их не видит — адаптеров нет, упоминаний в коде нет вовсе.
|
||||
|
||||
Оба **OpenAI-совместимы**, поэтому образец есть: `adapters/local_adapter.py` и `adapters/deepseek_adapter.py` работают ровно так же — `POST {base_url}/chat/completions`, `GET {base_url}/models`.
|
||||
|
||||
1. **Адаптеры** `openrouter` и `nvidia`. Базовый адрес — **настройка, не константа**. Для OpenRouter это `https://openrouter.ai/api/v1`, у NVIDIA свой; но зашивать нельзя, владелец может использовать прокси.
|
||||
2. **Несколько аккаунтов на провайдера**, без потолка. Потолок в A26 уже снят: `find_free_slot` выдаёт идентификаторы сама, когда предопределённые кончились (`codex-4`, `codex-5`). Сделать так же.
|
||||
3. **Ключ вводится в мастере** и хранится там же, где ключи прочих провайдеров. В снапшот, в журнал и в `/api/settings` он попадать не должен — тест на это уже есть.
|
||||
4. **Обнаружение моделей** через `GET /models`. У OpenRouter список большой; показывать надо тот, что вернул провайдер, а не подмножество из головы.
|
||||
5. **Квоты.** OpenRouter отдаёт остаток кредитов, у NVIDIA свои лимиты. Отдаёт — показывать; не отдаёт — **«Н/Д» с причиной**, а не ноль и не пустая полоса, которую можно принять за исчерпание.
|
||||
6. **Логотипы** провайдеров у владельца есть в каталоге с макетами. Файла нет — нейтральная заглушка, а не чужой знак.
|
||||
|
||||
## P0-3. Автопоиск локальных моделей в интерфейсе
|
||||
|
||||
Серверная часть готова ревьюером, писать её заново не нужно.
|
||||
|
||||
```
|
||||
router/local_discovery.py discover_local_servers()
|
||||
action_handler действие discover_local_models
|
||||
```
|
||||
|
||||
Опрашивает Ollama 11434, LM Studio 1234, llama.cpp 8080–8082, vLLM 8000, Jan, GPT4All, Text Generation WebUI — параллельно, девять портов за 1.5 с. Возвращает только ответившие, со списком моделей от самого сервера.
|
||||
|
||||
Требуется кнопка **«Найти на этом компьютере»** в шаге подключения локального провайдера:
|
||||
|
||||
1. Нажатие — опрос, показ найденного: имя сервера, адрес, список моделей.
|
||||
2. Выбор найденного заполняет адрес; вводить руками по-прежнему можно.
|
||||
3. **Ничего не найдено — так и сказать**, с подсказкой запустить Ollama, LM Studio или llama.cpp либо ввести адрес вручную. Пустой список это результат, а не ошибка.
|
||||
4. Порт, занятый чужим сервисом, показывается **с причиной** — иначе владелец будет гадать, почему заведомо работающий сервер не виден.
|
||||
5. Опрос идёт в фоне, интерфейс не блокируется.
|
||||
|
||||
Учесть: хаб может работать на сервере, а браузер у владельца на другой машине. Поиск идёт **там, где работает хаб**, и это надо сказать в интерфейсе прямо, иначе результат будет непонятен.
|
||||
|
||||
## P0-4. Удаление десктопа (задание A32 целиком)
|
||||
|
||||
Выполняется **после** P0-1: пока веб не подключает аккаунты, удалять десктоп нельзя.
|
||||
|
||||
Полный текст — `agents/inbox/2026-08-25-A32-remove-desktop.md`, здесь коротко:
|
||||
|
||||
```
|
||||
router/ui/** 20 файлов, ~6 910 строк
|
||||
hermes_hub_app.py ~1 345 строк, CustomTkinter
|
||||
cli_commands.py:481 команда запуска десктопа
|
||||
HermesHubSetup.cs:575 ярлык «Hermes Hub (Desktop).lnk»
|
||||
HermesHubSetup.cs:140 проверка зависимостей ТРЕБУЕТ customtkinter
|
||||
pyproject.toml:40 customtkinter>=6.0.0
|
||||
```
|
||||
|
||||
Сначала **таблица паритета** «умение десктопа → где в вебе → проверено», и только потом удаление. Непокрытое умение не удалять, а назвать в отчёте.
|
||||
|
||||
Отдельно: в `b4ae08e` появился обход «GUI helpers importable without customtkinter». После удаления десктопа эта прослойка не нужна — снять её, а не оставлять.
|
||||
|
||||
Обновление пойдёт **поверх установок с десктопом** на трёх машинах владельца: старый ярлык обязан убираться, учётные данные, настройки и цепочки ролей — уцелеть.
|
||||
|
||||
## P0-5. Проверка на живой установке
|
||||
|
||||
1. Собрать оба установщика, поставить на Windows и на Linux.
|
||||
2. Подключить хотя бы по одному аккаунту каждого потока: код устройства, вход по ссылке, локальный сервер.
|
||||
3. Разложить аккаунты по ролям и убедиться, что порядок переживает перезапуск.
|
||||
4. Проверить обновление поверх старой установки.
|
||||
|
||||
## P0-6. Аудит вторым проходом
|
||||
|
||||
1. **Повисшие вызовы.** Собрать все `onclick`/`onchange` и убедиться, что каждая функция определена. Именно этот класс дефекта и пропустили в A29: разметка звала пять функций, которых нет.
|
||||
2. **Консоль браузера чистая** при загрузке и при работе.
|
||||
3. **Выдуманные значения.** Особый риск в P0-2: квоты и списки моделей новых провайдеров. Ни одного числа, которого не дал провайдер.
|
||||
4. **Ключи не утекают** в снапшот, журнал и `/api/settings`.
|
||||
5. **Мьютекс Antigravity не вернулся** — есть тест, он должен проходить.
|
||||
6. **Побочные изменения** объяснить.
|
||||
7. **Пропущенный пункт назвать пропущенным.**
|
||||
|
||||
---
|
||||
|
||||
## Ограничения
|
||||
|
||||
- Не переделывать то, что перечислено в разделе «сделано ревьюером».
|
||||
- Без сборки, без npm, без фреймворка — решение обосновано в контракте.
|
||||
- Действия только через `action_handler`; новые — с правкой `docs/web-api/CONTRACT.md`.
|
||||
- Правило честности без исключений: нет данных — «Н/Д» и причина.
|
||||
- Тег `v0.1.1` не создавать.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
1. Ветка в `origin` от `review/a28-a31-fixes`, `git status` чист.
|
||||
2. В консоли браузера нет `ReferenceError` ни при загрузке, ни при работе; все обработчики определены — проверено списком.
|
||||
3. Аккаунт подключается всеми тремя потоками; слот выбирает владелец, занятые видны.
|
||||
4. Аккаунт назначается агенту и меняется модель — из «Обзора» и из «Маршрутизации»; переживает перезапуск.
|
||||
5. OpenRouter и NVIDIA подключаются, аккаунтов больше трёх на провайдера; ключи не утекают; модели берутся у провайдера.
|
||||
6. Квоты новых провайдеров показаны настоящие либо «Н/Д» с причиной.
|
||||
7. Кнопка автопоиска находит запущенные локальные серверы; пустой результат объяснён; чужой сервис на порту назван с причиной.
|
||||
8. `router/ui/**` и `hermes_hub_app.py` удалены, `customtkinter` из зависимостей убран, ярлык один; обновление поверх старой установки сохраняет данные.
|
||||
9. Таблица паритета приложена.
|
||||
10. `ruff check .` чисто; релизный гейт не ухудшен.
|
||||
11. **Скриншоты:** мастер на каждом из трёх потоков, автопоиск локальных, «Обзор» с назначением аккаунта, «Маршрутизация».
|
||||
12. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, `X passed / Y skipped / Z failed`. На ветке ревьюера сейчас **475 passed, 2 skipped**.
|
||||
|
||||
## Главное
|
||||
|
||||
Сейчас в новой сборке нельзя подключить ни одного аккаунта и нельзя назначить его агенту — разметка зовёт пять функций, которых в коде нет. Всё остальное в задании бессмысленно, пока это не восстановлено.
|
||||
|
||||
## Порядок сдачи
|
||||
Передать точный `FINAL_COMMIT_SHA`. Сдано только после появления коммита в `origin`.
|
||||
Loading…
Reference in a new issue