Experiment dashboard · 2026-07-15

LIBERO Task Results

公开审阅版:任务结果、视觉证据、真实 API prompt/code 与逐案因果审计。

已执行任务5
成功0
失败5

Cross-case diagnosis

五案例 Failure Mode Analysis

按“最早不可逆物理偏差”归因;后续空夹放置、错误 RESULT 和未执行到的参数只记为传播或 latent risk。

trace audit · n=5
直接回答

不是单一模型的问题:GPT 代码与 grasp/control 接口共同占主导;“纯 magic number”与 gross detector miss 都不是总体解释。

三个 pick/lift 链路的近端失败集中在 Contact-GraspNet 单候选、TCP/approach 与缺少持物观测;microwave+mug 则是可证明的 GPT 轨迹符号错误;drawer 同时包含 wrong-handle point 与零 grasp candidate。

79%A + D 合计权重
0 / 5仅靠 magic number 可解释
1 / 5有直接 wrong-part 感知证据
Weighted view

五案平均工程权重

A · GPT 代码
42%
D · 抓取/接口
37%
B · 仿真/TCP 标定
11%
C · SAM3/Molmo
10%

算术平均来自下方 5 个 trace-level 矩阵;用于排查优先级,不代表总体成功率或统计置信区间。

TaskA · codeB · calibrationC · perceptionD · grasp/APIconf.
README play config · microwave + milk38%27%5%30%0.82
Put moka pot on stove · turn stove on30%5%10%55%0.88
Open microwave · put porcelain mug inside65%5%5%25%0.93
Open top drawer · put cookies inside40%5%25%30%0.86
Put milk on plate35%15%5%45%0.78
A · GPT-5.5 code坐标/顺序/参数错误;无 post-condition gate;失败后仍继续。
B · LIBERO calibration同一正确动作存在稳定数值残差,offset sweep 才能确认。
C · SAM3 / Molmopoint/mask/3-D center 在动作前已经落错对象或部位。
D · grasp / APImask 可用但 candidate、3-D 对齐、TCP/control 或可观测性失败。
强证据代码问题

microwave+mug 的 Y 轨迹符号与资产铰链几何相反;所有 5 案都把 API 返回等同物理成功,缺少真实状态 gate。

强证据抓取/接口问题

milk×2、moka、mug 都到达正确邻域后空抓;cookies 对非空 segment 明确返回 zero candidates。

局部证据上游感知

drawer 的 top-handle Molmo 点落在下部把手附近。其他 4 案的点与运动目标均基本正确,未见 gross miss。

尚未证实magic number

门阈值和倾斜 local-axis approach 可能需要标定,但没有任何 case 证明只改常数即可稳定成功。

Candidate selection只取一个 argmaxbest_idx = grasp_scores.argmax()

没有 top-k retry、部位语义或 box/cylinder 的规则 grasp;实现注释反而建议规则物体使用 top-down OBB helper。

Frame conventionoffset 与 approach 都随姿态旋转+0.12 grasp TF · local TCP −0.10

z_approach 也沿 grasp local axis,不是 prompt 容易理解的 world +Z;倾斜姿态会把“抬高”变成明显横移。

3-D fusionmask-depth 尺寸不符时直接截断pts[:min_len][mask[:min_len]]

这会破坏像素与深度对应;多视角只要任意一对点距离 <1 cm 就 union,也可能混入坏 wrist cloud。

ObservabilityPolicy 看不到物理结果no is_grasped · no qpos/open state

可用 API 没有夹爪宽度、接触、持物或铰接关节状态;两项 learned skills 也未暴露在 Policy Writer prompt 中,usage=0。

系统性根因Policy Writer 只能得到单个 argmax grasp,没有 top-k/score、gripper width、is_grasped、关节 open state 或动作特定 grasp helper;因此 GPT 很难闭环纠错。与此同时,它仍生成 176–287 个非空行并无条件自报成功。这是模型代码与工具契约的耦合失败。
证据边界与如何把归因升级为受控结论
当前可以说

逐帧视频、native predicates、真实 prompt/code、Molmo 点、grasp pose、traceback 与 LIBERO asset 几何多源一致。

当前不能说

raw SAM masks、top-k grasps、actual TCP、gripper contact 未保存,D 与 B 的精确比例仍不能从单条 trace 唯一识别。

最小 ablation

oracle mask;oracle/规则 grasp;同一 candidate TCP sweep;仅修 policy gate/trajectory。每组同 seed 重放 3 次并记录 object pose、qpos、gripper width。

任务执行失败Door threshold + milk grasp

README play config · microwave + milk

repro_readme_nonpriv_hf

FAIL
最终判定门发生明显运动但 native Open=false;milk 随后空抓,最终严格谓词 0/2。
失败阶段Door threshold + milk grasp

Causal trace audit

Failure Mode Analysis

confidence 0.82
判定双重失败:门发生运动但未跨过 Open 阈值;随后 milk 又独立空抓。
最早失效点Step 4 · microwave door only partially opened; native Open(microwave)=false
近端物理原因

固定世界坐标拉门轨迹不足以满足铰链阈值;milk 的单一 grasp candidate 随后没有形成承重夹持。

传播原因

代码在两个动作后都无条件写 success,没有检查门关节状态、milk 是否随抬升移动,继续空夹放置。

AGPT-5.5 代码 / 状态机38%

硬编码门弧;动作返回即判成功;门/抓取均无 post-condition gate。

BLIBERO / TCP 标定27%

门的铰链阈值与弧线需要几何标定;但这不是“代码完全正确、只差一个数”。

CMolmo / SAM3 感知5%

Molmo 离线是混杂项;现有运动证据不支持 SAM3 把对象认错。

D抓取 / 3-D / 控制接口30%

milk 候选位置合理但抓取失稳;top-k、夹爪接触与实际 TCP 都未暴露。

决定性证据
  1. 504 帧完整轨迹:frames 86–216 门确实运动,但 native Open=false;LIBERO 的 is_open 阈值为 qpos < -1.3 rad(约 74.5°)。
  2. frames 246–357:夹爪到达 milk 附近并抬升,milk 始终留在桌面。grasp position=[0.8885,-0.0424,0.0985] 与目标区域一致。
  3. 该轮 Molmo 服务离线,但 SAM3 text fallback 仍把机器人引到 handle 与 milk 附近,因此不能把失败解释为 gross detector miss。
仍不能确认

没有保存 SAM mask、top-k grasp、实际 TCP 和 microwave qpos 曲线,故 milk 的 Contact-GraspNet 与 TCP 残差、门弧与接触滑脱仍无法完全拆开。

最小反事实实验

固定感知后读取 qpos 并闭环拉门;对同一 milk mask 比较 top-down/宽侧 oracle grasp 与当前 argmax,再做 ±1–3 cm TCP sweep。

责任百分比用于表达该条 trace 的工程因果权重,不是统计概率;没有受控重放的结论标为 strongly supported,而非 confirmed。

01

Task setting

Kitchen tabletop; microwave starts closed; milk carton starts upright on the table. Goal predicates: Open(microwave) AND In(milk, microwave_heating_region).

02

失败根因

双重失败:门发生运动但未跨过 Open 阈值;随后 milk 又独立空抓。

Evidence

视觉证据

iter001_attempt0_failed.mp4
Why

证据与推理

  1. 504 帧完整执行:门有明显运动,但没有跨过 LIBERO 的 Open 阈值。
  2. milk 抓取是第二个独立失败:闭爪/抬升后 milk 仍在初始桌面位置。
  3. 两个动作都被代码无条件记为 success,最终 native predicates 为 0/2。
03

真实 API 审计

model=gpt-5.5 · elapsed=22.3s · finish_reason=stop · source: 0005_p506268_policy_writer._generate_once.json

发送给 Policy Writer 的完整 prompt
===== SYSTEM =====
You are a deterministic policy writer for a code-as-policy robot system. Write ONLY Python code. Do not use while True loops. Use only the provided imported primitive functions and learned helper functions.

===== USER =====
You are a deterministic policy writer for a code-as-policy robot system.

Write Python code that executes the following plan.

AVAILABLE IMPORTED FUNCTIONS (use ONLY these, not env.<method>):
close_gripper, get_object_3d_points_and_masks_from_language, get_object_pose, get_observation, get_oriented_bounding_box_from_3d_points, goto_home_joint_position, goto_pose, open_gripper, sample_grasp_pose

API DOCUMENTATION:
get_observation() -> dict[str, typing.Any]
  Doc:
    Get the observation of the environment.
    Returns:
        observation:
            A dictionary containing the observation of the environment.
            The dictionary contains the following keys:
            - ["agentview"]["images"]["rgb"]: Current color camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["agentview"]["images"]["depth"]: Current depth camera image as a numpy array of shape (H, W), dtype float32.
            - ["agentview"]["intrinsics"]: Camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["agentview"]["pose_mat"]: Camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot0_eye_in_hand"]["images"]["rgb"]: Current wrist camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["robot0_eye_in_hand"]["images"]["depth"]: Current wrist camera depth image as a numpy array of shape (H, W), dtype float32.
            - ["robot0_eye_in_hand"]["intrinsics"]: Wrist camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["robot0_eye_in_hand"]["pose_mat"]: Wrist camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot_cartesian_pos"]: Current end-effector (panda_hand) pose in the robot/world frame as a numpy array of shape (8,), dtype float64. The first 3 elements are the robot's end-effector XYZ, the next 4 elements are the quaternion wxyz, and the last element is the gripper position normalized, 0 (closed) to 1 (open).
            - ["robot_joint_pos"]: Current joint positions as a numpy array of shape (7,), dtype float64. The last element is the gripper position normalized, 0 (closed) to 1 (open).

get_object_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray] | tuple[None, None]
  Doc:
    Get the pose of an object in the environment from a natural language description.
    The quaternion from get_object_pose may be unreliable, so disregard it and use the grasp
    pose quaternion OR (0, 0, 1, 0) wxyz as the gripper down orientation if using this for
    placement position.
    It is possible that get_object_pose is sometimes unreliable and will return None for both
    position and quaternion.
    
    Args:
        object_name: The name of the object to get the pose of, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

sample_grasp_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray]
  Doc:
    Sample a grasp pose for an object in the environment from a natural language description.
    Uses multiview point clouds and plan_grasp_from_point_clouds for more reliable grasp planning.
    Do use the grasp sample quaternion from sample_grasp_pose.
    
    Args:
        object_name: The name of the object to sample a grasp pose for, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

goto_pose(position: numpy.ndarray, quaternion_wxyz: numpy.ndarray, z_approach: float = 0.0) -> None
  Doc:
    Go to pose using Inverse Kinematics.
    There is no need to call a second goto_pose with the same position and quaternion_wxyz after calling it with z_approach.
    Args:
        position: (3,) XYZ in meters.
        quaternion_wxyz: (4,) WXYZ unit quaternion.
        z_approach: (float) Z-axis distance offset for goto_pose insertion approach motion. Will first arrive at position + z_approach meters in Z-axis before moving to the requested pose. Useful for more precise grasp approaches. Default is 0.0.
    Returns:
        None

open_gripper() -> None
  Doc:
    Open gripper fully.
    
    Args:
        None

close_gripper() -> None
  Doc:
    Close gripper fully.
    
    Args:
        None

get_oriented_bounding_box_from_3d_points(points: numpy.ndarray) -> dict[str, typing.Any]
  Doc:
    Get the oriented bounding box from 3D points.
    
    Args:
        points: np.ndarray: The 3D points to get the oriented bounding box from.
            Shape: (N, 3), dtype float64.
    
    Returns:
        dict[str, Any]: The oriented bounding box. The dictionary contains the following keys:
            - "center": np.ndarray: The center of the oriented bounding box in point cloud frame.
            - "extent": np.ndarray: The extent of the oriented bounding box.
            - "R": np.ndarray: The rotation matrix of the oriented bounding box in point cloud frame.
    
    Example:
        >>> points = np.random.randn((100, 3))
        >>> obb = get_oriented_bounding_box_from_3d_points(points)

get_object_3d_points_and_masks_from_language(text_prompt: str, use_multiview: bool = True) -> dict[str, typing.Any]
  Doc:
    Segment an object using text prompt across multiple views (agentview and wrist).
    
    Uses Molmo to locate the object in both camera views, then SAM3 for
    segmentation. Returns the masks and 3D points that appear in both views.
    
    Args:
        text_prompt: Text description of the object to segment.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation.
        
    Returns:
        dict containing:
            - "agentview_mask": np.ndarray of shape (H, W), dtype bool
            - "wrist_mask": np.ndarray of shape (H, W), dtype bool (None if single view)
            - "points_3d": np.ndarray of shape (N, 3), 3D points in world frame
            - "agentview_score": float, SAM3 confidence score
            - "wrist_score": float, SAM3 confidence score (None if single view)

goto_home_joint_position() -> None
  Doc:
    Return the arm to its reset joint configuration with high manipulability

LEARNED HELPER FUNCTION REFERENCES (already defined and callable — use them directly):
No learned helper functions available yet.

REQUIREMENTS:
- Use the primitive functions listed in AVAILABLE IMPORTED FUNCTIONS above AND any LEARNED HELPER FUNCTION REFERENCES shown above.
- The learned helper functions are pre-defined and available in your execution scope. Call them directly.
- Do NOT invent wrapper functions on env or low_level_env.
- Do NOT use while True loops or any unbounded retry patterns. Use bounded for loops instead.
- Set RESULT to a structured dict describing success/failure for each step.
- Add explicit comments before each plan step.
- Wrap the executable body for EACH plan step in the runtime marker context
  `with step_context("<step id>", "<step description>", step_index=<0-based index>):`.
  This is a logging marker, not a robot primitive. It lets the verifier save
  exact per-step API traces, motion frame ranges, and intermediate artifacts.
- Define reusable sub-functions for non-trivial skill sequences that could be added to the skill library.
- On retries, follow the diagnoser's requested edit scale. If a top-of-retry "## EDIT SCALE: argument-level" banner is present (or the prose says argument-level), keep the same primitive/helper call sequence and change only the named arguments first (target text, verify_label, pose/offset, approach axis, release height, retry count, or gate threshold). Rewrite helper bodies, replace primitives, or add new wrappers only when the banner / diagnosis says rewrite-needed because arguments cannot express the fix, the API/function is wrong for the task, the sequence is structurally wrong, or there is a real code/logic bug.


IMPORTANT: Use ONLY functions from the AVAILABLE IMPORTED FUNCTIONS list and LEARNED HELPER FUNCTION REFERENCES above.
Do NOT call any function not in those lists. Check the API DOCUMENTATION for correct function signatures.
Extract object names from the GOAL description below.

General rules:
- Read the API DOCUMENTATION carefully for the correct function signatures and return types.
- When retry feedback names a primitive/helper call, preserve that call and tune its arguments before changing the overall code structure, unless the feedback explicitly calls for a larger rewrite.
- For pick-and-place: perceive object location, move to grasp pose, close gripper, move to target, open gripper. Use the available perception functions to locate objects.
- Use bounded for loops (not while True) for retry patterns.
- For multi-step tasks (pick A then place on B), chain the patterns sequentially.
- Never leave a successfully grasped object suspended because a pre-release wrist check failed. Once the placement target has been localized, execute a cautious descend, open the gripper, retreat, and then verify the final resting state.
- NumPy array truthiness: localization primitives often return ndarrays or lists of candidates. NEVER write `if pos:` or `if not result:` on an ndarray — raises "truth value of an array is ambiguous". Instead use `if pos is None` / `if len(pos) == 0` / `if result.get("verified")` on explicit scalars. This pattern has burned many past attempts.



# === TASK-SPECIFIC INPUTS BELOW (vary per attempt; everything above is stable for cache reuse) ===

SCENE: i_want_to_open_the_microwave_and_put_the_milk_inside_it
GOAL: I want to open the microwave and put the milk inside it.
OBJECT SCOPE: {}

PLAN:
- step-1: Get an updated observation and confirm the scene: the microwave is on the right side of the table with its door closed, the vertical handle is visible on the front-left edge of the microwave door, and the milk carton is upright near the center-front area of the table. | skills: get_observation | notes: Use the agent-view image to verify the microwave door state before planning the opening motion. The milk appears unobstructed and graspable.
- step-2: Localize the microwave handle and estimate the microwave door/face geometry for grasping and opening. | skills: get_object_pose, get_object_3d_points_and_masks_from_language, get_oriented_bounding_box_from_3d_points | notes: Segment/localize the microwave handle using a prompt such as 'microwave handle' or 'vertical handle on microwave door'. If handle pose is unreliable, segment the microwave door/handle region and use the visible vertical handle on the left/front edge of the microwave as the grasp target.
- step-3: Open the gripper, move to a pre-grasp pose in front of the microwave handle, then grasp the handle. | skills: open_gripper, sample_grasp_pose, goto_pose, close_gripper | notes: (a) APPROACH DIRECTION: approach from the front of the microwave, perpendicular to the door face, targeting the exposed vertical handle; avoid approaching from above because the gripper may collide with the microwave top or door edge. (b) PULL/PUSH DIRECTION: after grasping, pull the handle outward away from the microwave body and slightly leftward following the door hinge arc, since the visible handle is on the left/front edge and the door should swing open outward. (c) GRASP SELECTION CRITERION: select a grasp whose approach axis is roughly perpendicular to the microwave front face and whose fingers can wrap around the vertical handle from the front, with the gripper aligned to clamp the handle thickness rather than pinching the flat door surface.
- step-4: Pull the microwave door open by moving the grasped handle outward and leftward along a short arc, then release the handle once the door is sufficiently open. | skills: goto_pose, open_gripper | notes: A dedicated articulated-opening skill would improve reliability by maintaining a compliant grasp and following the hinge arc. Use a conservative motion: pull outward from the microwave face, then continue leftward/outward until the interior opening is exposed enough to place the milk. Keep clearance from the table and microwave body.
- step-5: Move the arm away from the opened microwave door area and get a fresh observation to verify that the microwave is open and the interior cavity is reachable. | skills: goto_home_joint_position, get_observation | notes: This prevents collision with the open door and confirms the prerequisite state before picking the milk.
- step-6: Localize the milk carton on the table and sample a stable grasp pose. | skills: get_object_pose, sample_grasp_pose | notes: The milk carton is visible upright near the center-front of the table. Use multiview perception for grasp sampling if available. Prefer a side grasp around the carton body that keeps the carton upright.
- step-7: Pick up the milk carton from the table. | skills: open_gripper, goto_pose, close_gripper | notes: Approach the sampled grasp pose from above with a small z_approach, close the gripper on the carton, then lift vertically to clear the table.
- step-8: Localize the open microwave interior and compute a placement pose inside the cavity. | skills: get_object_pose, get_object_3d_points_and_masks_from_language, get_oriented_bounding_box_from_3d_points | notes: Use prompts such as 'open microwave interior', 'inside of microwave', or 'microwave cavity'. The placement point should be centered inside the open cavity, above the microwave floor, with enough clearance from the open door and front lip.
- step-9: Move the milk into the open microwave and place it on the microwave floor. | skills: goto_pose, open_gripper | notes: A dedicated place-inside-container skill would help handle the tight opening and avoid collisions. Use a gripper-down or upright-preserving orientation, insert through the open front of the microwave, lower to the interior floor, release the milk, and retreat outward along the same approach path.
- step-10: Retract the arm to a safe pose and verify that the milk is inside the open microwave. | skills: goto_home_joint_position, get_observation | notes: Final verification should check that the milk is no longer on the table and is visible or plausibly placed inside the microwave cavity. The goal only requires opening the microwave and putting the milk inside; it does not require closing the microwave.





## LESSONS FROM PAST FAILURES (advisory — NOT ground truth)

The block above (if non-empty) lists distilled lessons in "WHEN ... | WRONG ... | DO ..." form, each followed by a metadata footer like `(confidence=0.80, applied=5× helped=1×, last_helped=iter4 (2 iters ago), distilled=iter2 (4 iters ago))`. Use that footer to weigh how much to trust each lesson.

PRIORITY ORDER when signals conflict:
  0. The SUB-AGENT DIRECTIVE block above (if non-empty) — this is the parallel sub-agent's committed approach assignment, a HARD constraint, and dominates every other guidance source below.
  1. The current attempt's RETRY CONTEXT (diagnoser feedback + visual evidence + PREVIOUS CODE below) — this saw what actually happened on this exact task and is ground truth for what to fix.
  2. A lesson with high reliability (helped/applied ≥ 0.5 with applied ≥ 2) AND recent `last_helped` (≤ 2 iters ago) — strong prior, follow its DO recipe.
  3. A lesson with low reliability (helped/applied < 0.3) OR stale (`last_helped=never` or ≥ 5 iters ago) — background prior only; don't let it override the current diagnosis.

Empty block means no relevant prior failures.

API 返回并实际执行的 robot control code
RESULT = {
    "step-1": {"success": False, "details": ""},
    "step-2": {"success": False, "details": ""},
    "step-3": {"success": False, "details": ""},
    "step-4": {"success": False, "details": ""},
    "step-5": {"success": False, "details": ""},
    "step-6": {"success": False, "details": ""},
    "step-7": {"success": False, "details": ""},
    "step-8": {"success": False, "details": ""},
    "step-9": {"success": False, "details": ""},
    "step-10": {"success": False, "details": ""},
    "overall_success": False,
}


def make_offset_pose(position, dx=0.0, dy=0.0, dz=0.0):
    new_position = position.copy()
    new_position[0] = new_position[0] + dx
    new_position[1] = new_position[1] + dy
    new_position[2] = new_position[2] + dz
    return new_position


def safe_localize_object(object_name, use_multiview=True, attempts=2):
    found_position = None
    found_quaternion = None
    for _ in range(attempts):
        position, quaternion = get_object_pose(object_name, use_multiview=use_multiview)
        if position is not None:
            found_position = position
            found_quaternion = quaternion
            break
    return found_position, found_quaternion


def safe_segment_obb(text_prompt, use_multiview=True, attempts=2):
    segmented = None
    obb = None
    for _ in range(attempts):
        segmented_candidate = get_object_3d_points_and_masks_from_language(text_prompt, use_multiview=use_multiview)
        points = segmented_candidate.get("points_3d")
        if points is not None and len(points) > 0:
            segmented = segmented_candidate
            obb = get_oriented_bounding_box_from_3d_points(points)
            break
    return segmented, obb


def sample_grasp_with_retries(object_name, use_multiview=True, attempts=2):
    grasp_position = None
    grasp_quaternion = None
    for _ in range(attempts):
        grasp_position, grasp_quaternion = sample_grasp_pose(object_name, use_multiview=use_multiview)
        if grasp_position is not None and grasp_quaternion is not None:
            break
    return grasp_position, grasp_quaternion


def pick_object_from_sampled_grasp(object_name, z_approach=0.08, lift_height=0.16):
    grasp_position, grasp_quaternion = sample_grasp_with_retries(object_name, use_multiview=True, attempts=2)
    if grasp_position is None or grasp_quaternion is None:
        return False, None, None
    open_gripper()
    goto_pose(grasp_position, grasp_quaternion, z_approach=z_approach)
    close_gripper()
    lifted_position = make_offset_pose(grasp_position, dz=lift_height)
    goto_pose(lifted_position, grasp_quaternion, z_approach=0.0)
    return True, lifted_position, grasp_quaternion


