claude-evolve 1.6.21 → 1.6.23
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.
- package/lib/config.py +32 -19
- package/lib/config.sh +124 -158
- package/package.json +1 -1
package/lib/config.py
CHANGED
|
@@ -44,31 +44,44 @@ class Config:
|
|
|
44
44
|
|
|
45
45
|
def load(self, config_path=None, working_dir=None):
|
|
46
46
|
"""Load configuration from YAML file."""
|
|
47
|
-
# Determine config file path
|
|
47
|
+
# Determine local config file path
|
|
48
|
+
local_config_path = None
|
|
48
49
|
if config_path:
|
|
49
|
-
# Explicit config path provided
|
|
50
|
-
|
|
50
|
+
# Explicit config path provided, treat as local
|
|
51
|
+
local_config_path = Path(config_path)
|
|
51
52
|
elif working_dir:
|
|
52
53
|
# Look for config.yaml in working directory
|
|
53
54
|
self.working_dir = Path(working_dir)
|
|
54
|
-
|
|
55
|
+
local_config_path = self.working_dir / 'config.yaml'
|
|
55
56
|
else:
|
|
56
57
|
# Default to evolution/config.yaml
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
#
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
local_config_path = Path('evolution/config.yaml')
|
|
59
|
+
|
|
60
|
+
# Store the resolved config_path for path resolution later
|
|
61
|
+
self.config_path = local_config_path
|
|
62
|
+
|
|
63
|
+
# Load local config if it exists
|
|
64
|
+
if local_config_path.exists():
|
|
65
|
+
with open(local_config_path, 'r') as f:
|
|
66
|
+
local_yaml_data = yaml.safe_load(f) or {}
|
|
67
|
+
self._merge_config_data(local_yaml_data)
|
|
68
|
+
|
|
69
|
+
# Load global config from ~/.config/claude-evolve/config.yaml
|
|
70
|
+
global_config_path = Path.home() / '.config' / 'claude-evolve' / 'config.yaml'
|
|
71
|
+
if global_config_path.exists():
|
|
72
|
+
with open(global_config_path, 'r') as f:
|
|
73
|
+
global_yaml_data = yaml.safe_load(f) or {}
|
|
74
|
+
self._merge_config_data(global_yaml_data)
|
|
75
|
+
|
|
76
|
+
def _merge_config_data(self, new_data):
|
|
77
|
+
"""Helper to merge new data into self.data, handling nested structures."""
|
|
78
|
+
for key, value in new_data.items():
|
|
79
|
+
if key in self.data and isinstance(self.data[key], dict) and isinstance(value, dict):
|
|
80
|
+
# Recursively merge nested dictionaries
|
|
81
|
+
self.data[key].update(value)
|
|
82
|
+
else:
|
|
83
|
+
# Overwrite or add other types of values
|
|
84
|
+
self.data[key] = value
|
|
72
85
|
|
|
73
86
|
def resolve_path(self, relative_path):
|
|
74
87
|
"""Resolve a path relative to the config directory."""
|
package/lib/config.sh
CHANGED
|
@@ -59,23 +59,119 @@ DEFAULT_LLM_RUN="codex-qwen3 codex-oss gemini-flash"
|
|
|
59
59
|
# Ideate: Commercial models for idea generation + local fallback
|
|
60
60
|
DEFAULT_LLM_IDEATE="gemini sonnet-think gpt5high glm grok-4 codex-qwen3 codex-oss"
|
|
61
61
|
|
|
62
|
-
# Load configuration from
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
# Load configuration from a YAML file and update variables
|
|
63
|
+
_load_yaml_config() {
|
|
64
|
+
local config_file="$1"
|
|
65
|
+
if [[ ! -f "$config_file" ]]; then
|
|
66
|
+
return 0 # File does not exist, nothing to load
|
|
67
|
+
fi
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
echo "[DEBUG] Loading configuration from: $config_file" >&2
|
|
70
|
+
|
|
71
|
+
local in_ideation_section=false
|
|
72
|
+
local in_parallel_section=false
|
|
73
|
+
local in_llm_cli_section=false
|
|
74
|
+
local llm_cli_subsection=""
|
|
75
|
+
|
|
76
|
+
while IFS='' read -r line; do
|
|
77
|
+
[[ $line =~ ^[[:space:]]*# ]] || [[ -z $line ]] && continue
|
|
78
|
+
|
|
79
|
+
if [[ ! $line =~ ^([^:]+):(.*)$ ]]; then
|
|
80
|
+
continue
|
|
81
|
+
fi
|
|
82
|
+
local key="${BASH_REMATCH[1]}"
|
|
83
|
+
local value="${BASH_REMATCH[2]}"
|
|
84
|
+
|
|
85
|
+
local is_indented=false
|
|
86
|
+
[[ $key =~ ^[[:space:]]+ ]] && is_indented=true
|
|
87
|
+
|
|
88
|
+
key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
89
|
+
value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
90
|
+
|
|
91
|
+
if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
|
|
92
|
+
echo "[CONFIG DEBUG] Before comment removal: key='$key' value='$value'" >&2
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
value=$(echo "$value" | sed 's/[[:space:]]*#.*$//')
|
|
96
|
+
value=$(echo "$value" | sed 's/^"//;s/"$//')
|
|
97
|
+
|
|
98
|
+
if [[ $key == "ideation_strategies" ]]; then
|
|
99
|
+
in_ideation_section=true
|
|
100
|
+
in_parallel_section=false
|
|
101
|
+
in_llm_cli_section=false
|
|
102
|
+
continue
|
|
103
|
+
elif [[ $key == "parallel" ]]; then
|
|
104
|
+
in_parallel_section=true
|
|
105
|
+
in_ideation_section=false
|
|
106
|
+
in_llm_cli_section=false
|
|
107
|
+
continue
|
|
108
|
+
elif [[ $key == "llm_cli" ]]; then
|
|
109
|
+
in_llm_cli_section=true
|
|
110
|
+
in_ideation_section=false
|
|
111
|
+
in_parallel_section=false
|
|
112
|
+
llm_cli_subsection=""
|
|
113
|
+
continue
|
|
114
|
+
elif [[ $is_indented == false ]] && [[ $in_ideation_section == true || $in_parallel_section == true || $in_llm_cli_section == true ]]; then
|
|
115
|
+
in_ideation_section=false
|
|
116
|
+
in_parallel_section=false
|
|
117
|
+
in_llm_cli_section=false
|
|
118
|
+
llm_cli_subsection=""
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
if [[ $in_ideation_section == true ]]; then
|
|
122
|
+
case $key in
|
|
123
|
+
total_ideas) TOTAL_IDEAS="$value" ;;
|
|
124
|
+
novel_exploration) NOVEL_EXPLORATION="$value" ;;
|
|
125
|
+
hill_climbing) HILL_CLIMBING="$value" ;;
|
|
126
|
+
structural_mutation) STRUCTURAL_MUTATION="$value" ;;
|
|
127
|
+
crossover_hybrid) CROSSOVER_HYBRID="$value" ;;
|
|
128
|
+
num_elites) NUM_ELITES="$value" ;;
|
|
129
|
+
num_revolution) NUM_REVOLUTION="$value" ;;
|
|
130
|
+
esac
|
|
131
|
+
elif [[ $in_parallel_section == true ]]; then
|
|
132
|
+
case $key in
|
|
133
|
+
enabled) PARALLEL_ENABLED="$value" ;;
|
|
134
|
+
max_workers) MAX_WORKERS="$value" ;;
|
|
135
|
+
lock_timeout) LOCK_TIMEOUT="$value" ;;
|
|
136
|
+
esac
|
|
137
|
+
elif [[ $in_llm_cli_section == true ]]; then
|
|
138
|
+
if [[ $key == "run" || $key == "ideate" ]]; then
|
|
139
|
+
case $key in
|
|
140
|
+
run) LLM_RUN="$value" ;;
|
|
141
|
+
ideate) LLM_IDEATE="$value" ;;
|
|
142
|
+
esac
|
|
143
|
+
else
|
|
144
|
+
value=$(echo "$value" | sed "s/^'//;s/'$//")
|
|
145
|
+
local var_key=$(echo "$key" | sed 's/-/_/g')
|
|
146
|
+
if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
|
|
147
|
+
echo "[CONFIG DEBUG] Setting LLM_CLI_${var_key} = '$value'" >&2
|
|
148
|
+
fi
|
|
149
|
+
eval "LLM_CLI_${var_key}=\"$value\""
|
|
150
|
+
fi
|
|
74
151
|
else
|
|
75
|
-
|
|
152
|
+
case $key in
|
|
153
|
+
algorithm_file) ALGORITHM_FILE="$value" ;;
|
|
154
|
+
evaluator_file) EVALUATOR_FILE="$value" ;;
|
|
155
|
+
brief_file) BRIEF_FILE="$value" ;;
|
|
156
|
+
evolution_csv) EVOLUTION_CSV="$value" ;;
|
|
157
|
+
output_dir) OUTPUT_DIR="$value" ;;
|
|
158
|
+
parent_selection) PARENT_SELECTION="$value" ;;
|
|
159
|
+
python_cmd) PYTHON_CMD="$value" ;;
|
|
160
|
+
auto_ideate) AUTO_IDEATE="$value" ;;
|
|
161
|
+
max_retries) MAX_RETRIES="$value" ;;
|
|
162
|
+
memory_limit_mb) MEMORY_LIMIT_MB="$value" ;;
|
|
163
|
+
evolution_dir):
|
|
164
|
+
echo "[WARN] evolution_dir in config is ignored - automatically inferred from config file location" >&2
|
|
165
|
+
;;
|
|
166
|
+
esac
|
|
76
167
|
fi
|
|
77
|
-
|
|
78
|
-
|
|
168
|
+
done < "$config_file"
|
|
169
|
+
# Keep track of the last config file loaded to infer evolution_dir
|
|
170
|
+
LAST_CONFIG_FILE_LOADED="$config_file"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Load configuration from config file
|
|
174
|
+
load_config() {
|
|
79
175
|
# Set defaults first
|
|
80
176
|
EVOLUTION_DIR="$DEFAULT_EVOLUTION_DIR"
|
|
81
177
|
ALGORITHM_FILE="$DEFAULT_ALGORITHM_FILE"
|
|
@@ -86,7 +182,6 @@ load_config() {
|
|
|
86
182
|
PARENT_SELECTION="$DEFAULT_PARENT_SELECTION"
|
|
87
183
|
PYTHON_CMD="$DEFAULT_PYTHON_CMD"
|
|
88
184
|
|
|
89
|
-
# Set ideation strategy defaults
|
|
90
185
|
TOTAL_IDEAS="$DEFAULT_TOTAL_IDEAS"
|
|
91
186
|
NOVEL_EXPLORATION="$DEFAULT_NOVEL_EXPLORATION"
|
|
92
187
|
HILL_CLIMBING="$DEFAULT_HILL_CLIMBING"
|
|
@@ -95,23 +190,14 @@ load_config() {
|
|
|
95
190
|
NUM_ELITES="$DEFAULT_NUM_ELITES"
|
|
96
191
|
NUM_REVOLUTION="$DEFAULT_NUM_REVOLUTION"
|
|
97
192
|
|
|
98
|
-
# Set parallel execution defaults
|
|
99
193
|
PARALLEL_ENABLED="$DEFAULT_PARALLEL_ENABLED"
|
|
100
194
|
MAX_WORKERS="$DEFAULT_MAX_WORKERS"
|
|
101
195
|
LOCK_TIMEOUT="$DEFAULT_LOCK_TIMEOUT"
|
|
102
196
|
|
|
103
|
-
# Set auto ideation default
|
|
104
197
|
AUTO_IDEATE="$DEFAULT_AUTO_IDEATE"
|
|
105
|
-
|
|
106
|
-
# Set retry default
|
|
107
198
|
MAX_RETRIES="$DEFAULT_MAX_RETRIES"
|
|
108
|
-
|
|
109
|
-
# Set memory limit default
|
|
110
199
|
MEMORY_LIMIT_MB="$DEFAULT_MEMORY_LIMIT_MB"
|
|
111
200
|
|
|
112
|
-
# Set LLM CLI defaults (compatibility for older bash)
|
|
113
|
-
# Initialize associative array for LLM commands
|
|
114
|
-
# Use simpler approach for compatibility
|
|
115
201
|
LLM_CLI_gpt5high='codex exec --profile gpt5high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
116
202
|
LLM_CLI_o3high='codex exec --profile o3high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
117
203
|
LLM_CLI_codex='codex exec --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
@@ -127,142 +213,22 @@ load_config() {
|
|
|
127
213
|
LLM_CLI_deepseek='opencode -m openrouter/deepseek/deepseek-v3.1-terminus run "{{PROMPT}}"'
|
|
128
214
|
LLM_RUN="$DEFAULT_LLM_RUN"
|
|
129
215
|
LLM_IDEATE="$DEFAULT_LLM_IDEATE"
|
|
130
|
-
|
|
131
|
-
# Load config if found
|
|
132
|
-
if [[ -f "$config_file" ]]; then
|
|
133
|
-
echo "[DEBUG] Loading configuration from: $config_file" >&2
|
|
134
|
-
# Simple YAML parsing for key: value pairs and nested structures
|
|
135
|
-
local in_ideation_section=false
|
|
136
|
-
local in_parallel_section=false
|
|
137
|
-
local in_llm_cli_section=false
|
|
138
|
-
local llm_cli_subsection=""
|
|
139
|
-
while IFS='' read -r line; do
|
|
140
|
-
# Skip comments and empty lines
|
|
141
|
-
[[ $line =~ ^[[:space:]]*# ]] || [[ -z $line ]] && continue
|
|
142
|
-
|
|
143
|
-
# Parse key:value from line
|
|
144
|
-
if [[ ! $line =~ ^([^:]+):(.*)$ ]]; then
|
|
145
|
-
continue
|
|
146
|
-
fi
|
|
147
|
-
key="${BASH_REMATCH[1]}"
|
|
148
|
-
value="${BASH_REMATCH[2]}"
|
|
149
|
-
|
|
150
|
-
# Check if key is indented (for nested sections)
|
|
151
|
-
local is_indented=false
|
|
152
|
-
[[ $key =~ ^[[:space:]]+ ]] && is_indented=true
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
# Remove leading/trailing whitespace
|
|
156
|
-
key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
157
|
-
value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
158
|
-
|
|
159
|
-
# Debug before comment removal
|
|
160
|
-
if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
|
|
161
|
-
echo "[CONFIG DEBUG] Before comment removal: key='$key' value='$value'" >&2
|
|
162
|
-
fi
|
|
163
|
-
|
|
164
|
-
# Remove inline comments from value
|
|
165
|
-
value=$(echo "$value" | sed 's/[[:space:]]*#.*$//')
|
|
166
|
-
|
|
167
|
-
# Remove quotes from value
|
|
168
|
-
value=$(echo "$value" | sed 's/^"//;s/"$//')
|
|
169
|
-
|
|
170
|
-
# Handle nested sections
|
|
171
|
-
if [[ $key == "ideation_strategies" ]]; then
|
|
172
|
-
in_ideation_section=true
|
|
173
|
-
in_parallel_section=false
|
|
174
|
-
in_llm_cli_section=false
|
|
175
|
-
continue
|
|
176
|
-
elif [[ $key == "parallel" ]]; then
|
|
177
|
-
in_parallel_section=true
|
|
178
|
-
in_ideation_section=false
|
|
179
|
-
in_llm_cli_section=false
|
|
180
|
-
continue
|
|
181
|
-
elif [[ $key == "llm_cli" ]]; then
|
|
182
|
-
in_llm_cli_section=true
|
|
183
|
-
in_ideation_section=false
|
|
184
|
-
in_parallel_section=false
|
|
185
|
-
llm_cli_subsection=""
|
|
186
|
-
continue
|
|
187
|
-
elif [[ $is_indented == false ]] && [[ $in_ideation_section == true || $in_parallel_section == true || $in_llm_cli_section == true ]]; then
|
|
188
|
-
# Non-indented key found while in a section, exit nested sections
|
|
189
|
-
in_ideation_section=false
|
|
190
|
-
in_parallel_section=false
|
|
191
|
-
in_llm_cli_section=false
|
|
192
|
-
llm_cli_subsection=""
|
|
193
|
-
fi
|
|
194
|
-
|
|
195
|
-
if [[ $in_ideation_section == true ]]; then
|
|
196
|
-
# Handle indented keys in ideation_strategies
|
|
197
|
-
case $key in
|
|
198
|
-
total_ideas) TOTAL_IDEAS="$value" ;;
|
|
199
|
-
novel_exploration) NOVEL_EXPLORATION="$value" ;;
|
|
200
|
-
hill_climbing) HILL_CLIMBING="$value" ;;
|
|
201
|
-
structural_mutation) STRUCTURAL_MUTATION="$value" ;;
|
|
202
|
-
crossover_hybrid) CROSSOVER_HYBRID="$value" ;;
|
|
203
|
-
num_elites) NUM_ELITES="$value" ;;
|
|
204
|
-
num_revolution) NUM_REVOLUTION="$value" ;;
|
|
205
|
-
esac
|
|
206
|
-
elif [[ $in_parallel_section == true ]]; then
|
|
207
|
-
# Handle indented keys in parallel section
|
|
208
|
-
case $key in
|
|
209
|
-
enabled) PARALLEL_ENABLED="$value" ;;
|
|
210
|
-
max_workers) MAX_WORKERS="$value" ;;
|
|
211
|
-
lock_timeout) LOCK_TIMEOUT="$value" ;;
|
|
212
|
-
esac
|
|
213
|
-
elif [[ $in_llm_cli_section == true ]]; then
|
|
214
|
-
# Handle indented keys in llm_cli section
|
|
215
|
-
# Check if this is a model definition (o3, codex, gemini, etc.) or a command list (run, ideate)
|
|
216
|
-
if [[ $key == "run" || $key == "ideate" ]]; then
|
|
217
|
-
# Command list - value is a space-separated list of models
|
|
218
|
-
case $key in
|
|
219
|
-
run) LLM_RUN="$value" ;;
|
|
220
|
-
ideate) LLM_IDEATE="$value" ;;
|
|
221
|
-
esac
|
|
222
|
-
else
|
|
223
|
-
# Model definition - key is model name, value is command template
|
|
224
|
-
# Remove single quotes from value if present
|
|
225
|
-
value=$(echo "$value" | sed "s/^'//;s/'$//")
|
|
226
|
-
# Convert dashes to underscores for bash variable names
|
|
227
|
-
var_key=$(echo "$key" | sed 's/-/_/g')
|
|
228
|
-
# Debug config loading
|
|
229
|
-
if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
|
|
230
|
-
echo "[CONFIG DEBUG] Setting LLM_CLI_${var_key} = '$value'" >&2
|
|
231
|
-
fi
|
|
232
|
-
# Use dynamic variable name for compatibility
|
|
233
|
-
eval "LLM_CLI_${var_key}=\"$value\""
|
|
234
|
-
fi
|
|
235
|
-
else
|
|
236
|
-
# Handle top-level keys
|
|
237
|
-
case $key in
|
|
238
|
-
algorithm_file) ALGORITHM_FILE="$value" ;;
|
|
239
|
-
evaluator_file) EVALUATOR_FILE="$value" ;;
|
|
240
|
-
brief_file) BRIEF_FILE="$value" ;;
|
|
241
|
-
evolution_csv) EVOLUTION_CSV="$value" ;;
|
|
242
|
-
output_dir) OUTPUT_DIR="$value" ;;
|
|
243
|
-
parent_selection) PARENT_SELECTION="$value" ;;
|
|
244
|
-
python_cmd) PYTHON_CMD="$value" ;;
|
|
245
|
-
auto_ideate) AUTO_IDEATE="$value" ;;
|
|
246
|
-
max_retries) MAX_RETRIES="$value" ;;
|
|
247
|
-
memory_limit_mb) MEMORY_LIMIT_MB="$value" ;;
|
|
248
|
-
evolution_dir)
|
|
249
|
-
echo "[WARN] evolution_dir in config is ignored - automatically inferred from config file location" >&2
|
|
250
|
-
;;
|
|
251
|
-
esac
|
|
252
|
-
fi
|
|
253
|
-
done < "$config_file"
|
|
254
|
-
fi
|
|
255
216
|
|
|
256
|
-
# If config file is
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
# Use the config directory as evolution directory (including "." for current dir)
|
|
261
|
-
if [[ "$config_dir" != "" ]]; then
|
|
262
|
-
EVOLUTION_DIR="$config_dir"
|
|
263
|
-
echo "[DEBUG] Using evolution directory from config path: $EVOLUTION_DIR" >&2
|
|
264
|
-
fi
|
|
217
|
+
# If a config file is explicitly provided, use it as the local config
|
|
218
|
+
local local_config_file="evolution/config.yaml"
|
|
219
|
+
if [[ -n "$1" ]]; then
|
|
220
|
+
local_config_file="$1"
|
|
265
221
|
fi
|
|
222
|
+
|
|
223
|
+
# Load local config
|
|
224
|
+
_load_yaml_config "$local_config_file"
|
|
225
|
+
|
|
226
|
+
# Load global config (overrides local config)
|
|
227
|
+
local global_config_file="$HOME/.config/claude-evolve/config.yaml"
|
|
228
|
+
_load_yaml_config "$global_config_file"
|
|
229
|
+
|
|
230
|
+
# EVOLUTION_DIR should always be the project's evolution directory, not derived from config file location
|
|
231
|
+
# It is initialized to DEFAULT_EVOLUTION_DIR at the start of load_config and should not be changed here.
|
|
266
232
|
|
|
267
233
|
# Create full paths - ALL paths are relative to evolution_dir
|
|
268
234
|
# Make evolution_dir absolute if it's relative
|