Skip to content

common: refactor model handling - #24980

Merged
ngxson merged 12 commits into
ggml-org:masterfrom
ngxson:xsn/refactor_common_models
Jun 25, 2026
Merged

common: refactor model handling#24980
ngxson merged 12 commits into
ggml-org:masterfrom
ngxson:xsn/refactor_common_models

Conversation

@ngxson

@ngxson ngxson commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Overview

Refactor model handling (-m, -hf, etc) into a centralized common_models_handler object

It exposes 2 main calls:

  • fetch_meta(): check if the input option like -hf or -dr is valid; in case of HF repo: get the list of files
  • apply(): download and apply the model local path to common_params

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: most of the code is human-written, AI only used for validation

Comment thread common/hf-cache.h Outdated

using hf_files = std::vector<hf_file>;

struct hf_plan {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to hf-cache.h to me, but to the selection mechanism and model management

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm ok I moved it back to download.h in df822d2

Comment thread common/download.h Outdated
Comment on lines +104 to +111
struct hf_plan {
hf_cache::hf_file primary;
hf_cache::hf_files model_files;
hf_cache::hf_file mmproj;
hf_cache::hf_file mtp;
hf_cache::hf_file preset; // if set, only this file is downloaded
};
hf_plan get_hf_plan(const common_params_model & model, const common_download_opts & opts);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
struct hf_plan {
hf_cache::hf_file primary;
hf_cache::hf_files model_files;
hf_cache::hf_file mmproj;
hf_cache::hf_file mtp;
hf_cache::hf_file preset; // if set, only this file is downloaded
};
hf_plan get_hf_plan(const common_params_model & model, const common_download_opts & opts);
struct common_download_hf_plan {
hf_cache::hf_file primary;
hf_cache::hf_files model_files;
hf_cache::hf_file mmproj;
hf_cache::hf_file mtp;
hf_cache::hf_file preset; // if set, only this file is downloaded
};
common_download_hf_plan common_download_get_hf_plan(const common_params_model & model, const common_download_opts & opts);

Comment thread common/arg.h Outdated

#include "common.h"
#include "download.h"
#include "hf-cache.h"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed

Comment thread common/arg.h
Comment on lines +134 to +156
struct common_models_handler {
common_params & params;
common_download_callback * callback = nullptr;
bool preset_only = false; // if true, only check & download remote preset (for router mode)
};
hf_plan plan;
common_download_opts opts;

common_models_handler(common_params & params) : params(params) {}

// fetch the metadata if needed (but do not download the model)
void fetch_meta(llama_example curr_ex);

// populate model paths (main model, mmproj, etc) from -hf if necessary
// return true if the model is ready to use
// throw an exception if there is an error that prevents the model from being used (e.g. network error, model not found, etc)
// if params.skip_download is true, no downloads will be attempted. return false if the model is invalid or missing (e.g. ETag check failed)
bool common_params_handle_models(
common_params & params,
llama_example curr_ex,
const common_params_handle_models_params & handle_params);
// return true if the input -hf is a preset-only repo (i.e. contains a preset.ini file)
bool is_preset_repo() const;

// download the model if needed, then apply it to the common_params
void apply();

private:
std::string get_default_local_path(const std::string & url);

// build download tasks for a plain (non-hf) url model, honoring a user-supplied -m path
std::vector<common_download_task> build_url_tasks(const common_params_model & model);
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This struct seems a bit unnecessary - likely can remain a function. The private methods can be static functions in the cpp file.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense, I refactored it again:

struct common_models_handler {
    common_download_hf_plan plan;
    common_download_opts opts;
};

common_models_handler common_models_handler_init(const common_params & params, llama_example curr_ex);
bool common_models_handler_is_preset_repo(const common_models_handler & handler);
void common_models_handler_apply(common_models_handler & handler, common_params & params, common_download_callback * callback = nullptr);

Usage:

  • common_models_handler_init will fetch metadata and construct the hf_plan / opts
  • common_models_handler_is_preset_repo is to check if the hf-repo is preset.ini-only
  • common_models_handler_apply will download the files and modify params to point to the downloaded location

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since all the usages are like:

{
    auto handler = common_models_handler_init(...);
    if (need_apply) {
        common_models_handler_apply(handler);
    }
}

It does not seem necessary to introduce the common_models_handler. A single function such as the following seems enough?

void common_params_update(
        common_params & params,
        llama_example ex,
        bool apply,
        common_download_callback * callback);

@ngxson ngxson Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your idea is similar to the existing common_params_handle_models before this refactoring, but the main point of the 2-step init/apply is for server code, it looks somewhat like this:

models_handler = common_models_handler_init(params, LLAMA_EXAMPLE_SERVER);
if (common_models_handler_is_preset_repo(models_handler)) {
    // apply the preset and start the server in router mode
    common_models_handler_apply(models_handler, params);
}

// do other endpoint setup
ctx_http.get ("/models/sse", progress_download_report);
// ... then later on

if (not_preset) {
    // non-roter + non-preset: download model, with progress callback via `progress_download_report`
    common_models_handler_apply(models_handler, params, callback);
}

We could also get rid of common_models_handler but that will require re-fetching the list of files for each call. My idea is somewhat like this:

