fix(gemini): tighten native routing and streaming replay
- only use the native adapter for the canonical Gemini native endpoint - keep custom and /openai base URLs on the OpenAI-compatible path - preserve Hermes keepalive transport injection for native Gemini clients - stabilize streaming tool-call replay across repeated SSE events - add follow-up tests for base_url precedence, async streaming, and duplicate tool-call chunks
This commit is contained in:
@@ -13,7 +13,7 @@ class TestCustomProvidersValidation:
|
||||
issues = validate_config_structure({
|
||||
"custom_providers": {
|
||||
"name": "Generativelanguage.googleapis.com",
|
||||
"base_url": "https://generativelanguage.googleapis.com/v1beta/openai",
|
||||
"base_url": "https://generativelanguage.googleapis.com/v1beta",
|
||||
"api_key": "xxx",
|
||||
"model": "models/gemini-2.5-flash",
|
||||
"rate_limit_delay": 2.0,
|
||||
|
||||
@@ -210,8 +210,10 @@ class TestGeminiAgentInit:
|
||||
def test_gemini_agent_uses_native_client(self, monkeypatch):
|
||||
monkeypatch.setenv("GOOGLE_API_KEY", "AIzaSy_REAL_KEY")
|
||||
with patch("agent.gemini_native_adapter.GeminiNativeClient") as mock_client, \
|
||||
patch("run_agent.OpenAI") as mock_openai:
|
||||
patch("run_agent.OpenAI") as mock_openai, \
|
||||
patch("run_agent.ContextCompressor") as mock_compressor:
|
||||
mock_client.return_value = MagicMock()
|
||||
mock_compressor.return_value = MagicMock(context_length=1048576, threshold_tokens=524288)
|
||||
from run_agent import AIAgent
|
||||
AIAgent(
|
||||
model="gemini-2.5-flash",
|
||||
@@ -222,6 +224,38 @@ class TestGeminiAgentInit:
|
||||
assert mock_client.called
|
||||
mock_openai.assert_not_called()
|
||||
|
||||
def test_gemini_custom_base_url_keeps_openai_client(self, monkeypatch):
|
||||
monkeypatch.setenv("GOOGLE_API_KEY", "AIzaSy_REAL_KEY")
|
||||
with patch("agent.gemini_native_adapter.GeminiNativeClient") as mock_client, \
|
||||
patch("run_agent.OpenAI") as mock_openai, \
|
||||
patch("run_agent.ContextCompressor") as mock_compressor:
|
||||
mock_openai.return_value = MagicMock()
|
||||
mock_compressor.return_value = MagicMock(context_length=128000, threshold_tokens=64000)
|
||||
from run_agent import AIAgent
|
||||
AIAgent(
|
||||
model="gemini-2.5-flash",
|
||||
provider="gemini",
|
||||
api_key="AIzaSy_REAL_KEY",
|
||||
base_url="https://proxy.example.com/v1",
|
||||
)
|
||||
mock_openai.assert_called_once()
|
||||
|
||||
def test_gemini_openai_compat_base_url_keeps_openai_client(self, monkeypatch):
|
||||
monkeypatch.setenv("GOOGLE_API_KEY", "AIzaSy_REAL_KEY")
|
||||
with patch("agent.gemini_native_adapter.GeminiNativeClient") as mock_client, \
|
||||
patch("run_agent.OpenAI") as mock_openai, \
|
||||
patch("run_agent.ContextCompressor") as mock_compressor:
|
||||
mock_openai.return_value = MagicMock()
|
||||
mock_compressor.return_value = MagicMock(context_length=1048576, threshold_tokens=524288)
|
||||
from run_agent import AIAgent
|
||||
AIAgent(
|
||||
model="gemini-2.5-flash",
|
||||
provider="gemini",
|
||||
api_key="AIzaSy_REAL_KEY",
|
||||
base_url="https://generativelanguage.googleapis.com/v1beta/openai",
|
||||
)
|
||||
mock_openai.assert_called_once()
|
||||
|
||||
def test_gemini_resolve_provider_client_uses_native_client(self, monkeypatch):
|
||||
"""resolve_provider_client('gemini') should build GeminiNativeClient."""
|
||||
monkeypatch.setenv("GEMINI_API_KEY", "AIzaSy_TEST_KEY")
|
||||
@@ -233,6 +267,16 @@ class TestGeminiAgentInit:
|
||||
assert mock_client.called
|
||||
mock_openai.assert_not_called()
|
||||
|
||||
def test_gemini_resolve_provider_client_keeps_openai_for_non_native_base_url(self, monkeypatch):
|
||||
monkeypatch.setenv("GOOGLE_API_KEY", "AIzaSy_TEST_KEY")
|
||||
monkeypatch.setenv("GEMINI_BASE_URL", "https://proxy.example.com/v1")
|
||||
with patch("agent.gemini_native_adapter.GeminiNativeClient") as mock_client, \
|
||||
patch("agent.auxiliary_client.OpenAI") as mock_openai:
|
||||
mock_openai.return_value = MagicMock()
|
||||
from agent.auxiliary_client import resolve_provider_client
|
||||
resolve_provider_client("gemini")
|
||||
mock_openai.assert_called_once()
|
||||
|
||||
|
||||
# ── models.dev Integration ──
|
||||
|
||||
|
||||
Reference in New Issue
Block a user