# step-1: Get an updated observation and confirm the scene.
with step_context("step-1", "Get updated observation and confirm microwave and milk scene", step_index=0):
    observation_initial = get_observation()
    RESULT["step-1"]["success"] = observation_initial is not None
    RESULT["step-1"]["details"] = "Updated observation acquired for microwave door, handle, and milk carton scene."

# step-2: Localize the microwave handle and estimate the microwave door/face geometry.
with step_context("step-2", "Localize microwave handle and estimate handle geometry", step_index=1):
    handle_position, handle_quaternion_from_pose = safe_localize_object("microwave_handle", use_multiview=True, attempts=2)
    handle_segment, handle_obb = safe_segment_obb("vertical handle on microwave door", use_multiview=True, attempts=2)
    if handle_position is None and handle_obb is not None:
        handle_position = handle_obb["center"]
    RESULT["step-2"]["success"] = handle_position is not None
    RESULT["step-2"]["details"] = "Microwave handle localized using pose and/or segmented oriented bounding box."

# step-3: Open the gripper, move to a pre-grasp pose in front of the microwave handle, then grasp the handle.
with step_context("step-3", "Approach and grasp microwave handle from the front", step_index=2):
    handle_grasp_position, handle_grasp_quaternion = sample_grasp_with_retries("microwave_handle", use_multiview=True, attempts=2)
    if handle_grasp_position is None or handle_grasp_quaternion is None:
        handle_grasp_position, handle_grasp_quaternion = sample_grasp_with_retries("vertical_handle_on_microwave_door", use_multiview=True, attempts=1)
    if handle_grasp_position is None and handle_position is not None:
        handle_grasp_position = handle_position
        handle_grasp_quaternion = (0.0, 0.0, 1.0, 0.0)
    if handle_grasp_position is not None and handle_grasp_quaternion is not None:
        open_gripper()
        goto_pose(handle_grasp_position, handle_grasp_quaternion, z_approach=0.10)
        close_gripper()
        RESULT["step-3"]["success"] = True
        RESULT["step-3"]["details"] = "Gripper closed on microwave handle."
    else:
        RESULT["step-3"]["details"] = "Failed to obtain a usable microwave handle grasp pose."

# step-4: Pull the microwave door open by moving the grasped handle outward and leftward along a short arc, then release.
with step_context("step-4", "Pull microwave door outward and leftward, then release handle", step_index=3):
    if RESULT["step-3"]["success"]:
        pull_pose_1 = make_offset_pose(handle_grasp_position, dx=-0.10, dy=0.00, dz=0.00)
        pull_pose_2 = make_offset_pose(handle_grasp_position, dx=-0.16, dy=0.10, dz=0.00)
        pull_pose_3 = make_offset_pose(handle_grasp_position, dx=-0.20, dy=0.16, dz=0.00)
        goto_pose(pull_pose_1, handle_grasp_quaternion, z_approach=0.0)
        goto_pose(pull_pose_2, handle_grasp_quaternion, z_approach=0.0)
        goto_pose(pull_pose_3, handle_grasp_quaternion, z_approach=0.0)
        open_gripper()
        retreat_from_handle = make_offset_pose(pull_pose_3, dx=-0.04, dy=0.04, dz=0.08)
        goto_pose(retreat_from_handle, handle_grasp_quaternion, z_approach=0.0)
        RESULT["step-4"]["success"] = True
        RESULT["step-4"]["details"] = "Microwave handle pulled outward/leftward and released."
    else:
        RESULT["step-4"]["details"] = "Skipped opening motion because handle grasp failed."

# step-5: Move the arm away from opened microwave door area and get a fresh observation.
with step_context("step-5", "Return home and observe opened microwave", step_index=4):
    goto_home_joint_position()
    observation_after_open = get_observation()
    RESULT["step-5"]["success"] = observation_after_open is not None
    RESULT["step-5"]["details"] = "Arm moved home and fresh observation acquired after door-opening attempt."

# step-6: Localize the milk carton on the table and sample a stable grasp pose.
with step_context("step-6", "Localize milk carton and sample grasp", step_index=5):
    milk_position, milk_quaternion_from_pose = safe_localize_object("milk_carton", use_multiview=True, attempts=2)
    milk_grasp_position, milk_grasp_quaternion = sample_grasp_with_retries("milk_carton", use_multiview=True, attempts=2)
    if milk_grasp_position is None or milk_grasp_quaternion is None:
        milk_grasp_position, milk_grasp_quaternion = sample_grasp_with_retries("milk", use_multiview=True, attempts=1)
    RESULT["step-6"]["success"] = milk_grasp_position is not None and milk_grasp_quaternion is not None
    RESULT["step-6"]["details"] = "Milk carton localized and grasp pose sampled."

# step-7: Pick up the milk carton from the table.
with step_context("step-7", "Pick up milk carton", step_index=6):
    if RESULT["step-6"]["success"]:
        open_gripper()
        goto_pose(milk_grasp_position, milk_grasp_quaternion, z_approach=0.10)
        close_gripper()
        milk_lift_position = make_offset_pose(milk_grasp_position, dz=0.18)
        goto_pose(milk_lift_position, milk_grasp_quaternion, z_approach=0.0)
        RESULT["step-7"]["success"] = True
        RESULT["step-7"]["details"] = "Milk carton grasped and lifted from table."
    else:
        RESULT["step-7"]["details"] = "Skipped milk pickup because grasp sampling failed."

# step-8: Localize the open microwave interior and compute a placement pose inside the cavity.
with step_context("step-8", "Localize open microwave interior and compute placement pose", step_index=7):
    interior_position, interior_quaternion_from_pose = safe_localize_object("open_microwave_interior", use_multiview=True, attempts=2)
    interior_segment, interior_obb = safe_segment_obb("open microwave interior", use_multiview=True, attempts=2)
    if interior_position is None and interior_obb is not None:
        interior_position = interior_obb["center"]
    if interior_position is None:
        interior_position, interior_quaternion_from_pose = safe_localize_object("inside_of_microwave", use_multiview=True, attempts=1)
    if interior_position is not None:
        placement_position = interior_position.copy()
        placement_position[2] = placement_position[2] + 0.03
        pre_place_position = make_offset_pose(placement_position, dx=-0.10, dy=0.00, dz=0.10)
        placement_quaternion = milk_grasp_quaternion
        RESULT["step-8"]["success"] = True
        RESULT["step-8"]["details"] = "Open microwave interior localized and placement pose computed."
    else:
        RESULT["step-8"]["details"] = "Failed to localize open microwave interior."

# step-9: Move the milk into the open microwave and place it on the microwave floor.
with step_context("step-9", "Place milk inside open microwave", step_index=8):
    if RESULT["step-7"]["success"] and RESULT["step-8"]["success"]:
        goto_pose(pre_place_position, placement_quaternion, z_approach=0.0)
        goto_pose(placement_position, placement_quaternion, z_approach=0.04)
        open_gripper()
        retreat_position = make_offset_pose(pre_place_position, dx=-0.06, dy=0.00, dz=0.04)
        goto_pose(retreat_position, placement_quaternion, z_approach=0.0)
        RESULT["step-9"]["success"] = True
        RESULT["step-9"]["details"] = "Milk inserted into microwave cavity, released, and gripper retreated."
    else:
        RESULT["step-9"]["details"] = "Skipped placement because milk was not picked or microwave interior was not localized."

# step-10: Retract the arm to a safe pose and verify that the milk is inside the open microwave.
with step_context("step-10", "Retract and verify final state", step_index=9):
    goto_home_joint_position()
    final_observation = get_observation()
    RESULT["step-10"]["success"] = final_observation is not None and RESULT["step-9"]["success"]
    RESULT["step-10"]["details"] = "Arm retracted home and final observation acquired after placing milk inside microwave."

