Skip to content

Commit ec4aee8

Browse files
committed
fix: prevent executor agent from getting stuck in action loop (#251)
- Add critical rules to executor system prompt: use wait as fallback when no viable action exists, always output a valid action, try different approaches after repeated failures - Add repeated-action loop detection in handle_executor_result: when the same action is repeated 3+ times consecutively, set error_flag_plan to force the manager to re-plan
1 parent 21e477b commit ec4aee8

2 files changed

Lines changed: 19 additions & 2 deletions

File tree

droidrun/agent/droid/droid_agent.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- When reasoning=True: Uses Manager (planning) + Executor (action) workflows
88
"""
99

10+
import json
1011
import logging
1112
from typing import TYPE_CHECKING, Type, Awaitable, Union
1213

@@ -762,9 +763,23 @@ async def handle_executor_result(
762763
"""
763764
Process Executor result and continue.
764765
765-
Checks for error escalation and loops back to Manager.
766+
Checks for error escalation, repeated action loops, and loops back to Manager.
766767
Note: Max steps check is now done in run_manager pre-flight.
767768
"""
769+
# Check for repeated action loop (same action N times in a row)
770+
repeat_thresh = 3
771+
if len(self.shared_state.action_pool) >= repeat_thresh:
772+
recent_actions = self.shared_state.action_pool[-repeat_thresh:]
773+
try:
774+
normalized = [json.dumps(a, sort_keys=True) for a in recent_actions]
775+
if len(set(normalized)) == 1:
776+
logger.warning(
777+
f"⚠️ Executor stuck: same action repeated {repeat_thresh} times in a row: {normalized[0]}"
778+
)
779+
self.shared_state.error_flag_plan = True
780+
except (TypeError, ValueError):
781+
pass # Non-serializable actions, skip detection
782+
768783
# Check error escalation and reset flag when errors are resolved
769784
err_thresh = self.shared_state.err_to_manager_thresh
770785

droidrun/config/prompts/executor/system.jinja2

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,10 @@ No actions have been taken yet.
9393
Whatever the current subgoal says to do, do that EXACTLY. Do not substitute with what you think is better. Do not optimize. Do not consider screen state. Parse the subgoal text literally and execute the matching atomic action.
9494

9595
IMPORTANT:
96-
1. Do NOT repeat previously failed actions multiple times. Try changing to another action.
96+
1. Do NOT repeat previously failed actions multiple times. If an action failed, try a DIFFERENT action or approach.
9797
2. Must do the current subgoal.
98+
3. If you have tried the same action 2+ times and it keeps failing, try a completely different approach. If truly stuck with no viable action, use `{"action": "wait", "duration": 1.0}` as a fallback and explain why in the Description (e.g., "No actionable element found for subgoal").
99+
4. ALWAYS output a valid action. There is no "skip" or "do nothing" option — use `wait` with duration 1.0 if uncertain.
98100

99101
Provide your output in the following format, which contains three parts:
100102

0 commit comments

Comments
 (0)