  • The list of files to be downloaded will be stored in common_models_handler
  • It can also be useful for future, for example, if we want to show to the user list of files (+ size), then ask for confirmation before downloading

@ngxson ngxson Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, note that if we only call common_models_handler_init without _apply, that means "validate if the HF model exist", and indeed the logic is being used in POST /models endpoint is now benefit from this

@ngxson
ngxson merged commit 60bc886 into ggml-org:master Jun 25, 2026
21 of 25 checks passed
bernardladenthin pushed a commit to bernardladenthin/java-llama.cpp that referenced this pull request Jun 26, 2026
The b9803 model-download refactor (PR ggml-org/llama.cpp#24980) removed
common_params::skip_download and common_skip_download_exception. That
exposed that the project's ModelFlag.SKIP_DOWNLOAD ("--skip-download")
never worked: --skip-download was never a registered upstream argument
(at b9789 or b9803), so passing it only ever forced common_params_parse
to fail, which SkipDownloadFailureTranslator mapped to
ModelUnavailableException. It could not even load a model that WAS
present — the unknown arg failed parsing unconditionally.

Replace it with the real upstream --offline flag, which the new
common_models_handler_apply honors (it skips all download tasks when
params.offline is set): a cached/present model loads, a missing one
fails instead of being fetched.

- ModelFlag: SKIP_DOWNLOAD("--skip-download") -> OFFLINE("--offline")
- ModelParameters: setSkipDownload(boolean) -> setOffline(boolean);
  add @nullable getModel() read-back used by the guard
- loader/SkipDownloadFailureTranslator (parse-failure heuristic) ->
  loader/OfflineModelGuard: a deterministic PRE-check that throws
  ModelUnavailableException when --offline is set and the configured
  local --model file does not exist, before the native call. hf-repo /
  model-url loads (no local path) fall through to the native loader.
- LlamaModel: call OfflineModelGuard.check(parameters) before load in
  both constructors; drop the catch-and-translate
- ModelUnavailableException retained (typed air-gapped-miss signal);
  javadoc updated
- Tests: LlamaModelSkipDownloadTest -> LlamaModelOfflineTest (flag
  round-trip + guard present/missing/hf-repo/not-set cases); ModelFlagTest
  + ModelUnavailableExceptionTest updated
- Docs: breaking-changes row, TODO.md, feature-investigation table

Pure-Java change, no JNI rebuild. spotless clean; LlamaModelOfflineTest
(8), ModelFlagTest (103), ModelUnavailableExceptionTest (6),
ModelParametersTest (64), LlamaArchitectureTest (12) green; javadoc:jar
BUILD SUCCESS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015iMgeCXHE9UNu359GbFyXj
@ggerganov

ggerganov commented Jun 26, 2026

Copy link
Copy Markdown
Member

After this change the following config no longer loads:

https://huggingface.co/ggerganov/preset-128gb/blob/main/preset.ini#L122-L137

This is the error:

[52799] 0.03.758.552 I srv    load_model: loading draft model 'mtp-Qwen3.6-27B-Q4_0.gguf'
[52799] 0.03.758.602 E gguf_init_from_file: failed to open GGUF file 'mtp-Qwen3.6-27B-Q4_0.gguf' (No such file or directory)
[52799] 0.03.758.640 E llama_model_load: error loading model: llama_model_loader: failed to load model from mtp-Qwen3.6-27B-Q4_0.gguf
[52799] 0.03.758.645 E llama_model_load_from_file_impl: failed to load model
[52799] 0.03.758.645 E srv    load_model: failed to load draft model, 'mtp-Qwen3.6-27B-Q4_0.gguf'
[52799] 0.03.758.651 I srv    operator(): operator(): cleaning up before exit...
[52799] 0.03.759.154 E srv  llama_server: exiting due to model loading error
[52799] 0.03.759.471 I ggml_metal_free: deallocating
0.09.008.129 I srv    operator(): instance name=qwen3.6-27b-hf-think-mtp exited with status 1

Before the change it loads the draft model like this:

[53064] 0.04.864.512 I common_init_from_params: warming up the model with an empty run - please wait ... (--no-warmup to disable)
[53064] 0.05.063.933 I srv    load_model: loading draft model '~/.cache/huggingface/hub/models--ggml-org--Qwen3.6-27B-GGUF/snapshots/4194c3ffc51e8c43a5d438470db134921e4cb577/mtp-Qwen3.6-27B-Q4_0.gguf'

papamoose pushed a commit to papamoose/llama.cpp that referenced this pull request Jun 27, 2026
* common: refactor models handling

* remote preset

* cont

* rm skip_download option

* missing header

* fix plan.model_files

* fix --offline case

* move hf_plan to download

* refactor

* rm redundant curr_ex, add comments

* adapt
@adrianhoehne

Copy link
Copy Markdown

After this change, this config broke. I start the server generally with the --offline argument.

2927] 0.00.331.823 I srv    load_model: loading model 'unsloth/Qwen3-Coder-Next-GGUF'
[52927] 0.00.396.249 E llama_model_load: error loading model: illegal split file idx: 2 (file: /home/adrian/.cache/huggingface/hub/models--unsloth--Qwen3-Coder-Next-GGUF/snapshots/ce09c67b53bc8739eef83fe67b2f5d293c270632/UD-Q6_K/Qwen3-Coder-Next-UD-Q6_K-00003-of-00003.gguf), model must be loaded with the first split
[52927] 0.00.396.270 E llama_model_load_from_file_impl: failed to load model

Config:

[qwen3-coder-next-q6k-rtx-hot-autolearn]
hf-repo = unsloth/Qwen3-Coder-Next-GGUF
hf-file = UD-Q6_K/Qwen3-Coder-Next-UD-Q6_K-00001-of-00003.gguf
device = CUDA0
main-gpu = 0
temp = 0.2
reasoning = off
tags = qwen3next,coder-next,hot-cache,primary-rtx,autolearn

cpu-moe = true
no-mmproj-offload = true

adrianhoehne pushed a commit to adrianhoehne/llama.cpp that referenced this pull request Jul 5, 2026
* common: refactor models handling

* remote preset

* cont

* rm skip_download option

* missing header

* fix plan.model_files

* fix --offline case

* move hf_plan to download

* refactor

* rm redundant curr_ex, add comments

* adapt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants