claude-evolve 1.5.28 → 1.5.29
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-worker +96 -58
- package/lib/ai-cli.sh +3 -3
- package/lib/config.sh +4 -4
- package/package.json +1 -1
package/bin/claude-evolve-worker
CHANGED
|
@@ -72,68 +72,106 @@ fi
|
|
|
72
72
|
call_ai_for_evolution() {
|
|
73
73
|
local prompt="$1"
|
|
74
74
|
local candidate_id="$2"
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
# Get target file path from worker context
|
|
77
77
|
local target_file="$FULL_OUTPUT_DIR/evolution_${candidate_id}.py"
|
|
78
|
-
|
|
79
|
-
#
|
|
80
|
-
local
|
|
81
|
-
local
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
id_num=$((10#${BASH_REMATCH[2]}))
|
|
93
|
-
fi
|
|
94
|
-
|
|
95
|
-
# Calculate hash for round-robin (combine generation and ID)
|
|
96
|
-
local hash_value=$((gen_num * 1000 + id_num))
|
|
97
|
-
|
|
98
|
-
# Use the centralized AI library for evolution (run command)
|
|
99
|
-
local ai_output
|
|
100
|
-
ai_output=$(call_ai_with_round_robin "$prompt" "run" "$hash_value")
|
|
101
|
-
local ai_exit_code=$?
|
|
102
|
-
|
|
103
|
-
# Handle special exit codes
|
|
104
|
-
if [[ $ai_exit_code -eq 3 ]]; then
|
|
105
|
-
echo "[WORKER-$$] All models hit usage limits" >&2
|
|
106
|
-
echo "[WORKER-$$] Unable to complete evolution due to API limits" >&2
|
|
107
|
-
exit 3
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
# Check if the target file was actually modified
|
|
111
|
-
local file_was_modified=false
|
|
112
|
-
if [[ -f "$target_file" ]]; then
|
|
113
|
-
local file_hash_after
|
|
114
|
-
local file_mtime_after
|
|
115
|
-
file_hash_after=$(shasum -a 256 "$target_file" 2>/dev/null | cut -d' ' -f1)
|
|
116
|
-
file_mtime_after=$(stat -f %m "$target_file" 2>/dev/null || stat -c %Y "$target_file" 2>/dev/null)
|
|
117
|
-
|
|
118
|
-
if [[ "$file_hash_before" != "$file_hash_after" ]] || [[ "$file_mtime_before" != "$file_mtime_after" ]]; then
|
|
119
|
-
file_was_modified=true
|
|
78
|
+
|
|
79
|
+
# Retry configuration for API limits
|
|
80
|
+
local retry_count=0
|
|
81
|
+
local max_retries=3
|
|
82
|
+
local wait_seconds=300 # Start with 5 minutes
|
|
83
|
+
local max_wait_seconds=1800 # Cap at 30 minutes
|
|
84
|
+
|
|
85
|
+
while true; do
|
|
86
|
+
# Capture file state before AI call
|
|
87
|
+
local file_hash_before=""
|
|
88
|
+
local file_mtime_before=""
|
|
89
|
+
if [[ -f "$target_file" ]]; then
|
|
90
|
+
file_hash_before=$(shasum -a 256 "$target_file" 2>/dev/null | cut -d' ' -f1)
|
|
91
|
+
file_mtime_before=$(stat -f %m "$target_file" 2>/dev/null || stat -c %Y "$target_file" 2>/dev/null)
|
|
120
92
|
fi
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if [[
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
echo "[WORKER-$$] AI succeeded with exit code 0" >&2
|
|
93
|
+
|
|
94
|
+
# Extract generation and ID numbers for round-robin calculation
|
|
95
|
+
local gen_num=0
|
|
96
|
+
local id_num=0
|
|
97
|
+
if [[ $candidate_id =~ ^gen([0-9]+)-([0-9]+)$ ]]; then
|
|
98
|
+
gen_num=$((10#${BASH_REMATCH[1]}))
|
|
99
|
+
id_num=$((10#${BASH_REMATCH[2]}))
|
|
129
100
|
fi
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
101
|
+
|
|
102
|
+
# Calculate hash for round-robin (combine generation and ID)
|
|
103
|
+
local hash_value=$((gen_num * 1000 + id_num))
|
|
104
|
+
|
|
105
|
+
# Use the centralized AI library for evolution (run command)
|
|
106
|
+
local ai_output
|
|
107
|
+
ai_output=$(call_ai_with_round_robin "$prompt" "run" "$hash_value")
|
|
108
|
+
local ai_exit_code=$?
|
|
109
|
+
|
|
110
|
+
# Handle special exit codes
|
|
111
|
+
if [[ $ai_exit_code -eq 3 ]]; then
|
|
112
|
+
# All models hit usage limits
|
|
113
|
+
if [[ $retry_count -lt $max_retries ]]; then
|
|
114
|
+
((retry_count++))
|
|
115
|
+
echo "[WORKER-$$] All models hit usage limits (retry $retry_count/$max_retries)" >&2
|
|
116
|
+
echo "[WORKER-$$] Waiting $wait_seconds seconds ($(($wait_seconds / 60)) minutes) before retrying..." >&2
|
|
117
|
+
|
|
118
|
+
# Sleep with countdown
|
|
119
|
+
local remaining=$wait_seconds
|
|
120
|
+
while [[ $remaining -gt 0 ]]; do
|
|
121
|
+
if [[ $((remaining % 60)) -eq 0 ]]; then
|
|
122
|
+
echo "[WORKER-$$] Retrying in $((remaining / 60)) minutes..." >&2
|
|
123
|
+
fi
|
|
124
|
+
sleep 60
|
|
125
|
+
remaining=$((remaining - 60))
|
|
126
|
+
done
|
|
127
|
+
|
|
128
|
+
echo "[WORKER-$$] Retrying AI call (attempt #$((retry_count + 1)))..." >&2
|
|
129
|
+
|
|
130
|
+
# Exponential backoff: double the wait time, up to max
|
|
131
|
+
wait_seconds=$((wait_seconds * 2))
|
|
132
|
+
if [[ $wait_seconds -gt $max_wait_seconds ]]; then
|
|
133
|
+
wait_seconds=$max_wait_seconds
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# Continue to retry
|
|
137
|
+
continue
|
|
138
|
+
else
|
|
139
|
+
# Exhausted retries
|
|
140
|
+
echo "[WORKER-$$] All models hit usage limits after $max_retries retries" >&2
|
|
141
|
+
echo "[WORKER-$$] Unable to complete evolution due to API limits" >&2
|
|
142
|
+
exit 3
|
|
143
|
+
fi
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
# Check if the target file was actually modified
|
|
147
|
+
local file_was_modified=false
|
|
148
|
+
if [[ -f "$target_file" ]]; then
|
|
149
|
+
local file_hash_after
|
|
150
|
+
local file_mtime_after
|
|
151
|
+
file_hash_after=$(shasum -a 256 "$target_file" 2>/dev/null | cut -d' ' -f1)
|
|
152
|
+
file_mtime_after=$(stat -f %m "$target_file" 2>/dev/null || stat -c %Y "$target_file" 2>/dev/null)
|
|
153
|
+
|
|
154
|
+
if [[ "$file_hash_before" != "$file_hash_after" ]] || [[ "$file_mtime_before" != "$file_mtime_after" ]]; then
|
|
155
|
+
file_was_modified=true
|
|
156
|
+
fi
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# Success if file was modified OR exit code is 0 (for cases where file validation isn't applicable)
|
|
160
|
+
if [[ "$file_was_modified" == "true" ]] || [[ $ai_exit_code -eq 0 ]]; then
|
|
161
|
+
if [[ "$file_was_modified" == "true" ]]; then
|
|
162
|
+
echo "[WORKER-$$] AI successfully modified $target_file (exit code: $ai_exit_code)" >&2
|
|
163
|
+
else
|
|
164
|
+
echo "[WORKER-$$] AI succeeded with exit code 0" >&2
|
|
165
|
+
fi
|
|
166
|
+
# Output the result for the worker to use
|
|
167
|
+
echo "$ai_output"
|
|
168
|
+
return 0
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# Non-limit failure - don't retry
|
|
172
|
+
echo "[WORKER-$$] AI failed: exit code $ai_exit_code, no file changes detected" >&2
|
|
173
|
+
return 1
|
|
174
|
+
done
|
|
137
175
|
}
|
|
138
176
|
|
|
139
177
|
# Validate paths
|
package/lib/ai-cli.sh
CHANGED
|
@@ -19,7 +19,7 @@ call_ai_model_configured() {
|
|
|
19
19
|
case "$model_name" in
|
|
20
20
|
opus|sonnet)
|
|
21
21
|
local ai_output
|
|
22
|
-
ai_output=$(timeout 300 claude --dangerously-skip-permissions --model "$model_name" -p "$prompt" 2>&1)
|
|
22
|
+
ai_output=$(timeout 300 claude --dangerously-skip-permissions --mcp-config '' --model "$model_name" -p "$prompt" 2>&1)
|
|
23
23
|
local ai_exit_code=$?
|
|
24
24
|
;;
|
|
25
25
|
sonnet-think)
|
|
@@ -28,7 +28,7 @@ call_ai_model_configured() {
|
|
|
28
28
|
local think_prompt="ultrathink
|
|
29
29
|
|
|
30
30
|
$prompt"
|
|
31
|
-
ai_output=$(timeout 600 claude --dangerously-skip-permissions --model sonnet -p "$think_prompt" 2>&1)
|
|
31
|
+
ai_output=$(timeout 600 claude --dangerously-skip-permissions --mcp-config '' --model sonnet -p "$think_prompt" 2>&1)
|
|
32
32
|
local ai_exit_code=$?
|
|
33
33
|
;;
|
|
34
34
|
opus-think)
|
|
@@ -37,7 +37,7 @@ $prompt"
|
|
|
37
37
|
local think_prompt="ultrathink
|
|
38
38
|
|
|
39
39
|
$prompt"
|
|
40
|
-
ai_output=$(timeout 600 claude --dangerously-skip-permissions --model opus -p "$think_prompt" 2>&1)
|
|
40
|
+
ai_output=$(timeout 600 claude --dangerously-skip-permissions --mcp-config '' --model opus -p "$think_prompt" 2>&1)
|
|
41
41
|
local ai_exit_code=$?
|
|
42
42
|
;;
|
|
43
43
|
gpt5high)
|
package/lib/config.sh
CHANGED
|
@@ -102,10 +102,10 @@ load_config() {
|
|
|
102
102
|
LLM_CLI_o3high='codex exec --profile o3high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
103
103
|
LLM_CLI_codex='codex exec --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
|
|
104
104
|
LLM_CLI_gemini='gemini -y -p "{{PROMPT}}"'
|
|
105
|
-
LLM_CLI_opus='claude --dangerously-skip-permissions --model opus -p "{{PROMPT}}"'
|
|
106
|
-
LLM_CLI_opus_think='claude --dangerously-skip-permissions --model opus -p "ultrathink\n\n{{PROMPT}}"'
|
|
107
|
-
LLM_CLI_sonnet='claude --dangerously-skip-permissions --model sonnet -p "{{PROMPT}}"'
|
|
108
|
-
LLM_CLI_sonnet_think='claude --dangerously-skip-permissions --model sonnet -p "ultrathink\n\n{{PROMPT}}"'
|
|
105
|
+
LLM_CLI_opus='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "{{PROMPT}}"'
|
|
106
|
+
LLM_CLI_opus_think='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "ultrathink\n\n{{PROMPT}}"'
|
|
107
|
+
LLM_CLI_sonnet='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "{{PROMPT}}"'
|
|
108
|
+
LLM_CLI_sonnet_think='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "ultrathink\n\n{{PROMPT}}"'
|
|
109
109
|
LLM_CLI_cursor_sonnet='cursor-agent sonnet -p "{{PROMPT}}"'
|
|
110
110
|
LLM_CLI_cursor_opus='cursor-agent opus -p "{{PROMPT}}"'
|
|
111
111
|
LLM_CLI_glm='opencode -m openrouter/z-ai/glm-4.6 run "{{PROMPT}}"'
|