mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-02 02:01:47 +00:00
feat(gemini): add Google Gemini (OAuth) inference provider
Adds 'google-gemini-cli' as a first-class inference provider using Authorization Code + PKCE (S256) OAuth against Google's accounts.google.com, hitting the OpenAI-compatible Gemini endpoint (v1beta/openai) with a Bearer access token. Users sign in with their Google account — no API-key copy-paste. Synthesized from three competing PRs per multi-PR design analysis: - Clean PKCE module structure shaped after #10176 (thanks @sliverp) - Cross-process file lock (fcntl POSIX / msvcrt Windows) with thread-local re-entrancy counter from #10779 (thanks @newarthur) - Rejects #6745's subprocess approach entirely (different paradigm) Improvements over the competing PRs: - Port fallback: if 8085 is taken, bind ephemeral port instead of failing - Preserves refresh_token when Google omits one (correct per Google spec) - Accepts both full redirect URL and bare code in paste fallback - doctor.py health check (neither PR had this) - No regression in _OAUTH_CAPABLE_PROVIDERS (#10779 dropped anthropic/nous) - No bundled unrelated features (#10779 mixed in persona/personality routing) Storage: - ~/.hermes/auth/google_oauth.json (0o600, atomic write via fsync+replace) - Cross-process fcntl/msvcrt lock with 30s timeout - Refresh 5 min before expiry on every request via get_valid_access_token Provider registration (9-point checklist): - auth.py: PROVIDER_REGISTRY entry, aliases (gemini-cli, gemini-oauth), resolve_gemini_oauth_runtime_credentials, get_gemini_oauth_auth_status, get_auth_status() dispatch - models.py: _PROVIDER_MODELS catalog, CANONICAL_PROVIDERS entry, aliases - providers.py: HermesOverlay, ALIASES entries - runtime_provider.py: resolve_runtime_provider() dispatch branch - config.py: OPTIONAL_ENV_VARS for HERMES_GEMINI_CLIENT_ID/_SECRET/_BASE_URL - main.py: _model_flow_google_gemini_cli, select_provider_and_model dispatch - auth_commands.py: add-to-pool handler, _OAUTH_CAPABLE_PROVIDERS - doctor.py: 'Google Gemini OAuth' status line Client ID: Not shipped. Users register a Desktop OAuth client in Google Cloud Console (Generative Language API) and set HERMES_GEMINI_CLIENT_ID in ~/.hermes/.env. Documented in website/docs/integrations/providers.md. Tests: 44 new unit tests covering PKCE S256 roundtrip, credential I/O (permissions + atomic write), cross-process lock, port fallback, paste fallback (URL + bare code), token exchange/refresh, rotation handling, get_valid_access_token refresh semantics, runtime provider dispatch, alias resolution, and regression guards for _OAUTH_CAPABLE_PROVIDERS. Docs: new 'Google Gemini via OAuth' section in providers.md with full walkthrough including GCP Desktop OAuth client registration, and env var table updated in environment-variables.md. Closes partial work in #6745, #10176, #10779 (to be closed with credit once this merges).
This commit is contained in:
parent
387aa9afc9
commit
1e5ee33f68
12 changed files with 1693 additions and 4 deletions
|
|
@ -35,12 +35,68 @@ You need at least one way to connect to an LLM. Use `hermes model` to switch pro
|
|||
| **DeepSeek** | `DEEPSEEK_API_KEY` in `~/.hermes/.env` (provider: `deepseek`) |
|
||||
| **Hugging Face** | `HF_TOKEN` in `~/.hermes/.env` (provider: `huggingface`, aliases: `hf`) |
|
||||
| **Google / Gemini** | `GOOGLE_API_KEY` (or `GEMINI_API_KEY`) in `~/.hermes/.env` (provider: `gemini`) |
|
||||
| **Google Gemini (OAuth)** | `hermes model` → "Google Gemini (OAuth)" (provider: `google-gemini-cli`, browser PKCE login, requires `HERMES_GEMINI_CLIENT_ID`) |
|
||||
| **Custom Endpoint** | `hermes model` → choose "Custom endpoint" (saved in `config.yaml`) |
|
||||
|
||||
:::tip Model key alias
|
||||
In the `model:` config section, you can use either `default:` or `model:` as the key name for your model ID. Both `model: { default: my-model }` and `model: { model: my-model }` work identically.
|
||||
:::
|
||||
|
||||
|
||||
### Google Gemini via OAuth (`google-gemini-cli`)
|
||||
|
||||
The `google-gemini-cli` provider lets you authenticate with your Google account
|
||||
via a browser-based Authorization Code + PKCE flow — no API key copy-paste, and
|
||||
credentials are refreshed automatically before every request.
|
||||
|
||||
**Quick start:**
|
||||
|
||||
```bash
|
||||
# 1. Set your OAuth client ID (see "Registering a Desktop OAuth client" below)
|
||||
export HERMES_GEMINI_CLIENT_ID="your-client-id.apps.googleusercontent.com"
|
||||
|
||||
# 2. Run the login flow
|
||||
hermes model
|
||||
# → pick "Google Gemini (OAuth)"
|
||||
# → a browser opens to accounts.google.com, sign in, Hermes captures the callback
|
||||
|
||||
# 3. Chat as normal
|
||||
hermes chat
|
||||
```
|
||||
|
||||
**Storage:** tokens are persisted to `~/.hermes/auth/google_oauth.json` with
|
||||
0600 permissions, atomic writes, and a cross-process fcntl lock so multiple
|
||||
Hermes instances can safely share a session.
|
||||
|
||||
**Endpoint:** requests are routed to Google's OpenAI-compatible Gemini endpoint
|
||||
(`https://generativelanguage.googleapis.com/v1beta/openai`) with a Bearer
|
||||
access token. Supports the full Gemini 2.5 / 3.x lineup and Gemma open models.
|
||||
|
||||
#### Registering a Desktop OAuth client
|
||||
|
||||
Hermes does not ship with a default OAuth client ID — you register one yourself
|
||||
in Google Cloud Console so quota and consent screens are scoped to your
|
||||
organization:
|
||||
|
||||
1. Go to <https://console.cloud.google.com/apis/credentials>.
|
||||
2. Create (or pick) a project and click **"Create Credentials" → "OAuth client ID"**.
|
||||
3. Choose **Application type: Desktop app**, name it "Hermes Agent".
|
||||
4. Enable the **Generative Language API** for the project under APIs & Services.
|
||||
5. Download the JSON and set `HERMES_GEMINI_CLIENT_ID` in `~/.hermes/.env`
|
||||
(client secret is optional for Desktop clients but can be set via
|
||||
`HERMES_GEMINI_CLIENT_SECRET` if required by your org policy).
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
- **Port 8085 already in use** — Hermes will automatically fall back to an
|
||||
ephemeral port. Add that exact URL to your OAuth client's authorized redirect
|
||||
URIs if Google refuses it.
|
||||
- **"State mismatch — aborting for safety"** — someone hit the callback URL
|
||||
with a stale/forged request. Re-run the login.
|
||||
- **Refresh failures persist** — re-run login (`hermes auth add --provider
|
||||
google-gemini-cli`); stale refresh tokens can happen after password changes
|
||||
or scope revocation.
|
||||
|
||||
:::info Codex Note
|
||||
The OpenAI Codex provider authenticates via device code (open a URL, enter a code). Hermes stores the resulting credentials in its own auth store under `~/.hermes/auth.json` and can import existing Codex CLI credentials from `~/.codex/auth.json` when present. No Codex CLI installation is required.
|
||||
:::
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue