Task configuration:
{"task_id": "24", "task_name": "configure_streaming_settings", "description": "Configure some settings in Output", "application_info": {"name": "obs-studio", "executable_path": "apps/obs-studio/bin/64bit/obs", "args": []}, "task_parameters": {"video_bitrate": "2000", "audio_bitrate": "320", "encoder_preset": "faster", "replay_buffer_time": "30"}, "instruction_template": "Use a profile in obs-studio, set the video bitrate to ${video_bitrate}Kbps, audio bitrate to ${audio_bitrate}, encoder preset to ${encoder_preset} in the output streming settings with output mode Simple, and enable Replay Buffer with maximum replay time of ${replay_buffer_time} seconds", "evaluation_setup": {"scripts": [{"role": "hook", "path": "hooker.js"}, {"role": "handler", "path": "handler.py"}], "timeout": 180}, "total_key_steps": 5, "events": {"video_bitrate_set": {"key_step_name": "Set video bitrate", "description": "Set video bitrate to 2000Kbps", "is_key_step": true, "key_step_index": 1}, "audio_bitrate_set": {"key_step_name": "Set audio bitrate", "description": "Set audio bitrate to 320", "is_key_step": true, "key_step_index": 2}, "encoder_preset_set": {"key_step_name": "Set encoder preset", "description": "Set encoder preset to faster", "is_key_step": true, "key_step_index": 3}, "replay_buffer_enabled": {"key_step_name": "Enable replay buffer", "description": "Enable replay buffer", "is_key_step": true, "key_step_index": 4}, "replay_time_set": {"key_step_name": "Set replay time", "description": "Set maximum replay time to 30 seconds", "is_key_step": true, "key_step_index": 5}}, "mcp_servers": [{"command": "node", "args": ["/home/agent/obs-mcp/build/index.js"]}]}

Hook script:
(function () {
    // Script settings
    const MESSAGE_script_initialized = "Monitoring script has started";
    const MESSAGE_hook_installed = "Monitoring hook installed, waiting for operations...";
    const MESSAGE_config_updated = "Configuration update detected";

    // Send events to the evaluation system
    function sendEvent(eventType, data = {}) {
        const payload = {
            event: eventType,
            ...data,
            timestamp: new Date().getTime()
        };
        send(payload);
    }

    // Get function address
    function getFunctionAddress(functionName) {
        const funcAddr = DebugSymbol.getFunctionByName(functionName);
        if (!funcAddr) {
            sendEvent("error", {
                error_type: "function_not_found",
                message: `Unable to find function ${functionName}`
            });
            return null;
        }

        sendEvent("debug", {
            address: funcAddr.toString(),
            message: `Found the actual address of function ${functionName}`
        });
        return funcAddr;
    }

    // Monitor configuration file modifications
    function hookConfigSave() {
        let function_name = "config_save";
        let symbol_name = "config_save";

        Interceptor.attach(getFunctionAddress(symbol_name), {
            onEnter(args) {
                this.configFile = args[0];
                sendEvent("debug", {
                    message: "Saving configuration file",
                    function: function_name
                });
            },
            onLeave(retval) {
                sendEvent("config_saved", {
                    message: MESSAGE_config_updated,
                    function: function_name,
                    result: retval.toInt32(),
                    configFile: this.configFile.readPointer().readCString()
                });
            }
        });
    }

    // Monitor video bitrate settings
    function hookVideoBitrateSet() {
        let function_name = "config_set_int";
        let symbol_name = "config_set_int";

        Interceptor.attach(getFunctionAddress(symbol_name), {
            onEnter(args) {
                if (args[0] === null) return;

                this.section = args[1].readCString();
                this.name = args[2].readCString();
                this.value = args[3].toInt32();

                // Check if setting video bitrate
                if (this.section === "SimpleOutput" && this.name === "VBitrate" && this.value === 2000) {
                    sendEvent("video_bitrate_set", {
                        message: "Video bitrate has been set to 2000",
                        section: this.section,
                        name: this.name,
                        value: this.value
                    });
                }

                // Check if setting replay time
                if (this.section === "SimpleOutput" && this.name === "RecRBTime" && this.value === 30) {
                    sendEvent("replay_time_set", {
                        message: "Maximum replay time has been set to 30 seconds",
                        section: this.section,
                        name: this.name,
                        value: this.value
                    });
                }
            },
            onLeave(retval) {}
        });
    }

    // Monitor encoder preset settings
    function hookEncoderPresetSet() {
        let function_name = "config_set_string";
        let symbol_name = "config_set_string";

        Interceptor.attach(getFunctionAddress(symbol_name), {
            onEnter(args) {
                if (args[0] === null) return;

                this.section = args[1].readCString();
                this.name = args[2].readCString();
                
                // Check if string value is null
                if (args[3] !== null) {
                    this.value = args[3].readCString();
                    console.log("Set value:", this.value);
                
                    // Check if setting encoder preset
                    if (this.section === "SimpleOutput" && this.name === "Preset" && this.value === "faster") {
                        sendEvent("encoder_preset_set", {
                            message: "Encoder preset has been set to faster",
                            section: this.section,
                            name: this.name,
                            value: this.value
                        });
                    }

                    // Check if setting audio bitrate
                    if (this.section === "SimpleOutput" && this.name === "ABitrate" && this.value === "320") {
                        sendEvent("audio_bitrate_set", {
                            message: "Audio bitrate has been set to 320",
                            section: this.section,
                            name: this.name,
                            value: this.value
                        });
                    }
                }
            },
            onLeave(retval) {}
        });
    }

    // Monitor replay buffer enable settings
    function hookReplayBufferEnable() {
        let function_name = "config_set_bool";
        let symbol_name = "config_set_bool";

        Interceptor.attach(getFunctionAddress(symbol_name), {
            onEnter(args) {
                if (args[0] === null) return;

                this.section = args[1].readCString();
                this.name = args[2].readCString();
                this.value = args[3].toInt32();

                // Check if enabling replay buffer
                if (this.section === "SimpleOutput" && this.name === "RecRB" && this.value === 1) {
                    sendEvent("replay_buffer_enabled", {
                        message: "Replay buffer has been enabled",
                        section: this.section,
                        name: this.name,
                        value: this.value
                    });
                }
            },
            onLeave(retval) {}
        });
    }

    // Initialize all hook functions
    function initHook() {
        sendEvent("script_initialized", {
            message: MESSAGE_script_initialized
        });

        // Initialize each hook
        hookConfigSave();
        hookVideoBitrateSet();
        hookEncoderPresetSet();
        hookReplayBufferEnable();

        sendEvent("hook_installed", {
            message: MESSAGE_hook_installed
        });
    }

    // Start script
    initHook();
})();

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

from typing import Dict, Any, Optional, List
import configparser
import os

# Task completion status tracking
_TASK_STATUS = {
    "video_bitrate_set": False,
    "audio_bitrate_set": False,
    "encoder_preset_set": False,
    "replay_buffer_enabled": False,
    "replay_time_set": False,
}

key_steps = []


def check_task_completion() -> Optional[List[Dict[str, Any]]]:
    """Check if all tasks have been completed"""
    global key_steps
    all_completed = all(_TASK_STATUS.values())

    if all_completed:
        key_steps.append(
            {
                "status": "success",
                "reason": "All settings have been successfully completed",
            }
        )
        return key_steps
    return None


def message_handler(
    message: Dict[str, Any], logger, task_parameter: Dict[str, Any]
) -> Optional[List[Dict[str, Any]]]:
    global key_steps
    payload = message["payload"]
    print(payload)
    event_type = payload["event"]
    logger.debug(f"Received event: {event_type}")

    # Handle various event types
    if event_type == "video_bitrate_set":
        expected_value = int(task_parameter["video_bitrate"])
        if payload.get("value") == expected_value:
            _TASK_STATUS["video_bitrate_set"] = True
            key_steps.append({"status": "key_step", "index": 1})
            logger.info(f"Video bitrate has been correctly set to {expected_value}Kbps")

    elif event_type == "audio_bitrate_set":
        expected_value = int(task_parameter["audio_bitrate"])
        if int(payload.get("value")) == expected_value:
            _TASK_STATUS["audio_bitrate_set"] = True
            key_steps.append({"status": "key_step", "index": 2})
            logger.info(f"Audio bitrate has been correctly set to {expected_value}")

    elif event_type == "encoder_preset_set":
        expected_value = task_parameter["encoder_preset"]
        if payload.get("value") == expected_value:
            _TASK_STATUS["encoder_preset_set"] = True
            key_steps.append({"status": "key_step", "index": 3})
            logger.info(f"Encoder preset has been correctly set to {expected_value}")

    elif event_type == "replay_buffer_enabled":
        if payload.get("value") == 1:
            _TASK_STATUS["replay_buffer_enabled"] = True
            key_steps.append({"status": "key_step", "index": 4})
            logger.info("Replay buffer has been successfully enabled")

    elif event_type == "replay_time_set":
        expected_value = int(task_parameter["replay_buffer_time"])
        if payload.get("value") == expected_value:
            _TASK_STATUS["replay_time_set"] = True
            key_steps.append({"status": "key_step", "index": 5})
            logger.info(
                f"Replay time has been correctly set to {expected_value} seconds"
            )

    elif event_type == "config_saved":
        config_file = payload.get("configFile")

        # Check if the ini file exists
        if os.path.exists(config_file):
            config = configparser.ConfigParser()
            config.read(config_file)
            # Check if the SimpleOutput section exists
            if config.has_section("SimpleOutput"):
                # Use configparser's interface to check the SimpleOutput section's configuration
                section = "SimpleOutput"

                # Check video bitrate setting
                if config.has_option(section, "VBitrate"):
                    expected_video_bitrate = int(task_parameter["video_bitrate"])
                    actual_video_bitrate = config.getint(section, "VBitrate")
                    if actual_video_bitrate == expected_video_bitrate:
                        logger.info(
                            f"Video bitrate in the configuration file has been correctly set to {expected_video_bitrate}Kbps"
                        )
                        _TASK_STATUS["video_bitrate_set"] = True
                        if not dict_have_index(key_steps, 1):
                            key_steps.append({"status": "key_step", "index": 1})
                    else:
                        logger.warning(
                            f"Video bitrate setting in the configuration file is incorrect: {actual_video_bitrate}"
                        )

                # Check audio bitrate setting
                if config.has_option(section, "ABitrate"):
                    expected_audio_bitrate = int(task_parameter["audio_bitrate"])
                    actual_audio_bitrate = config.getint(section, "ABitrate")
                    if actual_audio_bitrate == expected_audio_bitrate:
                        logger.info(
                            f"Audio bitrate in the configuration file has been correctly set to {expected_audio_bitrate}"
                        )
                        _TASK_STATUS["audio_bitrate_set"] = True
                        if not dict_have_index(key_steps, 2):
                            key_steps.append({"status": "key_step", "index": 2})
                    else:
                        logger.warning(
                            f"Audio bitrate setting in the configuration file is incorrect: {actual_audio_bitrate}"
                        )

                # Check encoder preset
                if config.has_option(section, "Preset"):
                    expected_preset = task_parameter["encoder_preset"]
                    actual_preset = config.get(section, "Preset")
                    if actual_preset == expected_preset:
                        logger.info(
                            f"Encoder preset in the configuration file has been correctly set to {expected_preset}"
                        )
                        _TASK_STATUS["encoder_preset_set"] = True
                        if not dict_have_index(key_steps, 3):
                            key_steps.append({"status": "key_step", "index": 3})
                    else:
                        logger.warning(
                            f"Encoder preset setting in the configuration file is incorrect: {actual_preset}"
                        )

                # Check replay buffer enabled status
                if config.has_option(section, "RecRB"):
                    is_enabled = config.getboolean(section, "RecRB")
                    if is_enabled:
                        logger.info(
                            "Replay buffer has been successfully enabled in the configuration file"
                        )
                        _TASK_STATUS["replay_buffer_enabled"] = True
                        if not dict_have_index(key_steps, 4):
                            key_steps.append({"status": "key_step", "index": 4})
                    else:
                        logger.warning(
                            "Replay buffer is not enabled in the configuration file"
                        )

                # Check replay time setting
                if config.has_option(section, "RecRBTime"):
                    expected_replay_time = int(task_parameter["replay_buffer_time"])
                    actual_replay_time = config.getint(section, "RecRBTime")
                    if actual_replay_time == expected_replay_time:
                        logger.info(
                            f"Replay time in the configuration file has been correctly set to {expected_replay_time} seconds"
                        )
                        _TASK_STATUS["replay_time_set"] = True
                        if not dict_have_index(key_steps, 5):
                            key_steps.append({"status": "key_step", "index": 5})
                    else:
                        logger.warning(
                            f"Replay time setting in the configuration file is incorrect: {actual_replay_time}"
                        )

    # Check if all tasks have been completed
    return check_task_completion()


def dict_have_index(key_steps: List[Dict[str, Any]], index: int) -> bool:
    for key_step in key_steps:
        if "index" in key_step and key_step["index"] == index:
            return True

    return False