fix(auth): set active_provider after hermes auth add google-gemini-cli
hermes auth add google-gemini-cli called pool.add_entry() but never wrote to providers["google-gemini-cli"] or set active_provider in auth.json. _model_section_has_credentials() checks get_active_provider() first; with active_provider unset and no api_key_env_vars configured for oauth_external providers, the setup wizard reported "No inference provider configured" even after a successful OAuth login. Add _mark_google_gemini_cli_active() in auth.py: writes a minimal provider state entry (email for display only) and calls _save_provider_state() to set active_provider. The function deliberately does not copy access_token or refresh_token — those are managed by agent.google_oauth in the Google credential file and must not be duplicated in auth.json where they would become stale. pool.add_entry() is retained so "hermes auth list" continues to show the entry. Runtime credential resolution continues to use agent.google_oauth directly. Mirrors the fix applied to openai-codex (#37517) and xai-oauth (#37576).
This commit is contained in:
@ -2100,6 +2100,24 @@ def get_qwen_auth_status() -> Dict[str, Any]:
|
||||
# Actual HTTP traffic goes to https://cloudcode-pa.googleapis.com/v1internal:*.
|
||||
# =============================================================================
|
||||
|
||||
def _mark_google_gemini_cli_active(creds: Dict[str, Any]) -> None:
|
||||
"""Set active_provider to google-gemini-cli in auth.json.
|
||||
|
||||
The actual OAuth tokens live in the Google credential file managed by
|
||||
agent.google_oauth. This function only writes a minimal provider-state
|
||||
entry (email for display) and sets active_provider so that
|
||||
get_active_provider() and _model_section_has_credentials() detect the
|
||||
provider for the setup wizard and status commands.
|
||||
"""
|
||||
with _auth_store_lock():
|
||||
auth_store = _load_auth_store()
|
||||
state: Dict[str, Any] = {}
|
||||
if creds.get("email"):
|
||||
state["email"] = str(creds["email"])
|
||||
_save_provider_state(auth_store, "google-gemini-cli", state)
|
||||
_save_auth_store(auth_store)
|
||||
|
||||
|
||||
def resolve_gemini_oauth_runtime_credentials(
|
||||
*,
|
||||
force_refresh: bool = False,
|
||||
|
||||
@ -353,6 +353,7 @@ def auth_add_command(args) -> None:
|
||||
from agent.google_oauth import run_gemini_oauth_login_pure
|
||||
|
||||
creds = run_gemini_oauth_login_pure()
|
||||
auth_mod._mark_google_gemini_cli_active(creds)
|
||||
label = (getattr(args, "label", None) or "").strip() or (
|
||||
creds.get("email") or _oauth_default_label(provider, len(pool.entries()) + 1)
|
||||
)
|
||||
|
||||
@ -97,6 +97,51 @@ def test_auth_add_anthropic_oauth_persists_pool_entry(tmp_path, monkeypatch):
|
||||
assert entry["expires_at_ms"] == 1711234567000
|
||||
|
||||
|
||||
def test_auth_add_google_gemini_cli_sets_active_provider(tmp_path, monkeypatch):
|
||||
"""hermes auth add google-gemini-cli must set active_provider in auth.json.
|
||||
|
||||
Tokens are managed by agent.google_oauth (written to the Google credential
|
||||
file by start_oauth_flow). The auth.json entry must record active_provider
|
||||
so get_active_provider() and _model_section_has_credentials() detect the
|
||||
provider — without storing tokens that would become stale.
|
||||
"""
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
|
||||
_write_auth_store(tmp_path, {"version": 1, "providers": {}})
|
||||
monkeypatch.setattr(
|
||||
"agent.google_oauth.run_gemini_oauth_login_pure",
|
||||
lambda: {
|
||||
"access_token": "ya29.test-token",
|
||||
"refresh_token": "google-refresh",
|
||||
"email": "user@example.com",
|
||||
"expires_at_ms": 9999999999000,
|
||||
"project_id": "my-project",
|
||||
},
|
||||
)
|
||||
|
||||
from hermes_cli.auth_commands import auth_add_command
|
||||
|
||||
class _Args:
|
||||
provider = "google-gemini-cli"
|
||||
auth_type = "oauth"
|
||||
api_key = None
|
||||
label = None
|
||||
|
||||
auth_add_command(_Args())
|
||||
|
||||
payload = json.loads((tmp_path / "hermes" / "auth.json").read_text())
|
||||
assert payload["active_provider"] == "google-gemini-cli"
|
||||
state = payload["providers"]["google-gemini-cli"]
|
||||
# Only email stored — no access_token/refresh_token (those live in
|
||||
# the Google OAuth credential file managed by agent.google_oauth).
|
||||
assert state.get("email") == "user@example.com"
|
||||
assert "access_token" not in state
|
||||
assert "refresh_token" not in state
|
||||
# pool entry from pool.add_entry() still present for hermes auth list
|
||||
entries = payload["credential_pool"]["google-gemini-cli"]
|
||||
entry = next(item for item in entries if item["source"] == "manual:google_pkce")
|
||||
assert entry["access_token"] == "ya29.test-token"
|
||||
|
||||
|
||||
def test_auth_add_nous_oauth_persists_pool_entry(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
|
||||
_write_auth_store(tmp_path, {"version": 1, "providers": {}})
|
||||
|
||||
Reference in New Issue
Block a user