Task configuration:
{"task_id": "24", "task_name": "\u65b0\u5efa\u4e00\u4e2a\u95ee\u7b54\u9898\u6a21\u677f", "description": "\u65b0\u5efa\u4e00\u4e2a\u95ee\u9898\u9898\u6a21\u677f\uff0c\u542b\u6709\u4e00\u4e2a\"\u7b14\u8bb0\"\u90e8\u5206\u3002\u5e76\u6dfb\u52a0\u4e00\u5f20\u5361\u724c", "application_info": {"name": "anki", "executable_path": "/home/agent/anki/out/pyenv/bin/python", "args": ["/home/agent/anki/tools/run.py"], "cwd": "/home/agent/anki"}, "task_parameters": {"name": "simple2", "first_field": "The quick brown fox jumps over the lazy dog.", "second_field": "test", "third_field": "note"}, "instruction_template": "\u521b\u5efa\u4e00\u4e2a\u53eb${name}\u7684\u6a21\u677f\uff0c\u590d\u5236\u95ee\u7b54\u9898\u7684\u6a21\u677f\u3002\u6dfb\u52a0\u4e00\u4e2a\u65b0\u5b57\u6bb5\u53ebNote,\u5e76\u653e\u5728\u7b2c\u4e09\u4e2a\u5b57\u6bb5\u7684\u4f4d\u7f6e\u3002\u5728\u6b63\u9762\u4f7f\u7528\u6761\u4ef6\u66ff\u6362\u8bed\u6cd5\uff0c\u4f8b\u5982\u8fd9\u6837\u7684\uff1a{{#Tags}}\n\u6807\u7b7e\uff1a{{Tags}}\n{{/Tags}}\u3002\u4f7f\u7528\u6761\u4ef6\u66ff\u6362\u8bed\u6cd5\uff0c\u5982\u679c\u5b58\u5728Note\u5b57\u6bb5\uff0c\u5219\u5c06\u6b63\u9762\u6807\u84dd\uff0c\u5e76\u628aNote\u653e\u5230\u53cd\u9762\u7b54\u6848\u7684\u540e\u9762\uff0c\u7528<br>\u9694\u5f00\uff0c\u5e76\u4e14\u7528Note:{{Note}}\u5c55\u793a\uff0c\u5982\u679c\u6ca1\u6709Note\u7684\u60c5\u51b5\uff0c\u4e0d\u5fc5\u663e\u793aNote\u8fd9\u4e00\u884c\u3002\u6dfb\u52a0\u4e00\u5f20\u5361\u7247\uff0c\u5361\u7247\u7684\u6b63\u9762\u5199\u4e0a\"${first_field}\"\uff0c\u53cd\u9762\u5199\u4e0a\"${second_field}\",Note\u5199\u4e0a\"${thrid_field}\"", "evaluation_setup": {"scripts": [{"role": "hook", "path": "hooker.js", "dependency": ["../common/hooker_common.js"]}, {"role": "handler", "path": "handler.py"}], "timeout": 120}, "events": {"add_notetype": {"description": "\u6dfb\u52a0\u6210\u529f", "is_key_step": true, "key_step_index": 1, "key_step_name": "\u6dfb\u52a0\u6210\u529f"}, "notetype_field_correct": {"description": "\u5b57\u6bb5\u6b63\u786e", "is_key_step": true, "key_step_index": 2, "key_step_name": "\u5b57\u6bb5\u6b63\u786e"}, "notetype_template_correct": {"description": "\u6a21\u677f\u6b63\u786e", "is_key_step": true, "key_step_index": 3, "key_step_name": "\u6a21\u677f\u6b63\u786e"}, "add_card_success": {"description": "\u6dfb\u52a0\u5361\u7247\u6210\u529f", "is_key_step": true, "key_step_index": 4, "key_step_name": "\u6dfb\u52a0\u5361\u7247\u6210\u529f"}, "card_correct": {"description": "\u5361\u7247\u5185\u5bb9\u6b63\u786e", "is_key_step": true, "key_step_index": 5, "key_step_name": "\u5361\u7247\u5185\u5bb9\u6b63\u786e"}}, "sql_path": "/home/agent/.local/share/Anki2/sam/collection.anki2", "total_key_steps": 4, "mcp_servers": [{"command": "/home/agent/anki-mcp-server/.venv/bin/python", "args": ["/home/agent/anki-mcp-server/run_server.py"]}]}

Hook script:
const TRACE_FUNCTION = [
    "storage_update_notetypes",
    "storage_add_card"
]
function initHooks() {
    // iterate function name and addr, init it.
    for (const function_name of TRACE_FUNCTION){
        initHook(function_name, TRACE_MAPS[function_name]);
    }
}
initHooks();
sendLog("info", "add hooks done");

Evaluation handler:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import os
sys.path.append(os.path.dirname(__file__))
from common import *
import re


def handle_storage_update_notetypes(context: Context,message) -> Status:
    status = Status()
    notetype : Notetype = None
    time.sleep(0.3)
    context.update_database()
    for i in AnkiObjMap().array_by_type("notetype"):
        if i.name == tp.name:
            notetype = i
            if not context.monitor.is_event_triggered(EventAddNotetype()):
                status.emit(EventAddNotetype())
            break
    if notetype is None:
        return None
    else:
        context._tracking_id = notetype.id

    if len(notetype.fields) == 3 and  notetype.fields[2] == "Note":
        status.emit(EventNotetypeFieldCorrect())
    front_side_pattern = r'\{\{#Note\}\}.*color:blue.*\{\{/Note\}\}.*\{\{正面\}\}.*\{\{#Note\}\}.*\{\{/Note\}\}'
    back_side_pattern = r'.\{\{FrontSide\}\}.*\{\{背面\}\}.*<br>.*\{\{#Note\}\}.*Note:\s*\{\{Note\}\}.*\{\{/Note\}\}'
    if  len(notetype.templates) == 2:
        if re.findall(front_side_pattern,notetype.templates[0],re.DOTALL):
            print("Front side pattern matched") 
        else:
            print(notetype.templates[0])
            return status
        if re.findall(back_side_pattern,notetype.templates[1],re.DOTALL):
            print("Back side pattern matched") 
        else:
            print(notetype.templates[1])
            return status
        status.emit(EventNotetypeTemplateCorrect())

    return status

def handle_storage_add_card(context: Context,message) -> Status:
    status = Status()
    if not context.monitor.is_event_triggered(EventNotetypeTemplateCorrect()):
        return None
    context.update_database()
    latest : Card = sorted(context.cards,key=lambda x: x.mod,reverse=True)[0]
    note :Note = latest.get_note()
    if note.mid != context._tracking_id:
        print(f"Error: Latest card's note {note.mid} does not match the tracking id({context._tracking_id}).")
        return None
    status.emit(EventAddCardSuccess())
    status.mark_progress()

    if len(note.fields) == 3 and note.fields[0] == tp.first_field and note.fields[1] == tp.second_field and note.fields[2] == tp.third_field:
        status.emit(EventCardCorrect())
    return status
    

TRACE_HANDLERS = {
    "storage_update_notetypes" : handle_storage_update_notetypes,
    "storage_add_card" : handle_storage_add_card
}   
dependency_graph = {
    add_notetype_ : [],
    notetype_field_correct_ : [add_notetype_],
    notetype_template_correct_ : [notetype_field_correct_],
    add_card_success_ : [notetype_template_correct_],
    card_correct_ : [add_card_success_],
}
finished_list = [
    card_correct_
]

bind_handlers(TRACE_HANDLERS,dependency_graph,finished_list)