RESULT["overall_success"] = (
    RESULT["step-1"]["success"]
    and RESULT["step-2"]["success"]
    and RESULT["step-3"]["success"]
    and RESULT["step-4"]["success"]
    and RESULT["step-5"]["success"]
    and RESULT["step-6"]["success"]
    and RESULT["step-7"]["success"]
    and RESULT["step-8"]["success"]
    and RESULT["step-9"]["success"]
    and RESULT["step-10"]["success"]
)
API 返回的失败诊断原文
```json
{
  "visual_success": false,
  "failed_step": "step-7",
  "failure_mode": "grasp_failure",
  "confidence": 0.82,
  "plan_issue": false,
  "plan_issue_reason": "",
  "subagent_skill_target": null,
  "subagent_skill_target_reason": "",
  "subagent_approaches": [],
  "edit_scale": "argument_level",
  "visual_predicate_status": [
    {
      "step_id": "step-1",
      "description": "Get an updated observation and confirm the scene: the microwave is on the right side of the table with its door closed, the vertical handle is visible on the front-left edge of the microwave door, and the milk carton is upright near the center-front area of the table.",
      "visually_satisfied": true,
      "evidence": "The initial scene/verifier evidence shows the microwave on the right with the vertical handle visible and the milk carton upright on the table. This was an observation-only step and is consistent with the trajectory setup."
    },
    {
      "step_id": "step-2",
      "description": "Localize the microwave handle and estimate the microwave door/face geometry for grasping and opening.",
      "visually_satisfied": false,
      "evidence": "The handle is visible and the robot later moved to the handle area, but the final segment does not visually prove that the handle/door geometry was localized. The stdout also shows repeated perception-service connection failures and no segmentation/pose artifacts for the handle."
    },
    {
      "step_id": "step-3",
      "description": "Open the gripper, move to a pre-grasp pose in front of the microwave handle, then grasp the handle.",
      "visually_satisfied": false,
      "evidence": "The robot appears to have interacted with the handle earlier, but by the final segment the handle has been released, so the grasp itself is no longer observable. This step was likely achieved transiently but is not directly satisfied in the terminal view."
    },
    {
      "step_id": "step-4",
      "description": "Pull the microwave door open by moving the grasped handle outward and leftward along a short arc, then release the handle once the door is sufficiently open.",
      "visually_satisfied": true,
      "evidence": "The terminal wrist/scene view shows the microwave door displaced open relative to the body, with the handle/door no longer closed flush. The verifier also reports the door was pulled open and released."
    },
    {
      "step_id": "step-5",
      "description": "Move the arm away from the opened microwave door area and get a fresh observation to verify that the microwave is open and the interior cavity is reachable.",
      "visually_satisfied": false,
      "evidence": "Although the arm retreated, the terminal image does not clearly show a verified reachable interior cavity. The view is close/oblique and does not establish that the open microwave interior was usable for placement."
    },
    {
      "step_id": "step-6",
      "description": "Localize the milk carton on the table and sample a stable grasp pose.",
      "visually_satisfied": false,
      "evidence": "The milk carton remained visible on the table, but there are no reliable localization/grasp artifacts. Stdout shows repeated perception-service connection failures for 'milk_carton', and the later grasp did not result in holding the carton."
    },
    {
      "step_id": "step-7",
      "description": "Pick up the milk carton from the table.",
      "visually_satisfied": false,
      "evidence": "The milk carton was not lifted and the gripper is empty by the end. The code executed close_gripper and a lift after sampling a milk grasp, but visually the carton remained on the table, indicating the gripper closed off-target or failed to secure the carton."
    },
    {
      "step_id": "step-8",
      "description": "Localize the open microwave interior and compute a placement pose inside the cavity.",
      "visually_satisfied": false,
      "evidence": "The final view does not show a confirmed computed placement pose or clear localization of the microwave floor/cavity. Stdout shows repeated failures for 'open_microwave_interior' and 'open microwave interior', with no useful segmentation artifacts."
    },
    {
      "step_id": "step-9",
      "description": "Move the milk into the open microwave and place it on the microwave floor.",
      "visually_satisfied": false,
      "evidence": "The milk was never transported into the microwave. The gripper appears empty after the milk pickup attempt, and the verifier reports the carton remains upright on the table rather than inside the cavity."
    },
    {
      "step_id": "step-10",
      "description": "Retract the arm to a safe pose and verify that the milk is inside the open microwave.",
      "visually_satisfied": false,
      "evidence": "The arm retracted, but the required final state is not met: the milk is not inside the microwave. The terminal view/verification indicates an empty gripper and no placed carton in the microwave."
    }
  ],
  "policy_feedback": "argument_level: keep the overall sequence of opening the microwave, then grasping the milk, then placing it. The door-opening portion appears to have worked; do not rewrite that part. Change the milk pickup call in step-7: the sampled grasp for `sample_grasp_with_retries(\"milk_carton\", use_multiview=True, attempts=2)` / `goto_pose(milk_grasp_position, milk_grasp_quaternion, z_approach=0.10)` did not actually close on the carton. Use a more explicit target text such as the visible upright milk carton body/broad side, sample or bias the grasp toward the carton side faces rather than an arbitrary point, and increase retries. Approach the carton with a side or slightly top-down grasp centered on its rectangular body, then close and lift only after the gripper is aligned around the carton width. Also reduce reliance on the failing language-service calls shown in stdout: if `get_object_pose`/segmentation returns no points for `milk_carton`, retry with the simpler label `milk` or a fresh observation before executing the grasp pose. The code currently marks step-7 successful immediately after close/lift even though the gripper is empty, so add a post-lift visual/width check that retries the milk grasp before proceeding to microwave placement."
}
```

source: 0018_p506268_failure_diagnoser._query_llm_text.json

Agent 调用时间线 展开原始调用索引
#调用方耗时结果证据
1task_proposer.propose_novel_candidates12.9sstopembedded above
2environment_creator._generate_bddl3.7sstopembedded above
3planner.plan21.0sstopembedded above
4planner_verifier.verify_plan7.9sstopembedded above
5policy_writer._generate_once22.3sstopembedded above
6per_step_verifier._verify_step_package6.5sstopembedded above
7per_step_verifier._verify_step_package6.5sstopembedded above
8per_step_verifier._verify_step_package9.0sstopembedded above
9per_step_verifier._verify_step_package7.2sstopembedded above
10per_step_verifier._verify_step_package14.4sstopembedded above
11per_step_verifier._verify_step_package6.8sstopembedded above
12per_step_verifier._verify_step_package6.5sstopembedded above
13per_step_verifier._verify_step_package8.5sstopembedded above
14per_step_verifier._verify_step_package7.7sstopembedded above
15per_step_verifier._verify_step_package6.5sstopembedded above
16verifier._query_llm_json3.0sstopembedded above
17verifier._query_llm_json7.2sstopembedded above
18failure_diagnoser._query_llm_text25.2sstopembedded above
算法/交互失败Moka pot grasp

Put moka pot on stove · turn stove on

repro_readme_nonpriv_full_services

FAIL
最终判定任务完整执行;moka pot 未上灶、炉灶未开启,严格谓词 0/2。
失败阶段Moka pot grasp

Causal trace audit

Failure Mode Analysis

confidence 0.88
判定最早失败在 moka pot 抓取;物体定位基本正确,单一抓取候选/执行接口是首因。
最早失效点Step 3 · empty lift; moka pot remained stationary (frames 1–101)
近端物理原因

Contact-GraspNet 最高分候选落在细柄/上缘附近,闭爪后没有形成稳定承重夹持。

传播原因

GPT 代码把 close+lift 的命令完成当成 pickup success,随后空夹执行放置;没有候选重选或 holding gate。

AGPT-5.5 代码 / 状态机30%

调用顺序合理,但缺少抓后验证,且在必要前提失败后继续串行执行。

BLIBERO / TCP 标定5%

burner +0.055、knob arc 未被持物状态真正测试;不能据此认定 magic number 是根因。

CMolmo / SAM3 感知10%

moka 与 burner 点正确;后续 knob point 明显可疑,但不是最早失败点。

D抓取 / 3-D / 控制接口55%

单一候选缺少语义部位/稳定性筛选;3-D mask-depth 对齐还存在真实接口风险。

决定性证据
  1. Molmo agent-view 返回正确 moka pot 点;grasp position=[0.8329,-0.1586,0.1122] 位于物体邻域,视频没有 wrong-object 行为。
  2. per-step verifier 对 step 3 判 failed, confidence=0.95;抬升后夹爪为空,pot 未移动。
  3. sample_grasp_pose 只执行 scores.argmax();API 不提供候选部位、夹爪宽度、接触状态或 top-k retry。
  4. 独立的 knob 链确有感知/3-D 风险:agent 点落在画面顶部、get_object_pose 两次为 None,且 wrist point-cloud 363258 vs mask 409600;但它发生在首个空抓之后。
仍不能确认

缺少候选可视化、finger closure 与 object-pose trace,无法把“坏 candidate”与“正确 candidate 的 TCP/接触误差”精确分配。

最小反事实实验

同一 mask 下重放当前 argmax、人工 central-body grasp 与 top-k 候选;每次记录 gripper width、pot GT pose、commanded/actual TCP。

责任百分比用于表达该条 trace 的工程因果权重,不是统计概率;没有受控重放的结论标为 strongly supported,而非 confirmed。

01

Task setting

Kitchen tabletop; moka pot starts on the table; stove and control knob are visible. Goal predicates: On(moka_pot, stove_cooking_region) AND On(stove).

02

失败根因

最早失败在 moka pot 抓取;物体定位基本正确,单一抓取候选/执行接口是首因。

Evidence

视觉证据

iter001_attempt0_failed.mp4
Why

证据与推理

  1. 第 3 步视觉验证直接观察到夹爪抬升后未持物;moka pot 仍在桌面。
  2. 后续放置与旋钮动作继续执行,但已经失去任务成功的必要前提。
  3. 最终严格谓词同时判定 moka pot 不在 cooking region、stove 未开启。
03

真实 API 审计

model=gpt-5.5 · elapsed=25.1s · finish_reason=stop · source: 0005_p537028_policy_writer._generate_once.json

发送给 Policy Writer 的完整 prompt
===== SYSTEM =====
You are a deterministic policy writer for a code-as-policy robot system. Write ONLY Python code. Do not use while True loops. Use only the provided imported primitive functions and learned helper functions.

===== USER =====
You are a deterministic policy writer for a code-as-policy robot system.

Write Python code that executes the following plan.

AVAILABLE IMPORTED FUNCTIONS (use ONLY these, not env.<method>):
close_gripper, get_object_3d_points_and_masks_from_language, get_object_pose, get_observation, get_oriented_bounding_box_from_3d_points, goto_home_joint_position, goto_pose, open_gripper, sample_grasp_pose

API DOCUMENTATION:
get_observation() -> dict[str, typing.Any]
  Doc:
    Get the observation of the environment.
    Returns:
        observation:
            A dictionary containing the observation of the environment.
            The dictionary contains the following keys:
            - ["agentview"]["images"]["rgb"]: Current color camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["agentview"]["images"]["depth"]: Current depth camera image as a numpy array of shape (H, W), dtype float32.
            - ["agentview"]["intrinsics"]: Camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["agentview"]["pose_mat"]: Camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot0_eye_in_hand"]["images"]["rgb"]: Current wrist camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["robot0_eye_in_hand"]["images"]["depth"]: Current wrist camera depth image as a numpy array of shape (H, W), dtype float32.
            - ["robot0_eye_in_hand"]["intrinsics"]: Wrist camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["robot0_eye_in_hand"]["pose_mat"]: Wrist camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot_cartesian_pos"]: Current end-effector (panda_hand) pose in the robot/world frame as a numpy array of shape (8,), dtype float64. The first 3 elements are the robot's end-effector XYZ, the next 4 elements are the quaternion wxyz, and the last element is the gripper position normalized, 0 (closed) to 1 (open).
            - ["robot_joint_pos"]: Current joint positions as a numpy array of shape (7,), dtype float64. The last element is the gripper position normalized, 0 (closed) to 1 (open).

get_object_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray] | tuple[None, None]
  Doc:
    Get the pose of an object in the environment from a natural language description.
    The quaternion from get_object_pose may be unreliable, so disregard it and use the grasp
    pose quaternion OR (0, 0, 1, 0) wxyz as the gripper down orientation if using this for
    placement position.
    It is possible that get_object_pose is sometimes unreliable and will return None for both
    position and quaternion.
    
    Args:
        object_name: The name of the object to get the pose of, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

sample_grasp_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray]
  Doc:
    Sample a grasp pose for an object in the environment from a natural language description.
    Uses multiview point clouds and plan_grasp_from_point_clouds for more reliable grasp planning.
    Do use the grasp sample quaternion from sample_grasp_pose.
    
    Args:
        object_name: The name of the object to sample a grasp pose for, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

goto_pose(position: numpy.ndarray, quaternion_wxyz: numpy.ndarray, z_approach: float = 0.0) -> None
  Doc:
    Go to pose using Inverse Kinematics.
    There is no need to call a second goto_pose with the same position and quaternion_wxyz after calling it with z_approach.
    Args:
        position: (3,) XYZ in meters.
        quaternion_wxyz: (4,) WXYZ unit quaternion.
        z_approach: (float) Z-axis distance offset for goto_pose insertion approach motion. Will first arrive at position + z_approach meters in Z-axis before moving to the requested pose. Useful for more precise grasp approaches. Default is 0.0.
    Returns:
        None

open_gripper() -> None
  Doc:
    Open gripper fully.
    
    Args:
        None

close_gripper() -> None
  Doc:
    Close gripper fully.
    
    Args:
        None

get_oriented_bounding_box_from_3d_points(points: numpy.ndarray) -> dict[str, typing.Any]
  Doc:
    Get the oriented bounding box from 3D points.
    
    Args:
        points: np.ndarray: The 3D points to get the oriented bounding box from.
            Shape: (N, 3), dtype float64.
    
    Returns:
        dict[str, Any]: The oriented bounding box. The dictionary contains the following keys:
            - "center": np.ndarray: The center of the oriented bounding box in point cloud frame.
            - "extent": np.ndarray: The extent of the oriented bounding box.
            - "R": np.ndarray: The rotation matrix of the oriented bounding box in point cloud frame.
    
    Example:
        >>> points = np.random.randn((100, 3))
        >>> obb = get_oriented_bounding_box_from_3d_points(points)

get_object_3d_points_and_masks_from_language(text_prompt: str, use_multiview: bool = True) -> dict[str, typing.Any]
  Doc:
    Segment an object using text prompt across multiple views (agentview and wrist).
    
    Uses Molmo to locate the object in both camera views, then SAM3 for
    segmentation. Returns the masks and 3D points that appear in both views.
    
    Args:
        text_prompt: Text description of the object to segment.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation.
        
    Returns:
        dict containing:
            - "agentview_mask": np.ndarray of shape (H, W), dtype bool
            - "wrist_mask": np.ndarray of shape (H, W), dtype bool (None if single view)
            - "points_3d": np.ndarray of shape (N, 3), 3D points in world frame
            - "agentview_score": float, SAM3 confidence score
            - "wrist_score": float, SAM3 confidence score (None if single view)

goto_home_joint_position() -> None
  Doc:
    Return the arm to its reset joint configuration with high manipulability

LEARNED HELPER FUNCTION REFERENCES (already defined and callable — use them directly):
No learned helper functions available yet.

REQUIREMENTS:
- Use the primitive functions listed in AVAILABLE IMPORTED FUNCTIONS above AND any LEARNED HELPER FUNCTION REFERENCES shown above.
- The learned helper functions are pre-defined and available in your execution scope. Call them directly.
- Do NOT invent wrapper functions on env or low_level_env.
- Do NOT use while True loops or any unbounded retry patterns. Use bounded for loops instead.
- Set RESULT to a structured dict describing success/failure for each step.
- Add explicit comments before each plan step.
- Wrap the executable body for EACH plan step in the runtime marker context
  `with step_context("<step id>", "<step description>", step_index=<0-based index>):`.
  This is a logging marker, not a robot primitive. It lets the verifier save
  exact per-step API traces, motion frame ranges, and intermediate artifacts.
- Define reusable sub-functions for non-trivial skill sequences that could be added to the skill library.
- On retries, follow the diagnoser's requested edit scale. If a top-of-retry "## EDIT SCALE: argument-level" banner is present (or the prose says argument-level), keep the same primitive/helper call sequence and change only the named arguments first (target text, verify_label, pose/offset, approach axis, release height, retry count, or gate threshold). Rewrite helper bodies, replace primitives, or add new wrappers only when the banner / diagnosis says rewrite-needed because arguments cannot express the fix, the API/function is wrong for the task, the sequence is structurally wrong, or there is a real code/logic bug.


IMPORTANT: Use ONLY functions from the AVAILABLE IMPORTED FUNCTIONS list and LEARNED HELPER FUNCTION REFERENCES above.
Do NOT call any function not in those lists. Check the API DOCUMENTATION for correct function signatures.
Extract object names from the GOAL description below.

General rules:
- Read the API DOCUMENTATION carefully for the correct function signatures and return types.
- When retry feedback names a primitive/helper call, preserve that call and tune its arguments before changing the overall code structure, unless the feedback explicitly calls for a larger rewrite.
- For pick-and-place: perceive object location, move to grasp pose, close gripper, move to target, open gripper. Use the available perception functions to locate objects.
- Use bounded for loops (not while True) for retry patterns.
- For multi-step tasks (pick A then place on B), chain the patterns sequentially.
- Never leave a successfully grasped object suspended because a pre-release wrist check failed. Once the placement target has been localized, execute a cautious descend, open the gripper, retreat, and then verify the final resting state.
- NumPy array truthiness: localization primitives often return ndarrays or lists of candidates. NEVER write `if pos:` or `if not result:` on an ndarray — raises "truth value of an array is ambiguous". Instead use `if pos is None` / `if len(pos) == 0` / `if result.get("verified")` on explicit scalars. This pattern has burned many past attempts.



# === TASK-SPECIFIC INPUTS BELOW (vary per attempt; everything above is stable for cache reuse) ===

SCENE: i_want_to_put_the_moka_pot_on_the_stove_and_turn_on_the_stov
GOAL: I want to put the moka pot on the stove and turn on the stove.
OBJECT SCOPE: {}

PLAN:
- step-1: Get a fresh observation and confirm the visible scene state: moka pot is on the front-left area of the table, stove/burner is on the right side of the table, and the stove control knob is upright on the black circular knob base behind/left of the burner. The stove surface appears unobstructed and ready for placement. | skills: get_observation | notes: Use the attached image as initial evidence, then refresh with get_observation before acting.
- step-2: Localize the moka pot and sample a stable grasp pose for it, preferably on the upper body/handle area where the gripper can lift without colliding with the table. | skills: sample_grasp_pose | notes: Call sample_grasp_pose('moka_pot', use_multiview=True). The moka pot is visually distinct and unobstructed on the tabletop.
- step-3: Pick up the moka pot from the table. | skills: open_gripper, goto_pose, close_gripper | notes: Open the gripper, move to the sampled moka pot grasp pose with a small vertical approach offset, descend to grasp, close the gripper, then lift upward to clear the table.
- step-4: Localize the stove burner center as the placement target. | skills: get_object_pose | notes: Call get_object_pose('stove_burner', use_multiview=True) or get_object_pose('burner', use_multiview=True). Disregard the returned quaternion for placement; use a gripper-down placement orientation such as (0, 0, 1, 0) wxyz or retain a safe carry orientation. The target burner is visible on the right-side metal stove plate.
- step-5: Place the moka pot onto the center of the stove burner and release it. | skills: goto_pose, open_gripper | notes: Move above the burner center with clearance, lower until the moka pot base contacts the burner/stove plate, open the gripper to release, then retreat upward. Placement should be centered on the circular coil, not on the knob.
- step-6: Localize the stove control knob and sample/compute a grasp pose suitable for turning it. | skills: get_object_pose, sample_grasp_pose | notes: The knob is visible as a black vertical tab on a round base behind/left of the burner. Use get_object_pose('stove_knob', use_multiview=True) or sample_grasp_pose('stove_knob', use_multiview=True). Avoid colliding with the placed moka pot on the burner.
- step-7: Grasp the stove knob and rotate it to the on position. | skills: open_gripper, goto_pose, close_gripper, goto_pose | notes: ARTICULATED/CONTROL STEP. APPROACH DIRECTION: approach the vertical black knob tab from the front/top-front side of the stove control, keeping the gripper above the tabletop and clear of the moka pot; the fingers should straddle the thin vertical tab rather than press down on the circular base. PULL/PUSH/TURN DIRECTION: after grasping, rotate the knob about its vertical axis toward the stove's on direction, likely a clockwise or counterclockwise quarter-turn depending on the fixture convention; execute as a small horizontal arc around the knob center, not a linear pull. GRASP SELECTION CRITERION: select a grasp whose closing direction pinches the narrow vertical tab from opposite sides, with the gripper approach axis roughly horizontal or slightly downward and not aimed into the stove body; reject grasps that contact the circular base, collide with the moka pot, or approach from directly above with no ability to impart torque.
- step-8: Release the knob, retreat to a safe height, and verify the final state: moka pot is on the burner and the stove knob has been turned from its initial upright/off orientation. | skills: open_gripper, goto_home_joint_position, get_observation | notes: Use get_observation after retreating. The primary visual checks are moka pot centered on the stove and knob orientation changed to an on position.





## LESSONS FROM PAST FAILURES (advisory — NOT ground truth)

The block above (if non-empty) lists distilled lessons in "WHEN ... | WRONG ... | DO ..." form, each followed by a metadata footer like `(confidence=0.80, applied=5× helped=1×, last_helped=iter4 (2 iters ago), distilled=iter2 (4 iters ago))`. Use that footer to weigh how much to trust each lesson.

PRIORITY ORDER when signals conflict:
  0. The SUB-AGENT DIRECTIVE block above (if non-empty) — this is the parallel sub-agent's committed approach assignment, a HARD constraint, and dominates every other guidance source below.
  1. The current attempt's RETRY CONTEXT (diagnoser feedback + visual evidence + PREVIOUS CODE below) — this saw what actually happened on this exact task and is ground truth for what to fix.
  2. A lesson with high reliability (helped/applied ≥ 0.5 with applied ≥ 2) AND recent `last_helped` (≤ 2 iters ago) — strong prior, follow its DO recipe.
  3. A lesson with low reliability (helped/applied < 0.3) OR stale (`last_helped=never` or ≥ 5 iters ago) — background prior only; don't let it override the current diagnosis.

Empty block means no relevant prior failures.

API 返回并实际执行的 robot control code
def pick_object_with_sampled_grasp(object_name, approach_height=0.08, lift_height=0.15):
    grasp_position, grasp_quaternion = sample_grasp_pose(object_name, use_multiview=True)
    if grasp_position is None or grasp_quaternion is None:
        return {
            "success": False,
            "object": object_name,
            "error": "failed_to_sample_grasp_pose",
            "grasp_position": None,
            "grasp_quaternion": None,
        }

    open_gripper()
    goto_pose(grasp_position, grasp_quaternion, z_approach=approach_height)
    close_gripper()
    goto_pose(grasp_position + [0.0, 0.0, lift_height], grasp_quaternion)

    return {
        "success": True,
        "object": object_name,
        "grasp_position": grasp_position,
        "grasp_quaternion": grasp_quaternion,
        "lift_position": grasp_position + [0.0, 0.0, lift_height],
    }


def place_held_object_at_target(target_name, placement_z_offset=0.05, approach_height=0.14, retreat_height=0.16):
    target_position, _ = get_object_pose(target_name, use_multiview=True)
    if target_position is None:
        return {
            "success": False,
            "target": target_name,
            "error": "failed_to_localize_target",
            "target_position": None,
        }

    placement_quaternion = (0.0, 0.0, 1.0, 0.0)
    placement_position = target_position + [0.0, 0.0, placement_z_offset]

    goto_pose(placement_position, placement_quaternion, z_approach=approach_height)
    open_gripper()
    goto_pose(placement_position + [0.0, 0.0, retreat_height], placement_quaternion)

    return {
        "success": True,
        "target": target_name,
        "target_position": target_position,
        "placement_position": placement_position,
        "placement_quaternion": placement_quaternion,
        "retreat_position": placement_position + [0.0, 0.0, retreat_height],
    }


def turn_stove_knob_by_horizontal_arc(knob_name, grasp_approach_height=0.06, arc_radius=0.045, z_clearance=0.035):
    knob_position, _ = get_object_pose(knob_name, use_multiview=True)
    if knob_position is None:
        return {
            "success": False,
            "knob": knob_name,
            "error": "failed_to_localize_knob",
            "knob_position": None,
        }

    knob_grasp_position, knob_grasp_quaternion = sample_grasp_pose(knob_name, use_multiview=True)
    if knob_grasp_position is None or knob_grasp_quaternion is None:
        return {
            "success": False,
            "knob": knob_name,
            "error": "failed_to_sample_knob_grasp",
            "knob_position": knob_position,
            "grasp_position": None,
            "grasp_quaternion": None,
        }

    open_gripper()
    goto_pose(knob_grasp_position + [0.0, 0.0, z_clearance], knob_grasp_quaternion)
    goto_pose(knob_grasp_position, knob_grasp_quaternion, z_approach=grasp_approach_height)
    close_gripper()

    arc_start = knob_position + [0.0, -arc_radius, z_clearance]
    arc_mid_1 = knob_position + [0.032, -0.032, z_clearance]
    arc_mid_2 = knob_position + [arc_radius, 0.0, z_clearance]
    arc_mid_3 = knob_position + [0.032, 0.032, z_clearance]
    arc_end = knob_position + [0.0, arc_radius, z_clearance]

    goto_pose(arc_start, knob_grasp_quaternion)
    goto_pose(arc_mid_1, knob_grasp_quaternion)
    goto_pose(arc_mid_2, knob_grasp_quaternion)
    goto_pose(arc_mid_3, knob_grasp_quaternion)
    goto_pose(arc_end, knob_grasp_quaternion)

    open_gripper()
    goto_pose(knob_position + [0.0, 0.0, 0.14], knob_grasp_quaternion)

    return {
        "success": True,
        "knob": knob_name,
        "knob_position": knob_position,
        "grasp_position": knob_grasp_position,
        "grasp_quaternion": knob_grasp_quaternion,
        "arc_points": [arc_start, arc_mid_1, arc_mid_2, arc_mid_3, arc_end],
        "retreat_position": knob_position + [0.0, 0.0, 0.14],
    }


RESULT = {
    "overall_success": False,
    "steps": {},
}

# step-1: Get a fresh observation and confirm the visible scene state.
with step_context("step-1", "Get fresh observation of moka pot, stove burner, and control knob", step_index=0):
    observation = get_observation()
    RESULT["steps"]["step-1"] = {
        "success": observation is not None,
        "observation_keys": list(observation.keys()) if observation is not None else None,
        "notes": "Fresh observation captured before acting.",
    }

# step-2: Localize the moka pot and sample a stable grasp pose for it.
with step_context("step-2", "Sample grasp pose for the moka pot", step_index=1):
    moka_grasp_position, moka_grasp_quaternion = sample_grasp_pose("moka_pot", use_multiview=True)
    RESULT["steps"]["step-2"] = {
        "success": moka_grasp_position is not None and moka_grasp_quaternion is not None,
        "object": "moka_pot",
        "grasp_position": moka_grasp_position,
        "grasp_quaternion": moka_grasp_quaternion,
    }

# step-3: Pick up the moka pot from the table.
with step_context("step-3", "Pick up the moka pot", step_index=2):
    if RESULT["steps"]["step-2"]["success"]:
        open_gripper()
        goto_pose(moka_grasp_position, moka_grasp_quaternion, z_approach=0.08)
        close_gripper()
        moka_lift_position = moka_grasp_position + [0.0, 0.0, 0.16]
        goto_pose(moka_lift_position, moka_grasp_quaternion)
        RESULT["steps"]["step-3"] = {
            "success": True,
            "object": "moka_pot",
            "lift_position": moka_lift_position,
        }
    else:
        RESULT["steps"]["step-3"] = {
            "success": False,
            "error": "skipped_because_moka_grasp_not_available",
        }

# step-4: Localize the stove burner center as the placement target.
with step_context("step-4", "Localize the stove burner center", step_index=3):
    burner_position, burner_quaternion_unused = get_object_pose("stove_burner", use_multiview=True)
    burner_label_used = "stove_burner"
    if burner_position is None:
        burner_position, burner_quaternion_unused = get_object_pose("burner", use_multiview=True)
        burner_label_used = "burner"

    RESULT["steps"]["step-4"] = {
        "success": burner_position is not None,
        "target_label": burner_label_used,
        "burner_position": burner_position,
        "returned_quaternion_disregarded": burner_quaternion_unused,
    }

# step-5: Place the moka pot onto the center of the stove burner and release it.
with step_context("step-5", "Place moka pot on the stove burner", step_index=4):
    if RESULT["steps"]["step-3"]["success"] and RESULT["steps"]["step-4"]["success"]:
        placement_quaternion = (0.0, 0.0, 1.0, 0.0)
        moka_placement_position = burner_position + [0.0, 0.0, 0.055]
        goto_pose(moka_placement_position, placement_quaternion, z_approach=0.15)
        open_gripper()
        moka_retreat_position = moka_placement_position + [0.0, 0.0, 0.17]
        goto_pose(moka_retreat_position, placement_quaternion)
        RESULT["steps"]["step-5"] = {
            "success": True,
            "placement_position": moka_placement_position,
            "placement_quaternion": placement_quaternion,
            "retreat_position": moka_retreat_position,
        }
    else:
        RESULT["steps"]["step-5"] = {
            "success": False,
            "error": "skipped_because_pick_or_burner_localization_failed",
        }

# step-6: Localize the stove control knob and sample/compute a grasp pose suitable for turning it.
with step_context("step-6", "Localize and sample grasp pose for the stove control knob", step_index=5):
    knob_position, knob_quaternion_unused = get_object_pose("stove_knob", use_multiview=True)
    knob_label_used = "stove_knob"
    if knob_position is None:
        knob_position, knob_quaternion_unused = get_object_pose("stove_control_knob", use_multiview=True)
        knob_label_used = "stove_control_knob"

    if knob_position is not None:
        knob_grasp_position, knob_grasp_quaternion = sample_grasp_pose(knob_label_used, use_multiview=True)
    else:
        knob_grasp_position, knob_grasp_quaternion = None, None

    RESULT["steps"]["step-6"] = {
        "success": knob_position is not None and knob_grasp_position is not None and knob_grasp_quaternion is not None,
        "knob_label": knob_label_used,
        "knob_position": knob_position,
        "returned_quaternion_disregarded": knob_quaternion_unused,
        "knob_grasp_position": knob_grasp_position,
        "knob_grasp_quaternion": knob_grasp_quaternion,
    }

# step-7: Grasp the stove knob and rotate it to the on position.
with step_context("step-7", "Grasp and rotate stove knob along a small horizontal arc", step_index=6):
    if RESULT["steps"]["step-6"]["success"]:
        open_gripper()

        knob_safe_pregrasp = knob_grasp_position + [0.0, 0.0, 0.05]
        goto_pose(knob_safe_pregrasp, knob_grasp_quaternion)
        goto_pose(knob_grasp_position, knob_grasp_quaternion, z_approach=0.05)
        close_gripper()

        arc_radius = 0.045
        arc_z = 0.035
        knob_arc_start = knob_position + [0.0, -arc_radius, arc_z]
        knob_arc_mid_1 = knob_position + [0.032, -0.032, arc_z]
        knob_arc_mid_2 = knob_position + [arc_radius, 0.0, arc_z]
        knob_arc_mid_3 = knob_position + [0.032, 0.032, arc_z]
        knob_arc_end = knob_position + [0.0, arc_radius, arc_z]

        goto_pose(knob_arc_start, knob_grasp_quaternion)
        goto_pose(knob_arc_mid_1, knob_grasp_quaternion)
        goto_pose(knob_arc_mid_2, knob_grasp_quaternion)
        goto_pose(knob_arc_mid_3, knob_grasp_quaternion)
        goto_pose(knob_arc_end, knob_grasp_quaternion)

        RESULT["steps"]["step-7"] = {
            "success": True,
            "arc_points": [
                knob_arc_start,
                knob_arc_mid_1,
                knob_arc_mid_2,
                knob_arc_mid_3,
                knob_arc_end,
            ],
            "notes": "Executed bounded quarter-turn-like horizontal arc around the localized knob center.",
        }
    else:
        RESULT["steps"]["step-7"] = {
            "success": False,
            "error": "skipped_because_knob_localization_or_grasp_failed",
        }

# step-8: Release the knob, retreat to a safe height, and verify the final state.
with step_context("step-8", "Release knob, retreat home, and observe final state", step_index=7):
    open_gripper()
    if RESULT["steps"]["step-6"].get("knob_position") is not None and RESULT["steps"]["step-6"].get("knob_grasp_quaternion") is not None:
        final_knob_retreat_position = RESULT["steps"]["step-6"]["knob_position"] + [0.0, 0.0, 0.16]
        goto_pose(final_knob_retreat_position, RESULT["steps"]["step-6"]["knob_grasp_quaternion"])
    else:
        final_knob_retreat_position = None

    goto_home_joint_position()
    final_observation = get_observation()

    RESULT["steps"]["step-8"] = {
        "success": final_observation is not None,
        "retreat_position": final_knob_retreat_position,
        "observation_keys": list(final_observation.keys()) if final_observation is not None else None,
        "notes": "Final observation captured for visual verification of moka pot on burner and changed knob orientation.",
    }

RESULT["overall_success"] = (
    RESULT["steps"]["step-1"]["success"]
    and RESULT["steps"]["step-2"]["success"]
    and RESULT["steps"]["step-3"]["success"]
    and RESULT["steps"]["step-4"]["success"]
    and RESULT["steps"]["step-5"]["success"]
    and RESULT["steps"]["step-6"]["success"]
    and RESULT["steps"]["step-7"]["success"]
    and RESULT["steps"]["step-8"]["success"]
)
API 返回的失败诊断原文
```json
{
  "visual_success": false,
  "failed_step": "step-3",
  "failure_mode": "grasp_failure",
  "confidence": 0.9,
  "plan_issue": false,
  "plan_issue_reason": "",
  "subagent_skill_target": null,
  "subagent_skill_target_reason": "",
  "subagent_approaches": [],
  "edit_scale": "argument_level",
  "visual_predicate_status": [
    {
      "step_id": "step-1",
      "description": "Get a fresh observation and confirm the visible scene state: moka pot is on the front-left area of the table, stove/burner is on the right side of the table, and the stove control knob is upright on the black circular knob base behind/left of the burner. The stove surface appears unobstructed and ready for placement.",
      "visually_satisfied": true,
      "evidence": "The terminal/wrist view still shows the stove burner on the right/top area and the moka pot on the table near the lower-right/front area. The knob is visible near the stove area. The initial layout described by the plan is consistent with the visible scene."
    },
    {
      "step_id": "step-2",
      "description": "Localize the moka pot and sample a stable grasp pose for it, preferably on the upper body/handle area where the gripper can lift without colliding with the table.",
      "visually_satisfied": false,
      "evidence": "Although stdout reports a sampled moka_pot grasp at approximately [0.833, -0.159, 0.112], the final visual state shows the moka pot was never successfully held. The wrist view shows the gripper empty and the moka pot still on the table, so the sampled grasp was not visually demonstrated to be stable or correctly aligned."
    },
    {
      "step_id": "step-3",
      "description": "Pick up the moka pot from the table.",
      "visually_satisfied": false,
      "evidence": "The moka pot remains on the table at the end, and the wrist camera shows the gripper empty rather than holding the pot. This indicates the close_gripper/lift sequence did not actually grasp and lift the moka pot."
    },
    {
      "step_id": "step-4",
      "description": "Localize the stove burner center as the placement target.",
      "visually_satisfied": false,
      "evidence": "The burner is visible, and stdout shows a stove_burner point was generated, but the final visual evidence cannot confirm that the localized target was the burner center. Since the pot was never carried to the burner, this localization was not visually validated by successful placement."
    },
    {
      "step_id": "step-5",
      "description": "Place the moka pot onto the center of the stove burner and release it.",
      "visually_satisfied": false,
      "evidence": "The final wrist view clearly shows the stove burner unobstructed and the moka pot still off the burner on the table. The robot appears to have released with an empty gripper or without the pot over the burner."
    },
    {
      "step_id": "step-6",
      "description": "Localize the stove control knob and sample/compute a grasp pose suitable for turning it.",
      "visually_satisfied": false,
      "evidence": "The knob is visible near the stove, and stdout shows attempted text detections for stove_knob/stove_control_knob, but the final visual state does not demonstrate a successful grasp pose on the knob. There is no visible evidence that the gripper closed on the knob."
    },
    {
      "step_id": "step-7",
      "description": "Grasp the stove knob and rotate it to the on position.",
      "visually_satisfied": false,
      "evidence": "The final image does not show a clear changed/on orientation of the knob. The knob appears still on its black base and there is no visible evidence that it was grasped and rotated; the main task state remains incomplete."
    },
    {
      "step_id": "step-8",
      "description": "Release the knob, retreat to a safe height, and verify the final state: moka pot is on the burner and the stove knob has been turned from its initial upright/off orientation.",
      "visually_satisfied": false,
      "evidence": "At the end, the gripper is empty and retreated, but the moka pot is not on the burner and the knob orientation is not visibly verified as changed. The required final state is not achieved."
    }
  ],
  "policy_feedback": "argument_level: Keep the same high-level sequence, but fix the moka pot grasp before proceeding. The sampled grasp used by `sample_grasp_pose(\"moka_pot\", use_multiview=True)` led to `close_gripper()` and lift with an empty gripper; the final wrist image shows the moka pot still on the table. Change the grasp target/selection to the moka pot's rigid central metal body or upper body, not the thin handle/spout or an edge beside it, and use a pose/offset that puts both fingers around the body before closing. In the step-3 `goto_pose(moka_grasp_position, moka_grasp_quaternion, z_approach=0.08)` call, reduce any lateral offset error and ensure the approach descends directly over the pot body; after closing, lift only if the pot visibly moves with the gripper. Do not spend effort tuning burner placement or knob turning until the pot is actually held, because the later placement ran with an empty gripper."
}
```

source: 0016_p537028_failure_diagnoser._query_llm_text.json

Agent 调用时间线 展开原始调用索引
#调用方耗时结果证据
1task_proposer.propose_novel_candidates24.4sstopembedded above
2environment_creator._generate_bddl4.0sstopembedded above
3planner.plan20.9sstopembedded above
4planner_verifier.verify_plan11.5sstopembedded above
5policy_writer._generate_once25.1sstopembedded above
6per_step_verifier._verify_step_package8.0sstopembedded above
7per_step_verifier._verify_step_package7.7sstopembedded above
8per_step_verifier._verify_step_package7.3sstopembedded above
9per_step_verifier._verify_step_package7.0sstopembedded above
10per_step_verifier._verify_step_package7.2sstopembedded above
11per_step_verifier._verify_step_package7.9sstopembedded above
12per_step_verifier._verify_step_package6.9sstopembedded above
13per_step_verifier._verify_step_package9.6sstopembedded above
14verifier._query_llm_json2.6sstopembedded above
15verifier._query_llm_json7.4sstopembedded above
16failure_diagnoser._query_llm_text20.3sstopembedded above
任务失败Door trajectory

Open microwave · put porcelain mug inside

repro_readme_task_cases

FAIL
最终判定执行 506 帧;微波炉未打开,杯子仍在桌面。严格谓词 0/2。
失败阶段Door trajectory

Causal trace audit

Failure Mode Analysis

confidence 0.93
判定首因是 GPT 生成的开门轨迹方向错误,不是检测偏差或少量 offset。
最早失效点Step 3 · door-opening path moves in the wrong Y direction; door stays closed
近端物理原因

LIBERO 资产要求把手约沿 (-X,-Y) 圆弧移动;代码实际命令 (-X,+Y),与真实铰链运动学相反。

传播原因

门未开仍继续抓 mug、定位不存在的 open interior,并无条件标记各 step 成功;mug 后续也发生独立空抓。

AGPT-5.5 代码 / 状态机65%

决定性错误是铰链轨迹符号;同时缺少门/持物 gate,RESULT 是自报而非观测。

BLIBERO / TCP 标定5%

1–2 cm 深插/clearance 可能影响接触,但无法修正 +Y/−Y 的方向错误。

CMolmo / SAM3 感知5%

handle 与 mug 点都在正确物体上,gross localisation error 被反证。

D抓取 / 3-D / 控制接口25%

把手候选四元数较斜且无动作特定筛选;mug 的第二次空抓也支持该次因。

决定性证据
  1. 资产几何:闭门把手相对铰链约(+0.2375,-0.054),开到 -90° 的位移约(-0.2915,-0.1835)。
  2. GPT waypoints 为(-0.10,+0.08)、(-0.20,+0.18)、(-0.28,+0.30),Y 符号完全相反;完美感知也无法修复。
  3. Molmo handle point (658,606) 映射到图像约(526,310),落在竖把手;3-D grasp position=[0.7170,0.2033,0.1641] 也在邻域。
  4. frames 1–216 门始终关闭;frames 256–358 mug 也没有随夹爪抬升。native predicates 两项均 false。
仍不能确认

即使先修正轨迹,当前把手 candidate 是否能维持接触仍需重放;这不改变原代码必然走错方向的判断。

最小反事实实验

冻结当前 handle pose,仅把轨迹改为资产导出的 (-X,-Y) 弧并加入 Open gate;oracle handle pose + 原代码应仍因 +Y 失败。

责任百分比用于表达该条 trace 的工程因果权重,不是统计概率;没有受控重放的结论标为 strongly supported,而非 confirmed。

01

Task setting

Kitchen tabletop; microwave starts closed; porcelain mug starts on the table. Goal predicates: Open(microwave) AND In(porcelain_mug, microwave_heating_region).

02

失败根因

首因是 GPT 生成的开门轨迹方向错误,不是检测偏差或少量 offset。

Evidence

视觉证据

iter001_attempt0_failed.mp4
Why

证据与推理

  1. 逐步视觉证据判定第 3 步开门失败(confidence 0.90)。
  2. 最终状态明确为 Open(microwave)=false、In(mug, heating_region)=false。
  3. failure_mode=partial_completion;失败点在 articulated door interaction,而不是任务初始化。
03

真实 API 审计

model=gpt-5.5 · elapsed=20.5s · finish_reason=stop · source: 0005_p568475_policy_writer._generate_once.json

发送给 Policy Writer 的完整 prompt
===== SYSTEM =====
You are a deterministic policy writer for a code-as-policy robot system. Write ONLY Python code. Do not use while True loops. Use only the provided imported primitive functions and learned helper functions.

===== USER =====
You are a deterministic policy writer for a code-as-policy robot system.

Write Python code that executes the following plan.

AVAILABLE IMPORTED FUNCTIONS (use ONLY these, not env.<method>):
close_gripper, get_object_3d_points_and_masks_from_language, get_object_pose, get_observation, get_oriented_bounding_box_from_3d_points, goto_home_joint_position, goto_pose, open_gripper, sample_grasp_pose

API DOCUMENTATION:
get_observation() -> dict[str, typing.Any]
  Doc:
    Get the observation of the environment.
    Returns:
        observation:
            A dictionary containing the observation of the environment.
            The dictionary contains the following keys:
            - ["agentview"]["images"]["rgb"]: Current color camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["agentview"]["images"]["depth"]: Current depth camera image as a numpy array of shape (H, W), dtype float32.
            - ["agentview"]["intrinsics"]: Camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["agentview"]["pose_mat"]: Camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot0_eye_in_hand"]["images"]["rgb"]: Current wrist camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["robot0_eye_in_hand"]["images"]["depth"]: Current wrist camera depth image as a numpy array of shape (H, W), dtype float32.
            - ["robot0_eye_in_hand"]["intrinsics"]: Wrist camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["robot0_eye_in_hand"]["pose_mat"]: Wrist camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot_cartesian_pos"]: Current end-effector (panda_hand) pose in the robot/world frame as a numpy array of shape (8,), dtype float64. The first 3 elements are the robot's end-effector XYZ, the next 4 elements are the quaternion wxyz, and the last element is the gripper position normalized, 0 (closed) to 1 (open).
            - ["robot_joint_pos"]: Current joint positions as a numpy array of shape (7,), dtype float64. The last element is the gripper position normalized, 0 (closed) to 1 (open).

get_object_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray] | tuple[None, None]
  Doc:
    Get the pose of an object in the environment from a natural language description.
    The quaternion from get_object_pose may be unreliable, so disregard it and use the grasp
    pose quaternion OR (0, 0, 1, 0) wxyz as the gripper down orientation if using this for
    placement position.
    It is possible that get_object_pose is sometimes unreliable and will return None for both
    position and quaternion.
    
    Args:
        object_name: The name of the object to get the pose of, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

sample_grasp_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray]
  Doc:
    Sample a grasp pose for an object in the environment from a natural language description.
    Uses multiview point clouds and plan_grasp_from_point_clouds for more reliable grasp planning.
    Do use the grasp sample quaternion from sample_grasp_pose.
    
    Args:
        object_name: The name of the object to sample a grasp pose for, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

goto_pose(position: numpy.ndarray, quaternion_wxyz: numpy.ndarray, z_approach: float = 0.0) -> None
  Doc:
    Go to pose using Inverse Kinematics.
    There is no need to call a second goto_pose with the same position and quaternion_wxyz after calling it with z_approach.
    Args:
        position: (3,) XYZ in meters.
        quaternion_wxyz: (4,) WXYZ unit quaternion.
        z_approach: (float) Z-axis distance offset for goto_pose insertion approach motion. Will first arrive at position + z_approach meters in Z-axis before moving to the requested pose. Useful for more precise grasp approaches. Default is 0.0.
    Returns:
        None

open_gripper() -> None
  Doc:
    Open gripper fully.
    
    Args:
        None

close_gripper() -> None
  Doc:
    Close gripper fully.
    
    Args:
        None

get_oriented_bounding_box_from_3d_points(points: numpy.ndarray) -> dict[str, typing.Any]
  Doc:
    Get the oriented bounding box from 3D points.
    
    Args:
        points: np.ndarray: The 3D points to get the oriented bounding box from.
            Shape: (N, 3), dtype float64.
    
    Returns:
        dict[str, Any]: The oriented bounding box. The dictionary contains the following keys:
            - "center": np.ndarray: The center of the oriented bounding box in point cloud frame.
            - "extent": np.ndarray: The extent of the oriented bounding box.
            - "R": np.ndarray: The rotation matrix of the oriented bounding box in point cloud frame.
    
    Example:
        >>> points = np.random.randn((100, 3))
        >>> obb = get_oriented_bounding_box_from_3d_points(points)

get_object_3d_points_and_masks_from_language(text_prompt: str, use_multiview: bool = True) -> dict[str, typing.Any]
  Doc:
    Segment an object using text prompt across multiple views (agentview and wrist).
    
    Uses Molmo to locate the object in both camera views, then SAM3 for
    segmentation. Returns the masks and 3D points that appear in both views.
    
    Args:
        text_prompt: Text description of the object to segment.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation.
        
    Returns:
        dict containing:
            - "agentview_mask": np.ndarray of shape (H, W), dtype bool
            - "wrist_mask": np.ndarray of shape (H, W), dtype bool (None if single view)
            - "points_3d": np.ndarray of shape (N, 3), 3D points in world frame
            - "agentview_score": float, SAM3 confidence score
            - "wrist_score": float, SAM3 confidence score (None if single view)

goto_home_joint_position() -> None
  Doc:
    Return the arm to its reset joint configuration with high manipulability

LEARNED HELPER FUNCTION REFERENCES (already defined and callable — use them directly):
No learned helper functions available yet.

REQUIREMENTS:
- Use the primitive functions listed in AVAILABLE IMPORTED FUNCTIONS above AND any LEARNED HELPER FUNCTION REFERENCES shown above.
- The learned helper functions are pre-defined and available in your execution scope. Call them directly.
- Do NOT invent wrapper functions on env or low_level_env.
- Do NOT use while True loops or any unbounded retry patterns. Use bounded for loops instead.
- Set RESULT to a structured dict describing success/failure for each step.
- Add explicit comments before each plan step.
- Wrap the executable body for EACH plan step in the runtime marker context
  `with step_context("<step id>", "<step description>", step_index=<0-based index>):`.
  This is a logging marker, not a robot primitive. It lets the verifier save
  exact per-step API traces, motion frame ranges, and intermediate artifacts.
- Define reusable sub-functions for non-trivial skill sequences that could be added to the skill library.
- On retries, follow the diagnoser's requested edit scale. If a top-of-retry "## EDIT SCALE: argument-level" banner is present (or the prose says argument-level), keep the same primitive/helper call sequence and change only the named arguments first (target text, verify_label, pose/offset, approach axis, release height, retry count, or gate threshold). Rewrite helper bodies, replace primitives, or add new wrappers only when the banner / diagnosis says rewrite-needed because arguments cannot express the fix, the API/function is wrong for the task, the sequence is structurally wrong, or there is a real code/logic bug.


IMPORTANT: Use ONLY functions from the AVAILABLE IMPORTED FUNCTIONS list and LEARNED HELPER FUNCTION REFERENCES above.
Do NOT call any function not in those lists. Check the API DOCUMENTATION for correct function signatures.
Extract object names from the GOAL description below.

General rules:
- Read the API DOCUMENTATION carefully for the correct function signatures and return types.
- When retry feedback names a primitive/helper call, preserve that call and tune its arguments before changing the overall code structure, unless the feedback explicitly calls for a larger rewrite.
- For pick-and-place: perceive object location, move to grasp pose, close gripper, move to target, open gripper. Use the available perception functions to locate objects.
- Use bounded for loops (not while True) for retry patterns.
- For multi-step tasks (pick A then place on B), chain the patterns sequentially.
- Never leave a successfully grasped object suspended because a pre-release wrist check failed. Once the placement target has been localized, execute a cautious descend, open the gripper, retreat, and then verify the final resting state.
- NumPy array truthiness: localization primitives often return ndarrays or lists of candidates. NEVER write `if pos:` or `if not result:` on an ndarray — raises "truth value of an array is ambiguous". Instead use `if pos is None` / `if len(pos) == 0` / `if result.get("verified")` on explicit scalars. This pattern has burned many past attempts.



# === TASK-SPECIFIC INPUTS BELOW (vary per attempt; everything above is stable for cache reuse) ===

SCENE: i_want_to_open_the_microwave_and_put_the_porcelain_mug_insid
GOAL: I want to open the microwave and put the porcelain mug inside it.
OBJECT SCOPE: {}

PLAN:
- step-1: Get a fresh observation and confirm the initial state: the porcelain mug is on the open tabletop in front-left of the microwave, and the microwave door appears closed with the vertical handle visible on the front-left side. | skills: get_observation | notes: Use the initial image as guidance but refresh perception before acting. The microwave must be opened before attempting to place the mug inside.
- step-2: Localize the microwave handle and plan a grasp on it. | skills: get_object_pose, sample_grasp_pose | notes: Target object name should be something like microwave_handle. If sample_grasp_pose fails, use get_object_pose for the handle and approach with a gripper-down or front-facing orientation appropriate for wrapping around the handle.
- step-3: Open the microwave door by grasping the handle and pulling the door outward until the interior is accessible. | skills: open_gripper, goto_pose, close_gripper | notes: ARTICULATED OBJECT NOTES: (a) APPROACH DIRECTION: approach the microwave handle from the front of the microwave, roughly perpendicular to the microwave door face, so the gripper comes toward the handle without colliding with the door body. (b) PULL/PUSH DIRECTION: after closing on the handle, pull outward away from the microwave front face and slightly leftward following the door's swing arc, stopping when the door is open enough to expose the cavity. (c) GRASP SELECTION CRITERION: select a grasp whose approach axis is roughly perpendicular to the door surface and whose fingers wrap around the vertical handle from the front, not from above or from the side; reject grasps that would collide with the microwave body or scrape along the front panel. The robot should maintain grasp while executing a smooth arc-like pull, then release the handle once the door is open.
- step-4: Release the microwave handle and move the arm to a safe intermediate pose away from the open door and table objects. | skills: open_gripper, goto_home_joint_position | notes: This clears the workspace before picking the mug. Avoid contacting the open microwave door.
- step-5: Localize and sample a grasp pose for the porcelain mug on the tabletop. | skills: get_object_pose, sample_grasp_pose | notes: Target object name should be porcelain_mug. The mug is visible on the tabletop, with the handle on the right side. Prefer a stable rim/body grasp that avoids relying on the small handle unless the grasp planner identifies it as robust.
- step-6: Pick up the porcelain mug from the tabletop. | skills: open_gripper, goto_pose, close_gripper | notes: Use the sampled grasp pose quaternion from sample_grasp_pose. Approach from above with a small z_approach, close the gripper, then lift vertically enough to clear the tabletop and the open microwave door.
- step-7: Localize the open microwave interior / placement region. | skills: get_object_pose, get_object_3d_points_and_masks_from_language, get_oriented_bounding_box_from_3d_points | notes: Segment or localize the open microwave cavity/interior floor rather than the closed door front. Use the interior floor center as the placement target, with a gripper-down orientation such as quaternion (0, 0, 1, 0) if needed for placement.
- step-8: Place the mug inside the open microwave and release it. | skills: goto_pose, open_gripper | notes: Move to a pre-place pose above the microwave cavity, then lower carefully to the interior floor center. Keep clearance from the microwave roof, side walls, and open door. Release the mug only after reaching a stable placement height inside the cavity, then retreat upward and outward.
- step-9: Return the arm to a safe home configuration and verify that the mug is inside the open microwave. | skills: goto_home_joint_position, get_observation | notes: Final goal does not require closing the microwave. Verify the door remains open and the mug is no longer on the tabletop but is visible or inferred inside the microwave cavity.





## LESSONS FROM PAST FAILURES (advisory — NOT ground truth)

The block above (if non-empty) lists distilled lessons in "WHEN ... | WRONG ... | DO ..." form, each followed by a metadata footer like `(confidence=0.80, applied=5× helped=1×, last_helped=iter4 (2 iters ago), distilled=iter2 (4 iters ago))`. Use that footer to weigh how much to trust each lesson.

PRIORITY ORDER when signals conflict:
  0. The SUB-AGENT DIRECTIVE block above (if non-empty) — this is the parallel sub-agent's committed approach assignment, a HARD constraint, and dominates every other guidance source below.
  1. The current attempt's RETRY CONTEXT (diagnoser feedback + visual evidence + PREVIOUS CODE below) — this saw what actually happened on this exact task and is ground truth for what to fix.
  2. A lesson with high reliability (helped/applied ≥ 0.5 with applied ≥ 2) AND recent `last_helped` (≤ 2 iters ago) — strong prior, follow its DO recipe.
  3. A lesson with low reliability (helped/applied < 0.3) OR stale (`last_helped=never` or ≥ 5 iters ago) — background prior only; don't let it override the current diagnosis.

Empty block means no relevant prior failures.

API 返回并实际执行的 robot control code
RESULT = {
    "step-1": {"success": False, "details": ""},
    "step-2": {"success": False, "details": ""},
    "step-3": {"success": False, "details": ""},
    "step-4": {"success": False, "details": ""},
    "step-5": {"success": False, "details": ""},
    "step-6": {"success": False, "details": ""},
    "step-7": {"success": False, "details": ""},
    "step-8": {"success": False, "details": ""},
    "step-9": {"success": False, "details": ""},
}


def safe_pick_object(object_name, grasp_position, grasp_quaternion, approach_height, lift_height):
    open_gripper()
    goto_pose(grasp_position, grasp_quaternion, z_approach=approach_height)
    close_gripper()
    lift_position = grasp_position.copy()
    lift_position[2] = lift_position[2] + lift_height
    goto_pose(lift_position, grasp_quaternion)
    return lift_position


def safe_place_object(place_position, place_quaternion, approach_height, retreat_height):
    goto_pose(place_position, place_quaternion, z_approach=approach_height)
    open_gripper()
    retreat_position = place_position.copy()
    retreat_position[2] = retreat_position[2] + retreat_height
    goto_pose(retreat_position, place_quaternion)
    return retreat_position


def open_microwave_door_from_handle(handle_position, handle_quaternion):
    open_gripper()
    goto_pose(handle_position, handle_quaternion, z_approach=0.08)
    close_gripper()

    pull_position_1 = handle_position.copy()
    pull_position_1[0] = pull_position_1[0] - 0.10
    pull_position_1[1] = pull_position_1[1] + 0.08
    pull_position_1[2] = pull_position_1[2] + 0.01
    goto_pose(pull_position_1, handle_quaternion)

    pull_position_2 = handle_position.copy()
    pull_position_2[0] = pull_position_2[0] - 0.20
    pull_position_2[1] = pull_position_2[1] + 0.18
    pull_position_2[2] = pull_position_2[2] + 0.01
    goto_pose(pull_position_2, handle_quaternion)

    pull_position_3 = handle_position.copy()
    pull_position_3[0] = pull_position_3[0] - 0.28
    pull_position_3[1] = pull_position_3[1] + 0.30
    pull_position_3[2] = pull_position_3[2] + 0.01
    goto_pose(pull_position_3, handle_quaternion)

    open_gripper()

    retreat_position = pull_position_3.copy()
    retreat_position[2] = retreat_position[2] + 0.12
    goto_pose(retreat_position, handle_quaternion)
    return retreat_position


# step-1: Get a fresh observation and confirm the initial scene state.
with step_context("step-1", "Get a fresh observation and confirm the mug and closed microwave are visible", step_index=0):
    observation_initial = get_observation()
    if observation_initial is not None:
        RESULT["step-1"]["success"] = True
        RESULT["step-1"]["details"] = "Fresh observation acquired before acting."
    else:
        RESULT["step-1"]["details"] = "Failed to acquire initial observation."


# step-2: Localize the microwave handle and plan a grasp on it.
with step_context("step-2", "Localize the microwave handle and sample a grasp pose", step_index=1):
    handle_position = None
    handle_quaternion = None

    for handle_name in ["microwave_handle", "vertical_microwave_handle", "microwave_door_handle"]:
        try:
            handle_position, handle_quaternion = sample_grasp_pose(handle_name, use_multiview=True)
        except Exception as exc:
            handle_position = None
            handle_quaternion = None

        if handle_position is not None and handle_quaternion is not None:
            RESULT["step-2"]["success"] = True
            RESULT["step-2"]["details"] = "Sampled grasp pose for " + handle_name + "."
            break

    if handle_position is None:
        for handle_name in ["microwave_handle", "vertical_microwave_handle", "microwave_door_handle"]:
            pose_position, pose_quaternion = get_object_pose(handle_name, use_multiview=True)
            if pose_position is not None:
                handle_position = pose_position
                handle_quaternion = (0, 0, 1, 0)
                RESULT["step-2"]["success"] = True
                RESULT["step-2"]["details"] = "Used object pose fallback for " + handle_name + "."
                break

    if handle_position is None:
        RESULT["step-2"]["details"] = "Could not localize microwave handle."


# step-3: Open the microwave door by grasping and pulling the handle outward and leftward.
with step_context("step-3", "Open the microwave door by grasping the handle and pulling outward", step_index=2):
    if handle_position is not None and handle_quaternion is not None:
        open_microwave_door_from_handle(handle_position, handle_quaternion)
        RESULT["step-3"]["success"] = True
        RESULT["step-3"]["details"] = "Executed handle grasp and outward-left pull to open the door."
    else:
        RESULT["step-3"]["details"] = "Skipped because handle pose was unavailable."


# step-4: Release the microwave handle and move the arm to a safe intermediate pose.
with step_context("step-4", "Release the handle and return to a safe home configuration", step_index=3):
    open_gripper()
    goto_home_joint_position()
    RESULT["step-4"]["success"] = True
    RESULT["step-4"]["details"] = "Gripper opened and arm returned home to clear the open door."


# step-5: Localize and sample a grasp pose for the porcelain mug.
with step_context("step-5", "Localize and sample grasp pose for the porcelain mug", step_index=4):
    mug_position = None
    mug_quaternion = None

    for mug_name in ["porcelain_mug", "white_porcelain_mug", "mug"]:
        try:
            mug_position, mug_quaternion = sample_grasp_pose(mug_name, use_multiview=True)
        except Exception as exc:
            mug_position = None
            mug_quaternion = None

        if mug_position is not None and mug_quaternion is not None:
            RESULT["step-5"]["success"] = True
            RESULT["step-5"]["details"] = "Sampled grasp pose for " + mug_name + "."
            break

    if mug_position is None:
        for mug_name in ["porcelain_mug", "white_porcelain_mug", "mug"]:
            pose_position, pose_quaternion = get_object_pose(mug_name, use_multiview=True)
            if pose_position is not None:
                mug_position = pose_position
                mug_quaternion = (0, 0, 1, 0)
                RESULT["step-5"]["success"] = True
                RESULT["step-5"]["details"] = "Used object pose fallback for " + mug_name + "."
                break

    if mug_position is None:
        RESULT["step-5"]["details"] = "Could not localize porcelain mug."


# step-6: Pick up the porcelain mug from the tabletop.
with step_context("step-6", "Pick up the porcelain mug and lift it clear of the table", step_index=5):
    if mug_position is not None and mug_quaternion is not None:
        mug_lift_position = safe_pick_object(
            "porcelain_mug",
            mug_position,
            mug_quaternion,
            approach_height=0.10,
            lift_height=0.18,
        )
        RESULT["step-6"]["success"] = True
        RESULT["step-6"]["details"] = "Mug grasped and lifted from tabletop."
    else:
        RESULT["step-6"]["details"] = "Skipped because mug grasp pose was unavailable."


# step-7: Localize the open microwave interior placement region.
with step_context("step-7", "Localize the open microwave interior floor for placement", step_index=6):
    interior_position = None
    interior_quaternion = (0, 0, 1, 0)

    for interior_prompt in ["open microwave interior floor", "microwave cavity floor", "inside of the open microwave"]:
        try:
            interior_data = get_object_3d_points_and_masks_from_language(interior_prompt, use_multiview=True)
            interior_points = interior_data["points_3d"]
            if interior_points is not None and len(interior_points) > 0:
                interior_obb = get_oriented_bounding_box_from_3d_points(interior_points)
                interior_position = interior_obb["center"].copy()
                interior_position[2] = interior_position[2] + 0.035
                RESULT["step-7"]["success"] = True
                RESULT["step-7"]["details"] = "Computed placement center from segmented " + interior_prompt + "."
                break
        except Exception as exc:
            interior_position = None

    if interior_position is None:
        for interior_name in ["microwave_interior", "open_microwave_interior", "microwave_cavity"]:
            pose_position, pose_quaternion = get_object_pose(interior_name, use_multiview=True)
            if pose_position is not None:
                interior_position = pose_position.copy()
                interior_position[2] = interior_position[2] + 0.035
                RESULT["step-7"]["success"] = True
                RESULT["step-7"]["details"] = "Used pose fallback for " + interior_name + "."
                break

    if interior_position is None:
        RESULT["step-7"]["details"] = "Could not localize open microwave interior."


# step-8: Place the mug inside the open microwave and release it.
with step_context("step-8", "Place the mug inside the open microwave and release", step_index=7):
    if interior_position is not None:
        retreat_after_place = safe_place_object(
            interior_position,
            interior_quaternion,
            approach_height=0.12,
            retreat_height=0.14,
        )

        outward_retreat = retreat_after_place.copy()
        outward_retreat[0] = outward_retreat[0] - 0.12
        outward_retreat[2] = outward_retreat[2] + 0.04
        goto_pose(outward_retreat, interior_quaternion)

        RESULT["step-8"]["success"] = True
        RESULT["step-8"]["details"] = "Mug lowered to the interior floor center, released, and retreated."
    else:
        RESULT["step-8"]["details"] = "Skipped because interior placement pose was unavailable."


# step-9: Return to home and verify final state with a fresh observation.
with step_context("step-9", "Return home and verify final state by observation", step_index=8):
    goto_home_joint_position()
    final_observation = get_observation()
    if final_observation is not None:
        RESULT["step-9"]["success"] = True
        RESULT["step-9"]["details"] = "Returned home and acquired final observation for verification."
    else:
        RESULT["step-9"]["details"] = "Returned home but failed to acquire final observation."
API 返回的失败诊断原文
```json
{
  "visual_success": false,
  "failed_step": "step-3",
  "failure_mode": "partial_completion",
  "confidence": 0.88,
  "plan_issue": false,
  "plan_issue_reason": "",
  "subagent_skill_target": null,
  "subagent_skill_target_reason": "",
  "subagent_approaches": [],
  "edit_scale": "argument_level",
  "visual_predicate_status": [
    {
      "step_id": "step-1",
      "description": "Get a fresh observation and confirm the initial state: the porcelain mug is on the open tabletop in front-left of the microwave, and the microwave door appears closed with the vertical handle visible on the front-left side.",
      "visually_satisfied": true,
      "evidence": "The scene state is consistent with the initial condition: the mug is still on the tabletop near the microwave, and the microwave does not appear open in the final view. Observation acquisition itself is not directly visible, but the state described is visible."
    },
    {
      "step_id": "step-2",
      "description": "Localize the microwave handle and plan a grasp on it.",
      "visually_satisfied": false,
      "evidence": "Although the code sampled a microwave_handle grasp, the subsequent motion did not visibly engage the handle or open the door. The final state gives no visual evidence that a usable handle grasp pose was planned."
    },
    {
      "step_id": "step-3",
      "description": "Open the microwave door by grasping the handle and pulling the door outward until the interior is accessible.",
      "visually_satisfied": false,
      "evidence": "The microwave door is not open at the end, and the interior is not accessible. The code executed close_gripper and pull motions, but visually the handle/door was not effectively grasped or actuated."
    },
    {
      "step_id": "step-4",
      "description": "Release the microwave handle and move the arm to a safe intermediate pose away from the open door and table objects.",
      "visually_satisfied": true,
      "evidence": "By the final segment the gripper is not attached to the microwave handle and the arm has moved away from the handle/table region into a safe, non-contact posture. However, this occurred after a failed door-opening attempt."
    },
    {
      "step_id": "step-5",
      "description": "Localize and sample a grasp pose for the porcelain mug on the tabletop.",
      "visually_satisfied": false,
      "evidence": "The mug remains on the tabletop, and the final segment does not show a successful or stable mug grasp plan. The code sampled a mug grasp pose, but the later pick did not result in the mug being held."
    },
    {
      "step_id": "step-6",
      "description": "Pick up the porcelain mug from the tabletop.",
      "visually_satisfied": false,
      "evidence": "The mug is still on the tabletop at the end and is not held in the gripper. The wrist-camera terminal view also shows no mug captured between the fingers."
    },
    {
      "step_id": "step-7",
      "description": "Localize the open microwave interior / placement region.",
      "visually_satisfied": false,
      "evidence": "Because the microwave door never opened, there is no visible open cavity/floor placement region in the final state. Any interior localization attempted by the code was not grounded in an actually accessible microwave interior."
    },
    {
      "step_id": "step-8",
      "description": "Place the mug inside the open microwave and release it.",
      "visually_satisfied": false,
      "evidence": "The mug was not transported into the microwave; it remains outside on the tabletop. No release inside the microwave is visible."
    },
    {
      "step_id": "step-9",
      "description": "Return the arm to a safe home configuration and verify that the mug is inside the open microwave.",
      "visually_satisfied": false,
      "evidence": "The arm appears to end in a safe/home-like posture, but the final task state is wrong: the mug is not inside the microwave and the microwave is not open."
    }
  ],
  "policy_feedback": "argument_level: keep the same high-level sequence, but fix the targeted poses and add outcome checks before proceeding. In `open_microwave_door_from_handle`, the sampled `handle_position`/`handle_quaternion` did not produce a real handle grasp: the code called `close_gripper()` and executed the pull path, but the door stayed closed. Change the handle grasp target to the visible vertical handle surface/edge, use an approach axis normal to the microwave front so the fingers straddle the handle rather than closing beside it, and adjust the pull offsets in `pull_position_1/2/3` to follow the door’s hinge arc outward from the front-left handle. After this primitive, verify that the door is actually open before running mug pickup/interior placement. Also change `safe_pick_object` for the mug to target a stable rim/body or handle-aligned grasp with a slightly higher approach/closure pose; the current sampled mug pose led to an empty or ineffective grasp, with the mug still on the table. Do not trust the code’s RESULT success flags after issuing motions; they currently mark success even when the visual state did not change."
}
```

source: 0017_p568475_failure_diagnoser._query_llm_text.json

Agent 调用时间线 展开原始调用索引
#调用方耗时结果证据
1task_proposer.propose_novel_candidates15.9sstopembedded above
2environment_creator._generate_bddl3.8sstopembedded above
3planner.plan21.1sstopembedded above
4planner_verifier.verify_plan7.7sstopembedded above
5policy_writer._generate_once20.5sstopembedded above
6per_step_verifier._verify_step_package6.5sstopembedded above
7per_step_verifier._verify_step_package6.2sstopembedded above
8per_step_verifier._verify_step_package6.9sstopembedded above
9per_step_verifier._verify_step_package8.1sstopembedded above
10per_step_verifier._verify_step_package5.9sstopembedded above
11per_step_verifier._verify_step_package6.8sstopembedded above
12per_step_verifier._verify_step_package6.6sstopembedded above
13per_step_verifier._verify_step_package8.1sstopembedded above
14per_step_verifier._verify_step_package6.9sstopembedded above
15verifier._query_llm_json4.3sstopembedded above
16verifier._query_llm_json7.5sstopembedded above
17failure_diagnoser._query_llm_text23.6sstopembedded above
18task_proposer.propose_novel_candidates16.8sstopembedded above
19environment_creator._generate_bddl4.2sstopembedded above
20planner.plan23.3sstopembedded above
21planner_verifier.verify_plan11.0sstopembedded above
22policy_writer._generate_once30.8sstopembedded above
23per_step_verifier._verify_step_package9.3sstopembedded above
24per_step_verifier._verify_step_package9.5sstopembedded above
25per_step_verifier._verify_step_package10.9sstopembedded above
26per_step_verifier._verify_step_package11.1sstopembedded above
27per_step_verifier._verify_step_package12.0sstopembedded above
28verifier._query_llm_json7.1sstopembedded above
29skill_proposer.propose19.2sstopembedded above
30library._find_semantic_duplicate2.1sstopembedded above
31task_proposer.propose_novel_candidates18.1sstopembedded above
32environment_creator._generate_bddl3.6sstopembedded above
33planner.plan15.7sstopembedded above
34planner_verifier.verify_plan6.3sstopembedded above
35policy_writer._generate_once20.7sstopembedded above
36per_step_verifier._verify_step_package6.2sstopembedded above
37per_step_verifier._verify_step_package8.1sstopembedded above
38per_step_verifier._verify_step_package6.5sstopembedded above
39per_step_verifier._verify_step_package8.4sstopembedded above
40per_step_verifier._verify_step_package7.2sstopembedded above
41per_step_verifier._verify_step_package11.5sstopembedded above
42per_step_verifier._verify_step_package11.6sstopembedded above
43per_step_verifier._verify_step_package9.6sstopembedded above
44verifier._query_llm_json3.0sstopembedded above
45verifier._query_llm_json14.9sstopembedded above
46failure_diagnoser._query_llm_text18.3sstopembedded above
任务失败Handle perception + cookie grasp

Open top drawer · put cookies inside

repro_readme_task_cases

FAIL
最终判定执行 232 帧;抽屉未充分打开,cookies 未放入。严格谓词 0/2。
失败阶段Handle perception + cookie grasp

Causal trace audit

Failure Mode Analysis

confidence 0.86
判定两个独立 blocker:top-handle 点疑似落到下层;cookies 点云随后又产生零 grasp candidates。
最早失效点Step 2 information error (wrong handle point); step 4 first physical failure (top drawer not open)
近端物理原因

把手感知/抓取没有可靠建立 top-drawer 接触;之后 Contact-GraspNet 对非空 cookies segment 返回零候选并抛 AssertionError。

传播原因

代码没有检查 top drawer qpos,甚至用命令后的 handle 坐标虚构 cavity;异常后也没有规则盒体 grasp fallback。

AGPT-5.5 代码 / 状态机40%

无 open gate;用预测位置代替实际 cavity;没有 fallback/恢复,局部失败被放大全局。

BLIBERO / TCP 标定5%

命令距离已足够,缺少“数值再大一点即可”的证据。

CMolmo / SAM3 感知25%

五案中唯一有直接 wrong-part point 证据的案例;SAM mask 未保存,故不把 25% 写成确定 100%。

D抓取 / 3-D / 控制接口30%

cookies 非空点云零候选是直接 blocker;把手 grasp 也可能未建立有效接触。

决定性证据
  1. Molmo 对 top-drawer handle 返回(567,394)→图像约(454,202),初始帧上落在三把手的下部、接近底层,而非 top handle。
  2. 真实 slider 方向约为 -Y,代码 0.23 m pull 已超过约 0.14–0.16 m open range,因此不支持“只是距离 magic number 不够”。
  3. native Open(top_region)=false;视频显示机器人接近柜体,但 top drawer 未达到 open 条件。
  4. step 6 traceback:sample_grasp_pose(cookies) → AssertionError: No grasp candidates found;非空 segment 已进入 Contact-GraspNet。
仍不能确认

需保存 SAM mask 并记录 top/middle/bottom qpos,才能确认错误点最终分割/拉动的是哪一层。

最小反事实实验

oracle top-handle mask + 当前 pull;当前 cookies mask + 规则盒体 top-down grasp;分别测试可证明 C 与 D 是独立 blocker。

责任百分比用于表达该条 trace 的工程因果权重,不是统计概率;没有受控重放的结论标为 strongly supported,而非 confirmed。

01

Task setting

Kitchen tabletop; wooden cabinet top drawer starts closed; cookies box starts on the table. Goal predicates: Open(cabinet_top_region) AND In(cookies, cabinet_top_region).

02

失败根因

两个独立 blocker:top-handle 点疑似落到下层;cookies 点云随后又产生零 grasp candidates。

Evidence

视觉证据

iter002_attempt0_failed.mp4
Why

证据与推理

  1. 第 3 步到达把手被判为成功,但第 4 步抽屉打开被判失败。
  2. Contact-GraspNet 对 cookies segment 返回零候选,运行记录为 failure_mode=code_bug。
  3. 最终状态明确为 Open(top_drawer)=false、In(cookies, top_drawer)=false。
03

真实 API 审计

model=gpt-5.5 · elapsed=30.8s · finish_reason=stop · source: 0022_p568475_policy_writer._generate_once.json

发送给 Policy Writer 的完整 prompt
===== SYSTEM =====
You are a deterministic policy writer for a code-as-policy robot system. Write ONLY Python code. Do not use while True loops. Use only the provided imported primitive functions and learned helper functions.

===== USER =====
You are a deterministic policy writer for a code-as-policy robot system.

Write Python code that executes the following plan.

AVAILABLE IMPORTED FUNCTIONS (use ONLY these, not env.<method>):
close_gripper, get_object_3d_points_and_masks_from_language, get_object_pose, get_observation, get_oriented_bounding_box_from_3d_points, goto_home_joint_position, goto_pose, open_gripper, sample_grasp_pose

API DOCUMENTATION:
get_observation() -> dict[str, typing.Any]
  Doc:
    Get the observation of the environment.
    Returns:
        observation:
            A dictionary containing the observation of the environment.
            The dictionary contains the following keys:
            - ["agentview"]["images"]["rgb"]: Current color camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["agentview"]["images"]["depth"]: Current depth camera image as a numpy array of shape (H, W), dtype float32.
            - ["agentview"]["intrinsics"]: Camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["agentview"]["pose_mat"]: Camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot0_eye_in_hand"]["images"]["rgb"]: Current wrist camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["robot0_eye_in_hand"]["images"]["depth"]: Current wrist camera depth image as a numpy array of shape (H, W), dtype float32.
            - ["robot0_eye_in_hand"]["intrinsics"]: Wrist camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["robot0_eye_in_hand"]["pose_mat"]: Wrist camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot_cartesian_pos"]: Current end-effector (panda_hand) pose in the robot/world frame as a numpy array of shape (8,), dtype float64. The first 3 elements are the robot's end-effector XYZ, the next 4 elements are the quaternion wxyz, and the last element is the gripper position normalized, 0 (closed) to 1 (open).
            - ["robot_joint_pos"]: Current joint positions as a numpy array of shape (7,), dtype float64. The last element is the gripper position normalized, 0 (closed) to 1 (open).

get_object_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray] | tuple[None, None]
  Doc:
    Get the pose of an object in the environment from a natural language description.
    The quaternion from get_object_pose may be unreliable, so disregard it and use the grasp
    pose quaternion OR (0, 0, 1, 0) wxyz as the gripper down orientation if using this for
    placement position.
    It is possible that get_object_pose is sometimes unreliable and will return None for both
    position and quaternion.
    
    Args:
        object_name: The name of the object to get the pose of, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

sample_grasp_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray]
  Doc:
    Sample a grasp pose for an object in the environment from a natural language description.
    Uses multiview point clouds and plan_grasp_from_point_clouds for more reliable grasp planning.
    Do use the grasp sample quaternion from sample_grasp_pose.
    
    Args:
        object_name: The name of the object to sample a grasp pose for, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

goto_pose(position: numpy.ndarray, quaternion_wxyz: numpy.ndarray, z_approach: float = 0.0) -> None
  Doc:
    Go to pose using Inverse Kinematics.
    There is no need to call a second goto_pose with the same position and quaternion_wxyz after calling it with z_approach.
    Args:
        position: (3,) XYZ in meters.
        quaternion_wxyz: (4,) WXYZ unit quaternion.
        z_approach: (float) Z-axis distance offset for goto_pose insertion approach motion. Will first arrive at position + z_approach meters in Z-axis before moving to the requested pose. Useful for more precise grasp approaches. Default is 0.0.
    Returns:
        None

open_gripper() -> None
  Doc:
    Open gripper fully.
    
    Args:
        None

close_gripper() -> None
  Doc:
    Close gripper fully.
    
    Args:
        None

get_oriented_bounding_box_from_3d_points(points: numpy.ndarray) -> dict[str, typing.Any]
  Doc:
    Get the oriented bounding box from 3D points.
    
    Args:
        points: np.ndarray: The 3D points to get the oriented bounding box from.
            Shape: (N, 3), dtype float64.
    
    Returns:
        dict[str, Any]: The oriented bounding box. The dictionary contains the following keys:
            - "center": np.ndarray: The center of the oriented bounding box in point cloud frame.
            - "extent": np.ndarray: The extent of the oriented bounding box.
            - "R": np.ndarray: The rotation matrix of the oriented bounding box in point cloud frame.
    
    Example:
        >>> points = np.random.randn((100, 3))
        >>> obb = get_oriented_bounding_box_from_3d_points(points)

get_object_3d_points_and_masks_from_language(text_prompt: str, use_multiview: bool = True) -> dict[str, typing.Any]
  Doc:
    Segment an object using text prompt across multiple views (agentview and wrist).
    
    Uses Molmo to locate the object in both camera views, then SAM3 for
    segmentation. Returns the masks and 3D points that appear in both views.
    
    Args:
        text_prompt: Text description of the object to segment.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation.
        
    Returns:
        dict containing:
            - "agentview_mask": np.ndarray of shape (H, W), dtype bool
            - "wrist_mask": np.ndarray of shape (H, W), dtype bool (None if single view)
            - "points_3d": np.ndarray of shape (N, 3), 3D points in world frame
            - "agentview_score": float, SAM3 confidence score
            - "wrist_score": float, SAM3 confidence score (None if single view)

goto_home_joint_position() -> None
  Doc:
    Return the arm to its reset joint configuration with high manipulability

LEARNED HELPER FUNCTION REFERENCES (already defined and callable — use them directly):
No learned helper functions available yet.

REQUIREMENTS:
- Use the primitive functions listed in AVAILABLE IMPORTED FUNCTIONS above AND any LEARNED HELPER FUNCTION REFERENCES shown above.
- The learned helper functions are pre-defined and available in your execution scope. Call them directly.
- Do NOT invent wrapper functions on env or low_level_env.
- Do NOT use while True loops or any unbounded retry patterns. Use bounded for loops instead.
- Set RESULT to a structured dict describing success/failure for each step.
- Add explicit comments before each plan step.
- Wrap the executable body for EACH plan step in the runtime marker context
  `with step_context("<step id>", "<step description>", step_index=<0-based index>):`.
  This is a logging marker, not a robot primitive. It lets the verifier save
  exact per-step API traces, motion frame ranges, and intermediate artifacts.
- Define reusable sub-functions for non-trivial skill sequences that could be added to the skill library.
- On retries, follow the diagnoser's requested edit scale. If a top-of-retry "## EDIT SCALE: argument-level" banner is present (or the prose says argument-level), keep the same primitive/helper call sequence and change only the named arguments first (target text, verify_label, pose/offset, approach axis, release height, retry count, or gate threshold). Rewrite helper bodies, replace primitives, or add new wrappers only when the banner / diagnosis says rewrite-needed because arguments cannot express the fix, the API/function is wrong for the task, the sequence is structurally wrong, or there is a real code/logic bug.


IMPORTANT: Use ONLY functions from the AVAILABLE IMPORTED FUNCTIONS list and LEARNED HELPER FUNCTION REFERENCES above.
Do NOT call any function not in those lists. Check the API DOCUMENTATION for correct function signatures.
Extract object names from the GOAL description below.

General rules:
- Read the API DOCUMENTATION carefully for the correct function signatures and return types.
- When retry feedback names a primitive/helper call, preserve that call and tune its arguments before changing the overall code structure, unless the feedback explicitly calls for a larger rewrite.
- For pick-and-place: perceive object location, move to grasp pose, close gripper, move to target, open gripper. Use the available perception functions to locate objects.
- Use bounded for loops (not while True) for retry patterns.
- For multi-step tasks (pick A then place on B), chain the patterns sequentially.
- Never leave a successfully grasped object suspended because a pre-release wrist check failed. Once the placement target has been localized, execute a cautious descend, open the gripper, retreat, and then verify the final resting state.
- NumPy array truthiness: localization primitives often return ndarrays or lists of candidates. NEVER write `if pos:` or `if not result:` on an ndarray — raises "truth value of an array is ambiguous". Instead use `if pos is None` / `if len(pos) == 0` / `if result.get("verified")` on explicit scalars. This pattern has burned many past attempts.



# === TASK-SPECIFIC INPUTS BELOW (vary per attempt; everything above is stable for cache reuse) ===

SCENE: i_want_to_open_the_wooden_cabinet_top_drawer_and_put_the_coo
GOAL: I want to open the wooden cabinet top drawer and put the cookies inside it.
OBJECT SCOPE: {}

PLAN:
- step-1: Get a fresh observation and confirm the scene state: the wooden cabinet is on the right side of the table, the top drawer appears closed, its handle is visible on the cabinet front facing the robot, and the cookies box is on the open tabletop near the front-center area. | skills: get_observation | notes: Use the current agent-view image as the primary scene check. The cabinet top drawer must be opened before attempting to place the cookies inside.
- step-2: Localize the wooden cabinet top drawer handle using language-based segmentation or pose estimation. If direct pose estimation fails, segment the cabinet handle/top drawer handle and compute an approximate handle center from the 3D points. | skills: get_object_pose, get_object_3d_points_and_masks_from_language, get_oriented_bounding_box_from_3d_points | notes: Try object names such as wooden_cabinet_top_drawer_handle, top_drawer_handle, or wooden_cabinet_handle. The visible handle is on the cabinet front/left-facing side in the image, near the robot.
- step-3: Open the gripper, move to a grasp pose on the top drawer handle, and close the gripper around the handle. | skills: open_gripper, sample_grasp_pose, goto_pose, close_gripper | notes: ARTICULATED OBJECT GRASP/PULL NOTES: (a) APPROACH DIRECTION: approach the top drawer handle from the front of the cabinet, perpendicular to the drawer face, so the gripper comes toward the handle from open tabletop space rather than from above or from the cabinet side. (b) PULL DIRECTION: after grasping, pull the handle outward away from the cabinet body, approximately along the drawer's sliding axis toward the robot/table center, not upward or sideways. (c) GRASP SELECTION CRITERION: choose a grasp whose approach axis is roughly perpendicular to the drawer front and whose fingers can wrap around the horizontal/vertical handle without colliding with the cabinet face; reject top-down grasps that pinch the handle against the drawer front.
- step-4: Pull the top drawer open by moving the grasped handle outward along the drawer sliding direction, then release the handle once the drawer is sufficiently open. | skills: goto_pose, open_gripper | notes: This requires an articulated drawer-opening motion primitive implemented from available goto_pose commands: maintain the grasp orientation and translate the end effector outward from the cabinet face by an estimated 0.15-0.25 m, monitoring for collision. Pull direction is away from the cabinet body toward the open table/robot side. Stop when the top drawer cavity is accessible.
- step-5: Move the arm away from the opened drawer and get a new observation to verify that the top drawer is open and to localize the open drawer cavity/interior placement region. | skills: goto_home_joint_position, get_observation, get_object_pose, get_object_3d_points_and_masks_from_language, get_oriented_bounding_box_from_3d_points | notes: If the drawer still appears closed or only slightly open, repeat the pulling motion before picking the cookies. The placement target should be the open interior of the top drawer, not the closed drawer front or the cabinet top.
- step-6: Localize the cookies box on the tabletop and sample a grasp pose for it. | skills: get_object_pose, sample_grasp_pose | notes: The cookies are visible on the front-center tabletop as a small rectangular box. Use the object name cookies or cookies_box. Prefer a grasp on the box sides with a top-down or slightly angled approach that avoids dragging it across the table.
- step-7: Pick up the cookies: open the gripper, approach the sampled cookies grasp pose from above, move to the grasp pose, close the gripper, and lift the cookies clear of the tabletop. | skills: open_gripper, goto_pose, close_gripper | notes: Use the quaternion returned by sample_grasp_pose for the grasp. Use a small positive z_approach for the approach motion, then lift vertically after closing to avoid colliding with the table.
- step-8: Move the held cookies to a placement pose above the open top drawer interior. | skills: goto_pose | notes: Use the localized open drawer cavity center as the XY placement target. Set the Z coordinate safely above the drawer rim first, then descend into the drawer enough for stable release. Use a gripper-down placement orientation such as quaternion (0, 0, 1, 0) if object orientation is not critical.
- step-9: Release the cookies inside the open top drawer, then lift the gripper away from the drawer. | skills: open_gripper, goto_pose | notes: Release only after the cookies are positioned inside the open drawer cavity. After opening the gripper, lift vertically to avoid disturbing the drawer or knocking the cookies out.
- step-10: Get a final observation to verify the goal: the wooden cabinet top drawer is open and the cookies are inside it. | skills: get_observation | notes: The goal does not require closing the drawer; leave it open with the cookies inside.





## LESSONS FROM PAST FAILURES (advisory — NOT ground truth)
--- RAW FAILURE EPISODES (most relevant) ---
1. Task "i_want_to_open_the_microwave_and_put_the_porcelain_mug_insid": partial_completion -- [attempt 1] argument_level: keep the same high-level sequence, but fix the targeted poses and add outcome checks before proceeding. In `open_microwave_door_from_handle`, the sampled `handle_position`/`handle_quaternion` did not produce a real handle grasp: the code called `close_gripper()` and executed the pull path, but the door stayed closed. Change the handle grasp target to the visible vertical handle surface/edge, use an approach axis normal to the microwave front so the fingers straddle the handle rather than closing beside it, and adjust the pull offsets in `pull_position_1/2/3` to follow the door’s hinge arc outward from the front-left handle. After this primitive, verify that the door is actually open before running mug pickup/interior placement. Also change `safe_pick_object` for the mug to target a stable rim/body or handle-aligned grasp with a slightly higher approach/closure pose; the current sampled mug pose led to an empty or ineffective grasp, with the mug still on the table. Do not trust the code’s RESULT success flags after issuing motions; they currently mark success even when the visual state did not change.
   Failed code (diagnosed step step-3):
```python
# step-3: Open the microwave door by grasping and pulling the handle outward and leftward.
with step_context("step-3", "Open the microwave door by grasping the handle and pulling outward", step_index=2):
    if handle_position is not None and handle_quaternion is not None:
        open_microwave_door_from_handle(handle_position, handle_quaternion)
        RESULT["step-3"]["success"] = True
        RESULT["step-3"]["details"] = "Executed handle grasp and outward-left pull to open the door."
    else:
        RESULT["step-3"]["details"] = "Skipped because handle pose was unavailable."
