Spaces:
Paused
Paused
Claude Code Claude Opus 4.6 commited on
Commit ·
f729048
1
Parent(s): 5cbdd00
god: Fix manual terminate+task blocking - allow immediate task reassignment
Browse files[PROBLEM] When agents sent [ACTION: terminate_cc] followed by [TASK] in the
same message, the task submission condition was checked BEFORE the terminate_cc
action was processed. This caused:
1. has_manual_terminate bypass allowed submission even with cc_status["running"]=True
2. Race condition where terminate_cc was processed after task submission
3. Duplicate action history entries
[FIX] Process [ACTION: terminate_cc] BEFORE [TASK] block (now #1b, before #2).
This ensures cc_status["running"] is False when task submission condition runs,
eliminating the need for has_manual_terminate bypass and preventing race conditions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- scripts/conversation-loop.py +9 -12
scripts/conversation-loop.py
CHANGED
|
@@ -1646,20 +1646,23 @@ def parse_and_execute_turn(raw_text, ctx):
|
|
| 1646 |
task_assigned = True
|
| 1647 |
return raw_text, results, task_assigned
|
| 1648 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1649 |
# 2. Handle [TASK]...[/TASK] → Claude Code
|
| 1650 |
task_match = re.search(r'\[TASK\](.*?)\[/TASK\]', raw_text, re.DOTALL)
|
| 1651 |
if task_match:
|
| 1652 |
task_desc = task_match.group(1).strip()
|
| 1653 |
-
# Check if this message also contains [ACTION: terminate_cc]
|
| 1654 |
-
# If so, the termination will be processed before task submission (below),
|
| 1655 |
-
# so we should allow this task to proceed even if cc_status["running"] is currently True.
|
| 1656 |
-
has_manual_terminate = re.search(r'\[ACTION:\s*terminate_cc\]', raw_text)
|
| 1657 |
# task_assigned is set to True ONLY when task is actually submitted, not when blocked
|
| 1658 |
if not task_desc:
|
| 1659 |
results.append({"action": "task", "result": "Empty task description."})
|
| 1660 |
elif child_state["stage"] in ("BUILDING", "RESTARTING", "APP_STARTING"):
|
| 1661 |
results.append({"action": "task", "result": f"BLOCKED: Cain is {child_state['stage']}. Wait for it to finish."})
|
| 1662 |
-
elif cc_status["running"]
|
| 1663 |
# LOW-PUSH-FREQUENCY EMERGENCY: If push frequency is critically low and task has been running 60s+, allow task handoff
|
| 1664 |
# This prevents all-talk-no-action when agents get stuck after 1 push
|
| 1665 |
global _push_count, _turns_since_last_push, _push_count_this_task
|
|
@@ -1684,8 +1687,7 @@ def parse_and_execute_turn(raw_text, ctx):
|
|
| 1684 |
|
| 1685 |
# Task submission block - handles both normal flow and post-zero-push-termination flow
|
| 1686 |
# Only proceeds if not blocked above (results is empty or only contains termination notice)
|
| 1687 |
-
|
| 1688 |
-
if (not results or any("terminate_cc" in r.get("action", "") for r in results)) and (cc_status["running"] == False or has_manual_terminate):
|
| 1689 |
# Check cooldown
|
| 1690 |
check_and_clear_cooldown()
|
| 1691 |
if last_rebuild_trigger_at > 0:
|
|
@@ -1737,11 +1739,6 @@ def parse_and_execute_turn(raw_text, ctx):
|
|
| 1737 |
result = action_send_bubble(bubble_match.group(1).strip())
|
| 1738 |
results.append({"action": "send_bubble", "result": result})
|
| 1739 |
|
| 1740 |
-
# 5. Handle [ACTION: terminate_cc] (terminate stuck Claude Code)
|
| 1741 |
-
if re.search(r'\[ACTION:\s*terminate_cc\]', raw_text):
|
| 1742 |
-
result = action_terminate_cc()
|
| 1743 |
-
results.append({"action": "terminate_cc", "result": result})
|
| 1744 |
-
|
| 1745 |
# Activate deferred cooldown
|
| 1746 |
if _pending_cooldown:
|
| 1747 |
last_rebuild_trigger_at = time.time()
|
|
|
|
| 1646 |
task_assigned = True
|
| 1647 |
return raw_text, results, task_assigned
|
| 1648 |
|
| 1649 |
+
# 1b. Handle [ACTION: terminate_cc] FIRST (before task submission)
|
| 1650 |
+
# This ensures cc_status["running"] is False before task submission check,
|
| 1651 |
+
# preventing race conditions when agents terminate+submit in same message.
|
| 1652 |
+
if re.search(r'\[ACTION:\s*terminate_cc\]', raw_text):
|
| 1653 |
+
result = action_terminate_cc()
|
| 1654 |
+
results.append({"action": "terminate_cc", "result": result})
|
| 1655 |
+
|
| 1656 |
# 2. Handle [TASK]...[/TASK] → Claude Code
|
| 1657 |
task_match = re.search(r'\[TASK\](.*?)\[/TASK\]', raw_text, re.DOTALL)
|
| 1658 |
if task_match:
|
| 1659 |
task_desc = task_match.group(1).strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1660 |
# task_assigned is set to True ONLY when task is actually submitted, not when blocked
|
| 1661 |
if not task_desc:
|
| 1662 |
results.append({"action": "task", "result": "Empty task description."})
|
| 1663 |
elif child_state["stage"] in ("BUILDING", "RESTARTING", "APP_STARTING"):
|
| 1664 |
results.append({"action": "task", "result": f"BLOCKED: Cain is {child_state['stage']}. Wait for it to finish."})
|
| 1665 |
+
elif cc_status["running"]:
|
| 1666 |
# LOW-PUSH-FREQUENCY EMERGENCY: If push frequency is critically low and task has been running 60s+, allow task handoff
|
| 1667 |
# This prevents all-talk-no-action when agents get stuck after 1 push
|
| 1668 |
global _push_count, _turns_since_last_push, _push_count_this_task
|
|
|
|
| 1687 |
|
| 1688 |
# Task submission block - handles both normal flow and post-zero-push-termination flow
|
| 1689 |
# Only proceeds if not blocked above (results is empty or only contains termination notice)
|
| 1690 |
+
if (not results or any("terminate_cc" in r.get("action", "") for r in results)) and cc_status["running"] == False:
|
|
|
|
| 1691 |
# Check cooldown
|
| 1692 |
check_and_clear_cooldown()
|
| 1693 |
if last_rebuild_trigger_at > 0:
|
|
|
|
| 1739 |
result = action_send_bubble(bubble_match.group(1).strip())
|
| 1740 |
results.append({"action": "send_bubble", "result": result})
|
| 1741 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1742 |
# Activate deferred cooldown
|
| 1743 |
if _pending_cooldown:
|
| 1744 |
last_rebuild_trigger_at = time.time()
|