Task configuration:
{"task_id": "12", "task_name": "create_cube_with_wedge_cut", "description": "Create a cuboid with a wedge-shaped cut in FreeCAD", "application_info": {"name": "FreeCAD", "executable_path": "/usr/local/bin/FreeCAD", "args": []}, "task_parameters": {"source_path": "/FreeCAD/", "filename": "task12.FCStd", "cube_length": 30, "cube_width": 20, "cube_height": 15, "wedge_Xmin": 0.0, "wedge_Xmax": 20.0, "wedge_Ymin": 0.0, "wedge_Ymax": 10.0, "wedge_Zmin": 0.0, "wedge_Zmax": 10.0, "wedge_X2min": 10.0, "wedge_X2max": 10.0, "wedge_Z2min": 5.0, "wedge_Z2max": 5.0}, "instruction_template": "The application is already open. Create a cuboid in FreeCAD with length ${cube_length}, width ${cube_width}, and height ${cube_height}, then create a wedge-shaped cut on its top with parameters: Xmin=${wedge_Xmin}, Xmax=${wedge_Xmax}, Ymin=${wedge_Ymin}, Ymax=${wedge_Ymax}, Zmin=${wedge_Zmin}, Zmax=${wedge_Zmax}, X2min=${wedge_X2min}, X2max=${wedge_X2max}, Z2min=${wedge_Z2min}, Z2max=${wedge_Z2max}. The cuboid should be created using 'create an additive cube', and the wedge cut should be created using 'create subtractive wedge'. Finally, save the file to ${source_path}${filename}", "evaluation_setup": {"scripts": [{"role": "hook", "path": "hooker.js"}, {"role": "handler", "path": "handler.py"}], "timeout": 300, "evaluator_type": "HookManager"}, "preconditions": {"freecad_running": false}, "total_key_steps": 2, "events": {"script_initialized": {"description": "Hook script initialized", "is_key_step": false}, "function_found": {"description": "Save document function found", "is_key_step": false}, "function_called": {"description": "Save document function called", "is_key_step": true, "key_step_index": 1, "key_step_name": "Save document"}, "function_key_word_detected": {"description": "Save document key content detected", "is_key_step": true, "key_step_index": 2, "key_step_name": "Cuboid with wedge cut created and saved successfully"}, "error": {"description": "Error event", "is_key_step": false}}, "mcp_servers": [{"command": "python3", "args": ["/home/agent/.local/share/FreeCAD/Mod/freecad_mcp/src/freecad_bridge.py"]}]}

Hook script:
// FreeCAD Cuboid with Wedge Cut Monitoring Hook Script
// Used to monitor FreeCAD's cuboid with wedge cut creation operation and detect task completion
// After creating a cuboid with wedge cut and saving the file, the test program listens for the save and checks if there is a cuboid with wedge cut meeting the requirements in the corresponding document