```
Do NOT repeat the failed approaches above. Apply the lessons and try a different strategy.
The block above (if non-empty) lists distilled lessons in "WHEN ... | WRONG ... | DO ..." form, each followed by a metadata footer like `(confidence=0.80, applied=5× helped=1×, last_helped=iter4 (2 iters ago), distilled=iter2 (4 iters ago))`. Use that footer to weigh how much to trust each lesson.

PRIORITY ORDER when signals conflict:
  0. The SUB-AGENT DIRECTIVE block above (if non-empty) — this is the parallel sub-agent's committed approach assignment, a HARD constraint, and dominates every other guidance source below.
  1. The current attempt's RETRY CONTEXT (diagnoser feedback + visual evidence + PREVIOUS CODE below) — this saw what actually happened on this exact task and is ground truth for what to fix.
  2. A lesson with high reliability (helped/applied ≥ 0.5 with applied ≥ 2) AND recent `last_helped` (≤ 2 iters ago) — strong prior, follow its DO recipe.
  3. A lesson with low reliability (helped/applied < 0.3) OR stale (`last_helped=never` or ≥ 5 iters ago) — background prior only; don't let it override the current diagnosis.

Empty block means no relevant prior failures.

API 返回并实际执行的 robot control code
RESULT = {
    "step-1": {"success": False, "details": ""},
    "step-2": {"success": False, "details": ""},
    "step-3": {"success": False, "details": ""},
    "step-4": {"success": False, "details": ""},
    "step-5": {"success": False, "details": ""},
    "step-6": {"success": False, "details": ""},
    "step-7": {"success": False, "details": ""},
    "step-8": {"success": False, "details": ""},
    "step-9": {"success": False, "details": ""},
    "step-10": {"success": False, "details": ""},
}


def localize_by_pose_or_points(object_names):
    best_position = None
    best_quaternion = None
    best_obb = None
    best_name = None

    for object_name in object_names:
        position, quaternion = get_object_pose(object_name, use_multiview=True)
        if position is not None:
            best_position = position
            best_quaternion = quaternion
            best_name = object_name
            break

    if best_position is None:
        for object_name in object_names:
            seg = get_object_3d_points_and_masks_from_language(object_name, use_multiview=True)
            points = seg.get("points_3d")
            if points is not None and len(points) > 0:
                obb = get_oriented_bounding_box_from_3d_points(points)
                best_position = obb["center"]
                best_obb = obb
                best_name = object_name
                break

    return best_position, best_quaternion, best_obb, best_name


def compute_xy_unit_direction(from_position, to_position):
    direction = from_position.copy()
    direction[0] = to_position[0] - from_position[0]
    direction[1] = to_position[1] - from_position[1]
    direction[2] = 0.0
    length = (direction[0] ** 2 + direction[1] ** 2) ** 0.5
    if length < 0.001:
        direction[0] = -1.0
        direction[1] = 0.0
        direction[2] = 0.0
    else:
        direction[0] = direction[0] / length
        direction[1] = direction[1] / length
        direction[2] = 0.0
    return direction


def execute_drawer_handle_grasp(handle_names, fallback_position):
    grasp_position = None
    grasp_quaternion = None
    grasp_name = None

    for handle_name in handle_names:
        position, quaternion = sample_grasp_pose(handle_name, use_multiview=True)
        if position is not None and quaternion is not None:
            grasp_position = position
            grasp_quaternion = quaternion
            grasp_name = handle_name
            break

    if grasp_position is None:
        grasp_position = fallback_position
        grasp_quaternion = (0.0, 0.0, 1.0, 0.0)
        grasp_name = "fallback_handle_center"

    open_gripper()
    goto_pose(grasp_position, grasp_quaternion, z_approach=0.06)
    close_gripper()

    return grasp_position, grasp_quaternion, grasp_name


def pull_drawer_open_from_grasp(start_position, grasp_quaternion, pull_direction):
    pull_position_1 = start_position.copy()
    pull_position_1[0] = pull_position_1[0] + pull_direction[0] * 0.08
    pull_position_1[1] = pull_position_1[1] + pull_direction[1] * 0.08

    pull_position_2 = start_position.copy()
    pull_position_2[0] = pull_position_2[0] + pull_direction[0] * 0.16
    pull_position_2[1] = pull_position_2[1] + pull_direction[1] * 0.16

    pull_position_3 = start_position.copy()
    pull_position_3[0] = pull_position_3[0] + pull_direction[0] * 0.23
    pull_position_3[1] = pull_position_3[1] + pull_direction[1] * 0.23

    goto_pose(pull_position_1, grasp_quaternion)
    goto_pose(pull_position_2, grasp_quaternion)
    goto_pose(pull_position_3, grasp_quaternion)
    open_gripper()

    retreat_position = pull_position_3.copy()
    retreat_position[2] = retreat_position[2] + 0.10
    goto_pose(retreat_position, grasp_quaternion)

    return pull_position_3


def pick_object_with_sampled_grasp(object_names):
    object_position = None
    object_quaternion = None
    object_name_used = None

    for object_name in object_names:
        pose_position, pose_quaternion = get_object_pose(object_name, use_multiview=True)
        if pose_position is not None:
            object_position = pose_position
            object_name_used = object_name
            break

    grasp_position = None
    grasp_quaternion = None
    for object_name in object_names:
        position, quaternion = sample_grasp_pose(object_name, use_multiview=True)
        if position is not None and quaternion is not None:
            grasp_position = position
            grasp_quaternion = quaternion
            object_name_used = object_name
            break

    if grasp_position is None:
        return None, None, object_position, object_name_used

    open_gripper()
    goto_pose(grasp_position, grasp_quaternion, z_approach=0.08)
    close_gripper()

    lift_position = grasp_position.copy()
    lift_position[2] = lift_position[2] + 0.16
    goto_pose(lift_position, grasp_quaternion)

    return grasp_position, grasp_quaternion, object_position, object_name_used


# step-1: Get a fresh observation and confirm the initial scene state.
with step_context("step-1", "Get fresh observation and confirm cabinet, closed top drawer handle, and cookies on tabletop", step_index=0):
    observation_initial = get_observation()
    RESULT["step-1"]["success"] = observation_initial is not None
    RESULT["step-1"]["details"] = "Fresh observation captured for initial scene check."

# step-2: Localize the wooden cabinet top drawer handle.
with step_context("step-2", "Localize wooden cabinet top drawer handle using pose estimation or segmentation", step_index=1):
    handle_names = [
        "wooden_cabinet_top_drawer_handle",
        "top_drawer_handle",
        "wooden_cabinet_handle",
        "cabinet_top_drawer_handle",
    ]
    handle_position, handle_quaternion, handle_obb, handle_name_used = localize_by_pose_or_points(handle_names)

    cabinet_position, cabinet_quaternion, cabinet_obb, cabinet_name_used = localize_by_pose_or_points([
        "wooden_cabinet",
        "cabinet",
    ])

    if handle_position is not None:
        RESULT["step-2"]["success"] = True
        RESULT["step-2"]["details"] = {
            "handle_name_used": handle_name_used,
            "cabinet_name_used": cabinet_name_used,
        }
    else:
        RESULT["step-2"]["details"] = "Failed to localize the top drawer handle."

# step-3: Open gripper, move to a grasp pose on the handle, and close the gripper.
with step_context("step-3", "Grasp the top drawer handle from the front", step_index=2):
    if handle_position is not None:
        drawer_grasp_position, drawer_grasp_quaternion, drawer_grasp_name = execute_drawer_handle_grasp(
            handle_names,
            handle_position,
        )
        RESULT["step-3"]["success"] = drawer_grasp_position is not None and drawer_grasp_quaternion is not None
        RESULT["step-3"]["details"] = {
            "drawer_grasp_name": drawer_grasp_name,
            "note": "Executed handle grasp; sampled grasp pose used when available.",
        }
    else:
        drawer_grasp_position = None
        drawer_grasp_quaternion = None
        RESULT["step-3"]["details"] = "Skipped because handle localization failed."

# step-4: Pull the top drawer open outward along the drawer sliding direction, then release.
with step_context("step-4", "Pull top drawer open along sliding direction and release handle", step_index=3):
    if drawer_grasp_position is not None and drawer_grasp_quaternion is not None:
        if cabinet_position is not None:
            pull_direction = compute_xy_unit_direction(cabinet_position, handle_position)
        else:
            table_center_reference = handle_position.copy()
            table_center_reference[0] = 0.0
            table_center_reference[1] = 0.0
            table_center_reference[2] = handle_position[2]
            pull_direction = compute_xy_unit_direction(handle_position, table_center_reference)

        opened_handle_position = pull_drawer_open_from_grasp(
            drawer_grasp_position,
            drawer_grasp_quaternion,
            pull_direction,
        )
        RESULT["step-4"]["success"] = True
        RESULT["step-4"]["details"] = {
            "pull_distance_m": 0.23,
            "released_handle": True,
        }
    else:
        opened_handle_position = None
        pull_direction = None
        RESULT["step-4"]["details"] = "Skipped because drawer handle was not grasped."

# step-5: Move away, observe, and localize open drawer cavity/interior placement region.
with step_context("step-5", "Verify open drawer and localize open top drawer interior placement region", step_index=4):
    goto_home_joint_position()
    observation_after_open = get_observation()

    cavity_names = [
        "open_top_drawer_interior",
        "wooden_cabinet_top_drawer_interior",
        "open_drawer_cavity",
        "top_drawer_cavity",
        "inside_top_drawer",
    ]
    cavity_position, cavity_quaternion, cavity_obb, cavity_name_used = localize_by_pose_or_points(cavity_names)

    if cavity_position is None and opened_handle_position is not None and pull_direction is not None:
        cavity_position = opened_handle_position.copy()
        cavity_position[0] = cavity_position[0] - pull_direction[0] * 0.08
        cavity_position[1] = cavity_position[1] - pull_direction[1] * 0.08
        cavity_position[2] = cavity_position[2] + 0.04
        cavity_name_used = "estimated_from_opened_handle"

    if cavity_position is not None:
        RESULT["step-5"]["success"] = True
        RESULT["step-5"]["details"] = {
            "cavity_name_used": cavity_name_used,
            "observation_captured": observation_after_open is not None,
        }
    else:
        RESULT["step-5"]["details"] = "Could not localize or estimate open drawer cavity."

# step-6: Localize the cookies box and sample a grasp pose.
with step_context("step-6", "Localize cookies box and sample grasp pose", step_index=5):
    cookies_names = [
        "cookies_box",
        "cookies",
        "cookie_box",
    ]

    cookies_pose_position = None
    cookies_pose_quaternion = None
    cookies_pose_name = None
    for cookies_name in cookies_names:
        position, quaternion = get_object_pose(cookies_name, use_multiview=True)
        if position is not None:
            cookies_pose_position = position
            cookies_pose_quaternion = quaternion
            cookies_pose_name = cookies_name
            break

    cookies_grasp_position = None
    cookies_grasp_quaternion = None
    cookies_grasp_name = None
    for cookies_name in cookies_names:
        position, quaternion = sample_grasp_pose(cookies_name, use_multiview=True)
        if position is not None and quaternion is not None:
            cookies_grasp_position = position
            cookies_grasp_quaternion = quaternion
            cookies_grasp_name = cookies_name
            break

    RESULT["step-6"]["success"] = cookies_grasp_position is not None and cookies_grasp_quaternion is not None
    RESULT["step-6"]["details"] = {
        "cookies_pose_name": cookies_pose_name,
        "cookies_grasp_name": cookies_grasp_name,
    }

# step-7: Pick up the cookies from the tabletop and lift clear of the table.
with step_context("step-7", "Pick up cookies box and lift it clear of tabletop", step_index=6):
    if cookies_grasp_position is not None and cookies_grasp_quaternion is not None:
        open_gripper()
        goto_pose(cookies_grasp_position, cookies_grasp_quaternion, z_approach=0.08)
        close_gripper()

        cookies_lift_position = cookies_grasp_position.copy()
        cookies_lift_position[2] = cookies_lift_position[2] + 0.18
        goto_pose(cookies_lift_position, cookies_grasp_quaternion)

        RESULT["step-7"]["success"] = True
        RESULT["step-7"]["details"] = "Executed cookies grasp and vertical lift."
    else:
        cookies_lift_position = None
        RESULT["step-7"]["details"] = "Skipped because cookies grasp pose was unavailable."

# step-8: Move the held cookies to a safe pose above the open drawer interior, then descend for placement.
with step_context("step-8", "Move held cookies above open drawer interior and descend into drawer", step_index=7):
    if cookies_lift_position is not None and cavity_position is not None:
        placement_quaternion = (0.0, 0.0, 1.0, 0.0)

        placement_above_position = cavity_position.copy()
        placement_above_position[2] = cavity_position[2] + 0.18

        placement_release_position = cavity_position.copy()
        placement_release_position[2] = cavity_position[2] + 0.06

        goto_pose(placement_above_position, placement_quaternion)
        goto_pose(placement_release_position, placement_quaternion)

        RESULT["step-8"]["success"] = True
        RESULT["step-8"]["details"] = "Moved cookies above the open drawer cavity and descended to release height."
    else:
        placement_above_position = None
        placement_release_position = None
        placement_quaternion = (0.0, 0.0, 1.0, 0.0)
        RESULT["step-8"]["details"] = "Skipped because cookies were not lifted or drawer cavity was unavailable."

# step-9: Release cookies inside the open top drawer and lift away.
with step_context("step-9", "Release cookies inside open top drawer and retreat vertically", step_index=8):
    if placement_release_position is not None:
        open_gripper()

        retreat_after_place_position = placement_release_position.copy()
        retreat_after_place_position[2] = retreat_after_place_position[2] + 0.18
        goto_pose(retreat_after_place_position, placement_quaternion)

        RESULT["step-9"]["success"] = True
        RESULT["step-9"]["details"] = "Opened gripper inside drawer and retreated upward."
    else:
        RESULT["step-9"]["details"] = "Skipped because placement release pose was unavailable."

# step-10: Get final observation to verify drawer is open and cookies are inside.
with step_context("step-10", "Final observation verifying cookies inside open wooden cabinet top drawer", step_index=9):
    final_observation = get_observation()
    RESULT["step-10"]["success"] = final_observation is not None
    RESULT["step-10"]["details"] = "Final observation captured; drawer should remain open with cookies released inside."
Agent 调用时间线 展开原始调用索引
#调用方耗时结果证据
1task_proposer.propose_novel_candidates15.9sstopembedded above
2environment_creator._generate_bddl3.8sstopembedded above
3planner.plan21.1sstopembedded above
4planner_verifier.verify_plan7.7sstopembedded above
5policy_writer._generate_once20.5sstopembedded above
6per_step_verifier._verify_step_package6.5sstopembedded above
7per_step_verifier._verify_step_package6.2sstopembedded above
8per_step_verifier._verify_step_package6.9sstopembedded above
9per_step_verifier._verify_step_package8.1sstopembedded above
10per_step_verifier._verify_step_package5.9sstopembedded above
11per_step_verifier._verify_step_package6.8sstopembedded above
12per_step_verifier._verify_step_package6.6sstopembedded above
13per_step_verifier._verify_step_package8.1sstopembedded above
14per_step_verifier._verify_step_package6.9sstopembedded above
15verifier._query_llm_json4.3sstopembedded above
16verifier._query_llm_json7.5sstopembedded above
17failure_diagnoser._query_llm_text23.6sstopembedded above
18task_proposer.propose_novel_candidates16.8sstopembedded above
19environment_creator._generate_bddl4.2sstopembedded above
20planner.plan23.3sstopembedded above
21planner_verifier.verify_plan11.0sstopembedded above
22policy_writer._generate_once30.8sstopembedded above
23per_step_verifier._verify_step_package9.3sstopembedded above
24per_step_verifier._verify_step_package9.5sstopembedded above
25per_step_verifier._verify_step_package10.9sstopembedded above
26per_step_verifier._verify_step_package11.1sstopembedded above
27per_step_verifier._verify_step_package12.0sstopembedded above
28verifier._query_llm_json7.1sstopembedded above
29skill_proposer.propose19.2sstopembedded above
30library._find_semantic_duplicate2.1sstopembedded above
31task_proposer.propose_novel_candidates18.1sstopembedded above
32environment_creator._generate_bddl3.6sstopembedded above
33planner.plan15.7sstopembedded above
34planner_verifier.verify_plan6.3sstopembedded above
35policy_writer._generate_once20.7sstopembedded above
36per_step_verifier._verify_step_package6.2sstopembedded above
37per_step_verifier._verify_step_package8.1sstopembedded above
38per_step_verifier._verify_step_package6.5sstopembedded above
39per_step_verifier._verify_step_package8.4sstopembedded above
40per_step_verifier._verify_step_package7.2sstopembedded above
41per_step_verifier._verify_step_package11.5sstopembedded above
42per_step_verifier._verify_step_package11.6sstopembedded above
43per_step_verifier._verify_step_package9.6sstopembedded above
44verifier._query_llm_json3.0sstopembedded above
45verifier._query_llm_json14.9sstopembedded above
46failure_diagnoser._query_llm_text18.3sstopembedded above
任务失败Milk grasp

Put milk on plate

repro_readme_task_cases

FAIL
最终判定执行 197 帧;milk 最终位于 plate 外。结构化几何/contact verifier 判定 0/1。
失败阶段Milk grasp

Causal trace audit

Failure Mode Analysis

confidence 0.78
判定首个物理失败是 milk 抓取/抬升;不是 plate 放置,也没有证据表明对象被识别错。
最早失效点Step 5 · gripper closes and lifts empty; milk remains at its initial pose
近端物理原因

单一倾斜 Contact-GraspNet candidate 与 TCP/approach 约定没有形成奶盒宽侧稳定夹持。

传播原因

代码未验证 milk 是否随动,空夹继续到 plate;固定 release z=plate_z+0.055 是潜在后续缺陷,但本次尚未真正测试。

AGPT-5.5 代码 / 状态机35%

API 返回首个结果即使用;close+lift 后直接 success;没有 retry 或 holding gate。

BLIBERO / TCP 标定15%

z_approach 实际沿倾斜姿态局部轴,0.06 m 主要变成约 5.8 cm 横移;可能存在 frame/TCP 标定问题。

CMolmo / SAM3 感知5%

两个语义点与运动目标都正确;仅因 raw mask 未保存保留 5%。

D抓取 / 3-D / 控制接口45%

只暴露 argmax candidate,无法表达 broad-side 约束;无 score/top-k/contact/actual-TCP 观测。

决定性证据
  1. Molmo milk point (471,462) 与 plate point (562,812) 均在正确轮廓;没有 wrong-object 轨迹。
  2. grasp position=[0.4995,-0.0359,0.1012] 与 milk 真值中心大致吻合,但 quaternion 明显倾斜。
  3. step 5 verifier failed, confidence=0.95;最终 milk xy=[-0.1794,-0.0409] 仍在 BDDL 初始范围。
  4. structured verifier:xy_inside=false、contact=false;视频显示夹爪空手到达 plate。
仍不能确认

没有 offset sweep,故 D(候选本身)与 B(同一候选执行偏差)的精确比例仍是工程判断。

最小反事实实验

oracle broad-side grasp + 当前控制、当前 candidate + TCP sweep、oracle mask + 当前 Contact-GraspNet 三组对照。

责任百分比用于表达该条 trace 的工程因果权重,不是统计概率;没有受控重放的结论标为 strongly supported,而非 confirmed。

01

Task setting

Uncluttered kitchen tabletop; upright milk carton near center; plate at front-right. Goal predicate: On(milk, plate).

02

失败根因

首个物理失败是 milk 抓取/抬升;不是 plate 放置,也没有证据表明对象被识别错。

Evidence

视觉证据

iter003_attempt0_failed.mp4
Why

证据与推理

  1. 这是不含门或抽屉的基础 pick-and-place,对基础抓取能力形成直接对照。
  2. 结构化 verifier:xy_inside=false、contact=false、ok=false。
  3. 逐步验证第 5 步抓取/抬升失败(confidence 0.95),failure_mode=grasp_failure。
03

真实 API 审计

model=gpt-5.5 · elapsed=20.7s · finish_reason=stop · source: 0035_p568475_policy_writer._generate_once.json

发送给 Policy Writer 的完整 prompt
===== SYSTEM =====
You are a deterministic policy writer for a code-as-policy robot system. Write ONLY Python code. Do not use while True loops. Use only the provided imported primitive functions and learned helper functions.

===== USER =====
You are a deterministic policy writer for a code-as-policy robot system.

Write Python code that executes the following plan.

AVAILABLE IMPORTED FUNCTIONS (use ONLY these, not env.<method>):
close_gripper, get_object_3d_points_and_masks_from_language, get_object_pose, get_observation, get_oriented_bounding_box_from_3d_points, goto_home_joint_position, goto_pose, open_gripper, sample_grasp_pose

API DOCUMENTATION:
get_observation() -> dict[str, typing.Any]
  Doc:
    Get the observation of the environment.
    Returns:
        observation:
            A dictionary containing the observation of the environment.
            The dictionary contains the following keys:
            - ["agentview"]["images"]["rgb"]: Current color camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["agentview"]["images"]["depth"]: Current depth camera image as a numpy array of shape (H, W), dtype float32.
            - ["agentview"]["intrinsics"]: Camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["agentview"]["pose_mat"]: Camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot0_eye_in_hand"]["images"]["rgb"]: Current wrist camera image as a numpy array of shape (H, W, 3), dtype uint8.
            - ["robot0_eye_in_hand"]["images"]["depth"]: Current wrist camera depth image as a numpy array of shape (H, W), dtype float32.
            - ["robot0_eye_in_hand"]["intrinsics"]: Wrist camera intrinsic matrix as a numpy array of shape (3, 3), dtype float64.
            - ["robot0_eye_in_hand"]["pose_mat"]: Wrist camera extrinsic matrix as a numpy array of shape (4, 4), dtype float64.
            - ["robot_cartesian_pos"]: Current end-effector (panda_hand) pose in the robot/world frame as a numpy array of shape (8,), dtype float64. The first 3 elements are the robot's end-effector XYZ, the next 4 elements are the quaternion wxyz, and the last element is the gripper position normalized, 0 (closed) to 1 (open).
            - ["robot_joint_pos"]: Current joint positions as a numpy array of shape (7,), dtype float64. The last element is the gripper position normalized, 0 (closed) to 1 (open).

get_object_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray] | tuple[None, None]
  Doc:
    Get the pose of an object in the environment from a natural language description.
    The quaternion from get_object_pose may be unreliable, so disregard it and use the grasp
    pose quaternion OR (0, 0, 1, 0) wxyz as the gripper down orientation if using this for
    placement position.
    It is possible that get_object_pose is sometimes unreliable and will return None for both
    position and quaternion.
    
    Args:
        object_name: The name of the object to get the pose of, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

sample_grasp_pose(object_name: str, use_multiview: bool = True) -> tuple[numpy.ndarray, numpy.ndarray]
  Doc:
    Sample a grasp pose for an object in the environment from a natural language description.
    Uses multiview point clouds and plan_grasp_from_point_clouds for more reliable grasp planning.
    Do use the grasp sample quaternion from sample_grasp_pose.
    
    Args:
        object_name: The name of the object to sample a grasp pose for, in underscore separated lowercase words.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation. If False, only uses the main camera for segmentation.
    
    Returns:
        position: (3,) XYZ in meters (world frame).
        quaternion_wxyz: (4,) WXYZ unit quaternion (world frame).

goto_pose(position: numpy.ndarray, quaternion_wxyz: numpy.ndarray, z_approach: float = 0.0) -> None
  Doc:
    Go to pose using Inverse Kinematics.
    There is no need to call a second goto_pose with the same position and quaternion_wxyz after calling it with z_approach.
    Args:
        position: (3,) XYZ in meters.
        quaternion_wxyz: (4,) WXYZ unit quaternion.
        z_approach: (float) Z-axis distance offset for goto_pose insertion approach motion. Will first arrive at position + z_approach meters in Z-axis before moving to the requested pose. Useful for more precise grasp approaches. Default is 0.0.
    Returns:
        None

open_gripper() -> None
  Doc:
    Open gripper fully.
    
    Args:
        None

close_gripper() -> None
  Doc:
    Close gripper fully.
    
    Args:
        None

get_oriented_bounding_box_from_3d_points(points: numpy.ndarray) -> dict[str, typing.Any]
  Doc:
    Get the oriented bounding box from 3D points.
    
    Args:
        points: np.ndarray: The 3D points to get the oriented bounding box from.
            Shape: (N, 3), dtype float64.
    
    Returns:
        dict[str, Any]: The oriented bounding box. The dictionary contains the following keys:
            - "center": np.ndarray: The center of the oriented bounding box in point cloud frame.
            - "extent": np.ndarray: The extent of the oriented bounding box.
            - "R": np.ndarray: The rotation matrix of the oriented bounding box in point cloud frame.
    
    Example:
        >>> points = np.random.randn((100, 3))
        >>> obb = get_oriented_bounding_box_from_3d_points(points)

get_object_3d_points_and_masks_from_language(text_prompt: str, use_multiview: bool = True) -> dict[str, typing.Any]
  Doc:
    Segment an object using text prompt across multiple views (agentview and wrist).
    
    Uses Molmo to locate the object in both camera views, then SAM3 for
    segmentation. Returns the masks and 3D points that appear in both views.
    
    Args:
        text_prompt: Text description of the object to segment.
        use_multiview: If True, uses the wrist camera as well as the main camera for segmentation.
        
    Returns:
        dict containing:
            - "agentview_mask": np.ndarray of shape (H, W), dtype bool
            - "wrist_mask": np.ndarray of shape (H, W), dtype bool (None if single view)
            - "points_3d": np.ndarray of shape (N, 3), 3D points in world frame
            - "agentview_score": float, SAM3 confidence score
            - "wrist_score": float, SAM3 confidence score (None if single view)

goto_home_joint_position() -> None
  Doc:
    Return the arm to its reset joint configuration with high manipulability

LEARNED HELPER FUNCTION REFERENCES (already defined and callable — use them directly):
No learned helper functions available yet.

REQUIREMENTS:
- Use the primitive functions listed in AVAILABLE IMPORTED FUNCTIONS above AND any LEARNED HELPER FUNCTION REFERENCES shown above.
- The learned helper functions are pre-defined and available in your execution scope. Call them directly.
- Do NOT invent wrapper functions on env or low_level_env.
- Do NOT use while True loops or any unbounded retry patterns. Use bounded for loops instead.
- Set RESULT to a structured dict describing success/failure for each step.
- Add explicit comments before each plan step.
- Wrap the executable body for EACH plan step in the runtime marker context
  `with step_context("<step id>", "<step description>", step_index=<0-based index>):`.
  This is a logging marker, not a robot primitive. It lets the verifier save
  exact per-step API traces, motion frame ranges, and intermediate artifacts.
- Define reusable sub-functions for non-trivial skill sequences that could be added to the skill library.
- On retries, follow the diagnoser's requested edit scale. If a top-of-retry "## EDIT SCALE: argument-level" banner is present (or the prose says argument-level), keep the same primitive/helper call sequence and change only the named arguments first (target text, verify_label, pose/offset, approach axis, release height, retry count, or gate threshold). Rewrite helper bodies, replace primitives, or add new wrappers only when the banner / diagnosis says rewrite-needed because arguments cannot express the fix, the API/function is wrong for the task, the sequence is structurally wrong, or there is a real code/logic bug.


IMPORTANT: Use ONLY functions from the AVAILABLE IMPORTED FUNCTIONS list and LEARNED HELPER FUNCTION REFERENCES above.
Do NOT call any function not in those lists. Check the API DOCUMENTATION for correct function signatures.
Extract object names from the GOAL description below.

General rules:
- Read the API DOCUMENTATION carefully for the correct function signatures and return types.
- When retry feedback names a primitive/helper call, preserve that call and tune its arguments before changing the overall code structure, unless the feedback explicitly calls for a larger rewrite.
- For pick-and-place: perceive object location, move to grasp pose, close gripper, move to target, open gripper. Use the available perception functions to locate objects.
- Use bounded for loops (not while True) for retry patterns.
- For multi-step tasks (pick A then place on B), chain the patterns sequentially.
- Never leave a successfully grasped object suspended because a pre-release wrist check failed. Once the placement target has been localized, execute a cautious descend, open the gripper, retreat, and then verify the final resting state.
- NumPy array truthiness: localization primitives often return ndarrays or lists of candidates. NEVER write `if pos:` or `if not result:` on an ndarray — raises "truth value of an array is ambiguous". Instead use `if pos is None` / `if len(pos) == 0` / `if result.get("verified")` on explicit scalars. This pattern has burned many past attempts.



# === TASK-SPECIFIC INPUTS BELOW (vary per attempt; everything above is stable for cache reuse) ===

SCENE: i_want_to_put_the_milk_on_the_plate
GOAL: I want to put the milk on the plate.
OBJECT SCOPE: {}

PLAN:
- step-1: Get a fresh observation to confirm the current scene. The milk carton is visible upright near the middle of the table, and the plate is visible on the front-right area of the table. There is no apparent clutter blocking either object. | skills: get_observation | notes: Use the agent-view image to verify that the milk remains upright and reachable and that the plate remains unobstructed before beginning the pick-and-place.
- step-2: Localize the plate position as the placement target. | skills: get_object_pose | notes: Call get_object_pose('plate', use_multiview=True). Use the returned position for placement; disregard its quaternion and use a gripper-down placement orientation such as (0, 0, 1, 0) wxyz. If pose localization fails, segment the plate with get_object_3d_points_and_masks_from_language('plate') and use the center of its 3D point cloud or oriented bounding box as the placement center.
- step-3: Sample a stable grasp pose for the upright milk carton. | skills: sample_grasp_pose | notes: Call sample_grasp_pose('milk', use_multiview=True). Prefer a side grasp on the carton body around its mid-height rather than a top grasp, since the carton is upright and narrow. The grasp should avoid colliding with the tabletop and should leave enough clearance to lift the carton vertically.
- step-4: Open the gripper and move to the sampled milk grasp pose with a short vertical approach. | skills: open_gripper, goto_pose | notes: Open the gripper, then call goto_pose(grasp_position, grasp_quaternion, z_approach=0.06). The z approach helps descend onto the carton accurately without sweeping into it from the side.
- step-5: Close the gripper to grasp the milk carton, then lift it above the table. | skills: close_gripper, goto_pose | notes: After close_gripper(), lift the held milk by moving to the same grasp orientation with the position raised about 0.10 to 0.15 m in Z. Do not stop the task based on ambiguous wrist visibility; continue to placement unless the grasp clearly fails mechanically.
- step-6: Move the milk over the center of the plate. | skills: goto_pose | notes: Use the localized plate center as the XY target. Set the Z height safely above the plate, approximately table height plus object clearance. Maintain the grasp orientation that keeps the carton upright if possible.
- step-7: Lower the milk onto the plate and release it. | skills: goto_pose, open_gripper | notes: Lower toward the plate center until the milk bottom is close to the plate surface, then open_gripper(). The final placement should put the milk centered on or within the rim of the plate. Avoid pushing the milk sideways across the plate during release.
- step-8: Retreat upward and return the robot to a safe home configuration. | skills: goto_pose, goto_home_joint_position | notes: After release, move the end effector upward at least 0.08 to 0.12 m before returning home to avoid knocking over the milk or contacting the plate.
- step-9: Verify that the milk is on the plate. | skills: get_observation, get_object_pose | notes: Use a final observation and/or get_object_pose for both 'milk' and 'plate'. Success is indicated if the milk XY position is close to the plate center and the milk appears resting on the plate rather than beside it.





## LESSONS FROM PAST FAILURES (advisory — NOT ground truth)
--- RAW FAILURE EPISODES (most relevant) ---
1. Task "i_want_to_open_the_microwave_and_put_the_porcelain_mug_insid": partial_completion -- [attempt 1] argument_level: keep the same high-level sequence, but fix the targeted poses and add outcome checks before proceeding. In `open_microwave_door_from_handle`, the sampled `handle_position`/`handle_quaternion` did not produce a real handle grasp: the code called `close_gripper()` and executed the pull path, but the door stayed closed. Change the handle grasp target to the visible vertical handle surface/edge, use an approach axis normal to the microwave front so the fingers straddle the handle rather than closing beside it, and adjust the pull offsets in `pull_position_1/2/3` to follow the door’s hinge arc outward from the front-left handle. After this primitive, verify that the door is actually open before running mug pickup/interior placement. Also change `safe_pick_object` for the mug to target a stable rim/body or handle-aligned grasp with a slightly higher approach/closure pose; the current sampled mug pose led to an empty or ineffective grasp, with the mug still on the table. Do not trust the code’s RESULT success flags after issuing motions; they currently mark success even when the visual state did not change.
   Failed code (diagnosed step step-3):
```python
# step-3: Open the microwave door by grasping and pulling the handle outward and leftward.
with step_context("step-3", "Open the microwave door by grasping the handle and pulling outward", step_index=2):
    if handle_position is not None and handle_quaternion is not None:
        open_microwave_door_from_handle(handle_position, handle_quaternion)
        RESULT["step-3"]["success"] = True
        RESULT["step-3"]["details"] = "Executed handle grasp and outward-left pull to open the door."
    else:
        RESULT["step-3"]["details"] = "Skipped because handle pose was unavailable."
