claude-evolve 1.5.27 → 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.
@@ -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
- # Capture file state before AI call
80
- local file_hash_before=""
81
- local file_mtime_before=""
82
- if [[ -f "$target_file" ]]; then
83
- file_hash_before=$(shasum -a 256 "$target_file" 2>/dev/null | cut -d' ' -f1)
84
- file_mtime_before=$(stat -f %m "$target_file" 2>/dev/null || stat -c %Y "$target_file" 2>/dev/null)
85
- fi
86
-
87
- # Extract generation and ID numbers for round-robin calculation
88
- local gen_num=0
89
- local id_num=0
90
- if [[ $candidate_id =~ ^gen([0-9]+)-([0-9]+)$ ]]; then
91
- gen_num=$((10#${BASH_REMATCH[1]}))
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
- fi
122
-
123
- # Success if file was modified OR exit code is 0 (for cases where file validation isn't applicable)
124
- if [[ "$file_was_modified" == "true" ]] || [[ $ai_exit_code -eq 0 ]]; then
125
- if [[ "$file_was_modified" == "true" ]]; then
126
- echo "[WORKER-$$] AI successfully modified $target_file (exit code: $ai_exit_code)" >&2
127
- else
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
- # Output the result for the worker to use
131
- echo "$ai_output"
132
- return 0
133
- fi
134
-
135
- echo "[WORKER-$$] AI failed: exit code $ai_exit_code, no file changes detected" >&2
136
- return 1
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)
@@ -76,6 +76,11 @@ $prompt"
76
76
  ai_output=$(timeout 300 cursor-agent opus -p "$prompt" 2>&1)
77
77
  local ai_exit_code=$?
78
78
  ;;
79
+ glm)
80
+ local ai_output
81
+ ai_output=$(timeout 300 opencode -m openrouter/z-ai/glm-4.6 run "$prompt" 2>&1)
82
+ local ai_exit_code=$?
83
+ ;;
79
84
  *)
80
85
  echo "[ERROR] Unknown model: $model_name" >&2
81
86
  return 1
package/lib/config.sh CHANGED
@@ -54,7 +54,7 @@ DEFAULT_MAX_RETRIES=3
54
54
  DEFAULT_MEMORY_LIMIT_MB=12288
55
55
 
56
56
  # Default LLM CLI configuration - use simple variables instead of arrays
57
- DEFAULT_LLM_RUN="sonnet gpt5 cursor-sonnet"
57
+ DEFAULT_LLM_RUN="sonnet gpt5 cursor-sonnet glm"
58
58
  DEFAULT_LLM_IDEATE="gemini sonnet-think sonnet-think gpt5high sonnet-think o3high"
59
59
 
60
60
  # Load configuration from config file
@@ -102,12 +102,13 @@ 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
+ LLM_CLI_glm='opencode -m openrouter/z-ai/glm-4.6 run "{{PROMPT}}"'
111
112
  LLM_RUN="$DEFAULT_LLM_RUN"
112
113
  LLM_IDEATE="$DEFAULT_LLM_IDEATE"
113
114
 
@@ -327,7 +328,7 @@ show_config() {
327
328
  echo " Memory limit: ${MEMORY_LIMIT_MB}MB"
328
329
  echo " LLM configuration:"
329
330
  # Show LLM configurations using dynamic variable names
330
- for model in gpt5high o3high codex gemini opus opus_think sonnet sonnet_think cursor_sonnet cursor_opus; do
331
+ for model in gpt5high o3high codex gemini opus opus_think sonnet sonnet_think cursor_sonnet cursor_opus glm; do
331
332
  var_name="LLM_CLI_${model}"
332
333
  var_value=$(eval echo "\$$var_name")
333
334
  if [[ -n "$var_value" ]]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-evolve",
3
- "version": "1.5.27",
3
+ "version": "1.5.29",
4
4
  "bin": {
5
5
  "claude-evolve": "./bin/claude-evolve",
6
6
  "claude-evolve-main": "./bin/claude-evolve-main",
@@ -72,7 +72,7 @@ llm_cli:
72
72
 
73
73
  # commented out because these change over time; if you want to fix them in a particular
74
74
  # configuration, uncomment them and set them
75
- #run: sonnet gpt5 cursor-sonnet
75
+ #run: sonnet gpt5 cursor-sonnet glm
76
76
  #ideate: gemini sonnet-think sonnet-think gpt5high sonnet-think o3high
77
77
 
78
78
  # Available models:
@@ -86,3 +86,4 @@ llm_cli:
86
86
  # - o3high: O3 via Codex CLI (high reasoning)
87
87
  # - cursor-sonnet: Claude 3.5 Sonnet via Cursor Agent CLI
88
88
  # - cursor-opus: Claude 3 Opus via Cursor Agent CLI
89
+ # - glm: GLM-4.6 via OpenCode CLI