Skip to content

Commit 62a6a04

Browse files
committed
df
1 parent 37ba871 commit 62a6a04

File tree

4 files changed

+187
-0
lines changed

4 files changed

+187
-0
lines changed

openevolve/cli.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ async def main_async() -> int:
9797
config.llm.secondary_model = args.secondary_model
9898
print(f"Using secondary model: {config.llm.secondary_model}")
9999

100+
# Rebuild models list to apply CLI overrides
101+
if args.primary_model or args.secondary_model:
102+
config.llm.rebuild_models()
103+
print(f"Applied CLI model overrides - active models:")
104+
for i, model in enumerate(config.llm.models):
105+
print(f" Model {i+1}: {model.name} (weight: {model.weight})")
106+
100107
# Initialize OpenEvolve
101108
try:
102109
openevolve = OpenEvolve(

openevolve/config.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,51 @@ def update_model_params(self, args: Dict[str, Any], overwrite: bool = False) ->
128128
if overwrite or getattr(model, key, None) is None:
129129
setattr(model, key, value)
130130

131+
def rebuild_models(self) -> None:
132+
"""Rebuild the models list after primary_model/secondary_model field changes"""
133+
# Clear existing models lists
134+
self.models = []
135+
self.evaluator_models = []
136+
137+
# Re-run model generation logic from __post_init__
138+
if self.primary_model:
139+
# Create primary model
140+
primary_model = LLMModelConfig(
141+
name=self.primary_model, weight=self.primary_model_weight or 1.0
142+
)
143+
self.models.append(primary_model)
144+
145+
if self.secondary_model:
146+
# Create secondary model (only if weight > 0)
147+
if self.secondary_model_weight is None or self.secondary_model_weight > 0:
148+
secondary_model = LLMModelConfig(
149+
name=self.secondary_model,
150+
weight=(
151+
self.secondary_model_weight
152+
if self.secondary_model_weight is not None
153+
else 0.2
154+
),
155+
)
156+
self.models.append(secondary_model)
157+
158+
# If no evaluator models are defined, use the same models as for evolution
159+
if not self.evaluator_models:
160+
self.evaluator_models = self.models.copy()
161+
162+
# Update models with shared configuration values
163+
shared_config = {
164+
"api_base": self.api_base,
165+
"api_key": self.api_key,
166+
"temperature": self.temperature,
167+
"top_p": self.top_p,
168+
"max_tokens": self.max_tokens,
169+
"timeout": self.timeout,
170+
"retries": self.retries,
171+
"retry_delay": self.retry_delay,
172+
"random_seed": self.random_seed,
173+
}
174+
self.update_model_params(shared_config)
175+
131176

132177
@dataclass
133178
class PromptConfig:

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ dev = [
2626
"black>=22.0.0",
2727
"isort>=5.10.0",
2828
"mypy>=0.950",
29+
"requests>=2.28.0",
2930
]
3031

3132
[tool.black]

tests/test_cli_model_override.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
"""
2+
Test CLI model override functionality (GitHub issue #245)
3+
"""
4+
import unittest
5+
import tempfile
6+
import os
7+
8+
from openevolve.config import Config, load_config
9+
10+
11+
class TestCLIModelOverride(unittest.TestCase):
12+
"""Test that CLI model overrides work correctly"""
13+
14+
def test_rebuild_models_with_both_models(self):
15+
"""Test rebuilding models with both primary and secondary models"""
16+
config = Config()
17+
18+
# Initially no models
19+
self.assertEqual(len(config.llm.models), 0)
20+
21+
# Set CLI overrides
22+
config.llm.primary_model = "gpt-4"
23+
config.llm.secondary_model = "gpt-3.5-turbo"
24+
25+
# Models list should still be empty before rebuild
26+
self.assertEqual(len(config.llm.models), 0)
27+
28+
# Rebuild models
29+
config.llm.rebuild_models()
30+
31+
# Now should have both models
32+
self.assertEqual(len(config.llm.models), 2)
33+
self.assertEqual(config.llm.models[0].name, "gpt-4")
34+
self.assertEqual(config.llm.models[0].weight, 1.0)
35+
self.assertEqual(config.llm.models[1].name, "gpt-3.5-turbo")
36+
self.assertEqual(config.llm.models[1].weight, 0.2)
37+
38+
def test_rebuild_models_primary_only(self):
39+
"""Test rebuilding with only primary model"""
40+
config = Config()
41+
config.llm.primary_model = "claude-3-opus"
42+
43+
config.llm.rebuild_models()
44+
45+
self.assertEqual(len(config.llm.models), 1)
46+
self.assertEqual(config.llm.models[0].name, "claude-3-opus")
47+
self.assertEqual(config.llm.models[0].weight, 1.0)
48+
49+
def test_rebuild_models_with_weights(self):
50+
"""Test rebuilding with custom weights"""
51+
config = Config()
52+
config.llm.primary_model = "gpt-4"
53+
config.llm.primary_model_weight = 0.8
54+
config.llm.secondary_model = "gpt-3.5-turbo"
55+
config.llm.secondary_model_weight = 0.5
56+
57+
config.llm.rebuild_models()
58+
59+
self.assertEqual(len(config.llm.models), 2)
60+
self.assertEqual(config.llm.models[0].weight, 0.8)
61+
self.assertEqual(config.llm.models[1].weight, 0.5)
62+
63+
def test_rebuild_models_zero_weight_secondary(self):
64+
"""Test that secondary model with zero weight is excluded"""
65+
config = Config()
66+
config.llm.primary_model = "gpt-4"
67+
config.llm.secondary_model = "gpt-3.5-turbo"
68+
config.llm.secondary_model_weight = 0.0
69+
70+
config.llm.rebuild_models()
71+
72+
# Should only have primary model
73+
self.assertEqual(len(config.llm.models), 1)
74+
self.assertEqual(config.llm.models[0].name, "gpt-4")
75+
76+
def test_rebuild_preserves_shared_config(self):
77+
"""Test that rebuilding preserves shared configuration"""
78+
config = Config()
79+
config.llm.api_base = "https://custom-api.com/v1"
80+
config.llm.temperature = 0.8
81+
config.llm.primary_model = "custom-model"
82+
83+
config.llm.rebuild_models()
84+
85+
# Model should inherit shared configuration
86+
self.assertEqual(config.llm.models[0].api_base, "https://custom-api.com/v1")
87+
self.assertEqual(config.llm.models[0].temperature, 0.8)
88+
89+
def test_rebuild_models_with_config_file_override(self):
90+
"""Test CLI override of config file models"""
91+
config_content = """
92+
llm:
93+
primary_model: "original-model"
94+
temperature: 0.5
95+
"""
96+
97+
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
98+
f.write(config_content)
99+
config_path = f.name
100+
101+
try:
102+
# Load config from file
103+
config = load_config(config_path)
104+
105+
# Verify original model is loaded
106+
self.assertEqual(config.llm.models[0].name, "original-model")
107+
108+
# Apply CLI override
109+
config.llm.primary_model = "overridden-model"
110+
config.llm.rebuild_models()
111+
112+
# Should now use overridden model
113+
self.assertEqual(len(config.llm.models), 1)
114+
self.assertEqual(config.llm.models[0].name, "overridden-model")
115+
# Should preserve other settings
116+
self.assertEqual(config.llm.temperature, 0.5)
117+
118+
finally:
119+
os.unlink(config_path)
120+
121+
def test_evaluator_models_updated_after_rebuild(self):
122+
"""Test that evaluator_models list is also updated after rebuild"""
123+
config = Config()
124+
config.llm.primary_model = "test-model"
125+
126+
config.llm.rebuild_models()
127+
128+
# Evaluator models should be populated from main models
129+
self.assertEqual(len(config.llm.evaluator_models), 1)
130+
self.assertEqual(config.llm.evaluator_models[0].name, "test-model")
131+
132+
133+
if __name__ == '__main__':
134+
unittest.main()

0 commit comments

Comments
 (0)