(function() {
  // Script constant settings
  const FUNCTION_NAME = "_ZNK3App8Document10saveToFileEPKc"
  const ORIGIN_FUNCTION_NAME = "Document::saveToFile"
  const FUNCTION_BEHAVIOR = "Save Document"

  const SCRIPT_INITIALIZED = "script_initialized"
  const FUNCTION_NOT_FOUND = "function_not_found"
  const FUNCTION_FOUND = "function_found"
  const FUNCTION_CALLED = "function_called"
  const FUNCTION_KEY_WORD_DETECTED = "function_key_word_detected"
  const ERROR = "error"
  const HOOK_INSTALLED = "hook_installed"

  const APP_NAME = "FreeCAD"
  
  // Global variable
  let funcFound = false;
  
  // Send event to the evaluation system
  function sendEvent(eventType, data = {}) {
      const payload = {
          event: eventType,
          ...data,
          timestamp: new Date().getTime()
      };
      send(payload);
  }
  
  // Find Document::saveToFile function
  function getFunction() {
      // Try to find directly through exported symbols
      let FuncAddr = DebugSymbol.getFunctionByName(FUNCTION_NAME);
      
      // If not found, report an error
      if (!FuncAddr) {
          sendEvent(ERROR, {
              error_type: FUNCTION_NOT_FOUND,
              message: `Cannot find ${ORIGIN_FUNCTION_NAME} function`
          });
          return null;
      }
      
      // Report function found
      funcFound = true;
      sendEvent(FUNCTION_FOUND, {
          address: FuncAddr.toString(),
          message: `Found ${ORIGIN_FUNCTION_NAME} function`
      });
      
      return FuncAddr;
  }
  
  // Initialize hook and execute immediately
  function initHook() {
      sendEvent(SCRIPT_INITIALIZED, {
          message: `${APP_NAME} ${FUNCTION_BEHAVIOR} monitoring script started`
      });
      
      // Find search function
      const funcAddr = getFunction();
      if (!funcAddr) {
          return;
      }
      
      // Install search function hook
      Interceptor.attach(funcAddr, {
          onEnter: function(args) {
              try {
                  sendEvent(FUNCTION_CALLED, {
                      message: `Intercepted ${FUNCTION_BEHAVIOR} function call`
                  });
                  this.filename = args[1].readCString();
              } catch (error) {
                  sendEvent(ERROR, {
                      error_type: "general_error",
                      message: `Execution error: ${error.message}`
                  });
              }
          },

          onLeave: function(retval) {
              try {
                if (retval) {
                    const pythonCode = `
import freecad
import FreeCAD
import Part
import math

# Open specified file
file_path = '${this.filename}'
doc = FreeCAD.open(file_path)

# Get active document
if doc is None:
    result = None
else:
    # Find cuboid and wedge cut in the document
    main_cube = None
    wedge_cut = None
    
    # Check all objects, look for cuboid and wedge cut
    for obj in doc.Objects:
        # Check if it's a solid object
        if hasattr(obj, "Shape"):
            # Check shape type
            if hasattr(obj.Shape, "ShapeType"):
                # For objects created using Part Design method, we need to check sub-objects
                if obj.TypeId == "PartDesign::Body":
                    # Prevent counting the same object multiple times
                    processed_objects = set()
                    
                    for subobj in obj.OutList:
                        if hasattr(subobj, "Shape") and hasattr(subobj.Shape, "ShapeType"):
                            # Use TypeId to check if it's an additive box
                            if subobj.TypeId == 'PartDesign::AdditiveBox' or subobj.TypeId == 'Part::Box':
                                # Use object ID as unique identifier
                                obj_id = subobj.ID if hasattr(subobj, "ID") else subobj.Name
                                
                                # Skip if this object has been processed
                                if obj_id in processed_objects:
                                    continue
                                processed_objects.add(obj_id)
                                
                                if subobj.Shape.ShapeType == "Solid" and hasattr(subobj.Shape, "Volume"):
                                    # Get cuboid dimensions
                                    cube_length = subobj.Length.Value if hasattr(subobj, "Length") else 0
                                    cube_width = subobj.Width.Value if hasattr(subobj, "Width") else 0
                                    cube_height = subobj.Height.Value if hasattr(subobj, "Height") else 0
                                    
                                    # Get position information
                                    cube_position = None
                                    if hasattr(subobj, "Placement") and hasattr(subobj.Placement, "Base"):
                                        cube_position = {
                                            'x': subobj.Placement.Base.x,
                                            'y': subobj.Placement.Base.y,
                                            'z': subobj.Placement.Base.z
                                        }
                                    
                                    # Store cuboid information
                                    main_cube = {
                                        'length': cube_length,
                                        'width': cube_width,
                                        'height': cube_height,
                                        'position': cube_position
                                    }
                            
                            # Use TypeId to check if it's a subtractive wedge
                            elif subobj.TypeId == 'PartDesign::SubtractiveWedge' or subobj.TypeId.endswith('::Wedge'):
                                # Use object ID as unique identifier
                                obj_id = subobj.ID if hasattr(subobj, "ID") else subobj.Name
                                
                                # Skip if this object has been processed
                                if obj_id in processed_objects:
                                    continue
                                processed_objects.add(obj_id)
                                
                                if subobj.Shape.ShapeType == "Solid" and hasattr(subobj.Shape, "Volume"):
                                    # Get wedge parameters
                                    wedge_Xmin = subobj.Xmin.Value if hasattr(subobj, "Xmin") else 0.0
                                    wedge_Xmax = subobj.Xmax.Value if hasattr(subobj, "Xmax") else 0.0
                                    wedge_Ymin = subobj.Ymin.Value if hasattr(subobj, "Ymin") else 0.0
                                    wedge_Ymax = subobj.Ymax.Value if hasattr(subobj, "Ymax") else 0.0
                                    wedge_Zmin = subobj.Zmin.Value if hasattr(subobj, "Zmin") else 0.0
                                    wedge_Zmax = subobj.Zmax.Value if hasattr(subobj, "Zmax") else 0.0
                                    wedge_X2min = subobj.X2min.Value if hasattr(subobj, "X2min") else 0.0
                                    wedge_X2max = subobj.X2max.Value if hasattr(subobj, "X2max") else 0.0
                                    wedge_Z2min = subobj.Z2min.Value if hasattr(subobj, "Z2min") else 0.0
                                    wedge_Z2max = subobj.Z2max.Value if hasattr(subobj, "Z2max") else 0.0
                                    
                                    # Get position information
                                    wedge_position = None
                                    if hasattr(subobj, "Placement") and hasattr(subobj.Placement, "Base"):
                                        wedge_position = {
                                            'x': subobj.Placement.Base.x,
                                            'y': subobj.Placement.Base.y,
                                            'z': subobj.Placement.Base.z
                                        }
                                    
                                    # Store wedge information
                                    wedge_cut = {
                                        'Xmin': wedge_Xmin,
                                        'Xmax': wedge_Xmax,
                                        'Ymin': wedge_Ymin,
                                        'Ymax': wedge_Ymax,
                                        'Zmin': wedge_Zmin,
                                        'Zmax': wedge_Zmax,
                                        'X2min': wedge_X2min,
                                        'X2max': wedge_X2max,
                                        'Z2min': wedge_Z2min,
                                        'Z2max': wedge_Z2max,
                                        'position': wedge_position
                                    }
    
    # Handle values that might have units
    def extract_value(val):
        if val is None:
            return None
        try:
            # If it's a string with unit (like "10.0 mm"), extract the numeric part
            if isinstance(val, str) and ' ' in val:
                return float(val.split()[0])
            # If it's a FreeCAD Quantity object, try converting to float
            return float(val)
        except:
            # If conversion fails, return original value
            return val
    
    # Return result
    result = {
        'cube_length': extract_value(main_cube['length']) if main_cube else None,
        'cube_width': extract_value(main_cube['width']) if main_cube else None,
        'cube_height': extract_value(main_cube['height']) if main_cube else None,
        'wedge_Xmin': extract_value(wedge_cut['Xmin']) if wedge_cut else None,
        'wedge_Xmax': extract_value(wedge_cut['Xmax']) if wedge_cut else None,
        'wedge_Ymin': extract_value(wedge_cut['Ymin']) if wedge_cut else None,
        'wedge_Ymax': extract_value(wedge_cut['Ymax']) if wedge_cut else None,
        'wedge_Zmin': extract_value(wedge_cut['Zmin']) if wedge_cut else None,
        'wedge_Zmax': extract_value(wedge_cut['Zmax']) if wedge_cut else None,
        'wedge_X2min': extract_value(wedge_cut['X2min']) if wedge_cut else None,
        'wedge_X2max': extract_value(wedge_cut['X2max']) if wedge_cut else None,
        'wedge_Z2min': extract_value(wedge_cut['Z2min']) if wedge_cut else None,
        'wedge_Z2max': extract_value(wedge_cut['Z2max']) if wedge_cut else None,
        'has_wedge_cut': wedge_cut is not None
    }
                    `
                    sendEvent(FUNCTION_KEY_WORD_DETECTED, {
                        message: `Detected ${FUNCTION_BEHAVIOR} operation`,
                        filename: this.filename,
                        code: pythonCode
                    });
                }
              } catch (error) {
                  sendEvent(ERROR, {
                      error_type: "general_error",
                      message: `Execution error: ${error.message}`
                  });
              }
          }
      });
      
      sendEvent(HOOK_INSTALLED, {
          message: `Hook installed, waiting for ${FUNCTION_BEHAVIOR} operation...`
      });
  }
  
  // Execute hook initialization immediately
  initHook();
})();


