mirror of
https://github.com/huggingface/lerobot.git
synced 2026-05-26 14:09:47 +00:00
fix(smolvla2-runtime): allow task switching mid-run via 'task:' prefix
Both stdin handlers (autonomous mode and rich REPL) gated 'task:' to 'only if no task is set yet' — once the initial task existed, typing 'task: <new task>' silently fell through to the interjection branch. Make 'task:' always override the active task and clear stale plan/memory/subtask so the next high-level pass regenerates context from scratch for the new task. For rephrasings within the same task, the interjection path (user_interjection_response recipe) is still the right channel — it refreshes the plan and emits a paired <say> in one trained call. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -776,8 +776,28 @@ def _run_autonomous(
|
|||||||
lower = line.lower()
|
lower = line.lower()
|
||||||
if lower in {"stop", "quit", "exit"}:
|
if lower in {"stop", "quit", "exit"}:
|
||||||
break
|
break
|
||||||
|
# ``task: <text>`` always overrides the active task — both
|
||||||
|
# at first set and to switch tasks mid-run. Without the
|
||||||
|
# prefix and with a task already set, an utterance becomes
|
||||||
|
# either a VQA query (ends in ``?``) or an interjection
|
||||||
|
# (the user_interjection_response recipe — generates a
|
||||||
|
# fresh plan + ``<say>`` paired with the new instruction).
|
||||||
|
# Typing a rephrasing of the current task as an
|
||||||
|
# interjection is the trained way to redirect without
|
||||||
|
# resetting the high-level plan from scratch.
|
||||||
|
if lower.startswith("task:"):
|
||||||
|
new_task = line[5:].strip()
|
||||||
|
if new_task:
|
||||||
|
runtime.set_task(new_task)
|
||||||
|
# Clear stale plan/memory/subtask so the next
|
||||||
|
# high-level pass regenerates from the new task
|
||||||
|
# rather than carrying over context from the old.
|
||||||
|
runtime.state["current_plan"] = None
|
||||||
|
runtime.state["current_memory"] = None
|
||||||
|
runtime.state["current_subtask"] = None
|
||||||
|
continue
|
||||||
if not runtime.state.get("task"):
|
if not runtime.state.get("task"):
|
||||||
runtime.set_task(line[5:].strip() if lower.startswith("task:") else line)
|
runtime.set_task(line)
|
||||||
continue
|
continue
|
||||||
if lower.endswith("?"):
|
if lower.endswith("?"):
|
||||||
runtime.state["recent_vqa_query"] = line
|
runtime.state["recent_vqa_query"] = line
|
||||||
@@ -1083,9 +1103,15 @@ def _run_repl(runtime: Any, *, initial_task: str | None, max_ticks: int | None)
|
|||||||
|
|
||||||
# Inject the user input as the right kind of event,
|
# Inject the user input as the right kind of event,
|
||||||
# then run a single pipeline tick to consume it.
|
# then run a single pipeline tick to consume it.
|
||||||
if not runtime.state.get("task"):
|
if lower.startswith("task:"):
|
||||||
task = line[5:].strip() if lower.startswith("task:") else line
|
new_task = line[5:].strip()
|
||||||
runtime.set_task(task)
|
if new_task:
|
||||||
|
runtime.set_task(new_task)
|
||||||
|
runtime.state["current_plan"] = None
|
||||||
|
runtime.state["current_memory"] = None
|
||||||
|
runtime.state["current_subtask"] = None
|
||||||
|
elif not runtime.state.get("task"):
|
||||||
|
runtime.set_task(line)
|
||||||
elif lower.endswith("?"):
|
elif lower.endswith("?"):
|
||||||
runtime.state["recent_vqa_query"] = line
|
runtime.state["recent_vqa_query"] = line
|
||||||
runtime.state.setdefault("events_this_tick", []).append(
|
runtime.state.setdefault("events_this_tick", []).append(
|
||||||
|
|||||||
Reference in New Issue
Block a user