docs(task): A9 — интеграция с Hermes и обновление токенов Codex
P0-00: Hub подключён к Hermes как middleware llm_execution и срабатывает на каждом вызове, но Hermes не передаёт role — поэтому всё уходило в роль по умолчанию, цепочка orchestrator исчерпана, и Hermes получал текст ошибки вместо ответа модели. Следствие устранено в 2d62d39; в задании — причина: не претендовать на вызов без достоверной роли, описать границу между учётными системами Hub и Hermes, подготовить варианты связывания профилей. P0-01: Codex сохраняет refresh_token, но функции обновления нет вовсе. Требуется обновление токена, раздельная проверка access_token и id_token и переключение аккаунта с остановкой клиента до подмены учётных данных — по образцу Cockpit Tools, присланному владельцем. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
2d62d3973e
commit
95afdfe179
1 changed files with 90 additions and 10 deletions
|
|
@ -109,6 +109,83 @@ HermesHubSetup.cs(968,18): warning CS0219: Переменной "isRepair" пр
|
|||
|
||||
---
|
||||
|
||||
## P0-00. Hub перехватывает КАЖДЫЙ вызов Hermes как `orchestrator`
|
||||
|
||||
Это самое важное в задании. Владелец сообщил: «зашёл в Гермеса, а там наш хаб не работает, основной оркестратор не выбрался», и сделал вывод, что Hub к Hermes не привязан. Вывод неверный, а положение хуже: **Hub привязан и активно ломал Hermes.**
|
||||
|
||||
Что установлено разбором кода Hermes и его журналов:
|
||||
|
||||
1. Плагин регистрируется штатно. `plugins.py:4789` берёт `register` у модуля, корневой `__init__.py` его экспортирует, `ctx.register_middleware("llm_execution", …)` — допустимое имя (`hermes_cli/middleware.py:23`). Перехватчик **срабатывает на каждом обращении к модели**, это видно в трейсбеке `agent.log`.
|
||||
|
||||
2. **Hermes не передаёт роль.** `agent/conversation_loop.py:2950` передаёт `task_id`, `turn_id`, `api_request_id`, `session_id`, `platform`, `model`, `provider`, `base_url`, `api_mode`, `api_call_count` — и всё. Ключа `role` в вызове нет.
|
||||
|
||||
3. Поэтому `resolve_role` доходит до последней строки и возвращает `config.default_role`. **Каждый вызов Hermes маршрутизируется как `orchestrator`.**
|
||||
|
||||
4. Цепочка `orchestrator` у владельца исчерпана целиком:
|
||||
|
||||
```
|
||||
ag-orch-fallback skipped_unhealthy
|
||||
codex-orch 429: Your account is not active, please check your billing details
|
||||
opengo-3 No API key found for OpenCode Go profile 'opengo-3'
|
||||
ag-w1, ag-w3 Antigravity error: agy error: authentication failed or timed out
|
||||
```
|
||||
|
||||
5. Роутер возвращал «⚠️ Hermes Router Failover Exhausted» **как ответ ассистента**, и Hermes показывал это вместо ответа модели — хотя его собственный провайдер работал.
|
||||
|
||||
**Немедленная часть уже исправлена ревьюером** (`2d62d39`) и развёрнута владельцу: при `router_error` вызов уходит дальше по цепочке через `next_call`, отказ пишется в журнал уровнем `warning` с полным следом. Регрессия закрыта тестом `tests/test_plugin_passthrough.py`. Правку не откатывать.
|
||||
|
||||
Принцип, который она закрепляет и который должен соблюдаться дальше: **плагин может улучшить маршрутизацию, но не имеет права сделать Hermes хуже, чем без него.** Любой отказ роутера — это молчаливый пропуск вниз плюс запись в журнал, а не подмена ответа.
|
||||
|
||||
**Что требуется от вас — устранить причину, а не последствие.**
|
||||
|
||||
Сейчас Hub перехватывает все вызовы Hermes и на каждом сначала пробует цепочку `orchestrator`: это лишняя задержка и расход квоты не той роли, даже когда пропуск отработал правильно.
|
||||
|
||||
1. **Определить роль честно.** Разобраться, что из переданного Hermes пригодно как признак роли: `task_id`, `session_id`, `platform`, `model`, `provider`. Если надёжного признака нет — **не угадывать**. Эвристика в `resolve_role`, которая ищет в системном сообщении подстроки «developer», «coding agent», «review agent», — это гадание по тексту промпта, и оно тоже подлежит пересмотру.
|
||||
|
||||
2. **Не претендовать на вызов без роли.** Если роль не определена достоверно, Hub не должен подменять выбор Hermes: пропускать вниз сразу, не тратя попыток. Роль по умолчанию для внешнего перехвата — неверная модель поведения.
|
||||
|
||||
3. **Описать честную границу продукта.** Hermes ведёт собственные профили (`agy-01`…`agy-06`, `worker-fast`, `worker-research`, `worker-review`, `worker-code`, `worker-code-2`, `deepseek`) в каталоге `profiles` своего домашнего каталога, и его `delegate_task` настроен отдельно (`max_concurrent_children=3`, `provider=opencode-go`, `model=kimi-k2.7-code`). Профили Hub (`ag-w1`, `codex-orch`, `opengo-*`) — **другое множество идентификаторов**, ничем с ними не связанное. То есть один и тот же аккаунт Google живёт в двух учётных системах под разными именами.
|
||||
|
||||
Написать в `docs/UI_STATE_CONTRACT.md` раздел о границе: что Hub видит от Hermes, чего не видит, чем управляет и чем не управляет. Без этого любые обещания интерфейса о «команде агентов» вводят владельца в заблуждение — он видит на экране Hub роли, которые Hermes не спрашивает.
|
||||
|
||||
4. **Предложить путь связывания** профилей Hub с профилями Hermes и оценить его трудоёмкость: сопоставление по идентичности аккаунта (email из `id_token`), либо чтение профилей Hermes как источника, либо явная таблица соответствия. Решение принимает владелец — вам подготовить варианты с ценой каждого, не реализовывать молча.
|
||||
|
||||
**Тесты:** вызов без определяемой роли уходит вниз, не тратя попыток роутера; вызов с определённой ролью маршрутизируется; отказ цепочки никогда не возвращается как ответ ассистента.
|
||||
|
||||
## P0-01. Codex: обновление токена и безопасное переключение аккаунта
|
||||
|
||||
Владелец прислал, как это делает Cockpit Tools после обновления, и просит так же. Их последовательность:
|
||||
|
||||
```
|
||||
1. Прочитать данные аккаунта access_token · id_token · refresh_token
|
||||
2. Проверить access_token действителен до 28.08, обновление не требуется
|
||||
3. Проверить id_token истёк 5 дней назад — нужно обновление
|
||||
4. Обновить данные входа полный набор обновлён и сохранён
|
||||
5. Остановить прежний процесс безопасная остановка ChatGPT/Codex и app-server
|
||||
6. Записать данные клиента
|
||||
7. Синхронизировать настройки
|
||||
8. Запустить клиент Codex
|
||||
```
|
||||
|
||||
Ключевое в этой схеме: **токены проверяются по отдельности**, обновляется весь набор, и **клиент останавливается до подмены учётных данных, а не после**.
|
||||
|
||||
Состояние у нас:
|
||||
|
||||
- `codex_oauth.py` сохраняет `refresh_token` (строка 226), но **функции обновления не существует**. Для Antigravity есть `oauth.refresh_access_token`, для Codex — ничего. Протухший токен Codex означает полный повторный вход вместо тихого обновления.
|
||||
- Раздельной проверки `access_token` и `id_token` нет.
|
||||
- Остановки клиента Codex при смене аккаунта нет вовсе: подмена учётных данных под работающим процессом оставляет его со старыми.
|
||||
|
||||
**Требуется:**
|
||||
|
||||
1. Обновление токена Codex по `refresh_token`, с сохранением полного набора и понятной ошибкой, когда `refresh_token` отсутствует или отвергнут.
|
||||
2. Раздельная проверка срока `access_token` и `id_token` с запасом по времени; в статусе профиля видно, что именно просрочено.
|
||||
3. Переключение аккаунта как последовательность с остановкой клиента **до** записи учётных данных и запуском **после**. Шаги должны быть наблюдаемыми — интерфейс покажет их прогрессом (это часть B8), а от вас нужен backend, который эти шаги выполняет и сообщает о каждом.
|
||||
4. Сбой на любом шаге не оставляет систему в промежуточном состоянии: либо аккаунт переключён полностью, либо всё вернулось к прежнему.
|
||||
|
||||
**Тесты:** просроченный `access_token` при живом `refresh_token` обновляется без повторного входа; отсутствие `refresh_token` даёт понятную ошибку, а не молчаливый провал; прерывание на середине переключения не оставляет смешанных учётных данных.
|
||||
|
||||
---
|
||||
|
||||
## P0-1. Квоты для OpenAI Codex и OpenCode Go
|
||||
|
||||
Жалобы владельца: **«лимиты не подтягиваются, всё стоит Н/Д»** и **«у опенкода тоже нет лимитов»**.
|
||||
|
|
@ -204,16 +281,19 @@ claude-sonnet-4-6, claude-opus-4-6-thinking, gpt-oss-120b-medium
|
|||
## Критерии приёмки
|
||||
|
||||
1. Ни один файл зоны Codex не изменён.
|
||||
2. На существующем конфиге без claude/grok после загрузки `find_free_slot` для обоих возвращает существующий профиль; десять профилей `antigravity` не изменены; проверено тестом.
|
||||
3. Миграция идемпотентна и не теряет пользовательские правки и комментарии.
|
||||
4. Квоты `openai-codex` и `opencode-go` приходят измеренными либо `None` с причиной; ни одного выдуманного числа; проверено тестом на обоих исходах.
|
||||
5. Обнаружение моделей кэшируется, обновляется в фоне и не блокирует вызывающий поток при таймауте; проверено тестом с искусственной задержкой.
|
||||
6. Новые профили не содержат выдуманных моделей; проверка конфигурации сообщает о несуществующих моделях в ролях владельца.
|
||||
7. `/reinstall` либо работает с кодами возврата, либо удалён; предупреждение CS0219 при сборке отсутствует.
|
||||
8. В отчёте назван конкретный способ доставки установщика владельцу.
|
||||
9. Прогон **в обоих окружениях**; обе команды и оба результата в отчёте.
|
||||
10. `ruff check .` чисто. Про релизный гейт: он **красный на `main` уже сейчас** (проверка 4 падает не по вашей вине). Указать в отчёте его состояние до и после ваших правок; ухудшать нельзя.
|
||||
11. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`.
|
||||
2. Вызов без достоверно определённой роли уходит вниз, не тратя попыток роутера; отказ цепочки никогда не возвращается как ответ ассистента; правка `2d62d39` сохранена.
|
||||
3. В контракте описана граница между учётными системами Hub и Hermes; подготовлены варианты связывания профилей с оценкой цены каждого.
|
||||
4. Токен Codex обновляется по `refresh_token`; переключение аккаунта останавливает клиент до подмены учётных данных и не оставляет промежуточного состояния.
|
||||
5. На существующем конфиге без claude/grok после загрузки `find_free_slot` для обоих возвращает существующий профиль; десять профилей `antigravity` не изменены; проверено тестом.
|
||||
6. Миграция идемпотентна и не теряет пользовательские правки и комментарии.
|
||||
7. Квоты `openai-codex` и `opencode-go` приходят измеренными либо `None` с причиной; ни одного выдуманного числа; проверено тестом на обоих исходах.
|
||||
8. Обнаружение моделей кэшируется, обновляется в фоне и не блокирует вызывающий поток при таймауте; проверено тестом с искусственной задержкой.
|
||||
9. Новые профили не содержат выдуманных моделей; проверка конфигурации сообщает о несуществующих моделях в ролях владельца.
|
||||
10. `/reinstall` либо работает с кодами возврата, либо удалён; предупреждение CS0219 при сборке отсутствует.
|
||||
11. В отчёте назван конкретный способ доставки установщика владельцу.
|
||||
12. Прогон **в обоих окружениях**; обе команды и оба результата в отчёте.
|
||||
13. `ruff check .` чисто. Про релизный гейт: он **красный на `main` уже сейчас** (проверка 4 падает не по вашей вине). Указать в отчёте его состояние до и после ваших правок; ухудшать нельзя.
|
||||
14. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`.
|
||||
|
||||
## Главное
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue