feat: support custom base_url for Gemini native adapter - #21747
Open
li0near wants to merge 1 commit into
Open
Conversation
li0near
force-pushed
the
fix/gemini-custom-base-url
branch
2 times, most recently
from
May 8, 2026 08:01
4078f6c to
7f4c3ef
Compare
li0near
force-pushed
the
fix/gemini-custom-base-url
branch
2 times, most recently
from
May 8, 2026 08:53
1b8da05 to
49a5e27
Compare
When provider is explicitly set to "gemini", use the native Gemini REST
adapter for any base_url that doesn't end in /openai — matching how
other providers (Anthropic, OpenAI, Copilot) work unconditionally.
Previously, is_native_gemini_base_url() gated the native adapter on
the presence of "generativelanguage.googleapis.com" in the URL. This
made Gemini the only provider with a domain-based gate in
_create_openai_client(). With a custom base_url (e.g. a local proxy),
the domain check would fail and silently fall through to the OpenAI-
compatible client, sending the wrong request format to endpoints
expecting Gemini's native models/{model}:generateContent REST API.
URLs ending in /openai (e.g. generativelanguage.googleapis.com/v1beta/
openai) continue to fall through to the OpenAI client, as those
endpoints speak OpenAI format by design.
li0near
force-pushed
the
fix/gemini-custom-base-url
branch
from
May 11, 2026 03:58
49a5e27 to
1c7d686
Compare
teknium1
reviewed
Jul 13, 2026
teknium1
left a comment
Contributor
There was a problem hiding this comment.
Thanks for documenting the proxy use case. Current main has an explicit contrary routing contract, so this needs a maintainer design decision before salvage.
Problems
- Commit
d393104baddeliberately limited the native adapter to the canonical Gemini endpoint and kept custom base URLs on the OpenAI-compatible path. That contract remains inagent/gemini_native_adapter.py:55-62and is used by the live client factory atagent/agent_runtime_helpers.py:1671-1693. - The PR changes the former implementation in
run_agent.py; currentrun_agent.py:3987-3990is only a forwarder afterc42fa94afextracted the implementation. - The predicate also controls auxiliary routing (
agent/auxiliary_client.py:1855-1859,1895-1899,4904-4911), streaming (agent/chat_completion_helpers.py:2105-2112), and native request filtering (agent/transports/chat_completions.py:621-630). A one-site port would not establish a coherent endpoint contract.
Suggested changes
- First resolve whether the intentional custom-endpoint policy from
d393104badshould change. If approved, update the shared classification contract and all consumers, with an end-to-end proxy-path test.
Automated hermes-sweeper review.
|
|
||
| base_url = str(client_kwargs.get("base_url", "") or "") | ||
| if is_native_gemini_base_url(base_url): | ||
| # URLs ending in /openai are OpenAI-compatible endpoints (e.g. |
Contributor
There was a problem hiding this comment.
Current main has extracted this implementation: run_agent.py:3987-3990 now forwards to agent/agent_runtime_helpers.py:1643. Port the change to the live helper only after resolving the explicit custom-endpoint routing policy in d393104bad; changing this former implementation cannot be salvaged as-is.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When
provider: "gemini"is explicitly configured, use the native Gemini REST adapter (models/{model}:generateContent) for anybase_urlthat doesn't end in/openai— matching how other providers work unconditionally in_create_openai_client().Gemini was the only provider with a domain-based gate:
copilot-acpgoogle-gemini-cligeminiopenai/customanthropicProblem
Previously,
is_native_gemini_base_url()checked forgenerativelanguage.googleapis.comin the URL before using the native adapter. With a custombase_url(e.g. a local proxy that speaks Gemini's native REST protocol), the check would fail and silently fall through to the OpenAI-compatible client — sending/v1/chat/completionsformat instead of/models/{model}:generateContent.Fix
Replaced the domain-based
is_native_gemini_base_url()check with a simpler/openaisuffix check:base_url(including custom proxies) → native Gemini adapter/openai(e.g.generativelanguage.googleapis.com/v1beta/openai) → OpenAI client (these speak OpenAI format)base_url→ native adapter (defaults to Google's endpoint internally)Example config (cli-config.yaml)
Test plan
test_gemini_custom_base_urlto assert native client is usedtest_gemini_openai_compat_base_url_keeps_openai_clientunchanged (verifies/openaisuffix fallback)provider: "gemini"with nobase_urlstill defaults to Google's endpointprovider: "gemini"with custombase_urluses native adapter