params.speculative.types.end(),
COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3) != params.speculative.types.end();
+ const bool spec_type_draft_dspark = std::find(params.speculative.types.begin(),
+ params.speculative.types.end(),
+ COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK) != params.speculative.types.end();
+
// only download mmproj if the current example is using it
bool use_mmproj = false;
for (const auto & ex : mmproj_examples) {
opts.download_mtp = spec_type_draft_mtp;
opts.download_eagle3 = spec_type_draft_eagle3;
opts.download_dflash = spec_type_draft_dflash;
+ opts.download_dspark = spec_type_draft_dspark;
opts.download_mmproj = use_mmproj && !params.no_mmproj
&& params.mmproj.path.empty() && params.mmproj.url.empty();
opts_spec.download_mtp = true;
opts_spec.download_dflash = true;
opts_spec.download_eagle3 = true;
+ opts_spec.download_dspark = true;
}
plan_spec = common_download_get_hf_plan(params.speculative.draft.mparams, opts_spec);
}
plan_spec.mtp = {};
plan_spec.dflash = {};
plan_spec.eagle3 = {};
+ plan_spec.dspark = {};
}
// infer the speculative type from the sidecar shipped by the draft repo when none is requested
if (spec_types_is_default(params)) {
if (!plan_spec.mtp.local_path.empty()) {
params.speculative.types = { COMMON_SPECULATIVE_TYPE_DRAFT_MTP };
+ plan_spec.dspark = {};
+ plan_spec.dflash = {};
+ plan_spec.eagle3 = {};
+ } else if (!plan_spec.dspark.local_path.empty()) {
+ // dspark outranks dflash, its sidecar carries the extra Markov head
+ params.speculative.types = { COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK };
plan_spec.dflash = {};
plan_spec.eagle3 = {};
} else if (!plan_spec.dflash.local_path.empty()) {
// when a sidecar type is requested, the draft repo resolves to its sidecar instead of a full model
const bool spec_sidecar_found = !plan_spec.mtp.local_path.empty() ||
!plan_spec.dflash.local_path.empty() ||
- !plan_spec.eagle3.local_path.empty();
+ !plan_spec.eagle3.local_path.empty() ||
+ !plan_spec.dspark.local_path.empty();
if (!plan_spec.mtp.local_path.empty() && !had_spec_url) {
tasks.emplace_back(plan_spec.mtp, opts, [&]() {
// only use the discovered MTP head when no draft path is set yet
}
});
}
+ if (!plan_spec.dspark.local_path.empty() && !had_spec_url) {
+ tasks.emplace_back(plan_spec.dspark, opts, [&]() {
+ // only use the discovered DSpark sidecar when no draft path is set yet
+ if (params.speculative.draft.mparams.path.empty()) {
+ params.speculative.draft.mparams.path = hf_cache::finalize_file(plan_spec.dspark);
+ } else {
+ hf_cache::finalize_file(plan_spec.dspark);
+ }
+ });
+ }
// a wired draft sidecar counts as an explicit draft for the main plan fallback below
if (spec_sidecar_found) {
}
});
}
+ if (!plan.dspark.local_path.empty() && !had_spec_url) {
+ tasks.emplace_back(plan.dspark, opts, [&]() {
+ // only fall back to the discovered DSpark sidecar when no draft was explicitly provided
+ if (params.speculative.draft.mparams.empty()) {
+ params.speculative.draft.mparams.path = hf_cache::finalize_file(plan.dspark);
+ } else {
+ hf_cache::finalize_file(plan.dspark);
+ }
+ });
+ }
if (!plan.preset.local_path.empty()) {
tasks.emplace_back(plan.preset, opts, [&]() {
// if HF repo is a preset repo, we simply run server in router mode with the preset.ini file
return find_best_sibling(files, model, "dflash-", tag);
}
+static hf_cache::hf_file find_best_dspark(const hf_cache::hf_files & files,
+ const std::string & model,
+ const std::string & tag = "") {
+ return find_best_sibling(files, model, "dspark-", tag);
+}
+
static bool gguf_filename_is_model(const std::string & filepath) {
if (!string_ends_with(filepath, ".gguf")) {
return false;
filename.find("imatrix") == std::string::npos &&
filename.find("mtp-") == std::string::npos &&
filename.find("eagle3-") == std::string::npos &&
- filename.find("dflash-") == std::string::npos;
+ filename.find("dflash-") == std::string::npos &&
+ filename.find("dspark-") == std::string::npos;
}
static hf_cache::hf_file find_best_model(const hf_cache::hf_files & files,
} else {
primary = find_best_model(all, tag);
// a requested sidecar can resolve on its own, without a full model of the same tag
- if (primary.path.empty() && !opts.download_mtp && !opts.download_dflash && !opts.download_eagle3) {
+ if (primary.path.empty() && !opts.download_mtp && !opts.download_dflash && !opts.download_eagle3 && !opts.download_dspark) {
LOG_ERR("%s: no GGUF files found in repository %s\n", __func__, repo.c_str());
list_available_gguf_files(all);
return plan;
if (opts.download_eagle3) {
plan.eagle3 = find_best_eagle3(all, primary.path, tag);
}
+ if (opts.download_dspark) {
+ plan.dspark = find_best_dspark(all, primary.path, tag);
+ }
if (primary.path.empty() &&
- plan.mtp.local_path.empty() && plan.dflash.local_path.empty() && plan.eagle3.local_path.empty()) {
+ plan.mtp.local_path.empty() && plan.dflash.local_path.empty() && plan.eagle3.local_path.empty() && plan.dspark.local_path.empty()) {
LOG_ERR("%s: no GGUF files found in repository %s\n", __func__, repo.c_str());
list_available_gguf_files(all);
}
split.prefix.find("mmproj") != std::string::npos ||
split.prefix.find("mtp-") != std::string::npos ||
split.prefix.find("eagle3-") != std::string::npos ||
- split.prefix.find("dflash-") != std::string::npos) {
+ split.prefix.find("dflash-") != std::string::npos ||
+ split.prefix.find("dspark-") != std::string::npos) {
continue;
}
if (seen.insert(f.repo_id + ":" + split.tag).second) {