Integrate Qwen3.8 model intake

This commit is contained in:
Georg Bauer committed 2026-09-03 19:56:23 +02:00
1 parent 4c83ac0360
commit 3773cfda2e
15 files changed
+1805 -35

No files matched your search

+203 -2
View File
@@ -14,6 +14,9 @@ pub(crate) fn download_managed_artifact(
cancel: &AtomicBool,
verified_bytes: &AtomicU64,
) -> Result<DownloadOutcome, String> {
if id == ManagedArtifactId::Qwen38FlashNext {
return download_qwen(models_path, cancel, verified_bytes);
}
download_artifact_with_cancel(
id.model(),
id.artifact(),
@@ -29,6 +32,9 @@ pub(crate) fn validate_managed_artifact(
cancel: &AtomicBool,
verified_bytes: &AtomicU64,
) -> Result<DownloadOutcome, String> {
if id == ManagedArtifactId::Qwen38FlashNext {
return validate_qwen(models_path, cancel, verified_bytes);
}
let model = id.model();
let artifact = id.artifact();
let destination = artifact.path(model, models_path);
@@ -67,6 +73,9 @@ pub(crate) fn delete_managed_artifact(
id: ManagedArtifactId,
models_path: &Path,
) -> Result<(), String> {
if id == ManagedArtifactId::Qwen38FlashNext {
return delete_qwen(models_path);
}
let model = id.model();
let artifact = id.artifact();
for path in [
@@ -83,6 +92,144 @@ pub(crate) fn delete_managed_artifact(
Ok(())
}
fn download_qwen(
models_path: &Path,
cancel: &AtomicBool,
verified_bytes: &AtomicU64,
) -> Result<DownloadOutcome, String> {
let root = qwen::root(models_path);
fs::create_dir_all(&root).map_err(|error| format!("{}: {error}", root.display()))?;
verified_bytes.store(0, Ordering::Relaxed);
for artifact in qwen::artifacts() {
if cancel.load(Ordering::Relaxed) {
return Ok(DownloadOutcome::Stopped);
}
if qwen::artifact_is_installed(&root, artifact) {
verified_bytes.fetch_add(artifact.size, Ordering::Relaxed);
continue;
}
let destination = qwen::path(&root, artifact);
let partial = qwen::partial_path(&root, artifact);
let source = if destination.exists() {
destination.clone()
} else {
if partial.metadata().map_or(0, |metadata| metadata.len()) > artifact.size {
File::create(&partial)
.map_err(|error| format!("{}: {error}", partial.display()))?;
}
if partial.metadata().map_or(0, |metadata| metadata.len()) != artifact.size
&& download_url_to_partial(&qwen::url(artifact), &partial, cancel)?
== DownloadOutcome::Stopped
{
return Ok(DownloadOutcome::Stopped);
}
partial.clone()
};
match qwen::verify(&source, artifact, cancel, verified_bytes) {
Ok(false) => return Ok(DownloadOutcome::Stopped),
Ok(true) => {}
Err(error) => {
let _ = fs::remove_file(qwen::verification_path(&root, artifact));
if source == partial {
fs::remove_file(&partial).map_err(|remove_error| {
format!("{error}; could not remove partial file: {remove_error}")
})?;
}
return Err(error);
}
}
if source == partial {
fs::rename(&partial, &destination)
.map_err(|error| format!("{}: {error}", destination.display()))?;
}
fs::write(qwen::verification_path(&root, artifact), &artifact.sha256)
.map_err(|error| error.to_string())?;
}
if let Err(error) = crate::engine::validate_qwen_artifacts(&root) {
clear_qwen_markers(&root)?;
return Err(error);
}
Ok(DownloadOutcome::Complete)
}
fn validate_qwen(
models_path: &Path,
cancel: &AtomicBool,
verified_bytes: &AtomicU64,
) -> Result<DownloadOutcome, String> {
let root = qwen::root(models_path);
verified_bytes.store(0, Ordering::Relaxed);
for artifact in qwen::artifacts() {
if !qwen::path(&root, artifact).exists() && !qwen::partial_path(&root, artifact).exists() {
return Err(format!("{} is not downloaded", artifact.path));
}
}
for artifact in qwen::artifacts() {
let destination = qwen::path(&root, artifact);
let partial = qwen::partial_path(&root, artifact);
let (source, promote) = if destination.exists() {
(destination.clone(), false)
} else if partial.exists() {
(partial.clone(), true)
} else {
return Err(format!("{} is not downloaded", artifact.path));
};
match qwen::verify(&source, artifact, cancel, verified_bytes) {
Ok(false) => return Ok(DownloadOutcome::Stopped),
Ok(true) => {}
Err(error) => {
let _ = fs::remove_file(qwen::verification_path(&root, artifact));
return Err(error);
}
}
if promote {
fs::rename(&partial, &destination)
.map_err(|error| format!("{}: {error}", destination.display()))?;
}
fs::write(qwen::verification_path(&root, artifact), &artifact.sha256)
.map_err(|error| error.to_string())?;
}
if let Err(error) = crate::engine::validate_qwen_artifacts(&root) {
clear_qwen_markers(&root)?;
return Err(error);
}
Ok(DownloadOutcome::Complete)
}
fn clear_qwen_markers(root: &Path) -> Result<(), String> {
for artifact in qwen::artifacts() {
let path = qwen::verification_path(root, artifact);
match fs::remove_file(&path) {
Ok(()) => {}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
Err(error) => return Err(format!("{}: {error}", path.display())),
}
}
Ok(())
}
fn delete_qwen(models_path: &Path) -> Result<(), String> {
let root = qwen::root(models_path);
for artifact in qwen::artifacts() {
for path in [
qwen::path(&root, artifact),
qwen::partial_path(&root, artifact),
qwen::verification_path(&root, artifact),
] {
match fs::remove_file(&path) {
Ok(()) => {}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
Err(error) => return Err(format!("{}: {error}", path.display())),
}
}
}
match fs::remove_dir(&root) {
Ok(()) => Ok(()),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
Err(error) => Err(format!("{}: {error}", root.display())),
}
}
#[cfg(test)]
fn download_artifact(
model: ModelChoice,
@@ -332,8 +479,12 @@ mod tests {
Some(ModelChoice::DeepSeekV4Flash0731)
);
assert!(ModelChoice::from_id("unknown").is_none());
assert_eq!(MODEL_CHOICES.len(), 4);
assert_eq!(MANAGED_ARTIFACTS.len(), 6);
assert_eq!(MODEL_CHOICES.len(), 5);
assert_eq!(MANAGED_ARTIFACTS.len(), 7);
assert_eq!(
ModelChoice::from_id("qwen3.8-flash-next"),
Some(ModelChoice::Qwen38FlashNext)
);
assert_eq!(ModelChoice::Glm52.main_artifact().size, 211_075_856_448);
assert_eq!(
ModelChoice::DeepSeekV4Flash0731.main_artifact().size,
@@ -342,6 +493,10 @@ mod tests {
assert_eq!(ModelChoice::DeepSeekV4Flash0731.artifacts(true).count(), 2);
assert_eq!(ModelChoice::Glm52.artifacts(true).count(), 1);
assert_eq!(ModelChoice::Glm53Flash.artifacts(true).count(), 2);
assert_eq!(
engine_artifacts(ModelChoice::Qwen38FlashNext, false, Path::new("/models")).model,
Path::new("/models/qwen3.8-flash-next")
);
let id = SystemTime::now()
.duration_since(UNIX_EPOCH)
@@ -417,6 +572,52 @@ mod tests {
fs::remove_dir_all(models_path).unwrap();
}
#[test]
#[ignore = "requires DS4_QWEN38_ARTIFACTS to point at the pinned 105 GB source"]
fn qwen_set_verifies_reloads_and_removes_as_one_managed_artifact() {
let source = std::env::var_os("DS4_QWEN38_ARTIFACTS")
.map(std::path::PathBuf::from)
.expect("DS4_QWEN38_ARTIFACTS is set");
let models = std::env::temp_dir().join(format!(
"ds4-qwen-managed-{}-{}",
std::process::id(),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos()
));
let root = qwen::root(&models);
fs::create_dir_all(&root).unwrap();
for artifact in qwen::artifacts() {
fs::hard_link(source.join(&artifact.path), qwen::path(&root, artifact)).unwrap();
}
fs::remove_file(qwen::path(
&root,
qwen::artifacts()
.iter()
.find(|artifact| artifact.role == "mtp")
.unwrap(),
))
.unwrap();
assert!(
validate_qwen(&models, &AtomicBool::new(false), &AtomicU64::new(0))
.unwrap_err()
.contains("mtp.safetensors is not downloaded")
);
fs::hard_link(source.join("mtp.safetensors"), root.join("mtp.safetensors")).unwrap();
let verified = AtomicU64::new(0);
assert_eq!(
validate_qwen(&models, &AtomicBool::new(false), &verified).unwrap(),
DownloadOutcome::Complete
);
assert_eq!(verified.load(Ordering::Relaxed), qwen::total_bytes());
assert!(qwen::is_installed(&root));
assert!(crate::engine::validate_qwen_artifacts(&root).is_ok());
delete_qwen(&models).unwrap();
assert!(!root.exists());
fs::remove_dir_all(models).unwrap();
}
#[test]
fn verification_reports_bytes_read() {
let path = std::env::temp_dir().join(format!(