mirror of
https://github.com/huggingface/lerobot.git
synced 2026-07-24 02:06:15 +00:00
refactor(runtime): remove compatibility aliases
This commit is contained in:
@@ -239,8 +239,7 @@ MUJOCO_GL=egl lerobot-rollout \
|
|||||||
|
|
||||||
Open `http://localhost:8010` for the live simulator view. Add
|
Open `http://localhost:8010` for the live simulator view. Add
|
||||||
`--sim.direct_subtask` to bypass the language planner and make each typed prompt
|
`--sim.direct_subtask` to bypass the language planner and make each typed prompt
|
||||||
the action policy's current subtask. The legacy `lerobot-language-runtime`
|
the action policy's current subtask.
|
||||||
command remains as a compatibility alias.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -358,8 +358,6 @@ lerobot-edit-dataset="lerobot.scripts.lerobot_edit_dataset:main"
|
|||||||
lerobot-setup-can="lerobot.scripts.lerobot_setup_can:main"
|
lerobot-setup-can="lerobot.scripts.lerobot_setup_can:main"
|
||||||
lerobot-annotate="lerobot.scripts.lerobot_annotate:main"
|
lerobot-annotate="lerobot.scripts.lerobot_annotate:main"
|
||||||
lerobot-rollout="lerobot.scripts.lerobot_rollout:main"
|
lerobot-rollout="lerobot.scripts.lerobot_rollout:main"
|
||||||
# Backward-compatible alias; interactive language deployment is part of lerobot-rollout.
|
|
||||||
lerobot-language-runtime="lerobot.scripts.lerobot_language_runtime:main"
|
|
||||||
|
|
||||||
# ---------------- Tool Configurations ----------------
|
# ---------------- Tool Configurations ----------------
|
||||||
|
|
||||||
|
|||||||
@@ -146,15 +146,6 @@ class PI052Config(PI05Config):
|
|||||||
Degrades gracefully to BF16 if ``kernels`` / the FlashRT packages are
|
Degrades gracefully to BF16 if ``kernels`` / the FlashRT packages are
|
||||||
missing. Default off keeps behaviour identical to the BF16 path."""
|
missing. Default off keeps behaviour identical to the BF16 path."""
|
||||||
|
|
||||||
use_hf_kernels: bool = True
|
|
||||||
"""Deprecated. Liger HF kernels are patched unconditionally by
|
|
||||||
``_enable_hf_kernels`` — this field is retained as a no-op for
|
|
||||||
backward compatibility with checkpoints saved before commit
|
|
||||||
d70c8104 (which still serialize ``use_hf_kernels: true`` into
|
|
||||||
``config.json``). Loading those configs would otherwise raise
|
|
||||||
``DecodingError: The fields use_hf_kernels are not valid for
|
|
||||||
PI052Config`` (job 22164492). Remove in a future major bump."""
|
|
||||||
|
|
||||||
use_flex_attention: bool = False
|
use_flex_attention: bool = False
|
||||||
"""Accepted for checkpoint-config compatibility only — no-op in this branch.
|
"""Accepted for checkpoint-config compatibility only — no-op in this branch.
|
||||||
Newer training runs serialize ``use_flex_attention`` into ``config.json`` to
|
Newer training runs serialize ``use_flex_attention`` into ``config.json`` to
|
||||||
|
|||||||
@@ -979,15 +979,11 @@ class PI052Policy(PreTrainedPolicy):
|
|||||||
"PI052: knowledge insulation enabled — action→VLM K/V gradients are blocked in attention."
|
"PI052: knowledge insulation enabled — action→VLM K/V gradients are blocked in attention."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Size per-environment inference state lazily; the scalar mirrors env 0 for compatibility.
|
# Size per-environment inference state lazily.
|
||||||
self.last_subtasks: list[str] | None = None
|
self.last_subtasks: list[str] | None = None
|
||||||
self.last_subtasks_raw: list[str] | None = None
|
self.last_subtasks_raw: list[str] | None = None
|
||||||
self.last_subtasks_source: list[str] | None = None
|
self.last_subtasks_source: list[str] | None = None
|
||||||
self._last_good_subtasks: list[str | None] | None = None
|
self._last_good_subtasks: list[str | None] | None = None
|
||||||
self.last_subtask: str | None = None
|
|
||||||
self.last_subtask_raw: str | None = None
|
|
||||||
self.last_subtask_source: str = "unset"
|
|
||||||
self.last_subtask_debug: str = ""
|
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""Reset action and high-level inference state."""
|
"""Reset action and high-level inference state."""
|
||||||
@@ -1000,10 +996,6 @@ class PI052Policy(PreTrainedPolicy):
|
|||||||
self.last_subtasks_raw = None
|
self.last_subtasks_raw = None
|
||||||
self.last_subtasks_source = None
|
self.last_subtasks_source = None
|
||||||
self._last_good_subtasks = None
|
self._last_good_subtasks = None
|
||||||
self.last_subtask = None
|
|
||||||
self.last_subtask_raw = None
|
|
||||||
self.last_subtask_source = "unset"
|
|
||||||
self.last_subtask_debug = ""
|
|
||||||
# Counts action chunks since the last subtask (re)generation, so the
|
# Counts action chunks since the last subtask (re)generation, so the
|
||||||
# subtask can be held across several chunks (see subtask_replan_steps).
|
# subtask can be held across several chunks (see subtask_replan_steps).
|
||||||
self._subtask_chunk_counter = 0
|
self._subtask_chunk_counter = 0
|
||||||
@@ -1828,11 +1820,6 @@ class PI052Policy(PreTrainedPolicy):
|
|||||||
|
|
||||||
tokens, masks = self._stack_token_rows(rows, tokenizer)
|
tokens, masks = self._stack_token_rows(rows, tokenizer)
|
||||||
|
|
||||||
# Scalar aliases mirror env 0 for back-compat / single-env overlays.
|
|
||||||
self.last_subtask = self.last_subtasks[0] if self.last_subtasks else None
|
|
||||||
self.last_subtask_raw = self.last_subtasks_raw[0] if self.last_subtasks_raw else None
|
|
||||||
self.last_subtask_source = self.last_subtasks_source[0] if self.last_subtasks_source else "unset"
|
|
||||||
|
|
||||||
out = dict(batch)
|
out = dict(batch)
|
||||||
out[OBS_LANGUAGE_TOKENS] = tokens
|
out[OBS_LANGUAGE_TOKENS] = tokens
|
||||||
out[OBS_LANGUAGE_ATTENTION_MASK] = masks
|
out[OBS_LANGUAGE_ATTENTION_MASK] = masks
|
||||||
|
|||||||
+17
-19
@@ -27,7 +27,6 @@ from typing import Any
|
|||||||
|
|
||||||
from .adapter import GenerationConfig
|
from .adapter import GenerationConfig
|
||||||
from .language_runtime import LanguageConditionedPolicyAdapter, LanguageConditionedRuntime
|
from .language_runtime import LanguageConditionedPolicyAdapter, LanguageConditionedRuntime
|
||||||
from .repl import _emit
|
|
||||||
|
|
||||||
logger = logging.getLogger("lerobot.runtime")
|
logger = logging.getLogger("lerobot.runtime")
|
||||||
|
|
||||||
@@ -586,7 +585,7 @@ def _handle_slash_command(runtime: Any, line: str) -> bool:
|
|||||||
runtime.set_task(rest)
|
runtime.set_task(rest)
|
||||||
# New task → drop the stale subtask so the high-level
|
# New task → drop the stale subtask so the high-level
|
||||||
# loop regenerates one for the new goal.
|
# loop regenerates one for the new goal.
|
||||||
runtime.state["current_subtask"] = None
|
runtime.state.set_context("subtask", None)
|
||||||
print(f"[runtime] action — task: {rest!r}", flush=True)
|
print(f"[runtime] action — task: {rest!r}", flush=True)
|
||||||
elif runtime.state.get("task"):
|
elif runtime.state.get("task"):
|
||||||
print(
|
print(
|
||||||
@@ -643,17 +642,16 @@ def _make_state_panel_renderer(
|
|||||||
console.print(
|
console.print(
|
||||||
" [dim]commands:[/] [bold]/action[/] <task> run · [bold]/help[/] · [bold]stop[/]"
|
" [dim]commands:[/] [bold]/action[/] <task> run · [bold]/help[/] · [bold]stop[/]"
|
||||||
)
|
)
|
||||||
for key, label in (
|
display_values = {
|
||||||
("task", "task"),
|
"task": st.get("task"),
|
||||||
("current_subtask", "subtask"),
|
**(st.get("language_context") or {}),
|
||||||
("current_plan", "plan"),
|
}
|
||||||
("current_memory", "memory"),
|
for key in ("task", "subtask", "plan", "memory"):
|
||||||
):
|
value = display_values.get(key)
|
||||||
value = st.get(key)
|
|
||||||
if value:
|
if value:
|
||||||
console.print(f" [bold cyan]{label:<8}[/] {value}")
|
console.print(f" [bold cyan]{key:<8}[/] {value}")
|
||||||
else:
|
else:
|
||||||
console.print(f" [dim]{label:<8} (not set)[/]")
|
console.print(f" [dim]{key:<8} (not set)[/]")
|
||||||
queue_len = (
|
queue_len = (
|
||||||
len(st["action_queue"])
|
len(st["action_queue"])
|
||||||
if isinstance(st.get("action_queue"), (list, tuple)) or hasattr(st.get("action_queue"), "__len__")
|
if isinstance(st.get("action_queue"), (list, tuple)) or hasattr(st.get("action_queue"), "__len__")
|
||||||
@@ -728,7 +726,7 @@ def run(
|
|||||||
*,
|
*,
|
||||||
adapter_factory: Callable[[Any, GenerationConfig], LanguageConditionedPolicyAdapter] | None = None,
|
adapter_factory: Callable[[Any, GenerationConfig], LanguageConditionedPolicyAdapter] | None = None,
|
||||||
panel_label: str | None = None,
|
panel_label: str | None = None,
|
||||||
prog: str = "lerobot-language-runtime",
|
prog: str = "lerobot-rollout",
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Run the interactive language-conditioned runtime CLI.
|
"""Run the interactive language-conditioned runtime CLI.
|
||||||
|
|
||||||
@@ -821,7 +819,7 @@ def run(
|
|||||||
rt = runtime_box.get("rt")
|
rt = runtime_box.get("rt")
|
||||||
if rt is None:
|
if rt is None:
|
||||||
return args.task
|
return args.task
|
||||||
return rt.state.get("current_subtask") or rt.state.get("task") or args.task
|
return rt.state.language_context.get("subtask") or rt.state.task or args.task
|
||||||
|
|
||||||
if sim_mode:
|
if sim_mode:
|
||||||
from lerobot.runtime.sim_robocasa import RoboCasaSimBackend # noqa: PLC0415
|
from lerobot.runtime.sim_robocasa import RoboCasaSimBackend # noqa: PLC0415
|
||||||
@@ -936,7 +934,7 @@ def _run_sim_interactive(
|
|||||||
runtime.set_task(initial_task)
|
runtime.set_task(initial_task)
|
||||||
# In direct-subtask mode the typed text IS the subtask; otherwise clear
|
# In direct-subtask mode the typed text IS the subtask; otherwise clear
|
||||||
# it so the model generates one.
|
# it so the model generates one.
|
||||||
runtime.state["current_subtask"] = initial_task if direct_subtask else None
|
runtime.state.set_context("subtask", initial_task if direct_subtask else None)
|
||||||
runtime.state["mode"] = "action"
|
runtime.state["mode"] = "action"
|
||||||
|
|
||||||
# Keep the terminal quiet while the browser renders the rollout.
|
# Keep the terminal quiet while the browser renders the rollout.
|
||||||
@@ -985,7 +983,7 @@ def _run_sim_interactive(
|
|||||||
elif low in {"/reset", "reset"}:
|
elif low in {"/reset", "reset"}:
|
||||||
sim_backend.reset_scene()
|
sim_backend.reset_scene()
|
||||||
_clear_action_queue(runtime)
|
_clear_action_queue(runtime)
|
||||||
runtime.state["current_subtask"] = None
|
runtime.state.set_context("subtask", None)
|
||||||
if hasattr(runtime.policy, "reset"):
|
if hasattr(runtime.policy, "reset"):
|
||||||
runtime.policy.reset()
|
runtime.policy.reset()
|
||||||
print("[reset] new kitchen scene", flush=True)
|
print("[reset] new kitchen scene", flush=True)
|
||||||
@@ -994,7 +992,7 @@ def _run_sim_interactive(
|
|||||||
runtime.set_task(cmd)
|
runtime.set_task(cmd)
|
||||||
# Direct mode: the typed text is the subtask itself;
|
# Direct mode: the typed text is the subtask itself;
|
||||||
# otherwise clear it so the model regenerates one.
|
# otherwise clear it so the model regenerates one.
|
||||||
runtime.state["current_subtask"] = cmd if direct_subtask else None
|
runtime.state.set_context("subtask", cmd if direct_subtask else None)
|
||||||
_clear_action_queue(runtime)
|
_clear_action_queue(runtime)
|
||||||
adapter = getattr(runtime, "policy_adapter", None)
|
adapter = getattr(runtime, "policy_adapter", None)
|
||||||
if adapter is not None and hasattr(adapter, "_chunks_until_regen"):
|
if adapter is not None and hasattr(adapter, "_chunks_until_regen"):
|
||||||
@@ -1043,7 +1041,7 @@ def _run_robot_interactive(
|
|||||||
|
|
||||||
if initial_task:
|
if initial_task:
|
||||||
runtime.set_task(initial_task)
|
runtime.set_task(initial_task)
|
||||||
runtime.state["current_subtask"] = initial_task if direct_subtask else None
|
runtime.state.set_context("subtask", initial_task if direct_subtask else None)
|
||||||
# An explicit initial task starts immediately; otherwise the robot stays paused.
|
# An explicit initial task starts immediately; otherwise the robot stays paused.
|
||||||
runtime.state["mode"] = "action"
|
runtime.state["mode"] = "action"
|
||||||
|
|
||||||
@@ -1092,7 +1090,7 @@ def _run_robot_interactive(
|
|||||||
else:
|
else:
|
||||||
# New command: switch task/subtask immediately and regenerate.
|
# New command: switch task/subtask immediately and regenerate.
|
||||||
runtime.set_task(line)
|
runtime.set_task(line)
|
||||||
runtime.state["current_subtask"] = line if direct_subtask else None
|
runtime.state.set_context("subtask", line if direct_subtask else None)
|
||||||
_clear_action_queue(runtime)
|
_clear_action_queue(runtime)
|
||||||
adapter = getattr(runtime, "policy_adapter", None)
|
adapter = getattr(runtime, "policy_adapter", None)
|
||||||
if adapter is not None and hasattr(adapter, "_chunks_until_regen"):
|
if adapter is not None and hasattr(adapter, "_chunks_until_regen"):
|
||||||
@@ -1172,7 +1170,7 @@ def _run_repl(
|
|||||||
_redraw(last_logs)
|
_redraw(last_logs)
|
||||||
continue
|
continue
|
||||||
runtime.state["recent_interjection"] = line
|
runtime.state["recent_interjection"] = line
|
||||||
_emit(runtime.state, "user_interjection")
|
runtime.state.emit("user_interjection")
|
||||||
|
|
||||||
last_logs = runtime.step_once() or []
|
last_logs = runtime.step_once() or []
|
||||||
_redraw(last_logs)
|
_redraw(last_logs)
|
||||||
|
|||||||
@@ -42,14 +42,6 @@ class RuntimeState:
|
|||||||
action_deadline: float | None = None
|
action_deadline: float | None = None
|
||||||
extra: dict[str, Any] = field(default_factory=dict)
|
extra: dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
_ALIASES = {
|
|
||||||
"current_plan": ("language_context", "plan"),
|
|
||||||
"current_subtask": ("language_context", "subtask"),
|
|
||||||
"current_memory": ("language_context", "memory"),
|
|
||||||
"events_this_tick": ("events", None),
|
|
||||||
"_tick": ("tick", None),
|
|
||||||
}
|
|
||||||
|
|
||||||
def emit(self, event_name: str) -> None:
|
def emit(self, event_name: str) -> None:
|
||||||
self.events.add(event_name)
|
self.events.add(event_name)
|
||||||
|
|
||||||
@@ -88,11 +80,6 @@ class RuntimeState:
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
def __getitem__(self, key: str) -> Any:
|
def __getitem__(self, key: str) -> Any:
|
||||||
alias = self._ALIASES.get(key)
|
|
||||||
if alias is not None:
|
|
||||||
target, subkey = alias
|
|
||||||
value = getattr(self, target)
|
|
||||||
return value if subkey is None else value.get(subkey)
|
|
||||||
if hasattr(self, key):
|
if hasattr(self, key):
|
||||||
return getattr(self, key)
|
return getattr(self, key)
|
||||||
if key in self.extra:
|
if key in self.extra:
|
||||||
@@ -100,16 +87,6 @@ class RuntimeState:
|
|||||||
raise KeyError(key)
|
raise KeyError(key)
|
||||||
|
|
||||||
def __setitem__(self, key: str, value: Any) -> None:
|
def __setitem__(self, key: str, value: Any) -> None:
|
||||||
alias = self._ALIASES.get(key)
|
|
||||||
if alias is not None:
|
|
||||||
target, subkey = alias
|
|
||||||
if subkey is None:
|
|
||||||
setattr(self, target, value)
|
|
||||||
elif value is None:
|
|
||||||
getattr(self, target).pop(subkey, None)
|
|
||||||
else:
|
|
||||||
getattr(self, target)[subkey] = value
|
|
||||||
return
|
|
||||||
if hasattr(self, key):
|
if hasattr(self, key):
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
# Copyright 2026 The HuggingFace Inc. team. All rights reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
"""Small event helper shared by the language-runtime command loops."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
|
|
||||||
def _emit(state: Any, event_name: str) -> None:
|
|
||||||
if hasattr(state, "emit"):
|
|
||||||
state.emit(event_name)
|
|
||||||
else:
|
|
||||||
state.setdefault("events_this_tick", []).append(event_name)
|
|
||||||
@@ -211,7 +211,7 @@ class RoboCasaSimBackend:
|
|||||||
def bind_runtime(self, runtime: Any) -> None:
|
def bind_runtime(self, runtime: Any) -> None:
|
||||||
"""Wire live task/subtask/memory getters from the runtime state."""
|
"""Wire live task/subtask/memory getters from the runtime state."""
|
||||||
self._task_getter = lambda: runtime.state.get("task")
|
self._task_getter = lambda: runtime.state.get("task")
|
||||||
self._subtask_getter = lambda: runtime.state.get("current_subtask")
|
self._subtask_getter = lambda: runtime.state.language_context.get("subtask")
|
||||||
self._memory_getter = lambda: (runtime.state.get("language_context") or {}).get("memory")
|
self._memory_getter = lambda: (runtime.state.get("language_context") or {}).get("memory")
|
||||||
|
|
||||||
def _scene_description(self) -> str:
|
def _scene_description(self) -> str:
|
||||||
|
|||||||
@@ -505,13 +505,10 @@ def eval_policy(
|
|||||||
tasks = list(env.call("task"))
|
tasks = list(env.call("task"))
|
||||||
except (AttributeError, NotImplementedError):
|
except (AttributeError, NotImplementedError):
|
||||||
tasks = None
|
tasks = None
|
||||||
# Per-env subtasks when available (batched hierarchical policies);
|
|
||||||
# fall back to the scalar last_subtask for single-env / other policies.
|
|
||||||
subtasks = getattr(policy, "last_subtasks", None)
|
subtasks = getattr(policy, "last_subtasks", None)
|
||||||
subtask_scalar = getattr(policy, "last_subtask", None)
|
|
||||||
annotated = []
|
annotated = []
|
||||||
for i in range(frames.shape[0]):
|
for i in range(frames.shape[0]):
|
||||||
subtask_i = subtasks[i] if subtasks is not None and i < len(subtasks) else subtask_scalar
|
subtask_i = subtasks[i] if subtasks is not None and i < len(subtasks) else None
|
||||||
annotated.append(
|
annotated.append(
|
||||||
_annotate_eval_frames(
|
_annotate_eval_frames(
|
||||||
frames[i : i + 1],
|
frames[i : i + 1],
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# Copyright 2026 The HuggingFace Inc. team. All rights reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
"""Compatibility entry point for ``lerobot-language-runtime``.
|
|
||||||
|
|
||||||
New commands should use ``lerobot-rollout --language`` or ``--sim``.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv: list[str] | None = None) -> int:
|
|
||||||
from lerobot.runtime.cli import run
|
|
||||||
|
|
||||||
return run(argv)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
from lerobot.runtime import (
|
from lerobot.runtime import (
|
||||||
LanguageConditionedRuntime,
|
LanguageConditionedRuntime,
|
||||||
RuntimeState,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -70,12 +69,3 @@ def test_runtime_handles_user_interjection():
|
|||||||
|
|
||||||
assert "please say ok" in adapter.interjections
|
assert "please say ok" in adapter.interjections
|
||||||
assert runtime.state.language_context["plan"] == "new plan"
|
assert runtime.state.language_context["plan"] == "new plan"
|
||||||
|
|
||||||
|
|
||||||
def test_runtime_state_aliases_legacy_keys_to_language_context():
|
|
||||||
state = RuntimeState()
|
|
||||||
state["current_subtask"] = "open drawer"
|
|
||||||
state["current_memory"] = "drawer open"
|
|
||||||
|
|
||||||
assert state.get("current_subtask") == "open drawer"
|
|
||||||
assert state.language_context == {"subtask": "open drawer", "memory": "drawer open"}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user