```
2. Task "i_want_to_open_the_wooden_cabinet_top_drawer_and_put_the_coo": code_bug -- [attempt 1] Fix runtime error: AssertionError: No grasp candidates found. Avoid dynamic execution or hidden retry loops.
   Failed code (diagnosed step runtime):
```python
RESULT = {
    "step-1": {"success": False, "details": ""},
    "step-2": {"success": False, "details": ""},
    "step-3": {"success": False, "details": ""},
    "step-4": {"success": False, "details": ""},
    "step-5": {"success": False, "details": ""},
    "step-6": {"success": False, "details": ""},
    "step-7": {"success": False, "details": ""},
    "step-8": {"success": False, "details": ""},
    "step-9": {"success": False, "details": ""},
    "step-10": {"success": False, "details": ""},
}


def localize_by_pose_or_points(object_names):
    best_position = None
    best_quaternion = None
    best_obb = None
    best_name = None

    for object_name in object_names:
        position, quaternion = get_object_pose(object_name, use_multiview=True)
        if position is not None:
            best_position = position
            best_quaternion = quaternion
            best_name = object_name
            break

    if best_position is None:
        for object_name in object_names:
            seg = get_object_3d_points_and_masks_from_language(object_name, use_multiview=True)
            points = seg.get("points_3d")
            if points is not None and len(points) > 0:
                obb = get_oriented_bounding_box_from_3d_points(points)
                best_position = obb["center"]
                best_obb = obb
                best_name = object_name
                break

    return best_position, best_quaternion, best_obb, best_name


