def process_llm_pipeline(
    model: CompositeModelHandler,
    llm_pipeline: list,
    process_func: Callable,
    output_dir: Union[str, Path],
    decoder_config_extra: Optional[dict[str, Any]] = None,
    group_session_options: Optional[dict[str, Any]] = None,
) -> CompositeModelHandler:
    """Process an LLM pipeline with the given function.

    :param model_handler: The composite model with the pipeline.
    :param llm_pipeline: The pipeline to process.
    :param process_func: The function to apply to the context and iterator groups.
        Must accept a mapping from component name to component handler, pipeline, and output directory.
        Returns a
    :param output_dir: The directory to save the processed model.
    :param decoder_config_extra: Extra configuration for the decoder.
    :param group_session_options: Session options for the context and iterator groups.
    :return: The processed composite model handler.
    """
    output_dir = Path(output_dir)
    component_models = dict(model.get_model_components())

    new_component_models = {}
    new_llm_pipeline = {}

    # resave embeddings model
    embeddings_model_path = output_dir / "embeddings.onnx"
    resave_model(component_models[llm_pipeline["embeddings"]].model_path, embeddings_model_path)
    new_component_models["embeddings"] = ONNXModelHandler(
        model_path=output_dir, onnx_file_name=embeddings_model_path.name
    )
    new_llm_pipeline["embeddings"] = "embeddings"

    # process the context and iterator models
    new_groups = process_func(component_models, llm_pipeline, output_dir)
    for key, group in new_groups.items():
        new_component_models.update(group)
        new_llm_pipeline[key] = list(group.keys())

    # resave the lm_head model
    lm_head_model_path = output_dir / "lm_head.onnx"
    resave_model(component_models[llm_pipeline["lm_head"]].model_path, lm_head_model_path)
    new_component_models["lm_head"] = ONNXModelHandler(model_path=output_dir, onnx_file_name=lm_head_model_path.name)
    new_llm_pipeline["lm_head"] = "lm_head"

    # create new model attributes
    new_model_attributes = deepcopy(model.model_attributes) or {}
    new_model_attributes["llm_pipeline"] = new_llm_pipeline

    return update_llm_pipeline_genai_config(
        CompositeModelHandler(
            list(new_component_models.values()),
            list(new_component_models.keys()),
            model_path=output_dir,
            model_attributes=new_model_attributes,
        ),
        source_llm_pipeline=llm_pipeline,
        decoder_config_extra=decoder_config_extra,
        group_session_options=group_session_options,
    )
Process an LLM pipeline with the given function.

    :param model_handler: The composite model with the pipeline.
    :param llm_pipeline: The pipeline to process.
    :param process_func: The function to apply to the context and iterator groups.
        Must accept a mapping from component name to component handler, pipeline, and output directory.
        Returns a
    :param output_dir: The directory to save the processed model.
    :param decoder_config_extra: Extra configuration for the decoder.
    :param group_session_options: Session options for the context and iterator groups.
    :return: The processed composite model handler.
    
olive/passes/onnx/common.py