claude-evolve 1.8.17 → 1.8.19
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/bin/claude-evolve-edit +81 -15
- package/lib/__pycache__/evolution_csv.cpython-311.pyc +0 -0
- package/lib/ai-cli.sh +1 -7
- package/lib/config.sh +1 -1
- package/package.json +1 -1
- package/templates/config.yaml +2 -2
- package/lib/config.sh.new +0 -327
- package/lib/config_with_ollama.sh +0 -327
package/bin/claude-evolve-edit
CHANGED
|
@@ -35,6 +35,7 @@ OPTIONS:
|
|
|
35
35
|
SELECTORS:
|
|
36
36
|
gen01, gen02, etc. Target specific generation
|
|
37
37
|
all Target all generations
|
|
38
|
+
winner Target the candidate with highest performance score
|
|
38
39
|
failed Target all candidates with failed status (includes retries)
|
|
39
40
|
complete Target all candidates with complete status
|
|
40
41
|
pending Target all candidates with pending status
|
|
@@ -56,6 +57,7 @@ ACTIONS:
|
|
|
56
57
|
|
|
57
58
|
EXAMPLES:
|
|
58
59
|
claude-evolve edit gen03 failed # Mark all gen03 as failed
|
|
60
|
+
claude-evolve edit winner pending # Reset the winner to pending (recalculate)
|
|
59
61
|
claude-evolve edit failed pending # Reset all failed candidates to pending
|
|
60
62
|
claude-evolve edit pending skipped # Skip all pending candidates
|
|
61
63
|
claude-evolve edit --recent-generations=15 failed pending # Reset only recent 15 gen failures
|
|
@@ -116,8 +118,8 @@ if ! validate_config; then
|
|
|
116
118
|
fi
|
|
117
119
|
|
|
118
120
|
# Validate selector format
|
|
119
|
-
if [[ "$SELECTOR" != "all" && ! "$SELECTOR" =~ ^gen[0-9]+$ && "$SELECTOR" != "failed" && "$SELECTOR" != "complete" && "$SELECTOR" != "pending" && "$SELECTOR" != "running" && "$SELECTOR" != "skipped" && "$SELECTOR" != "0perf" ]]; then
|
|
120
|
-
echo "[ERROR] Selector must be 'all', 'genXX' (e.g., gen01), or status ('failed', 'complete', 'pending', 'running', 'skipped', '0perf')" >&2
|
|
121
|
+
if [[ "$SELECTOR" != "all" && "$SELECTOR" != "winner" && ! "$SELECTOR" =~ ^gen[0-9]+$ && "$SELECTOR" != "failed" && "$SELECTOR" != "complete" && "$SELECTOR" != "pending" && "$SELECTOR" != "running" && "$SELECTOR" != "skipped" && "$SELECTOR" != "0perf" ]]; then
|
|
122
|
+
echo "[ERROR] Selector must be 'all', 'winner', 'genXX' (e.g., gen01), or status ('failed', 'complete', 'pending', 'running', 'skipped', '0perf')" >&2
|
|
121
123
|
exit 1
|
|
122
124
|
fi
|
|
123
125
|
|
|
@@ -201,19 +203,45 @@ try:
|
|
|
201
203
|
recent_gen_set = set(sorted_generations[:n_recent])
|
|
202
204
|
print(f'[INFO] Filtering to recent generations: {sorted(recent_gen_set)}', file=sys.stderr)
|
|
203
205
|
|
|
206
|
+
# For 'winner' selector, find the candidate with highest performance
|
|
207
|
+
winner_candidate_id = None
|
|
208
|
+
if selector == 'winner':
|
|
209
|
+
max_performance = None
|
|
210
|
+
for i in range(1, len(rows)):
|
|
211
|
+
row = rows[i]
|
|
212
|
+
if len(row) < 4:
|
|
213
|
+
continue
|
|
214
|
+
try:
|
|
215
|
+
perf_str = row[3].strip()
|
|
216
|
+
if perf_str and perf_str != '':
|
|
217
|
+
performance = float(perf_str)
|
|
218
|
+
if max_performance is None or performance > max_performance:
|
|
219
|
+
max_performance = performance
|
|
220
|
+
winner_candidate_id = row[0]
|
|
221
|
+
except (ValueError, IndexError):
|
|
222
|
+
continue
|
|
223
|
+
|
|
224
|
+
if winner_candidate_id:
|
|
225
|
+
print(f'[INFO] Winner candidate: {winner_candidate_id} with performance: {max_performance}', file=sys.stderr)
|
|
226
|
+
else:
|
|
227
|
+
print('[WARN] No winner found (no valid performance scores)', file=sys.stderr)
|
|
228
|
+
|
|
204
229
|
# Update matching rows
|
|
205
230
|
for i in range(1, len(rows)):
|
|
206
231
|
row = rows[i]
|
|
207
232
|
if len(row) < 1:
|
|
208
233
|
continue
|
|
209
|
-
|
|
234
|
+
|
|
210
235
|
candidate_id = row[0]
|
|
211
236
|
current_status = row[4] if len(row) > 4 else ''
|
|
212
|
-
|
|
237
|
+
|
|
213
238
|
# Check if this row matches selector
|
|
214
239
|
matches = False
|
|
215
240
|
if selector == 'all':
|
|
216
241
|
matches = True
|
|
242
|
+
elif selector == 'winner':
|
|
243
|
+
# Match only the winner candidate
|
|
244
|
+
matches = (candidate_id == winner_candidate_id)
|
|
217
245
|
elif selector.startswith('gen') and '-' in candidate_id:
|
|
218
246
|
# Generation selector (e.g., gen01, gen02)
|
|
219
247
|
matches = candidate_id.startswith(selector + '-')
|
|
@@ -335,41 +363,60 @@ try:
|
|
|
335
363
|
|
|
336
364
|
# Skip header if present
|
|
337
365
|
start_idx = 1 if rows and rows[0] and rows[0][0].lower() == 'id' else 0
|
|
338
|
-
|
|
366
|
+
|
|
339
367
|
# Determine recent generations if filtering is requested
|
|
340
368
|
recent_gen_set = set()
|
|
341
369
|
if recent_generations and recent_generations.isdigit():
|
|
342
370
|
n_recent = int(recent_generations)
|
|
343
|
-
|
|
371
|
+
|
|
344
372
|
# Find all generation numbers from candidate IDs
|
|
345
373
|
all_generations = set()
|
|
346
374
|
for row in rows[start_idx:]:
|
|
347
375
|
if len(row) < 1:
|
|
348
376
|
continue
|
|
349
377
|
candidate_id = row[0]
|
|
350
|
-
|
|
378
|
+
|
|
351
379
|
# Extract generation number from candidate_id (e.g., gen01-001 -> 1)
|
|
352
380
|
match = re.match(r'^gen(\d+)-', candidate_id)
|
|
353
381
|
if match:
|
|
354
382
|
gen_num = int(match.group(1))
|
|
355
383
|
all_generations.add(gen_num)
|
|
356
|
-
|
|
384
|
+
|
|
357
385
|
# Get the most recent N generations
|
|
358
386
|
if all_generations:
|
|
359
387
|
sorted_generations = sorted(all_generations, reverse=True)
|
|
360
388
|
recent_gen_set = set(sorted_generations[:n_recent])
|
|
361
|
-
|
|
389
|
+
|
|
390
|
+
# For 'winner' selector, find the candidate with highest performance
|
|
391
|
+
winner_candidate_id = None
|
|
392
|
+
if selector == 'winner':
|
|
393
|
+
max_performance = None
|
|
394
|
+
for row in rows[start_idx:]:
|
|
395
|
+
if len(row) < 4:
|
|
396
|
+
continue
|
|
397
|
+
try:
|
|
398
|
+
perf_str = row[3].strip()
|
|
399
|
+
if perf_str and perf_str != '':
|
|
400
|
+
performance = float(perf_str)
|
|
401
|
+
if max_performance is None or performance > max_performance:
|
|
402
|
+
max_performance = performance
|
|
403
|
+
winner_candidate_id = row[0]
|
|
404
|
+
except (ValueError, IndexError):
|
|
405
|
+
continue
|
|
406
|
+
|
|
362
407
|
candidates = []
|
|
363
408
|
for row in rows[start_idx:]:
|
|
364
409
|
if len(row) < 1:
|
|
365
410
|
continue
|
|
366
|
-
|
|
411
|
+
|
|
367
412
|
candidate_id = row[0]
|
|
368
413
|
current_status = row[4] if len(row) > 4 else ''
|
|
369
|
-
|
|
414
|
+
|
|
370
415
|
# Check if matches status selector
|
|
371
416
|
matches = False
|
|
372
|
-
if selector == '
|
|
417
|
+
if selector == 'winner':
|
|
418
|
+
matches = (candidate_id == winner_candidate_id)
|
|
419
|
+
elif selector == 'pending':
|
|
373
420
|
matches = current_status == '' or current_status == 'pending'
|
|
374
421
|
elif selector == 'failed':
|
|
375
422
|
matches = current_status.startswith('failed')
|
|
@@ -478,17 +525,36 @@ with EvolutionCSV('$FULL_CSV_PATH') as csv:
|
|
|
478
525
|
if all_generations:
|
|
479
526
|
sorted_generations = sorted(all_generations, reverse=True)
|
|
480
527
|
recent_gen_set = set(sorted_generations[:n_recent])
|
|
481
|
-
|
|
528
|
+
|
|
529
|
+
# For 'winner' selector, find the candidate with highest performance
|
|
530
|
+
winner_candidate_id = None
|
|
531
|
+
if selector == 'winner':
|
|
532
|
+
max_performance = None
|
|
533
|
+
for row in rows[start_idx:]:
|
|
534
|
+
if not row or len(row) < 4:
|
|
535
|
+
continue
|
|
536
|
+
try:
|
|
537
|
+
perf_str = row[3].strip()
|
|
538
|
+
if perf_str and perf_str != '':
|
|
539
|
+
performance = float(perf_str)
|
|
540
|
+
if max_performance is None or performance > max_performance:
|
|
541
|
+
max_performance = performance
|
|
542
|
+
winner_candidate_id = row[0].strip()
|
|
543
|
+
except (ValueError, IndexError):
|
|
544
|
+
continue
|
|
545
|
+
|
|
482
546
|
for row in rows[start_idx:]:
|
|
483
547
|
if not row or not row[0].strip():
|
|
484
548
|
continue
|
|
485
|
-
|
|
549
|
+
|
|
486
550
|
candidate_id = row[0].strip()
|
|
487
551
|
current_status = row[4].strip() if len(row) > 4 else ''
|
|
488
|
-
|
|
552
|
+
|
|
489
553
|
matches = False
|
|
490
554
|
if selector == 'all':
|
|
491
555
|
matches = True
|
|
556
|
+
elif selector == 'winner':
|
|
557
|
+
matches = (candidate_id == winner_candidate_id)
|
|
492
558
|
elif selector.startswith('gen') and re.match(r'^gen\\d+$', selector):
|
|
493
559
|
# Generation selector (e.g., gen01, gen02)
|
|
494
560
|
gen_pattern = f'^{selector}-'
|
|
Binary file
|
package/lib/ai-cli.sh
CHANGED
|
@@ -118,7 +118,7 @@ $prompt"
|
|
|
118
118
|
ai_output=$(timeout 600 opencode -m openrouter/anthropic/claude-opus-4.1 run "$prompt" 2>&1)
|
|
119
119
|
local ai_exit_code=$?
|
|
120
120
|
;;
|
|
121
|
-
|
|
121
|
+
kimi-k2-think-moonshot)
|
|
122
122
|
local ai_output
|
|
123
123
|
ai_output=$(timeout 600 opencode -m moonshotai/kimi-k2-thinking run "$prompt" 2>&1)
|
|
124
124
|
local ai_exit_code=$?
|
|
@@ -129,12 +129,6 @@ $prompt"
|
|
|
129
129
|
ai_output=$(timeout 2400 codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss "$prompt" 2>&1)
|
|
130
130
|
local ai_exit_code=$?
|
|
131
131
|
;;
|
|
132
|
-
kimi-k2-llamacloud)
|
|
133
|
-
# Kimi K2 via Codex CLI with Ollama cloud backend
|
|
134
|
-
local ai_output
|
|
135
|
-
ai_output=$(timeout 600 codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss -m kimi-k2:1t-cloud "$prompt" 2>&1)
|
|
136
|
-
local ai_exit_code=$?
|
|
137
|
-
;;
|
|
138
132
|
deepseek-v3-llamacloud)
|
|
139
133
|
# Deepseek via Codex CLI with Ollama cloud backend
|
|
140
134
|
local ai_output
|
package/lib/config.sh
CHANGED
|
@@ -60,7 +60,7 @@ DEFAULT_WORKER_MAX_CANDIDATES=3
|
|
|
60
60
|
# Default LLM CLI configuration
|
|
61
61
|
DEFAULT_LLM_RUN="glm-zai glm-zai glm-zai glm-zai glm-zai codex-oss-local gemini-flash haiku"
|
|
62
62
|
# Ideate: Commercial models for idea generation + local fallback
|
|
63
|
-
DEFAULT_LLM_IDEATE="opus-openrouter
|
|
63
|
+
DEFAULT_LLM_IDEATE="opus-openrouter kimi-k2-think-moonshot gemini-pro sonnet-think gpt5high grok-4-openrouter deepseek-openrouter glm-zai"
|
|
64
64
|
|
|
65
65
|
# Load configuration from a YAML file and update variables
|
|
66
66
|
_load_yaml_config() {
|
package/package.json
CHANGED
package/templates/config.yaml
CHANGED
|
@@ -80,7 +80,7 @@ llm_cli:
|
|
|
80
80
|
# Default configuration: 100% local code generation, commercial ideation + local fallback
|
|
81
81
|
# Commented out because these change over time; uncomment to override
|
|
82
82
|
#run: codex-qwen3
|
|
83
|
-
#ideate: opus-openrouter
|
|
83
|
+
#ideate: opus-openrouter kimi-k2-think-moonshot gemini-pro sonnet-think gpt5high grok-4-openrouter deepseek-openrouter glm-zai
|
|
84
84
|
|
|
85
85
|
# Available models:
|
|
86
86
|
# - sonnet: Claude 3.5 Sonnet via Claude CLI
|
|
@@ -97,6 +97,6 @@ llm_cli:
|
|
|
97
97
|
# - grok-code-fast: Grok Code Fast 1 via OpenRouter
|
|
98
98
|
# - grok-4: Grok 4 via OpenRouter
|
|
99
99
|
# - opus-openrouter: Claude Opus 4.1 via OpenRouter
|
|
100
|
-
# -
|
|
100
|
+
# - kimi-k2-think-moonshot: Kimi K2 Thinking via Moonshot
|
|
101
101
|
# - codex-qwen3: Qwen3-Coder via Codex + Ollama (local, free, RECOMMENDED)
|
|
102
102
|
# - aider-qwen3: Qwen3-Coder via Aider + Ollama (local, free, experimental)
|
package/lib/config.sh.new
DELETED
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Configuration loader for claude-evolve
|
|
3
|
-
|
|
4
|
-
# Default configuration values
|
|
5
|
-
DEFAULT_EVOLUTION_DIR="evolution"
|
|
6
|
-
DEFAULT_ALGORITHM_FILE="algorithm.py"
|
|
7
|
-
DEFAULT_EVALUATOR_FILE="evaluator.py"
|
|
8
|
-
DEFAULT_BRIEF_FILE="BRIEF.md"
|
|
9
|
-
DEFAULT_EVOLUTION_CSV="evolution.csv"
|
|
10
|
-
DEFAULT_OUTPUT_DIR=""
|
|
11
|
-
DEFAULT_PARENT_SELECTION="best"
|
|
12
|
-
# Detect Python command based on platform
|
|
13
|
-
detect_python_cmd() {
|
|
14
|
-
# Try python3 first (macOS, Linux)
|
|
15
|
-
if command -v python3 >/dev/null 2>&1; then
|
|
16
|
-
echo "python3"
|
|
17
|
-
# Try python (Windows, some Linux)
|
|
18
|
-
elif command -v python >/dev/null 2>&1; then
|
|
19
|
-
# Verify it's Python 3
|
|
20
|
-
if python -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
|
|
21
|
-
echo "python"
|
|
22
|
-
else
|
|
23
|
-
echo "python3" # Fallback
|
|
24
|
-
fi
|
|
25
|
-
else
|
|
26
|
-
echo "python3" # Default fallback
|
|
27
|
-
fi
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
DEFAULT_PYTHON_CMD="$(detect_python_cmd)"
|
|
31
|
-
|
|
32
|
-
# Default ideation strategy values
|
|
33
|
-
DEFAULT_TOTAL_IDEAS=15
|
|
34
|
-
DEFAULT_NOVEL_EXPLORATION=3
|
|
35
|
-
DEFAULT_HILL_CLIMBING=5
|
|
36
|
-
DEFAULT_STRUCTURAL_MUTATION=3
|
|
37
|
-
DEFAULT_CROSSOVER_HYBRID=4
|
|
38
|
-
DEFAULT_NUM_ELITES=3
|
|
39
|
-
DEFAULT_NUM_REVOLUTION=2 # Number of top novel candidates to include
|
|
40
|
-
|
|
41
|
-
# Default parallel execution values
|
|
42
|
-
DEFAULT_PARALLEL_ENABLED=false
|
|
43
|
-
DEFAULT_MAX_WORKERS=4
|
|
44
|
-
DEFAULT_LOCK_TIMEOUT=10
|
|
45
|
-
|
|
46
|
-
# Default auto ideation value
|
|
47
|
-
DEFAULT_AUTO_IDEATE=true
|
|
48
|
-
|
|
49
|
-
# Default retry value
|
|
50
|
-
DEFAULT_MAX_RETRIES=3
|
|
51
|
-
|
|
52
|
-
# Default memory limit (in MB, 0 means no limit)
|
|
53
|
-
# Set to reasonable limit for ML workloads - about half of available system RAM
|
|
54
|
-
DEFAULT_MEMORY_LIMIT_MB=12288
|
|
55
|
-
|
|
56
|
-
# Default LLM CLI configuration - use simple variables instead of arrays
|
|
57
|
-
# Run: 100% local with qwen3 via Codex+Ollama (more reliable than aider)
|
|
58
|
-
DEFAULT_LLM_RUN="codex-qwen3 codex-oss gemini-flash"
|
|
59
|
-
# Ideate: Commercial models for idea generation + local fallback
|
|
60
|
-
DEFAULT_LLM_IDEATE="gemini sonnet-think gpt5high glm grok-4 codex-qwen3 codex-oss"
|
|
61
|
-
|
|
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
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
local in_ideation_section=false
|
|
71
|
-
local in_parallel_section=false
|
|
72
|
-
local in_llm_cli_section=false
|
|
73
|
-
local llm_cli_subsection=""
|
|
74
|
-
|
|
75
|
-
while IFS='' read -r line; do
|
|
76
|
-
[[ $line =~ ^[[:space:]]*# ]] || [[ -z $line ]] && continue
|
|
77
|
-
|
|
78
|
-
if [[ ! $line =~ ^([^:]+):(.*)$ ]]; then
|
|
79
|
-
continue
|
|
80
|
-
fi
|
|
81
|
-
local key="${BASH_REMATCH[1]}"
|
|
82
|
-
local value="${BASH_REMATCH[2]}"
|
|
83
|
-
|
|
84
|
-
local is_indented=false
|
|
85
|
-
[[ $key =~ ^[[:space:]]+ ]] && is_indented=true
|
|
86
|
-
|
|
87
|
-
key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
88
|
-
value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
89
|
-
|
|
90
|
-
if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
|
|
91
|
-
echo "[CONFIG DEBUG] Before comment removal: key='$key' value='$value'" >&2
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
value=$(echo "$value" | sed 's/[[:space:]]*#.*$//')
|
|
95
|
-
value=$(echo "$value" | sed 's/^"//;s/"$//')
|
|
96
|
-
|
|
97
|
-
if [[ $key == "ideation_strategies" ]]; then
|
|
98
|
-
in_ideation_section=true
|
|
99
|
-
in_parallel_section=false
|
|
100
|
-
in_llm_cli_section=false
|
|
101
|
-
continue
|
|
102
|
-
elif [[ $key == "parallel" ]]; then
|
|
103
|
-
in_parallel_section=true
|
|
104
|
-
in_ideation_section=false
|
|
105
|
-
in_llm_cli_section=false
|
|
106
|
-
continue
|
|
107
|
-
elif [[ $key == "llm_cli" ]]; then
|
|
108
|
-
in_llm_cli_section=true
|
|
109
|
-
in_ideation_section=false
|
|
110
|
-
in_parallel_section=false
|
|
111
|
-
llm_cli_subsection=""
|
|
112
|
-
continue
|
|
113
|
-
elif [[ $is_indented == false ]] && [[ $in_ideation_section == true || $in_parallel_section == true || $in_llm_cli_section == true ]]; then
|
|
114
|
-
in_ideation_section=false
|
|
115
|
-
in_parallel_section=false
|
|
116
|
-
in_llm_cli_section=false
|
|
117
|
-
llm_cli_subsection=""
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
if [[ $in_ideation_section == true ]]; then
|
|
121
|
-
case $key in
|
|
122
|
-
total_ideas) TOTAL_IDEAS="$value" ;;
|
|
123
|
-
novel_exploration) NOVEL_EXPLORATION="$value" ;;
|
|
124
|
-
hill_climbing) HILL_CLIMBING="$value" ;;
|
|
125
|
-
structural_mutation) STRUCTURAL_MUTATION="$value" ;;
|
|
126
|
-
crossover_hybrid) CROSSOVER_HYBRID="$value" ;;
|
|
127
|
-
num_elites) NUM_ELITES="$value" ;;
|
|
128
|
-
num_revolution) NUM_REVOLUTION="$value" ;;
|
|
129
|
-
esac
|
|
130
|
-
elif [[ $in_parallel_section == true ]]; then
|
|
131
|
-
case $key in
|
|
132
|
-
enabled) PARALLEL_ENABLED="$value" ;;
|
|
133
|
-
max_workers) MAX_WORKERS="$value" ;;
|
|
134
|
-
lock_timeout) LOCK_TIMEOUT="$value" ;;
|
|
135
|
-
esac
|
|
136
|
-
elif [[ $in_llm_cli_section == true ]]; then
|
|
137
|
-
if [[ $key == "run" || $key == "ideate" ]]; then
|
|
138
|
-
case $key in
|
|
139
|
-
run) LLM_RUN="$value" ;;
|
|
140
|
-
ideate) LLM_IDEATE="$value" ;;
|
|
141
|
-
esac
|
|
142
|
-
else
|
|
143
|
-
value=$(echo "$value" | sed "s/^'//;s/'$//")
|
|
144
|
-
local var_key=$(echo "$key" | sed 's/-/_/g')
|
|
145
|
-
if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
|
|
146
|
-
echo "[CONFIG DEBUG] Setting LLM_CLI_${var_key} = '$value'" >&2
|
|
147
|
-
fi
|
|
148
|
-
eval "LLM_CLI_${var_key}=\"$value\""
|
|
149
|
-
fi
|
|
150
|
-
else
|
|
151
|
-
case $key in
|
|
152
|
-
algorithm_file) ALGORITHM_FILE="$value" ;;
|
|
153
|
-
evaluator_file) EVALUATOR_FILE="$value" ;;
|
|
154
|
-
brief_file) BRIEF_FILE="$value" ;;
|
|
155
|
-
evolution_csv) EVOLUTION_CSV="$value" ;;
|
|
156
|
-
output_dir) OUTPUT_DIR="$value" ;;
|
|
157
|
-
parent_selection) PARENT_SELECTION="$value" ;;
|
|
158
|
-
python_cmd) PYTHON_CMD="$value" ;;
|
|
159
|
-
auto_ideate) AUTO_IDEATE="$value" ;;
|
|
160
|
-
max_retries) MAX_RETRIES="$value" ;;
|
|
161
|
-
memory_limit_mb) MEMORY_LIMIT_MB="$value" ;;
|
|
162
|
-
evolution_dir):
|
|
163
|
-
echo "[WARN] evolution_dir in config is ignored - automatically inferred from config file location" >&2
|
|
164
|
-
;;
|
|
165
|
-
esac
|
|
166
|
-
fi
|
|
167
|
-
done < "$config_file"
|
|
168
|
-
# Keep track of the last config file loaded to infer evolution_dir
|
|
169
|
-
LAST_CONFIG_FILE_LOADED="$config_file"
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
load_config() {
|
|
173
|
-
# Set defaults first
|
|
174
|
-
EVOLUTION_DIR="$DEFAULT_EVOLUTION_DIR" # Initialize with default
|
|
175
|
-
ALGORITHM_FILE="$DEFAULT_ALGORITHM_FILE"
|
|
176
|
-
EVALUATOR_FILE="$DEFAULT_EVALUATOR_FILE"
|
|
177
|
-
BRIEF_FILE="$DEFAULT_BRIEF_FILE"
|
|
178
|
-
EVOLUTION_CSV="$DEFAULT_EVOLUTION_CSV"
|
|
179
|
-
OUTPUT_DIR="$DEFAULT_OUTPUT_DIR"
|
|
180
|
-
PARENT_SELECTION="$DEFAULT_PARENT_SELECTION"
|
|
181
|
-
PYTHON_CMD="$DEFAULT_PYTHON_CMD"
|
|
182
|
-
|
|
183
|
-
# Determine EVOLUTION_DIR based on specified logic, overriding default if found
|
|
184
|
-
if [[ -n "$CLAUDE_EVOLVE_WORKING_DIR" ]]; then
|
|
185
|
-
EVOLUTION_DIR="$CLAUDE_EVOLVE_WORKING_DIR"
|
|
186
|
-
elif [[ -f "evolution/evolution.csv" ]]; then
|
|
187
|
-
EVOLUTION_DIR="evolution"
|
|
188
|
-
elif [[ -f "./evolution.csv" ]]; then
|
|
189
|
-
EVOLUTION_DIR="."
|
|
190
|
-
else
|
|
191
|
-
fi
|
|
192
|
-
|
|
193
|
-
TOTAL_IDEAS="$DEFAULT_TOTAL_IDEAS"
|
|
194
|
-
NOVEL_EXPLORATION="$DEFAULT_NOVEL_EXPLORATION"
|
|
195
|
-
HILL_CLIMBING="$DEFAULT_HILL_CLIMBING"
|
|
196
|
-
STRUCTURAL_MUTATION="$DEFAULT_STRUCTURAL_MUTATION"
|
|
197
|
-
CROSSOVER_HYBRID="$DEFAULT_CROSSOVER_HYBRID"
|
|
198
|
-
NUM_ELITES="$DEFAULT_NUM_ELITES"
|
|
199
|
-
NUM_REVOLUTION="$DEFAULT_NUM_REVOLUTION"
|
|
200
|
-
|
|
201
|
-
PARALLEL_ENABLED="$DEFAULT_PARALLEL_ENABLED"
|
|
202
|
-
MAX_WORKERS="$DEFAULT_MAX_WORKERS"
|
|
203
|
-
LOCK_TIMEOUT="$DEFAULT_LOCK_TIMEOUT"
|
|
204
|
-
|
|
205
|
-
AUTO_IDEATE="$DEFAULT_AUTO_IDEATE"
|
|
206
|
-
MAX_RETRIES="$DEFAULT_MAX_RETRIES"
|
|
207
|
-
MEMORY_LIMIT_MB="$DEFAULT_MEMORY_LIMIT_MB"
|
|
208
|
-
|
|
209
|
-
LLM_CLI_gpt5high='codex exec --profile gpt5high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
210
|
-
LLM_CLI_o3high='codex exec --profile o3high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
211
|
-
LLM_CLI_codex='codex exec --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
212
|
-
LLM_CLI_gemini='gemini -y -p "{{PROMPT}}"'
|
|
213
|
-
LLM_CLI_gemini_flash='gemini -y -p "{{PROMPT}}" --model gemini-2.5-flash'
|
|
214
|
-
LLM_CLI_opus='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "{{PROMPT}}"'
|
|
215
|
-
LLM_CLI_opus_think='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "ultrathink\n\n{{PROMPT}}"'
|
|
216
|
-
LLM_CLI_sonnet='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "{{PROMPT}}"'
|
|
217
|
-
LLM_CLI_sonnet_think='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "ultrathink\n\n{{PROMPT}}"'
|
|
218
|
-
LLM_CLI_cursor_sonnet='cursor-agent sonnet -p "{{PROMPT}}"'
|
|
219
|
-
LLM_CLI_cursor_opus='cursor-agent opus -p "{{PROMPT}}"'
|
|
220
|
-
LLM_CLI_glm='opencode -m openrouter/z-ai/glm-4.6 run "{{PROMPT}}"'
|
|
221
|
-
LLM_CLI_deepseek='opencode -m openrouter/deepseek/deepseek-v3.1-terminus run "{{PROMPT}}"'
|
|
222
|
-
LLM_CLI_ollama-cloud-gpt-oss='codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss --model gpt-oss:20b-cloud "{{PROMPT}}"' LLM_CLI_ollama-cloud-kimi-k2='codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss --model kimi-k2:1t-cloud "{{PROMPT}}"' LLM_RUN="$DEFAULT_LLM_RUN"
|
|
223
|
-
LLM_IDEATE="$DEFAULT_LLM_IDEATE"
|
|
224
|
-
|
|
225
|
-
# Determine local config file path relative to EVOLUTION_DIR
|
|
226
|
-
local local_config_file="$EVOLUTION_DIR/config.yaml"
|
|
227
|
-
|
|
228
|
-
# Load local config
|
|
229
|
-
_load_yaml_config "$local_config_file"
|
|
230
|
-
|
|
231
|
-
# Load global config (overrides local config)
|
|
232
|
-
local global_config_file="$HOME/.config/claude-evolve/config.yaml"
|
|
233
|
-
_load_yaml_config "$global_config_file"
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
# Create full paths - ALL paths are relative to EVOLUTION_DIR
|
|
237
|
-
# Make EVOLUTION_DIR absolute if it\'s relative
|
|
238
|
-
if [[ "$EVOLUTION_DIR" = /* ]]; then
|
|
239
|
-
FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
|
|
240
|
-
else
|
|
241
|
-
FULL_EVOLUTION_DIR="$(cd "$EVOLUTION_DIR" 2>/dev/null && pwd)" || FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
|
|
242
|
-
fi
|
|
243
|
-
|
|
244
|
-
FULL_ALGORITHM_PATH="$FULL_EVOLUTION_DIR/$ALGORITHM_FILE"
|
|
245
|
-
FULL_EVALUATOR_PATH="$FULL_EVOLUTION_DIR/$EVALUATOR_FILE"
|
|
246
|
-
FULL_BRIEF_PATH="$FULL_EVOLUTION_DIR/$BRIEF_FILE"
|
|
247
|
-
FULL_CSV_PATH="$FULL_EVOLUTION_DIR/$EVOLUTION_CSV"
|
|
248
|
-
|
|
249
|
-
if [[ -n $OUTPUT_DIR ]]; then
|
|
250
|
-
FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR/$OUTPUT_DIR"
|
|
251
|
-
else
|
|
252
|
-
FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR"
|
|
253
|
-
fi
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
# Validate configuration
|
|
257
|
-
validate_config() {
|
|
258
|
-
local errors=0
|
|
259
|
-
|
|
260
|
-
if [[ ! -d "$FULL_EVOLUTION_DIR" ]]; then
|
|
261
|
-
echo "[ERROR] Evolution directory not found: $FULL_EVOLUTION_DIR" >&2
|
|
262
|
-
((errors++))
|
|
263
|
-
fi
|
|
264
|
-
|
|
265
|
-
if [[ ! -f "$FULL_ALGORITHM_PATH" ]]; then
|
|
266
|
-
echo "[ERROR] Algorithm file not found: $FULL_ALGORITHM_PATH" >&2
|
|
267
|
-
((errors++))
|
|
268
|
-
fi
|
|
269
|
-
|
|
270
|
-
if [[ ! -f "$FULL_EVALUATOR_PATH" ]]; then
|
|
271
|
-
echo "[ERROR] Evaluator file not found: $FULL_EVALUATOR_PATH" >&2
|
|
272
|
-
((errors++))
|
|
273
|
-
fi
|
|
274
|
-
|
|
275
|
-
if [[ ! -f "$FULL_BRIEF_PATH" ]]; then
|
|
276
|
-
echo "[ERROR] Brief file not found: $FULL_BRIEF_PATH" >&2
|
|
277
|
-
((errors++))
|
|
278
|
-
fi
|
|
279
|
-
|
|
280
|
-
if ! command -v "$PYTHON_CMD" >/dev/null 2>&1; then
|
|
281
|
-
echo "[ERROR] Python command not found: $PYTHON_CMD" >&2
|
|
282
|
-
echo "[ERROR] Please install Python 3.x or set python_cmd in config.yaml" >&2
|
|
283
|
-
echo "[ERROR] Examples: python_cmd: \"python\" or python_cmd: \"C:\\Python39\\python.exe\"" >&2
|
|
284
|
-
((errors++))
|
|
285
|
-
else
|
|
286
|
-
# Verify Python version is 3.x
|
|
287
|
-
if ! "$PYTHON_CMD" -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
|
|
288
|
-
echo "[ERROR] Python 3.x required, but $PYTHON_CMD appears to be Python 2" >&2
|
|
289
|
-
echo "[ERROR] Please set python_cmd in config.yaml to point to Python 3" >&2
|
|
290
|
-
((errors++))
|
|
291
|
-
fi
|
|
292
|
-
fi
|
|
293
|
-
|
|
294
|
-
return $errors
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
# Show current configuration
|
|
298
|
-
show_config() {
|
|
299
|
-
echo "Current claude-evolve configuration:"
|
|
300
|
-
echo " Evolution directory: $FULL_EVOLUTION_DIR"
|
|
301
|
-
echo " Algorithm file: $FULL_ALGORITHM_PATH"
|
|
302
|
-
echo " Evaluator file: $FULL_EVALUATOR_PATH"
|
|
303
|
-
echo " Brief file: $FULL_BRIEF_PATH"
|
|
304
|
-
echo " CSV file: $FULL_CSV_PATH"
|
|
305
|
-
echo " Output directory: $FULL_OUTPUT_DIR"
|
|
306
|
-
echo " Parent selection: $PARENT_SELECTION"
|
|
307
|
-
echo " Python command: $PYTHON_CMD"
|
|
308
|
-
echo " Parallel enabled: $PARALLEL_ENABLED"
|
|
309
|
-
echo " Max workers: $MAX_WORKERS"
|
|
310
|
-
echo " Lock timeout: $LOCK_TIMEOUT"
|
|
311
|
-
echo " Auto ideate: $AUTO_IDEATE"
|
|
312
|
-
echo " Max retries: $MAX_RETRIES"
|
|
313
|
-
echo " Memory limit: ${MEMORY_LIMIT_MB}MB"
|
|
314
|
-
echo " LLM configuration:"
|
|
315
|
-
# Show LLM configurations using dynamic variable names
|
|
316
|
-
for model in gpt5high o3high codex gemini opus opus_think sonnet sonnet_think cursor_sonnet cursor_opus glm deepseek; do
|
|
317
|
-
var_name="LLM_CLI_${model}"
|
|
318
|
-
var_value=$(eval echo "\$$var_name")
|
|
319
|
-
if [[ -n "$var_value" ]]; then
|
|
320
|
-
# Convert underscore back to dash for display
|
|
321
|
-
display_name=$(echo "$model" | sed 's/_/-/g')
|
|
322
|
-
echo " $display_name: $var_value"
|
|
323
|
-
fi
|
|
324
|
-
done
|
|
325
|
-
echo " LLM for run: $LLM_RUN"
|
|
326
|
-
echo " LLM for ideate: $LLM_IDEATE"
|
|
327
|
-
}
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Configuration loader for claude-evolve
|
|
3
|
-
|
|
4
|
-
# Default configuration values
|
|
5
|
-
DEFAULT_EVOLUTION_DIR="evolution"
|
|
6
|
-
DEFAULT_ALGORITHM_FILE="algorithm.py"
|
|
7
|
-
DEFAULT_EVALUATOR_FILE="evaluator.py"
|
|
8
|
-
DEFAULT_BRIEF_FILE="BRIEF.md"
|
|
9
|
-
DEFAULT_EVOLUTION_CSV="evolution.csv"
|
|
10
|
-
DEFAULT_OUTPUT_DIR=""
|
|
11
|
-
DEFAULT_PARENT_SELECTION="best"
|
|
12
|
-
# Detect Python command based on platform
|
|
13
|
-
detect_python_cmd() {
|
|
14
|
-
# Try python3 first (macOS, Linux)
|
|
15
|
-
if command -v python3 >/dev/null 2>&1; then
|
|
16
|
-
echo "python3"
|
|
17
|
-
# Try python (Windows, some Linux)
|
|
18
|
-
elif command -v python >/dev/null 2>&1; then
|
|
19
|
-
# Verify it's Python 3
|
|
20
|
-
if python -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
|
|
21
|
-
echo "python"
|
|
22
|
-
else
|
|
23
|
-
echo "python3" # Fallback
|
|
24
|
-
fi
|
|
25
|
-
else
|
|
26
|
-
echo "python3" # Default fallback
|
|
27
|
-
fi
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
DEFAULT_PYTHON_CMD="$(detect_python_cmd)"
|
|
31
|
-
|
|
32
|
-
# Default ideation strategy values
|
|
33
|
-
DEFAULT_TOTAL_IDEAS=15
|
|
34
|
-
DEFAULT_NOVEL_EXPLORATION=3
|
|
35
|
-
DEFAULT_HILL_CLIMBING=5
|
|
36
|
-
DEFAULT_STRUCTURAL_MUTATION=3
|
|
37
|
-
DEFAULT_CROSSOVER_HYBRID=4
|
|
38
|
-
DEFAULT_NUM_ELITES=3
|
|
39
|
-
DEFAULT_NUM_REVOLUTION=2 # Number of top novel candidates to include
|
|
40
|
-
|
|
41
|
-
# Default parallel execution values
|
|
42
|
-
DEFAULT_PARALLEL_ENABLED=false
|
|
43
|
-
DEFAULT_MAX_WORKERS=4
|
|
44
|
-
DEFAULT_LOCK_TIMEOUT=10
|
|
45
|
-
|
|
46
|
-
# Default auto ideation value
|
|
47
|
-
DEFAULT_AUTO_IDEATE=true
|
|
48
|
-
|
|
49
|
-
# Default retry value
|
|
50
|
-
DEFAULT_MAX_RETRIES=3
|
|
51
|
-
|
|
52
|
-
# Default memory limit (in MB, 0 means no limit)
|
|
53
|
-
# Set to reasonable limit for ML workloads - about half of available system RAM
|
|
54
|
-
DEFAULT_MEMORY_LIMIT_MB=12288
|
|
55
|
-
|
|
56
|
-
# Default LLM CLI configuration - use simple variables instead of arrays
|
|
57
|
-
# Run: 100% local with qwen3 via Codex+Ollama (more reliable than aider)
|
|
58
|
-
DEFAULT_LLM_RUN="codex-qwen3 codex-oss gemini-flash"
|
|
59
|
-
# Ideate: Commercial models for idea generation + local fallback
|
|
60
|
-
DEFAULT_LLM_IDEATE="gemini sonnet-think gpt5high glm grok-4 codex-qwen3 codex-oss"
|
|
61
|
-
|
|
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
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
local in_ideation_section=false
|
|
71
|
-
local in_parallel_section=false
|
|
72
|
-
local in_llm_cli_section=false
|
|
73
|
-
local llm_cli_subsection=""
|
|
74
|
-
|
|
75
|
-
while IFS='' read -r line; do
|
|
76
|
-
[[ $line =~ ^[[:space:]]*# ]] || [[ -z $line ]] && continue
|
|
77
|
-
|
|
78
|
-
if [[ ! $line =~ ^([^:]+):(.*)$ ]]; then
|
|
79
|
-
continue
|
|
80
|
-
fi
|
|
81
|
-
local key="${BASH_REMATCH[1]}"
|
|
82
|
-
local value="${BASH_REMATCH[2]}"
|
|
83
|
-
|
|
84
|
-
local is_indented=false
|
|
85
|
-
[[ $key =~ ^[[:space:]]+ ]] && is_indented=true
|
|
86
|
-
|
|
87
|
-
key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
88
|
-
value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
89
|
-
|
|
90
|
-
if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
|
|
91
|
-
echo "[CONFIG DEBUG] Before comment removal: key='$key' value='$value'" >&2
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
value=$(echo "$value" | sed 's/[[:space:]]*#.*$//')
|
|
95
|
-
value=$(echo "$value" | sed 's/^"//;s/"$//')
|
|
96
|
-
|
|
97
|
-
if [[ $key == "ideation_strategies" ]]; then
|
|
98
|
-
in_ideation_section=true
|
|
99
|
-
in_parallel_section=false
|
|
100
|
-
in_llm_cli_section=false
|
|
101
|
-
continue
|
|
102
|
-
elif [[ $key == "parallel" ]]; then
|
|
103
|
-
in_parallel_section=true
|
|
104
|
-
in_ideation_section=false
|
|
105
|
-
in_llm_cli_section=false
|
|
106
|
-
continue
|
|
107
|
-
elif [[ $key == "llm_cli" ]]; then
|
|
108
|
-
in_llm_cli_section=true
|
|
109
|
-
in_ideation_section=false
|
|
110
|
-
in_parallel_section=false
|
|
111
|
-
llm_cli_subsection=""
|
|
112
|
-
continue
|
|
113
|
-
elif [[ $is_indented == false ]] && [[ $in_ideation_section == true || $in_parallel_section == true || $in_llm_cli_section == true ]]; then
|
|
114
|
-
in_ideation_section=false
|
|
115
|
-
in_parallel_section=false
|
|
116
|
-
in_llm_cli_section=false
|
|
117
|
-
llm_cli_subsection=""
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
if [[ $in_ideation_section == true ]]; then
|
|
121
|
-
case $key in
|
|
122
|
-
total_ideas) TOTAL_IDEAS="$value" ;;
|
|
123
|
-
novel_exploration) NOVEL_EXPLORATION="$value" ;;
|
|
124
|
-
hill_climbing) HILL_CLIMBING="$value" ;;
|
|
125
|
-
structural_mutation) STRUCTURAL_MUTATION="$value" ;;
|
|
126
|
-
crossover_hybrid) CROSSOVER_HYBRID="$value" ;;
|
|
127
|
-
num_elites) NUM_ELITES="$value" ;;
|
|
128
|
-
num_revolution) NUM_REVOLUTION="$value" ;;
|
|
129
|
-
esac
|
|
130
|
-
elif [[ $in_parallel_section == true ]]; then
|
|
131
|
-
case $key in
|
|
132
|
-
enabled) PARALLEL_ENABLED="$value" ;;
|
|
133
|
-
max_workers) MAX_WORKERS="$value" ;;
|
|
134
|
-
lock_timeout) LOCK_TIMEOUT="$value" ;;
|
|
135
|
-
esac
|
|
136
|
-
elif [[ $in_llm_cli_section == true ]]; then
|
|
137
|
-
if [[ $key == "run" || $key == "ideate" ]]; then
|
|
138
|
-
case $key in
|
|
139
|
-
run) LLM_RUN="$value" ;;
|
|
140
|
-
ideate) LLM_IDEATE="$value" ;;
|
|
141
|
-
esac
|
|
142
|
-
else
|
|
143
|
-
value=$(echo "$value" | sed "s/^'//;s/'$//")
|
|
144
|
-
local var_key=$(echo "$key" | sed 's/-/_/g')
|
|
145
|
-
if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
|
|
146
|
-
echo "[CONFIG DEBUG] Setting LLM_CLI_${var_key} = '$value'" >&2
|
|
147
|
-
fi
|
|
148
|
-
eval "LLM_CLI_${var_key}=\"$value\""
|
|
149
|
-
fi
|
|
150
|
-
else
|
|
151
|
-
case $key in
|
|
152
|
-
algorithm_file) ALGORITHM_FILE="$value" ;;
|
|
153
|
-
evaluator_file) EVALUATOR_FILE="$value" ;;
|
|
154
|
-
brief_file) BRIEF_FILE="$value" ;;
|
|
155
|
-
evolution_csv) EVOLUTION_CSV="$value" ;;
|
|
156
|
-
output_dir) OUTPUT_DIR="$value" ;;
|
|
157
|
-
parent_selection) PARENT_SELECTION="$value" ;;
|
|
158
|
-
python_cmd) PYTHON_CMD="$value" ;;
|
|
159
|
-
auto_ideate) AUTO_IDEATE="$value" ;;
|
|
160
|
-
max_retries) MAX_RETRIES="$value" ;;
|
|
161
|
-
memory_limit_mb) MEMORY_LIMIT_MB="$value" ;;
|
|
162
|
-
evolution_dir):
|
|
163
|
-
echo "[WARN] evolution_dir in config is ignored - automatically inferred from config file location" >&2
|
|
164
|
-
;;
|
|
165
|
-
esac
|
|
166
|
-
fi
|
|
167
|
-
done < "$config_file"
|
|
168
|
-
# Keep track of the last config file loaded to infer evolution_dir
|
|
169
|
-
LAST_CONFIG_FILE_LOADED="$config_file"
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
load_config() {
|
|
173
|
-
# Set defaults first
|
|
174
|
-
EVOLUTION_DIR="$DEFAULT_EVOLUTION_DIR" # Initialize with default
|
|
175
|
-
ALGORITHM_FILE="$DEFAULT_ALGORITHM_FILE"
|
|
176
|
-
EVALUATOR_FILE="$DEFAULT_EVALUATOR_FILE"
|
|
177
|
-
BRIEF_FILE="$DEFAULT_BRIEF_FILE"
|
|
178
|
-
EVOLUTION_CSV="$DEFAULT_EVOLUTION_CSV"
|
|
179
|
-
OUTPUT_DIR="$DEFAULT_OUTPUT_DIR"
|
|
180
|
-
PARENT_SELECTION="$DEFAULT_PARENT_SELECTION"
|
|
181
|
-
PYTHON_CMD="$DEFAULT_PYTHON_CMD"
|
|
182
|
-
|
|
183
|
-
# Determine EVOLUTION_DIR based on specified logic, overriding default if found
|
|
184
|
-
if [[ -n "$CLAUDE_EVOLVE_WORKING_DIR" ]]; then
|
|
185
|
-
EVOLUTION_DIR="$CLAUDE_EVOLVE_WORKING_DIR"
|
|
186
|
-
elif [[ -f "evolution/evolution.csv" ]]; then
|
|
187
|
-
EVOLUTION_DIR="evolution"
|
|
188
|
-
elif [[ -f "./evolution.csv" ]]; then
|
|
189
|
-
EVOLUTION_DIR="."
|
|
190
|
-
else
|
|
191
|
-
fi
|
|
192
|
-
|
|
193
|
-
TOTAL_IDEAS="$DEFAULT_TOTAL_IDEAS"
|
|
194
|
-
NOVEL_EXPLORATION="$DEFAULT_NOVEL_EXPLORATION"
|
|
195
|
-
HILL_CLIMBING="$DEFAULT_HILL_CLIMBING"
|
|
196
|
-
STRUCTURAL_MUTATION="$DEFAULT_STRUCTURAL_MUTATION"
|
|
197
|
-
CROSSOVER_HYBRID="$DEFAULT_CROSSOVER_HYBRID"
|
|
198
|
-
NUM_ELITES="$DEFAULT_NUM_ELITES"
|
|
199
|
-
NUM_REVOLUTION="$DEFAULT_NUM_REVOLUTION"
|
|
200
|
-
|
|
201
|
-
PARALLEL_ENABLED="$DEFAULT_PARALLEL_ENABLED"
|
|
202
|
-
MAX_WORKERS="$DEFAULT_MAX_WORKERS"
|
|
203
|
-
LOCK_TIMEOUT="$DEFAULT_LOCK_TIMEOUT"
|
|
204
|
-
|
|
205
|
-
AUTO_IDEATE="$DEFAULT_AUTO_IDEATE"
|
|
206
|
-
MAX_RETRIES="$DEFAULT_MAX_RETRIES"
|
|
207
|
-
MEMORY_LIMIT_MB="$DEFAULT_MEMORY_LIMIT_MB"
|
|
208
|
-
|
|
209
|
-
LLM_CLI_gpt5high='codex exec --profile gpt5high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
210
|
-
LLM_CLI_o3high='codex exec --profile o3high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
211
|
-
LLM_CLI_codex='codex exec --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
212
|
-
LLM_CLI_gemini='gemini -y -p "{{PROMPT}}"'
|
|
213
|
-
LLM_CLI_gemini_flash='gemini -y -p "{{PROMPT}}" --model gemini-2.5-flash'
|
|
214
|
-
LLM_CLI_opus='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "{{PROMPT}}"'
|
|
215
|
-
LLM_CLI_opus_think='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "ultrathink\n\n{{PROMPT}}"'
|
|
216
|
-
LLM_CLI_sonnet='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "{{PROMPT}}"'
|
|
217
|
-
LLM_CLI_sonnet_think='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "ultrathink\n\n{{PROMPT}}"'
|
|
218
|
-
LLM_CLI_cursor_sonnet='cursor-agent sonnet -p "{{PROMPT}}"'
|
|
219
|
-
LLM_CLI_cursor_opus='cursor-agent opus -p "{{PROMPT}}"'
|
|
220
|
-
LLM_CLI_glm='opencode -m openrouter/z-ai/glm-4.6 run "{{PROMPT}}"'
|
|
221
|
-
LLM_CLI_deepseek='opencode -m openrouter/deepseek/deepseek-v3.1-terminus run "{{PROMPT}}"'
|
|
222
|
-
LLM_CLI_ollama-cloud-gpt-oss='codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss --model gpt-oss:20b-cloud "{{PROMPT}}"' LLM_CLI_ollama-cloud-kimi-k2='codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss --model kimi-k2:1t-cloud "{{PROMPT}}"' LLM_RUN="$DEFAULT_LLM_RUN"
|
|
223
|
-
LLM_IDEATE="$DEFAULT_LLM_IDEATE"
|
|
224
|
-
|
|
225
|
-
# Determine local config file path relative to EVOLUTION_DIR
|
|
226
|
-
local local_config_file="$EVOLUTION_DIR/config.yaml"
|
|
227
|
-
|
|
228
|
-
# Load local config
|
|
229
|
-
_load_yaml_config "$local_config_file"
|
|
230
|
-
|
|
231
|
-
# Load global config (overrides local config)
|
|
232
|
-
local global_config_file="$HOME/.config/claude-evolve/config.yaml"
|
|
233
|
-
_load_yaml_config "$global_config_file"
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
# Create full paths - ALL paths are relative to EVOLUTION_DIR
|
|
237
|
-
# Make EVOLUTION_DIR absolute if it\'s relative
|
|
238
|
-
if [[ "$EVOLUTION_DIR" = /* ]]; then
|
|
239
|
-
FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
|
|
240
|
-
else
|
|
241
|
-
FULL_EVOLUTION_DIR="$(cd "$EVOLUTION_DIR" 2>/dev/null && pwd)" || FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
|
|
242
|
-
fi
|
|
243
|
-
|
|
244
|
-
FULL_ALGORITHM_PATH="$FULL_EVOLUTION_DIR/$ALGORITHM_FILE"
|
|
245
|
-
FULL_EVALUATOR_PATH="$FULL_EVOLUTION_DIR/$EVALUATOR_FILE"
|
|
246
|
-
FULL_BRIEF_PATH="$FULL_EVOLUTION_DIR/$BRIEF_FILE"
|
|
247
|
-
FULL_CSV_PATH="$FULL_EVOLUTION_DIR/$EVOLUTION_CSV"
|
|
248
|
-
|
|
249
|
-
if [[ -n $OUTPUT_DIR ]]; then
|
|
250
|
-
FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR/$OUTPUT_DIR"
|
|
251
|
-
else
|
|
252
|
-
FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR"
|
|
253
|
-
fi
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
# Validate configuration
|
|
257
|
-
validate_config() {
|
|
258
|
-
local errors=0
|
|
259
|
-
|
|
260
|
-
if [[ ! -d "$FULL_EVOLUTION_DIR" ]]; then
|
|
261
|
-
echo "[ERROR] Evolution directory not found: $FULL_EVOLUTION_DIR" >&2
|
|
262
|
-
((errors++))
|
|
263
|
-
fi
|
|
264
|
-
|
|
265
|
-
if [[ ! -f "$FULL_ALGORITHM_PATH" ]]; then
|
|
266
|
-
echo "[ERROR] Algorithm file not found: $FULL_ALGORITHM_PATH" >&2
|
|
267
|
-
((errors++))
|
|
268
|
-
fi
|
|
269
|
-
|
|
270
|
-
if [[ ! -f "$FULL_EVALUATOR_PATH" ]]; then
|
|
271
|
-
echo "[ERROR] Evaluator file not found: $FULL_EVALUATOR_PATH" >&2
|
|
272
|
-
((errors++))
|
|
273
|
-
fi
|
|
274
|
-
|
|
275
|
-
if [[ ! -f "$FULL_BRIEF_PATH" ]]; then
|
|
276
|
-
echo "[ERROR] Brief file not found: $FULL_BRIEF_PATH" >&2
|
|
277
|
-
((errors++))
|
|
278
|
-
fi
|
|
279
|
-
|
|
280
|
-
if ! command -v "$PYTHON_CMD" >/dev/null 2>&1; then
|
|
281
|
-
echo "[ERROR] Python command not found: $PYTHON_CMD" >&2
|
|
282
|
-
echo "[ERROR] Please install Python 3.x or set python_cmd in config.yaml" >&2
|
|
283
|
-
echo "[ERROR] Examples: python_cmd: \"python\" or python_cmd: \"C:\\Python39\\python.exe\"" >&2
|
|
284
|
-
((errors++))
|
|
285
|
-
else
|
|
286
|
-
# Verify Python version is 3.x
|
|
287
|
-
if ! "$PYTHON_CMD" -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
|
|
288
|
-
echo "[ERROR] Python 3.x required, but $PYTHON_CMD appears to be Python 2" >&2
|
|
289
|
-
echo "[ERROR] Please set python_cmd in config.yaml to point to Python 3" >&2
|
|
290
|
-
((errors++))
|
|
291
|
-
fi
|
|
292
|
-
fi
|
|
293
|
-
|
|
294
|
-
return $errors
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
# Show current configuration
|
|
298
|
-
show_config() {
|
|
299
|
-
echo "Current claude-evolve configuration:"
|
|
300
|
-
echo " Evolution directory: $FULL_EVOLUTION_DIR"
|
|
301
|
-
echo " Algorithm file: $FULL_ALGORITHM_PATH"
|
|
302
|
-
echo " Evaluator file: $FULL_EVALUATOR_PATH"
|
|
303
|
-
echo " Brief file: $FULL_BRIEF_PATH"
|
|
304
|
-
echo " CSV file: $FULL_CSV_PATH"
|
|
305
|
-
echo " Output directory: $FULL_OUTPUT_DIR"
|
|
306
|
-
echo " Parent selection: $PARENT_SELECTION"
|
|
307
|
-
echo " Python command: $PYTHON_CMD"
|
|
308
|
-
echo " Parallel enabled: $PARALLEL_ENABLED"
|
|
309
|
-
echo " Max workers: $MAX_WORKERS"
|
|
310
|
-
echo " Lock timeout: $LOCK_TIMEOUT"
|
|
311
|
-
echo " Auto ideate: $AUTO_IDEATE"
|
|
312
|
-
echo " Max retries: $MAX_RETRIES"
|
|
313
|
-
echo " Memory limit: ${MEMORY_LIMIT_MB}MB"
|
|
314
|
-
echo " LLM configuration:"
|
|
315
|
-
# Show LLM configurations using dynamic variable names
|
|
316
|
-
for model in gpt5high o3high codex gemini opus opus_think sonnet sonnet_think cursor_sonnet cursor_opus glm deepseek; do
|
|
317
|
-
var_name="LLM_CLI_${model}"
|
|
318
|
-
var_value=$(eval echo "\$$var_name")
|
|
319
|
-
if [[ -n "$var_value" ]]; then
|
|
320
|
-
# Convert underscore back to dash for display
|
|
321
|
-
display_name=$(echo "$model" | sed 's/_/-/g')
|
|
322
|
-
echo " $display_name: $var_value"
|
|
323
|
-
fi
|
|
324
|
-
done
|
|
325
|
-
echo " LLM for run: $LLM_RUN"
|
|
326
|
-
echo " LLM for ideate: $LLM_IDEATE"
|
|
327
|
-
}
|