Evaluation handler:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
FreeCAD Cuboid with Wedge Cut Event Handler
Handles events generated by the hook script and updates evaluation metrics
"""

from typing import Dict, Any, Optional, List

# Event type constants
SCRIPT_INITIALIZED = "script_initialized"
FUNCTION_NOT_FOUND = "function_not_found"
FUNCTION_FOUND = "function_found"
FUNCTION_CALLED = "function_called"
FUNCTION_KEY_WORD_DETECTED = "function_key_word_detected"
ERROR = "error"
HOOK_INSTALLED = "hook_installed"

# Keyword-related constants
CUBE_LENGTH = "cube_length"
CUBE_WIDTH = "cube_width"
CUBE_HEIGHT = "cube_height"
WEDGE_XMIN = "wedge_Xmin"
WEDGE_XMAX = "wedge_Xmax"
WEDGE_YMIN = "wedge_Ymin"
WEDGE_YMAX = "wedge_Ymax"
WEDGE_ZMIN = "wedge_Zmin"
WEDGE_ZMAX = "wedge_Zmax"
WEDGE_X2MIN = "wedge_X2min"
WEDGE_X2MAX = "wedge_X2max"
WEDGE_Z2MIN = "wedge_Z2min"
WEDGE_Z2MAX = "wedge_Z2max"
HAS_WEDGE_CUT = "has_wedge_cut"

def execute_python_code(code: str, logger: Any) -> Dict[str, Any]:
    """
    Execute Python code and return results
    
    Args:
        code: Python code to execute
        logger: Logger instance
        
    Returns:
        Dict[str, Any]: Execution results
    """
    try:
        # Create a new namespace to execute the code
        namespace = {}
        exec(code, namespace)
        result = namespace.get('result', None)
        
        if result is None:
            logger.warning("Cuboid with wedge cut object not found")
            return None
            
        # Validate result format
        required_keys = [
            CUBE_LENGTH, CUBE_WIDTH, CUBE_HEIGHT, 
            WEDGE_XMIN, WEDGE_XMAX, WEDGE_YMIN, WEDGE_YMAX,
            WEDGE_ZMIN, WEDGE_ZMAX, WEDGE_X2MIN, WEDGE_X2MAX,
            WEDGE_Z2MIN, WEDGE_Z2MAX, HAS_WEDGE_CUT
        ]
        if not all(key in result for key in required_keys):
            logger.error(f"Result missing required keys: {required_keys}")
            return None
            
        return result
    except Exception as e:
        logger.error(f"Error executing Python code: {str(e)}")
        return None

def message_handler(message: Dict[str, Any], logger: Any, task_parameter: Dict[str, Any]) -> Optional[List[Dict[str, Any]]]:
    """
    Handle messages received from hook script
    
    Args:
        message: Frida message object
        logger: Logger instance
        task_parameter: Task parameters
        
    Returns:
        Optional[List[Dict[str, Any]]]: List of status updates, None if no updates
    """
    updates = []
    
    if message.get('type') == 'send' and 'payload' in message:
        payload = message['payload']
        
        if 'event' in payload:
            event_type = payload['event']
            logger.debug(f"Received event: {event_type}")
            
            if event_type == SCRIPT_INITIALIZED:
                logger.info(f"Hook script initialized: {payload.get('message', '')}")
                
            elif event_type == FUNCTION_FOUND:
                logger.info(f"Function found: {payload.get('address', '')}")
                
            elif event_type == FUNCTION_CALLED:
                logger.info(f"Function called: {payload.get('message', '')}")
                # Update first key step status
                updates.append({
                    'status': 'key_step',
                    'index': 1,
                    'name': 'Save document'
                })
                
            elif event_type == FUNCTION_KEY_WORD_DETECTED:
                # Execute Python code and get results
                code = payload.get('code', '')
                filename = payload.get('filename', '')
                expected_path = task_parameter.get("source_path", "") + task_parameter.get("filename", "")
                logger.info(f"Keyword detected, document path: {filename}, expected path: {expected_path}")
                
                if filename == expected_path:
                    result = execute_python_code(code, logger)
                    if result:
                        # Check if cuboid with wedge cut parameters match expectations
                        expected_cube_length = task_parameter.get(CUBE_LENGTH, 30)
                        expected_cube_width = task_parameter.get(CUBE_WIDTH, 20)
                        expected_cube_height = task_parameter.get(CUBE_HEIGHT, 15)
                        expected_wedge_Xmin = task_parameter.get(WEDGE_XMIN, 0.0)
                        expected_wedge_Xmax = task_parameter.get(WEDGE_XMAX, 20.0)
                        expected_wedge_Ymin = task_parameter.get(WEDGE_YMIN, 0.0)
                        expected_wedge_Ymax = task_parameter.get(WEDGE_YMAX, 10.0)
                        expected_wedge_Zmin = task_parameter.get(WEDGE_ZMIN, 0.0)
                        expected_wedge_Zmax = task_parameter.get(WEDGE_ZMAX, 10.0)
                        expected_wedge_X2min = task_parameter.get(WEDGE_X2MIN, 10.0)
                        expected_wedge_X2max = task_parameter.get(WEDGE_X2MAX, 10.0)
                        expected_wedge_Z2min = task_parameter.get(WEDGE_Z2MIN, 5.0)
                        expected_wedge_Z2max = task_parameter.get(WEDGE_Z2MAX, 5.0)

                        actual_cube_length = result[CUBE_LENGTH]
                        actual_cube_width = result[CUBE_WIDTH]
                        actual_cube_height = result[CUBE_HEIGHT]
                        actual_wedge_Xmin = result[WEDGE_XMIN]
                        actual_wedge_Xmax = result[WEDGE_XMAX]
                        actual_wedge_Ymin = result[WEDGE_YMIN]
                        actual_wedge_Ymax = result[WEDGE_YMAX]
                        actual_wedge_Zmin = result[WEDGE_ZMIN]
                        actual_wedge_Zmax = result[WEDGE_ZMAX]
                        actual_wedge_X2min = result[WEDGE_X2MIN]
                        actual_wedge_X2max = result[WEDGE_X2MAX]
                        actual_wedge_Z2min = result[WEDGE_Z2MIN]
                        actual_wedge_Z2max = result[WEDGE_Z2MAX]
                        actual_has_wedge_cut = result[HAS_WEDGE_CUT]

                        # Log key parameters
                        logger.info(f"Task parameter check: Expected cuboid {expected_cube_length}×{expected_cube_width}×{expected_cube_height}")
                        logger.info(f"Expected wedge cut: Xmin={expected_wedge_Xmin}, Xmax={expected_wedge_Xmax}, " +
                                   f"Ymin={expected_wedge_Ymin}, Ymax={expected_wedge_Ymax}, " +
                                   f"Zmin={expected_wedge_Zmin}, Zmax={expected_wedge_Zmax}, " +
                                   f"X2min={expected_wedge_X2min}, X2max={expected_wedge_X2max}, " +
                                   f"Z2min={expected_wedge_Z2min}, Z2max={expected_wedge_Z2max}")
                        logger.info(f"Actual parameters: Actual cuboid {actual_cube_length}×{actual_cube_width}×{actual_cube_height}")
                        logger.info(f"Actual wedge cut: Xmin={actual_wedge_Xmin}, Xmax={actual_wedge_Xmax}, " +
                                   f"Ymin={actual_wedge_Ymin}, Ymax={actual_wedge_Ymax}, " +
                                   f"Zmin={actual_wedge_Zmin}, Zmax={actual_wedge_Zmax}, " +
                                   f"X2min={actual_wedge_X2min}, X2max={actual_wedge_X2max}, " +
                                   f"Z2min={actual_wedge_Z2min}, Z2max={actual_wedge_Z2max}, " +
                                   f"Has wedge cut: {actual_has_wedge_cut}")

                        # Convert values that might have units to float
                        try:
                            # Try to get numeric part (handle possible units)
                            actual_cube_length_value = float(str(actual_cube_length).split()[0]) if isinstance(actual_cube_length, str) else float(actual_cube_length)
                            actual_cube_width_value = float(str(actual_cube_width).split()[0]) if isinstance(actual_cube_width, str) else float(actual_cube_width)
                            actual_cube_height_value = float(str(actual_cube_height).split()[0]) if isinstance(actual_cube_height, str) else float(actual_cube_height)
                            
                            actual_wedge_Xmin_value = float(str(actual_wedge_Xmin).split()[0]) if isinstance(actual_wedge_Xmin, str) else float(actual_wedge_Xmin)
                            actual_wedge_Xmax_value = float(str(actual_wedge_Xmax).split()[0]) if isinstance(actual_wedge_Xmax, str) else float(actual_wedge_Xmax)
                            actual_wedge_Ymin_value = float(str(actual_wedge_Ymin).split()[0]) if isinstance(actual_wedge_Ymin, str) else float(actual_wedge_Ymin)
                            actual_wedge_Ymax_value = float(str(actual_wedge_Ymax).split()[0]) if isinstance(actual_wedge_Ymax, str) else float(actual_wedge_Ymax)
                            actual_wedge_Zmin_value = float(str(actual_wedge_Zmin).split()[0]) if isinstance(actual_wedge_Zmin, str) else float(actual_wedge_Zmin)
                            actual_wedge_Zmax_value = float(str(actual_wedge_Zmax).split()[0]) if isinstance(actual_wedge_Zmax, str) else float(actual_wedge_Zmax)
                            actual_wedge_X2min_value = float(str(actual_wedge_X2min).split()[0]) if isinstance(actual_wedge_X2min, str) else float(actual_wedge_X2min)
                            actual_wedge_X2max_value = float(str(actual_wedge_X2max).split()[0]) if isinstance(actual_wedge_X2max, str) else float(actual_wedge_X2max)
                            actual_wedge_Z2min_value = float(str(actual_wedge_Z2min).split()[0]) if isinstance(actual_wedge_Z2min, str) else float(actual_wedge_Z2min)
                            actual_wedge_Z2max_value = float(str(actual_wedge_Z2max).split()[0]) if isinstance(actual_wedge_Z2max, str) else float(actual_wedge_Z2max)
                            
                            # Allow small error margin (0.01%)
                            cube_length_error = abs((actual_cube_length_value - expected_cube_length) / expected_cube_length) <= 0.0001
                            cube_width_error = abs((actual_cube_width_value - expected_cube_width) / expected_cube_width) <= 0.0001
                            cube_height_error = abs((actual_cube_height_value - expected_cube_height) / expected_cube_height) <= 0.0001
                            
                            wedge_Xmin_error = abs((actual_wedge_Xmin_value - expected_wedge_Xmin) / max(expected_wedge_Xmin, 0.0001)) <= 0.0001
                            wedge_Xmax_error = abs((actual_wedge_Xmax_value - expected_wedge_Xmax) / expected_wedge_Xmax) <= 0.0001
                            wedge_Ymin_error = abs((actual_wedge_Ymin_value - expected_wedge_Ymin) / max(expected_wedge_Ymin, 0.0001)) <= 0.0001
                            wedge_Ymax_error = abs((actual_wedge_Ymax_value - expected_wedge_Ymax) / expected_wedge_Ymax) <= 0.0001
                            wedge_Zmin_error = abs((actual_wedge_Zmin_value - expected_wedge_Zmin) / max(expected_wedge_Zmin, 0.0001)) <= 0.0001
                            wedge_Zmax_error = abs((actual_wedge_Zmax_value - expected_wedge_Zmax) / expected_wedge_Zmax) <= 0.0001
                            wedge_X2min_error = abs((actual_wedge_X2min_value - expected_wedge_X2min) / expected_wedge_X2min) <= 0.0001
                            wedge_X2max_error = abs((actual_wedge_X2max_value - expected_wedge_X2max) / expected_wedge_X2max) <= 0.0001
                            wedge_Z2min_error = abs((actual_wedge_Z2min_value - expected_wedge_Z2min) / expected_wedge_Z2min) <= 0.0001
                            wedge_Z2max_error = abs((actual_wedge_Z2max_value - expected_wedge_Z2max) / expected_wedge_Z2max) <= 0.0001
                            has_wedge_cut_correct = actual_has_wedge_cut
                        except Exception as e:
                            logger.error(f"Error comparing parameters: {str(e)}")
                            cube_length_error = False
                            cube_width_error = False
                            cube_height_error = False
                            wedge_Xmin_error = False
                            wedge_Xmax_error = False
                            wedge_Ymin_error = False
                            wedge_Ymax_error = False
                            wedge_Zmin_error = False
                            wedge_Zmax_error = False
                            wedge_X2min_error = False
                            wedge_X2max_error = False
                            wedge_Z2min_error = False
                            wedge_Z2max_error = False
                            has_wedge_cut_correct = False
                        
                        cube_correct = cube_length_error and cube_width_error and cube_height_error
                        wedge_correct = (wedge_Xmin_error and wedge_Xmax_error and
                                       wedge_Ymin_error and wedge_Ymax_error and
                                       wedge_Zmin_error and wedge_Zmax_error and
                                       wedge_X2min_error and wedge_X2max_error and
                                       wedge_Z2min_error and wedge_Z2max_error and
                                       has_wedge_cut_correct)
                        
                        if cube_correct and wedge_correct:
                            # Update second key step status
                            updates.append({
                                'status': 'key_step',
                                'index': 2,
                                'name': 'Cuboid with wedge cut created and saved successfully'
                            })
                            
                            # Task completed successfully
                            updates.append({
                                'status': 'success',
                                'reason': 'Successfully created and saved a cuboid with wedge cut meeting requirements'
                            })
                        else:
                            logger.warning(f"Parameter validation failed: " + 
                                          f"Cuboid correct: {cube_correct}, " +
                                          f"Wedge cut correct: {wedge_correct}")
                
            elif event_type == ERROR:
                error_type = payload.get("error_type", "unknown")
                error_message = payload.get("message", "Unknown error")
                
                logger.error(f"Hook script error ({error_type}): {error_message}")
                
                # Record error event
                updates.append({
                    'status': 'error',
                    'type': error_type,
                    'message': error_message
                })
                
    elif message.get('type') == 'error':
        logger.error(f"Hook script error: {message.get('stack', '')}")
        
        # Record error event
        updates.append({
            'status': 'error',
            'type': 'script_error',
            'message': message.get('stack', 'Unknown error')
        })
    
    return updates if updates else None