Accept GOOGLE_API_KEY for local Gemini eval

This workspace uses GOOGLE_API_KEY as the canonical Google credential. Accept it ahead of the Gemini-specific aliases so the local evaluation harness can run without a separate GEMINI_API_KEY export.

Validation: uv run python -m unittest tests.test_env_project tests.test_evaluate_search_quality and a one-shot keychain-backed resolution check.
This commit is contained in:
Jeffrey Sperling
2026-03-13 19:25:29 -07:00
parent 8eda5fad5c
commit 3a0f3d8b19
5 changed files with 56 additions and 2 deletions
+2 -1
View File
@@ -34,7 +34,8 @@ uv run python scripts/evaluate_search_quality.py \
Gemini configuration:
- set `GEMINI_API_KEY` to enable LLM judging
- preferred on this workspace: set `GOOGLE_API_KEY`
- also accepted: `GEMINI_API_KEY` or `GOOGLE_GENAI_API_KEY`
- optional: set `GEMINI_MODEL`
- default model is `gemini-3-pro-preview` for the direct Gemini API
+17 -1
View File
@@ -276,6 +276,22 @@ def extract_gemini_text(payload: Dict[str, Any]) -> str:
raise ValueError("Gemini response did not contain text")
def resolve_google_judge_api_key(config: Dict[str, Any]) -> Optional[str]:
"""Resolve the local canonical Google API key name.
This workspace conventionally uses GOOGLE_API_KEY. We also accept the
more Gemini-specific aliases for portability.
"""
return (
os.environ.get("GOOGLE_API_KEY")
or config.get("GOOGLE_API_KEY")
or os.environ.get("GEMINI_API_KEY")
or config.get("GEMINI_API_KEY")
or os.environ.get("GOOGLE_GENAI_API_KEY")
or config.get("GOOGLE_GENAI_API_KEY")
)
def call_gemini_judge(api_key: str, model: str, prompt: str) -> Dict[str, Any]:
body = {
"contents": [{"parts": [{"text": prompt}]}],
@@ -497,7 +513,7 @@ def main() -> int:
judge_config = envlib.get_config()
judge_provider = args.judge_provider
gemini_api_key = judge_config.get("GEMINI_API_KEY")
gemini_api_key = resolve_google_judge_api_key(judge_config)
judge_model = args.judge_model or judge_config.get("GEMINI_MODEL") or DEFAULT_JUDGE_MODEL
if judge_provider == "auto":
judge_provider = "gemini" if gemini_api_key else "none"
+2
View File
@@ -243,7 +243,9 @@ def get_config() -> Dict[str, Any]:
keys = [
('XAI_API_KEY', None),
('GOOGLE_API_KEY', None),
('GEMINI_API_KEY', None),
('GOOGLE_GENAI_API_KEY', None),
('OPENROUTER_API_KEY', None),
('PARALLEL_API_KEY', None),
('BRAVE_API_KEY', None),
+15
View File
@@ -96,6 +96,21 @@ class TestConfigPrecedence(unittest.TestCase):
self.assertEqual(config['GEMINI_API_KEY'], 'gem-key')
self.assertEqual(config['GEMINI_MODEL'], 'gemini-3-pro-preview')
def test_google_api_key_loads_from_project_env(self):
import tempfile
with tempfile.TemporaryDirectory() as tmpdir:
project_dir = Path(tmpdir) / ".claude"
project_dir.mkdir()
project_env = project_dir / "last30days.env"
project_env.write_text("GOOGLE_API_KEY=google-key\n")
with patch.object(Path, 'cwd', return_value=Path(tmpdir)), \
patch.object(env, 'CONFIG_FILE', None), \
patch.dict(os.environ, {}, clear=False):
os.environ.pop('GOOGLE_API_KEY', None)
config = env.get_config()
self.assertEqual(config['GOOGLE_API_KEY'], 'google-key')
class TestConfigSource(unittest.TestCase):
"""Tests for _CONFIG_SOURCE tracking."""
+20
View File
@@ -77,5 +77,25 @@ class TestPathWithoutNode(unittest.TestCase):
self.assertEqual(filtered, "/usr/bin:/opt/homebrew/bin")
class TestJudgeKeyResolution(unittest.TestCase):
def test_prefers_google_api_key(self):
config = {
"GOOGLE_API_KEY": "google-key",
"GEMINI_API_KEY": "gem-key",
"GOOGLE_GENAI_API_KEY": "genai-key",
}
self.assertEqual(evalsq.resolve_google_judge_api_key(config), "google-key")
def test_falls_back_to_gemini_aliases(self):
self.assertEqual(
evalsq.resolve_google_judge_api_key({"GEMINI_API_KEY": "gem-key"}),
"gem-key",
)
self.assertEqual(
evalsq.resolve_google_judge_api_key({"GOOGLE_GENAI_API_KEY": "genai-key"}),
"genai-key",
)
if __name__ == "__main__":
unittest.main()