def compute_xy_unit_direction(from_position, to_position):
    direction = from_position.copy()
    direction[0] = to_position[0] - from_position[0]
    direction[1] = to_position[1] - from_position[1]
    direction[2] = 0.0
    length = (direction[0] ** 2 + direction[1] ** 2) ** 0.5
    if length < 0.001:
        direction[0] = -1.0
        direction[1] = 0.0
        direction[2] = 0.0
    else:
        direction[0] = direction[0] / length
        direction[1] = direction[1] / length
        direction[2] = 0.0
    return direction


def execute_drawer_handle_grasp(handle_names, fallback_position):
    grasp_position = None
    grasp_quaternion = None
    grasp_name = None

    for handle_name in handle_names:
        position, quaternion = sample_grasp_pose(handle_name, use_multiview=True)
        if position is not None and quaternion is not None:
            grasp_position = position
            grasp_quaternion = quaternion
            grasp_name = handle_name
            break

    if grasp_position is None:
        grasp_position = fallback_position
        grasp_quaternion = (0.0, 0.0, 1.0, 0.0)
        grasp_name = "fallback_handle_center"

    open_gripper()
    goto_pose(grasp_position, grasp_quaternion, z_approach=0.06)
    close_gripper()

    return grasp_position, grasp_quaternion, grasp_name


