def run(
        self,
        app: Optional[
            Union[app_schema.AppDefinition, serial_utils.JSON]
        ] = None,
        record: Optional[record_schema.Record] = None,
        source_data: Optional[Dict] = None,
        **kwargs: Dict[str, Any],
    ) -> feedback_schema.FeedbackResult:
        """
        Run the feedback function on the given `record`. The `app` that
        produced the record is also required to determine input/output argument
        names.

        Args:
            app: The app that produced the record. This can be AppDefinition or a jsonized
                AppDefinition. It will be jsonized if it is not already.

            record: The record to evaluate the feedback on.

            source_data: Additional data to select from when extracting feedback
                function arguments.

            **kwargs: Any additional keyword arguments are used to set or override
                selected feedback function inputs.

        Returns:
            A FeedbackResult object with the result of the feedback function.
        """

        if isinstance(app, app_schema.AppDefinition):
            app_json = json_utils.jsonify(app)
        else:
            app_json = app

        result_vals = []

        feedback_calls = []

        feedback_result = feedback_schema.FeedbackResult(
            feedback_definition_id=self.feedback_definition_id,
            record_id=record.record_id if record is not None else "no record",
            name=self.supplied_name
            if self.supplied_name is not None
            else self.name,
        )

        source_data = self._construct_source_data(
            app=app_json, record=record, source_data=source_data
        )

        if self.if_exists is not None:
            if not self.if_exists.exists(source_data):
                logger.warning(
                    "Feedback %s skipped as %s does not exist.",
                    self.name,
                    self.if_exists,
                )
                feedback_result.status = (
                    feedback_schema.FeedbackResultStatus.SKIPPED
                )
                return feedback_result

        # Separate try block for extracting inputs from records/apps in case a
        # user specified something that does not exist. We want to fail and give
        # a warning earlier than later.
        try:
            input_combinations = list(
                self._extract_selection(
                    source_data=source_data,
                    combinations=self.combinations,
                    **kwargs,
                )
            )

        except InvalidSelector as e:
            # Handle the cases where a selector named something that does not
            # exist in source data.

            if (
                self.if_missing
                == feedback_schema.FeedbackOnMissingParameters.ERROR
            ):
                feedback_result.status = (
                    feedback_schema.FeedbackResultStatus.FAILED
                )
                raise e

            if (
                self.if_missing
                == feedback_schema.FeedbackOnMissingParameters.WARN
            ):
                feedback_result.status = (
                    feedback_schema.FeedbackResultStatus.SKIPPED
                )
                logger.warning(
                    "Feedback %s cannot run as %s does not exist in record or app.",
                    self.name,
                    e.selector,
                )
                return feedback_result

            if (
                self.if_missing
                == feedback_schema.FeedbackOnMissingParameters.IGNORE
            ):
                feedback_result.status = (
                    feedback_schema.FeedbackResultStatus.SKIPPED
                )
                return feedback_result

            feedback_result.status = feedback_schema.FeedbackResultStatus.FAILED
            raise ValueError(
                f"Unknown value for `if_missing` {self.if_missing}."
            ) from e

        try:
            # Total cost, will accumulate.
            cost = base_schema.Cost()
            multi_result = None

            # Keep track of evaluations that were skipped due to raising SkipEval.
            skipped_exceptions = []

            for ins in input_combinations:
                try:
                    result_and_meta, part_cost_tally = (
                        core_endpoint.Endpoint.track_all_costs_tally(
                            self, **ins
                        )
                    )

                    cost += part_cost_tally()

                except SkipEval as e:
                    e.feedback = self
                    e.ins = ins
                    skipped_exceptions.append(e)
                    warnings.warn(str(e), UserWarning, stacklevel=1)
                    continue  # go to next input_combination

                except Exception as e:
                    raise RuntimeError(
                        f"Evaluation of {self.name} failed on inputs: \n{pformat(ins)[0:128]}."
                    ) from e

                if isinstance(result_and_meta, Tuple):
                    # If output is a tuple of two, we assume it is the float/multifloat and the metadata.
                    assert len(result_and_meta) == 2, (
                        "Feedback functions must return either a single float, "
                        "a float-valued dict, or these in combination with a dictionary as a tuple."
                    )
                    result_val, meta = result_and_meta

                    assert isinstance(
                        meta, dict
                    ), f"Feedback metadata output must be a dictionary but was {type(meta)}."
                else:
                    # Otherwise it is just the float. We create empty metadata dict.
                    result_val = result_and_meta
                    meta = dict()

                if isinstance(result_val, dict):
                    for val in result_val.values():
                        assert isinstance(val, float), (
                            f"Feedback function output with multivalue must be "
                            f"a dict with float values but encountered {type(val)}."
                        )
                    feedback_call = feedback_schema.FeedbackCall(
                        args=ins,
                        ret=np.mean(list(result_val.values())),
                        meta=meta,
                    )

                else:
                    assert isinstance(
                        result_val, (int, float, list, dict)
                    ), f"Feedback function output must be a float or an int, a list of floats, or dict but was {type(result_val)}."
                    feedback_call = feedback_schema.FeedbackCall(
                        args=ins, ret=result_val, meta=meta
                    )

                result_vals.append(result_val)
                feedback_calls.append(feedback_call)

            # Warn that there were some skipped evals.
            num_skipped = len(skipped_exceptions)
            num_eval = len(result_vals)
            num_total = num_skipped + num_eval
            if num_skipped > 0 and num_total > 0:
                warnings.warn(
                    (
                        f"{num_skipped}/{num_total}={100.0 * num_skipped / num_total:0.1f}"
                        "% evaluation(s) were skipped because they raised SkipEval "
                        "(see earlier warnings for listing)."
                    ),
                    UserWarning,
                    stacklevel=1,
                )

            if num_eval == 0:
                warnings.warn(
                    f"Feedback function {self.supplied_name if self.supplied_name is not None else self.name} with aggregation {self.agg} had no inputs.",
                    UserWarning,
                    stacklevel=1,
                )
                result = float("nan")
            else:
                if isinstance(result_vals[0], float):
                    result_vals = np.array(result_vals)
                    result = self.agg(result_vals)
                else:
                    try:
                        # Operates on list of dict; Can be a dict output
                        # (maintain multi) or a float output (convert to single)
                        result = self.agg(result_vals)
                    except Exception:
                        # Alternatively, operate the agg per key
                        result = {}
                        for feedback_output in result_vals:
                            for key in feedback_output:
                                if key not in result:
                                    result[key] = []
                                result[key].append(feedback_output[key])
                        for key in result:
                            result[key] = self.agg(result[key])

                    if isinstance(result, dict):
                        multi_result = result
                        result = np.nan

            feedback_result.update(
                result=result,
                status=feedback_schema.FeedbackResultStatus.DONE,
                cost=cost,
                calls=feedback_calls,
                multi_result=json.dumps(multi_result),
            )

            return feedback_result

        except Exception:
            # Convert traceback to a UTF-8 string, replacing errors to avoid encoding issues
            exc_tb = (
                traceback.format_exc()
                .encode("utf-8", errors="replace")
                .decode("utf-8")
            )
            logger.warning("Feedback Function exception caught: %s", exc_tb)
            feedback_result.update(
                error=exc_tb,
                status=feedback_schema.FeedbackResultStatus.FAILED,
            )
            return feedback_result

        Run the feedback function on the given `record`. The `app` that
        produced the record is also required to determine input/output argument
        names.

        Args:
            app: The app that produced the record. This can be AppDefinition or a jsonized
                AppDefinition. It will be jsonized if it is not already.

            record: The record to evaluate the feedback on.

            source_data: Additional data to select from when extracting feedback
                function arguments.

            **kwargs: Any additional keyword arguments are used to set or override
                selected feedback function inputs.

        Returns:
            A FeedbackResult object with the result of the feedback function.
        
src/core/trulens/core/feedback/feedback.py