From 266fc51adf83dff755ef760979edfcf7143312ac Mon Sep 17 00:00:00 2001 From: Hermes Team Date: Tue, 1 Sep 2026 01:46:46 +0700 Subject: [PATCH] =?UTF-8?q?fix(providers):=20=D0=BA=D0=BB=D1=8E=D1=87=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=B4=D0=BE=D1=85=D0=BE=D0=B4=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=B4=D0=BE=20=D0=B0=D0=B4=D0=B0=D0=BF=D1=82=D0=B5=D1=80=D0=B0?= =?UTF-8?q?;=20=D1=81=D1=87=D1=91=D1=82=D1=87=D0=B8=D0=BA=20=D0=B0=D0=BA?= =?UTF-8?q?=D0=BA=D0=B0=D1=83=D0=BD=D1=82=D0=BE=D0=B2=20=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D1=85=D0=BE=D0=B4=D0=B8=D0=BB=D1=81=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ключ API. add_account сохраняет его через ProfileAuthManager, а адаптеры NVIDIA и OpenRouter читали только profile.auth_config из router_profiles.yaml — туда ключ не попадает. Запрос уходил без заголовка Authorization, и провайдер отвечал «401: Header of type authorization was missing», хотя список моделей тем же ключом получался: обнаружение читает ключ из хранилища, а адаптер читал из конфигурации. Проверено: auth_config в yaml пуст, адаптер теперь находит ключ в хранилище учётных данных. Счётчик аккаунтов. Значок в меню брал readiness.accounts_connected_count (строго AUTHENTICATED), а карточка на странице считала профили правилом «не NOT_CONFIGURED». Владелец видел 9 в меню и 3 на странице. Приведено к одному определению — тому же, что у страницы. 609 passed, ruff clean, релизный гейт 10/10. Co-Authored-By: Claude Opus 5 --- .../router/adapters/nvidia_adapter.py | 14 ++++++++++++++ .../router/adapters/openrouter_adapter.py | 14 ++++++++++++++ src/antigravity_provider/router/web/static/app.js | 8 +++++--- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/antigravity_provider/router/adapters/nvidia_adapter.py b/src/antigravity_provider/router/adapters/nvidia_adapter.py index af8520e..12c29ad 100644 --- a/src/antigravity_provider/router/adapters/nvidia_adapter.py +++ b/src/antigravity_provider/router/adapters/nvidia_adapter.py @@ -38,6 +38,20 @@ class NvidiaAdapter(BaseProviderAdapter): if key: return str(key).strip() + # Ключ, введённый в мастере, сохраняется через ProfileAuthManager, а не в + # auth_config из router_profiles.yaml. Адаптер читал только второе место и + # уходил без заголовка Authorization: провайдер отвечал 401 «Header of type + # authorization was missing», хотя список моделей тем же ключом получался. + try: + from antigravity_provider.router.profile_manager import ProfileAuthManager + + stored = ProfileAuthManager.load_profile_auth(profile.provider, profile.profile_id) or {} + key = stored.get("api_key") or stored.get("token") + if key: + return str(key).strip() + except Exception: + pass + suffix = profile.profile_id.upper().replace("-", "_") for candidate in (f"NVIDIA_API_KEY_{suffix}", "NVIDIA_API_KEY", "NV_API_KEY"): val = os.environ.get(candidate, "").strip() diff --git a/src/antigravity_provider/router/adapters/openrouter_adapter.py b/src/antigravity_provider/router/adapters/openrouter_adapter.py index f4b0777..0531ed0 100644 --- a/src/antigravity_provider/router/adapters/openrouter_adapter.py +++ b/src/antigravity_provider/router/adapters/openrouter_adapter.py @@ -41,6 +41,20 @@ class OpenRouterAdapter(BaseProviderAdapter): if key: return str(key).strip() + # Ключ, введённый в мастере, сохраняется через ProfileAuthManager, а не в + # auth_config из router_profiles.yaml. Адаптер читал только второе место и + # уходил без заголовка Authorization: провайдер отвечал 401 «Header of type + # authorization was missing», хотя список моделей тем же ключом получался. + try: + from antigravity_provider.router.profile_manager import ProfileAuthManager + + stored = ProfileAuthManager.load_profile_auth(profile.provider, profile.profile_id) or {} + key = stored.get("api_key") or stored.get("token") + if key: + return str(key).strip() + except Exception: + pass + suffix = profile.profile_id.upper().replace("-", "_") for candidate in (f"OPENROUTER_API_KEY_{suffix}", "OPENROUTER_API_KEY"): val = os.environ.get(candidate, "").strip() diff --git a/src/antigravity_provider/router/web/static/app.js b/src/antigravity_provider/router/web/static/app.js index 440fb9e..91880d0 100644 --- a/src/antigravity_provider/router/web/static/app.js +++ b/src/antigravity_provider/router/web/static/app.js @@ -576,9 +576,11 @@ function updateGlobalHeader() { const readiness = currentSnapshot.readiness || {}; renderAccountSummary(currentSnapshot); const allProfiles = Object.values(currentSnapshot.all_profiles || {}); - const connectedAccounts = readiness.accounts_connected_count ?? allProfiles.filter( - (p) => isConnectedProfile(p) - ).length; + // Одно число — одно определение. Готовность считает строго AUTHENTICATED, + // а страница аккаунтов — всё, что не NOT_CONFIGURED. Из-за двух определений + // значок в меню показывал 9, а карточка на той же странице — 3. + // Берём то же правило, что и страница аккаунтов: расходиться они не должны. + const connectedAccounts = allProfiles.filter((p) => isConnectedProfile(p)).length; if (elements.navAccountsCount) elements.navAccountsCount.textContent = connectedAccounts;