Spaces:
Running
Running
Claude Code Claude Opus 4.6 commited on
Commit Β·
a081e30
1
Parent(s): a67fdae
god: implement Emergency Override Protocol for discussion loops
Browse files- Define MAX_IDLE_TURNS = 3 for override trigger threshold
- Trigger when discussion_loop_count > 3 AND push_count == 0
- Override action:terminate_cc timeout restrictions (10s idle threshold)
- Force PUSH_ONLY mode with SYSTEM OVERRIDE message
- Reset _emergency_override_active flag on timeout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- scripts/conversation-loop.py +30 -15
scripts/conversation-loop.py
CHANGED
|
@@ -140,6 +140,10 @@ _force_push_mode = False # When True, bypass normal flow and force task generat
|
|
| 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."""
|
|
@@ -394,11 +398,19 @@ def action_send_bubble(text):
|
|
| 394 |
|
| 395 |
|
| 396 |
def action_terminate_cc():
|
| 397 |
-
"""Terminate a stuck Claude Code process. Use when CC has been running with no new output for too long.
|
| 398 |
-
|
|
|
|
| 399 |
with cc_lock:
|
| 400 |
if not cc_status["running"]:
|
| 401 |
return "Claude Code is not running. Nothing to terminate."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
# Mark as not running - the background thread will eventually finish
|
| 403 |
cc_status["running"] = False
|
| 404 |
cc_status["result"] = "(TERMINATED by agent - task was stuck)"
|
|
@@ -2206,11 +2218,11 @@ RULES:
|
|
| 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 |
-
#
|
| 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π¨π¨π¨
|
| 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.")
|
|
@@ -2218,6 +2230,7 @@ RULES:
|
|
| 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 |
|
|
@@ -2629,30 +2642,32 @@ while True:
|
|
| 2629 |
# Reset discussion loop counter since we're starting fresh
|
| 2630 |
_discussion_loop_count = 0
|
| 2631 |
|
| 2632 |
-
#
|
| 2633 |
-
# Trigger: discussion_loop_count >
|
| 2634 |
-
# This means agents have been discussing for
|
| 2635 |
-
if not _force_push_mode and _discussion_loop_count >
|
| 2636 |
-
print(f"[
|
| 2637 |
_force_push_mode = True
|
|
|
|
| 2638 |
_force_push_trigger_time = time.time()
|
| 2639 |
-
# Auto-terminate CC if running (
|
| 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 >
|
| 2643 |
-
print(f"[
|
| 2644 |
action_terminate_cc()
|
| 2645 |
_force_push_skip_termination = True
|
| 2646 |
else:
|
| 2647 |
-
print(f"[
|
| 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"[
|
| 2655 |
_force_push_mode = False
|
|
|
|
| 2656 |
_force_push_skip_termination = False
|
| 2657 |
|
| 2658 |
# Note: Aggressive CC auto-termination based on push frequency is removed.
|
|
|
|
| 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 |
+
# Emergency Override Protocol constants
|
| 144 |
+
MAX_IDLE_TURNS = 3 # Trigger emergency override after this many idle turns with zero pushes
|
| 145 |
+
_emergency_override_active = False # When True, safety throttles are ignored
|
| 146 |
+
|
| 147 |
def _init_push_count_from_workspace():
|
| 148 |
"""Initialize push count from existing workspace commits.
|
| 149 |
This persists push tracking across conversation loop restarts."""
|
|
|
|
| 398 |
|
| 399 |
|
| 400 |
def action_terminate_cc():
|
| 401 |
+
"""Terminate a stuck Claude Code process. Use when CC has been running with no new output for too long.
|
| 402 |
+
During Emergency Override, allows immediate termination if idle for > 10s."""
|
| 403 |
+
global cc_status, cc_live_lines, _cc_stale_count, _last_cc_snapshot, _last_cc_output_time, _emergency_override_active
|
| 404 |
with cc_lock:
|
| 405 |
if not cc_status["running"]:
|
| 406 |
return "Claude Code is not running. Nothing to terminate."
|
| 407 |
+
|
| 408 |
+
# During Emergency Override, allow immediate termination if idle for > 10s
|
| 409 |
+
if _emergency_override_active:
|
| 410 |
+
cc_idle_time = time.time() - (_last_cc_output_time if _last_cc_output_time > 0 else time.time())
|
| 411 |
+
if cc_idle_time > 10:
|
| 412 |
+
print(f"[EMERGENCY-OVERRIDE] Terminating CC immediately (idle {int(cc_idle_time)}s > 10s threshold)")
|
| 413 |
+
|
| 414 |
# Mark as not running - the background thread will eventually finish
|
| 415 |
cc_status["running"] = False
|
| 416 |
cc_status["result"] = "(TERMINATED by agent - task was stuck)"
|
|
|
|
| 2218 |
parts.append(f"\nπ¨ SYSTEM: STOP DISCUSSION. EXECUTE [TASK] or PUSH.")
|
| 2219 |
parts.append(f"Agents are stuck in conversational loop. Write ONLY [TASK]...[/TASK] this turn.")
|
| 2220 |
|
| 2221 |
+
# EMERGENCY OVERRIDE PROTOCOL: PUSH_ONLY mode for breaking discussion loops
|
| 2222 |
# When triggered, force agents to generate a task regardless of CC status
|
| 2223 |
+
global _force_push_mode, _force_push_skip_termination, _emergency_override_active
|
| 2224 |
if _force_push_mode:
|
| 2225 |
+
parts.append(f"\nπ¨π¨π¨ EMERGENCY OVERRIDE: PUSH_ONLY MODE π¨π¨π¨")
|
| 2226 |
parts.append(f"Discussion loop detected with ZERO pushes. You MUST write a [TASK]...[/TASK] this turn.")
|
| 2227 |
if not _force_push_skip_termination:
|
| 2228 |
parts.append(f"FIRST: Use [ACTION: terminate_cc] to kill stuck CC.")
|
|
|
|
| 2230 |
else:
|
| 2231 |
parts.append(f"CC is idle. Write [TASK]...[/TASK] NOW with a concrete code fix.")
|
| 2232 |
parts.append(f"DO NOT discuss. DO NOT plan. Write task ONLY.")
|
| 2233 |
+
parts.append(f"SYSTEM OVERRIDE: PLANNING SUSPENDED. EXECUTE PUSH NOW.")
|
| 2234 |
|
| 2235 |
return "\n".join(parts)
|
| 2236 |
|
|
|
|
| 2642 |
# Reset discussion loop counter since we're starting fresh
|
| 2643 |
_discussion_loop_count = 0
|
| 2644 |
|
| 2645 |
+
# EMERGENCY OVERRIDE PROTOCOL: Detect "all talk no action" deadlock
|
| 2646 |
+
# Trigger: discussion_loop_count > MAX_IDLE_TURNS AND zero pushes (_push_count == 0)
|
| 2647 |
+
# This means agents have been discussing for MAX_IDLE_TURNS+1 turns with ZERO progress.
|
| 2648 |
+
if not _force_push_mode and _discussion_loop_count > MAX_IDLE_TURNS and _push_count == 0:
|
| 2649 |
+
print(f"[EMERGENCY-OVERRIDE] TRIGGERED: {_discussion_loop_count} discussion turns with ZERO pushes!")
|
| 2650 |
_force_push_mode = True
|
| 2651 |
+
_emergency_override_active = True
|
| 2652 |
_force_push_trigger_time = time.time()
|
| 2653 |
+
# Auto-terminate CC if running (Emergency Override: idle > 10s allows immediate termination)
|
| 2654 |
cc_idle_time = time.time() - (_last_cc_output_time if _last_cc_output_time > 0 else time.time())
|
| 2655 |
if cc_status["running"]:
|
| 2656 |
+
if cc_idle_time > 10: # Emergency Override: Immediate termination if idle > 10s
|
| 2657 |
+
print(f"[EMERGENCY-OVERRIDE] CC idle {int(cc_idle_time)}s > 10s threshold, terminating immediately")
|
| 2658 |
action_terminate_cc()
|
| 2659 |
_force_push_skip_termination = True
|
| 2660 |
else:
|
| 2661 |
+
print(f"[EMERGENCY-OVERRIDE] CC running but active, will terminate on next agent turn")
|
| 2662 |
_force_push_skip_termination = False
|
| 2663 |
else:
|
| 2664 |
_force_push_skip_termination = True # CC already idle
|
| 2665 |
|
| 2666 |
# Reset FORCE_PUSH mode after 5 minutes (safety valve)
|
| 2667 |
if _force_push_mode and time.time() - _force_push_trigger_time > 300:
|
| 2668 |
+
print(f"[EMERGENCY-OVERRIDE] Mode timeout (300s), resetting to normal")
|
| 2669 |
_force_push_mode = False
|
| 2670 |
+
_emergency_override_active = False
|
| 2671 |
_force_push_skip_termination = False
|
| 2672 |
|
| 2673 |
# Note: Aggressive CC auto-termination based on push frequency is removed.
|