feat: make GEMINI_AUTH=oauth authenticate in Docker
Some checks failed
Release / semantic-release (push) Successful in 25s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-linux (push) Failing after 7m8s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Some checks failed
Release / semantic-release (push) Successful in 25s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-linux (push) Failing after 7m8s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
OAuth cannot be done interactively in the headless container, so the login
must be seeded into the mounted ~/.gemini. Three problems are fixed:
- Mount fragility on the Windows Docker Desktop target: the creds mount
defaulted to ${HOME}/.config/javis/gemini, but ${HOME} is often unset when
compose runs outside a WSL shell, silently mounting the wrong dir. Default is
now the project-local ./docker/gemini-oauth (cross-platform), GEMINI_OAUTH_DIR
still overrides.
- No visibility: when oauth is selected but no login is seeded, the path
silently degraded to DDG/Brave. Added gemini_oauth_ready() + a one-time debug
hint and a startup entrypoint warning (skipped on the browser role, fail-open).
- Seeding guidance: oauth_creds.json is the essential credential (refresh token;
GOOGLE_GENAI_USE_GCA=true forces OAuth), which is what the readiness check and
warning verify; docs recommend copying the whole ~/.gemini for convenience.
Adds docker/gemini-oauth/ seed dir (.gitkeep) with the login files gitignored,
GEMINI_OAUTH_DIR in .env.example, and updates DEPLOY.md, stream_browser_modes.md
and llm_contexts.md. Covered by 3 new tests (10 passed total).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -61,9 +61,19 @@ human-style input (visible on its VNC).
|
||||
|
||||
- Install the NVIDIA driver on Windows and enable GPU in Docker Desktop
|
||||
(Settings → Resources → WSL Integration). Use the `gpu-windows.yml` override.
|
||||
- Paths: named volumes are cross-platform. The Gemini OAuth bind mount defaults
|
||||
to `${HOME}/.config/javis/gemini` (works under WSL); override `GEMINI_OAUTH_DIR`
|
||||
if needed.
|
||||
- Paths: named volumes are cross-platform. The Gemini OAuth login (for
|
||||
`GEMINI_AUTH=oauth`) is bind-mounted from the project-local `./docker/gemini-oauth`
|
||||
into the container's `~/.gemini`. A project-relative path is used so it resolves
|
||||
the same on Windows Docker Desktop and Linux (`${HOME}` is often unset when
|
||||
compose runs from PowerShell/cmd). Seed it once from a machine with a browser and
|
||||
the logged-in Gemini CLI (`npm i -g @google/gemini-cli`, then `gemini` ->
|
||||
"Sign in with Google"), copying the login state:
|
||||
`cp -r ~/.gemini/. docker/gemini-oauth/`. The essential file is `oauth_creds.json`
|
||||
(it holds the refresh token; `GOOGLE_GENAI_USE_GCA=true` forces OAuth, so that is
|
||||
the file the startup readiness check looks for) - copying the whole dir simply also
|
||||
carries the cached account/settings. To reuse an existing host login without
|
||||
copying, set `GEMINI_OAUTH_DIR=~/.gemini` in `.env`. If unseeded, real-time search
|
||||
fail-opens to DDG/Brave and the container logs a `🔑` warning on startup.
|
||||
|
||||
## Known limitation
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ Every distinct LLM call in Jarvis, what feeds it, what consumes it, and how it i
|
||||
- **Weather** ([src/jarvis/tools/builtin/weather.py](src/jarvis/tools/builtin/weather.py), ~line 60) — `ollama_chat_model`, parses location/time/unit from the query.
|
||||
- **Nutrition log_meal** ([src/jarvis/tools/builtin/nutrition/log_meal.py](src/jarvis/tools/builtin/nutrition/log_meal.py), lines 48 & 136) — `ollama_chat_model`, extracts nutrients, confirms logging.
|
||||
- **Gemini real-time search** ([src/jarvis/tools/builtin/realtime_search.py](src/jarvis/tools/builtin/realtime_search.py)) — **external Gemini model**, NOT Ollama. Used on the `webSearch` route whenever the on-screen Chrome path is NOT active: either `STREAM_BROWSER=false` (broadcast disabled) or `STREAM_BROWSER=true` with the live broadcast currently off (`context.broadcasting` False). Sub-mode is `cfg.gemini_auth` (env `GEMINI_AUTH`, default `oauth`):
|
||||
- `oauth` (default) `gemini_cli_search()` — shells out to the Gemini CLI (`gemini -p <query> -o json --skip-trust`, default approval mode) authenticated by the user's Google-account login (`GEMINI_API_KEY`/`GOOGLE_API_KEY` stripped from the child env, `GOOGLE_GENAI_USE_GCA=true` set to select OAuth); model is whatever the CLI/account defaults to. Uses the CLI's built-in web-search grounding. Bounded by a 30s subprocess timeout.
|
||||
- `oauth` (default) `gemini_cli_search()` — shells out to the Gemini CLI (`gemini -p <query> -o json --skip-trust`, default approval mode) authenticated by the user's Google-account login (`GEMINI_API_KEY`/`GOOGLE_API_KEY` stripped from the child env, `GOOGLE_GENAI_USE_GCA=true` set to select OAuth); model is whatever the CLI/account defaults to. Uses the CLI's built-in web-search grounding. Bounded by a 30s subprocess timeout. The login lives in `~/.gemini`; in Docker that is the project-local `docker/gemini-oauth` bind mount (override `GEMINI_OAUTH_DIR`), which the operator seeds once. `gemini_oauth_ready()` checks `~/.gemini/oauth_creds.json` and logs a one-time fallback hint (and the entrypoint warns on startup) when oauth is selected but unseeded, since the path otherwise silently degrades to DDG/Brave.
|
||||
- `apikey` `gemini_search()` — one REST `generateContent` call (`gemini_model`, default `gemini-2.0-flash`) with the `google_search` grounding tool; keyed by `GEMINI_API_KEY`.
|
||||
Both return the fenced UNTRUSTED-WEB-EXTRACT envelope consumed by the main loop (#1). Fail-open: CLI missing / login expired / quota 429 / timeout / errors / missing key all fall through to the DDG cascade. The `STREAM_BROWSER=true` route (`browser_search()`) makes NO LLM call — it drives Chrome and scrapes Google results.
|
||||
|
||||
|
||||
@@ -59,7 +59,12 @@ entry) and falls back to the master flag so behaviour is unchanged.
|
||||
login (not API-key auth) and fails fast when no login exists rather than
|
||||
erroring on "no auth method". The CLI is resolved from `PATH` or
|
||||
`~/.local/bin/gemini`; install with `npm i -g @google/gemini-cli` and sign
|
||||
in once via interactive `gemini` ("Sign in with Google").
|
||||
in once via interactive `gemini` ("Sign in with Google"). In Docker the login
|
||||
can't be done interactively in the headless container: seed it instead by
|
||||
copying a logged-in `~/.gemini` into the project-local `docker/gemini-oauth`
|
||||
bind mount (or set `GEMINI_OAUTH_DIR`); the container reads/refreshes the
|
||||
token there. `gemini_oauth_ready()` gates an actionable log hint, and the
|
||||
entrypoint warns on startup, when oauth is selected but no login is seeded.
|
||||
- `apikey`: the REST endpoint (`generativelanguage.googleapis.com`) via stdlib
|
||||
`urllib` with the `google_search` grounding tool - no SDK dependency.
|
||||
- Both Gemini paths and the browser path return the same
|
||||
|
||||
Reference in New Issue
Block a user