Claude Code commited on
Commit
a67fdae
Β·
1 Parent(s): 6a122fb

god: implement Hard Reset override for discussion loops

Browse files
Files changed (1) hide show
  1. scripts/conversation-loop.py +67 -0
scripts/conversation-loop.py CHANGED
@@ -135,6 +135,11 @@ _last_push_time = 0.0 # timestamp of last successful push
135
  _turns_since_last_push = 0 # turns since last push (resets on push)
136
  _push_count_this_task = 0 # pushes made during the CURRENT CC task (resets on new task)
137
 
 
 
 
 
 
138
  def _init_push_count_from_workspace():
139
  """Initialize push count from existing workspace commits.
140
  This persists push tracking across conversation loop restarts."""
@@ -1235,6 +1240,11 @@ def enrich_task_with_context(task_desc, ctx):
1235
  # Only dynamic state β€” static knowledge (architecture, rules, env vars) is in CLAUDE.md
1236
  parts.append(f"\nCurrent stage: {child_state['stage']}")
1237
  parts.append(f"Health: {ctx.get('health', 'unknown')}")
 
 
 
 
 
1238
  return "\n".join(parts)
1239
 
1240
 
@@ -2178,6 +2188,37 @@ RULES:
2178
  - CONFIG_ERROR with collision = [ACTION: delete_env:KEY] then [ACTION: restart]
2179
  - English first, then --- separator, then Chinese translation""")
2180
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2181
  return "\n".join(parts)
2182
 
2183
 
@@ -2588,6 +2629,32 @@ while True:
2588
  # Reset discussion loop counter since we're starting fresh
2589
  _discussion_loop_count = 0
2590
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2591
  # Note: Aggressive CC auto-termination based on push frequency is removed.
2592
  # God monitors push frequency and proposes mechanism fixes when needed.
2593
  # The normal CLAUDE_TIMEOUT auto-kill in do_turn() handles truly stuck processes.
 
135
  _turns_since_last_push = 0 # turns since last push (resets on push)
136
  _push_count_this_task = 0 # pushes made during the CURRENT CC task (resets on new task)
137
 
138
+ # Hard Reset override β€” FORCE_PUSH mode for breaking discussion loops
139
+ _force_push_mode = False # When True, bypass normal flow and force task generation
140
+ _force_push_trigger_time = 0.0 # When FORCE_PUSH was triggered
141
+ _force_push_skip_termination = False # If True, skip termination (already terminated)
142
+
143
  def _init_push_count_from_workspace():
144
  """Initialize push count from existing workspace commits.
145
  This persists push tracking across conversation loop restarts."""
 
1240
  # Only dynamic state β€” static knowledge (architecture, rules, env vars) is in CLAUDE.md
1241
  parts.append(f"\nCurrent stage: {child_state['stage']}")
1242
  parts.append(f"Health: {ctx.get('health', 'unknown')}")
1243
+ # Hardcoded fix hint for common port binding issues
1244
+ if "port" in task_desc.lower() or "bind" in task_desc.lower() or child_state['stage'] in ("RUNTIME_ERROR", "BUILD_ERROR"):
1245
+ parts.append(f"\nPORT BINDING FIX HINT:")
1246
+ parts.append(f"The child process uses `uvicorn.run(app, host=\"0.0.0.0\", port=7860)`.")
1247
+ parts.append(f"Ensure app.py reflects this exactly β€” app must be bound to 0.0.0.0:7860.")
1248
  return "\n".join(parts)
1249
 
1250
 
 
2188
  - CONFIG_ERROR with collision = [ACTION: delete_env:KEY] then [ACTION: restart]
2189
  - English first, then --- separator, then Chinese translation""")
2190
 
