[agents] Offer Gemini as a model option alongside OpenRouter
Some checks failed
ci / test (push) Has been cancelled
ci / build-and-deploy (push) Has been cancelled

This commit is contained in:
2026-07-31 23:52:54 -04:00
parent 1e338dec2d
commit 42ccdf5507
6 changed files with 117 additions and 22 deletions

View File

@ -8,6 +8,7 @@ from agents.providers import (
_parse_opencode_events,
agent_prompt,
gemini_agent_prompt,
list_gemini_agent_models,
list_openrouter_free_models,
opencode_agent_prompt,
openrouter_agent_prompt,
@ -315,8 +316,8 @@ def test_list_openrouter_free_models_filters_free():
mock_get.assert_called_once()
assert models == [
{"id": "free/model-b", "name": "Alpha"},
{"id": "free/model-a", "name": "Bee"},
{"provider": "openrouter", "id": "free/model-b", "name": "Alpha"},
{"provider": "openrouter", "id": "free/model-a", "name": "Bee"},
]
@ -332,6 +333,28 @@ def test_list_openrouter_free_models_skips_missing_pricing():
assert list_openrouter_free_models() == []
def test_list_gemini_agent_models(settings):
settings.GOOGLE_AI_API_KEY = "test-key"
settings.GEMINI_AGENT_MODELS = "gemini-2.5-flash, gemini-3.6-flash"
assert list_gemini_agent_models() == [
{
"provider": "gemini",
"id": "gemini-2.5-flash",
"name": "gemini-2.5-flash",
},
{
"provider": "gemini",
"id": "gemini-3.6-flash",
"name": "gemini-3.6-flash",
},
]
def test_list_gemini_agent_models_no_key(settings):
settings.GOOGLE_AI_API_KEY = ""
assert list_gemini_agent_models() == []
# --- scrobbler ---
@ -580,10 +603,14 @@ def test_manual_scrobble_view_routes_plain_text_to_agent(mock_delay, client, use
@patch("agents.views.list_openrouter_free_models")
def test_agent_model_select_view_lists_models(mock_models, client, user):
mock_models.return_value = [
{"id": "free/model-a", "name": "Model A"},
{"id": "free/model-b", "name": "Model B"},
@patch("agents.views.list_gemini_agent_models")
def test_agent_model_select_view_lists_models(mock_gemini, mock_or, client, user):
mock_gemini.return_value = [
{"provider": "gemini", "id": "gemini-3.6-flash", "name": "gemini-3.6-flash"}
]
mock_or.return_value = [
{"provider": "openrouter", "id": "free/model-a", "name": "Model A"},
{"provider": "openrouter", "id": "free/model-b", "name": "Model B"},
]
client.force_login(user)
session = client.session
@ -595,12 +622,17 @@ def test_agent_model_select_view_lists_models(mock_models, client, user):
assert b"what is 2+2?" in response.content
assert b"free/model-a" in response.content
assert b"Model A" in response.content
assert client.session["agent_models"] == mock_models.return_value
assert b"gemini-3.6-flash" in response.content
assert b"Google Gemini" in response.content
expected = mock_gemini.return_value + mock_or.return_value
assert client.session["agent_models"] == expected
@patch("agents.views.list_openrouter_free_models")
def test_agent_model_select_view_handles_errors(mock_models, client, user):
mock_models.side_effect = ValueError("boom")
@patch("agents.views.list_gemini_agent_models")
def test_agent_model_select_view_handles_errors(mock_gemini, mock_or, client, user):
mock_gemini.return_value = []
mock_or.side_effect = ValueError("boom")
client.force_login(user)
session = client.session
session["agent_prompt"] = "hi"
@ -611,11 +643,8 @@ def test_agent_model_select_view_handles_errors(mock_models, client, user):
assert b"Could not load models from OpenRouter" in response.content
@patch("agents.views.list_openrouter_free_models")
@patch("scrobbles.tasks.scrobble_agent_session_prompt.delay")
def test_agent_scrobble_from_model_creates_session(
mock_delay, mock_models, client, user
):
def test_agent_scrobble_from_model_creates_session(mock_delay, client, user):
client.force_login(user)
session = client.session
session["agent_prompt"] = "what is 2+2?"
@ -635,9 +664,27 @@ def test_agent_scrobble_from_model_creates_session(
assert "agent_prompt" not in client.session
@patch("agents.views.list_openrouter_free_models")
@patch("scrobbles.tasks.scrobble_agent_session_prompt.delay")
def test_agent_scrobble_from_model_missing_model(mock_delay, mock_models, client, user):
def test_agent_scrobble_from_model_gemini_provider(mock_delay, client, user):
client.force_login(user)
session = client.session
session["agent_prompt"] = "what is 2+2?"
session.save()
response = client.post(
reverse("agents:agent_scrobble_from_model"),
{"provider": "gemini", "model": "gemini-3.6-flash", "prompt": "what is 2+2?"},
)
assert response.status_code == 302
scrobble = Scrobble.objects.filter(user_id=user.id).first()
assert scrobble is not None
assert scrobble.agent_session.provider == "gemini"
assert scrobble.agent_session.model == "gemini-3.6-flash"
assert response.url == scrobble.get_absolute_url()
@patch("scrobbles.tasks.scrobble_agent_session_prompt.delay")
def test_agent_scrobble_from_model_missing_model(mock_delay, client, user):
client.force_login(user)
response = client.post(reverse("agents:agent_scrobble_from_model"), {"model": ""})