Skip to content

Commit fba8dea

Browse files
CopilotCaellwyn
andcommitted
Add unit tests for chimera model functionality
Co-authored-by: Caellwyn <[email protected]>
1 parent 863f5c6 commit fba8dea

File tree

1 file changed

+266
-0
lines changed

1 file changed

+266
-0
lines changed

test_aiagent.py

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
"""
2+
Unit tests for AIAgent class, focusing on chimera model functionality.
3+
4+
These tests verify that the chimera model is properly set up to use OpenRouter
5+
and expose the issue where "chimera" is passed directly as the model name
6+
instead of a valid OpenRouter model identifier.
7+
"""
8+
import pytest
9+
from unittest.mock import Mock, patch, MagicMock
10+
import os
11+
import sys
12+
13+
14+
# Mock streamlit before importing aiagent
15+
@pytest.fixture(autouse=True)
16+
def mock_streamlit():
17+
"""Mock streamlit to avoid import issues in tests"""
18+
mock_st = MagicMock()
19+
mock_st.secrets = {}
20+
with patch.dict('sys.modules', {'streamlit': mock_st}):
21+
yield mock_st
22+
23+
24+
@pytest.fixture
25+
def mock_env_vars():
26+
"""Set up mock environment variables for API keys"""
27+
env_vars = {
28+
"GOOGLE_API_KEY": "fake-google-key",
29+
"OPENAI_API_KEY": "fake-openai-key",
30+
"OPEN_ROUTER_API_KEY": "fake-openrouter-key",
31+
"ANTHROPIC_API_KEY": "fake-anthropic-key",
32+
"TOGETHER_API_KEY": "fake-together-key",
33+
}
34+
with patch.dict(os.environ, env_vars):
35+
yield env_vars
36+
37+
38+
@pytest.fixture
39+
def mock_genai():
40+
"""Mock Google generative AI"""
41+
with patch('aiagent.genai') as mock:
42+
mock.configure = Mock()
43+
mock.GenerativeModel = Mock()
44+
yield mock
45+
46+
47+
@pytest.fixture
48+
def mock_openai():
49+
"""Mock OpenAI client"""
50+
with patch('aiagent.openai') as mock:
51+
mock_client = Mock()
52+
mock.OpenAI = Mock(return_value=mock_client)
53+
yield mock
54+
55+
56+
class TestChimeraModelSetup:
57+
"""Tests for chimera model setup and configuration"""
58+
59+
def test_set_model_chimera_uses_openrouter_base_url(self, mock_env_vars, mock_genai, mock_openai):
60+
"""Test that chimera model uses OpenRouter API endpoint"""
61+
from aiagent import AIAgent
62+
63+
agent = AIAgent(model="chimera")
64+
65+
# Verify OpenAI client was called with OpenRouter base URL
66+
mock_openai.OpenAI.assert_called()
67+
call_args = mock_openai.OpenAI.call_args
68+
assert call_args.kwargs.get('base_url') == "https://openrouter.ai/api/v1"
69+
assert call_args.kwargs.get('api_key') == "fake-openrouter-key"
70+
71+
def test_set_model_chimera_stores_model_name(self, mock_env_vars, mock_genai, mock_openai):
72+
"""Test that chimera model name is stored"""
73+
from aiagent import AIAgent
74+
75+
agent = AIAgent(model="chimera")
76+
77+
assert agent.model == "chimera"
78+
79+
def test_set_summary_model_chimera_uses_openrouter(self, mock_env_vars, mock_genai, mock_openai):
80+
"""Test that chimera summary model uses OpenRouter API"""
81+
from aiagent import AIAgent
82+
83+
agent = AIAgent(model="gpt-4o-mini")
84+
agent.set_summary_model("chimera")
85+
86+
# Verify OpenAI client was created with OpenRouter base URL
87+
calls = mock_openai.OpenAI.call_args_list
88+
openrouter_calls = [c for c in calls if c.kwargs.get('base_url') == "https://openrouter.ai/api/v1"]
89+
assert len(openrouter_calls) > 0
90+
91+
92+
class TestChimeraModelQuery:
93+
"""Tests for chimera model query functionality - exposes the silent failure bug"""
94+
95+
def test_query_with_chimera_passes_model_name_to_api(self, mock_env_vars, mock_genai, mock_openai):
96+
"""
97+
Test that documents the bug: 'chimera' is passed directly to OpenRouter API.
98+
99+
OpenRouter expects actual model identifiers (e.g., 'openai/gpt-4',
100+
'anthropic/claude-3-haiku'), not 'chimera'. This causes silent failures.
101+
"""
102+
from aiagent import AIAgent
103+
104+
# Setup mock response
105+
mock_completion = Mock()
106+
mock_completion.choices = [Mock()]
107+
mock_completion.choices[0].message.content = "Test response"
108+
mock_completion.usage = Mock()
109+
mock_completion.usage.prompt_tokens = 100
110+
mock_completion.usage.completion_tokens = 50
111+
112+
mock_client = Mock()
113+
mock_client.chat.completions.create.return_value = mock_completion
114+
mock_openai.OpenAI.return_value = mock_client
115+
116+
# Mock moderation API
117+
mock_moderation = Mock()
118+
mock_moderation.results = [Mock()]
119+
mock_moderation.results[0].flagged = False
120+
mock_client.moderations.create.return_value = mock_moderation
121+
122+
agent = AIAgent(model="chimera")
123+
agent.query("Hello")
124+
125+
# Get what model name was passed to the API
126+
create_call_kwargs = mock_client.chat.completions.create.call_args.kwargs
127+
model_passed = create_call_kwargs.get('model')
128+
129+
# This documents the bug: "chimera" is passed as model name
130+
# OpenRouter expects real model identifiers like "openai/gpt-4"
131+
assert model_passed == "chimera", (
132+
"Expected 'chimera' to be passed to API (documenting the bug). "
133+
"When this test fails with a different model name, the bug is fixed."
134+
)
135+
136+
def test_query_with_chimera_uses_chat_completions_api(self, mock_env_vars, mock_genai, mock_openai):
137+
"""Test that chimera uses the OpenAI-compatible chat completions API"""
138+
from aiagent import AIAgent
139+
140+
# Setup mock
141+
mock_completion = Mock()
142+
mock_completion.choices = [Mock()]
143+
mock_completion.choices[0].message.content = "Test response"
144+
mock_completion.usage = Mock()
145+
mock_completion.usage.prompt_tokens = 100
146+
mock_completion.usage.completion_tokens = 50
147+
148+
mock_client = Mock()
149+
mock_client.chat.completions.create.return_value = mock_completion
150+
mock_openai.OpenAI.return_value = mock_client
151+
152+
mock_moderation = Mock()
153+
mock_moderation.results = [Mock()]
154+
mock_moderation.results[0].flagged = False
155+
mock_client.moderations.create.return_value = mock_moderation
156+
157+
agent = AIAgent(model="chimera")
158+
response = agent.query("Hello")
159+
160+
# Verify chat.completions.create was called
161+
mock_client.chat.completions.create.assert_called_once()
162+
assert response == "Test response"
163+
164+
def test_query_chimera_includes_required_parameters(self, mock_env_vars, mock_genai, mock_openai):
165+
"""Test that chimera query includes all required parameters"""
166+
from aiagent import AIAgent
167+
168+
mock_completion = Mock()
169+
mock_completion.choices = [Mock()]
170+
mock_completion.choices[0].message.content = "Test response"
171+
mock_completion.usage = Mock()
172+
mock_completion.usage.prompt_tokens = 100
173+
mock_completion.usage.completion_tokens = 50
174+
175+
mock_client = Mock()
176+
mock_client.chat.completions.create.return_value = mock_completion
177+
mock_openai.OpenAI.return_value = mock_client
178+
179+
mock_moderation = Mock()
180+
mock_moderation.results = [Mock()]
181+
mock_moderation.results[0].flagged = False
182+
mock_client.moderations.create.return_value = mock_moderation
183+
184+
agent = AIAgent(model="chimera")
185+
agent.query("Hello", temperature=0.5, max_tokens=100)
186+
187+
call_kwargs = mock_client.chat.completions.create.call_args.kwargs
188+
189+
assert 'model' in call_kwargs
190+
assert 'messages' in call_kwargs
191+
assert call_kwargs['temperature'] == 0.5
192+
assert call_kwargs['max_tokens'] == 100
193+
194+
195+
class TestChimeraModelErrorHandling:
196+
"""Tests for error handling when chimera model fails"""
197+
198+
def test_chimera_invalid_model_error(self, mock_env_vars, mock_genai, mock_openai):
199+
"""Test behavior when OpenRouter returns an invalid model error"""
200+
from aiagent import AIAgent
201+
202+
# Simulate OpenRouter error for invalid model
203+
mock_client = Mock()
204+
mock_client.chat.completions.create.side_effect = Exception(
205+
"Error: The model `chimera` does not exist"
206+
)
207+
mock_openai.OpenAI.return_value = mock_client
208+
209+
agent = AIAgent(model="chimera")
210+
211+
with pytest.raises(Exception) as exc_info:
212+
agent.query("Hello")
213+
214+
assert "chimera" in str(exc_info.value)
215+
216+
217+
class TestModelSwitching:
218+
"""Tests for switching between models including chimera"""
219+
220+
def test_switch_to_chimera_updates_base_url(self, mock_env_vars, mock_genai, mock_openai):
221+
"""Test that switching to chimera uses OpenRouter endpoint"""
222+
from aiagent import AIAgent
223+
224+
agent = AIAgent(model="gpt-4o-mini")
225+
agent.set_model("chimera")
226+
227+
# Find the call that sets up chimera
228+
calls = mock_openai.OpenAI.call_args_list
229+
last_call = calls[-1]
230+
assert last_call.kwargs.get('base_url') == "https://openrouter.ai/api/v1"
231+
232+
def test_switch_from_chimera_to_gpt(self, mock_env_vars, mock_genai, mock_openai):
233+
"""Test that switching from chimera to GPT works correctly"""
234+
from aiagent import AIAgent
235+
236+
agent = AIAgent(model="chimera")
237+
agent.set_model("gpt-4o-mini")
238+
239+
calls = mock_openai.OpenAI.call_args_list
240+
last_call = calls[-1]
241+
assert last_call.kwargs.get('base_url') == "https://api.openai.com/v1"
242+
243+
244+
class TestApiKeyHandling:
245+
"""Tests for API key handling with chimera model"""
246+
247+
def test_chimera_uses_open_router_api_key(self, mock_genai, mock_openai):
248+
"""Test that chimera model uses OPEN_ROUTER_API_KEY"""
249+
with patch.dict(os.environ, {
250+
"GOOGLE_API_KEY": "fake-google-key",
251+
"OPENAI_API_KEY": "fake-openai-key",
252+
"OPEN_ROUTER_API_KEY": "test-openrouter-key-123",
253+
}):
254+
from aiagent import AIAgent
255+
256+
agent = AIAgent(model="chimera")
257+
258+
calls = mock_openai.OpenAI.call_args_list
259+
chimera_calls = [c for c in calls if c.kwargs.get('base_url') == "https://openrouter.ai/api/v1"]
260+
261+
assert len(chimera_calls) > 0
262+
assert chimera_calls[-1].kwargs.get('api_key') == "test-openrouter-key-123"
263+
264+
265+
if __name__ == "__main__":
266+
pytest.main([__file__, "-v"])

0 commit comments

Comments
 (0)