Skip to content

Tracking: make Google Gemini work end-to-end (config, security, errors, docs) #13052

Description

@aaronlippold

Summary

Gemini is nominally supported in Continue, but several independent defects make it fail in practice — most visibly for users behind corporate proxies, users on newly created API keys, and anyone relying on embeddings. A common report is "the Gemini API works fine in Google's Python sample, but the same key fails when I put it in my Continue config."

This issue tracks a set of small, independently reviewable PRs that fix each layer. I've split the work into four scoped PRs rather than one large change, since they touch different packages and some overlap with existing (currently stalled) PRs — I'd be glad to coordinate with those authors before merge. This issue is the shared anchor; each PR links back here.

Changes reviewers will want to know about up front

  • Token usage — non-breaking: completion_tokens now counts reasoning ("thoughts") tokens for thinking models, matching the OpenAI-compatible usage spec. No shape change; values rise for thinking-enabled models, which were previously undercounted (Google's totalTokenCount already included them).
  • Live-test model IDs — non-breaking: main.test.ts's live suite moves from gemini-2.5-* to the -latest aliases so it runs for newly created API keys; the trade-off is the suite is no longer pinned to a fixed model.
  • New public export — additive: getProxyFromEnv is re-exported from @continuedev/fetch (an existing internal helper) so the adapter shares one source of truth for env-proxy interpretation.

Root causes (each verified against the source)

  1. Config silently ignored on the chat path. The Gemini adapter built the @google/genai client with only apiKeyapiBase, requestOptions.headers, timeout, and all proxy/TLS options were dropped for chat/stream while embed() honored them. Python's requests honors HTTPS_PROXY/REQUESTS_CA_BUNDLE out of the box, which is why a plain sample works where a gateway-fronted Continue config does not.
  2. API key leaked into a URL. core/llm/fetchModels.ts passed the Gemini key as a ?key= query parameter when listing models — keys in URLs leak via server logs, proxies, and referer headers.
  3. Errors rendered as raw JSON / "Unknown error." Gemini quota/RESOURCE_EXHAUSTED responses carry the real message double-nested in JSON that nothing extracted, so failures were undiagnosable.
  4. embed() broken for bare model names. new URL("<model>:batchEmbedContents", apiBase) parsed the model name as a URL scheme and discarded apiBase; the response was also read from the wrong field (batchEmbedContents vs Google's embeddings). Anyone enabling @codebase/embeddings hit this.
  5. Docs pointed at gated model IDs. New API keys cannot invoke gemini-2.5-* ("no longer available to new users") even though the API still lists them; examples now use the -latest aliases (checked against the live API).

The four PRs

PR Scope Files Related upstream work Depends on
1 — Gemini adapter Honor apiBase/headers/timeout/proxy/TLS on all paths; surface nested errors; SDK-native embed; thinking-token accounting; serialize the fetch swap packages/openai-adapters/**, one export line in packages/fetch/src/index.ts Addresses #12008; builds on #12014 (credit to its author) and extends it to proxy/TLS on all paths; incorporates the embed fix from #12517
2 — Key-in-URL Send x-goog-api-key header instead of ?key= in fetchModels core/llm/fetchModels.ts (+ test) Same fix as #12190 (credit to its author)
3 — CLI errors Extract nested provider error messages in formatError extensions/cli/src/util/formatError.ts (+ test) Adapter/CLI counterpart to #13014 (which fixes the GUI layer)
4 — Docs Provider pages + a new end-to-end Gemini guide, real model IDs, role matrix, proxy/gateway config docs/** PR 1 (documents its behavior)

PRs 1–3 share no files and can be reviewed and merged in any order. PR 4 follows PR 1. The Closes #12008 keyword will live in PR 1's own description (a tracking issue doesn't auto-close).

Verification

Every behavioral change is backed by tests that run against a no-mocks local rig, plus manual runs against the real Google API (with a real key, outside CI):

  • Automated, no mocks: proxy routing (real local proxy, request hit-counters), TLS and mutual-TLS (self-signed mini-CA, passphrase-protected key), custom headers on the wire, embed through a proxy, env-var-proxy engagement with NO_PROXY bypass, config-over-env precedence, timeout abort, and cross-config credential isolation.
  • Manual, against the live API: Google's own live model tests pass once pointed at current model IDs (including tool calls, on two models); fetchModels returns real models with the key absent from the URL.

Other notes for reviewers

  • openssl is used by the TLS test rig at beforeAll (present on the CI image; same approach as packages/fetch's existing e2e tests).
  • The "Supported roles" table is a new docs convention applied to the Gemini and Vertex pages; happy to extend it to the other providers if that's wanted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions