code: def _construct_model(
      task_feature: Optional[int],
      Xs: List[Tensor],
      Ys: List[Tensor],
      Yvars: List[Tensor],
      fidelity_features: List[int],
      metric_names: List[str],
      use_input_warping: bool = False,
      prior: Optional[Dict[str, Any]] = None,
      *,
      multitask_gp_ranks: Optional[
          Dict[str, Union[Prior, float]]
      ] = None,
      **kwargs: Any,
  ) -> GPyTorchModel:
      """
      Figures out how to call `_get_model` depending on inputs. Used by
      `get_and_fit_model`.
      """
      if task_feature is None:
          if len(Xs) == 1:
              # Use single output, single task GP
              return _get_model(
                  X=Xs[0],
                  Y=Ys[0],
                  Yvar=Yvars[0],
                  task_feature=task_feature,
                  fidelity_features=fidelity_features,
                  use_input_warping=use_input_warping,
                  prior=deepcopy(prior),
                  **kwargs,
              )
          if (
              all(torch.equal(Xs[0], X) for X in Xs[1:])
              and not use_input_warping
          ):
              # Use batched multioutput, single task GP
              # Require using a ModelListGP if using input warping
              Y = torch.cat(Ys, dim=-1)
              Yvar = torch.cat(Yvars, dim=-1)
              return _get_model(
                  X=Xs[0],
                  Y=Y,
                  Yvar=Yvar,
                  task_feature=task_feature,
                  fidelity_features=fidelity_features,
                  prior=deepcopy(prior),
                  **kwargs,
              )
  
      if task_feature is None:
          models = [
              _get_model(
                  X=X,
                  Y=Y,
                  Yvar=Yvar,
                  use_input_warping=use_input_warping,
                  prior=deepcopy(prior),
                  **kwargs,
              )
              for X, Y, Yvar in zip(Xs, Ys, Yvars)
          ]
      else:
          # use multi-task GP
          mtgp_rank_dict = (
              {} if multitask_gp_ranks is None else multitask_gp_ranks
          )
          # assembles list of ranks associated with each metric
          if len({len(Xs), len(Ys), len(Yvars), len(metric_names)}) > 1:
              raise ValueError(
                  "Lengths of Xs, Ys, Yvars, and metric_names must match. Your "
                  f"inputs have lengths {len(Xs)}, {len(Ys)}, {len(Yvars)}, and "
                  f"{len(metric_names)}, respectively."
              )
          mtgp_rank_list = [
              mtgp_rank_dict.get(metric, None)
              for metric in metric_names
          ]
          models = [
              _get_model(
                  X=X,
                  Y=Y,
                  Yvar=Yvar,
                  task_feature=task_feature,
                  rank=mtgp_rank,
                  use_input_warping=use_input_warping,
                  prior=deepcopy(prior),
                  **kwargs,
              )
              for X, Y, Yvar, mtgp_rank in zip(
                  Xs, Ys, Yvars, mtgp_rank_list
              )
          ]
      return ModelListGP(*models)
  
imports: import functools
  from copy import deepcopy
  from random import randint
  from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple, Type, Union
  import torch
  from ax.models.model_utils import best_observed_point, get_observed
  from ax.models.torch.utils import _to_inequality_constraints
  from ax.models.torch_base import TorchModel
  from ax.models.types import TConfig
  from botorch.acquisition import get_acquisition_function
  from botorch.acquisition.acquisition import AcquisitionFunction
  from botorch.acquisition.fixed_feature import FixedFeatureAcquisitionFunction
  from botorch.acquisition.objective import ConstrainedMCObjective, GenericMCObjective
  from botorch.acquisition.utils import get_infeasible_cost
  from botorch.exceptions.errors import UnsupportedError
  from botorch.fit import fit_gpytorch_mll
  from botorch.models.gp_regression import SingleTaskGP
  from botorch.models.gp_regression_fidelity import SingleTaskMultiFidelityGP
  from botorch.models.gpytorch import GPyTorchModel
  from botorch.models.model import Model
  from botorch.models.model_list_gp_regression import ModelListGP
  from botorch.models.multitask import MultiTaskGP
  from botorch.models.transforms.input import Warp
  from botorch.optim.optimize import optimize_acqf
  from botorch.utils import get_objective_weights_transform, get_outcome_constraint_transforms
  from botorch.utils.multi_objective.scalarization import get_chebyshev_scalarization
  from botorch.utils.transforms import is_ensemble
  from gpytorch.kernels import MaternKernel, ScaleKernel
  from gpytorch.kernels.kernel import Kernel
  from gpytorch.mlls.exact_marginal_log_likelihood import ExactMarginalLogLikelihood
  from gpytorch.mlls.leave_one_out_pseudo_likelihood import LeaveOneOutPseudoLikelihood
  from gpytorch.mlls.sum_marginal_log_likelihood import SumMarginalLogLikelihood
  from gpytorch.priors import Prior
  from gpytorch.priors.lkj_prior import LKJCovariancePrior
  from gpytorch.priors.torch_priors import GammaPrior, LogNormalPrior
  from torch import Tensor
label_desc: Use image node_id 1 for calling a global function with example usage: _construct_model(task_feature, Xs, Ys, Yvars, fidelity_features, metric_names, use_input_warping, prior) and returns: ModelListGP, _get_model, _get_model