def METHOD_NAME(thread: list[ExportMessageNode]) -> bool:
    if mode == "sft":
        # in SFT mode `not thread[-1].replies` finds nodes without children (leaves).
        # We are interested in those which are role='assistant' but some trees don't end on assistant nodes
        # but have prompter leaves .. we want to use those trees too .. e.g. remove the last prompter message(s)
        # so that they end with assistant. The `thread[-2].replies[0] == thread[-1]` check makes sure that only
        # the FIRST prompter reply is added .. e.g. the parent does not appear multiple times and we can use
        # pop() to remove superfluous prompter leaf node later.
        return (
            len(thread) > 1
            and not thread[-1].replies
            and (thread[-1].role == "assistant" or thread[-2].replies[0] == thread[-1])
            and thread_filter(thread)
        )
    elif mode == "rm":
        # for reward models we use thread-fragments ending on prompter messages as prefix and
        # their (ranked) replies as possible continuations.
        if thread[-1].replies is None:
            return False
        return (
            thread[-1].role == "prompter"
            and len([r for r in thread[-1].replies if r.rank is not None]) > 1
            and thread_filter(thread)
        )
    elif mode == "rl":
        # during rl we are interested in all possible prefixes ending in prompter messages
        return thread[-1].role == "prompter" and not any(m.deleted or m.synthetic for m in thread)
    raise RuntimeError()