def _collect_inputs_from_events(
    events: pd.DataFrame,
    kwarg_groups: List[Tuple[str]],
    kwarg_to_selector: Dict[str, Selector],
) -> Dict[
    Tuple[str, Optional[str]],
    Dict[Tuple[str], List[Dict[str, FeedbackFunctionInput]]],
]:
    """Collect inputs from events based on selectors.

    Args:
        events: DataFrame containing trace events.
        kwarg_groups:
            List of list of kwargs. Each sublist contains kwargs that describe
            the same spans in their selector.
        kwarg_to_selector: Mapping from function kwargs to span selectors.

    Returns:
        Mapping from (record_id, span_group) to kwarg group to inputs.
    """
    ret = defaultdict(lambda: defaultdict(list))
    span_id_to_child_events = defaultdict(list)
    for _, curr in events.iterrows():
        parent_span_id = curr["trace"]["parent_id"]
        span_id_to_child_events[parent_span_id].append(curr)
    record_roots = [
        curr
        for _, curr in events.iterrows()
        if curr["record_attributes"].get(SpanAttributes.SPAN_TYPE)
        == SpanAttributes.SpanType.RECORD_ROOT
    ]
    for kwarg_group in kwarg_groups:
        for record_root in record_roots:
            _dfs_collect_inputs_from_events(
                kwarg_group,
                kwarg_to_selector,
                span_id_to_child_events,
                record_root,
                ret,
            )
    return ret
Collect inputs from events based on selectors.

    Args:
        events: DataFrame containing trace events.
        kwarg_groups:
            List of list of kwargs. Each sublist contains kwargs that describe
            the same spans in their selector.
        kwarg_to_selector: Mapping from function kwargs to span selectors.

    Returns:
        Mapping from (record_id, span_group) to kwarg group to inputs.
    
src/feedback/trulens/feedback/computer.py