claude-evolve 1.4.13 → 1.5.1
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-ideate +210 -186
- package/bin/claude-evolve-worker +255 -19
- package/package.json +1 -1
package/bin/claude-evolve-ideate
CHANGED
|
@@ -81,47 +81,16 @@ call_ai_with_limit_check() {
|
|
|
81
81
|
if [[ "$preferred_model" == "o3" ]] && command -v codex >/dev/null 2>&1; then
|
|
82
82
|
echo "[INFO] Using codex o3 for ideation" >&2
|
|
83
83
|
|
|
84
|
-
# Call codex with o3 model using
|
|
84
|
+
# Call codex with o3 model using exec subcommand
|
|
85
85
|
local ai_output
|
|
86
|
-
|
|
86
|
+
# Pass prompt as argument, not via stdin
|
|
87
|
+
ai_output=$(timeout 300 codex exec -m o3 --dangerously-bypass-approvals-and-sandbox "$prompt" 2>&1)
|
|
87
88
|
local ai_exit_code=$?
|
|
88
89
|
|
|
89
90
|
if [[ $ai_exit_code -eq 0 ]]; then
|
|
90
|
-
#
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
91
|
+
# For ideation, AI modifies files directly - just return success
|
|
92
|
+
echo "[INFO] Codex o3 succeeded" >&2
|
|
93
|
+
return 0
|
|
125
94
|
else
|
|
126
95
|
echo "[WARN] Codex o3 failed with exit code $ai_exit_code, falling back to Claude Opus" >&2
|
|
127
96
|
preferred_model="opus"
|
|
@@ -131,21 +100,13 @@ except:
|
|
|
131
100
|
|
|
132
101
|
# Call gemini with -y and -p flags
|
|
133
102
|
local ai_output
|
|
134
|
-
ai_output=$(gemini -y -p
|
|
103
|
+
ai_output=$(echo "$prompt" | timeout 300 gemini -y -p 2>&1)
|
|
135
104
|
local ai_exit_code=$?
|
|
136
105
|
|
|
137
106
|
if [[ $ai_exit_code -eq 0 ]]; then
|
|
138
|
-
#
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
107
|
+
# For ideation, AI modifies files directly - just return success
|
|
108
|
+
echo "[INFO] Gemini succeeded" >&2
|
|
109
|
+
return 0
|
|
149
110
|
else
|
|
150
111
|
echo "[WARN] Gemini failed with exit code $ai_exit_code, falling back to Claude Opus" >&2
|
|
151
112
|
preferred_model="opus"
|
|
@@ -157,7 +118,7 @@ except:
|
|
|
157
118
|
|
|
158
119
|
# Call Claude and capture output
|
|
159
120
|
local claude_output
|
|
160
|
-
claude_output=$(echo "$prompt" | claude --dangerously-skip-permissions --model "$preferred_model" -p 2>&1)
|
|
121
|
+
claude_output=$(echo "$prompt" | timeout 300 claude --dangerously-skip-permissions --model "$preferred_model" -p 2>&1)
|
|
161
122
|
local claude_exit_code=$?
|
|
162
123
|
|
|
163
124
|
# Check for usage limit
|
|
@@ -181,17 +142,13 @@ except:
|
|
|
181
142
|
exit 1
|
|
182
143
|
fi
|
|
183
144
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
echo "[
|
|
187
|
-
|
|
188
|
-
|
|
145
|
+
if [[ $claude_exit_code -eq 0 ]]; then
|
|
146
|
+
# For ideation, AI modifies files directly - just return success
|
|
147
|
+
echo "[INFO] Claude $preferred_model succeeded" >&2
|
|
148
|
+
return 0
|
|
149
|
+
else
|
|
150
|
+
return $claude_exit_code
|
|
189
151
|
fi
|
|
190
|
-
|
|
191
|
-
# Output Claude's response
|
|
192
|
-
echo "$claude_output"
|
|
193
|
-
|
|
194
|
-
return $claude_exit_code
|
|
195
152
|
}
|
|
196
153
|
|
|
197
154
|
# Backward compatibility alias
|
|
@@ -204,68 +161,63 @@ call_ai_with_fallbacks() {
|
|
|
204
161
|
local prompt="$1"
|
|
205
162
|
local generation="${2:-01}"
|
|
206
163
|
|
|
207
|
-
#
|
|
208
|
-
local
|
|
164
|
+
# Determine which model to use based on generation (round-robin)
|
|
165
|
+
local gen_num
|
|
166
|
+
if [[ $generation =~ ^0*([0-9]+)$ ]]; then
|
|
167
|
+
gen_num=$((10#${BASH_REMATCH[1]}))
|
|
168
|
+
else
|
|
169
|
+
gen_num=1
|
|
170
|
+
fi
|
|
209
171
|
|
|
210
172
|
# Check which AI tools are available
|
|
173
|
+
local available_models=()
|
|
211
174
|
if command -v codex >/dev/null 2>&1; then
|
|
212
|
-
|
|
175
|
+
available_models+=("o3")
|
|
213
176
|
fi
|
|
214
177
|
if command -v gemini >/dev/null 2>&1; then
|
|
215
|
-
|
|
178
|
+
available_models+=("gemini")
|
|
216
179
|
fi
|
|
217
|
-
# Claude
|
|
218
|
-
|
|
180
|
+
available_models+=("opus") # Claude Opus always available
|
|
181
|
+
|
|
182
|
+
# Create ordered list based on round-robin for this generation
|
|
183
|
+
local num_models=${#available_models[@]}
|
|
184
|
+
local start_index=$((gen_num % num_models))
|
|
185
|
+
local models=()
|
|
186
|
+
|
|
187
|
+
# Add models in round-robin order starting from the calculated index
|
|
188
|
+
for ((i=0; i<num_models; i++)); do
|
|
189
|
+
local idx=$(((start_index + i) % num_models))
|
|
190
|
+
models+=("${available_models[$idx]}")
|
|
191
|
+
done
|
|
192
|
+
|
|
193
|
+
echo "[INFO] Model order for generation $generation (round-robin): ${models[*]}" >&2
|
|
219
194
|
|
|
220
|
-
# Try each model in sequence
|
|
195
|
+
# Try each model in the ordered sequence
|
|
221
196
|
for model in "${models[@]}"; do
|
|
222
|
-
echo "[INFO] Trying $model for ideation
|
|
197
|
+
echo "[INFO] Trying $model for ideation" >&2
|
|
223
198
|
|
|
224
199
|
local ai_output
|
|
225
200
|
local ai_exit_code
|
|
226
201
|
|
|
227
202
|
if [[ "$model" == "o3" ]] && command -v codex >/dev/null 2>&1; then
|
|
228
|
-
|
|
203
|
+
# Pass prompt as argument, not via stdin
|
|
204
|
+
ai_output=$(timeout 300 codex exec -m o3 --dangerously-bypass-approvals-and-sandbox "$prompt" 2>&1)
|
|
229
205
|
ai_exit_code=$?
|
|
230
206
|
|
|
231
207
|
if [[ $ai_exit_code -eq 0 ]]; then
|
|
232
|
-
#
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
import sys
|
|
236
|
-
import json
|
|
237
|
-
try:
|
|
238
|
-
data = json.load(sys.stdin)
|
|
239
|
-
if 'content' in data:
|
|
240
|
-
print(data['content'])
|
|
241
|
-
elif 'response' in data:
|
|
242
|
-
print(data['response'])
|
|
243
|
-
elif 'text' in data:
|
|
244
|
-
print(data['text'])
|
|
245
|
-
else:
|
|
246
|
-
print(json.dumps(data))
|
|
247
|
-
except:
|
|
248
|
-
print(sys.stdin.read())
|
|
249
|
-
" 2>/dev/null || echo "$ai_output")
|
|
250
|
-
fi
|
|
251
|
-
|
|
252
|
-
if [[ -n "$ai_output" ]] && ! echo "$ai_output" | grep -q "error\|failed\|exception"; then
|
|
253
|
-
echo "$ai_output"
|
|
254
|
-
return 0
|
|
255
|
-
fi
|
|
208
|
+
# For ideation, we don't care about output content - AI modifies files directly
|
|
209
|
+
echo "[INFO] o3 completed successfully (exit code 0)" >&2
|
|
210
|
+
return 0
|
|
256
211
|
fi
|
|
257
212
|
|
|
258
213
|
elif [[ "$model" == "gemini" ]] && command -v gemini >/dev/null 2>&1; then
|
|
259
|
-
ai_output=$(gemini -y -p
|
|
214
|
+
ai_output=$(echo "$prompt" | timeout 300 gemini -y -p 2>&1)
|
|
260
215
|
ai_exit_code=$?
|
|
261
216
|
|
|
262
217
|
if [[ $ai_exit_code -eq 0 ]]; then
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
return 0
|
|
267
|
-
fi
|
|
268
|
-
fi
|
|
218
|
+
# For ideation, we don't care about output content - AI modifies files directly
|
|
219
|
+
echo "[INFO] gemini completed successfully (exit code 0)" >&2
|
|
220
|
+
return 0
|
|
269
221
|
fi
|
|
270
222
|
|
|
271
223
|
else
|
|
@@ -275,16 +227,20 @@ except:
|
|
|
275
227
|
|
|
276
228
|
if [[ $ai_exit_code -eq 0 ]]; then
|
|
277
229
|
# Check for usage limits
|
|
278
|
-
if
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
230
|
+
if echo "$ai_output" | grep -q "Claude AI usage limit reached"; then
|
|
231
|
+
echo "[INFO] Claude hit usage limit" >&2
|
|
232
|
+
else
|
|
233
|
+
# For ideation, we don't care about output content - AI modifies files directly
|
|
234
|
+
echo "[INFO] $model completed successfully (exit code 0)" >&2
|
|
235
|
+
return 0
|
|
283
236
|
fi
|
|
284
237
|
fi
|
|
285
238
|
fi
|
|
286
239
|
|
|
287
240
|
echo "[WARN] $model failed or returned unusable output, trying next model..." >&2
|
|
241
|
+
echo "[DEBUG] $model exit code: ${ai_exit_code:-unknown}" >&2
|
|
242
|
+
echo "[DEBUG] $model output length: ${#ai_output} chars" >&2
|
|
243
|
+
echo "[DEBUG] $model output preview: $(echo "$ai_output" | head -3 | tr '\n' ' ')" >&2
|
|
288
244
|
done
|
|
289
245
|
|
|
290
246
|
echo "[ERROR] All AI models failed to generate usable output" >&2
|
|
@@ -422,17 +378,18 @@ validate_direct_csv_modification() {
|
|
|
422
378
|
fi
|
|
423
379
|
|
|
424
380
|
# Validate the modified CSV has more entries than original
|
|
381
|
+
# Count actual data rows (excluding header and empty lines)
|
|
425
382
|
local original_count
|
|
426
|
-
original_count=$(
|
|
383
|
+
original_count=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
|
|
427
384
|
local new_count
|
|
428
|
-
new_count=$(
|
|
385
|
+
new_count=$(grep -v '^[[:space:]]*$' "$temp_csv" | tail -n +2 | wc -l)
|
|
429
386
|
|
|
430
|
-
echo "[DEBUG] Original CSV
|
|
431
|
-
echo "[DEBUG] Modified CSV
|
|
387
|
+
echo "[DEBUG] Original CSV data rows: $original_count" >&2
|
|
388
|
+
echo "[DEBUG] Modified CSV data rows: $new_count" >&2
|
|
432
389
|
echo "[DEBUG] Expected to add: $expected_count ideas" >&2
|
|
433
390
|
|
|
434
391
|
if [[ $new_count -le $original_count ]]; then
|
|
435
|
-
echo "[ERROR] CSV file wasn't modified - same number of
|
|
392
|
+
echo "[ERROR] CSV file wasn't modified - same number of data rows ($new_count <= $original_count)" >&2
|
|
436
393
|
echo "[DEBUG] First 10 lines of CSV after AI attempt:" >&2
|
|
437
394
|
head -10 "$temp_csv" >&2
|
|
438
395
|
return 1
|
|
@@ -529,8 +486,8 @@ process_ai_ideas_direct_old() {
|
|
|
529
486
|
local top_performers="${3:-}" # Optional, for non-novel ideas
|
|
530
487
|
local ai_output="$4" # The AI's response with ideas
|
|
531
488
|
|
|
532
|
-
# Create temporary CSV copy
|
|
533
|
-
local temp_csv="/
|
|
489
|
+
# Create temporary CSV copy in evolution directory (so AI can access it)
|
|
490
|
+
local temp_csv="$FULL_EVOLUTION_DIR/temp-csv-$$.csv"
|
|
534
491
|
cp "$FULL_CSV_PATH" "$temp_csv"
|
|
535
492
|
|
|
536
493
|
echo "[DEBUG] Starting CSV modification for $count $idea_type ideas" >&2
|
|
@@ -787,42 +744,58 @@ ideate_ai_strategies() {
|
|
|
787
744
|
generate_novel_ideas_direct() {
|
|
788
745
|
local count="$1"
|
|
789
746
|
|
|
790
|
-
# Create temporary CSV copy
|
|
791
|
-
local temp_csv="/
|
|
747
|
+
# Create temporary CSV copy in evolution directory (so AI can access it)
|
|
748
|
+
local temp_csv="$FULL_EVOLUTION_DIR/temp-csv-$$.csv"
|
|
792
749
|
cp "$FULL_CSV_PATH" "$temp_csv"
|
|
793
750
|
|
|
794
751
|
echo "[INFO] Generating $count novel exploration ideas..."
|
|
795
|
-
|
|
752
|
+
local data_rows=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
|
|
753
|
+
echo "[DEBUG] Original CSV has $data_rows data rows" >&2
|
|
796
754
|
|
|
797
|
-
|
|
755
|
+
# Use relative paths and change to evolution directory so AI can access files
|
|
756
|
+
local temp_csv_basename=$(basename "$temp_csv")
|
|
757
|
+
|
|
758
|
+
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
|
|
798
759
|
|
|
799
760
|
Current evolution context:
|
|
800
761
|
- Generation: $CURRENT_GENERATION
|
|
801
|
-
- Algorithm:
|
|
762
|
+
- Algorithm: algorithm.py (base algorithm)
|
|
802
763
|
- Brief: $(head -20 "$FULL_BRIEF_PATH")
|
|
803
764
|
|
|
804
765
|
Instructions:
|
|
805
|
-
1. Read the current CSV file
|
|
806
|
-
2.
|
|
807
|
-
3.
|
|
808
|
-
4.
|
|
809
|
-
5.
|
|
810
|
-
6.
|
|
811
|
-
7.
|
|
766
|
+
1. Use the Read tool to examine the current CSV file
|
|
767
|
+
2. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
|
|
768
|
+
3. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
|
|
769
|
+
4. Use the Edit or MultiEdit tool to add exactly $count new rows to the CSV file
|
|
770
|
+
5. For each idea, create a row with: id,,description,,pending (empty parent_id for novel ideas)
|
|
771
|
+
6. Each description should be one clear sentence describing a novel algorithmic approach
|
|
772
|
+
7. Focus on creative, ambitious ideas that haven't been tried yet
|
|
773
|
+
8. Consider machine learning, new indicators, regime detection, risk management, etc.
|
|
812
774
|
|
|
813
|
-
|
|
775
|
+
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."
|
|
814
776
|
|
|
777
|
+
# Change to evolution directory so AI can access files
|
|
778
|
+
local original_pwd=$(pwd)
|
|
779
|
+
cd "$FULL_EVOLUTION_DIR"
|
|
780
|
+
|
|
815
781
|
# Get AI to directly edit the CSV file
|
|
816
782
|
local ai_response
|
|
817
|
-
local stderr_file="
|
|
783
|
+
local stderr_file="stderr-$$.txt"
|
|
818
784
|
if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
|
|
819
785
|
echo "[ERROR] All AI models failed to generate novel ideas" >&2
|
|
786
|
+
echo "[DEBUG] Stderr output from AI calls:" >&2
|
|
820
787
|
cat "$stderr_file" >&2
|
|
788
|
+
echo "[DEBUG] Temp CSV location: $temp_csv" >&2
|
|
789
|
+
echo "[DEBUG] Working directory: $(pwd)" >&2
|
|
790
|
+
cd "$original_pwd"
|
|
821
791
|
rm -f "$temp_csv" "$stderr_file"
|
|
822
792
|
return 1
|
|
823
793
|
fi
|
|
824
794
|
rm -f "$stderr_file"
|
|
825
795
|
|
|
796
|
+
# Restore working directory
|
|
797
|
+
cd "$original_pwd"
|
|
798
|
+
|
|
826
799
|
echo "[DEBUG] AI response: $ai_response" >&2
|
|
827
800
|
|
|
828
801
|
# Validate that the CSV file was actually modified
|
|
@@ -840,18 +813,22 @@ generate_hill_climbing_direct() {
|
|
|
840
813
|
local count="$1"
|
|
841
814
|
local top_performers="$2"
|
|
842
815
|
|
|
843
|
-
# Create temporary CSV copy
|
|
844
|
-
local temp_csv="/
|
|
816
|
+
# Create temporary CSV copy in evolution directory (so AI can access it)
|
|
817
|
+
local temp_csv="$FULL_EVOLUTION_DIR/temp-csv-$$.csv"
|
|
845
818
|
cp "$FULL_CSV_PATH" "$temp_csv"
|
|
846
819
|
|
|
847
820
|
echo "[INFO] Generating $count hill climbing ideas..."
|
|
848
|
-
|
|
821
|
+
local data_rows=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
|
|
822
|
+
echo "[DEBUG] Original CSV has $data_rows data rows" >&2
|
|
849
823
|
|
|
850
824
|
# Extract just the IDs from top performers for clarity
|
|
851
825
|
local valid_parent_ids
|
|
852
826
|
valid_parent_ids=$(echo "$top_performers" | cut -d',' -f1 | paste -sd ',' -)
|
|
853
827
|
|
|
854
|
-
|
|
828
|
+
# Use relative paths and change to evolution directory so AI can access files
|
|
829
|
+
local temp_csv_basename=$(basename "$temp_csv")
|
|
830
|
+
|
|
831
|
+
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
|
|
855
832
|
|
|
856
833
|
IMPORTANT: You MUST use one of these exact parent IDs: $valid_parent_ids
|
|
857
834
|
|
|
@@ -859,31 +836,40 @@ Successful algorithms to tune:
|
|
|
859
836
|
$top_performers
|
|
860
837
|
|
|
861
838
|
CRITICAL INSTRUCTION: Before generating parameter tuning ideas, you MUST read the source code of the parent algorithms.
|
|
862
|
-
Algorithm source files are located at:
|
|
863
|
-
For example:
|
|
839
|
+
Algorithm source files are located at: evolution_<PARENT_ID>.py
|
|
840
|
+
For example: evolution_gen01-251.py
|
|
864
841
|
|
|
865
842
|
Instructions:
|
|
866
|
-
1. Read the current CSV file
|
|
867
|
-
2.
|
|
868
|
-
3.
|
|
869
|
-
4.
|
|
870
|
-
5.
|
|
871
|
-
6. Each
|
|
872
|
-
7.
|
|
843
|
+
1. Use the Read tool to examine the current CSV file
|
|
844
|
+
2. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
|
|
845
|
+
3. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
|
|
846
|
+
4. Use the Edit or MultiEdit tool to add exactly $count new rows to the CSV file
|
|
847
|
+
5. For each idea, create a row with: id,parent_id,description,,pending
|
|
848
|
+
6. Each parent_id MUST be one of: $valid_parent_ids
|
|
849
|
+
7. Each description should focus on adjusting specific parameters that exist in the parent's source code
|
|
850
|
+
8. Include current and new parameter values (e.g., \"Lower rsi_entry from 21 to 18\")
|
|
873
851
|
|
|
874
|
-
|
|
852
|
+
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."
|
|
875
853
|
|
|
854
|
+
# Change to evolution directory so AI can access files
|
|
855
|
+
local original_pwd=$(pwd)
|
|
856
|
+
cd "$FULL_EVOLUTION_DIR"
|
|
857
|
+
|
|
876
858
|
# Get AI to directly edit the CSV file
|
|
877
859
|
local ai_response
|
|
878
|
-
local stderr_file="
|
|
860
|
+
local stderr_file="stderr-$$.txt"
|
|
879
861
|
if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
|
|
880
862
|
echo "[ERROR] All AI models failed to generate hill climbing ideas" >&2
|
|
881
863
|
cat "$stderr_file" >&2
|
|
864
|
+
cd "$original_pwd"
|
|
882
865
|
rm -f "$temp_csv" "$stderr_file"
|
|
883
866
|
return 1
|
|
884
867
|
fi
|
|
885
868
|
rm -f "$stderr_file"
|
|
886
869
|
|
|
870
|
+
# Restore working directory
|
|
871
|
+
cd "$original_pwd"
|
|
872
|
+
|
|
887
873
|
echo "[DEBUG] AI response: $ai_response" >&2
|
|
888
874
|
|
|
889
875
|
# Validate that the CSV file was actually modified
|
|
@@ -901,18 +887,22 @@ generate_structural_mutation_direct() {
|
|
|
901
887
|
local count="$1"
|
|
902
888
|
local top_performers="$2"
|
|
903
889
|
|
|
904
|
-
# Create temporary CSV copy
|
|
905
|
-
local temp_csv="/
|
|
890
|
+
# Create temporary CSV copy in evolution directory (so AI can access it)
|
|
891
|
+
local temp_csv="$FULL_EVOLUTION_DIR/temp-csv-$$.csv"
|
|
906
892
|
cp "$FULL_CSV_PATH" "$temp_csv"
|
|
907
893
|
|
|
908
894
|
echo "[INFO] Generating $count structural mutation ideas..."
|
|
909
|
-
|
|
895
|
+
local data_rows=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
|
|
896
|
+
echo "[DEBUG] Original CSV has $data_rows data rows" >&2
|
|
910
897
|
|
|
911
898
|
# Extract just the IDs from top performers for clarity
|
|
912
899
|
local valid_parent_ids
|
|
913
900
|
valid_parent_ids=$(echo "$top_performers" | cut -d',' -f1 | paste -sd ',' -)
|
|
914
901
|
|
|
915
|
-
|
|
902
|
+
# Use relative paths and change to evolution directory so AI can access files
|
|
903
|
+
local temp_csv_basename=$(basename "$temp_csv")
|
|
904
|
+
|
|
905
|
+
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
|
|
916
906
|
|
|
917
907
|
IMPORTANT: You MUST use one of these exact parent IDs: $valid_parent_ids
|
|
918
908
|
|
|
@@ -920,31 +910,40 @@ Successful algorithms to modify structurally:
|
|
|
920
910
|
$top_performers
|
|
921
911
|
|
|
922
912
|
CRITICAL INSTRUCTION: Before generating structural modification ideas, you MUST read the source code of the parent algorithms.
|
|
923
|
-
Algorithm source files are located at:
|
|
924
|
-
For example:
|
|
913
|
+
Algorithm source files are located at: evolution_<PARENT_ID>.py
|
|
914
|
+
For example: evolution_gen01-251.py
|
|
925
915
|
|
|
926
916
|
Instructions:
|
|
927
|
-
1. Read the current CSV file
|
|
928
|
-
2.
|
|
929
|
-
3.
|
|
930
|
-
4.
|
|
931
|
-
5.
|
|
932
|
-
6. Each
|
|
933
|
-
7.
|
|
917
|
+
1. Use the Read tool to examine the current CSV file
|
|
918
|
+
2. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
|
|
919
|
+
3. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
|
|
920
|
+
4. Use the Edit or MultiEdit tool to add exactly $count new rows to the CSV file
|
|
921
|
+
5. For each idea, create a row with: id,parent_id,description,,pending
|
|
922
|
+
6. Each parent_id MUST be one of: $valid_parent_ids
|
|
923
|
+
7. Each description should focus on architectural/structural changes based on the parent's actual code
|
|
924
|
+
8. Reference actual components/methods found in the source code
|
|
934
925
|
|
|
935
|
-
|
|
926
|
+
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
927
|
|
|
928
|
+
# Change to evolution directory so AI can access files
|
|
929
|
+
local original_pwd=$(pwd)
|
|
930
|
+
cd "$FULL_EVOLUTION_DIR"
|
|
931
|
+
|
|
937
932
|
# Get AI to directly edit the CSV file
|
|
938
933
|
local ai_response
|
|
939
|
-
local stderr_file="
|
|
934
|
+
local stderr_file="stderr-$$.txt"
|
|
940
935
|
if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
|
|
941
936
|
echo "[ERROR] All AI models failed to generate structural mutation ideas" >&2
|
|
942
937
|
cat "$stderr_file" >&2
|
|
938
|
+
cd "$original_pwd"
|
|
943
939
|
rm -f "$temp_csv" "$stderr_file"
|
|
944
940
|
return 1
|
|
945
941
|
fi
|
|
946
942
|
rm -f "$stderr_file"
|
|
947
943
|
|
|
944
|
+
# Restore working directory
|
|
945
|
+
cd "$original_pwd"
|
|
946
|
+
|
|
948
947
|
echo "[DEBUG] AI response: $ai_response" >&2
|
|
949
948
|
|
|
950
949
|
# Validate that the CSV file was actually modified
|
|
@@ -962,18 +961,22 @@ generate_crossover_direct() {
|
|
|
962
961
|
local count="$1"
|
|
963
962
|
local top_performers="$2"
|
|
964
963
|
|
|
965
|
-
# Create temporary CSV copy
|
|
966
|
-
local temp_csv="/
|
|
964
|
+
# Create temporary CSV copy in evolution directory (so AI can access it)
|
|
965
|
+
local temp_csv="$FULL_EVOLUTION_DIR/temp-csv-$$.csv"
|
|
967
966
|
cp "$FULL_CSV_PATH" "$temp_csv"
|
|
968
967
|
|
|
969
968
|
echo "[INFO] Generating $count crossover hybrid ideas..."
|
|
970
|
-
|
|
969
|
+
local data_rows=$(grep -v '^[[:space:]]*$' "$FULL_CSV_PATH" | tail -n +2 | wc -l)
|
|
970
|
+
echo "[DEBUG] Original CSV has $data_rows data rows" >&2
|
|
971
971
|
|
|
972
972
|
# Extract just the IDs from top performers for clarity
|
|
973
973
|
local valid_parent_ids
|
|
974
974
|
valid_parent_ids=$(echo "$top_performers" | cut -d',' -f1 | paste -sd ',' -)
|
|
975
975
|
|
|
976
|
-
|
|
976
|
+
# Use relative paths and change to evolution directory so AI can access files
|
|
977
|
+
local temp_csv_basename=$(basename "$temp_csv")
|
|
978
|
+
|
|
979
|
+
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
|
|
977
980
|
|
|
978
981
|
IMPORTANT: You MUST use ONLY these exact parent IDs: $valid_parent_ids
|
|
979
982
|
|
|
@@ -981,31 +984,40 @@ Top performers to combine (reference at least 2 in each idea):
|
|
|
981
984
|
$top_performers
|
|
982
985
|
|
|
983
986
|
CRITICAL INSTRUCTION: Before generating hybrid combination ideas, you MUST read the source code of the parent algorithms.
|
|
984
|
-
Algorithm source files are located at:
|
|
985
|
-
For example:
|
|
987
|
+
Algorithm source files are located at: evolution_<PARENT_ID>.py
|
|
988
|
+
For example: evolution_gen01-251.py
|
|
986
989
|
|
|
987
990
|
Instructions:
|
|
988
|
-
1. Read the current CSV file
|
|
989
|
-
2.
|
|
990
|
-
3.
|
|
991
|
-
4.
|
|
992
|
-
5.
|
|
993
|
-
6. Each
|
|
994
|
-
7.
|
|
991
|
+
1. Use the Read tool to examine the current CSV file
|
|
992
|
+
2. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
|
|
993
|
+
3. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
|
|
994
|
+
4. Use the Edit or MultiEdit tool to add exactly $count new rows to the CSV file
|
|
995
|
+
5. For each idea, create a row with: id,parent_id,description,,pending
|
|
996
|
+
6. Each parent_id MUST be one of: $valid_parent_ids (choose the primary parent)
|
|
997
|
+
7. Each description should combine actual elements from 2+ algorithms based on their source code
|
|
998
|
+
8. Reference specific components/features found in the actual source code
|
|
995
999
|
|
|
996
|
-
|
|
1000
|
+
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."
|
|
997
1001
|
|
|
1002
|
+
# Change to evolution directory so AI can access files
|
|
1003
|
+
local original_pwd=$(pwd)
|
|
1004
|
+
cd "$FULL_EVOLUTION_DIR"
|
|
1005
|
+
|
|
998
1006
|
# Get AI to directly edit the CSV file
|
|
999
1007
|
local ai_response
|
|
1000
|
-
local stderr_file="
|
|
1008
|
+
local stderr_file="stderr-$$.txt"
|
|
1001
1009
|
if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
|
|
1002
1010
|
echo "[ERROR] All AI models failed to generate crossover hybrid ideas" >&2
|
|
1003
1011
|
cat "$stderr_file" >&2
|
|
1012
|
+
cd "$original_pwd"
|
|
1004
1013
|
rm -f "$temp_csv" "$stderr_file"
|
|
1005
1014
|
return 1
|
|
1006
1015
|
fi
|
|
1007
1016
|
rm -f "$stderr_file"
|
|
1008
1017
|
|
|
1018
|
+
# Restore working directory
|
|
1019
|
+
cd "$original_pwd"
|
|
1020
|
+
|
|
1009
1021
|
echo "[DEBUG] AI response: $ai_response" >&2
|
|
1010
1022
|
|
|
1011
1023
|
# Validate that the CSV file was actually modified
|
|
@@ -1025,8 +1037,8 @@ ideate_ai_legacy() {
|
|
|
1025
1037
|
exit 1
|
|
1026
1038
|
fi
|
|
1027
1039
|
|
|
1028
|
-
# Create temporary CSV copy
|
|
1029
|
-
local temp_csv="/
|
|
1040
|
+
# Create temporary CSV copy in evolution directory (so AI can access it)
|
|
1041
|
+
local temp_csv="$FULL_EVOLUTION_DIR/temp-csv-$$.csv"
|
|
1030
1042
|
cp "$FULL_CSV_PATH" "$temp_csv"
|
|
1031
1043
|
|
|
1032
1044
|
echo "[INFO] Generating $TOTAL_IDEAS ideas (legacy mode)..."
|
|
@@ -1040,15 +1052,18 @@ ideate_ai_legacy() {
|
|
|
1040
1052
|
fi
|
|
1041
1053
|
|
|
1042
1054
|
# Build prompt for direct CSV modification
|
|
1043
|
-
|
|
1055
|
+
# Use relative paths and change to evolution directory so AI can access files
|
|
1056
|
+
local temp_csv_basename=$(basename "$temp_csv")
|
|
1057
|
+
|
|
1058
|
+
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
|
|
1044
1059
|
|
|
1045
1060
|
Algorithm files for context:
|
|
1046
|
-
- Base algorithm:
|
|
1047
|
-
- Evolved algorithms:
|
|
1061
|
+
- Base algorithm: algorithm.py
|
|
1062
|
+
- Evolved algorithms: evolution_*.py
|
|
1048
1063
|
|
|
1049
1064
|
IMPORTANT: Before generating ideas, you should:
|
|
1050
|
-
1. Read the base algorithm to understand the codebase structure and possibilities
|
|
1051
|
-
2. Read ALL existing evolution_*.py files to see what modifications have been attempted
|
|
1065
|
+
1. Use the Read tool to examine the base algorithm to understand the codebase structure and possibilities
|
|
1066
|
+
2. Use the Read tool to examine ALL existing evolution_*.py files to see what modifications have been attempted
|
|
1052
1067
|
3. Consider which approaches might work well
|
|
1053
1068
|
|
|
1054
1069
|
Project Brief:
|
|
@@ -1064,12 +1079,13 @@ $top_performers"
|
|
|
1064
1079
|
prompt+="
|
|
1065
1080
|
|
|
1066
1081
|
Instructions:
|
|
1067
|
-
1. Read the current CSV file
|
|
1068
|
-
2.
|
|
1069
|
-
3.
|
|
1070
|
-
4.
|
|
1071
|
-
5.
|
|
1072
|
-
6.
|
|
1082
|
+
1. Use the Read tool to examine the current CSV file
|
|
1083
|
+
2. Find the highest ID number for generation $CURRENT_GENERATION (e.g., if gen$CURRENT_GENERATION-003 exists, next should be gen$CURRENT_GENERATION-004)
|
|
1084
|
+
3. If no gen$CURRENT_GENERATION entries exist yet, start with gen$CURRENT_GENERATION-001
|
|
1085
|
+
4. Use the Edit or MultiEdit tool to add exactly $TOTAL_IDEAS new rows to the CSV file
|
|
1086
|
+
5. For each idea, create a row with: id,parent_id,description,,pending
|
|
1087
|
+
6. Mix both parameter tuning and structural changes
|
|
1088
|
+
7. If building on existing algorithms, use their ID as parent_id, otherwise leave parent_id empty
|
|
1073
1089
|
|
|
1074
1090
|
⚠️ AVOID ONLY: Kelly floor/cap adjustments that assume leverage > 1.0 (these get clamped and have no effect)
|
|
1075
1091
|
|
|
@@ -1083,19 +1099,27 @@ Instructions:
|
|
|
1083
1099
|
- Time-Based Patterns: Intraday effects, calendar anomalies, volatility timing
|
|
1084
1100
|
- Parameter Optimization: Entry thresholds, indicator periods, strategy weights
|
|
1085
1101
|
|
|
1086
|
-
|
|
1102
|
+
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."
|
|
1087
1103
|
|
|
1104
|
+
# Change to evolution directory so AI can access files
|
|
1105
|
+
local original_pwd=$(pwd)
|
|
1106
|
+
cd "$FULL_EVOLUTION_DIR"
|
|
1107
|
+
|
|
1088
1108
|
# Get AI to directly edit the CSV file
|
|
1089
1109
|
local ai_response
|
|
1090
|
-
local stderr_file="
|
|
1110
|
+
local stderr_file="stderr-$$.txt"
|
|
1091
1111
|
if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
|
|
1092
1112
|
echo "[ERROR] All AI models failed to generate ideas" >&2
|
|
1093
1113
|
cat "$stderr_file" >&2
|
|
1114
|
+
cd "$original_pwd"
|
|
1094
1115
|
rm -f "$temp_csv" "$stderr_file"
|
|
1095
1116
|
return 1
|
|
1096
1117
|
fi
|
|
1097
1118
|
rm -f "$stderr_file"
|
|
1098
1119
|
|
|
1120
|
+
# Restore working directory
|
|
1121
|
+
cd "$original_pwd"
|
|
1122
|
+
|
|
1099
1123
|
echo "[DEBUG] AI response: $ai_response" >&2
|
|
1100
1124
|
|
|
1101
1125
|
# Validate that the CSV file was actually modified
|
package/bin/claude-evolve-worker
CHANGED
|
@@ -79,6 +79,244 @@ else
|
|
|
79
79
|
load_config
|
|
80
80
|
fi
|
|
81
81
|
|
|
82
|
+
# Call an AI model with a prompt - handles model-specific invocation
|
|
83
|
+
call_ai_model() {
|
|
84
|
+
local model="$1"
|
|
85
|
+
local prompt="$2"
|
|
86
|
+
local ai_output
|
|
87
|
+
local ai_exit_code
|
|
88
|
+
|
|
89
|
+
case "$model" in
|
|
90
|
+
"claude")
|
|
91
|
+
# Pass prompt as argument, not via stdin
|
|
92
|
+
ai_output=$(timeout 300 claude --dangerously-skip-permissions -p "$prompt" 2>&1)
|
|
93
|
+
ai_exit_code=$?
|
|
94
|
+
;;
|
|
95
|
+
|
|
96
|
+
"gemini")
|
|
97
|
+
# Pass prompt as argument, not via stdin
|
|
98
|
+
ai_output=$(timeout 300 gemini -y -p "$prompt" 2>&1)
|
|
99
|
+
ai_exit_code=$?
|
|
100
|
+
;;
|
|
101
|
+
|
|
102
|
+
"codex")
|
|
103
|
+
# Pass prompt as argument, not via stdin
|
|
104
|
+
ai_output=$(timeout 300 codex exec --dangerously-bypass-approvals-and-sandbox "$prompt" 2>&1)
|
|
105
|
+
ai_exit_code=$?
|
|
106
|
+
;;
|
|
107
|
+
|
|
108
|
+
*)
|
|
109
|
+
echo "[WORKER-$$] ERROR: Unknown AI model: $model" >&2
|
|
110
|
+
return 1
|
|
111
|
+
;;
|
|
112
|
+
esac
|
|
113
|
+
|
|
114
|
+
# Return output via stdout
|
|
115
|
+
echo "$ai_output"
|
|
116
|
+
return $ai_exit_code
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Check if AI output indicates a usage limit was hit
|
|
120
|
+
is_usage_limit_error() {
|
|
121
|
+
local output="$1"
|
|
122
|
+
local model="$2"
|
|
123
|
+
|
|
124
|
+
case "$model" in
|
|
125
|
+
"claude")
|
|
126
|
+
echo "$output" | grep -q "Claude AI usage limit reached"
|
|
127
|
+
;;
|
|
128
|
+
"gemini")
|
|
129
|
+
echo "$output" | grep -q "Quota exceeded.*Gemini"
|
|
130
|
+
;;
|
|
131
|
+
"codex")
|
|
132
|
+
# Add codex-specific limit patterns if they exist
|
|
133
|
+
false
|
|
134
|
+
;;
|
|
135
|
+
*)
|
|
136
|
+
false
|
|
137
|
+
;;
|
|
138
|
+
esac
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Validate if AI output is successful
|
|
142
|
+
is_valid_ai_output() {
|
|
143
|
+
local output="$1"
|
|
144
|
+
local model="$2"
|
|
145
|
+
local exit_code="$3"
|
|
146
|
+
|
|
147
|
+
# First check exit code
|
|
148
|
+
[[ $exit_code -ne 0 ]] && return 1
|
|
149
|
+
|
|
150
|
+
# Model-specific validation
|
|
151
|
+
case "$model" in
|
|
152
|
+
"claude")
|
|
153
|
+
# Claude is straightforward - exit code 0 means success
|
|
154
|
+
return 0
|
|
155
|
+
;;
|
|
156
|
+
|
|
157
|
+
"gemini")
|
|
158
|
+
# Gemini needs extra validation for auth messages
|
|
159
|
+
if echo "$output" | grep -q "Attempting to authenticate\|Authenticating\|Loading\|Initializing"; then
|
|
160
|
+
return 1
|
|
161
|
+
fi
|
|
162
|
+
# Also check for minimal output
|
|
163
|
+
if [[ -z "$output" ]] || [[ $(echo "$output" | wc -l) -lt 2 ]]; then
|
|
164
|
+
return 1
|
|
165
|
+
fi
|
|
166
|
+
return 0
|
|
167
|
+
;;
|
|
168
|
+
|
|
169
|
+
"codex")
|
|
170
|
+
# Codex might return JSON that needs extraction
|
|
171
|
+
if echo "$output" | grep -q '"content"'; then
|
|
172
|
+
# Will be cleaned later, just check it's not an error
|
|
173
|
+
if echo "$output" | grep -q "error\|failed\|exception"; then
|
|
174
|
+
return 1
|
|
175
|
+
fi
|
|
176
|
+
fi
|
|
177
|
+
[[ -n "$output" ]]
|
|
178
|
+
;;
|
|
179
|
+
|
|
180
|
+
*)
|
|
181
|
+
return 1
|
|
182
|
+
;;
|
|
183
|
+
esac
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
# Clean AI output if needed (e.g., extract from JSON)
|
|
187
|
+
clean_ai_output() {
|
|
188
|
+
local output="$1"
|
|
189
|
+
local model="$2"
|
|
190
|
+
|
|
191
|
+
case "$model" in
|
|
192
|
+
"codex")
|
|
193
|
+
# Clean codex output - extract content between "codex" marker and "tokens used"
|
|
194
|
+
if echo "$output" | grep -q "^\[.*\] codex$"; then
|
|
195
|
+
# Extract content between "codex" line and "tokens used" line
|
|
196
|
+
output=$(echo "$output" | awk '/\] codex$/{flag=1;next}/\] tokens used/{flag=0}flag')
|
|
197
|
+
elif echo "$output" | grep -q '"content"'; then
|
|
198
|
+
# Old JSON format
|
|
199
|
+
output=$(echo "$output" | python3 -c "
|
|
200
|
+
import sys
|
|
201
|
+
import json
|
|
202
|
+
try:
|
|
203
|
+
data = json.load(sys.stdin)
|
|
204
|
+
if 'content' in data:
|
|
205
|
+
print(data['content'])
|
|
206
|
+
elif 'response' in data:
|
|
207
|
+
print(data['response'])
|
|
208
|
+
elif 'text' in data:
|
|
209
|
+
print(data['text'])
|
|
210
|
+
else:
|
|
211
|
+
print(json.dumps(data))
|
|
212
|
+
except:
|
|
213
|
+
print(sys.stdin.read())
|
|
214
|
+
" 2>/dev/null || echo "$output")
|
|
215
|
+
fi
|
|
216
|
+
# Trim whitespace
|
|
217
|
+
output=$(echo "$output" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
|
|
218
|
+
;;
|
|
219
|
+
esac
|
|
220
|
+
|
|
221
|
+
echo "$output"
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
# AI round-robin with fallback function for code evolution
|
|
225
|
+
call_ai_for_evolution() {
|
|
226
|
+
local prompt="$1"
|
|
227
|
+
local candidate_id="$2"
|
|
228
|
+
|
|
229
|
+
# Extract generation and ID numbers for round-robin calculation
|
|
230
|
+
local gen_num=0
|
|
231
|
+
local id_num=0
|
|
232
|
+
if [[ $candidate_id =~ ^gen([0-9]+)-([0-9]+)$ ]]; then
|
|
233
|
+
gen_num=$((10#${BASH_REMATCH[1]}))
|
|
234
|
+
id_num=$((10#${BASH_REMATCH[2]}))
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
# Calculate hash for round-robin (combine generation and ID)
|
|
238
|
+
local hash_value=$((gen_num * 1000 + id_num))
|
|
239
|
+
|
|
240
|
+
# Check which AI tools are available
|
|
241
|
+
local available_models=()
|
|
242
|
+
if command -v claude >/dev/null 2>&1; then
|
|
243
|
+
available_models+=("claude")
|
|
244
|
+
fi
|
|
245
|
+
if command -v gemini >/dev/null 2>&1; then
|
|
246
|
+
available_models+=("gemini")
|
|
247
|
+
fi
|
|
248
|
+
if command -v codex >/dev/null 2>&1; then
|
|
249
|
+
available_models+=("codex")
|
|
250
|
+
fi
|
|
251
|
+
|
|
252
|
+
if [[ ${#available_models[@]} -eq 0 ]]; then
|
|
253
|
+
echo "[WORKER-$$] ERROR: No AI models available!" >&2
|
|
254
|
+
return 1
|
|
255
|
+
fi
|
|
256
|
+
|
|
257
|
+
# Create ordered list based on round-robin for this candidate
|
|
258
|
+
local num_models=${#available_models[@]}
|
|
259
|
+
local start_index=$((hash_value % num_models))
|
|
260
|
+
local models=()
|
|
261
|
+
|
|
262
|
+
# Add models in round-robin order starting from the calculated index
|
|
263
|
+
for ((i=0; i<num_models; i++)); do
|
|
264
|
+
local idx=$(((start_index + i) % num_models))
|
|
265
|
+
models+=("${available_models[$idx]}")
|
|
266
|
+
done
|
|
267
|
+
|
|
268
|
+
echo "[WORKER-$$] Model order for $candidate_id (round-robin): ${models[*]}" >&2
|
|
269
|
+
|
|
270
|
+
# Track if any model hit usage limits
|
|
271
|
+
local hit_usage_limit=false
|
|
272
|
+
local limited_models=()
|
|
273
|
+
|
|
274
|
+
# Try each model in the ordered sequence
|
|
275
|
+
for model in "${models[@]}"; do
|
|
276
|
+
echo "[WORKER-$$] Attempting code evolution with $model" >&2
|
|
277
|
+
|
|
278
|
+
# Call the AI model
|
|
279
|
+
local ai_output
|
|
280
|
+
ai_output=$(call_ai_model "$model" "$prompt")
|
|
281
|
+
local ai_exit_code=$?
|
|
282
|
+
|
|
283
|
+
# Check for usage limits
|
|
284
|
+
if is_usage_limit_error "$ai_output" "$model"; then
|
|
285
|
+
echo "[WORKER-$$] $model hit usage limit - trying next model" >&2
|
|
286
|
+
hit_usage_limit=true
|
|
287
|
+
limited_models+=("$model")
|
|
288
|
+
continue
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
# Validate output
|
|
292
|
+
if is_valid_ai_output "$ai_output" "$model" "$ai_exit_code"; then
|
|
293
|
+
# Clean output if needed
|
|
294
|
+
ai_output=$(clean_ai_output "$ai_output" "$model")
|
|
295
|
+
echo "[WORKER-$$] $model succeeded" >&2
|
|
296
|
+
# Output the cleaned result for the worker to use
|
|
297
|
+
echo "$ai_output"
|
|
298
|
+
return 0
|
|
299
|
+
fi
|
|
300
|
+
|
|
301
|
+
echo "[WORKER-$$] $model failed (exit code $ai_exit_code), trying next model..." >&2
|
|
302
|
+
if [[ -n "$ai_output" ]]; then
|
|
303
|
+
echo "[WORKER-$$] $model error: $(echo "$ai_output" | head -5)" >&2
|
|
304
|
+
fi
|
|
305
|
+
done
|
|
306
|
+
|
|
307
|
+
# All models have been tried
|
|
308
|
+
echo "[WORKER-$$] All AI models failed for code evolution" >&2
|
|
309
|
+
|
|
310
|
+
# If any model hit usage limits and we couldn't complete the task
|
|
311
|
+
if [[ "$hit_usage_limit" == "true" ]]; then
|
|
312
|
+
echo "[WORKER-$$] Models hit usage limits: ${limited_models[*]}" >&2
|
|
313
|
+
echo "[WORKER-$$] Unable to complete evolution due to API limits" >&2
|
|
314
|
+
exit 3
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
return 1
|
|
318
|
+
}
|
|
319
|
+
|
|
82
320
|
# Validate paths
|
|
83
321
|
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
84
322
|
echo "[WORKER-$$] CSV file not found: $FULL_CSV_PATH" >&2
|
|
@@ -153,42 +391,40 @@ with EvolutionCSV('$FULL_CSV_PATH') as csv:
|
|
|
153
391
|
echo "[WORKER-$$] Copying $source_file to $target_file"
|
|
154
392
|
cp "$source_file" "$target_file"
|
|
155
393
|
|
|
156
|
-
# Apply evolution using
|
|
157
|
-
echo "[WORKER-$$] Applying evolution
|
|
158
|
-
|
|
394
|
+
# Apply evolution using AI
|
|
395
|
+
echo "[WORKER-$$] Applying evolution..."
|
|
396
|
+
|
|
397
|
+
# Use relative path for AI prompt
|
|
398
|
+
local target_basename=$(basename "$target_file")
|
|
399
|
+
local evolution_prompt="Modify the algorithm in $target_basename based on this description: $description
|
|
159
400
|
|
|
160
401
|
The modification should be substantial and follow the description exactly. Make sure the algorithm still follows all interface requirements and can run properly.
|
|
161
402
|
|
|
162
403
|
Important: Make meaningful changes that match the description. Don't just add comments or make trivial adjustments."
|
|
163
404
|
|
|
164
405
|
if [[ "$is_baseline" != "true" ]]; then
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
406
|
+
# Change to evolution directory so AI can access files
|
|
407
|
+
local original_pwd=$(pwd)
|
|
408
|
+
cd "$FULL_EVOLUTION_DIR"
|
|
168
409
|
|
|
169
|
-
#
|
|
170
|
-
if
|
|
171
|
-
echo "[WORKER-$$] ERROR:
|
|
172
|
-
|
|
173
|
-
rm -f "$target_file" # Clean up on failure
|
|
174
|
-
# Exit with special code 3 to indicate API limit
|
|
175
|
-
exit 3
|
|
176
|
-
fi
|
|
177
|
-
|
|
178
|
-
if [[ $claude_exit_code -ne 0 ]]; then
|
|
179
|
-
echo "[WORKER-$$] ERROR: Claude evolution failed with exit code $claude_exit_code" >&2
|
|
180
|
-
echo "[WORKER-$$] ERROR: Claude output: $claude_output" >&2
|
|
410
|
+
# Try AI models with round-robin based on candidate ID
|
|
411
|
+
if ! call_ai_for_evolution "$evolution_prompt" "$candidate_id"; then
|
|
412
|
+
echo "[WORKER-$$] ERROR: All AI models failed to generate code" >&2
|
|
413
|
+
cd "$original_pwd"
|
|
181
414
|
rm -f "$target_file" # Clean up on failure
|
|
182
415
|
return 1
|
|
183
416
|
fi
|
|
184
417
|
|
|
418
|
+
# Restore working directory
|
|
419
|
+
cd "$original_pwd"
|
|
420
|
+
|
|
185
421
|
echo "[WORKER-$$] Evolution applied successfully"
|
|
186
422
|
fi
|
|
187
423
|
fi
|
|
188
424
|
|
|
189
425
|
# Run evaluation
|
|
190
426
|
echo "[WORKER-$$] Evaluating algorithm..."
|
|
191
|
-
local eval_output_file="/
|
|
427
|
+
local eval_output_file="$FULL_EVOLUTION_DIR/temp-eval-$$-$candidate_id.out"
|
|
192
428
|
local eval_start=$(date +%s)
|
|
193
429
|
|
|
194
430
|
# Prepare evaluation command
|