2191
+ # CHATTER DETECTION: Check if last 3 messages are pure discussion without [TASK] or code
2192
+ # If agents are stuck in conversational loops, force them to act
2193
+ if len(history) >= 3 and not cc_status["running"]:
2194
+ recent_texts = [h.get("text", "") for h in history[-3:]]
2195
+ conversational_keywords = ["let's", "maybe", "i think", "perhaps", "could we", "should we", "we could", "it might"]
2196
+ chatter_count = 0
2197
+ for text in recent_texts:
2198
+ text_lower = text.lower()
2199
+ # Check if message has [TASK], code blocks (```), or actions
2200
+ has_substance = ("[TASK]" in text or "[ACTION:" in text or "```" in text)
2201
+ # Check if message is mostly conversational
2202
+ is_chatter = any(kw in text_lower for kw in conversational_keywords)
2203
+ if is_chatter and not has_substance:
2204
+ chatter_count += 1
2205
+ if chatter_count >= 3: # All 3 recent messages are chatter without substance
2206
+ parts.append(f"\n🚨 SYSTEM: STOP DISCUSSION. EXECUTE [TASK] or PUSH.")
2207
+ parts.append(f"Agents are stuck in conversational loop. Write ONLY [TASK]...[/TASK] this turn.")
2208
+
2209
+ # FORCE_PUSH MODE OVERRIDE: Hard reset for discussion loops
2210
+ # When triggered, force agents to generate a task regardless of CC status
2211
+ global _force_push_mode, _force_push_skip_termination
2212
+ if _force_push_mode:
2213
+ parts.append(f"\n🚨🚨🚨 FORCE_PUSH MODE ACTIVATED 🚨🚨🚨")
2214
+ parts.append(f"Discussion loop detected with ZERO pushes. You MUST write a [TASK]...[/TASK] this turn.")
2215
+ if not _force_push_skip_termination:
2216
+ parts.append(f"FIRST: Use [ACTION: terminate_cc] to kill stuck CC.")
2217
+ parts.append(f"THEN: Write [TASK]...[/TASK] with a concrete code fix.")
2218
+ else:
2219
+ parts.append(f"CC is idle. Write [TASK]...[/TASK] NOW with a concrete code fix.")
2220
+ parts.append(f"DO NOT discuss. DO NOT plan. Write task ONLY.")
2221
+
2222
  return "\n".join(parts)
2223
 
2224
 
 
2629
  # Reset discussion loop counter since we're starting fresh
2630
  _discussion_loop_count = 0
2631
 
2632
+ # HARD RESET OVERRIDE: Detect "all talk no action" deadlock
2633
+ # Trigger: discussion_loop_count > 3 AND zero pushes (last_push_time == 0)
2634
+ # This means agents have been discussing for 4+ turns with ZERO progress.
2635
+ if not _force_push_mode and _discussion_loop_count > 3 and _last_push_time == 0:
2636
+ print(f"[FORCE-PUSH] HARD RESET TRIGGERED: {_discussion_loop_count} discussion turns with ZERO pushes!")
2637
+ _force_push_mode = True
2638
+ _force_push_trigger_time = time.time()
2639
+ # Auto-terminate CC if running (bypass 90s wait if idle > 2 min)
2640
+ cc_idle_time = time.time() - (_last_cc_output_time if _last_cc_output_time > 0 else time.time())
2641
+ if cc_status["running"]:
2642
+ if cc_idle_time > 120: # Idle > 2 minutes, skip wait
2643
+ print(f"[FORCE-PUSH] CC idle > 2min, terminating immediately")
2644
+ action_terminate_cc()
2645
+ _force_push_skip_termination = True
2646
+ else:
2647
+ print(f"[FORCE-PUSH] CC running but active, will terminate on next agent turn")
2648
+ _force_push_skip_termination = False
2649
+ else:
2650
+ _force_push_skip_termination = True # CC already idle
2651
+
2652
+ # Reset FORCE_PUSH mode after 5 minutes (safety valve)
2653
+ if _force_push_mode and time.time() - _force_push_trigger_time > 300:
2654
+ print(f"[FORCE-PUSH] Mode timeout (300s), resetting to normal")
2655
+ _force_push_mode = False
2656
+ _force_push_skip_termination = False
2657
+
2658
  # Note: Aggressive CC auto-termination based on push frequency is removed.
2659
  # God monitors push frequency and proposes mechanism fixes when needed.
2660
  # The normal CLAUDE_TIMEOUT auto-kill in do_turn() handles truly stuck processes.