Skip to content

Commit 8f65bdd

Browse files
committed
Add failure reason logging for options with zero actions
1 parent 0e1d3fc commit 8f65bdd

2 files changed

Lines changed: 22 additions & 2 deletions

File tree

predicators/agent_sdk/tools.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,15 @@ async def test_option_plan(args: Dict[str, Any]) -> Dict[str, Any]:
942942

943943
step_line = (f"Step {step_idx}: {opt_name}({obj_names}) "
944944
f"({num_actions} actions)")
945+
if num_actions == 0:
946+
failure = getattr(ctx.option_model,
947+
'last_execution_failure', None)
948+
if failure:
949+
step_line += f"\n FAILURE REASON: {failure}"
950+
else:
951+
step_line += ("\n FAILURE REASON: Option terminated "
952+
"immediately (terminal condition was True "
953+
"before any action was taken)")
945954
if include_atoms:
946955
atoms_before = utils.abstract(state, ctx.predicates)
947956
atoms_after = utils.abstract(next_state, ctx.predicates)

predicators/option_model.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,13 @@ def __init__(self, options: Set[ParameterizedOption],
6464
super().__init__()
6565
self._name_to_parameterized_option = {o.name: o for o in options}
6666
self._simulator = simulator
67+
# Diagnostic: stores the reason when the last call returned 0 actions.
68+
self.last_execution_failure: str | None = None
6769

6870
def get_next_state_and_num_actions(self, state: State,
6971
option: _Option) -> Tuple[State, int]:
72+
self.last_execution_failure = None
73+
7074
# We do not want to actually execute the option; we want to know what
7175
# *would* happen if we were to execute the option. So, we will make a
7276
# copy of the option and run that instead. This is important if the
@@ -109,7 +113,13 @@ def _terminal(s: State) -> bool:
109113
return True
110114
if last_state is not DefaultState and last_state.allclose(s):
111115
logging.debug("Option got stuck.")
112-
raise utils.OptionExecutionFailure("Option got stuck.")
116+
raise utils.OptionExecutionFailure(
117+
f"Option '{option_copy.name}' got stuck: the "
118+
f"policy's action did not change the state. "
119+
f"This usually means the first motion phase "
120+
f"produced a no-op (e.g. IK returned current "
121+
f"joints, or finger command matched current "
122+
f"finger state).")
113123
last_state = s
114124
return False
115125
else:
@@ -123,9 +133,10 @@ def _terminal(s: State) -> bool:
123133
state,
124134
_terminal,
125135
max_num_steps=CFG.max_num_steps_option_rollout)
126-
except utils.OptionExecutionFailure:
136+
except utils.OptionExecutionFailure as e:
127137
# If there is a failure during the execution of the option, treat
128138
# this as a noop.
139+
self.last_execution_failure = str(e)
129140
return state, 0
130141
# Note that in the case of using a PyBullet environment, the
131142
# second return value (num_actions) will be an underestimate

0 commit comments

Comments
 (0)