claude-evolve 1.5.0 → 1.5.2

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.
@@ -6,6 +6,10 @@ set -e
6
6
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
7
  # shellcheck source=../lib/config.sh
8
8
  source "$SCRIPT_DIR/../lib/config.sh"
9
+ # shellcheck source=../lib/csv-lock.sh
10
+ source "$SCRIPT_DIR/../lib/csv-lock.sh"
11
+ # shellcheck source=../lib/ai-cli.sh
12
+ source "$SCRIPT_DIR/../lib/ai-cli.sh"
9
13
 
10
14
  # Use CLAUDE_EVOLVE_CONFIG if set, otherwise default
11
15
  if [[ -n ${CLAUDE_EVOLVE_CONFIG:-} ]]; then
@@ -14,197 +18,57 @@ else
14
18
  load_config
15
19
  fi
16
20
 
17
- # Function to determine which model to use based on generation
18
- get_model_for_generation() {
19
- local generation="$1"
20
- local gen_num
21
-
22
- # Extract numeric part of generation (e.g., "05" from gen05)
23
- if [[ $generation =~ ^0*([0-9]+)$ ]]; then
24
- gen_num=$((10#${BASH_REMATCH[1]}))
25
- else
26
- gen_num=1 # Default for malformed input
27
- fi
28
-
29
- # Check which AI tools are available
30
- local has_o3=false
31
- local has_gemini=false
32
-
33
- if command -v codex >/dev/null 2>&1; then
34
- has_o3=true
35
- fi
36
-
37
- if command -v gemini >/dev/null 2>&1; then
38
- has_gemini=true
39
- fi
40
-
41
- # Determine rotation based on what's available
42
- if [[ "$has_o3" == "true" && "$has_gemini" == "true" ]]; then
43
- # All three available: opus -> o3 -> gemini rotation
44
- case $((gen_num % 3)) in
45
- 1) echo "opus" ;; # 1, 4, 7, 10...
46
- 2) echo "o3" ;; # 2, 5, 8, 11...
47
- 0) echo "gemini" ;; # 3, 6, 9, 12...
48
- esac
49
- elif [[ "$has_o3" == "true" ]]; then
50
- # Only opus and o3: alternate between them
51
- if (( gen_num % 2 == 1 )); then
52
- echo "opus" # Odd generations
53
- else
54
- echo "o3" # Even generations
55
- fi
56
- elif [[ "$has_gemini" == "true" ]]; then
57
- # Only opus and gemini: alternate between them
58
- if (( gen_num % 2 == 1 )); then
59
- echo "opus" # Odd generations
60
- else
61
- echo "gemini" # Even generations
62
- fi
63
- else
64
- # Only opus available
65
- echo "opus"
66
- fi
67
- }
68
-
69
- # Helper function to call AI model (alternating based on generation)
21
+ # Helper function to call AI with limit check
70
22
  call_ai_with_limit_check() {
71
23
  local prompt="$1"
72
24
  local generation="${2:-01}" # Default to generation 01 if not provided
73
25
 
74
- # Determine which model to use for this generation
75
- local preferred_model
76
- preferred_model=$(get_model_for_generation "$generation")
77
-
78
- echo "[INFO] Generation $generation: Using $preferred_model" >&2
79
-
80
- # Try preferred model first
81
- if [[ "$preferred_model" == "o3" ]] && command -v codex >/dev/null 2>&1; then
82
- echo "[INFO] Using codex o3 for ideation" >&2
83
-
84
- # Call codex with o3 model using exec subcommand
85
- local ai_output
86
- ai_output=$(echo "$prompt" | codex exec -m o3 --full-auto 2>&1)
87
- local ai_exit_code=$?
88
-
89
- if [[ $ai_exit_code -eq 0 ]]; then
90
- # Clean o3 output - it may be JSON with the response in a field
91
- local cleaned_output
92
- # Try to extract content from JSON response if present
93
- if echo "$ai_output" | grep -q '"content"'; then
94
- # Attempt to extract content field from JSON
95
- cleaned_output=$(echo "$ai_output" | python3 -c "
96
- import sys
97
- import json
98
- try:
99
- data = json.load(sys.stdin)
100
- if 'content' in data:
101
- print(data['content'])
102
- elif 'response' in data:
103
- print(data['response'])
104
- elif 'text' in data:
105
- print(data['text'])
106
- else:
107
- # If no known field, print the whole thing
108
- print(json.dumps(data))
109
- except:
110
- # If not valid JSON, print as-is
111
- print(sys.stdin.read())
112
- " 2>/dev/null || echo "$ai_output")
113
- else
114
- cleaned_output="$ai_output"
115
- fi
116
-
117
- # Validate the output is not empty and doesn't contain error messages
118
- if [[ -n "$cleaned_output" ]] && ! echo "$cleaned_output" | grep -q "error\|failed\|exception"; then
119
- echo "$cleaned_output"
120
- return 0
121
- else
122
- echo "[WARN] Codex o3 returned invalid output, falling back to Claude Opus" >&2
123
- preferred_model="opus"
124
- fi
125
- else
126
- echo "[WARN] Codex o3 failed with exit code $ai_exit_code, falling back to Claude Opus" >&2
127
- preferred_model="opus"
128
- fi
129
- elif [[ "$preferred_model" == "gemini" ]] && command -v gemini >/dev/null 2>&1; then
130
- echo "[INFO] Using gemini 2.5 pro for ideation" >&2
131
-
132
- # Call gemini with -y and -p flags
133
- local ai_output
134
- ai_output=$(gemini -y -p "$prompt" 2>&1)
135
- local ai_exit_code=$?
136
-
137
- if [[ $ai_exit_code -eq 0 ]]; then
138
- # Check for authentication messages or other non-response content
139
- if echo "$ai_output" | grep -q "Attempting to authenticate\|Authenticating\|Loading\|Initializing"; then
140
- echo "[WARN] Gemini is still authenticating, falling back to Claude Opus" >&2
141
- preferred_model="opus"
142
- elif [[ -z "$ai_output" ]] || [[ $(echo "$ai_output" | wc -l) -lt 2 ]]; then
143
- echo "[WARN] Gemini returned insufficient output, falling back to Claude Opus" >&2
144
- preferred_model="opus"
145
- else
146
- echo "$ai_output"
147
- return 0
148
- fi
149
- else
150
- echo "[WARN] Gemini failed with exit code $ai_exit_code, falling back to Claude Opus" >&2
151
- preferred_model="opus"
152
- fi
26
+ # Calculate hash value for round-robin based on generation
27
+ local gen_num
28
+ if [[ $generation =~ ^0*([0-9]+)$ ]]; then
29
+ gen_num=$((10#${BASH_REMATCH[1]}))
30
+ else
31
+ gen_num=1
153
32
  fi
154
33
 
155
- # Use Claude with preferred model (or fallback)
156
- echo "[INFO] Using Claude $preferred_model for ideation" >&2
157
-
158
- # Call Claude and capture output
159
- local claude_output
160
- claude_output=$(echo "$prompt" | claude --dangerously-skip-permissions --model "$preferred_model" -p 2>&1)
161
- local claude_exit_code=$?
34
+ # Use centralized AI library for ideation
35
+ local ai_output
36
+ ai_output=$(call_ai_with_round_robin "$prompt" "ideate" "$gen_num")
37
+ local ai_exit_code=$?
162
38
 
163
- # Check for usage limit
164
- if echo "$claude_output" | grep -q "Claude AI usage limit reached"; then
165
- # Extract timestamp if available
166
- local limit_timestamp=$(echo "$claude_output" | grep -o "Claude AI usage limit reached|[0-9]*" | cut -d'|' -f2)
167
-
168
- # Print red error message
169
- echo -e "\033[31m[ERROR] CLAUDE AI USAGE LIMIT REACHED!\033[0m" >&2
39
+ # Handle special exit codes
40
+ if [[ $ai_exit_code -eq 3 ]]; then
41
+ # All models hit usage limits
42
+ echo -e "\033[31m[ERROR] ALL AI MODELS HIT USAGE LIMITS!\033[0m" >&2
170
43
  echo -e "\033[31m[ERROR] Ideation halted due to API rate limits.\033[0m" >&2
171
-
172
- if [[ -n $limit_timestamp ]]; then
173
- # Convert timestamp to human-readable format
174
- local limit_date=$(date -r "$limit_timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "Unknown time")
175
- echo -e "\033[31m[ERROR] Limit will be released at: $limit_date\033[0m" >&2
176
- fi
177
-
178
- echo -e "\033[33m[INFO] Please wait for the rate limit to reset before continuing.\033[0m" >&2
179
- echo -e "\033[33m[INFO] No ideas were generated. Run ideate again when the limit resets.\033[0m" >&2
180
-
44
+ echo -e "\033[33m[INFO] Please wait for the rate limits to reset before continuing.\033[0m" >&2
45
+ echo -e "\033[33m[INFO] No ideas were generated. Run ideate again when the limits reset.\033[0m" >&2
181
46
  exit 1
182
47
  fi
183
48
 
184
- # Validate output doesn't contain shell constructs that could corrupt CSV
185
- if echo "$claude_output" | grep -E "EOF.*<.*null|<<.*EOF|<.*dev.*null" >/dev/null 2>&1; then
186
- echo "[ERROR] AI output contains invalid shell constructs" >&2
187
- echo "[DEBUG] Problematic output: $claude_output" | head -5 >&2
188
- return 1
49
+ if [[ $ai_exit_code -eq 0 ]]; then
50
+ # For ideation, AI modifies files directly - just return success
51
+ echo "[INFO] AI succeeded" >&2
52
+ return 0
53
+ else
54
+ return $ai_exit_code
189
55
  fi
190
-
191
- # Output Claude's response
192
- echo "$claude_output"
193
-
194
- return $claude_exit_code
195
56
  }
196
57
 
58
+
197
59
  # Backward compatibility alias
198
60
  call_claude_with_limit_check() {
199
61
  call_ai_with_limit_check "$@"
200
62
  }
201
63
 
202
64
  # Robust AI calling with fallbacks across all available models
203
- call_ai_with_fallbacks() {
65
+ call_ai_for_ideation() {
204
66
  local prompt="$1"
205
67
  local generation="${2:-01}"
68
+ local expected_count="${3:-1}" # Number of ideas expected to be added
69
+ local temp_csv_file="${4:-temp-csv-$$.csv}" # Optional temp CSV filename
206
70
 
207
- # Determine which model to use based on generation (round-robin)
71
+ # Calculate hash value for round-robin based on generation
208
72
  local gen_num
209
73
  if [[ $generation =~ ^0*([0-9]+)$ ]]; then
210
74
  gen_num=$((10#${BASH_REMATCH[1]}))
@@ -212,100 +76,47 @@ call_ai_with_fallbacks() {
212
76
  gen_num=1
213
77
  fi
214
78
 
215
- # Check which AI tools are available
216
- local available_models=()
217
- if command -v codex >/dev/null 2>&1; then
218
- available_models+=("o3")
219
- fi
220
- if command -v gemini >/dev/null 2>&1; then
221
- available_models+=("gemini")
79
+ # Get the current row count before any modifications
80
+ local original_csv_count
81
+ if [[ -f "$temp_csv_file" ]]; then
82
+ original_csv_count=$(grep -v '^[[:space:]]*$' "$temp_csv_file" | tail -n +2 | wc -l)
83
+ else
84
+ original_csv_count=0
222
85
  fi
223
- available_models+=("opus") # Claude Opus always available
224
86
 
225
- # Create ordered list based on round-robin for this generation
226
- local num_models=${#available_models[@]}
227
- local start_index=$((gen_num % num_models))
228
- local models=()
87
+ # Use centralized AI library
88
+ local ai_output
89
+ ai_output=$(call_ai_with_round_robin "$prompt" "ideate" "$gen_num")
90
+ local ai_exit_code=$?
229
91
 
230
- # Add models in round-robin order starting from the calculated index
231
- for ((i=0; i<num_models; i++)); do
232
- local idx=$(((start_index + i) % num_models))
233
- models+=("${available_models[$idx]}")
234
- done
235
-
236
- echo "[INFO] Model order for generation $generation (round-robin): ${models[*]}" >&2
92
+ # Handle special exit codes
93
+ # No special handling for exit codes anymore
237
94
 
238
- # Try each model in the ordered sequence
239
- for model in "${models[@]}"; do
240
- echo "[INFO] Trying $model for ideation" >&2
241
-
242
- local ai_output
243
- local ai_exit_code
244
-
245
- if [[ "$model" == "o3" ]] && command -v codex >/dev/null 2>&1; then
246
- ai_output=$(echo "$prompt" | codex exec -m o3 --full-auto 2>&1)
247
- ai_exit_code=$?
95
+ if [[ $ai_exit_code -eq 0 ]]; then
96
+ # For ideation, we need to verify the CSV file was actually modified
97
+ if [[ -f "$temp_csv_file" ]]; then
98
+ local new_csv_count
99
+ new_csv_count=$(grep -v '^[[:space:]]*$' "$temp_csv_file" | tail -n +2 | wc -l)
248
100
 
249
- if [[ $ai_exit_code -eq 0 ]]; then
250
- # Clean o3 output like in the original function
251
- if echo "$ai_output" | grep -q '"content"'; then
252
- ai_output=$(echo "$ai_output" | python3 -c "
253
- import sys
254
- import json
255
- try:
256
- data = json.load(sys.stdin)
257
- if 'content' in data:
258
- print(data['content'])
259
- elif 'response' in data:
260
- print(data['response'])
261
- elif 'text' in data:
262
- print(data['text'])
263
- else:
264
- print(json.dumps(data))
265
- except:
266
- print(sys.stdin.read())
267
- " 2>/dev/null || echo "$ai_output")
268
- fi
269
-
270
- if [[ -n "$ai_output" ]] && ! echo "$ai_output" | grep -q "error\|failed\|exception"; then
271
- echo "$ai_output"
272
- return 0
273
- fi
274
- fi
275
-
276
- elif [[ "$model" == "gemini" ]] && command -v gemini >/dev/null 2>&1; then
277
- ai_output=$(gemini -y -p "$prompt" 2>&1)
278
- ai_exit_code=$?
279
-
280
- if [[ $ai_exit_code -eq 0 ]]; then
281
- if ! echo "$ai_output" | grep -q "Attempting to authenticate\|Authenticating\|Loading\|Initializing"; then
282
- if [[ -n "$ai_output" ]] && [[ $(echo "$ai_output" | wc -l) -ge 2 ]]; then
283
- echo "$ai_output"
284
- return 0
285
- fi
286
- fi
101
+ if [[ $new_csv_count -gt $original_csv_count ]]; then
102
+ echo "[INFO] AI completed successfully and modified CSV ($new_csv_count vs $original_csv_count rows)" >&2
103
+ return 0
104
+ else
105
+ echo "[INFO] $model returned exit code 0 but didn't modify CSV file" >&2
106
+ echo "[DEBUG] Expected file: $temp_csv_file" >&2
107
+ echo "[DEBUG] Original count: $original_csv_count, New count: $new_csv_count" >&2
108
+ return 1
287
109
  fi
288
-
289
110
  else
290
- # Use Claude with the specified model
291
- ai_output=$(echo "$prompt" | claude --dangerously-skip-permissions --model "$model" -p 2>&1)
292
- ai_exit_code=$?
293
-
294
- if [[ $ai_exit_code -eq 0 ]]; then
295
- # Check for usage limits
296
- if ! echo "$ai_output" | grep -q "Claude AI usage limit reached"; then
297
- if ! echo "$ai_output" | grep -E "EOF.*<.*null|<<.*EOF|<.*dev.*null" >/dev/null 2>&1; then
298
- echo "$ai_output"
299
- return 0
300
- fi
301
- fi
302
- fi
111
+ echo "[INFO] Exit code 0 but temp CSV file not found: $temp_csv_file" >&2
112
+ echo "[DEBUG] Current directory: $(pwd)" >&2
113
+ echo "[DEBUG] Files matching temp-csv-*.csv:" >&2
114
+ ls -la temp-csv-*.csv 2>&1 >&2
115
+ return 1
303
116
  fi
304
-
305
- echo "[WARN] $model failed or returned unusable output, trying next model..." >&2
306
- done
117
+ fi
307
118
 
308
- echo "[ERROR] All AI models failed to generate usable output" >&2
119
+ echo "[INFO] No AI model successfully modified the CSV file" >&2
309
120
  return 1
310
121
  }
311
122
 
@@ -375,16 +186,15 @@ if [[ $use_strategies == true ]]; then
375
186
  fi
376
187
  fi
377
188
 
378
- # Get next generation number
189
+ # Get next generation number that doesn't have existing Python files
379
190
  get_next_generation() {
380
- if [[ ! -f "$FULL_CSV_PATH" ]]; then
381
- echo "01"
382
- return
383
- fi
191
+ # Start with generation 1 if no CSV exists
192
+ local start_gen=1
384
193
 
385
- # Use Python for proper CSV parsing
386
- local max_gen
387
- max_gen=$("$PYTHON_CMD" -c "
194
+ if [[ -f "$FULL_CSV_PATH" ]]; then
195
+ # Use Python for proper CSV parsing to find max generation
196
+ local max_gen
197
+ max_gen=$("$PYTHON_CMD" -c "
388
198
  import csv
389
199
  max_gen = 0
390
200
  with open('$FULL_CSV_PATH', 'r') as f:
@@ -402,9 +212,36 @@ with open('$FULL_CSV_PATH', 'r') as f:
402
212
  pass
403
213
  print(max_gen)
404
214
  ")
215
+ # Start checking from the next generation after max
216
+ start_gen=$((max_gen + 1))
217
+ fi
405
218
 
406
- # Increment and format with leading zero
407
- printf "%02d" $((max_gen + 1))
219
+ # Keep incrementing until we find a generation with no Python files
220
+ local candidate_gen=$start_gen
221
+ while true; do
222
+ local gen_formatted=$(printf "%02d" $candidate_gen)
223
+
224
+ # Check if any Python files exist for this generation
225
+ local py_files_exist=false
226
+ if ls "$FULL_OUTPUT_DIR"/evolution_gen${gen_formatted}-*.py >/dev/null 2>&1; then
227
+ py_files_exist=true
228
+ fi
229
+
230
+ if [[ "$py_files_exist" == "false" ]]; then
231
+ # This generation is safe to use
232
+ echo "$gen_formatted"
233
+ return
234
+ else
235
+ echo "[WARN] Generation $gen_formatted already has Python files, skipping to next generation" >&2
236
+ candidate_gen=$((candidate_gen + 1))
237
+
238
+ # Safety check to prevent infinite loop
239
+ if [[ $candidate_gen -gt 999 ]]; then
240
+ echo "[ERROR] Could not find a safe generation number (checked up to 999)" >&2
241
+ exit 1
242
+ fi
243
+ fi
244
+ done
408
245
  }
409
246
 
410
247
  # This function is no longer used with direct CSV modification approach
@@ -439,31 +276,64 @@ validate_direct_csv_modification() {
439
276
  return 1
440
277
  fi
441
278
 
442
- # Validate the modified CSV has more entries than original
443
- # Count actual data rows (excluding header and empty lines)
444
- local original_count
445
- original_count=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
279
+ # Get the count before modification from the temp CSV (which was copied from original before AI ran)
280
+ # We need to track this before the AI runs by reading from the beginning state
281
+ # First, get a fresh count from the current main CSV (which reflects any previous operations in this session)
282
+ local current_original_count
283
+ current_original_count=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
284
+
285
+ # Count data rows in the modified temp CSV
446
286
  local new_count
447
287
  new_count=$(grep -v '^[[:space:]]*$' "$temp_csv" | tail -n +2 | wc -l)
448
288
 
449
- echo "[DEBUG] Original CSV data rows: $original_count" >&2
450
- echo "[DEBUG] Modified CSV data rows: $new_count" >&2
289
+ echo "[DEBUG] Current main CSV data rows: $current_original_count" >&2
290
+ echo "[DEBUG] Modified temp CSV data rows: $new_count" >&2
451
291
  echo "[DEBUG] Expected to add: $expected_count ideas" >&2
452
292
 
453
- if [[ $new_count -le $original_count ]]; then
454
- echo "[ERROR] CSV file wasn't modified - same number of data rows ($new_count <= $original_count)" >&2
293
+ # Check if AI overwrote the file instead of appending
294
+ if [[ $new_count -lt $current_original_count ]]; then
295
+ echo "[ERROR] AI overwrote the CSV file instead of appending ($new_count < $current_original_count)" >&2
455
296
  echo "[DEBUG] First 10 lines of CSV after AI attempt:" >&2
456
297
  head -10 "$temp_csv" >&2
457
298
  return 1
458
299
  fi
459
300
 
460
- local added_count=$((new_count - original_count))
301
+ # Check if no changes were made
302
+ if [[ $new_count -eq $current_original_count ]]; then
303
+ echo "[ERROR] CSV file wasn't modified - same number of data rows ($new_count = $current_original_count)" >&2
304
+ echo "[DEBUG] First 10 lines of CSV after AI attempt:" >&2
305
+ head -10 "$temp_csv" >&2
306
+ return 1
307
+ fi
308
+
309
+ local added_count=$((new_count - current_original_count))
461
310
  if [[ $added_count -ne $expected_count ]]; then
462
311
  echo "[WARN] Expected to add $expected_count ideas but added $added_count" >&2
463
312
  fi
464
313
 
465
- # Replace original CSV with modified version
466
- mv "$temp_csv" "$FULL_CSV_PATH"
314
+ # Use proper locking to safely update the CSV
315
+ echo "[INFO] Acquiring CSV lock to apply changes..."
316
+
317
+ # Set the lockfile path
318
+ CSV_LOCKFILE="$FULL_EVOLUTION_DIR/.evolution.csv.lock"
319
+
320
+ if ! acquire_csv_lock; then
321
+ echo "[ERROR] Failed to acquire CSV lock for update" >&2
322
+ rm -f "$temp_csv"
323
+ return 1
324
+ fi
325
+
326
+ # Get just the new entries (skip header and existing entries)
327
+ local original_line_count=$(wc -l < "$FULL_CSV_PATH")
328
+
329
+ # Append only the new lines from temp CSV to the main CSV
330
+ tail -n +$((original_line_count + 1)) "$temp_csv" >> "$FULL_CSV_PATH"
331
+
332
+ # Clean up temp file
333
+ rm -f "$temp_csv"
334
+
335
+ # Release the lock
336
+ release_csv_lock
467
337
 
468
338
  echo "[INFO] Successfully added $added_count $idea_type ideas to CSV"
469
339
  return 0
@@ -534,8 +404,29 @@ validate_and_apply_csv_modification_old() {
534
404
  echo "[WARN] Expected to add $expected_count ideas but added $added_count" >&2
535
405
  fi
536
406
 
537
- # Replace original CSV with modified version
538
- mv "$temp_csv" "$FULL_CSV_PATH"
407
+ # Use proper locking to safely update the CSV
408
+ echo "[INFO] Acquiring CSV lock to apply changes..."
409
+
410
+ # Set the lockfile path
411
+ CSV_LOCKFILE="$FULL_EVOLUTION_DIR/.evolution.csv.lock"
412
+
413
+ if ! acquire_csv_lock; then
414
+ echo "[ERROR] Failed to acquire CSV lock for update" >&2
415
+ rm -f "$temp_csv"
416
+ return 1
417
+ fi
418
+
419
+ # Get just the new entries (skip header and existing entries)
420
+ local original_line_count=$(wc -l < "$FULL_CSV_PATH")
421
+
422
+ # Append only the new lines from temp CSV to the main CSV
423
+ tail -n +$((original_line_count + 1)) "$temp_csv" >> "$FULL_CSV_PATH"
424
+
425
+ # Clean up temp file
426
+ rm -f "$temp_csv"
427
+
428
+ # Release the lock
429
+ release_csv_lock
539
430
 
540
431
  echo "[INFO] Successfully added $added_count $idea_type ideas to CSV"
541
432
  return 0
@@ -580,8 +471,8 @@ IMPORTANT: Output the complete modified CSV file. Do not add any explanation or
580
471
 
581
472
  # Get AI to modify the CSV with fallbacks
582
473
  local modified_csv
583
- local stderr_file="/tmp/claude-evolve-stderr-$$.txt"
584
- if ! modified_csv=$(call_ai_with_fallbacks "$csv_prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
474
+ local stderr_file="$FULL_EVOLUTION_DIR/stderr-$$.txt"
475
+ if ! modified_csv=$(call_ai_for_ideation "$csv_prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
585
476
  echo "[ERROR] All AI models failed to modify CSV" >&2
586
477
  cat "$stderr_file" >&2
587
478
  rm -f "$temp_csv" "$stderr_file"
@@ -659,14 +550,72 @@ IMPORTANT: Output the complete modified CSV file. Do not add any explanation or
659
550
  echo "[WARN] Expected to add $count ideas but added $added_count" >&2
660
551
  fi
661
552
 
662
- # Replace original CSV with modified version
663
- mv "$temp_csv" "$FULL_CSV_PATH"
553
+ # Use proper locking to safely update the CSV
554
+ echo "[INFO] Acquiring CSV lock to apply changes..."
555
+
556
+ # Set the lockfile path
557
+ CSV_LOCKFILE="$FULL_EVOLUTION_DIR/.evolution.csv.lock"
558
+
559
+ if ! acquire_csv_lock; then
560
+ echo "[ERROR] Failed to acquire CSV lock for update" >&2
561
+ rm -f "$temp_csv"
562
+ return 1
563
+ fi
564
+
565
+ # Get just the new entries (skip header and existing entries)
566
+ local original_line_count=$(wc -l < "$FULL_CSV_PATH")
567
+
568
+ # Append only the new lines from temp CSV to the main CSV
569
+ tail -n +$((original_line_count + 1)) "$temp_csv" >> "$FULL_CSV_PATH"
570
+
571
+ # Clean up temp file
572
+ rm -f "$temp_csv"
573
+
574
+ # Release the lock
575
+ release_csv_lock
664
576
 
665
577
  echo "[INFO] Successfully added $added_count $idea_type ideas to CSV"
666
578
 
667
579
  return 0
668
580
  }
669
581
 
582
+ # Get list of existing Python files for a generation
583
+ get_existing_py_files_for_generation() {
584
+ local generation="$1"
585
+ local py_files=""
586
+
587
+ # List all Python files for this generation
588
+ for py_file in "$FULL_OUTPUT_DIR"/evolution_gen${generation}-*.py; do
589
+ if [[ -f "$py_file" ]]; then
590
+ local basename=$(basename "$py_file" .py)
591
+ local id="${basename#evolution_}"
592
+ if [[ -n "$py_files" ]]; then
593
+ py_files="$py_files, $id"
594
+ else
595
+ py_files="$id"
596
+ fi
597
+ fi
598
+ done
599
+
600
+ echo "$py_files"
601
+ }
602
+
603
+ # Add existing Python files warning to prompt
604
+ add_existing_files_warning() {
605
+ local prompt="$1"
606
+ local generation="$2"
607
+ local existing_py_files=$(get_existing_py_files_for_generation "$generation")
608
+
609
+ if [[ -n "$existing_py_files" ]]; then
610
+ prompt+="
611
+
612
+ WARNING: The following IDs already have Python files and MUST NOT be reused: $existing_py_files
613
+ Skip these IDs when assigning new IDs (e.g., if gen$generation-001 and gen$generation-002 exist as Python files, start with gen$generation-003)"
614
+ fi
615
+
616
+ echo "$prompt"
617
+ }
618
+
670
619
  # Get next available ID for current generation
671
620
  get_next_id() {
672
621
  local generation="$1"
@@ -796,10 +745,55 @@ ideate_ai_strategies() {
796
745
  echo " Crossover hybrid: $CROSSOVER_HYBRID"
797
746
 
798
747
  # Generate each type of idea by having Claude directly edit the CSV
799
- [[ $NOVEL_EXPLORATION -gt 0 ]] && generate_novel_ideas_direct "$NOVEL_EXPLORATION"
800
- [[ $HILL_CLIMBING -gt 0 ]] && generate_hill_climbing_direct "$HILL_CLIMBING" "$top_performers"
801
- [[ $STRUCTURAL_MUTATION -gt 0 ]] && generate_structural_mutation_direct "$STRUCTURAL_MUTATION" "$top_performers"
802
- [[ $CROSSOVER_HYBRID -gt 0 ]] && generate_crossover_direct "$CROSSOVER_HYBRID" "$top_performers"
748
+ # Track successes - continue even if some strategies fail
749
+ local strategies_attempted=0
750
+ local strategies_succeeded=0
751
+
752
+ if [[ $NOVEL_EXPLORATION -gt 0 ]]; then
753
+ ((strategies_attempted++))
754
+ if generate_novel_ideas_direct "$NOVEL_EXPLORATION"; then
755
+ ((strategies_succeeded++))
756
+ else
757
+ echo "[WARN] Novel exploration strategy failed, continuing with other strategies" >&2
758
+ fi
759
+ fi
760
+
761
+ if [[ $HILL_CLIMBING -gt 0 ]]; then
762
+ ((strategies_attempted++))
763
+ if generate_hill_climbing_direct "$HILL_CLIMBING" "$top_performers"; then
764
+ ((strategies_succeeded++))
765
+ else
766
+ echo "[WARN] Hill climbing strategy failed, continuing with other strategies" >&2
767
+ fi
768
+ fi
769
+
770
+ if [[ $STRUCTURAL_MUTATION -gt 0 ]]; then
771
+ ((strategies_attempted++))
772
+ if generate_structural_mutation_direct "$STRUCTURAL_MUTATION" "$top_performers"; then
773
+ ((strategies_succeeded++))
774
+ else
775
+ echo "[WARN] Structural mutation strategy failed, continuing with other strategies" >&2
776
+ fi
777
+ fi
778
+
779
+ if [[ $CROSSOVER_HYBRID -gt 0 ]]; then
780
+ ((strategies_attempted++))
781
+ if generate_crossover_direct "$CROSSOVER_HYBRID" "$top_performers"; then
782
+ ((strategies_succeeded++))
783
+ else
784
+ echo "[WARN] Crossover strategy failed, continuing with other strategies" >&2
785
+ fi
786
+ fi
787
+
788
+ echo "[INFO] Strategy results: $strategies_succeeded/$strategies_attempted succeeded" >&2
789
+
790
+ # Success if at least one strategy worked
791
+ if [[ $strategies_succeeded -gt 0 ]]; then
792
+ return 0
793
+ else
794
+ echo "[ERROR] All ideation strategies failed" >&2
795
+ return 1
796
+ fi
803
797
  }
804
798
 
805
799
  # Generate novel exploration ideas using direct CSV modification
@@ -817,34 +811,71 @@ generate_novel_ideas_direct() {
817
811
  # Use relative paths and change to evolution directory so AI can access files
818
812
  local temp_csv_basename=$(basename "$temp_csv")
819
813
 
820
- local prompt="I need you to use your file editing capabilities to add exactly $count novel algorithmic ideas to the CSV file: $temp_csv_basename
814
+ # Get existing Python files for this generation to avoid ID collisions
815
+ local existing_py_files=$(get_existing_py_files_for_generation "$CURRENT_GENERATION")
816
+
817
+ local prompt="I need you to use your file editing capabilities to APPEND exactly $count novel algorithmic ideas to the CSV file: $temp_csv_basename
821
818
 
822
819
  Current evolution context:
823
820
  - Generation: $CURRENT_GENERATION
824
821
  - Algorithm: algorithm.py (base algorithm)
825
- - Brief: $(head -20 "$FULL_BRIEF_PATH")
822
+ - Brief: $(head -5 "$FULL_BRIEF_PATH" 2>/dev/null | head -c 500 || echo "No brief file found")
826
823
 
827
- Instructions:
824
+ CRITICAL INSTRUCTIONS:
828
825
  1. Use the Read tool to examine the current CSV file
829
- 2. Use the Edit or MultiEdit tool to add exactly $count new rows to the CSV file
830
- 3. Use the next available generation numbers (gen$CURRENT_GENERATION-XXX format)
831
- 4. For each idea, create a row with: id,,description,,pending (empty parent_id for novel ideas)
832
- 5. Each description should be one clear sentence describing a novel algorithmic approach
833
- 6. Focus on creative, ambitious ideas that haven't been tried yet
834
- 7. Consider machine learning, new indicators, regime detection, risk management, etc.
835
-
836
- CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly."
826
+ 2. DO NOT DELETE OR REPLACE ANY EXISTING ROWS - YOU MUST PRESERVE ALL EXISTING DATA
827
+ 3. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
828
+ 4. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001"
829
+
830
+ if [[ -n "$existing_py_files" ]]; then
831
+ prompt+="
832
+ 5. IMPORTANT: The following IDs already have Python files and MUST NOT be reused: $existing_py_files
833
+ 6. Skip these IDs when assigning new IDs (e.g., if gen$CURRENT_GENERATION-001 and gen$CURRENT_GENERATION-002 exist as Python files, start with gen$CURRENT_GENERATION-003)"
834
+ else
835
+ prompt+="
836
+ 5. No existing Python files found for generation $CURRENT_GENERATION"
837
+ fi
838
+
839
+ prompt+="
840
+ 6. Use the Edit or MultiEdit tool to APPEND exactly $count new rows AT THE END of the CSV file
841
+ 7. For each idea, create a row with: id,,description,,pending (empty parent_id for novel ideas)
842
+ 8. Each description should be one clear sentence describing a novel algorithmic approach
843
+ 9. Focus on creative, ambitious ideas that haven't been tried yet
844
+ 10. Consider machine learning, new indicators, regime detection, risk management, etc.
845
+
846
+ IMPORTANT: You must APPEND new rows to the existing CSV file. DO NOT replace the file contents. All existing rows must remain unchanged.
847
+ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly.
848
+ CRITICAL: Do NOT use any git commands (git add, git commit, git reset, etc.). Only modify the file directly."
849
+
850
+ # Debug prompt size and context
851
+ echo "[DEBUG] Novel ideas prompt length: ${#prompt} characters" >&2
852
+ echo "[DEBUG] Working dir: $(pwd)" >&2
853
+ echo "[DEBUG] Evolution dir: $FULL_EVOLUTION_DIR" >&2
854
+ echo "[DEBUG] Temp CSV: $temp_csv" >&2
855
+ if [[ -f "$temp_csv" ]]; then
856
+ echo "[DEBUG] Temp CSV exists, size: $(wc -l < "$temp_csv") lines" >&2
857
+ else
858
+ echo "[DEBUG] Temp CSV does not exist yet" >&2
859
+ fi
837
860
 
838
861
  # Change to evolution directory so AI can access files
839
862
  local original_pwd=$(pwd)
840
863
  cd "$FULL_EVOLUTION_DIR"
841
864
 
865
+ # Debug: Show files in evolution directory
866
+ echo "[DEBUG] Current directory: $(pwd)" >&2
867
+ echo "[DEBUG] Temp CSV exists: $(ls -la "$temp_csv_basename" 2>&1)" >&2
868
+
842
869
  # Get AI to directly edit the CSV file
843
870
  local ai_response
844
871
  local stderr_file="stderr-$$.txt"
845
- if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
872
+ # Temporarily show stderr for debugging
873
+ if ! ai_response=$(call_ai_for_ideation "$prompt" "$CURRENT_GENERATION" "$count" "$temp_csv_basename"); then
846
874
  echo "[ERROR] All AI models failed to generate novel ideas" >&2
875
+ echo "[DEBUG] Stderr output from AI calls:" >&2
847
876
  cat "$stderr_file" >&2
877
+ echo "[DEBUG] Temp CSV location: $temp_csv" >&2
878
+ echo "[DEBUG] Working directory: $(pwd)" >&2
848
879
  cd "$original_pwd"
849
880
  rm -f "$temp_csv" "$stderr_file"
850
881
  return 1
@@ -879,6 +910,9 @@ generate_hill_climbing_direct() {
879
910
  local data_rows=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
880
911
  echo "[DEBUG] Original CSV has $data_rows data rows" >&2
881
912
 
913
+ # Get existing Python files for this generation to avoid ID collisions
914
+ local existing_py_files=$(get_existing_py_files_for_generation "$CURRENT_GENERATION")
915
+
882
916
  # Extract just the IDs from top performers for clarity
883
917
  local valid_parent_ids
884
918
  valid_parent_ids=$(echo "$top_performers" | cut -d',' -f1 | paste -sd ',' -)
@@ -886,7 +920,7 @@ generate_hill_climbing_direct() {
886
920
  # Use relative paths and change to evolution directory so AI can access files
887
921
  local temp_csv_basename=$(basename "$temp_csv")
888
922
 
889
- local prompt="I need you to use your file editing capabilities to add exactly $count parameter tuning ideas to the CSV file: $temp_csv_basename
923
+ local prompt="I need you to use your file editing capabilities to APPEND exactly $count parameter tuning ideas to the CSV file: $temp_csv_basename
890
924
 
891
925
  IMPORTANT: You MUST use one of these exact parent IDs: $valid_parent_ids
892
926
 
@@ -897,16 +931,20 @@ CRITICAL INSTRUCTION: Before generating parameter tuning ideas, you MUST read th
897
931
  Algorithm source files are located at: evolution_<PARENT_ID>.py
898
932
  For example: evolution_gen01-251.py
899
933
 
900
- Instructions:
934
+ CRITICAL INSTRUCTIONS:
901
935
  1. Use the Read tool to examine the current CSV file
902
- 2. Use the Edit or MultiEdit tool to add exactly $count new rows to the CSV file
903
- 3. Use the next available generation numbers (gen$CURRENT_GENERATION-XXX format)
904
- 4. For each idea, create a row with: id,parent_id,description,,pending
905
- 5. Each parent_id MUST be one of: $valid_parent_ids
906
- 6. Each description should focus on adjusting specific parameters that exist in the parent's source code
907
- 7. Include current and new parameter values (e.g., \"Lower rsi_entry from 21 to 18\")
908
-
909
- CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly."
936
+ 2. DO NOT DELETE OR REPLACE ANY EXISTING ROWS - YOU MUST PRESERVE ALL EXISTING DATA
937
+ 3. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
938
+ 4. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
939
+ 5. Use the Edit or MultiEdit tool to APPEND exactly $count new rows AT THE END of the CSV file
940
+ 6. For each idea, create a row with: id,parent_id,description,,pending
941
+ 7. Each parent_id MUST be one of: $valid_parent_ids
942
+ 8. Each description should focus on adjusting specific parameters that exist in the parent's source code
943
+ 9. Include current and new parameter values (e.g., \"Lower rsi_entry from 21 to 18\")
944
+
945
+ IMPORTANT: You must APPEND new rows to the existing CSV file. DO NOT replace the file contents. All existing rows must remain unchanged.
946
+ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly.
947
+ CRITICAL: Do NOT use any git commands (git add, git commit, git reset, etc.). Only modify the file directly."
910
948
 
911
949
  # Change to evolution directory so AI can access files
912
950
  local original_pwd=$(pwd)
@@ -915,7 +953,8 @@ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CS
915
953
  # Get AI to directly edit the CSV file
916
954
  local ai_response
917
955
  local stderr_file="stderr-$$.txt"
918
- if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
956
+ # Temporarily show stderr for debugging
957
+ if ! ai_response=$(call_ai_for_ideation "$prompt" "$CURRENT_GENERATION" "$count" "$temp_csv_basename"); then
919
958
  echo "[ERROR] All AI models failed to generate hill climbing ideas" >&2
920
959
  cat "$stderr_file" >&2
921
960
  cd "$original_pwd"
@@ -952,6 +991,9 @@ generate_structural_mutation_direct() {
952
991
  local data_rows=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
953
992
  echo "[DEBUG] Original CSV has $data_rows data rows" >&2
954
993
 
994
+ # Get existing Python files for this generation to avoid ID collisions
995
+ local existing_py_files=$(get_existing_py_files_for_generation "$CURRENT_GENERATION")
996
+
955
997
  # Extract just the IDs from top performers for clarity
956
998
  local valid_parent_ids
957
999
  valid_parent_ids=$(echo "$top_performers" | cut -d',' -f1 | paste -sd ',' -)
@@ -959,7 +1001,7 @@ generate_structural_mutation_direct() {
959
1001
  # Use relative paths and change to evolution directory so AI can access files
960
1002
  local temp_csv_basename=$(basename "$temp_csv")
961
1003
 
962
- local prompt="I need you to use your file editing capabilities to add exactly $count structural modification ideas to the CSV file: $temp_csv_basename
1004
+ local prompt="I need you to use your file editing capabilities to APPEND exactly $count structural modification ideas to the CSV file: $temp_csv_basename
963
1005
 
964
1006
  IMPORTANT: You MUST use one of these exact parent IDs: $valid_parent_ids
965
1007
 
@@ -970,16 +1012,20 @@ CRITICAL INSTRUCTION: Before generating structural modification ideas, you MUST
970
1012
  Algorithm source files are located at: evolution_<PARENT_ID>.py
971
1013
  For example: evolution_gen01-251.py
972
1014
 
973
- Instructions:
1015
+ CRITICAL INSTRUCTIONS:
974
1016
  1. Use the Read tool to examine the current CSV file
975
- 2. Use the Edit or MultiEdit tool to add exactly $count new rows to the CSV file
976
- 3. Use the next available generation numbers (gen$CURRENT_GENERATION-XXX format)
977
- 4. For each idea, create a row with: id,parent_id,description,,pending
978
- 5. Each parent_id MUST be one of: $valid_parent_ids
979
- 6. Each description should focus on architectural/structural changes based on the parent's actual code
980
- 7. Reference actual components/methods found in the source code
981
-
982
- CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly."
1017
+ 2. DO NOT DELETE OR REPLACE ANY EXISTING ROWS - YOU MUST PRESERVE ALL EXISTING DATA
1018
+ 3. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
1019
+ 4. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
1020
+ 5. Use the Edit or MultiEdit tool to APPEND exactly $count new rows AT THE END of the CSV file
1021
+ 6. For each idea, create a row with: id,parent_id,description,,pending
1022
+ 7. Each parent_id MUST be one of: $valid_parent_ids
1023
+ 8. Each description should focus on architectural/structural changes based on the parent's actual code
1024
+ 9. Reference actual components/methods found in the source code
1025
+
1026
+ IMPORTANT: You must APPEND new rows to the existing CSV file. DO NOT replace the file contents. All existing rows must remain unchanged.
1027
+ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly.
1028
+ CRITICAL: Do NOT use any git commands (git add, git commit, git reset, etc.). Only modify the file directly."
983
1029
 
984
1030
  # Change to evolution directory so AI can access files
985
1031
  local original_pwd=$(pwd)
@@ -988,7 +1034,8 @@ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CS
988
1034
  # Get AI to directly edit the CSV file
989
1035
  local ai_response
990
1036
  local stderr_file="stderr-$$.txt"
991
- if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
1037
+ # Temporarily show stderr for debugging
1038
+ if ! ai_response=$(call_ai_for_ideation "$prompt" "$CURRENT_GENERATION" "$count" "$temp_csv_basename"); then
992
1039
  echo "[ERROR] All AI models failed to generate structural mutation ideas" >&2
993
1040
  cat "$stderr_file" >&2
994
1041
  cd "$original_pwd"
@@ -1025,6 +1072,9 @@ generate_crossover_direct() {
1025
1072
  local data_rows=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
1026
1073
  echo "[DEBUG] Original CSV has $data_rows data rows" >&2
1027
1074
 
1075
+ # Get existing Python files for this generation to avoid ID collisions
1076
+ local existing_py_files=$(get_existing_py_files_for_generation "$CURRENT_GENERATION")
1077
+
1028
1078
  # Extract just the IDs from top performers for clarity
1029
1079
  local valid_parent_ids
1030
1080
  valid_parent_ids=$(echo "$top_performers" | cut -d',' -f1 | paste -sd ',' -)
@@ -1032,7 +1082,7 @@ generate_crossover_direct() {
1032
1082
  # Use relative paths and change to evolution directory so AI can access files
1033
1083
  local temp_csv_basename=$(basename "$temp_csv")
1034
1084
 
1035
- local prompt="I need you to use your file editing capabilities to add exactly $count hybrid combination ideas to the CSV file: $temp_csv_basename
1085
+ local prompt="I need you to use your file editing capabilities to APPEND exactly $count hybrid combination ideas to the CSV file: $temp_csv_basename
1036
1086
 
1037
1087
  IMPORTANT: You MUST use ONLY these exact parent IDs: $valid_parent_ids
1038
1088
 
@@ -1043,16 +1093,20 @@ CRITICAL INSTRUCTION: Before generating hybrid combination ideas, you MUST read
1043
1093
  Algorithm source files are located at: evolution_<PARENT_ID>.py
1044
1094
  For example: evolution_gen01-251.py
1045
1095
 
1046
- Instructions:
1096
+ CRITICAL INSTRUCTIONS:
1047
1097
  1. Use the Read tool to examine the current CSV file
1048
- 2. Use the Edit or MultiEdit tool to add exactly $count new rows to the CSV file
1049
- 3. Use the next available generation numbers (gen$CURRENT_GENERATION-XXX format)
1050
- 4. For each idea, create a row with: id,parent_id,description,,pending
1051
- 5. Each parent_id MUST be one of: $valid_parent_ids (choose the primary parent)
1052
- 6. Each description should combine actual elements from 2+ algorithms based on their source code
1053
- 7. Reference specific components/features found in the actual source code
1054
-
1055
- CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly."
1098
+ 2. DO NOT DELETE OR REPLACE ANY EXISTING ROWS - YOU MUST PRESERVE ALL EXISTING DATA
1099
+ 3. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
1100
+ 4. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
1101
+ 5. Use the Edit or MultiEdit tool to APPEND exactly $count new rows AT THE END of the CSV file
1102
+ 6. For each idea, create a row with: id,parent_id,description,,pending
1103
+ 7. Each parent_id MUST be one of: $valid_parent_ids (choose the primary parent)
1104
+ 8. Each description should combine actual elements from 2+ algorithms based on their source code
1105
+ 9. Reference specific components/features found in the actual source code
1106
+
1107
+ IMPORTANT: You must APPEND new rows to the existing CSV file. DO NOT replace the file contents. All existing rows must remain unchanged.
1108
+ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly.
1109
+ CRITICAL: Do NOT use any git commands (git add, git commit, git reset, etc.). Only modify the file directly."
1056
1110
 
1057
1111
  # Change to evolution directory so AI can access files
1058
1112
  local original_pwd=$(pwd)
@@ -1061,7 +1115,8 @@ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CS
1061
1115
  # Get AI to directly edit the CSV file
1062
1116
  local ai_response
1063
1117
  local stderr_file="stderr-$$.txt"
1064
- if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
1118
+ # Temporarily show stderr for debugging
1119
+ if ! ai_response=$(call_ai_for_ideation "$prompt" "$CURRENT_GENERATION" "$count" "$temp_csv_basename"); then
1065
1120
  echo "[ERROR] All AI models failed to generate crossover hybrid ideas" >&2
1066
1121
  cat "$stderr_file" >&2
1067
1122
  cd "$original_pwd"
@@ -1133,13 +1188,15 @@ $top_performers"
1133
1188
 
1134
1189
  prompt+="
1135
1190
 
1136
- Instructions:
1191
+ CRITICAL INSTRUCTIONS:
1137
1192
  1. Use the Read tool to examine the current CSV file
1138
- 2. Use the Edit or MultiEdit tool to add exactly $TOTAL_IDEAS new rows to the CSV file
1139
- 3. Use the next available generation numbers (gen$CURRENT_GENERATION-XXX format)
1140
- 4. For each idea, create a row with: id,parent_id,description,,pending
1141
- 5. Mix both parameter tuning and structural changes
1142
- 6. If building on existing algorithms, use their ID as parent_id, otherwise leave parent_id empty
1193
+ 2. DO NOT DELETE OR REPLACE ANY EXISTING ROWS - YOU MUST PRESERVE ALL EXISTING DATA
1194
+ 3. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
1195
+ 4. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
1196
+ 5. Use the Edit or MultiEdit tool to APPEND exactly $TOTAL_IDEAS new rows AT THE END of the CSV file
1197
+ 6. For each idea, create a row with: id,parent_id,description,,pending
1198
+ 7. Mix both parameter tuning and structural changes
1199
+ 8. If building on existing algorithms, use their ID as parent_id, otherwise leave parent_id empty
1143
1200
 
1144
1201
  ⚠️ AVOID ONLY: Kelly floor/cap adjustments that assume leverage > 1.0 (these get clamped and have no effect)
1145
1202
 
@@ -1153,7 +1210,9 @@ Instructions:
1153
1210
  - Time-Based Patterns: Intraday effects, calendar anomalies, volatility timing
1154
1211
  - Parameter Optimization: Entry thresholds, indicator periods, strategy weights
1155
1212
 
1156
- CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly."
1213
+ IMPORTANT: You must APPEND new rows to the existing CSV file. DO NOT replace the file contents. All existing rows must remain unchanged.
1214
+ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CSV file. DO NOT return CSV text - use your tools to edit the file directly.
1215
+ CRITICAL: Do NOT use any git commands (git add, git commit, git reset, etc.). Only modify the file directly."
1157
1216
 
1158
1217
  # Change to evolution directory so AI can access files
1159
1218
  local original_pwd=$(pwd)
@@ -1162,7 +1221,7 @@ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CS
1162
1221
  # Get AI to directly edit the CSV file
1163
1222
  local ai_response
1164
1223
  local stderr_file="stderr-$$.txt"
1165
- if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
1224
+ if ! ai_response=$(call_ai_for_ideation "$prompt" "$CURRENT_GENERATION" "$TOTAL_IDEAS" "$temp_csv_basename" 2>"$stderr_file"); then
1166
1225
  echo "[ERROR] All AI models failed to generate ideas" >&2
1167
1226
  cat "$stderr_file" >&2
1168
1227
  cd "$original_pwd"