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.
@@ -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
- ai_output=$(echo "$prompt" | codex exec -m o3 --full-auto 2>&1)
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
- # 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
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 "$prompt" 2>&1)
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
- # 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
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
- # 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
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
- ai_output=$(echo "$prompt" | codex exec -m o3 --full-auto 2>&1)
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
- # 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
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 "$prompt" 2>&1)
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
- 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
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 ! 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
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. 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.
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. 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\")
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. 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
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. 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
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. 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
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
 
@@ -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
- available_models+=("claude") # Claude Sonnet always available
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
- local ai_exit_code
280
+ ai_output=$(call_ai_model "$model" "$prompt")
281
+ local ai_exit_code=$?
126
282
 
127
- case "$model" in
128
- "claude")
129
- ai_output=$(echo "$prompt" | claude --dangerously-skip-permissions -p 2>&1)
130
- ai_exit_code=$?
131
-
132
- # Check for usage limits
133
- if echo "$ai_output" | grep -q "Claude AI usage limit reached"; then
134
- echo "[WORKER-$$] Claude AI usage limit reached - trying next model" >&2
135
- continue
136
- fi
137
-
138
- if [[ $ai_exit_code -eq 0 ]]; then
139
- echo "[WORKER-$$] Claude Sonnet succeeded" >&2
140
- return 0
141
- fi
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 in round-robin failed, check for API limit exit
199
- if echo "${ai_output:-}" | grep -q "Claude AI usage limit reached"; then
200
- echo "[WORKER-$$] ERROR: All AI models unavailable - Claude hit usage limit" >&2
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-evolve",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "bin": {
5
5
  "claude-evolve": "./bin/claude-evolve",
6
6
  "claude-evolve-main": "./bin/claude-evolve-main",