def _remove_already_computed_feedbacks(
    events: pd.DataFrame,
    feedback_name: str,
    flattened_inputs: List[
        Tuple[str, Optional[str], Dict[str, FeedbackFunctionInput]]
    ],
) -> List[Tuple[str, Optional[str], Dict[str, FeedbackFunctionInput]]]:
    """Remove inputs that have already been computed.

    Args:
        events: DataFrame containing trace events.
        feedback_name: Name of the feedback function.
        flattened_inputs:
            Flattened inputs to remove inputs that have already been computed
            from.

    Returns:
        List of inputs that have not already been computed.
    """
    attributes = events["record_attributes"]
    eval_root_attributes = attributes[
        attributes.apply(
            lambda curr: curr.get(SpanAttributes.SPAN_TYPE)
            == SpanAttributes.SpanType.EVAL_ROOT
        )
    ]
    record_id_to_eval_root_attributes = eval_root_attributes.groupby(
        by=eval_root_attributes.apply(
            lambda curr: curr.get(SpanAttributes.RECORD_ID)
        )
    )
    ret = []
    for record_id, span_group, inputs in flattened_inputs:
        curr_eval_root_attributes = []
        if record_id in record_id_to_eval_root_attributes.groups:
            curr_eval_root_attributes = (
                record_id_to_eval_root_attributes.get_group(record_id)
            )
        if not _feedback_already_computed(
            span_group, inputs, feedback_name, curr_eval_root_attributes
        ):
            ret.append((record_id, span_group, inputs))
    return ret
Remove inputs that have already been computed.

    Args:
        events: DataFrame containing trace events.
        feedback_name: Name of the feedback function.
        flattened_inputs:
            Flattened inputs to remove inputs that have already been computed
            from.

    Returns:
        List of inputs that have not already been computed.
    
src/feedback/trulens/feedback/computer.py