I made an assert block that uses SPLIT BY BLOCKS to tell you what the predicate's arguments were if the assertion fails. It also has a label slot for arbitrary text that's displayed as part of the error message, to help you find where in the script the error occurred.
Nice. I was a little sad when I realized that you use, e.g., LHS and RHS as the input labels for all dyadic blocks. I guess for primitives the alternative would be to have a table of all of them with appropriate labels. But for custom blocks you should be able to extract the formal parameters from the block.
Oh thanks that's a neat idea! Is there a simpler way to get the names of the parameters that I'm just missing? The only way I found seems a bit overcomplicated:
split the block definition by blocks
if the definition only contains one command block, the last n items of that list are its parameter names (where n is the number of parameters)
if it contains more than one, the parameter names are the last n items of the first item of that list