Skip to content

gemini provider: env allowlists drop GOOGLE_GEMINI_BASE_URL (required for custom endpoints like OneChats proxy) #193

@SevenX77

Description

@SevenX77

Summary

Gemini CLI agents spawned by CCB cannot honor custom endpoints (proxy providers such as OneChats) because two independent env allowlists drop the env variable that Gemini CLI specifically reads for endpoint override: GOOGLE_GEMINI_BASE_URL.

End-to-end symptom: Gemini agent tries to call https://generativelanguage.googleapis.com (Google's production API) with a proxy-issued `sk-...` key → API_KEY_INVALID.

Evidence

Tested on ${CCB_VERSION} installed at ~/.local/share/codex-dual/. Host shell exports:

```bash
export GOOGLE_GEMINI_BASE_URL="https://chatapi.onechats.ai"
export GEMINI_MODEL="gemini-3.1-pro-preview"
export GEMINI_API_KEY="sk-..."
```

Outside CCB (direct `gemini` CLI invocation) — requests succeed, traffic goes to the proxy.

Inside CCB agent pane — request fails with:

```json
{"error": {"code": 400, "message": "API key not valid...",
"details": [{"metadata": {"service": "generativelanguage.googleapis.com"}}]}}
```

The `service` field confirms the CLI defaulted to Google's production endpoint, meaning `GOOGLE_GEMINI_BASE_URL` was never in its env.

```
$ cat /proc/$PID_OF_GEMINI_NODE/environ | tr '\0' '\n' | grep -iE '^(GEMINI|GOOGLE)'
GEMINI_API_KEY=sk-...
GEMINI_ROOT=...

GOOGLE_GEMINI_BASE_URL is missing

GEMINI_MODEL is missing

```

Root cause

Two hardcoded allowlists filter the env on its way from the caller shell → ccbd → tmux server → agent pane → Gemini CLI process:

  1. `lib/runtime_env/control_plane.py` — `_CONTROL_PLANE_ALLOWLIST`:

    • Includes: `GEMINI_API_KEY`, `GOOGLE_API_KEY`, `GOOGLE_API_BASE`, `GOOGLE_GENAI_USE_VERTEXAI`
    • Missing: `GOOGLE_GEMINI_BASE_URL`, `GEMINI_MODEL`
    • Additionally `CONTROL_PLANE_BLOCKED_PREFIXES` includes `'GEMINI'`, explicitly blocking any non-allowlisted `GEMINI_*` var (which kills `GEMINI_MODEL`).
  2. `lib/provider_profiles/materializer.py` — `_API_ENV_KEYS['gemini']`:

    • Same vocabulary, same gap — filters again at provider-profile materialization.

Claude provider handles this gracefully because `ANTHROPIC_BASE_URL` IS allowlisted. The gemini vocabulary uses an older Google Generative AI SDK naming convention (`GOOGLE_API_BASE`) that the current Gemini CLI does not honor as an endpoint override — empirical test with renaming `GOOGLE_GEMINI_BASE_URL` → `GOOGLE_API_BASE` reproduces the same "API_KEY_INVALID" failure against the production endpoint, proving the CLI ignores `GOOGLE_API_BASE`.

Fix

Minimal two-line patch to each file (tested locally, Gemini pane traffic now correctly routes to the custom endpoint):

```diff

lib/provider_profiles/materializer.py

  • 'gemini': {'GEMINI_API_KEY', 'GOOGLE_API_KEY', 'GOOGLE_API_BASE', 'GOOGLE_GENAI_USE_VERTEXAI'},
  • 'gemini': {'GEMINI_API_KEY', 'GOOGLE_API_KEY', 'GOOGLE_API_BASE', 'GOOGLE_GENAI_USE_VERTEXAI',
  •           'GOOGLE_GEMINI_BASE_URL', 'GEMINI_MODEL'},
    

lib/runtime_env/control_plane.py _CONTROL_PLANE_ALLOWLIST

 'GEMINI_API_KEY',
  • 'GEMINI_MODEL',
    'GOOGLE_API_BASE',
    'GOOGLE_API_KEY',
  • 'GOOGLE_GEMINI_BASE_URL',
    'GOOGLE_GENAI_USE_VERTEXAI',
    ```

Longer-term direction (discussion, not part of the fix)

The allowlists are hardcoded in source. When a user needs a new var (custom proxy, vendor-specific knob), they have to fork or locally patch CCB. A config-driven extension point would be preferable — e.g. `ccb.config` could declare `provider_profile.env_allowlist: [NEW_VAR_1, NEW_VAR_2]` which gets merged into the base set at materialisation time. Out of scope for this issue but worth tracking as a separate enhancement.

Affected versions

Reproduced on CCB as installed via the standard codex-dual layout at `~/.local/share/codex-dual/` on Linux (`Linux 5.15.0-176-generic`).

🤖 Filed via Claude Code after empirical reproduction + local patch verification.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions