claude-evolve 1.3.39 → 1.3.41
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/README.md +80 -317
- package/bin/claude-evolve-analyze +34 -5
- package/bin/claude-evolve-cleanup +297 -0
- package/bin/claude-evolve-edit +293 -0
- package/bin/claude-evolve-ideate +6 -6
- package/bin/claude-evolve-main +51 -29
- package/bin/{claude-evolve-run-unified → claude-evolve-run} +135 -4
- package/bin/claude-evolve-status +220 -0
- package/bin/claude-evolve-worker +76 -13
- package/lib/config.sh +5 -3
- package/lib/csv-lock.sh +26 -4
- package/lib/csv_helper.py +1 -1
- package/package.json +1 -1
- package/templates/config.yaml +8 -7
- package/bin/claude-evolve-run-parallel.OLD +0 -389
- package/bin/claude-evolve-run.OLD +0 -662
package/bin/claude-evolve-main
CHANGED
|
@@ -55,26 +55,30 @@ show_help() {
|
|
|
55
55
|
claude-evolve - AI-powered algorithm evolution tool
|
|
56
56
|
|
|
57
57
|
USAGE:
|
|
58
|
-
claude-evolve [--
|
|
58
|
+
claude-evolve [--working-dir=PATH] [COMMAND] [OPTIONS]
|
|
59
59
|
|
|
60
60
|
COMMANDS:
|
|
61
|
-
setup
|
|
62
|
-
ideate
|
|
63
|
-
run
|
|
64
|
-
analyze
|
|
65
|
-
|
|
61
|
+
setup Initialize evolution workspace
|
|
62
|
+
ideate Generate new algorithm ideas
|
|
63
|
+
run Execute evolution candidates
|
|
64
|
+
analyze Analyze evolution results
|
|
65
|
+
edit Manage candidate statuses by generation
|
|
66
|
+
status Show evolution progress and current leader
|
|
67
|
+
cleanup Clean up unchanged algorithms and descendants
|
|
68
|
+
cleanup-duplicates Alias for cleanup (deprecated)
|
|
69
|
+
help Show this help message
|
|
66
70
|
|
|
67
71
|
GLOBAL OPTIONS:
|
|
68
|
-
--
|
|
69
|
-
-h, --help
|
|
70
|
-
-v, --version
|
|
72
|
+
--working-dir=PATH Use alternate working directory (default: evolution/)
|
|
73
|
+
-h, --help Show help message
|
|
74
|
+
-v, --version Show version
|
|
71
75
|
|
|
72
76
|
EXAMPLES:
|
|
73
77
|
claude-evolve setup
|
|
74
78
|
claude-evolve ideate 5
|
|
75
79
|
claude-evolve run --timeout 300
|
|
76
80
|
claude-evolve analyze --open
|
|
77
|
-
claude-evolve --
|
|
81
|
+
claude-evolve --working-dir=evolution-abc run
|
|
78
82
|
|
|
79
83
|
For more information, visit: https://github.com/anthropics/claude-evolve
|
|
80
84
|
EOF
|
|
@@ -91,9 +95,11 @@ show_menu() {
|
|
|
91
95
|
echo " 2) ideate - Generate new algorithm ideas"
|
|
92
96
|
echo " 3) run - Execute evolution candidates"
|
|
93
97
|
echo " 4) analyze - Analyze evolution results"
|
|
94
|
-
echo " 5)
|
|
95
|
-
echo " 6)
|
|
96
|
-
echo " 7)
|
|
98
|
+
echo " 5) edit - Manage candidate statuses by generation"
|
|
99
|
+
echo " 6) status - Show evolution progress and current leader"
|
|
100
|
+
echo " 7) config - Manage configuration settings"
|
|
101
|
+
echo " 8) help - Show help message"
|
|
102
|
+
echo " 9) exit - Exit"
|
|
97
103
|
echo
|
|
98
104
|
|
|
99
105
|
# Show workspace status
|
|
@@ -105,19 +111,19 @@ show_menu() {
|
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
# Parse global options
|
|
108
|
-
|
|
114
|
+
WORKING_DIR=""
|
|
109
115
|
while [[ $# -gt 0 ]] && [[ "$1" =~ ^-- ]]; do
|
|
110
116
|
case "$1" in
|
|
111
|
-
--
|
|
117
|
+
--working-dir)
|
|
112
118
|
if [[ -z ${2:-} ]]; then
|
|
113
|
-
echo -e "${RED}[ERROR] --
|
|
119
|
+
echo -e "${RED}[ERROR] --working-dir requires a directory path${NC}" >&2
|
|
114
120
|
exit 1
|
|
115
121
|
fi
|
|
116
|
-
|
|
122
|
+
WORKING_DIR="$2"
|
|
117
123
|
shift 2
|
|
118
124
|
;;
|
|
119
|
-
--
|
|
120
|
-
|
|
125
|
+
--working-dir=*)
|
|
126
|
+
WORKING_DIR="${1#*=}"
|
|
121
127
|
shift
|
|
122
128
|
;;
|
|
123
129
|
*)
|
|
@@ -126,9 +132,11 @@ while [[ $# -gt 0 ]] && [[ "$1" =~ ^-- ]]; do
|
|
|
126
132
|
esac
|
|
127
133
|
done
|
|
128
134
|
|
|
129
|
-
# Export
|
|
130
|
-
if [[ -n $
|
|
131
|
-
|
|
135
|
+
# Export config file path for subcommands
|
|
136
|
+
if [[ -n $WORKING_DIR ]]; then
|
|
137
|
+
# Remove trailing slash if present
|
|
138
|
+
WORKING_DIR="${WORKING_DIR%/}"
|
|
139
|
+
export CLAUDE_EVOLVE_CONFIG="$WORKING_DIR/config.yaml"
|
|
132
140
|
fi
|
|
133
141
|
|
|
134
142
|
# Check for updates (quick, non-blocking)
|
|
@@ -137,21 +145,23 @@ check_for_updates
|
|
|
137
145
|
# Main logic
|
|
138
146
|
if [[ $# -eq 0 ]]; then
|
|
139
147
|
show_menu
|
|
140
|
-
read -r -p "Enter your choice (1-
|
|
148
|
+
read -r -p "Enter your choice (1-9): " choice
|
|
141
149
|
|
|
142
150
|
case $choice in
|
|
143
151
|
1) exec "$SCRIPT_DIR/claude-evolve-setup" ;;
|
|
144
152
|
2) exec "$SCRIPT_DIR/claude-evolve-ideate" ;;
|
|
145
|
-
3) exec "$SCRIPT_DIR/claude-evolve-run
|
|
153
|
+
3) exec "$SCRIPT_DIR/claude-evolve-run" ;;
|
|
146
154
|
4) exec "$SCRIPT_DIR/claude-evolve-analyze" ;;
|
|
147
|
-
5) exec "$SCRIPT_DIR/claude-evolve-
|
|
148
|
-
6)
|
|
149
|
-
7)
|
|
155
|
+
5) exec "$SCRIPT_DIR/claude-evolve-edit" ;;
|
|
156
|
+
6) exec "$SCRIPT_DIR/claude-evolve-status" ;;
|
|
157
|
+
7) exec "$SCRIPT_DIR/claude-evolve-config" ;;
|
|
158
|
+
8) show_help ;;
|
|
159
|
+
9)
|
|
150
160
|
echo "Goodbye!"
|
|
151
161
|
exit 0
|
|
152
162
|
;;
|
|
153
163
|
*)
|
|
154
|
-
echo -e "${RED}Invalid choice. Please select 1-
|
|
164
|
+
echo -e "${RED}Invalid choice. Please select 1-9.${NC}"
|
|
155
165
|
exit 1
|
|
156
166
|
;;
|
|
157
167
|
esac
|
|
@@ -174,12 +184,24 @@ ideate)
|
|
|
174
184
|
;;
|
|
175
185
|
run)
|
|
176
186
|
shift
|
|
177
|
-
exec "$SCRIPT_DIR/claude-evolve-run
|
|
187
|
+
exec "$SCRIPT_DIR/claude-evolve-run" "$@"
|
|
178
188
|
;;
|
|
179
189
|
analyze)
|
|
180
190
|
shift
|
|
181
191
|
exec "$SCRIPT_DIR/claude-evolve-analyze" "$@"
|
|
182
192
|
;;
|
|
193
|
+
edit)
|
|
194
|
+
shift
|
|
195
|
+
exec "$SCRIPT_DIR/claude-evolve-edit" "$@"
|
|
196
|
+
;;
|
|
197
|
+
status)
|
|
198
|
+
shift
|
|
199
|
+
exec "$SCRIPT_DIR/claude-evolve-status" "$@"
|
|
200
|
+
;;
|
|
201
|
+
cleanup-duplicates|cleanup)
|
|
202
|
+
shift
|
|
203
|
+
exec "$SCRIPT_DIR/claude-evolve-cleanup" "$@"
|
|
204
|
+
;;
|
|
183
205
|
config)
|
|
184
206
|
shift
|
|
185
207
|
exec "$SCRIPT_DIR/claude-evolve-config" "$@"
|
|
@@ -236,12 +236,32 @@ cleanup_workers() {
|
|
|
236
236
|
# Worker finished
|
|
237
237
|
if wait "$pid" 2>/dev/null; then
|
|
238
238
|
echo "[DISPATCHER] Worker $pid completed successfully"
|
|
239
|
+
consecutive_failures=0 # Reset counter on success
|
|
239
240
|
else
|
|
240
241
|
local exit_code=$?
|
|
241
242
|
if [[ $exit_code -eq 2 ]]; then
|
|
242
243
|
echo "[DISPATCHER] Worker $pid hit rate limit, will retry later"
|
|
244
|
+
# Rate limits don't count as consecutive failures
|
|
243
245
|
else
|
|
244
246
|
echo "[DISPATCHER] Worker $pid failed with exit code $exit_code"
|
|
247
|
+
((consecutive_failures++))
|
|
248
|
+
|
|
249
|
+
# Check if we've hit the failure limit
|
|
250
|
+
if [[ $consecutive_failures -ge $MAX_CONSECUTIVE_FAILURES ]]; then
|
|
251
|
+
echo "" >&2
|
|
252
|
+
echo "⚠️ EVOLUTION PAUSED: Multiple consecutive failures detected" >&2
|
|
253
|
+
echo "⚠️ $consecutive_failures consecutive worker failures - indicates systemic issues" >&2
|
|
254
|
+
echo "⚠️ Possible causes: Claude API issues, evaluator bugs, configuration problems" >&2
|
|
255
|
+
echo "⚠️ Check recent worker logs in logs/ directory for specific error details" >&2
|
|
256
|
+
echo "⚠️ Fix issues before restarting evolution" >&2
|
|
257
|
+
echo "" >&2
|
|
258
|
+
|
|
259
|
+
# Shutdown all workers and exit
|
|
260
|
+
shutdown_workers
|
|
261
|
+
exit 1
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
echo "[DISPATCHER] Consecutive failures: $consecutive_failures/$MAX_CONSECUTIVE_FAILURES"
|
|
245
265
|
fi
|
|
246
266
|
fi
|
|
247
267
|
fi
|
|
@@ -269,9 +289,26 @@ get_csv_stats() {
|
|
|
269
289
|
total_rows=$(wc -l < "$csv_path" | tr -d '[:space:]')
|
|
270
290
|
complete_count=$(grep ',complete' "$csv_path" 2>/dev/null | wc -l | tr -d '[:space:]')
|
|
271
291
|
|
|
272
|
-
# Count pending
|
|
273
|
-
#
|
|
274
|
-
pending_count=$(
|
|
292
|
+
# Count pending using same logic as find_next_pending_with_lock
|
|
293
|
+
# This includes rows with <5 fields AND rows with empty/pending status
|
|
294
|
+
pending_count=$("$PYTHON_CMD" -c "
|
|
295
|
+
import csv
|
|
296
|
+
import sys
|
|
297
|
+
|
|
298
|
+
pending_count = 0
|
|
299
|
+
with open('$csv_path', 'r') as f:
|
|
300
|
+
reader = csv.reader(f)
|
|
301
|
+
rows = list(reader)
|
|
302
|
+
|
|
303
|
+
for i in range(1, len(rows)):
|
|
304
|
+
# Same logic as find_next_pending_with_lock
|
|
305
|
+
if len(rows[i]) < 5:
|
|
306
|
+
pending_count += 1
|
|
307
|
+
elif len(rows[i]) >= 5 and (rows[i][4] == 'pending' or rows[i][4] == ''):
|
|
308
|
+
pending_count += 1
|
|
309
|
+
|
|
310
|
+
print(pending_count)
|
|
311
|
+
")
|
|
275
312
|
|
|
276
313
|
echo "$total_rows $complete_count $pending_count"
|
|
277
314
|
}
|
|
@@ -279,6 +316,100 @@ get_csv_stats() {
|
|
|
279
316
|
echo "[DISPATCHER] Starting unified evolution engine"
|
|
280
317
|
echo "[DISPATCHER] Configuration: max_workers=$MAX_WORKERS, timeout=${timeout_seconds:-none}"
|
|
281
318
|
|
|
319
|
+
# Validate CSV and clean up stuck statuses
|
|
320
|
+
if [[ -f "$FULL_CSV_PATH" ]]; then
|
|
321
|
+
echo "[DISPATCHER] Validating CSV and cleaning up..."
|
|
322
|
+
if ! "$PYTHON_CMD" -c "
|
|
323
|
+
import csv
|
|
324
|
+
import sys
|
|
325
|
+
|
|
326
|
+
csv_file = '$FULL_CSV_PATH'
|
|
327
|
+
|
|
328
|
+
try:
|
|
329
|
+
# Read CSV - let Python's csv module handle all the complexity
|
|
330
|
+
with open(csv_file, 'r') as f:
|
|
331
|
+
reader = csv.reader(f)
|
|
332
|
+
rows = list(reader)
|
|
333
|
+
|
|
334
|
+
if not rows:
|
|
335
|
+
print('[ERROR] CSV is empty')
|
|
336
|
+
sys.exit(1)
|
|
337
|
+
|
|
338
|
+
# Basic sanity checks
|
|
339
|
+
header = rows[0]
|
|
340
|
+
num_fields = len(header)
|
|
341
|
+
|
|
342
|
+
if len(rows) == 1:
|
|
343
|
+
print('[INFO] CSV has no data rows (only header)')
|
|
344
|
+
|
|
345
|
+
# Clean up any stuck 'running' statuses
|
|
346
|
+
changed = 0
|
|
347
|
+
for i in range(1, len(rows)):
|
|
348
|
+
if len(rows[i]) > 4 and rows[i][4] == 'running':
|
|
349
|
+
rows[i][4] = ''
|
|
350
|
+
changed += 1
|
|
351
|
+
|
|
352
|
+
if changed > 0:
|
|
353
|
+
# Write back
|
|
354
|
+
with open(csv_file + '.tmp', 'w', newline='') as f:
|
|
355
|
+
writer = csv.writer(f)
|
|
356
|
+
writer.writerows(rows)
|
|
357
|
+
import os
|
|
358
|
+
os.rename(csv_file + '.tmp', csv_file)
|
|
359
|
+
print(f'[INFO] Reset {changed} stuck running candidates to pending')
|
|
360
|
+
|
|
361
|
+
# Count pending candidates
|
|
362
|
+
pending = 0
|
|
363
|
+
for i in range(1, len(rows)):
|
|
364
|
+
# Row with < 5 fields or empty/pending status in field 5
|
|
365
|
+
if len(rows[i]) < 5 or (len(rows[i]) >= 5 and rows[i][4] in ['', 'pending']):
|
|
366
|
+
pending += 1
|
|
367
|
+
|
|
368
|
+
print(f'[INFO] CSV loaded: {len(rows)-1} total candidates, {pending} pending')
|
|
369
|
+
|
|
370
|
+
except csv.Error as e:
|
|
371
|
+
print(f'[ERROR] CSV parsing error: {e}')
|
|
372
|
+
print('[ERROR] The CSV file appears to be malformed')
|
|
373
|
+
sys.exit(1)
|
|
374
|
+
except Exception as e:
|
|
375
|
+
print(f'[ERROR] Failed to read CSV: {e}')
|
|
376
|
+
sys.exit(1)
|
|
377
|
+
"; then
|
|
378
|
+
echo "[ERROR] CSV validation failed. Please check the error message above."
|
|
379
|
+
exit 1
|
|
380
|
+
fi
|
|
381
|
+
fi
|
|
382
|
+
|
|
383
|
+
# Automatic cleanup detection - check for unchanged algorithms and warn user
|
|
384
|
+
echo "[DISPATCHER] Checking for duplicate/unchanged algorithms..."
|
|
385
|
+
cleanup_output=$("$SCRIPT_DIR/claude-evolve-cleanup" --dry-run 2>&1)
|
|
386
|
+
|
|
387
|
+
# Check if cleanup found any issues (look for "UNCHANGED:" in output)
|
|
388
|
+
if echo "$cleanup_output" | grep -q "📋 UNCHANGED:"; then
|
|
389
|
+
echo "⚠️ WARNING: Issues detected that may need cleanup:"
|
|
390
|
+
echo "$cleanup_output"
|
|
391
|
+
echo ""
|
|
392
|
+
echo "🔧 RECOMMENDATION: Run 'claude-evolve cleanup --force' to fix these issues before continuing"
|
|
393
|
+
echo " This will delete unchanged algorithms and reset their descendants to pending status"
|
|
394
|
+
echo ""
|
|
395
|
+
echo "⏰ Continuing in 10 seconds (Ctrl+C to abort and run cleanup)..."
|
|
396
|
+
|
|
397
|
+
# Give user time to read and potentially abort
|
|
398
|
+
for i in {10..1}; do
|
|
399
|
+
echo -n " $i..."
|
|
400
|
+
sleep 1
|
|
401
|
+
done
|
|
402
|
+
echo ""
|
|
403
|
+
echo "🚀 Proceeding with evolution run..."
|
|
404
|
+
echo ""
|
|
405
|
+
else
|
|
406
|
+
echo "[DISPATCHER] No cleanup issues detected - proceeding with run"
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
# Consecutive failure tracking
|
|
410
|
+
consecutive_failures=0
|
|
411
|
+
MAX_CONSECUTIVE_FAILURES=5
|
|
412
|
+
|
|
282
413
|
# Main dispatch loop
|
|
283
414
|
while true; do
|
|
284
415
|
# Clean up finished workers
|
|
@@ -337,7 +468,7 @@ while true; do
|
|
|
337
468
|
done
|
|
338
469
|
|
|
339
470
|
# Brief pause to avoid busy waiting
|
|
340
|
-
sleep
|
|
471
|
+
sleep 5
|
|
341
472
|
done
|
|
342
473
|
|
|
343
474
|
# Clean shutdown
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
# Load configuration
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
# shellcheck source=../lib/config.sh
|
|
8
|
+
source "$SCRIPT_DIR/../lib/config.sh"
|
|
9
|
+
|
|
10
|
+
# Use CLAUDE_EVOLVE_CONFIG if set, otherwise default
|
|
11
|
+
if [[ -n ${CLAUDE_EVOLVE_CONFIG:-} ]]; then
|
|
12
|
+
load_config "$CLAUDE_EVOLVE_CONFIG"
|
|
13
|
+
else
|
|
14
|
+
load_config
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Validate configuration
|
|
18
|
+
if ! validate_config; then
|
|
19
|
+
echo "[ERROR] Configuration validation failed" >&2
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Function to show help
|
|
24
|
+
show_help() {
|
|
25
|
+
cat <<EOF
|
|
26
|
+
claude-evolve status - Show evolution progress and current leader
|
|
27
|
+
|
|
28
|
+
USAGE:
|
|
29
|
+
claude-evolve status [OPTIONS]
|
|
30
|
+
|
|
31
|
+
OPTIONS:
|
|
32
|
+
--brief Show only summary stats (no per-generation breakdown)
|
|
33
|
+
--winner Show only the current best performer
|
|
34
|
+
--help Show this help message
|
|
35
|
+
|
|
36
|
+
DESCRIPTION:
|
|
37
|
+
Displays evolution progress by generation including:
|
|
38
|
+
- Candidate counts by status (pending, complete, failed, running)
|
|
39
|
+
- Current best performer across all generations
|
|
40
|
+
- Generation-by-generation breakdown
|
|
41
|
+
|
|
42
|
+
EXAMPLES:
|
|
43
|
+
claude-evolve status # Full status report
|
|
44
|
+
claude-evolve status --brief # Just totals and winner
|
|
45
|
+
claude-evolve status --winner # Just the best performer
|
|
46
|
+
EOF
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Parse arguments
|
|
50
|
+
SHOW_BRIEF=false
|
|
51
|
+
SHOW_WINNER_ONLY=false
|
|
52
|
+
|
|
53
|
+
while [[ $# -gt 0 ]]; do
|
|
54
|
+
case $1 in
|
|
55
|
+
--brief)
|
|
56
|
+
SHOW_BRIEF=true
|
|
57
|
+
shift
|
|
58
|
+
;;
|
|
59
|
+
--winner)
|
|
60
|
+
SHOW_WINNER_ONLY=true
|
|
61
|
+
shift
|
|
62
|
+
;;
|
|
63
|
+
--help)
|
|
64
|
+
show_help
|
|
65
|
+
exit 0
|
|
66
|
+
;;
|
|
67
|
+
*)
|
|
68
|
+
echo "[ERROR] Unknown option: $1" >&2
|
|
69
|
+
exit 1
|
|
70
|
+
;;
|
|
71
|
+
esac
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
# Check if CSV exists
|
|
75
|
+
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
76
|
+
echo "[ERROR] Evolution CSV not found: $FULL_CSV_PATH" >&2
|
|
77
|
+
echo "Run 'claude-evolve setup' first or navigate to the correct directory" >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Determine what we're evolving based on paths
|
|
82
|
+
EVOLUTION_CONTEXT=""
|
|
83
|
+
if [[ -n "$EVOLUTION_DIR" ]]; then
|
|
84
|
+
# Get the evolution directory name (e.g., "evolution-atr" -> "ATR")
|
|
85
|
+
EVOLUTION_NAME=$(basename "$EVOLUTION_DIR")
|
|
86
|
+
EVOLUTION_CONTEXT="${EVOLUTION_NAME#evolution-}"
|
|
87
|
+
EVOLUTION_CONTEXT=$(echo "$EVOLUTION_CONTEXT" | tr '[:lower:]' '[:upper:]')
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# If we can't determine from evolution dir, try from algorithm path
|
|
91
|
+
if [[ -z "$EVOLUTION_CONTEXT" && -n "$ALGORITHM_PATH" ]]; then
|
|
92
|
+
# Get parent directory name or algorithm file name
|
|
93
|
+
if [[ -f "$FULL_ALGORITHM_PATH" ]]; then
|
|
94
|
+
ALGO_NAME=$(basename "$FULL_ALGORITHM_PATH" .py)
|
|
95
|
+
EVOLUTION_CONTEXT="$ALGO_NAME"
|
|
96
|
+
fi
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# Default if we still can't determine
|
|
100
|
+
if [[ -z "$EVOLUTION_CONTEXT" ]]; then
|
|
101
|
+
EVOLUTION_CONTEXT="Algorithm"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Main status reporting using Python
|
|
105
|
+
"$PYTHON_CMD" -c "
|
|
106
|
+
import csv
|
|
107
|
+
import sys
|
|
108
|
+
|
|
109
|
+
csv_file = '$FULL_CSV_PATH'
|
|
110
|
+
show_brief = '$SHOW_BRIEF' == 'true'
|
|
111
|
+
show_winner_only = '$SHOW_WINNER_ONLY' == 'true'
|
|
112
|
+
evolution_context = '$EVOLUTION_CONTEXT'
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
with open(csv_file, 'r') as f:
|
|
116
|
+
reader = csv.reader(f)
|
|
117
|
+
rows = list(reader)
|
|
118
|
+
|
|
119
|
+
if len(rows) <= 1:
|
|
120
|
+
print('No evolution candidates found')
|
|
121
|
+
sys.exit(0)
|
|
122
|
+
|
|
123
|
+
header = rows[0]
|
|
124
|
+
|
|
125
|
+
# Collect all candidates with scores and statuses
|
|
126
|
+
all_candidates = []
|
|
127
|
+
stats_by_gen = {}
|
|
128
|
+
total_stats = {'pending': 0, 'complete': 0, 'failed': 0, 'running': 0}
|
|
129
|
+
|
|
130
|
+
for row in rows[1:]:
|
|
131
|
+
if len(row) >= 1 and row[0]: # Must have an ID
|
|
132
|
+
candidate_id = row[0]
|
|
133
|
+
|
|
134
|
+
# Extract generation (e.g., 'gen03' from 'gen03-001')
|
|
135
|
+
if '-' in candidate_id:
|
|
136
|
+
gen = candidate_id.split('-')[0]
|
|
137
|
+
|
|
138
|
+
# Get status and performance
|
|
139
|
+
status = row[4] if len(row) > 4 and row[4] else 'pending'
|
|
140
|
+
performance = row[3] if len(row) > 3 and row[3] else ''
|
|
141
|
+
|
|
142
|
+
# Track by generation
|
|
143
|
+
if gen not in stats_by_gen:
|
|
144
|
+
stats_by_gen[gen] = {'pending': 0, 'complete': 0, 'failed': 0, 'running': 0}
|
|
145
|
+
|
|
146
|
+
if status in stats_by_gen[gen]:
|
|
147
|
+
stats_by_gen[gen][status] += 1
|
|
148
|
+
total_stats[status] += 1
|
|
149
|
+
else:
|
|
150
|
+
stats_by_gen[gen]['pending'] += 1
|
|
151
|
+
total_stats['pending'] += 1
|
|
152
|
+
|
|
153
|
+
# Collect for winner analysis (only completed with valid scores)
|
|
154
|
+
if status == 'complete' and performance:
|
|
155
|
+
try:
|
|
156
|
+
score = float(performance)
|
|
157
|
+
description = row[2] if len(row) > 2 else 'No description'
|
|
158
|
+
all_candidates.append((candidate_id, description, score))
|
|
159
|
+
except ValueError:
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
# Find the winner
|
|
163
|
+
winner = None
|
|
164
|
+
if all_candidates:
|
|
165
|
+
winner = max(all_candidates, key=lambda x: x[2])
|
|
166
|
+
|
|
167
|
+
# Show winner only
|
|
168
|
+
if show_winner_only:
|
|
169
|
+
if winner:
|
|
170
|
+
print(f'🏆 CURRENT LEADER: {winner[0]} (score: {winner[2]:.4f})')
|
|
171
|
+
print(f' {winner[1]}')
|
|
172
|
+
else:
|
|
173
|
+
print('No completed candidates found')
|
|
174
|
+
sys.exit(0)
|
|
175
|
+
|
|
176
|
+
# Show header
|
|
177
|
+
print(f'🧬 Evolution Status Report - {evolution_context}')
|
|
178
|
+
print('=' * 50)
|
|
179
|
+
|
|
180
|
+
# Show overall stats
|
|
181
|
+
total_candidates = sum(total_stats.values())
|
|
182
|
+
if total_candidates > 0:
|
|
183
|
+
print(f'📊 OVERALL: {total_candidates} total candidates')
|
|
184
|
+
print(f' • {total_stats[\"pending\"]} pending')
|
|
185
|
+
print(f' • {total_stats[\"complete\"]} complete')
|
|
186
|
+
print(f' • {total_stats[\"failed\"]} failed')
|
|
187
|
+
print(f' • {total_stats[\"running\"]} running')
|
|
188
|
+
print()
|
|
189
|
+
|
|
190
|
+
# Show current winner
|
|
191
|
+
if winner:
|
|
192
|
+
print(f'🏆 CURRENT LEADER: {winner[0]} (score: {winner[2]:.4f})')
|
|
193
|
+
print(f' {winner[1]}')
|
|
194
|
+
print()
|
|
195
|
+
else:
|
|
196
|
+
print('🏆 CURRENT LEADER: None (no completed candidates)')
|
|
197
|
+
print()
|
|
198
|
+
|
|
199
|
+
# Show per-generation breakdown (unless brief mode)
|
|
200
|
+
if not show_brief and stats_by_gen:
|
|
201
|
+
print('📈 BY GENERATION:')
|
|
202
|
+
for gen in sorted(stats_by_gen.keys()):
|
|
203
|
+
data = stats_by_gen[gen]
|
|
204
|
+
total = sum(data.values())
|
|
205
|
+
|
|
206
|
+
# Find best performer in this generation
|
|
207
|
+
gen_candidates = [c for c in all_candidates if c[0].startswith(gen + '-')]
|
|
208
|
+
gen_best = max(gen_candidates, key=lambda x: x[2]) if gen_candidates else None
|
|
209
|
+
|
|
210
|
+
status_str = f'{data[\"pending\"]}p {data[\"complete\"]}c {data[\"failed\"]}f {data[\"running\"]}r'
|
|
211
|
+
|
|
212
|
+
if gen_best:
|
|
213
|
+
print(f' {gen}: {total} total ({status_str}) - best: {gen_best[0]} ({gen_best[2]:.4f})')
|
|
214
|
+
else:
|
|
215
|
+
print(f' {gen}: {total} total ({status_str}) - best: none')
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
print(f'Error reading evolution status: {e}')
|
|
219
|
+
sys.exit(1)
|
|
220
|
+
"
|