fix(brain): drop --approval-mode yolo from Gemini CLI search
yolo auto-approves every tool call, so a real-time search query could in principle trigger write/shell tools. Default approval mode still auto-runs the CLI's read-only web search in headless mode but never silently approves destructive tools. Verified end-to-end: a grounded query returns a current answer in ~23s with the account OAuth login. Test asserts yolo is absent; specs and docs/llm_contexts.md updated. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -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. Only on the `webSearch` route when `STREAM_BROWSER=false`; the 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 --approval-mode yolo`) 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.
|
||||
- `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.
|
||||
|
||||
|
||||
@@ -33,8 +33,9 @@ info is fetched by a tool the reply engine calls. `STREAM_BROWSER` selects HOW:
|
||||
`UNTRUSTED WEB EXTRACT` envelope. Keeps the 39k-line Python brain dep-free.
|
||||
- Gemini has two auth sub-modes (`GEMINI_AUTH`):
|
||||
- `oauth` (default): shell out to the Gemini CLI (`gemini -p <query> -o json
|
||||
--skip-trust --approval-mode yolo`) authenticated by the user's Google
|
||||
account login. `GEMINI_API_KEY`/`GOOGLE_API_KEY` are stripped from the child
|
||||
--skip-trust`, default approval mode — read-only tools like web search run
|
||||
headless, but write/shell tools are never auto-approved) authenticated by
|
||||
the user's Google account login. `GEMINI_API_KEY`/`GOOGLE_API_KEY` are stripped from the child
|
||||
env, and `GOOGLE_GENAI_USE_GCA=true` is set, so the CLI uses the account
|
||||
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
|
||||
|
||||
@@ -131,7 +131,11 @@ def gemini_cli_search(query: str, timeout: int = 30) -> Optional[str]:
|
||||
env["GOOGLE_GENAI_USE_GCA"] = "true"
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
[binary, "-p", query, "-o", "json", "--skip-trust", "--approval-mode", "yolo"],
|
||||
# Default approval mode (no --yolo): the CLI auto-runs read-only
|
||||
# tools like its web search in headless mode but will not silently
|
||||
# approve write/shell tools, so a search query can't trigger
|
||||
# destructive actions.
|
||||
[binary, "-p", query, "-o", "json", "--skip-trust"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout,
|
||||
|
||||
@@ -17,7 +17,7 @@ Before the DuckDuckGo cascade, `run()` routes by the env flag `STREAM_BROWSER`
|
||||
- **false**: Gemini answers, with the sub-mode chosen by `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 --approval-mode yolo`) using the
|
||||
(`gemini -p <query> -o json --skip-trust`, default approval mode) using the
|
||||
user's Google-account login and the CLI's built-in web-search grounding.
|
||||
`GEMINI_API_KEY` / `GOOGLE_API_KEY` are stripped from the child env so the
|
||||
CLI uses the account login, not API-key auth. Requires a one-time
|
||||
|
||||
@@ -89,3 +89,7 @@ def test_api_key_stripped_from_child_env(monkeypatch):
|
||||
assert captured["env"].get("GOOGLE_GENAI_USE_GCA") == "true"
|
||||
# invoked headless with JSON output
|
||||
assert "-p" in captured["cmd"] and "-o" in captured["cmd"] and "json" in captured["cmd"]
|
||||
# never auto-approve all tools: a search query must not be able to trigger
|
||||
# write/shell tool execution.
|
||||
assert "yolo" not in captured["cmd"]
|
||||
assert "--yolo" not in captured["cmd"]
|
||||
|
||||
Reference in New Issue
Block a user