claude-evolve 1.8.13 → 1.8.15

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.
@@ -1057,6 +1057,11 @@ Current evolution context:
1057
1057
 
1058
1058
  IMPORTANT: DO NOT read algorithm.py or any evolution_*.py files. Focus on creative ideation based on the brief and CSV context only. Reading code files wastes tokens and time.
1059
1059
 
1060
+ CROSS-POLLINATION OPPORTUNITY:
1061
+ Consider looking at the last 20-30 ideas from other evolution files in sibling directories (../*/evolution.csv).
1062
+ These may contain different algorithmic approaches that could inspire novel combinations or variations.
1063
+ This is OPTIONAL - only do it if you think it would help generate more diverse ideas.
1064
+
1060
1065
  CRITICAL TASK:
1061
1066
  The CSV file already contains $count stub rows with these IDs: $required_ids_str
1062
1067
  Each stub row has a PLACEHOLDER description like: \"[PLACEHOLDER: Replace this with your algorithmic idea]\"
@@ -1191,7 +1196,10 @@ generate_hill_climbing_direct() {
1191
1196
  # Use relative paths and change to evolution directory so AI can access files
1192
1197
  local temp_csv_basename=$(basename "$temp_csv")
1193
1198
 
1194
- local prompt="I need you to use your file editing capabilities to fill in PLACEHOLDER descriptions in the CSV file: $temp_csv_basename
1199
+ # Build prompt using cat with heredoc to avoid variable expansion issues
1200
+ local prompt
1201
+ prompt=$(cat <<EOF
1202
+ I need you to use your file editing capabilities to fill in PLACEHOLDER descriptions in the CSV file: $temp_csv_basename
1195
1203
 
1196
1204
  THE FILE HAS $total_lines TOTAL LINES. Read from line $read_offset to see the placeholder rows at the end.
1197
1205
 
@@ -1201,6 +1209,15 @@ Successful algorithms to tune:
1201
1209
  $top_performers
1202
1210
 
1203
1211
  IMPORTANT: Generate parameter tuning ideas based primarily on the descriptions and scores above.
1212
+ EOF
1213
+ )
1214
+
1215
+ prompt+="
1216
+
1217
+ CROSS-POLLINATION OPPORTUNITY:
1218
+ Consider looking at the last 20-30 ideas from other evolution files in sibling directories (../*/evolution.csv).
1219
+ These may contain interesting parameter tuning approaches or strategies that could be applied to your top performers.
1220
+ This is OPTIONAL - only do it if you think it would help generate more diverse tuning ideas.
1204
1221
 
1205
1222
  ONLY read parent source files (evolution_<PARENT_ID>.py) if:
1206
1223
  - The description is too vague to identify specific parameters
