diff --git a/frontend/src/components/landing/InferenceModal.test.tsx b/frontend/src/components/landing/InferenceModal.test.tsx index a8ad8a242..313cbb2a2 100644 --- a/frontend/src/components/landing/InferenceModal.test.tsx +++ b/frontend/src/components/landing/InferenceModal.test.tsx @@ -90,6 +90,18 @@ test("an unsaved camera permits a manual rotation with a training-data reminder" expect(request.cameras.wrist).toMatchObject({ camera_index: 3, rotation: 90, width: 640, height: 480 }); }); +test("the plugin package note shows only for a policy type LeRobot does not register", async () => { + await render(); + expect(container.textContent).not.toContain("plugin policy"); + act(() => root.unmount()); root = createRoot(container); + const builtin = mocks.fetcher.getMockImplementation()!; + mocks.fetcher.mockImplementation(async (url: string, init?: RequestInit) => url.endsWith("/policy-config") + ? new Response(JSON.stringify({ policy_type: "my_plugin", requires_task: true, image_features: {} })) + : builtin(url, init)); + await render(); + expect(container.textContent).toContain("This is a plugin policy"); +}); + test("an invalid saved rotation blocks inference and gives a visible correction instruction", async () => { await render({ ...robot, cameras: [{ ...robot.cameras[0], rotation: 45 as never }] }); expect(container.textContent).toContain("Correct the camera settings in Calibration"); diff --git a/frontend/src/components/landing/InferenceModal.tsx b/frontend/src/components/landing/InferenceModal.tsx index c537c5a1f..d7b3ad031 100644 --- a/frontend/src/components/landing/InferenceModal.tsx +++ b/frontend/src/components/landing/InferenceModal.tsx @@ -37,6 +37,28 @@ interface Props { } const DEFAULT_FPS = 30; +// Policy types LeRobot (v0.6.1) registers itself; any other type comes from a plugin package. +const BUILTIN_POLICY_TYPES = new Set([ + "act", + "diffusion", + "eo1", + "evo1", + "fastwam", + "gaussian_actor", + "groot", + "lingbot_va", + "molmoact2", + "multi_task_dit", + "pi0", + "pi05", + "pi0_fast", + "smolvla", + "tdmpc", + "vla_jepa", + "vqbet", + "wall_x", + "xvla", +]); const InferenceModal: React.FC = ({ open, @@ -176,6 +198,12 @@ const InferenceModal: React.FC = ({ Pick a checkpoint and confirm hardware. The selected policy will drive the follower autonomously for the configured duration. + {policyConfig && !BUILTIN_POLICY_TYPES.has(policyConfig.policy_type ?? "") && ( +

+ This is a plugin policy: its package must be installed alongside + lelab, or the run will fail to load the policy. +

+ )}