def pull_drawer_open_from_grasp(start_position, grasp_quaternion, pull_direction):
    pull_position_1 = start_position.copy()
    pull_position_1[0] = pull_position_1[0] + pull_direction[0] * 0.08
    pull_position_1[1] = pull_position_1[1] + pull_direction[1] * 0.08

    pull_position_2 = start_position.copy()
    pull_position_2[0] = pull_position_2[0] + pull_direction[0] * 0.16
    pull_position_2[1] = pull_position_2[1] + pull_direction[1] * 0.16

    pull_position_3 = start_position.copy()
    pull_position_3[0] = pull_position_3[0] + pull_direction[0] * 0.23
    pull_position_3[1] = pull_position_3[1] + pull_direction[1] * 0.23

    goto_pose(pull_position_1, grasp_quaternion)
    goto_pose(pull_position_2, grasp_quaternion)
    goto_pose(pull_position_3, grasp_quaternion)
    open_gripper()

    retreat_position = pull_position_3.copy()
    retreat_position[2] = retreat_position[2] + 0.10
    goto_pose(retreat_position, grasp_quaternion)

    return pull_position_3


def pick_object_with_sampled_grasp(object_names):
    object_position = None
    object_quaternion = None
    object_name_used = None

    for object_name in object_names:
        pose_position, pose_quaternion = get_object_pose(object_name, use_multiview=True)
        if pose_position is not None:
            object_position = pose_position
            object_name_used = object_name
            break

    grasp_position = None
    grasp_quaternion = None
    for object_name in object_names:
        position, quaternion = sample_grasp_pose(object_name, use_multiview=True)
        if position is not None and quaternion is not None:
            grasp_position = position
            grasp_quaternion = quaternion
            object_name_used = object_name
            break

    if grasp_position is None:
        return None, None, object_position, object_name_used

    open_gripper()
    goto_pose(grasp_position, grasp_quaternion, z_approach=0.08)
    close_gripper()

    lift_position = grasp_position.copy()
    lift_position[2] = lift_position[2] + 0.16
    goto_pose(lift_position, grasp_quaternion)

    return grasp_position, grasp_quaternion, object_position, object_name_used


# step-1: Get a fresh observation and confirm the initial scene state.
with step_context("step-1", "Get fresh observation and confirm cabinet, closed top drawer handle, and cookies on tabletop", step_index=0):
    observation_initial = get_observation()
    RESULT["step-1"]["success"] = observation_initial is not None
    RESULT["step-1"]["details"] = "Fresh observation captured for initial scene check."

# step-2: Localize the wooden cabinet top drawer handle.
with step_context("step-2", "Localize wooden cabinet top drawer handle using pose estimation or segmentation", step_index=1):
    handle_names = [
        "wooden_cabinet_top_drawer_handle",
        "top_drawer_handle",
        "wooden_cabinet_handle",
        "cabinet_top_drawer_handle",
    ]
    handle_position, handle_quaternion, handle_obb, handle_name_used = localize_by_pose_or_points(handle_names)

    cabinet_position, cabinet_quaternion, cabinet_obb, cabinet_name_used = localize_by_pose_or_points([
        "wooden_cabinet",
        "cabinet",
    ])

    if handle_position is not None:
        RESULT["step-2"]["success"] = True
        RESULT["step-2"]["details"] = {
            "handle_name_used": handle_name_used,
            "cabinet_name_used": cabinet_name_used,
        }
    else:
        RESULT["step-2"]["details"] = "Failed to localize the top drawer handle."

# step-3: Open gripper, move to a grasp pose on the handle, and close the gripper.
with step_context("step-3", "Grasp the top drawer handle from the front", step_index=2):
    if handle_position is not None:
        drawer_grasp_position, drawer_grasp_quaternion, drawer_grasp_name = execute_drawer_handle_grasp(
            handle_names,
            handle_position,
        )
        RESULT["step-3"]["success"] = drawer_grasp_position is not None and drawer_grasp_quaternion is not None
        RESULT["step-3"]["details"] = {
            "drawer_grasp_name": drawer_grasp_name,
            "note": "Executed handle grasp; sampled grasp pose used when available.",
        }
    else:
        drawer_grasp_position = None
        drawer_grasp_quaternion = None
        RESULT["step-3"]["details"] = "Skipped because handle localization failed."

# step-4: Pull the top drawer open outward along the drawer sliding direction, then release.
with step_context("step-4", "Pull top drawer open along sliding direction and release handle", step_index=3):
    if drawer_grasp_position is not None and drawer_grasp_quaternion is not None:
        if cabinet_position is not None:
            pull_direction = compute_xy_unit_direction(cabinet_position, handle_position)
        else:
            table_center_reference = handle_position.copy()
            table_center_reference[0] = 0.0
            table_center_reference[1] = 0.0
            table_center_reference[2] = handle_position[2]
            pull_direction = compute_xy_unit_direction(handle_position, table_center_reference)

        opened_handle_position = pull_drawer_open_from_grasp(
            drawer_grasp_position,
            drawer_grasp_quaternion,
            pull_direction,
        )
        RESULT["step-4"]["success"] = True
        RESULT["step-4"]["details"] = {
            "pull_distance_m": 0.23,
            "released_handle": True,
        }
    else:
        opened_handle_position = None
        pull_direction = None
        RESULT["step-4"]["details"] = "Skipped because drawer handle was not grasped."