@@ -1327,7 +1344,10 @@ generate_structural_mutation_direct() {
1327
1344
  # Use relative paths and change to evolution directory so AI can access files
1328
1345
  local temp_csv_basename=$(basename "$temp_csv")
1329
1346
 
1330
- local prompt="I need you to use your file editing capabilities to fill in PLACEHOLDER descriptions in the CSV file: $temp_csv_basename
1347
+ # Build prompt using cat with heredoc to avoid variable expansion issues
1348
+ local prompt
1349
+ prompt=$(cat <<EOF
1350
+ I need you to use your file editing capabilities to fill in PLACEHOLDER descriptions in the CSV file: $temp_csv_basename
1331
1351
 
1332
1352
  THE FILE HAS $total_lines TOTAL LINES. Read from line $read_offset to see the placeholder rows at the end.
1333
1353
 
@@ -1341,6 +1361,15 @@ IMPORTANT: DO NOT read evolution_*.py files. Generate structural ideas based ONL
1341
1361
  - The performance scores
1342
1362
  - Your knowledge of common algorithmic structures and patterns
1343
1363
  Reading code files wastes tokens and time. Focus on high-level architectural ideas based on the descriptions.
1364
+ EOF
1365
+ )
1366
+
1367
+ prompt+="
1368
+
1369
+ CROSS-POLLINATION OPPORTUNITY:
1370
+ Consider looking at the last 20-30 ideas from other evolution files in sibling directories (../*/evolution.csv).
1371
+ These may contain different structural approaches or architectural patterns that could be adapted to your top performers.
1372
+ This is OPTIONAL - only do it if you think it would help generate more creative structural modifications.
1344
1373
 
1345
1374
  CRITICAL TASK:
1346
1375
  The CSV file already contains $count stub rows with these IDs: $required_ids_str
@@ -1454,7 +1483,10 @@ generate_crossover_direct() {
1454
1483
  # Use relative paths and change to evolution directory so AI can access files
1455
1484
  local temp_csv_basename=$(basename "$temp_csv")
1456
1485
 
1457
- local prompt="I need you to use your file editing capabilities to fill in PLACEHOLDER descriptions in the CSV file: $temp_csv_basename
1486
+ # Build prompt using cat with heredoc to avoid variable expansion issues
1487
+ local prompt
1488
+ prompt=$(cat <<EOF
1489
+ I need you to use your file editing capabilities to fill in PLACEHOLDER descriptions in the CSV file: $temp_csv_basename
1458
1490
 
1459
1491
  THE FILE HAS $total_lines TOTAL LINES. Read from line $read_offset to see the placeholder rows at the end.
1460
1492
 
@@ -1468,6 +1500,15 @@ IMPORTANT: DO NOT read evolution_*.py files. Generate crossover ideas based ONLY
1468
1500
  - The performance scores
1469
1501
  - Your knowledge of how different algorithmic approaches can be combined
1470
1502
  Reading code files wastes tokens and time. Focus on combining the described features creatively.
1503
+ EOF
1504
+ )
1505
+
1506
+ prompt+="
1507
+
1508
+ CROSS-POLLINATION OPPORTUNITY:
1509
+ Consider looking at the last 20-30 ideas from other evolution files in sibling directories (../*/evolution.csv).
1510
+ These parallel evolutionary strains may have developed different successful features that could be crossed with your top performers.
1511
+ This is OPTIONAL - only do it if you think it would help generate more innovative hybrid ideas.
1471
1512
 
1472
1513
  CRITICAL TASK:
1473
1514
  The CSV file already contains $count stub rows with these IDs: $required_ids_str
@@ -1551,15 +1592,20 @@ ideate_ai_legacy() {
1551
1592
  # Build prompt for direct CSV modification
1552
1593
  # Use relative paths and change to evolution directory so AI can access files
1553
1594
  local temp_csv_basename=$(basename "$temp_csv")
1554
-
1555
- local prompt="I need you to use your file editing capabilities to add exactly $TOTAL_IDEAS algorithmic ideas to the CSV file: $temp_csv_basename
1595
+
1596
+ # Build initial prompt safely
1597
+ local prompt
1598
+ prompt=$(cat <<EOF
1599
+ I need you to use your file editing capabilities to add exactly $TOTAL_IDEAS algorithmic ideas to the CSV file: $temp_csv_basename
1556
1600
 
1557
1601
  Current evolution context:
1558
1602
  - Generation: $CURRENT_GENERATION
1559
1603
  - Algorithm: algorithm.py (base algorithm)
1560
1604
  - Brief: $(head -10 "$FULL_BRIEF_PATH" 2>/dev/null | head -c 1000 || echo "No brief file found")
1561
1605
 
1562
- IMPORTANT: DO NOT read algorithm.py or any evolution_*.py files - that uses too many tokens and is unnecessary for ideation. Just generate creative ideas based on the brief and top performers listed above. Focus your creativity on the problem space, not the implementation details."
1606
+ IMPORTANT: DO NOT read algorithm.py or any evolution_*.py files - that uses too many tokens and is unnecessary for ideation. Just generate creative ideas based on the brief and top performers listed above. Focus your creativity on the problem space, not the implementation details.
1607
+ EOF
1608
+ )
1563
1609
 
1564
1610
  if [[ -n $top_performers ]]; then
1565
1611
  prompt+="
@@ -1641,7 +1687,7 @@ echo "[INFO] Starting ideation for generation $CURRENT_GENERATION"
1641
1687
  # Main execution with retry logic and exponential backoff
1642
1688
  retry_count=0
1643
1689
  wait_seconds=300 # Start with 5 minutes
1644
- max_wait_seconds=1800 # Cap at 30 minutes
1690
+ max_wait_seconds=300 # Cap at 5 minutes
1645
1691
 
1646
1692
  while true; do
1647
1693
  if [[ $use_strategies == true ]]; then
@@ -275,29 +275,34 @@ count_pending_candidates() {
275
275
  # Function to get CSV stats
276
276
  get_csv_stats() {
277
277
  local csv_path="${1:-$FULL_CSV_PATH}"
278
-
278
+
279
279
  if [[ ! -f "$csv_path" ]]; then
280
280
  echo "[ERROR] CSV not found at: $csv_path" >&2
281
281
  echo "0 0 0"
282
282
  return
283
283
  fi
284
-
284
+
285
285
  local total_rows complete_count pending_count
286
286
  total_rows=$(wc -l < "$csv_path" | tr -d '[:space:]')
287
287
  complete_count=$(grep ',complete' "$csv_path" 2>/dev/null | wc -l | tr -d '[:space:]')
288
-
288
+
289
289
  # Count pending using UNIFIED CSV logic
290
290
  pending_count=$("$PYTHON_CMD" "$SCRIPT_DIR/../lib/evolution_csv.py" "$csv_path" count)
291
-
291
+
292
292
  echo "$total_rows $complete_count $pending_count"
293
293
  }
294
294
 
295
- echo "[DISPATCHER] Starting unified evolution engine"
296
- echo "[DISPATCHER] Configuration: max_workers=$MAX_WORKERS, timeout=${timeout_seconds:-none}"
295
+ # Function to perform full CSV cleanup (duplicates, stuck statuses, missing files, etc.)
296
+ cleanup_csv_full() {
297
+ if [[ ! -f "$FULL_CSV_PATH" ]]; then
298
+ echo "[DISPATCHER] No CSV file to clean up" >&2
299
+ return 0
300
+ fi
301
+
302
+ echo "[DISPATCHER] Performing full CSV cleanup..." >&2
297
303
 
298
- # Clean up any stuck 'running' statuses and duplicates at startup
299
- if [[ -f "$FULL_CSV_PATH" ]]; then
300
- echo "[DISPATCHER] Checking for duplicate candidates..."
304
+ # Remove duplicate candidates
305
+ echo "[DISPATCHER] Checking for duplicate candidates..." >&2
301
306
  "$PYTHON_CMD" -c "
302
307
  import sys
303
308
  sys.path.insert(0, '$SCRIPT_DIR/..')
@@ -312,53 +317,49 @@ except Exception as e:
312
317
  print(f'[ERROR] Failed to remove duplicates: {e}', file=sys.stderr)
313
318
  " 2>&1 || true
314
319
 
315
- echo "[DISPATCHER] Resetting any stuck 'running' candidates to 'pending'..."
320
+ # Reset stuck 'running' candidates
321
+ echo "[DISPATCHER] Resetting any stuck 'running' candidates to 'pending'..." >&2
316
322
  if "$SCRIPT_DIR/claude-evolve-edit" running pending >/dev/null 2>&1; then
317
- echo "[DISPATCHER] Successfully reset stuck candidates"
323
+ echo "[DISPATCHER] Successfully reset stuck candidates" >&2
318
324
  else
319
- echo "[DISPATCHER] No stuck candidates found or edit command not available"
325
+ echo "[DISPATCHER] No stuck candidates found or edit command not available" >&2
320
326
  fi
321
- fi
322
327
 
323
- # Validate CSV and clean up stuck statuses and duplicates
324
- if [[ -f "$FULL_CSV_PATH" ]]; then
325
- echo "[DISPATCHER] Validating CSV and cleaning up..."
326
-
327
- # First check for and clean up duplicates
328
- echo "[DISPATCHER] Checking for duplicate entries..."
328
+ # Clean up duplicates with the dedicated cleanup script
329
+ echo "[DISPATCHER] Checking for duplicate entries..." >&2
329
330
  duplicate_check_output=$("$PYTHON_CMD" "$SCRIPT_DIR/claude-evolve-cleanup-duplicates" "$FULL_CSV_PATH" 2>&1)
330
331
  if echo "$duplicate_check_output" | grep -q "Found.*duplicate"; then
331
- echo "[DISPATCHER] WARNING: Duplicate entries detected in CSV!"
332
- echo "$duplicate_check_output"
333
- echo "[DISPATCHER] Automatically cleaning up duplicates..."
332
+ echo "[DISPATCHER] WARNING: Duplicate entries detected in CSV!" >&2
333
+ echo "$duplicate_check_output" >&2
334
+ echo "[DISPATCHER] Automatically cleaning up duplicates..." >&2
334
335
  if "$PYTHON_CMD" "$SCRIPT_DIR/claude-evolve-cleanup-duplicates" "$FULL_CSV_PATH" --fix; then
335
- echo "[DISPATCHER] Duplicates cleaned up successfully"
336
+ echo "[DISPATCHER] Duplicates cleaned up successfully" >&2
336
337
  else
337
338
  echo "[ERROR] Failed to clean up duplicates" >&2
338
- exit 1
339
+ return 1
339
340
  fi
340
341
  else
341
- echo "[DISPATCHER] No duplicates found"
342
+ echo "[DISPATCHER] No duplicates found" >&2
342
343
  fi
343
-
344
- # Check for and clean up invalid entries
345
- echo "[DISPATCHER] Checking for invalid entries..."
344
+
345
+ # Clean up invalid entries
346
+ echo "[DISPATCHER] Checking for invalid entries..." >&2
346
347
  invalid_check_output=$("$PYTHON_CMD" "$SCRIPT_DIR/claude-evolve-clean-invalid" "$FULL_CSV_PATH" --dry-run 2>&1)
347
348
  if echo "$invalid_check_output" | grep -q "Found.*invalid"; then
348
- echo "[DISPATCHER] WARNING: Invalid entries detected in CSV!"
349
- echo "$invalid_check_output"
350
- echo "[DISPATCHER] Automatically cleaning up invalid entries..."
349
+ echo "[DISPATCHER] WARNING: Invalid entries detected in CSV!" >&2
350
+ echo "$invalid_check_output" >&2
351
+ echo "[DISPATCHER] Automatically cleaning up invalid entries..." >&2
351
352
  if "$PYTHON_CMD" "$SCRIPT_DIR/claude-evolve-clean-invalid" "$FULL_CSV_PATH"; then
352
- echo "[DISPATCHER] Invalid entries cleaned up successfully"
353
+ echo "[DISPATCHER] Invalid entries cleaned up successfully" >&2
353
354
  else
354
355
  echo "[ERROR] Failed to clean up invalid entries" >&2
355
- exit 1
356
+ return 1
356
357
  fi
357
358
  else
358
- echo "[DISPATCHER] No invalid entries found"
359
+ echo "[DISPATCHER] No invalid entries found" >&2
359
360
  fi
360
-
361
- # Then validate and clean stuck statuses
361
+
362
+ # Clean stuck statuses and missing files
362
363
  if ! "$PYTHON_CMD" -c "
363
364
  import csv
364
365
  import sys
@@ -366,90 +367,88 @@ import os
366
367
  from pathlib import Path
367
368
 
368
369
  csv_file = '$FULL_CSV_PATH'
369
- full_output_dir = '$FULL_OUTPUT_DIR' # Pass FULL_OUTPUT_DIR to Python script
370
- script_dir = '$SCRIPT_DIR' # Pass SCRIPT_DIR for sys.path.append
370
+ full_output_dir = '$FULL_OUTPUT_DIR'
371
+ script_dir = '$SCRIPT_DIR'
371
372
 
372
373
  try:
373
- # Read CSV - let Python's csv module handle all the complexity
374
374
  with open(csv_file, 'r') as f:
375
375
  reader = csv.reader(f)
376
376
  rows = list(reader)
377
-
377
+
378
378
  if not rows:
379
379
  print('[ERROR] CSV is empty')
380
380
  sys.exit(1)
381
-
382
- # Basic sanity checks
383
- header = rows[0]
384
- num_fields = len(header)
385
-
381
+
386
382
  if len(rows) == 1:
387
383
  print('[INFO] CSV has no data rows (only header)')
388
-
384
+
389
385
  changed_count = 0
390
-
386
+
391
387
  # Clean up any stuck 'running' statuses
392
388
  for i in range(1, len(rows)):
393
389
  if len(rows[i]) > 4 and rows[i][4] == 'running':
394
390
  rows[i][4] = ''
395
391
  changed_count += 1
396
392
 
397
- # Reset failed-parent-missing to pending at startup - give them another chance
393
+ # Reset failed-parent-missing to pending - give them another chance
398
394
  for i in range(1, len(rows)):
399
395
  if len(rows[i]) > 4 and rows[i][4] == 'failed-parent-missing':
400
396
  rows[i][4] = 'pending'
401
397
  changed_count += 1
402
-
398
+
403
399
  # Check for missing Python files for completed/failed candidates
404
400
  for i in range(1, len(rows)):
405
401
  if len(rows[i]) > 4:
406
402
  candidate_id = rows[i][0]
407
403
  status = rows[i][4]
408
-
409
- # Only check if status implies a file should exist
404
+
410
405
  if status in ['complete', 'failed', 'failed-ai-retry', 'failed-retry1', 'failed-retry2', 'failed-retry3']:
411
406
  expected_file = Path(full_output_dir) / f'evolution_{candidate_id}.py'
412
407
  if not expected_file.is_file():
413
408
  print(f'[INFO] Detected missing file for {candidate_id} (status: {status}). Resetting to pending.')
414
- rows[i][4] = 'pending' # Reset status to pending
415
- # Clear performance and other fields if desired, for a clean retry
416
- if len(rows[i]) > 3: rows[i][3] = '' # Performance
417
- if len(rows[i]) > 5: rows[i][5] = '' # LLM used for run
409
+ rows[i][4] = 'pending'
410
+ if len(rows[i]) > 3: rows[i][3] = ''
411
+ if len(rows[i]) > 5: rows[i][5] = ''
418
412
  changed_count += 1
419
-
413
+
420
414
  if changed_count > 0:
421
- # Write back
422
415
  with open(csv_file + '.tmp', 'w', newline='') as f:
423
416
  writer = csv.writer(f)
424
417
  writer.writerows(rows)
425
418
  os.rename(csv_file + '.tmp', csv_file)
426
419
  print(f'[INFO] Reset {changed_count} candidates (stuck running or missing files) to pending')
427
-
428
- # Count pending candidates using UNIFIED logic
420
+
429
421
  sys.path.append(script_dir + '/..')
430
422
  from lib.evolution_csv import EvolutionCSV
431
-
423
+
432
424
  with EvolutionCSV(csv_file) as csv_ops:
433
- # Auto-fix any corrupted status fields before counting
434
425
  fixed = csv_ops.cleanup_corrupted_status_fields()
435
426
  if fixed > 0:
436
427
  print(f'[INFO] Auto-fixed {fixed} corrupted status field(s)', file=sys.stderr)
437
428
  pending = csv_ops.count_pending_candidates()
438
429
 
439
430
  print(f'[INFO] CSV loaded: {len(rows)-1} total candidates, {pending} pending')
440
-
431
+
441
432
  except csv.Error as e:
442
433
  print(f'[ERROR] CSV parsing error: {e}')
443
- print('[ERROR] The CSV file appears to be malformed')
444
434
  sys.exit(1)
445
435
  except Exception as e:
446
436
  print(f'[ERROR] Failed to read CSV: {e}')
447
437
  sys.exit(1)
448
438
  " 2>&1; then
449
- echo "[ERROR] CSV validation failed. Please check the error message above."
450
- exit 1
439
+ echo "[ERROR] CSV validation failed during cleanup" >&2
440
+ return 1
451
441
  fi
452
- fi
442
+
443
+ echo "[DISPATCHER] Full CSV cleanup complete" >&2
444
+ return 0
445
+ }
446
+
447
+ echo "[DISPATCHER] Starting unified evolution engine"
448
+ echo "[DISPATCHER] Configuration: max_workers=$MAX_WORKERS, timeout=${timeout_seconds:-none}"
449
+
450
+ # Perform full CSV cleanup at startup
451
+ cleanup_csv_full || exit 1
453
452
 
454
453
  # Automatic cleanup detection - check for unchanged algorithms and warn user
455
454
  echo "[DISPATCHER] Checking for duplicate/unchanged algorithms..."
@@ -585,8 +584,28 @@ while true; do
585
584
 
586
585
  # Check if API limit was reached
587
586
  if [[ "$api_limit_reached" == "true" ]]; then
588
- echo "[DISPATCHER] Stopping evolution run due to API usage limits" >&2
589
- break
587
+ echo "[DISPATCHER] All AI models hit usage limits" >&2
588
+ echo "[DISPATCHER] Waiting 5 minutes before restarting the run process..." >&2
589
+
590
+ # Wait 5 minutes with countdown
591
+ remaining=300
592
+ while [[ $remaining -gt 0 ]]; do
593
+ if [[ $((remaining % 60)) -eq 0 ]]; then
594
+ echo "[DISPATCHER] Restarting in $((remaining / 60)) minutes..." >&2
595
+ fi
596
+ sleep 60
597
+ remaining=$((remaining - 60))
598
+ done
599
+
600
+ echo "[DISPATCHER] Restarting run process to clear stuck states and retry..." >&2
601
+ # Perform full CSV cleanup to reset stuck states, just like at startup
602
+ cleanup_csv_full || {
603
+ echo "[ERROR] CSV cleanup failed after API limit wait" >&2
604
+ # Continue anyway - better to try than to stop completely
605
+ }
606
+ # Clear the flag and continue - this restarts the main loop
607
+ api_limit_reached=false
608
+ continue
590
609
  fi
591
610
 
592
611
  # Periodic cleanup of stuck candidates (every 5 iterations, ~25 seconds)
@@ -104,7 +104,7 @@ call_ai_for_evolution() {
104
104
  local retry_count=0
105
105
  local max_retries=3
106
106
  local wait_seconds=300 # Start with 5 minutes
107
- local max_wait_seconds=1800 # Cap at 30 minutes
107
+ local max_wait_seconds=300 # Cap at 5 minutes
108
108
 
109
109
  while true; do
110
110
  # Capture file state before AI call
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="gemini-pro sonnet-think gpt5high glm-openrouter grok-4-openrouter deepseek-openrouter glm-zai"
63
+ DEFAULT_LLM_IDEATE="opus 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-evolve",
3
- "version": "1.8.13",
3
+ "version": "1.8.15",
4
4
  "bin": {
5
5
  "claude-evolve": "./bin/claude-evolve",
6
6
  "claude-evolve-main": "./bin/claude-evolve-main",
@@ -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: gemini sonnet-think gpt5high o3high glm grok-4 codex-qwen3
83
+ #ideate: opus 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