Studio: apply remembered settings for MLX and safetensors models to API loads by Lyxot · Pull Request #11904 · unslothai/unsloth · GitHub
Skip to content

Studio: apply remembered settings for MLX and safetensors models to API loads - #11904

Merged
NilayYadav merged 3 commits into
unslothai:mainfrom
Lyxot:fix/non-gguf-override-mirror
Sep 25, 2026
Merged

NilayYadav merged 3 commits into
unslothai:mainfrom
Lyxot:fix/non-gguf-override-mirror

Conversation

@Lyxot

@Lyxot Lyxot commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Fixes #11821

Problem

In Unsloth Studio, "Remember for this model" saved settings only in the browser for MLX and safetensors models. The server override store, which the OpenAI API auto-switch applies to /v1/* loads, was updated only for GGUF targets. Since #8768 the auto-switch also loads non-GGUF weights, so an API request loaded those models with defaults and ignored the remembered context length, KV precision, or chat template.

Root cause

Both settings targets (the model picker and the chat sidebar) set apiLoadable to isGguf && !ollamaLink. The one-time backfill filtered to GGUF ids in the same way. Neither was widened when the auto-switch gained non-GGUF support. The panel's server-row hydration also returned early for every non-GGUF model, so even a row written by another origin or a manual PUT never showed in the panel.

Changes

  • Panel hydration: the settings panel now adopts the server row for every non-diffusion model. For a non-GGUF model the row is adopted without llama_extra_args (panelOverrideRow), since a non-GGUF load never sends them. Load now waits for this read on every non-diffusion model, as it already did for GGUF. With Remember unchecked, Load forgets the server row, so a load started before the read settled would delete settings the panel had never shown. The existing release paths (settle, failure, 15 s backstop) are unchanged.
  • Live mirroring: both target builders now share apiAutoSwitchMayLoad, which excludes only what the backend resolver never serves: bare LoRA adapters and materialized Ollama links. For a cached Hugging Face repo loaded with no quant, /api/inference/status reports the snapshot path. The sidebar now keys that model by its repo id (cachedRepoConfigId), matching the picker; otherwise a bare snapshot-path row would outrank the picker's row on the backend and survive its Forget. Browser records an older build saved under the snapshot path are adopted to the repo id lazily. A record already under the repo id wins.
  • Backfill: the one-time upload of browser-only settings now includes non-GGUF entries. Its done-flag is bumped to v3 so installs that already ran v2 pick them up. It still fills only absent rows and never overwrites; snapshot-path records are adopted to the repo id first, so it never uploads a snapshot-path row.

The commits are ordered so the Load wait lands before non-GGUF mirroring; no commit has forget-on-load without it.

Risks and tradeoffs

  • For MLX and safetensors models, Load is now briefly disabled while the panel reads the server row (bounded by the existing 15 s backstop).
  • When a non-GGUF model's server row is newer than this browser's copy, for example written from another origin, opening the panel now shows the server values. This is the same precedence GGUF already has.
  • The backfill may upload settings saved for a LoRA adapter. The server never applies them to a load.
  • Backend unchanged: resolve_override_for_load and model_override_load_kwargs(is_gguf=False) already honor non-GGUF rows.

Validation

Targeted frontend tests pass at each commit, and every new assertion fails when its production change is reverted:

cd studio/frontend
node --experimental-strip-types --test \
  tests/model-config-handoff.test.ts \
  tests/resident-remembered-config.test.ts \
  tests/server-tuning-upgrade-downgrade-compat.test.ts \
  tests/llama-extra-args-diagnostics.test.ts \
  tests/llama-extra-args-panel-hydration.test.ts \
  tests/hydration-clears-stale-local-record.test.ts
# 162 pass, 0 fail
npx tsc -b --noEmit

End to end against an isolated Unsloth Studio on Apple Silicon: I saved the override row the panel now sends for Qwen/Qwen3-0.6B (custom chat template, mlx_kv_bits=8). A /v1/chat/completions request that auto-loaded the model applied both settings.

Not exercised in a browser: the brief Load wait for a non-GGUF model. It's covered by source-level tests only, because the panel has no renderer in this test suite.

The OpenAI API auto-switch applies a model's server override row to MLX and safetensors loads too, but the settings panel read that row only for GGUF models, so a non-GGUF panel showed this browser's copy while API loads used another. The panel now adopts the row for every non-diffusion model, without the llama-server arguments a non-GGUF load never sends, and Load waits for the read as it does for GGUF: with Remember unchecked, Load forgets the row, so loading before it was read would delete settings the panel never showed.
"Remember for this model" only mirrored settings to the server override store for GGUF models, so an OpenAI API auto-switch loaded MLX and safetensors checkpoints with defaults (chat template, KV cache bits, context) even though the auto-switch has served them since non-GGUF weights became loadable through it.

Both settings targets now share apiAutoSwitchMayLoad, which only excludes identities the resolver never serves: a LoRA adapter and a materialized Ollama link. The chat sidebar passes whether the loaded model is a LoRA adapter.

A cached repo loads from its snapshot directory and /api/inference/status reports that path, while the picker keys the repo id; the backend folds those two spellings only for a quant. The sidebar and the resident config resolver now key a snapshot directory loaded without a quant by its repo id, and a record an older build saved under the path is moved to the repo id, so a bare snapshot-path row can no longer outrank the picker's row or survive its Forget.
The one-time upload of settings remembered only in this browser skipped every model that was not a GGUF quant, a .gguf file or an Ollama tag, so MLX and safetensors settings saved before the API mirror covered them kept loading with defaults through an API auto-switch.

The pass now offers any remembered model except identities the resolver never keys (materialized Ollama links, bare file labels) and reruns once under a new done flag. A record an older build saved under a cached repo's snapshot path is moved to its repo id first, and one that cannot be moved is not uploaded, since a bare snapshot-path row would outrank the repo's.
@Lyxot
Lyxot force-pushed the fix/non-gguf-override-mirror branch from 35c2de7 to b7f57f6 Compare September 25, 2026 08:29
@Lyxot

Lyxot commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator Author

@NilayYadav NilayYadav self-assigned this Sep 25, 2026
@NilayYadav
NilayYadav merged commit 54fbe52 into unslothai:main Sep 25, 2026
47 checks passed
shaojun pushed a commit to shaojun/unsloth that referenced this pull request Sep 29, 2026
…PI loads (unslothai#11904)

* fix(studio): show the server settings row in the non-GGUF settings panel

The OpenAI API auto-switch applies a model's server override row to MLX and safetensors loads too, but the settings panel read that row only for GGUF models, so a non-GGUF panel showed this browser's copy while API loads used another. The panel now adopts the row for every non-diffusion model, without the llama-server arguments a non-GGUF load never sends, and Load waits for the read as it does for GGUF: with Remember unchecked, Load forgets the row, so loading before it was read would delete settings the panel never showed.

* fix(studio): mirror remembered settings for non-GGUF models to the API

"Remember for this model" only mirrored settings to the server override store for GGUF models, so an OpenAI API auto-switch loaded MLX and safetensors checkpoints with defaults (chat template, KV cache bits, context) even though the auto-switch has served them since non-GGUF weights became loadable through it.

Both settings targets now share apiAutoSwitchMayLoad, which only excludes identities the resolver never serves: a LoRA adapter and a materialized Ollama link. The chat sidebar passes whether the loaded model is a LoRA adapter.

A cached repo loads from its snapshot directory and /api/inference/status reports that path, while the picker keys the repo id; the backend folds those two spellings only for a quant. The sidebar and the resident config resolver now key a snapshot directory loaded without a quant by its repo id, and a record an older build saved under the path is moved to the repo id, so a bare snapshot-path row can no longer outrank the picker's row or survive its Forget.

* fix(studio): backfill browser-only settings for non-GGUF models

The one-time upload of settings remembered only in this browser skipped every model that was not a GGUF quant, a .gguf file or an Ollama tag, so MLX and safetensors settings saved before the API mirror covered them kept loading with defaults through an API auto-switch.

The pass now offers any remembered model except identities the resolver never keys (materialized Ollama links, bare file labels) and reruns once under a new done flag. A record an older build saved under a cached repo's snapshot path is moved to its repo id first, and one that cannot be moved is not uploaded, since a bare snapshot-path row would outrank the repo's.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Studio: "Remember for this model" never mirrors settings to the server for MLX models, so API auto-switch loads them with defaults

2 participants