# step-5: Move away, observe, and localize open drawer cavity/interior placement region.
with step_context("step-5", "Verify open drawer and localize open top drawer interior placement region", step_index=4):
    goto_home_joint_position()
    observation_after_open = get_observation()

    cavity_names = [
        "open_top_drawer_interior",
        "wooden_cabinet_top_drawer_interior",
        "open_drawer_cavity",
        "top_drawer_cavity",
        "inside_top_drawer",
    ]
    cavity_position, cavity_quaternion, cavity_obb, cavity_name_used = localize_by_pose_or_points(cavity_names)

    if cavity_position is None and opened_handle_position is not None and pull_direction is not None:
        cavity_position = opened_handle_position.copy()
        cavity_position[0] = cavity_position[0] - pull_direction[0] * 0.08
        cavity_position[1] = cavity_position[1] - pull_direction[1] * 0.08
        cavity_position[2] = cavity_position[2] + 0.04
        cavity_name_used = "estimated_from_opened_handle"

    if cavity_position is not None:
        RESULT["step-5"]["success"] = True
        RESULT["step-5"]["details"] = {
            "cavity_name_used": cavity_name_used,
            "observation_captured": observation_after_open is not None,
        }
    else:
        RESULT["step-5"]["details"] = "Could not localize or estimate open drawer cavity."

# step-6: Localize the cookies box and sample a grasp pose.
with step_context("step-6", "Localize cookies box and sample grasp pose", step_index=5):
    cookies_names = [
        "cookies_box",
        "cookies",
        "cookie_box",
    ]

    cookies_pose_position = None
    cookies_pose_quaternion = None
    cookies_pose_name = None
    for cookies_name in cookies_names:
        position, quaternion = get_object_pose(cookies_name, use_multiview=True)
        if position is not None:
            cookies_pose_position = position
            cookies_pose_quaternion = quaternion
            cookies_pose_name = cookies_name
            break

    cookies_grasp_position = None
    cookies_grasp_quaternion = None
    cookies_grasp_name = None
    for cookies_name in cookies_names:
        position, quaternion = sample_grasp_pose(cookies_name, use_multiview=True)
        if position is not None and quaternion is not None:
            cookies_grasp_position = position
            cookies_grasp_quaternion = quaternion
            cookies_grasp_name = cookies_name
            break

    RESULT["step-6"]["success"] = cookies_grasp_position is not None and cookies_grasp_quaternion is not None
    RESULT["step-6"]["details"] = {
        "cookies_pose_name": cookies_pose_name,
        "cookies_grasp_name": cookies_grasp_name,
    }

# step-7: Pick up the cookies from the tabletop and lift clear of the table.
with step_context("step-7", "Pick up cookies box and lift it clear of tabletop", step_index=6):
    if cookies_grasp_position is not None and cookies_grasp_quaternion is not None:
        open_gripper()
        goto_pose(cookies_grasp_position, cookies_grasp_quaternion, z_approach=0.08)
        close_gripper()

        cookies_lift_position = cookies_grasp_position.copy()
        cookies_lift_position[2] = cookies_lift_position[2] + 0.18
        goto_pose(cookies_lift_position, cookies_grasp_quaternion)

        RESULT["step-7"]["success"] = True
        RESULT["step-7"]["details"] = "Executed cookies grasp and vertical lift."
    else:
        cookies_lift_position = None
        RESULT["step-7"]["details"] = "Skipped because cookies grasp pose was unavailable."

# step-8: Move the held cookies to a safe pose above the open drawer interior, then descend for placement.
with step_context("step-8", "Move held cookies above open drawer interior and descend into drawer", step_index=7):
    if cookies_lift_position is not None and cavity_position is not None:
        placement_quaternion = (0.0, 0.0, 1.0, 0.0)

        placement_above_position = cavity_position.copy()
        placement_above_position[2] = cavity_position[2] + 0.18

        placement_release_position = cavity_position.copy()
        placement_release_position[2] = cavity_position[2] + 0.06

        goto_pose(placement_above_position, placement_quaternion)
        goto_pose(placement_release_position, placement_quaternion)

        RESULT["step-8"]["success"] = True
        RESULT["step-8"]["details"] = "Moved cookies above the open drawer cavity and descended to release height."
    else:
        placement_above_position = None
        placement_release_position = None
        placement_quaternion = (0.0, 0.0, 1.0, 0.0)
        RESULT["step-8"]["details"] = "Skipped because cookies were not lifted or drawer cavity was unavailable."

# step-9: Release cookies inside the open top drawer and lift away.
with step_context("step-9", "Release cookies inside open top drawer and retreat vertically", step_index=8):
    if placement_release_position is not None:
        open_gripper()

        retreat_after_place_position = placement_release_position.copy()
        retreat_after_place_position[2] = retreat_after_place_position[2] + 0.18
        goto_pose(retreat_after_place_position, placement_quaternion)

        RESULT["step-9"]["success"] = True
        RESULT["step-9"]["details"] = "Opened gripper inside drawer and retreated upward."
    else:
        RESULT["step-9"]["details"] = "Skipped because placement release pose was unavailable."

# step-10: Get final observation to verify drawer is open and cookies are inside.
with step_context("step-10", "Final observation verifying cookies inside open wooden cabinet top drawer", step_index=9):
    final_observation = get_observation()
    RESULT["step-10"]["success"] = final_observation is not None
    RESULT["step-10"]["details"] = "Final observation captured; drawer should remain open with cookies released inside."
```
Do NOT repeat the failed approaches above. Apply the lessons and try a different strategy.
The block above (if non-empty) lists distilled lessons in "WHEN ... | WRONG ... | DO ..." form, each followed by a metadata footer like `(confidence=0.80, applied=5× helped=1×, last_helped=iter4 (2 iters ago), distilled=iter2 (4 iters ago))`. Use that footer to weigh how much to trust each lesson.

PRIORITY ORDER when signals conflict:
  0. The SUB-AGENT DIRECTIVE block above (if non-empty) — this is the parallel sub-agent's committed approach assignment, a HARD constraint, and dominates every other guidance source below.
  1. The current attempt's RETRY CONTEXT (diagnoser feedback + visual evidence + PREVIOUS CODE below) — this saw what actually happened on this exact task and is ground truth for what to fix.
  2. A lesson with high reliability (helped/applied ≥ 0.5 with applied ≥ 2) AND recent `last_helped` (≤ 2 iters ago) — strong prior, follow its DO recipe.
  3. A lesson with low reliability (helped/applied < 0.3) OR stale (`last_helped=never` or ≥ 5 iters ago) — background prior only; don't let it override the current diagnosis.

Empty block means no relevant prior failures.

API 返回并实际执行的 robot control code
RESULT = {
    "step-1": {"success": False, "details": ""},
    "step-2": {"success": False, "details": ""},
    "step-3": {"success": False, "details": ""},
    "step-4": {"success": False, "details": ""},
    "step-5": {"success": False, "details": ""},
    "step-6": {"success": False, "details": ""},
    "step-7": {"success": False, "details": ""},
    "step-8": {"success": False, "details": ""},
    "step-9": {"success": False, "details": ""},
}


def localize_object_pose_or_pointcloud_center(object_name):
    position = None
    quaternion = None
    source = None
    obb = None

    pose_position, pose_quaternion = get_object_pose(object_name, use_multiview=True)
    if pose_position is not None:
        position = pose_position
        quaternion = pose_quaternion
        source = "get_object_pose"
    else:
        seg = get_object_3d_points_and_masks_from_language(object_name, use_multiview=True)
        points = seg.get("points_3d")
        if points is not None and len(points) > 0:
            obb = get_oriented_bounding_box_from_3d_points(points)
            position = obb["center"]
            quaternion = None
            source = "pointcloud_obb_center"

    return position, quaternion, source, obb


def bounded_sample_grasp_pose(object_names):
    grasp_position = None
    grasp_quaternion = None
    grasp_name = None
    error_details = []

    for object_name in object_names:
        try:
            position, quaternion = sample_grasp_pose(object_name, use_multiview=True)
            if position is not None and quaternion is not None:
                grasp_position = position
                grasp_quaternion = quaternion
                grasp_name = object_name
                break
        except Exception as exc:
            error_details.append({"object_name": object_name, "error": str(exc)})

    return grasp_position, grasp_quaternion, grasp_name, error_details


def copy_position_with_z_offset(position, z_offset):
    new_position = position.copy()
    new_position[2] = new_position[2] + z_offset
    return new_position


def make_position_over_target(reference_position, target_position, target_z):
    new_position = reference_position.copy()
    new_position[0] = target_position[0]
    new_position[1] = target_position[1]
    new_position[2] = target_z
    return new_position


def compute_xy_distance(position_a, position_b):
    dx = position_a[0] - position_b[0]
    dy = position_a[1] - position_b[1]
    return (dx * dx + dy * dy) ** 0.5


def pick_with_sampled_grasp(grasp_position, grasp_quaternion, approach_height, lift_height):
    open_gripper()
    goto_pose(grasp_position, grasp_quaternion, z_approach=approach_height)
    close_gripper()
    lifted_position = copy_position_with_z_offset(grasp_position, lift_height)
    goto_pose(lifted_position, grasp_quaternion)
    return lifted_position


def place_at_target_center(current_lift_position, grasp_quaternion, target_position, above_offset, release_offset):
    above_position = make_position_over_target(
        current_lift_position,
        target_position,
        target_position[2] + above_offset,
    )
    release_position = make_position_over_target(
        current_lift_position,
        target_position,
        target_position[2] + release_offset,
    )
    goto_pose(above_position, grasp_quaternion)
    goto_pose(release_position, grasp_quaternion)
    open_gripper()
    retreat_position = copy_position_with_z_offset(release_position, 0.12)
    goto_pose(retreat_position, grasp_quaternion)
    return above_position, release_position, retreat_position


# step-1: Get a fresh observation to confirm the current scene.
with step_context("step-1", "Get fresh observation confirming milk and plate are visible and reachable", step_index=0):
    initial_observation = get_observation()
    RESULT["step-1"]["success"] = initial_observation is not None
    RESULT["step-1"]["details"] = "Fresh observation captured for milk-on-plate task."

# step-2: Localize the plate position as the placement target.
with step_context("step-2", "Localize plate position as placement target", step_index=1):
    plate_position, plate_quaternion_raw, plate_source, plate_obb = localize_object_pose_or_pointcloud_center("plate")
    placement_quaternion = (0.0, 0.0, 1.0, 0.0)

    if plate_position is not None:
        RESULT["step-2"]["success"] = True
        RESULT["step-2"]["details"] = {
            "plate_source": plate_source,
            "used_quaternion": "gripper_down_wxyz_0_0_1_0",
        }
    else:
        RESULT["step-2"]["details"] = "Failed to localize plate by pose or point cloud."

# step-3: Sample a stable grasp pose for the upright milk carton.
with step_context("step-3", "Sample stable grasp pose for upright milk carton", step_index=2):
    milk_grasp_position, milk_grasp_quaternion, milk_grasp_name, milk_grasp_errors = bounded_sample_grasp_pose([
        "milk",
        "milk_carton",
    ])

    if milk_grasp_position is not None and milk_grasp_quaternion is not None:
        RESULT["step-3"]["success"] = True
        RESULT["step-3"]["details"] = {
            "milk_grasp_name": milk_grasp_name,
            "note": "Sampled grasp pose will be used directly, preserving planner orientation.",
        }
    else:
        RESULT["step-3"]["details"] = {
            "failure": "Failed to sample milk grasp pose.",
            "errors": milk_grasp_errors,
        }

# step-4: Open the gripper and move to the sampled milk grasp pose with a short vertical approach.
with step_context("step-4", "Open gripper and move to sampled milk grasp pose with vertical approach", step_index=3):
    if milk_grasp_position is not None and milk_grasp_quaternion is not None:
        open_gripper()
        goto_pose(milk_grasp_position, milk_grasp_quaternion, z_approach=0.06)
        RESULT["step-4"]["success"] = True
        RESULT["step-4"]["details"] = "Opened gripper and approached milk grasp pose with z_approach=0.06."
    else:
        RESULT["step-4"]["details"] = "Skipped because milk grasp pose was unavailable."

# step-5: Close the gripper to grasp the milk carton, then lift it above the table.
with step_context("step-5", "Close gripper on milk carton and lift above table", step_index=4):
    if milk_grasp_position is not None and milk_grasp_quaternion is not None:
        close_gripper()
        milk_lift_position = copy_position_with_z_offset(milk_grasp_position, 0.14)
        goto_pose(milk_lift_position, milk_grasp_quaternion)
        RESULT["step-5"]["success"] = True
        RESULT["step-5"]["details"] = {
            "lift_height_m": 0.14,
            "note": "Continued to placement after mechanical grasp command without relying on ambiguous wrist visibility.",
        }
    else:
        milk_lift_position = None
        RESULT["step-5"]["details"] = "Skipped because milk grasp pose was unavailable."

# step-6: Move the milk over the center of the plate.
with step_context("step-6", "Move held milk over center of plate", step_index=5):
    if milk_lift_position is not None and plate_position is not None:
        milk_above_plate_position = make_position_over_target(
            milk_lift_position,
            plate_position,
            plate_position[2] + 0.22,
        )
        goto_pose(milk_above_plate_position, milk_grasp_quaternion)
        RESULT["step-6"]["success"] = True
        RESULT["step-6"]["details"] = {
            "above_plate_z_offset_m": 0.22,
            "note": "Moved over plate center while maintaining sampled grasp orientation.",
        }
    else:
        milk_above_plate_position = None
        RESULT["step-6"]["details"] = "Skipped because milk was not lifted or plate was unavailable."

# step-7: Lower the milk onto the plate and release it.
with step_context("step-7", "Lower milk onto plate center and release", step_index=6):
    if milk_above_plate_position is not None and plate_position is not None:
        milk_release_position = make_position_over_target(
            milk_above_plate_position,
            plate_position,
            plate_position[2] + 0.055,
        )
        goto_pose(milk_release_position, milk_grasp_quaternion)
        open_gripper()
        RESULT["step-7"]["success"] = True
        RESULT["step-7"]["details"] = {
            "release_z_offset_m": 0.055,
            "note": "Released milk near plate center without sideways sliding.",
        }
    else:
        milk_release_position = None
        RESULT["step-7"]["details"] = "Skipped because above-plate pose or plate target was unavailable."

# step-8: Retreat upward and return the robot to a safe home configuration.
with step_context("step-8", "Retreat upward after release and return home", step_index=7):
    if milk_release_position is not None:
        retreat_after_release_position = copy_position_with_z_offset(milk_release_position, 0.12)
        goto_pose(retreat_after_release_position, milk_grasp_quaternion)
        goto_home_joint_position()
        RESULT["step-8"]["success"] = True
        RESULT["step-8"]["details"] = "Retreated upward by 0.12 m and returned to home joint position."
    else:
        retreat_after_release_position = None
        goto_home_joint_position()
        RESULT["step-8"]["success"] = True
        RESULT["step-8"]["details"] = "Release pose unavailable; returned robot to home for safety."

# step-9: Verify that the milk is on the plate.
with step_context("step-9", "Verify milk is on the plate", step_index=8):
    final_observation = get_observation()

    final_milk_position, final_milk_quaternion = get_object_pose("milk", use_multiview=True)
    final_plate_position, final_plate_quaternion = get_object_pose("plate", use_multiview=True)

    if final_milk_position is not None and final_plate_position is not None:
        final_xy_distance = compute_xy_distance(final_milk_position, final_plate_position)
        RESULT["step-9"]["success"] = final_xy_distance < 0.08
        RESULT["step-9"]["details"] = {
            "final_observation_captured": final_observation is not None,
            "final_xy_distance_m": final_xy_distance,
            "threshold_m": 0.08,
            "verification": "Milk localized close to plate center." if final_xy_distance < 0.08 else "Milk not localized close enough to plate center.",
        }
    else:
        RESULT["step-9"]["success"] = False
        RESULT["step-9"]["details"] = {
            "final_observation_captured": final_observation is not None,
            "milk_pose_available": final_milk_position is not None,
            "plate_pose_available": final_plate_position is not None,
            "verification": "Could not verify final milk-on-plate relation from object poses.",
        }
API 返回的失败诊断原文
```json
{
  "visual_success": false,
  "failed_step": "step-5",
  "failure_mode": "grasp_failure",
  "confidence": 0.88,
  "plan_issue": false,
  "plan_issue_reason": "",
  "subagent_skill_target": null,
  "subagent_skill_target_reason": "",
  "subagent_approaches": [],
  "edit_scale": "argument_level",
  "visual_predicate_status": [
    {
      "step_id": "step-1",
      "description": "Get a fresh observation to confirm the current scene. The milk carton is visible upright near the middle of the table, and the plate is visible on the front-right area of the table. There is no apparent clutter blocking either object.",
      "visually_satisfied": false,
      "evidence": "The terminal wrist view clearly shows the plate, but the final view does not show the initial full scene or confirm the milk carton remains visible and unobstructed. This step may have occurred, but it is not fully verifiable from the final segment."
    },
    {
      "step_id": "step-2",
      "description": "Localize the plate position as the placement target.",
      "visually_satisfied": true,
      "evidence": "The final wrist image is looking down at the plate centered between the gripper fingers, indicating the policy did move to the plate region and likely localized the plate as the placement target."
    },
    {
      "step_id": "step-3",
      "description": "Sample a stable grasp pose for the upright milk carton.",
      "visually_satisfied": false,
      "evidence": "Although stdout reports a sampled grasp pose for milk, the final visual state shows no milk in the gripper and no milk on the plate. The sampled pose did not result in a stable grasp observable by the end."
    },
    {
      "step_id": "step-4",
      "description": "Open the gripper and move to the sampled milk grasp pose with a short vertical approach.",
      "visually_satisfied": false,
      "evidence": "The final wrist image only shows the gripper over the plate, not the earlier approach to the milk. This step cannot be confirmed from the final segment alone."
    },
    {
      "step_id": "step-5",
      "description": "Close the gripper to grasp the milk carton, then lift it above the table.",
      "visually_satisfied": false,
      "evidence": "The terminal wrist view shows the gripper empty over the plate; no milk carton is held. The code did call close_gripper and lift, but visually the robot did not retain the milk carton through the lift/transport."
    },
    {
      "step_id": "step-6",
      "description": "Move the milk over the center of the plate.",
      "visually_satisfied": false,
      "evidence": "The gripper is over the plate in the final wrist view, but the milk is not visible in the gripper or over the plate. The arm moved to the placement area empty."
    },
    {
      "step_id": "step-7",
      "description": "Lower the milk onto the plate and release it.",
      "visually_satisfied": false,
      "evidence": "The plate center is visible and empty in the terminal wrist image. There is no milk carton on the plate after release."
    },
    {
      "step_id": "step-8",
      "description": "Retreat upward and return the robot to a safe home configuration.",
      "visually_satisfied": false,
      "evidence": "The wrist image still shows the gripper near/over the plate, and the final segment provided here does not clearly show a completed retreat to a safe home configuration."
    },
    {
      "step_id": "step-9",
      "description": "Verify that the milk is on the plate.",
      "visually_satisfied": false,
      "evidence": "The final wrist image directly shows the plate without the milk on it, so the milk-on-plate relation is not visually satisfied."
    }
  ],
  "policy_feedback": "argument_level: Keep the same overall pick-then-place sequence, but change the milk grasp sampling/approach arguments so the gripper actually closes on the carton’s broad rectangular side near mid-height. The current `sample_grasp_pose(\"milk\", use_multiview=True)` returned position `[0.499, -0.036, 0.101]` with a tilted quaternion, and the subsequent `close_gripper()`/lift appears to have proceeded empty. Constrain or bias the grasp to a side grasp on the milk carton body, centered higher on the flat side, with the gripper jaws aligned across the carton width; increase the approach clearance slightly in `goto_pose(..., z_approach=0.06)` if needed and add a retry with a different side-grasp candidate if the first sampled grasp is too low or angled. Do not change the plate placement logic yet: the final wrist view shows the robot can reach the plate center, but it arrived there without the milk."
}
```

source: 0046_p568475_failure_diagnoser._query_llm_text.json

Agent 调用时间线 展开原始调用索引
#调用方耗时结果证据
1task_proposer.propose_novel_candidates15.9sstopembedded above
2environment_creator._generate_bddl3.8sstopembedded above
3planner.plan21.1sstopembedded above
4planner_verifier.verify_plan7.7sstopembedded above
5policy_writer._generate_once20.5sstopembedded above
6per_step_verifier._verify_step_package6.5sstopembedded above
7per_step_verifier._verify_step_package6.2sstopembedded above
8per_step_verifier._verify_step_package6.9sstopembedded above
9per_step_verifier._verify_step_package8.1sstopembedded above
10per_step_verifier._verify_step_package5.9sstopembedded above
11per_step_verifier._verify_step_package6.8sstopembedded above
12per_step_verifier._verify_step_package6.6sstopembedded above
13per_step_verifier._verify_step_package8.1sstopembedded above
14per_step_verifier._verify_step_package6.9sstopembedded above
15verifier._query_llm_json4.3sstopembedded above
16verifier._query_llm_json7.5sstopembedded above
17failure_diagnoser._query_llm_text23.6sstopembedded above
18task_proposer.propose_novel_candidates16.8sstopembedded above
19environment_creator._generate_bddl4.2sstopembedded above
20planner.plan23.3sstopembedded above
21planner_verifier.verify_plan11.0sstopembedded above
22policy_writer._generate_once30.8sstopembedded above
23per_step_verifier._verify_step_package9.3sstopembedded above
24per_step_verifier._verify_step_package9.5sstopembedded above
25per_step_verifier._verify_step_package10.9sstopembedded above
26per_step_verifier._verify_step_package11.1sstopembedded above
27per_step_verifier._verify_step_package12.0sstopembedded above
28verifier._query_llm_json7.1sstopembedded above
29skill_proposer.propose19.2sstopembedded above
30library._find_semantic_duplicate2.1sstopembedded above
31task_proposer.propose_novel_candidates18.1sstopembedded above
32environment_creator._generate_bddl3.6sstopembedded above
33planner.plan15.7sstopembedded above
34planner_verifier.verify_plan6.3sstopembedded above
35policy_writer._generate_once20.7sstopembedded above
36per_step_verifier._verify_step_package6.2sstopembedded above
37per_step_verifier._verify_step_package8.1sstopembedded above
38per_step_verifier._verify_step_package6.5sstopembedded above
39per_step_verifier._verify_step_package8.4sstopembedded above
40per_step_verifier._verify_step_package7.2sstopembedded above
41per_step_verifier._verify_step_package11.5sstopembedded above
42per_step_verifier._verify_step_package11.6sstopembedded above
43per_step_verifier._verify_step_package9.6sstopembedded above
44verifier._query_llm_json3.0sstopembedded above
45verifier._query_llm_json14.9sstopembedded above
46failure_diagnoser._query_llm_text18.3sstopembedded above