diff --git a/CHANGELOG.md b/CHANGELOG.md index 57ce635..443913c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ --- +## [v0.50.7] OAuth provider onboarding path — Codex/Copilot no longer blocks setup (PR #331, fixes #329 bug 2) + +- **OAuth providers now have a proper onboarding path** (closes bug 2): Users with `openai-codex`, `copilot`, `qwen-oauth`, or any other OAuth-authenticated provider now see a clear confirmation card instead of an unusable API key input form. + - If already authenticated (`chat_ready: true`): blue "Provider already authenticated" card with a direct Continue button — no key entry required. + - If not yet authenticated: amber card explaining how to run `hermes auth` or `hermes model` in a terminal to complete setup. + - Either state includes a collapsible "switch provider" section for users who want to move to an API-key provider instead. + - `_build_setup_catalog` now includes `current_is_oauth` boolean; fixed a latent `KeyError` crash when looking up `default_model` for OAuth providers. + - 5 new i18n keys in English and Spanish (`onboarding_oauth_*`). + - 15 new tests in `tests/test_sprint40.py`; 791 tests total (up from 776) + ## [v0.50.6] Skip-onboarding env var + synchronous API key reload (PR #330, fixes #329 bugs 1+3) - **`HERMES_WEBUI_SKIP_ONBOARDING=1`** (closes bug 1): Hosting providers can set this env var to bypass the first-run wizard entirely. Only takes effect when `chat_ready` is also true — a misconfigured deployment still shows the wizard. Accepts `1`, `true`, or `yes`. diff --git a/api/onboarding.py b/api/onboarding.py index caabbb8..ae8ae8d 100644 --- a/api/onboarding.py +++ b/api/onboarding.py @@ -362,13 +362,23 @@ def _build_setup_catalog(cfg: dict) -> dict: } ) + # Flag whether the currently-configured provider is OAuth-based (not in the + # API-key flow). The frontend uses this to show a confirmation card instead + # of a key input when the user has already authenticated via 'hermes auth'. + current_is_oauth = current_provider not in _SUPPORTED_PROVIDER_SETUPS and bool( + current_provider + ) + return { "providers": providers, "unsupported_note": _UNSUPPORTED_PROVIDER_NOTE, + "current_is_oauth": current_is_oauth, "current": { "provider": current_provider, "model": current_model - or _SUPPORTED_PROVIDER_SETUPS[current_provider]["default_model"], + or _SUPPORTED_PROVIDER_SETUPS.get(current_provider, {}).get( + "default_model", "" + ), "base_url": current_base_url, }, } diff --git a/static/i18n.js b/static/i18n.js index 62a140c..57e8a6c 100644 --- a/static/i18n.js +++ b/static/i18n.js @@ -237,6 +237,11 @@ const LOCALES = { onboarding_missing_imports: 'Missing imports:', onboarding_notice_setup_required: 'Choose a simple provider path here. Advanced OAuth flows still belong in the Hermes CLI for now.', onboarding_notice_setup_already_ready: 'A working Hermes provider setup is already detected. You can keep it or replace it here.', + onboarding_oauth_provider_ready_title: 'Provider already authenticated', + onboarding_oauth_provider_ready_body: 'This instance is configured to use an OAuth provider ({provider}) that was set up via the Hermes CLI. No API key is needed here — click Continue to finish setup.', + onboarding_oauth_provider_not_ready_title: 'OAuth provider not yet authenticated', + onboarding_oauth_provider_not_ready_body: 'This instance is configured to use {provider}, which uses OAuth rather than an API key. Run hermes auth or hermes model in a terminal to authenticate, then reload the Web UI.', + onboarding_oauth_switch_hint: 'Or choose a different provider below to switch to an API-key setup:', onboarding_notice_workspace: 'These values reuse the same settings APIs as the normal app.', onboarding_workspace_label: 'Workspace', onboarding_workspace_or_path: 'Or enter a workspace path', @@ -497,6 +502,11 @@ const LOCALES = { onboarding_missing_imports: 'Importaciones faltantes:', onboarding_notice_setup_required: 'Elige aquí una ruta simple de proveedor. Los flujos OAuth avanzados siguen siendo del CLI de Hermes por ahora.', onboarding_notice_setup_already_ready: 'Ya se detectó una configuración funcional del proveedor de Hermes. Puedes conservarla o reemplazarla aquí.', + onboarding_oauth_provider_ready_title: 'Proveedor ya autenticado', + onboarding_oauth_provider_ready_body: 'Esta instancia está configurada para usar un proveedor OAuth ({provider}) configurado mediante la CLI de Hermes. No se necesita clave API aquí — haz clic en Continuar para finalizar la configuración.', + onboarding_oauth_provider_not_ready_title: 'Proveedor OAuth no autenticado aún', + onboarding_oauth_provider_not_ready_body: 'Esta instancia está configurada para usar {provider}, que utiliza OAuth en lugar de una clave API. Ejecuta hermes auth o hermes model en una terminal para autenticarte y recarga la interfaz web.', + onboarding_oauth_switch_hint: 'O elige un proveedor diferente a continuación para cambiar a la configuración con clave API:', onboarding_notice_workspace: 'Estos valores reutilizan las mismas APIs de configuración que la app normal.', onboarding_workspace_label: 'Espacio de trabajo', onboarding_workspace_or_path: 'O introduce la ruta de un espacio de trabajo', diff --git a/static/index.html b/static/index.html index 4890cd2..b399d5a 100644 --- a/static/index.html +++ b/static/index.html @@ -526,7 +526,7 @@
System
Instance version and access controls.
- v0.50.6 + v0.50.7
diff --git a/static/onboarding.js b/static/onboarding.js index 032457a..a55b21c 100644 --- a/static/onboarding.js +++ b/static/onboarding.js @@ -112,6 +112,61 @@ function _renderOnboardingBody(){ const provider=_getOnboardingSetupProvider(ONBOARDING.form.provider)||providers[0]||null; const showBaseUrl=provider&&provider.requires_base_url; const keyHelp=provider?`${t('onboarding_api_key_help_prefix')} ${esc(provider.env_var)}.`:''; + + // OAuth provider path: configured via CLI, no API key input needed. + const currentIsOauth=!!(ONBOARDING.status.setup||{}).current_is_oauth; + const currentProviderName=((ONBOARDING.status.setup||{}).current||{}).provider||''; + if(currentIsOauth){ + const isReady=!!(ONBOARDING.status.system||{}).chat_ready; + const providerLabel=esc(currentProviderName); + if(isReady){ + _setOnboardingNotice(t('onboarding_notice_setup_already_ready'),'success'); + body.innerHTML=` +
+
+
+ ${t('onboarding_oauth_provider_ready_title')} +

${t('onboarding_oauth_provider_ready_body').replace('{provider}',providerLabel)}

+
+
+

${t('onboarding_oauth_switch_hint')}

+ + + ${showBaseUrl?``:''} +

${keyHelp}

`; + } else { + _setOnboardingNotice(t('onboarding_notice_setup_required'),'warn'); + body.innerHTML=` +
+
+
+ ${t('onboarding_oauth_provider_not_ready_title')} +

${t('onboarding_oauth_provider_not_ready_body').replace('{provider}',providerLabel)}

+
+
+

${t('onboarding_oauth_switch_hint')}

+ + + ${showBaseUrl?``:''} +

${keyHelp}

`; + } + const providerSel=$('onboardingProviderSelect'); + if(providerSel) providerSel.value=ONBOARDING.form.provider; + return; + } + _setOnboardingNotice(system.chat_ready?t('onboarding_notice_setup_already_ready'):t('onboarding_notice_setup_required'),system.chat_ready?'success':'info'); body.innerHTML=`