Merge branch 'main' into pip

This commit is contained in:
Daniel Han 2026-05-18 08:43:14 -07:00
commit 07e2fccf38
8 changed files with 117 additions and 64 deletions

View file

@ -1285,7 +1285,7 @@ shell.Run cmd, 0, False
if ($SkipTorch) {
# No-torch: install unsloth + unsloth-zoo with --no-deps, then
# runtime deps (typer, safetensors, transformers, etc.) with --no-deps.
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --no-deps --reinstall-package unsloth --reinstall-package unsloth-zoo "unsloth>=2026.5.2" unsloth-zoo }
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --no-deps --reinstall-package unsloth --reinstall-package unsloth-zoo "unsloth>=2026.5.3" unsloth-zoo }
if ($baseInstallExit -eq 0) {
$NoTorchReq = Find-NoTorchRuntimeFile
if ($NoTorchReq) {
@ -1293,7 +1293,7 @@ shell.Run cmd, 0, False
}
}
} else {
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --reinstall-package unsloth --reinstall-package unsloth-zoo "unsloth>=2026.5.2" unsloth-zoo }
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --reinstall-package unsloth --reinstall-package unsloth-zoo "unsloth>=2026.5.3" unsloth-zoo }
}
if ($baseInstallExit -ne 0) {
Write-Host "[ERROR] Failed to install unsloth (exit code $baseInstallExit)" -ForegroundColor Red
@ -1331,7 +1331,7 @@ shell.Run cmd, 0, False
if ($SkipTorch) {
# No-torch: install unsloth + unsloth-zoo with --no-deps, then
# runtime deps (typer, safetensors, transformers, etc.) with --no-deps.
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --no-deps --upgrade-package unsloth --upgrade-package unsloth-zoo "unsloth>=2026.5.2" unsloth-zoo }
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --no-deps --upgrade-package unsloth --upgrade-package unsloth-zoo "unsloth>=2026.5.3" unsloth-zoo }
if ($baseInstallExit -eq 0) {
$NoTorchReq = Find-NoTorchRuntimeFile
if ($NoTorchReq) {
@ -1339,7 +1339,7 @@ shell.Run cmd, 0, False
}
}
} elseif ($StudioLocalInstall) {
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --upgrade-package unsloth "unsloth>=2026.5.2" unsloth-zoo }
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --upgrade-package unsloth "unsloth>=2026.5.3" unsloth-zoo }
} else {
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython --upgrade-package unsloth -- "$PackageName" }
}
@ -1367,7 +1367,7 @@ shell.Run cmd, 0, False
Write-TauriLog "STEP" "Installing unsloth"
substep "installing unsloth (this may take a few minutes)..."
if ($StudioLocalInstall) {
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython unsloth-zoo "unsloth>=2026.5.2" --torch-backend=auto }
$baseInstallExit = Invoke-InstallCommand { uv pip install --python $VenvPython unsloth-zoo "unsloth>=2026.5.3" --torch-backend=auto }
if ($baseInstallExit -ne 0) {
Write-Host "[ERROR] Failed to install unsloth (exit code $baseInstallExit)" -ForegroundColor Red
return (Exit-InstallFailure "Failed to install unsloth (exit code $baseInstallExit)" $baseInstallExit)

View file

@ -1849,7 +1849,7 @@ if [ "$_MIGRATED" = true ]; then
# to prevent transitive torch resolution.
run_install_cmd "install unsloth (migrated no-torch)" uv pip install --python "$_VENV_PY" --no-deps \
--reinstall-package unsloth --reinstall-package unsloth-zoo \
"unsloth>=2026.5.2" unsloth-zoo
"unsloth>=2026.5.3" unsloth-zoo
_NO_TORCH_RT="$(_find_no_torch_runtime)"
if [ -n "$_NO_TORCH_RT" ]; then
run_install_cmd "install no-torch runtime deps" uv pip install --python "$_VENV_PY" --no-deps -r "$_NO_TORCH_RT"
@ -1857,7 +1857,7 @@ if [ "$_MIGRATED" = true ]; then
else
run_install_cmd "install unsloth (migrated)" uv pip install --python "$_VENV_PY" \
--reinstall-package unsloth --reinstall-package unsloth-zoo \
"unsloth>=2026.5.2" unsloth-zoo
"unsloth>=2026.5.3" unsloth-zoo
fi
if [ "$STUDIO_LOCAL_INSTALL" = true ]; then
substep "overlaying local repo (editable)..."
@ -2025,7 +2025,7 @@ elif [ -n "$TORCH_INDEX_URL" ]; then
# runtime deps (typer, safetensors, transformers, etc.) with --no-deps.
run_install_cmd "install unsloth (no-torch)" uv pip install --python "$_VENV_PY" --no-deps \
--upgrade-package unsloth --upgrade-package unsloth-zoo \
"unsloth>=2026.5.2" unsloth-zoo
"unsloth>=2026.5.3" unsloth-zoo
_NO_TORCH_RT="$(_find_no_torch_runtime)"
if [ -n "$_NO_TORCH_RT" ]; then
run_install_cmd "install no-torch runtime deps" uv pip install --python "$_VENV_PY" --no-deps -r "$_NO_TORCH_RT"
@ -2040,7 +2040,7 @@ elif [ -n "$TORCH_INDEX_URL" ]; then
fi
elif [ "$STUDIO_LOCAL_INSTALL" = true ]; then
run_install_cmd "install unsloth (local)" uv pip install --python "$_VENV_PY" \
--upgrade-package unsloth "unsloth>=2026.5.2" unsloth-zoo
--upgrade-package unsloth "unsloth>=2026.5.3" unsloth-zoo
substep "overlaying local repo (editable)..."
run_install_cmd "overlay local repo" uv pip install --python "$_VENV_PY" -e "$_REPO_ROOT" --no-deps
substep "overlaying unsloth-zoo from git main..."
@ -2072,7 +2072,7 @@ else
tauri_log "STEP" "Installing Unsloth"
substep "installing unsloth (this may take a few minutes)..."
if [ "$STUDIO_LOCAL_INSTALL" = true ]; then
run_install_cmd "install unsloth (auto torch backend)" uv pip install --python "$_VENV_PY" unsloth-zoo "unsloth>=2026.5.2" --torch-backend=auto
run_install_cmd "install unsloth (auto torch backend)" uv pip install --python "$_VENV_PY" unsloth-zoo "unsloth>=2026.5.3" --torch-backend=auto
substep "overlaying local repo (editable)..."
run_install_cmd "overlay local repo" uv pip install --python "$_VENV_PY" -e "$_REPO_ROOT" --no-deps
substep "overlaying unsloth-zoo from git main..."

View file

@ -6,15 +6,16 @@
import utils.hardware.hardware as hw
DEFAULT_MODELS_GGUF = [
"unsloth/Qwen3.6-27B-MTP-GGUF",
"unsloth/Qwen3.6-35B-A3B-MTP-GGUF",
"unsloth/gemma-4-E2B-it-GGUF",
"unsloth/gemma-4-E4B-it-GGUF",
"unsloth/gemma-4-31B-it-GGUF",
"unsloth/gemma-4-26B-A4B-it-GGUF",
"unsloth/Qwen3.6-35B-A3B-GGUF",
"unsloth/Qwen3.5-4B-GGUF",
"unsloth/Qwen3.5-9B-GGUF",
"unsloth/Qwen3.5-35B-A3B-GGUF",
"unsloth/Qwen3.5-0.8B-GGUF",
"unsloth/Qwen3.5-4B-MTP-GGUF",
"unsloth/Qwen3.5-9B-MTP-GGUF",
"unsloth/Qwen3.5-35B-A3B-MTP-GGUF",
"unsloth/Qwen3.5-0.8B-MTP-GGUF",
"unsloth/Llama-3.2-1B-Instruct-GGUF",
"unsloth/Llama-3.2-3B-Instruct-GGUF",
"unsloth/Llama-3.1-8B-Instruct-GGUF",
@ -24,15 +25,16 @@ DEFAULT_MODELS_GGUF = [
]
DEFAULT_MODELS_STANDARD = [
"unsloth/Qwen3.6-27B-MTP-GGUF",
"unsloth/Qwen3.6-35B-A3B-MTP-GGUF",
"unsloth/gemma-4-E2B-it-GGUF",
"unsloth/gemma-4-E4B-it-GGUF",
"unsloth/gemma-4-31B-it-GGUF",
"unsloth/gemma-4-26B-A4B-it-GGUF",
"unsloth/Qwen3.6-35B-A3B-GGUF",
"unsloth/Qwen3.5-4B-GGUF",
"unsloth/Qwen3.5-9B-GGUF",
"unsloth/Qwen3.5-35B-A3B-GGUF",
"unsloth/Qwen3.5-0.8B-GGUF",
"unsloth/Qwen3.5-4B-MTP-GGUF",
"unsloth/Qwen3.5-9B-MTP-GGUF",
"unsloth/Qwen3.5-35B-A3B-MTP-GGUF",
"unsloth/Qwen3.5-0.8B-MTP-GGUF",
"unsloth/gemma-4-E2B-it",
"unsloth/gemma-4-E4B-it",
"unsloth/gemma-4-31B-it",

View file

@ -2651,9 +2651,10 @@ class LlamaCppBackend:
)
user_owns_spec_type = _extra_args_set_spec_type(extra_args)
# Auto-promote unset/"default" to draft-mtp on MTP GGUFs.
# llama.cpp #22673: MTP is compatible with mmproj, so the
# vision gate previously here was wrong.
if (
is_mtp_model
and not effective_is_vision
and not user_owns_spec_type
and normalized_spec in (None, "", "default")
):
@ -2662,11 +2663,7 @@ class LlamaCppBackend:
# User --spec-type wins (it accumulates if repeated).
normalized_spec = None
self._speculative_type = None
if (
normalized_spec
and normalized_spec != "off"
and not effective_is_vision
):
if normalized_spec and normalized_spec != "off":
if normalized_spec == "default":
cmd.append("--spec-default")
self._speculative_type = "default"
@ -3112,22 +3109,16 @@ class LlamaCppBackend:
if _norm(self._cache_type_kv) != _norm(cache_type_kv):
return False
# Vision GGUFs silently drop speculative decoding in
# load_model (the spec gate is "not is_vision"); treat the
# request's value as "off" so a vision load with
# speculative_type="default" still matches.
if self._is_vision or is_vision:
req_spec = "off"
else:
raw_spec = _norm(speculative_type)
req_spec = raw_spec or "off"
# Mirror load_model's auto-promotion so repeat /load matches.
if (
raw_spec in (None, "default")
and _is_mtp_model_name(model_identifier, gguf_path)
and not _extra_args_set_spec_type(extra_args)
):
req_spec = "draft-mtp"
# Mirror load_model's auto-promotion. Vision is no longer a
# spec blocker (llama.cpp #22673: MTP is compatible with mmproj).
raw_spec = _norm(speculative_type)
req_spec = raw_spec or "off"
if (
raw_spec in (None, "default")
and _is_mtp_model_name(model_identifier, gguf_path)
and not _extra_args_set_spec_type(extra_args)
):
req_spec = "draft-mtp"
backend_spec = _norm(self._speculative_type) or "off"
if req_spec != backend_spec:
return False

View file

@ -351,6 +351,67 @@ def test_already_in_target_state_local_file_mtp_match(tmp_path):
)
def test_already_in_target_state_vision_mtp_match():
# llama.cpp #22673: MTP is compatible with mmproj. A vision MTP load
# with auto/default spec must match a backend already running draft-mtp.
backend = _mtp_backend(_is_vision = True)
assert (
backend._already_in_target_state(
gguf_path = None,
model_identifier = "unsloth/Qwen3.6-27B-MTP-GGUF",
hf_variant = "Q4_K_M",
n_ctx = 8192,
cache_type_kv = None,
speculative_type = None,
chat_template_override = None,
extra_args = None,
is_vision = True,
)
is True
)
def test_already_in_target_state_vision_mtp_default_matches():
backend = _mtp_backend(_is_vision = True)
assert (
backend._already_in_target_state(
gguf_path = None,
model_identifier = "unsloth/Qwen3.6-27B-MTP-GGUF",
hf_variant = "Q4_K_M",
n_ctx = 8192,
cache_type_kv = None,
speculative_type = "default",
chat_template_override = None,
extra_args = None,
is_vision = True,
)
is True
)
def test_already_in_target_state_vision_non_mtp_unaffected():
# Vision non-MTP repo (no -MTP marker) must still mismatch req=None
# against a backend running draft-mtp.
backend = _mtp_backend(
_model_identifier = "unsloth/Qwen3-VL-4B-Instruct-GGUF",
_is_vision = True,
)
assert (
backend._already_in_target_state(
gguf_path = None,
model_identifier = "unsloth/Qwen3-VL-4B-Instruct-GGUF",
hf_variant = "Q4_K_M",
n_ctx = 8192,
cache_type_kv = None,
speculative_type = None,
chat_template_override = None,
extra_args = None,
is_vision = True,
)
is False
)
# GGUF-metadata-based detection (nextn_predict_layers).

View file

@ -979,26 +979,25 @@ export function ChatSettingsPanel({
</Select>
</div>
</div>
{!currentModelIsMultimodal && (
<div className="flex items-center justify-between gap-3">
<div className="flex min-w-0 items-center gap-1.5">
<span className="min-w-0 text-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
Speculative Decoding
</span>
<InfoHint>
N-gram speculation; faster generation with negligible
VRAM overhead. Text-only models.
</InfoHint>
</div>
<Switch
className="panel-switch shrink-0"
checked={speculativeType != null}
onCheckedChange={(checked) => {
setSpeculativeType(checked ? "default" : null);
}}
/>
<div className="flex items-center justify-between gap-3">
<div className="flex min-w-0 items-center gap-1.5">
<span className="min-w-0 text-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
Speculative Decoding
</span>
<InfoHint>
Faster generation with 0% accuracy hit.
</InfoHint>
</div>
)}
<Switch
className="panel-switch shrink-0"
checked={
speculativeType !== "off" && speculativeType != null
}
onCheckedChange={(checked) => {
setSpeculativeType(checked ? "default" : "off");
}}
/>
</div>
</>
)}
{!isGguf && params.checkpoint && (

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
import { apiUrl } from "@/lib/api-base";
import { authFetch } from "@/features/auth";
import { useEffect, useState } from "react";
export interface GpuInfo {
@ -28,7 +28,7 @@ async function fetchGpuOnce(): Promise<GpuInfo> {
fetchPromise = (async () => {
try {
const res = await fetch(apiUrl("/api/system"));
const res = await authFetch("/api/system");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
const gpuData = data?.gpu;

View file

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
__version__ = "2026.5.3"
__version__ = "2026.5.4"
__all__ = [
"SUPPORTS_BFLOAT16",