fix(acp): select gemini-cli 'oauth-personal' auth from cached creds#3396
Conversation
_select_auth_method special-cased codex's 'chatgpt' subscription login (checks ~/.codex/auth.json) but had no handling for gemini-cli's 'oauth-personal' method. So a gemini-cli logged in via Google OAuth (no GEMINI_API_KEY) never received an authenticate() call and session creation failed with a JSON-RPC -32603, even though valid cached credentials existed. Mirror the chatgpt path: when the server offers 'oauth-personal' and ~/.gemini/oauth_creds.json is present, select it (preferred over GEMINI_API_KEY, consistent with chatgpt-over-OPENAI_API_KEY). In a server image the creds file is absent, so the GEMINI_API_KEY fallback is unaffected. Verified end-to-end against the pinned @google/gemini-cli@0.38.0: the SDK now authenticates via oauth-personal and creates a session with no API key. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Python API breakage checks — ✅ PASSEDResult: ✅ PASSED |
REST API breakage checks (OpenAPI) — ✅ PASSEDResult: ✅ PASSED |
all-hands-bot
left a comment
There was a problem hiding this comment.
🟢 Taste Rating: Good taste — small, direct parity with the existing cached ChatGPT auth path.
[RISK ASSESSMENT]
- [Overall PR]
⚠️ Risk Assessment: 🟢 LOW
Auth-method selection only, with focused unit coverage and no dependency or public API changes.
VERDICT: ✅ Worth merging. Focused tests passed: uv run pytest tests/sdk/agent/test_acp_agent.py::TestSelectAuthMethod.
This review was created by an AI agent (OpenHands) on behalf of the user.
Was this automated review useful? React with 👍 or 👎 to this review to help us measure review quality.
Workflow run: https://github.com/OpenHands/software-agent-sdk/actions/runs/26497416747
Coverage Report •
|
||||||||||||||||||||
all-hands-bot
left a comment
There was a problem hiding this comment.
✅ QA Report: PASS
The SDK auth-selection behavior now matches the PR goal: cached Gemini OAuth credentials select oauth-personal, while API-key fallback still works when the cache is absent.
Does this PR achieve its stated goal?
Yes. I exercised the changed SDK behavior with real acp.schema.AuthMethod objects and a temporary user home containing ~/.gemini/oauth_creds.json: on origin/main, the cached-OAuth/no-key case returned None, while the PR branch returned 'oauth-personal'. I also verified the intended precedence (oauth-personal beats GEMINI_API_KEY) and fallback behavior (gemini-api-key is still selected when no OAuth cache exists).
| Phase | Result |
|---|---|
| Environment Setup | ✅ make build completed successfully with the uv workspace environment |
| CI Status | ⏳ No failures observed; 23 checks successful, 4 skipped, 8 still in progress at review time |
| Functional Verification | ✅ Before/after SDK auth-selection probe confirms the fix and fallback behavior |
Functional Verification
Test 1: Gemini cached OAuth is selected before API-key fallback
Step 1 — Reproduce / establish baseline (without the fix):
Ran git checkout --detach origin/main && OPENHANDS_SUPPRESS_BANNER=1 uv run python /tmp/qa_acp_auth_probe.py:
commit: 58771eeb
cached_oauth_without_api_key: None
cached_oauth_with_api_key: 'gemini-api-key'
no_oauth_with_api_key: 'gemini-api-key'
no_oauth_no_api_key: None
This confirms the reported bug in the base branch: even when the offered ACP methods include oauth-personal and a Gemini OAuth cache file exists, the SDK does not select OAuth. With both cached OAuth and GEMINI_API_KEY, base falls through to gemini-api-key instead of preferring the cached personal OAuth login.
Step 2 — Apply the PR's changes:
Checked out fix-acp-gemini-oauth-auth at 7cfdf967e1dd11acfd3292e3fb4376cb06f4b619.
Step 3 — Re-run with the fix in place:
Ran git checkout fix-acp-gemini-oauth-auth && OPENHANDS_SUPPRESS_BANNER=1 uv run python /tmp/qa_acp_auth_probe.py:
commit: 7cfdf967
cached_oauth_without_api_key: 'oauth-personal'
cached_oauth_with_api_key: 'oauth-personal'
no_oauth_with_api_key: 'gemini-api-key'
no_oauth_no_api_key: None
This shows the fix works for the stated behavior: cached Gemini OAuth now selects oauth-personal without requiring GEMINI_API_KEY, OAuth takes precedence when both credentials are available, and the existing server-image/API-key fallback remains intact when the OAuth cache is absent.
Unable to Verify
I did not run a live gemini-cli --acp session backed by a real Google OAuth login because this QA environment does not contain valid ~/.gemini/oauth_creds.json credentials. I avoided presenting fake OAuth credentials as evidence of live Google authentication. Future QA would be stronger with AGENTS.md guidance for a credentials-independent ACP auth smoke test or a sanctioned local Gemini OAuth test fixture.
Issues Found
None.
This QA review was created by an AI agent (OpenHands) on behalf of the user.
Problem
_select_auth_methodspecial-cases codex-acp'schatgptsubscription login (checks~/.codex/auth.json) but had no handling for gemini-cli'soauth-personalmethod. So agemini-clilogged in via Google OAuth (i.e.~/.gemini/oauth_creds.jsonpresent, noGEMINI_API_KEY) never received anauthenticate()call — the SDK logged"ACP server offers auth methods ['oauth-personal', 'gemini-api-key', ...] but no matching env var is set"and session creation failed with a JSON-RPC-32603even though valid cached credentials existed.Fix
Mirror the
chatgptpath: when the server offersoauth-personaland~/.gemini/oauth_creds.jsonexists, select it. Precedence matches the established design (OAuth/subscription login is preferred over an explicit API key, exactly likechatgptoverOPENAI_API_KEY).Server images are unaffected: there's no interactive OAuth login there, so
oauth_creds.jsonis absent and theGEMINI_API_KEYfallback is used exactly as before. This only fixes local/dev usage of an OAuth-logged-in gemini-cli.Validation
TestSelectAuthMethod, 4 new cases): creds-file present →oauth-personal; preferred overGEMINI_API_KEY; falls back to the key when the creds file is absent;Nonewhen neither is available. Fulltests/sdk/agent/test_acp_agent.py: 192 passed.@google/gemini-cli@0.38.0(the version in the agent-server Dockerfile): the SDK now logsAuthenticating with ACP method: oauth-personal, with zero "no matching env var" warnings, and creates a working session with no API key. Before this change the same setup failed at session creation with-32603.Context
Independent of #3390 (runtime
switch_acp_model). Surfaced while validating ACP model switching for OpenHands/agent-canvas#769 — this auth gap was the actual reason gemini-cli was effectively "untested": the SDK couldn't even establish a gemini session under OAuth auth.🤖 Generated with Claude Code
Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.13-nodejs22-slimgolang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:7cfdf96-pythonRun
All tags pushed for this build
About Multi-Architecture Support
7cfdf96-python) is a multi-arch manifest supporting both amd64 and arm647cfdf96-python-amd64) are also available if needed