[{'role': 'system', 'content': 'You are a helpful assistant that generates Python code to directly solve the task.'}, {'role': 'user', 'content': [{'type': 'text', 'text': '\nYou are controlling a Franka Emika Panda robot to assemble furniture: attach square_table_leg4 to\nsquare_table_top. The leg is threaded and screws into any one of the four holes on the tabletop.\n\nConventions:\n- All positions are XYZ metres in the ROBOT BASE frame. All quaternions are WXYZ.\n- The gripper points straight down at the table when its quaternion is (0, 1, 0, 0).\n- The table surface is at approximately z = 0. The parts start lying flat on it.\n- get_object_pose returns the pose of a part\'s geometric centre; with return_bbox_extent=True it\n also returns the part\'s size along the part\'s own axes.\n- get_holes(part) returns where each hole opens on the part\'s surface and the direction a leg\n screwed into it points.\n\nPhysical facts about the task:\n- The leg is threaded: it does not go in by being pushed. It has to stand along the hole axis with\n its threaded end at the hole and be turned about its own long axis while pressed against the\n hole. It is assembled once it is screwed all the way down, with its axes parallel to the\n tabletop\'s.\n- A part can slip in the fingers when it is moved or turned, so verify where things are with\n get_object_pose instead of assuming.\n- The wrist cannot turn indefinitely. To keep turning a part, release it, turn the empty gripper\n back, and grip it again.\n- Motions are blocking and the episode has a limited step budget.\n\nThe functions (APIs) below are already imported into the environment. If you want to use numpy,\nyou must import it explicitly.\nYou may write python comments for reasoning but write ONLY executable Python code, with no code fences.\n\nAPIs:\n\nget_object_pose(object_name: \'str\', return_bbox_extent: \'bool\' = False)\n Doc:\n Get the pose of a furniture part.\n \n Args:\n object_name: Part name, e.g. "square_table_top" or "square_table_leg4".\n return_bbox_extent: If True, also return the part\'s size.\n \n Returns:\n position: (3,) XYZ in metres, robot base frame -- the centre of the part\'s bounding box.\n quaternion_wxyz: (4,) WXYZ unit quaternion -- the orientation of the part\'s own axes.\n bbox_extent: only when return_bbox_extent is True -- (3,) full side lengths in metres\n along the part\'s OWN x, y, z axes (not the world axes), so a square table leg\n reads as (0.030, 0.0875, 0.030): 8.75 cm long along its own y axis with a 3 cm\n square cross-section. The part spans +/- half of each extent about the returned\n position, along the corresponding axis of the returned orientation.\n\nlist_parts() -> \'list[str]\'\n Doc:\n List the furniture parts present in the scene.\n \n Returns:\n List of part names accepted by get_object_pose / sample_grasp_pose / get_holes.\n\nget_holes(part_name: \'str\') -> \'list[tuple[np.ndarray, np.ndarray]]\'\n Doc:\n Get the holes on a part that other parts screw into.\n \n Design information (from the furniture\'s CAD): where each hole opens on the part\'s surface\n and the direction a part screwed into it extends away from the surface. Nothing about how\n deep the hole is or where a mounted part ends up -- that follows from the mounted part\'s\n own length.\n \n Args:\n part_name: The part with the holes, e.g. "square_table_top".\n \n Returns:\n List of (opening_position, axis): opening_position (3,) XYZ in metres, robot base\n frame, at the centre of the hole on the surface; axis (3,) unit vector in the robot\n base frame pointing out of the hole, i.e. along a seated leg from its threaded end\n toward its free end.\n\nsample_grasp_pose(object_name: \'str\') -> \'tuple[np.ndarray, np.ndarray]\'\n Doc:\n Get a top-down grasp pose for a furniture part.\n \n The gripper points down at the table with its fingers across the part\'s longest axis, at\n the part\'s centre (never below finger clearance above the table). The mirrored grasp --\n the same pose rotated 180 degrees about the gripper\'s approach axis -- is equally valid.\n \n Args:\n object_name: Part name.\n \n Returns:\n position: (3,) XYZ in metres, robot base frame, to pass straight to goto_pose.\n quaternion_wxyz: (4,) WXYZ unit quaternion for the gripper.\n\nget_ee_pose() -> \'tuple[np.ndarray, np.ndarray]\'\n Doc:\n Get the current end-effector pose (the point between the fingertips).\n \n Returns:\n position: (3,) XYZ in metres, robot base frame.\n quaternion_wxyz: (4,) WXYZ unit quaternion.\n\nget_joint_positions() -> \'np.ndarray\'\n Doc:\n Get the arm\'s current joint positions.\n \n Returns:\n (7,) joint angles in radians, joint 1 (base) to joint 7 (wrist). Joint limits are\n +/-2.90 for joints 1, 3, 5, 7; +/-1.76 for joint 2; [-3.07, -0.07] for joint 4;\n [-0.02, 3.75] for joint 6.\n\nis_reachable(position: \'np.ndarray\', quaternion_wxyz: \'np.ndarray\') -> \'bool\'\n Doc:\n Check whether the arm can place the end-effector at a pose.\n \n Solves inverse kinematics and verifies the solution actually reaches the pose within the\n arm\'s joint limits. Useful before committing to a grasp or a placement: a pose the arm\n cannot reach makes goto_pose stop short of it.\n \n Args:\n position: (3,) XYZ in metres, robot base frame.\n quaternion_wxyz: (4,) WXYZ unit quaternion.\n \n Returns:\n True if the pose is reachable.\n\ngoto_pose(position: \'np.ndarray\', quaternion_wxyz: \'np.ndarray\', z_approach: \'float\' = 0.0) -> \'None\'\n Doc:\n Move the end-effector to a pose using inverse kinematics. Blocking.\n \n Args:\n position: (3,) XYZ in metres, robot base frame.\n quaternion_wxyz: (4,) WXYZ unit quaternion.\n z_approach: If non-zero, first move to `z_approach` metres back along the gripper\'s\n approach axis (i.e. above the target for a downward-pointing gripper), then move\n to the target. Useful for grasps and insertions. There is no need to call\n goto_pose a second time with the same target afterwards.\n\nopen_gripper() -> \'None\'\n Doc:\n Open the gripper. Blocking.\n\nclose_gripper() -> \'None\'\n Doc:\n Close the gripper to grasp. Blocking.\n\nhome_pose() -> \'None\'\n Doc:\n Move the arm back to its home joint configuration. Blocking.'}]}]