mirror of
https://github.com/huggingface/lerobot.git
synced 2026-05-22 20:19:43 +00:00
fix(smolvla2): always show the startup task picker on a TTY
The picker was skipped whenever a task was already resolved — which is always the case with --dataset.repo_id, since the dataset's canonical task is auto-filled. The operator never got to choose. Now the picker always runs on an interactive terminal: the resolved task is shown as "(current)" and selected by an empty Enter, so the dataset-canonical default still works while letting the operator pick another task or type a custom one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -918,33 +918,38 @@ def _dataset_task_strings(ds_meta: Any) -> list[str]:
|
|||||||
def _select_task_interactively(ds_meta: Any, current_task: str | None) -> str | None:
|
def _select_task_interactively(ds_meta: Any, current_task: str | None) -> str | None:
|
||||||
"""Prompt the operator to pick a task from the dataset or type one.
|
"""Prompt the operator to pick a task from the dataset or type one.
|
||||||
|
|
||||||
Called at startup when no ``--task`` was given. Non-TTY / scripted
|
Called at startup. ``current_task`` is whatever was already resolved
|
||||||
runs return ``current_task`` unchanged so the existing
|
(``--task`` or the dataset's canonical task); it becomes the default
|
||||||
"first stdin line becomes the task" behaviour is preserved.
|
that an empty ``Enter`` selects, and is marked ``(current)`` in the
|
||||||
|
menu. Non-TTY / scripted runs return ``current_task`` unchanged so
|
||||||
|
the existing "first stdin line becomes the task" behaviour is kept.
|
||||||
"""
|
"""
|
||||||
if current_task:
|
|
||||||
return current_task
|
|
||||||
if not sys.stdin.isatty():
|
if not sys.stdin.isatty():
|
||||||
return current_task
|
return current_task
|
||||||
|
|
||||||
tasks = _dataset_task_strings(ds_meta)
|
tasks = _dataset_task_strings(ds_meta)
|
||||||
if not tasks:
|
if not tasks:
|
||||||
|
prompt = "[smolvla2] Enter the task"
|
||||||
|
if current_task:
|
||||||
|
prompt += f" [Enter = {current_task!r}]"
|
||||||
try:
|
try:
|
||||||
typed = input("[smolvla2] Enter the task: ").strip()
|
typed = input(prompt + ": ").strip()
|
||||||
except (EOFError, KeyboardInterrupt):
|
except (EOFError, KeyboardInterrupt):
|
||||||
return current_task
|
return current_task
|
||||||
return typed or current_task
|
return typed or current_task
|
||||||
|
|
||||||
print("[smolvla2] Select a task:", flush=True)
|
print("[smolvla2] Select a task:", flush=True)
|
||||||
for i, task in enumerate(tasks, 1):
|
for i, task in enumerate(tasks, 1):
|
||||||
print(f" [{i}] {task}", flush=True)
|
marker = " (current)" if task == current_task else ""
|
||||||
|
print(f" [{i}] {task}{marker}", flush=True)
|
||||||
print(" [c] type a custom task", flush=True)
|
print(" [c] type a custom task", flush=True)
|
||||||
|
hint = " (Enter = current)" if current_task else ""
|
||||||
try:
|
try:
|
||||||
raw = input("task> ").strip()
|
raw = input(f"task>{hint} ").strip()
|
||||||
except (EOFError, KeyboardInterrupt):
|
except (EOFError, KeyboardInterrupt):
|
||||||
return current_task
|
return current_task
|
||||||
if not raw:
|
if not raw:
|
||||||
return tasks[0]
|
return current_task or tasks[0]
|
||||||
if raw.lower() in {"c", "custom"}:
|
if raw.lower() in {"c", "custom"}:
|
||||||
try:
|
try:
|
||||||
return input("[smolvla2] Enter the task: ").strip() or current_task
|
return input("[smolvla2] Enter the task: ").strip() or current_task
|
||||||
@@ -954,8 +959,8 @@ def _select_task_interactively(ds_meta: Any, current_task: str | None) -> str |
|
|||||||
idx = int(raw) - 1
|
idx = int(raw) - 1
|
||||||
if 0 <= idx < len(tasks):
|
if 0 <= idx < len(tasks):
|
||||||
return tasks[idx]
|
return tasks[idx]
|
||||||
print("[smolvla2] invalid choice — using the first task", flush=True)
|
print("[smolvla2] invalid choice — keeping the current task", flush=True)
|
||||||
return tasks[0]
|
return current_task or tasks[0]
|
||||||
# Treat anything else as a custom task string typed directly.
|
# Treat anything else as a custom task string typed directly.
|
||||||
return raw
|
return raw
|
||||||
|
|
||||||
@@ -1398,11 +1403,11 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
flush=True,
|
flush=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# No task yet (no --task, no canonical dataset task) — let the
|
# Always offer the startup task picker on an interactive terminal:
|
||||||
# operator pick one from the dataset's task list or type a custom
|
# list the dataset's tasks (the canonical / --task one shown as the
|
||||||
# one. Non-TTY runs keep the "first stdin line is the task" path.
|
# default) so the operator can pick another or type a custom task.
|
||||||
if not args.task:
|
# Non-TTY runs keep the "first stdin line is the task" path.
|
||||||
args.task = _select_task_interactively(ds_meta, args.task)
|
args.task = _select_task_interactively(ds_meta, args.task)
|
||||||
|
|
||||||
observation_provider: Callable[[], dict | None] | None = None
|
observation_provider: Callable[[], dict | None] | None = None
|
||||||
robot_executor: Callable[[Any], None] | None = None
|
robot_executor: Callable[[Any], None] | None = None
|
||||||
|
|||||||
Reference in New Issue
Block a user