Skip to content

Commit 79db98d

Browse files
committed
Add agent_planner flags to deny/limit its planning simulator
Two CFG knobs let agent_planner run as a model-free or base-sim baseline against the world-model learner: - agent_planner_use_simulator (default True): when False, the planner gets no option model, so test_option_plan and the scene-rendering tools (visualize_state/annotate_scene) are withheld and the prompt shifts to open-loop framing -- it must plan from trajectory data and LLM reasoning alone. - agent_planner_use_base_simulator (default False): when a simulator is used, wraps the base env (skip_process_dynamics=True) instead of the real one, denying the delayed _domain_specific_step dynamics. create_option_model gains a skip_process_dynamics passthrough (forwarded only when True, so non-PyBullet analog envs are unaffected). docker_agent_runner honors the base-sim flag on its in-container rebuild. agent_bilevel asserts a non-None option model. Defaults reproduce existing behavior.
1 parent 2fd3f86 commit 79db98d

5 files changed

Lines changed: 96 additions & 20 deletions

File tree

predicators/agent_sdk/docker_agent_runner.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,9 @@ def main() -> None:
271271
CFG as _cfg # pylint: disable=import-outside-toplevel
272272
logger.info("Recreating option model (%s) inside Docker...",
273273
_cfg.option_model_name)
274-
ctx.option_model = create_option_model(_cfg.option_model_name)
274+
ctx.option_model = create_option_model(
275+
_cfg.option_model_name,
276+
skip_process_dynamics=_cfg.agent_planner_use_base_simulator)
275277
# Sync with all options in context (GT + any previously proposed)
276278
# after the model has its physics server set up.
277279
ctx.option_model._name_to_parameterized_option = { # pylint: disable=protected-access

predicators/approaches/agent_bilevel_approach.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ def _solve(self, task: Task, timeout: int) -> Callable[[State], Action]:
169169
# state-reset noise (see pybullet_env.py:506 warning).
170170
# Pass the original sketch so per-step subgoal divergence
171171
# is logged with the specific atom that went missing.
172+
assert self._option_model is not None, \
173+
"agent_bilevel requires a simulator " \
174+
"(agent_planner_use_simulator=True)."
172175
ok, reason = bilevel_sketch.validate_plan_forward(
173176
task,
174177
plan,
@@ -255,6 +258,9 @@ def _refine_sketch(
255258
implementation returns ``task`` unchanged.
256259
"""
257260
task = self._attach_initial_latent(task)
261+
assert self._option_model is not None, \
262+
"agent_bilevel requires a simulator " \
263+
"(agent_planner_use_simulator=True)."
258264
plan, success, _ = bilevel_sketch.refine_sketch(
259265
task,
260266
sketch,

predicators/approaches/agent_planner_approach.py

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,15 @@ def __init__(self,
5555
action_space, train_tasks, *args, **kwargs)
5656
self._offline_dataset = Dataset([])
5757
self._online_trajectories: List[LowLevelTrajectory] = []
58-
if option_model is not None:
59-
self._option_model = option_model
60-
else:
61-
self._option_model = create_option_model(CFG.option_model_name)
58+
self._option_model: Optional[_OptionModelBase] = (
59+
option_model if option_model is not None else
60+
self._create_planner_option_model())
6261
# Let the option model terminate Wait on atom change using the
6362
# approach's predicates (which may include invented ones). Looked
6463
# up lazily so the lambda picks up predicates invented after
6564
# __init__.
66-
if CFG.wait_option_terminate_on_atom_change:
65+
if self._option_model is not None and \
66+
CFG.wait_option_terminate_on_atom_change:
6767
cast( # pylint: disable=protected-access
6868
Any, self._option_model)._abstract_function = (
6969
lambda s: utils.abstract(s, self._get_all_predicates()))
@@ -119,6 +119,27 @@ def _get_all_trajectories(self) -> List[LowLevelTrajectory]:
119119
"""Return all trajectories (offline + online)."""
120120
return self._offline_dataset.trajectories + self._online_trajectories
121121

122+
def _create_planner_option_model(self) -> Optional[_OptionModelBase]:
123+
"""Build the option model the planner tests plans against.
124+
125+
Honors two CFG knobs:
126+
127+
* ``agent_planner_use_simulator`` -- when False, returns ``None``
128+
so the agent gets no ``test_option_plan`` rollouts and must
129+
plan open-loop from data + LLM reasoning (the model-free
130+
baseline).
131+
* ``agent_planner_use_base_simulator`` -- when True (and a
132+
simulator is used), wraps the *base* env
133+
(``skip_process_dynamics=True``) so the planner is denied the
134+
delayed ``_domain_specific_step`` dynamics; otherwise wraps the
135+
real env.
136+
"""
137+
if not CFG.agent_planner_use_simulator:
138+
return None
139+
return create_option_model(
140+
CFG.option_model_name,
141+
skip_process_dynamics=CFG.agent_planner_use_base_simulator)
142+
122143
# ------------------------------------------------------------------ #
123144
# AgentSessionMixin hooks
124145
# ------------------------------------------------------------------ #
@@ -217,8 +238,12 @@ def _get_all_trajectories(self) -> List[LowLevelTrajectory]:
217238

218239
def _get_agent_system_prompt(self) -> str:
219240
use_scratchpad = CFG.agent_planner_use_scratchpad
220-
use_visualize = CFG.agent_planner_use_visualize_state
221-
use_annotate = CFG.agent_planner_use_annotate_scene
241+
# visualize_state / annotate_scene render a live env, so they are
242+
# only available when the planner has a simulator.
243+
use_visualize = (CFG.agent_planner_use_simulator
244+
and CFG.agent_planner_use_visualize_state)
245+
use_annotate = (CFG.agent_planner_use_simulator
246+
and CFG.agent_planner_use_annotate_scene)
222247

223248
sections = [self._SYSTEM_PROMPT_BASE]
224249

@@ -317,13 +342,18 @@ def _get_sandbox_reference_files(self) -> Dict[str, str]:
317342

318343
def _get_solve_tool_names(self) -> Optional[List[str]]:
319344
tools = [
320-
"inspect_options", "inspect_trajectories", "inspect_train_tasks",
321-
"test_option_plan"
345+
"inspect_options", "inspect_trajectories", "inspect_train_tasks"
322346
]
323-
if CFG.agent_planner_use_annotate_scene:
324-
tools.append("annotate_scene")
325-
if CFG.agent_planner_use_visualize_state:
326-
tools.append("visualize_state")
347+
# The remaining tools all require a simulator / live env:
348+
# test_option_plan rolls plans out through the option model, and
349+
# visualize_state / annotate_scene render env states. None are
350+
# offered when the planner has no simulator.
351+
if CFG.agent_planner_use_simulator:
352+
tools.append("test_option_plan")
353+
if CFG.agent_planner_use_annotate_scene:
354+
tools.append("annotate_scene")
355+
if CFG.agent_planner_use_visualize_state:
356+
tools.append("visualize_state")
327357
return tools
328358

329359
# ------------------------------------------------------------------ #
@@ -524,6 +554,16 @@ def _build_solve_prompt(self, task: Task) -> str:
524554
{task.goal_nl}
525555
"""
526556

557+
if CFG.agent_planner_use_simulator:
558+
instructions_intro = (
559+
"Use your available tools to inspect the environment and "
560+
"test your plan before committing to it.")
561+
else:
562+
instructions_intro = (
563+
"You do NOT have a simulator to test plans against. Inspect "
564+
"the trajectory data and reason carefully about the dynamics, "
565+
"then commit to your best open-loop plan.")
566+
527567
prompt = f"""You are solving a task. \
528568
Generate an option plan to achieve the goal.
529569
{goal_nl_section}
@@ -543,7 +583,7 @@ def _build_solve_prompt(self, task: Task) -> str:
543583
{chr(10).join(option_strs)}
544584
{traj_summary}{tools_str}
545585
## Instructions
546-
Use your available tools to inspect the environment and test your plan before committing to it.
586+
{instructions_intro}
547587
548588
Based on the task information and any past trajectory data, output an option plan to achieve the goal.
549589

predicators/option_model.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import abc
1010
import logging
11-
from typing import Callable, Optional, Set, Tuple
11+
from typing import Any, Callable, Dict, Optional, Set, Tuple
1212

1313
import numpy as np
1414
import pybullet
@@ -43,23 +43,39 @@ def _check_wait_termination(option: _Option, state: State, last_state: State,
4343
return False
4444

4545

46-
def create_option_model(name: str,
47-
use_gui: Optional[bool] = None) -> _OptionModelBase:
46+
def create_option_model(
47+
name: str,
48+
use_gui: Optional[bool] = None,
49+
skip_process_dynamics: bool = False) -> _OptionModelBase:
4850
"""Create an option model given its name.
4951
5052
Args:
5153
name: The name of the option model.
5254
use_gui: If provided, overrides CFG.option_model_use_gui for the
5355
environment created by this option model.
56+
skip_process_dynamics: If True, the wrapped env runs with its
57+
delayed ``_domain_specific_step`` dynamics disabled (the
58+
"base" simulator). Forwarded to the env only when True, so
59+
non-PyBullet analog envs whose ``__init__`` does not accept
60+
the kwarg are unaffected by the default.
5461
"""
5562
gui = CFG.option_model_use_gui if use_gui is None else use_gui
63+
env_kwargs: Dict[str, Any] = {}
64+
if skip_process_dynamics:
65+
env_kwargs["skip_process_dynamics"] = True
5666
if name == "oracle":
57-
env = create_new_env(CFG.env, do_cache=False, use_gui=gui)
67+
env = create_new_env(CFG.env,
68+
do_cache=False,
69+
use_gui=gui,
70+
**env_kwargs)
5871
options = get_gt_options(env.get_name())
5972
return _OracleOptionModel(options, env.simulate)
6073
if name.startswith("oracle"):
6174
env_name = name[name.index("_") + 1:]
62-
env = create_new_env(env_name, do_cache=False, use_gui=gui)
75+
env = create_new_env(env_name,
76+
do_cache=False,
77+
use_gui=gui,
78+
**env_kwargs)
6379
options = get_gt_options(env.get_name())
6480
return _OracleOptionModel(options, env.simulate)
6581
raise NotImplementedError(f"Unknown option model: {name}")

predicators/settings.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,18 @@ class GlobalSettings:
10251025
agent_planner_use_scratchpad = False # include notes.md scratchpad
10261026
agent_planner_use_visualize_state = False # include visualize_state tool
10271027
agent_planner_use_annotate_scene = False # include annotate_scene tool
1028+
# Whether the planner is given a simulator to test candidate plans with
1029+
# (the test_option_plan tool / option-model rollouts). When False, the
1030+
# agent must plan open-loop from trajectory data and LLM reasoning alone
1031+
# -- the genuinely model-free baseline.
1032+
agent_planner_use_simulator = True
1033+
# When a simulator IS given, whether to wrap the *base* env
1034+
# (skip_process_dynamics=True -- delayed _domain_specific_step effects
1035+
# such as boiling/heating are disabled) instead of the real env. Lets the
1036+
# model-free planner be denied the ground-truth delayed dynamics that a
1037+
# world-model learner has to reconstruct. No effect when
1038+
# agent_planner_use_simulator is False.
1039+
agent_planner_use_base_simulator = False
10281040

10291041
# Agent bilevel approach settings
10301042
agent_bilevel_max_samples_per_step = 50 # param samples per step

0 commit comments

Comments
 (0)