openevolve 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openevolve/__init__.py +9 -0
- openevolve/cli.py +179 -0
- openevolve/config.py +354 -0
- openevolve/controller.py +568 -0
- openevolve/database.py +1290 -0
- openevolve/evaluation_result.py +54 -0
- openevolve/evaluator.py +506 -0
- openevolve/llm/__init__.py +9 -0
- openevolve/llm/base.py +22 -0
- openevolve/llm/ensemble.py +73 -0
- openevolve/llm/openai.py +114 -0
- openevolve/prompt/__init__.py +8 -0
- openevolve/prompt/sampler.py +494 -0
- openevolve/prompt/templates.py +176 -0
- openevolve/utils/__init__.py +45 -0
- openevolve/utils/async_utils.py +165 -0
- openevolve/utils/code_utils.py +207 -0
- openevolve/utils/format_utils.py +65 -0
- openevolve/utils/metrics_utils.py +66 -0
- openevolve-0.0.1.dist-info/METADATA +325 -0
- openevolve-0.0.1.dist-info/RECORD +25 -0
- openevolve-0.0.1.dist-info/WHEEL +5 -0
- openevolve-0.0.1.dist-info/entry_points.txt +2 -0
- openevolve-0.0.1.dist-info/licenses/LICENSE +201 -0
- openevolve-0.0.1.dist-info/top_level.txt +1 -0
openevolve/__init__.py
ADDED
openevolve/cli.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command-line interface for OpenEvolve
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import logging
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
from typing import Dict, List, Optional
|
|
11
|
+
|
|
12
|
+
from openevolve import OpenEvolve
|
|
13
|
+
from openevolve.config import Config, load_config
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def parse_args() -> argparse.Namespace:
|
|
19
|
+
"""Parse command-line arguments"""
|
|
20
|
+
parser = argparse.ArgumentParser(description="OpenEvolve - Evolutionary coding agent")
|
|
21
|
+
|
|
22
|
+
parser.add_argument("initial_program", help="Path to the initial program file")
|
|
23
|
+
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"evaluation_file", help="Path to the evaluation file containing an 'evaluate' function"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
parser.add_argument("--config", "-c", help="Path to configuration file (YAML)", default=None)
|
|
29
|
+
|
|
30
|
+
parser.add_argument("--output", "-o", help="Output directory for results", default=None)
|
|
31
|
+
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--iterations", "-i", help="Maximum number of iterations", type=int, default=None
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"--target-score", "-t", help="Target score to reach", type=float, default=None
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--log-level",
|
|
42
|
+
"-l",
|
|
43
|
+
help="Logging level",
|
|
44
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
45
|
+
default="INFO",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
parser.add_argument(
|
|
49
|
+
"--checkpoint",
|
|
50
|
+
help="Path to checkpoint directory to resume from (e.g., openevolve_output/checkpoints/checkpoint_50)",
|
|
51
|
+
default=None,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
parser.add_argument("--api-base", help="Base URL for the LLM API", default=None)
|
|
55
|
+
|
|
56
|
+
parser.add_argument("--primary-model", help="Primary LLM model name", default=None)
|
|
57
|
+
|
|
58
|
+
parser.add_argument("--secondary-model", help="Secondary LLM model name", default=None)
|
|
59
|
+
|
|
60
|
+
return parser.parse_args()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
async def main_async() -> int:
|
|
64
|
+
"""
|
|
65
|
+
Main asynchronous entry point
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Exit code
|
|
69
|
+
"""
|
|
70
|
+
args = parse_args()
|
|
71
|
+
|
|
72
|
+
# Check if files exist
|
|
73
|
+
if not os.path.exists(args.initial_program):
|
|
74
|
+
print(f"Error: Initial program file '{args.initial_program}' not found")
|
|
75
|
+
return 1
|
|
76
|
+
|
|
77
|
+
if not os.path.exists(args.evaluation_file):
|
|
78
|
+
print(f"Error: Evaluation file '{args.evaluation_file}' not found")
|
|
79
|
+
return 1
|
|
80
|
+
|
|
81
|
+
# Create config object with command-line overrides
|
|
82
|
+
config = None
|
|
83
|
+
if args.api_base or args.primary_model or args.secondary_model:
|
|
84
|
+
# Load base config from file or defaults
|
|
85
|
+
config = load_config(args.config)
|
|
86
|
+
|
|
87
|
+
# Apply command-line overrides
|
|
88
|
+
if args.api_base:
|
|
89
|
+
config.llm.api_base = args.api_base
|
|
90
|
+
print(f"Using API base: {config.llm.api_base}")
|
|
91
|
+
|
|
92
|
+
if args.primary_model:
|
|
93
|
+
config.llm.primary_model = args.primary_model
|
|
94
|
+
print(f"Using primary model: {config.llm.primary_model}")
|
|
95
|
+
|
|
96
|
+
if args.secondary_model:
|
|
97
|
+
config.llm.secondary_model = args.secondary_model
|
|
98
|
+
print(f"Using secondary model: {config.llm.secondary_model}")
|
|
99
|
+
|
|
100
|
+
# Initialize OpenEvolve
|
|
101
|
+
try:
|
|
102
|
+
openevolve = OpenEvolve(
|
|
103
|
+
initial_program_path=args.initial_program,
|
|
104
|
+
evaluation_file=args.evaluation_file,
|
|
105
|
+
config=config,
|
|
106
|
+
config_path=args.config if config is None else None,
|
|
107
|
+
output_dir=args.output,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Load from checkpoint if specified
|
|
111
|
+
if args.checkpoint:
|
|
112
|
+
if not os.path.exists(args.checkpoint):
|
|
113
|
+
print(f"Error: Checkpoint directory '{args.checkpoint}' not found")
|
|
114
|
+
return 1
|
|
115
|
+
print(f"Loading checkpoint from {args.checkpoint}")
|
|
116
|
+
openevolve.database.load(args.checkpoint)
|
|
117
|
+
print(
|
|
118
|
+
f"Checkpoint loaded successfully (iteration {openevolve.database.last_iteration})"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Override log level if specified
|
|
122
|
+
if args.log_level:
|
|
123
|
+
logging.getLogger().setLevel(getattr(logging, args.log_level))
|
|
124
|
+
|
|
125
|
+
# Run evolution
|
|
126
|
+
best_program = await openevolve.run(
|
|
127
|
+
iterations=args.iterations,
|
|
128
|
+
target_score=args.target_score,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Get the checkpoint path
|
|
132
|
+
checkpoint_dir = os.path.join(openevolve.output_dir, "checkpoints")
|
|
133
|
+
latest_checkpoint = None
|
|
134
|
+
if os.path.exists(checkpoint_dir):
|
|
135
|
+
checkpoints = [
|
|
136
|
+
os.path.join(checkpoint_dir, d)
|
|
137
|
+
for d in os.listdir(checkpoint_dir)
|
|
138
|
+
if os.path.isdir(os.path.join(checkpoint_dir, d))
|
|
139
|
+
]
|
|
140
|
+
if checkpoints:
|
|
141
|
+
latest_checkpoint = sorted(
|
|
142
|
+
checkpoints, key=lambda x: int(x.split("_")[-1]) if "_" in x else 0
|
|
143
|
+
)[-1]
|
|
144
|
+
|
|
145
|
+
print(f"\nEvolution complete!")
|
|
146
|
+
print(f"Best program metrics:")
|
|
147
|
+
for name, value in best_program.metrics.items():
|
|
148
|
+
# Handle mixed types: format numbers as floats, others as strings
|
|
149
|
+
if isinstance(value, (int, float)):
|
|
150
|
+
print(f" {name}: {value:.4f}")
|
|
151
|
+
else:
|
|
152
|
+
print(f" {name}: {value}")
|
|
153
|
+
|
|
154
|
+
if latest_checkpoint:
|
|
155
|
+
print(f"\nLatest checkpoint saved at: {latest_checkpoint}")
|
|
156
|
+
print(f"To resume, use: --checkpoint {latest_checkpoint}")
|
|
157
|
+
|
|
158
|
+
return 0
|
|
159
|
+
|
|
160
|
+
except Exception as e:
|
|
161
|
+
print(f"Error: {str(e)}")
|
|
162
|
+
import traceback
|
|
163
|
+
|
|
164
|
+
traceback.print_exc()
|
|
165
|
+
return 1
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def main() -> int:
|
|
169
|
+
"""
|
|
170
|
+
Main entry point
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Exit code
|
|
174
|
+
"""
|
|
175
|
+
return asyncio.run(main_async())
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
if __name__ == "__main__":
|
|
179
|
+
sys.exit(main())
|
openevolve/config.py
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration handling for OpenEvolve
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, List, Optional, Union
|
|
9
|
+
|
|
10
|
+
import yaml
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class LLMModelConfig:
|
|
15
|
+
"""Configuration for a single LLM model"""
|
|
16
|
+
|
|
17
|
+
# API configuration
|
|
18
|
+
api_base: str = None
|
|
19
|
+
api_key: Optional[str] = None
|
|
20
|
+
name: str = None
|
|
21
|
+
|
|
22
|
+
# Weight for model in ensemble
|
|
23
|
+
weight: float = 1.0
|
|
24
|
+
|
|
25
|
+
# Generation parameters
|
|
26
|
+
system_message: Optional[str] = None
|
|
27
|
+
temperature: float = None
|
|
28
|
+
top_p: float = None
|
|
29
|
+
max_tokens: int = None
|
|
30
|
+
|
|
31
|
+
# Request parameters
|
|
32
|
+
timeout: int = None
|
|
33
|
+
retries: int = None
|
|
34
|
+
retry_delay: int = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class LLMConfig(LLMModelConfig):
|
|
39
|
+
"""Configuration for LLM models"""
|
|
40
|
+
|
|
41
|
+
# API configuration
|
|
42
|
+
api_base: str = "https://api.openai.com/v1"
|
|
43
|
+
|
|
44
|
+
# Generation parameters
|
|
45
|
+
system_message: Optional[str] = "system_message"
|
|
46
|
+
temperature: float = 0.7
|
|
47
|
+
top_p: float = 0.95
|
|
48
|
+
max_tokens: int = 4096
|
|
49
|
+
|
|
50
|
+
# Request parameters
|
|
51
|
+
timeout: int = 60
|
|
52
|
+
retries: int = 3
|
|
53
|
+
retry_delay: int = 5
|
|
54
|
+
|
|
55
|
+
# n-model configuration for evolution LLM ensemble
|
|
56
|
+
models: List[LLMModelConfig] = field(default_factory=lambda: [LLMModelConfig()])
|
|
57
|
+
|
|
58
|
+
# n-model configuration for evaluator LLM ensemble
|
|
59
|
+
evaluator_models: List[LLMModelConfig] = field(default_factory=lambda: [])
|
|
60
|
+
|
|
61
|
+
# Backwardes compatibility with primary_model(_weight) options
|
|
62
|
+
primary_model: str = None
|
|
63
|
+
primary_model_weight: float = None
|
|
64
|
+
secondary_model: str = None
|
|
65
|
+
secondary_model_weight: float = None
|
|
66
|
+
|
|
67
|
+
def __post_init__(self):
|
|
68
|
+
"""Post-initialization to set up model configurations"""
|
|
69
|
+
# Handle backward compatibility for primary_model(_weight) and secondary_model(_weight).
|
|
70
|
+
if (self.primary_model or self.primary_model_weight) and len(self.models) < 1:
|
|
71
|
+
# Ensure we have a primary model
|
|
72
|
+
self.models.append(LLMModelConfig())
|
|
73
|
+
if self.primary_model:
|
|
74
|
+
self.models[0].name = self.primary_model
|
|
75
|
+
if self.primary_model_weight:
|
|
76
|
+
self.models[0].weight = self.primary_model_weight
|
|
77
|
+
|
|
78
|
+
if (self.secondary_model or self.secondary_model_weight) and len(self.models) < 2:
|
|
79
|
+
# Ensure we have a second model
|
|
80
|
+
self.models.append(LLMModelConfig())
|
|
81
|
+
if self.secondary_model:
|
|
82
|
+
self.models[1].name = self.secondary_model
|
|
83
|
+
if self.secondary_model_weight:
|
|
84
|
+
self.models[1].weight = self.secondary_model_weight
|
|
85
|
+
|
|
86
|
+
# If no evaluator models are defined, use the same models as for evolution
|
|
87
|
+
if not self.evaluator_models or len(self.evaluator_models) < 1:
|
|
88
|
+
self.evaluator_models = self.models.copy()
|
|
89
|
+
|
|
90
|
+
# Update models with shared configuration values
|
|
91
|
+
shared_config = {
|
|
92
|
+
"api_base": self.api_base,
|
|
93
|
+
"api_key": self.api_key,
|
|
94
|
+
"temperature": self.temperature,
|
|
95
|
+
"top_p": self.top_p,
|
|
96
|
+
"max_tokens": self.max_tokens,
|
|
97
|
+
"timeout": self.timeout,
|
|
98
|
+
"retries": self.retries,
|
|
99
|
+
"retry_delay": self.retry_delay,
|
|
100
|
+
}
|
|
101
|
+
self.update_model_params(shared_config)
|
|
102
|
+
|
|
103
|
+
def update_model_params(self, args: Dict[str, Any], overwrite: bool = False) -> None:
|
|
104
|
+
"""Update model parameters for all models"""
|
|
105
|
+
for model in self.models + self.evaluator_models:
|
|
106
|
+
for key, value in args.items():
|
|
107
|
+
if overwrite or getattr(model, key, None) is None:
|
|
108
|
+
setattr(model, key, value)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@dataclass
|
|
112
|
+
class PromptConfig:
|
|
113
|
+
"""Configuration for prompt generation"""
|
|
114
|
+
|
|
115
|
+
template_dir: Optional[str] = None
|
|
116
|
+
system_message: str = "system_message"
|
|
117
|
+
evaluator_system_message: str = "evaluator_system_message"
|
|
118
|
+
|
|
119
|
+
# Number of examples to include in the prompt
|
|
120
|
+
num_top_programs: int = 3
|
|
121
|
+
num_diverse_programs: int = 2
|
|
122
|
+
|
|
123
|
+
# Template stochasticity
|
|
124
|
+
use_template_stochasticity: bool = True
|
|
125
|
+
template_variations: Dict[str, List[str]] = field(default_factory=dict)
|
|
126
|
+
|
|
127
|
+
# Meta-prompting
|
|
128
|
+
use_meta_prompting: bool = False
|
|
129
|
+
meta_prompt_weight: float = 0.1
|
|
130
|
+
|
|
131
|
+
# Artifact rendering
|
|
132
|
+
include_artifacts: bool = True
|
|
133
|
+
max_artifact_bytes: int = 20 * 1024 # 20KB in prompt
|
|
134
|
+
artifact_security_filter: bool = True
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@dataclass
|
|
138
|
+
class DatabaseConfig:
|
|
139
|
+
"""Configuration for the program database"""
|
|
140
|
+
|
|
141
|
+
# General settings
|
|
142
|
+
db_path: Optional[str] = None # Path to store database on disk
|
|
143
|
+
in_memory: bool = True
|
|
144
|
+
|
|
145
|
+
# Evolutionary parameters
|
|
146
|
+
population_size: int = 1000
|
|
147
|
+
archive_size: int = 100
|
|
148
|
+
num_islands: int = 5
|
|
149
|
+
|
|
150
|
+
# Selection parameters
|
|
151
|
+
elite_selection_ratio: float = 0.1
|
|
152
|
+
exploration_ratio: float = 0.2
|
|
153
|
+
exploitation_ratio: float = 0.7
|
|
154
|
+
diversity_metric: str = "edit_distance" # Options: "edit_distance", "feature_based"
|
|
155
|
+
|
|
156
|
+
# Feature map dimensions for MAP-Elites
|
|
157
|
+
feature_dimensions: List[str] = field(default_factory=lambda: ["score", "complexity"])
|
|
158
|
+
feature_bins: int = 10
|
|
159
|
+
|
|
160
|
+
# Migration parameters for island-based evolution
|
|
161
|
+
migration_interval: int = 50 # Migrate every N generations
|
|
162
|
+
migration_rate: float = 0.1 # Fraction of population to migrate
|
|
163
|
+
|
|
164
|
+
# Random seed for reproducible sampling
|
|
165
|
+
random_seed: Optional[int] = None
|
|
166
|
+
|
|
167
|
+
# Artifact storage
|
|
168
|
+
artifacts_base_path: Optional[str] = None # Defaults to db_path/artifacts
|
|
169
|
+
artifact_size_threshold: int = 32 * 1024 # 32KB threshold
|
|
170
|
+
cleanup_old_artifacts: bool = True
|
|
171
|
+
artifact_retention_days: int = 30
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@dataclass
|
|
175
|
+
class EvaluatorConfig:
|
|
176
|
+
"""Configuration for program evaluation"""
|
|
177
|
+
|
|
178
|
+
# General settings
|
|
179
|
+
timeout: int = 300 # Maximum evaluation time in seconds
|
|
180
|
+
max_retries: int = 3
|
|
181
|
+
|
|
182
|
+
# Resource limits for evaluation
|
|
183
|
+
memory_limit_mb: Optional[int] = None
|
|
184
|
+
cpu_limit: Optional[float] = None
|
|
185
|
+
|
|
186
|
+
# Evaluation strategies
|
|
187
|
+
cascade_evaluation: bool = True
|
|
188
|
+
cascade_thresholds: List[float] = field(default_factory=lambda: [0.5, 0.75, 0.9])
|
|
189
|
+
|
|
190
|
+
# Parallel evaluation
|
|
191
|
+
parallel_evaluations: int = 4
|
|
192
|
+
distributed: bool = False
|
|
193
|
+
|
|
194
|
+
# LLM-based feedback
|
|
195
|
+
use_llm_feedback: bool = False
|
|
196
|
+
llm_feedback_weight: float = 0.1
|
|
197
|
+
|
|
198
|
+
# Artifact handling
|
|
199
|
+
enable_artifacts: bool = True
|
|
200
|
+
max_artifact_storage: int = 100 * 1024 * 1024 # 100MB per program
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@dataclass
|
|
204
|
+
class Config:
|
|
205
|
+
"""Master configuration for OpenEvolve"""
|
|
206
|
+
|
|
207
|
+
# General settings
|
|
208
|
+
max_iterations: int = 10000
|
|
209
|
+
checkpoint_interval: int = 100
|
|
210
|
+
log_level: str = "INFO"
|
|
211
|
+
log_dir: Optional[str] = None
|
|
212
|
+
random_seed: Optional[int] = None
|
|
213
|
+
|
|
214
|
+
# Component configurations
|
|
215
|
+
llm: LLMConfig = field(default_factory=LLMConfig)
|
|
216
|
+
prompt: PromptConfig = field(default_factory=PromptConfig)
|
|
217
|
+
database: DatabaseConfig = field(default_factory=DatabaseConfig)
|
|
218
|
+
evaluator: EvaluatorConfig = field(default_factory=EvaluatorConfig)
|
|
219
|
+
|
|
220
|
+
# Evolution settings
|
|
221
|
+
diff_based_evolution: bool = True
|
|
222
|
+
allow_full_rewrites: bool = False
|
|
223
|
+
max_code_length: int = 10000
|
|
224
|
+
|
|
225
|
+
@classmethod
|
|
226
|
+
def from_yaml(cls, path: Union[str, Path]) -> "Config":
|
|
227
|
+
"""Load configuration from a YAML file"""
|
|
228
|
+
with open(path, "r") as f:
|
|
229
|
+
config_dict = yaml.safe_load(f)
|
|
230
|
+
return cls.from_dict(config_dict)
|
|
231
|
+
|
|
232
|
+
@classmethod
|
|
233
|
+
def from_dict(cls, config_dict: Dict[str, Any]) -> "Config":
|
|
234
|
+
"""Create configuration from a dictionary"""
|
|
235
|
+
# Handle nested configurations
|
|
236
|
+
config = Config()
|
|
237
|
+
|
|
238
|
+
# Update top-level fields
|
|
239
|
+
for key, value in config_dict.items():
|
|
240
|
+
if key not in ["llm", "prompt", "database", "evaluator"] and hasattr(config, key):
|
|
241
|
+
setattr(config, key, value)
|
|
242
|
+
|
|
243
|
+
# Update nested configs
|
|
244
|
+
if "llm" in config_dict:
|
|
245
|
+
llm_dict = config_dict["llm"]
|
|
246
|
+
if "models" in llm_dict:
|
|
247
|
+
llm_dict["models"] = [LLMModelConfig(**m) for m in llm_dict["models"]]
|
|
248
|
+
if "evaluator_models" in llm_dict:
|
|
249
|
+
llm_dict["evaluator_models"] = [
|
|
250
|
+
LLMModelConfig(**m) for m in llm_dict["evaluator_models"]
|
|
251
|
+
]
|
|
252
|
+
config.llm = LLMConfig(**llm_dict)
|
|
253
|
+
if "prompt" in config_dict:
|
|
254
|
+
config.prompt = PromptConfig(**config_dict["prompt"])
|
|
255
|
+
if "database" in config_dict:
|
|
256
|
+
config.database = DatabaseConfig(**config_dict["database"])
|
|
257
|
+
if "evaluator" in config_dict:
|
|
258
|
+
config.evaluator = EvaluatorConfig(**config_dict["evaluator"])
|
|
259
|
+
|
|
260
|
+
return config
|
|
261
|
+
|
|
262
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
263
|
+
"""Convert configuration to a dictionary"""
|
|
264
|
+
return {
|
|
265
|
+
# General settings
|
|
266
|
+
"max_iterations": self.max_iterations,
|
|
267
|
+
"checkpoint_interval": self.checkpoint_interval,
|
|
268
|
+
"log_level": self.log_level,
|
|
269
|
+
"log_dir": self.log_dir,
|
|
270
|
+
"random_seed": self.random_seed,
|
|
271
|
+
# Component configurations
|
|
272
|
+
"llm": {
|
|
273
|
+
"models": self.llm.models,
|
|
274
|
+
"evaluator_models": self.llm.evaluator_models,
|
|
275
|
+
"api_base": self.llm.api_base,
|
|
276
|
+
"temperature": self.llm.temperature,
|
|
277
|
+
"top_p": self.llm.top_p,
|
|
278
|
+
"max_tokens": self.llm.max_tokens,
|
|
279
|
+
"timeout": self.llm.timeout,
|
|
280
|
+
"retries": self.llm.retries,
|
|
281
|
+
"retry_delay": self.llm.retry_delay,
|
|
282
|
+
},
|
|
283
|
+
"prompt": {
|
|
284
|
+
"template_dir": self.prompt.template_dir,
|
|
285
|
+
"system_message": self.prompt.system_message,
|
|
286
|
+
"evaluator_system_message": self.prompt.evaluator_system_message,
|
|
287
|
+
"num_top_programs": self.prompt.num_top_programs,
|
|
288
|
+
"num_diverse_programs": self.prompt.num_diverse_programs,
|
|
289
|
+
"use_template_stochasticity": self.prompt.use_template_stochasticity,
|
|
290
|
+
"template_variations": self.prompt.template_variations,
|
|
291
|
+
# Note: meta-prompting features not implemented
|
|
292
|
+
# "use_meta_prompting": self.prompt.use_meta_prompting,
|
|
293
|
+
# "meta_prompt_weight": self.prompt.meta_prompt_weight,
|
|
294
|
+
},
|
|
295
|
+
"database": {
|
|
296
|
+
"db_path": self.database.db_path,
|
|
297
|
+
"in_memory": self.database.in_memory,
|
|
298
|
+
"population_size": self.database.population_size,
|
|
299
|
+
"archive_size": self.database.archive_size,
|
|
300
|
+
"num_islands": self.database.num_islands,
|
|
301
|
+
"elite_selection_ratio": self.database.elite_selection_ratio,
|
|
302
|
+
"exploration_ratio": self.database.exploration_ratio,
|
|
303
|
+
"exploitation_ratio": self.database.exploitation_ratio,
|
|
304
|
+
# Note: diversity_metric fixed to "edit_distance"
|
|
305
|
+
# "diversity_metric": self.database.diversity_metric,
|
|
306
|
+
"feature_dimensions": self.database.feature_dimensions,
|
|
307
|
+
"feature_bins": self.database.feature_bins,
|
|
308
|
+
"migration_interval": self.database.migration_interval,
|
|
309
|
+
"migration_rate": self.database.migration_rate,
|
|
310
|
+
"random_seed": self.database.random_seed,
|
|
311
|
+
},
|
|
312
|
+
"evaluator": {
|
|
313
|
+
"timeout": self.evaluator.timeout,
|
|
314
|
+
"max_retries": self.evaluator.max_retries,
|
|
315
|
+
# Note: resource limits not implemented
|
|
316
|
+
# "memory_limit_mb": self.evaluator.memory_limit_mb,
|
|
317
|
+
# "cpu_limit": self.evaluator.cpu_limit,
|
|
318
|
+
"cascade_evaluation": self.evaluator.cascade_evaluation,
|
|
319
|
+
"cascade_thresholds": self.evaluator.cascade_thresholds,
|
|
320
|
+
"parallel_evaluations": self.evaluator.parallel_evaluations,
|
|
321
|
+
# Note: distributed evaluation not implemented
|
|
322
|
+
# "distributed": self.evaluator.distributed,
|
|
323
|
+
"use_llm_feedback": self.evaluator.use_llm_feedback,
|
|
324
|
+
"llm_feedback_weight": self.evaluator.llm_feedback_weight,
|
|
325
|
+
},
|
|
326
|
+
# Evolution settings
|
|
327
|
+
"diff_based_evolution": self.diff_based_evolution,
|
|
328
|
+
"allow_full_rewrites": self.allow_full_rewrites,
|
|
329
|
+
"max_code_length": self.max_code_length,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
def to_yaml(self, path: Union[str, Path]) -> None:
|
|
333
|
+
"""Save configuration to a YAML file"""
|
|
334
|
+
with open(path, "w") as f:
|
|
335
|
+
yaml.dump(self.to_dict(), f, default_flow_style=False)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def load_config(config_path: Optional[Union[str, Path]] = None) -> Config:
|
|
339
|
+
"""Load configuration from a YAML file or use defaults"""
|
|
340
|
+
if config_path and os.path.exists(config_path):
|
|
341
|
+
config = Config.from_yaml(config_path)
|
|
342
|
+
else:
|
|
343
|
+
config = Config()
|
|
344
|
+
|
|
345
|
+
# Use environment variables if available
|
|
346
|
+
api_key = os.environ.get("OPENAI_API_KEY")
|
|
347
|
+
api_base = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
348
|
+
|
|
349
|
+
config.llm.update_model_params({"api_key": api_key, "api_base": api_base})
|
|
350
|
+
|
|
351
|
+
# Make the system message available to the individual models, in case it is not provided from the prompt sampler
|
|
352
|
+
config.llm.update_model_params({"system_message": config.prompt.system_message})
|
|
353
|
+
|
|
354
|
+
return config
|