Task configuration:
{"task_id": "03", "task_name": "open_doc", "description": "Open an existing document in FreeCAD", "application_info": {"name": "FreeCAD", "executable_path": "/usr/local/bin/FreeCAD", "args": []}, "task_parameters": {"source_path": "/FreeCAD/", "filename": "task03.FCStd"}, "instruction_template": "The application is already open. Open a document in FreeCAD application, the document name is ${source_path}${filename}, show the opening result", "evaluation_setup": {"scripts": [{"role": "hook", "path": "hooker.js"}, {"role": "handler", "path": "handler.py"}], "timeout": 120}, "preconditions": {"FreeCAD_running": true}, "total_key_steps": 1, "events": {"script_initialized": {"description": "Hook script initialized", "is_key_step": false}, "function_found": {"description": "Found document open function", "is_key_step": false}, "function_called": {"description": "Document open function called", "is_key_step": false}, "function_key_word_detected": {"description": "Detected document open key content", "is_key_step": true, "key_step_index": 1, "key_step_name": "Successfully opened the specified document"}, "error": {"description": "Error event", "is_key_step": false}, "hook_installed": {"description": "Hook installed successfully", "is_key_step": false}}, "mcp_servers": [{"command": "python3", "args": ["/home/agent/.local/share/FreeCAD/Mod/freecad_mcp/src/freecad_bridge.py"]}]}

Hook script:
// FreeCAD Open Document Monitoring Hook Script
// Used to monitor document open operations in FreeCAD and detect any queries

(function() {
    // Script constants
    const FUNCTION_NAME = "_ZN3App11Application12openDocumentEPKcb"
    const ORIGIN_FUNCTION_NAME = "Application::openDocument"
    const FUNCTION_BEHAVIOR = "open 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 variables
    let funcFound = false;
    
    // Send event to evaluation system
    function sendEvent(eventType, data = {}) {
        const payload = {
            event: eventType,
            ...data,
            timestamp: new Date().getTime()
        };
        send(payload);
    }
    
    // Find Application::open function
    function getFunction() {
        // Try to find directly through exported symbol
        let FuncAddr = DebugSymbol.getFunctionByName(FUNCTION_NAME);
        
        // If not found, report 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 open document function
        const funcAddr = getFunction();
        if (!funcAddr) {
            return;
        }
        
        // Install hook on open document function
        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) {
                        sendEvent(FUNCTION_KEY_WORD_DETECTED, {
                            message: `Detected ${FUNCTION_BEHAVIOR} operation`,
                            filename: this.filename
                        });
                    }
                } catch (error) {
                    sendEvent(ERROR, {
                        error_type: "general_error",
                        message: `Execution error: ${error.message}`
                    });
                }
            }
        });
        
        sendEvent(HOOK_INSTALLED, {
            message: `Hook installation complete, waiting for ${FUNCTION_BEHAVIOR} operation...`
        });
    }
    
    // Execute hook initialization immediately
    initHook();
})();

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

"""
FreeCAD Event Handler
Responsible for handling events generated by hook scripts and updating evaluation metrics
"""

import os
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"

# Constants definition
SOURCE_PATH = "source_path"
KEY = "filename"

def message_handler(message: Dict[str, Any], logger: Any, task_parameter: Dict[str, Any]) -> Optional[List[Dict[str, Any]]]:
    """
    Process messages received from hook script

    Args:
        message: Frida message object
        logger: Logger object for logging
        task_parameter: Task parameters

    Returns:
        Optional[List[Dict[str, Any]]]: List of status dictionaries or None
    """
    # Process message
    if message.get('type') == 'send' and 'payload' in message:
        payload = message['payload']
        
        # Check if contains event type
        if 'event' in payload:
            event_type = payload['event']
            logger.debug(f"Received event: {event_type}")
            
            # List for status updates to return
            updates = []
            
            # Handle specific events
            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', '')}")
                # No longer mark this as a key step
                
            elif event_type == FUNCTION_CALLED: 
                logger.info(f"Function called: {payload.get('message', '')}")
                # No longer mark this as a key step
                
            elif event_type == FUNCTION_KEY_WORD_DETECTED:
                log_info = f"Function detected keyword: {payload.get('message', '')}"
                logger.info(log_info)

                source_path = task_parameter.get(SOURCE_PATH, '')
                expected_key = source_path + task_parameter.get(KEY, '')
                key = payload.get('filename', '')
                logger.debug(f"Expected keyword: {expected_key}, Actual keyword: {key}")

                if key and os.path.exists(expected_key):
                    # This is the only key step
                    updates.append({
                        'status': 'key_step',
                        'index': 1,
                    })
                    
                    # Mark task as successful
                    updates.append({
                        'status': 'success',
                        'reason': f"Successfully opened document: {key}"
                    })
                    
                    logger.info(f"Task completed successfully! Document opened: {key}")
                
            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}")
                
                # Report error
                updates.append({
                    'status': 'error',
                    'type': error_type,
                    'message': error_message
                })
            
            # If there are status updates, return them
            if updates:
                return updates
                
    elif message.get('type') == 'error':
        logger.error(f"Hook script error: {message.get('stack', '')}")
        return [{
            'status': 'error',
            'type': 'script_error',
            'message': f"Hook script error: {message.get('description', 'Unknown error')}", 
            'stack_trace': message.get('stack', '')
        }]
    
    return None