claude-evolve 1.5.0 → 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 +71 -125
- package/bin/claude-evolve-worker +182 -70
- package/package.json +1 -1
package/bin/claude-evolve-ideate
CHANGED
|
@@ -83,45 +83,14 @@ call_ai_with_limit_check() {
|
|
|
83
83
|
|
|
84
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
|
|
@@ -243,47 +200,24 @@ call_ai_with_fallbacks() {
|
|
|
243
200
|
local ai_exit_code
|
|
244
201
|
|
|
245
202
|
if [[ "$model" == "o3" ]] && command -v codex >/dev/null 2>&1; then
|
|
246
|
-
|
|
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)
|
|
247
205
|
ai_exit_code=$?
|
|
248
206
|
|
|
249
207
|
if [[ $ai_exit_code -eq 0 ]]; then
|
|
250
|
-
#
|
|
251
|
-
|
|
252
|
-
|
|
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
|
|
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
|
|
274
211
|
fi
|
|
275
212
|
|
|
276
213
|
elif [[ "$model" == "gemini" ]] && command -v gemini >/dev/null 2>&1; then
|
|
277
|
-
ai_output=$(gemini -y -p
|
|
214
|
+
ai_output=$(echo "$prompt" | timeout 300 gemini -y -p 2>&1)
|
|
278
215
|
ai_exit_code=$?
|
|
279
216
|
|
|
280
217
|
if [[ $ai_exit_code -eq 0 ]]; then
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return 0
|
|
285
|
-
fi
|
|
286
|
-
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
|
|
287
221
|
fi
|
|
288
222
|
|
|
289
223
|
else
|
|
@@ -293,16 +227,20 @@ except:
|
|
|
293
227
|
|
|
294
228
|
if [[ $ai_exit_code -eq 0 ]]; then
|
|
295
229
|
# Check for usage limits
|
|
296
|
-
if
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
|
301
236
|
fi
|
|
302
237
|
fi
|
|
303
238
|
fi
|
|
304
239
|
|
|
305
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
|
|
306
244
|
done
|
|
307
245
|
|
|
308
246
|
echo "[ERROR] All AI models failed to generate usable output" >&2
|
|
@@ -826,12 +764,13 @@ Current evolution context:
|
|
|
826
764
|
|
|
827
765
|
Instructions:
|
|
828
766
|
1. Use the Read tool to examine the current CSV file
|
|
829
|
-
2.
|
|
830
|
-
3.
|
|
831
|
-
4.
|
|
832
|
-
5.
|
|
833
|
-
6.
|
|
834
|
-
7.
|
|
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.
|
|
835
774
|
|
|
836
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."
|
|
837
776
|
|
|
@@ -844,7 +783,10 @@ CRITICAL: You must use your file editing tools (Edit/MultiEdit) to modify the CS
|
|
|
844
783
|
local stderr_file="stderr-$$.txt"
|
|
845
784
|
if ! ai_response=$(call_ai_with_fallbacks "$prompt" "$CURRENT_GENERATION" 2>"$stderr_file"); then
|
|
846
785
|
echo "[ERROR] All AI models failed to generate novel ideas" >&2
|
|
786
|
+
echo "[DEBUG] Stderr output from AI calls:" >&2
|
|
847
787
|
cat "$stderr_file" >&2
|
|
788
|
+
echo "[DEBUG] Temp CSV location: $temp_csv" >&2
|
|
789
|
+
echo "[DEBUG] Working directory: $(pwd)" >&2
|
|
848
790
|
cd "$original_pwd"
|
|
849
791
|
rm -f "$temp_csv" "$stderr_file"
|
|
850
792
|
return 1
|
|
@@ -899,12 +841,13 @@ For example: evolution_gen01-251.py
|
|
|
899
841
|
|
|
900
842
|
Instructions:
|
|
901
843
|
1. Use the Read tool to examine the current CSV file
|
|
902
|
-
2.
|
|
903
|
-
3.
|
|
904
|
-
4.
|
|
905
|
-
5.
|
|
906
|
-
6. Each
|
|
907
|
-
7.
|
|
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\")
|
|
908
851
|
|
|
909
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."
|
|
910
853
|
|
|
@@ -972,12 +915,13 @@ For example: evolution_gen01-251.py
|
|
|
972
915
|
|
|
973
916
|
Instructions:
|
|
974
917
|
1. Use the Read tool to examine the current CSV file
|
|
975
|
-
2.
|
|
976
|
-
3.
|
|
977
|
-
4.
|
|
978
|
-
5.
|
|
979
|
-
6. Each
|
|
980
|
-
7.
|
|
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
|
|
981
925
|
|
|
982
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."
|
|
983
927
|
|
|
@@ -1045,12 +989,13 @@ For example: evolution_gen01-251.py
|
|
|
1045
989
|
|
|
1046
990
|
Instructions:
|
|
1047
991
|
1. Use the Read tool to examine the current CSV file
|
|
1048
|
-
2.
|
|
1049
|
-
3.
|
|
1050
|
-
4.
|
|
1051
|
-
5.
|
|
1052
|
-
6. Each
|
|
1053
|
-
7.
|
|
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
|
|
1054
999
|
|
|
1055
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."
|
|
1056
1001
|
|
|
@@ -1135,11 +1080,12 @@ $top_performers"
|
|
|
1135
1080
|
|
|
1136
1081
|
Instructions:
|
|
1137
1082
|
1. Use the Read tool to examine the current CSV file
|
|
1138
|
-
2.
|
|
1139
|
-
3.
|
|
1140
|
-
4.
|
|
1141
|
-
5.
|
|
1142
|
-
6.
|
|
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
|
|
1143
1089
|
|
|
1144
1090
|
⚠️ AVOID ONLY: Kelly floor/cap adjustments that assume leverage > 1.0 (these get clamped and have no effect)
|
|
1145
1091
|
|
package/bin/claude-evolve-worker
CHANGED
|
@@ -79,6 +79,148 @@ 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
|
+
|
|
82
224
|
# AI round-robin with fallback function for code evolution
|
|
83
225
|
call_ai_for_evolution() {
|
|
84
226
|
local prompt="$1"
|
|
@@ -97,7 +239,9 @@ call_ai_for_evolution() {
|
|
|
97
239
|
|
|
98
240
|
# Check which AI tools are available
|
|
99
241
|
local available_models=()
|
|
100
|
-
|
|
242
|
+
if command -v claude >/dev/null 2>&1; then
|
|
243
|
+
available_models+=("claude")
|
|
244
|
+
fi
|
|
101
245
|
if command -v gemini >/dev/null 2>&1; then
|
|
102
246
|
available_models+=("gemini")
|
|
103
247
|
fi
|
|
@@ -105,6 +249,11 @@ call_ai_for_evolution() {
|
|
|
105
249
|
available_models+=("codex")
|
|
106
250
|
fi
|
|
107
251
|
|
|
252
|
+
if [[ ${#available_models[@]} -eq 0 ]]; then
|
|
253
|
+
echo "[WORKER-$$] ERROR: No AI models available!" >&2
|
|
254
|
+
return 1
|
|
255
|
+
fi
|
|
256
|
+
|
|
108
257
|
# Create ordered list based on round-robin for this candidate
|
|
109
258
|
local num_models=${#available_models[@]}
|
|
110
259
|
local start_index=$((hash_value % num_models))
|
|
@@ -118,76 +267,36 @@ call_ai_for_evolution() {
|
|
|
118
267
|
|
|
119
268
|
echo "[WORKER-$$] Model order for $candidate_id (round-robin): ${models[*]}" >&2
|
|
120
269
|
|
|
270
|
+
# Track if any model hit usage limits
|
|
271
|
+
local hit_usage_limit=false
|
|
272
|
+
local limited_models=()
|
|
273
|
+
|
|
121
274
|
# Try each model in the ordered sequence
|
|
122
275
|
for model in "${models[@]}"; do
|
|
123
276
|
echo "[WORKER-$$] Attempting code evolution with $model" >&2
|
|
277
|
+
|
|
278
|
+
# Call the AI model
|
|
124
279
|
local ai_output
|
|
125
|
-
|
|
280
|
+
ai_output=$(call_ai_model "$model" "$prompt")
|
|
281
|
+
local ai_exit_code=$?
|
|
126
282
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
"gemini")
|
|
145
|
-
ai_output=$(gemini -y -p "$prompt" 2>&1)
|
|
146
|
-
ai_exit_code=$?
|
|
147
|
-
|
|
148
|
-
# Check for authentication messages or valid response
|
|
149
|
-
if [[ $ai_exit_code -eq 0 ]]; then
|
|
150
|
-
if ! echo "$ai_output" | grep -q "Attempting to authenticate\|Authenticating\|Loading\|Initializing"; then
|
|
151
|
-
if [[ -n "$ai_output" ]] && [[ $(echo "$ai_output" | wc -l) -ge 2 ]]; then
|
|
152
|
-
echo "[WORKER-$$] Gemini succeeded" >&2
|
|
153
|
-
return 0
|
|
154
|
-
fi
|
|
155
|
-
fi
|
|
156
|
-
fi
|
|
157
|
-
;;
|
|
158
|
-
|
|
159
|
-
"codex")
|
|
160
|
-
ai_output=$(echo "$prompt" | codex exec --full-auto 2>&1)
|
|
161
|
-
ai_exit_code=$?
|
|
162
|
-
|
|
163
|
-
if [[ $ai_exit_code -eq 0 ]]; then
|
|
164
|
-
# Clean codex output if it's JSON
|
|
165
|
-
if echo "$ai_output" | grep -q '"content"'; then
|
|
166
|
-
ai_output=$(echo "$ai_output" | python3 -c "
|
|
167
|
-
import sys
|
|
168
|
-
import json
|
|
169
|
-
try:
|
|
170
|
-
data = json.load(sys.stdin)
|
|
171
|
-
if 'content' in data:
|
|
172
|
-
print(data['content'])
|
|
173
|
-
elif 'response' in data:
|
|
174
|
-
print(data['response'])
|
|
175
|
-
elif 'text' in data:
|
|
176
|
-
print(data['text'])
|
|
177
|
-
else:
|
|
178
|
-
print(json.dumps(data))
|
|
179
|
-
except:
|
|
180
|
-
print(sys.stdin.read())
|
|
181
|
-
" 2>/dev/null || echo "$ai_output")
|
|
182
|
-
fi
|
|
183
|
-
|
|
184
|
-
if [[ -n "$ai_output" ]] && ! echo "$ai_output" | grep -q "error\|failed\|exception"; then
|
|
185
|
-
echo "[WORKER-$$] Codex succeeded" >&2
|
|
186
|
-
return 0
|
|
187
|
-
fi
|
|
188
|
-
fi
|
|
189
|
-
;;
|
|
190
|
-
esac
|
|
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
|
|
191
300
|
|
|
192
301
|
echo "[WORKER-$$] $model failed (exit code $ai_exit_code), trying next model..." >&2
|
|
193
302
|
if [[ -n "$ai_output" ]]; then
|
|
@@ -195,13 +304,16 @@ except:
|
|
|
195
304
|
fi
|
|
196
305
|
done
|
|
197
306
|
|
|
198
|
-
# All models
|
|
199
|
-
|
|
200
|
-
|
|
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
|
|
201
314
|
exit 3
|
|
202
315
|
fi
|
|
203
316
|
|
|
204
|
-
echo "[WORKER-$$] All AI models failed for code evolution" >&2
|
|
205
317
|
return 1
|
|
206
318
|
}
|
|
207
319
|
|