From 880b59a301a7379f80ba5b7e4f0d3aefc8523f83 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Tue, 17 Mar 2026 08:03:32 -0700 Subject: [PATCH 01/42] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 16ec872b64..e802648afe 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,7 @@ Unsloth Studio works on **Windows, Linux, WSL** and **macOS**. #### Windows, MacOS Linux or WSL: ``` -git clone https://github.com/unslothai/unsloth.git -cd unsloth -pip install -e . +pip install unsloth unsloth studio setup unsloth studio -H 0.0.0.0 -p 8888 ``` From 881e05796484dfe109b2cf390d0a636d75519dd4 Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 08:42:03 -0700 Subject: [PATCH 02/42] Unsloth Studio update.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e802648afe..169fc80ea6 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ Run and train AI models with a unified local interface. DocumentationDiscord

-unsloth studio ui homepage + +unsloth studio ui homepage Unsloth Studio lets you run and train models for text, [audio](https://unsloth.ai/docs/basics/text-to-speech-tts-fine-tuning), [embedding](https://unsloth.ai/docs/new/embedding-finetuning), [vision](https://unsloth.ai/docs/basics/vision-fine-tuning) and more. Available on Windows, Linux and macOS. ## ⭐ Features From 685a0348e17b6eef9c2ed79b0fbe63e89a82f3db Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:00:57 -0700 Subject: [PATCH 03/42] Update Unsloth_Studio_Colab.ipynb --- studio/Unsloth_Studio_Colab.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/Unsloth_Studio_Colab.ipynb b/studio/Unsloth_Studio_Colab.ipynb index 0338fc3a47..6428079fd8 100644 --- a/studio/Unsloth_Studio_Colab.ipynb +++ b/studio/Unsloth_Studio_Colab.ipynb @@ -16,7 +16,7 @@ "\n", "### Unsloth Studio\n", "\n", - "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start). Installation may take 10 mins.\n", + "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start). Installation may take 30+ mins, so use a newer GPU.\n", "\n", "[Features](https://unsloth.ai/docs/new/unsloth-studio#features) • [Quickstart](https://unsloth.ai/docs/new/unsloth-studio/start) • [Data Recipes](https://unsloth.ai/docs/new/unsloth-studio/data-recipe) • [Studio Chat](https://unsloth.ai/docs/new/unsloth-studio/chat) • [Export](https://unsloth.ai/docs/new/unsloth-studio/export)" ] From a943705b4cf12c4a07fe4cc00da804be01c584ce Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 11:14:45 -0700 Subject: [PATCH 04/42] Update Unsloth_Studio_Colab.ipynb --- studio/Unsloth_Studio_Colab.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/Unsloth_Studio_Colab.ipynb b/studio/Unsloth_Studio_Colab.ipynb index 6428079fd8..d73295eeb4 100644 --- a/studio/Unsloth_Studio_Colab.ipynb +++ b/studio/Unsloth_Studio_Colab.ipynb @@ -16,7 +16,7 @@ "\n", "### Unsloth Studio\n", "\n", - "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start). Installation may take 30+ mins, so use a newer GPU.\n", + "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start).
We are actively working on making Unsloth Studio install on Colab T4 GPUs faster. Currently, installation may take 30+ mins so use a newer GPU.\n", "\n", "[Features](https://unsloth.ai/docs/new/unsloth-studio#features) • [Quickstart](https://unsloth.ai/docs/new/unsloth-studio/start) • [Data Recipes](https://unsloth.ai/docs/new/unsloth-studio/data-recipe) • [Studio Chat](https://unsloth.ai/docs/new/unsloth-studio/chat) • [Export](https://unsloth.ai/docs/new/unsloth-studio/export)" ] From 051b6f27f9bccc7e6911eb23081747d31de512ae Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 11:16:20 -0700 Subject: [PATCH 05/42] Update Unsloth_Studio_Colab.ipynb --- studio/Unsloth_Studio_Colab.ipynb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/studio/Unsloth_Studio_Colab.ipynb b/studio/Unsloth_Studio_Colab.ipynb index d73295eeb4..7c45c61196 100644 --- a/studio/Unsloth_Studio_Colab.ipynb +++ b/studio/Unsloth_Studio_Colab.ipynb @@ -16,7 +16,10 @@ "\n", "### Unsloth Studio\n", "\n", - "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start).
We are actively working on making Unsloth Studio install on Colab T4 GPUs faster. Currently, installation may take 30+ mins so use a newer GPU.\n", + "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start).\n", + "\n", + "\n", + We are actively working on making Unsloth Studio install on Colab T4 GPUs faster. Currently, installation may take 30+ mins so use a newer GPU.\n", "\n", "[Features](https://unsloth.ai/docs/new/unsloth-studio#features) • [Quickstart](https://unsloth.ai/docs/new/unsloth-studio/start) • [Data Recipes](https://unsloth.ai/docs/new/unsloth-studio/data-recipe) • [Studio Chat](https://unsloth.ai/docs/new/unsloth-studio/chat) • [Export](https://unsloth.ai/docs/new/unsloth-studio/export)" ] From a46cb120bb1df36a4167b00d7938cffb041f9487 Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 11:24:54 -0700 Subject: [PATCH 06/42] Update Unsloth_Studio_Colab.ipynb --- studio/Unsloth_Studio_Colab.ipynb | 49 ++++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/studio/Unsloth_Studio_Colab.ipynb b/studio/Unsloth_Studio_Colab.ipynb index 7c45c61196..9742b8f760 100644 --- a/studio/Unsloth_Studio_Colab.ipynb +++ b/studio/Unsloth_Studio_Colab.ipynb @@ -1,28 +1,29 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "6b87de59", - "metadata": {}, - "source": [ - "To run this, press \"*Runtime*\" and press \"*Run all*\" on a **free** Tesla T4 Google Colab instance!\n", - "
\n", - "\n", - "\n", - " Join Discord if you need help + ⭐ Star us on Github ⭐\n", - "
\n", - "\n", - "To install Unsloth Studio on your local device, follow [our guide](https://unsloth.ai/docs/new/unsloth-studio/install). Unsloth Studio is licensed [AGPL-3.0](https://github.com/unslothai/unsloth/blob/main/studio/LICENSE.AGPL-3.0).\n", - "\n", - "### Unsloth Studio\n", - "\n", - "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start).\n", - "\n", - "\n", - We are actively working on making Unsloth Studio install on Colab T4 GPUs faster. Currently, installation may take 30+ mins so use a newer GPU.\n", - "\n", - "[Features](https://unsloth.ai/docs/new/unsloth-studio#features) • [Quickstart](https://unsloth.ai/docs/new/unsloth-studio/start) • [Data Recipes](https://unsloth.ai/docs/new/unsloth-studio/data-recipe) • [Studio Chat](https://unsloth.ai/docs/new/unsloth-studio/chat) • [Export](https://unsloth.ai/docs/new/unsloth-studio/export)" - ] + "cells": [ + { + "cell_type": "markdown", + "id": "6b87de59", + "metadata": {}, + "source": [ + "To run this, press \"*Runtime*\" and press \"*Run all*\" on a **free** Tesla T4 Google Colab instance!\n", + "
\n", + "\n", + "\n", + " Join Discord if you need help + ⭐ Star us on Github ⭐\n", + "
\n", + "\n", + "To install Unsloth Studio on your local device, follow [our guide](https://unsloth.ai/docs/new/unsloth-studio/install). Unsloth Studio is licensed [AGPL-3.0](https://github.com/unslothai/unsloth/blob/main/studio/LICENSE.AGPL-3.0).\n", + "\n", + "### Unsloth Studio\n", + "\n", + "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start).\n", + "\n", + "\n", + "We are actively working on making Unsloth Studio install on Colab T4 GPUs faster. Currently, installation may take 30+ mins so use a newer GPU.\n", + "\n", + "[Features](https://unsloth.ai/docs/new/unsloth-studio#features) • [Quickstart](https://unsloth.ai/docs/new/unsloth-studio/start) • [Data Recipes](https://unsloth.ai/docs/new/unsloth-studio/data-recipe) • [Studio Chat](https://unsloth.ai/docs/new/unsloth-studio/chat) • [Export](https://unsloth.ai/docs/new/unsloth-studio/export)" + ] +} }, { "cell_type": "markdown", From 01dfbab5a84d9214a940d2948bb846698a991f18 Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 11:27:04 -0700 Subject: [PATCH 07/42] Update Unsloth_Studio_Colab.ipynb --- studio/Unsloth_Studio_Colab.ipynb | 195 +++++++++++++++--------------- 1 file changed, 97 insertions(+), 98 deletions(-) diff --git a/studio/Unsloth_Studio_Colab.ipynb b/studio/Unsloth_Studio_Colab.ipynb index 9742b8f760..3f1149c290 100644 --- a/studio/Unsloth_Studio_Colab.ipynb +++ b/studio/Unsloth_Studio_Colab.ipynb @@ -23,102 +23,101 @@ "\n", "[Features](https://unsloth.ai/docs/new/unsloth-studio#features) • [Quickstart](https://unsloth.ai/docs/new/unsloth-studio/start) • [Data Recipes](https://unsloth.ai/docs/new/unsloth-studio/data-recipe) • [Studio Chat](https://unsloth.ai/docs/new/unsloth-studio/chat) • [Export](https://unsloth.ai/docs/new/unsloth-studio/export)" ] -} - }, - { - "cell_type": "markdown", - "id": "e4206349", - "metadata": {}, - "source": [ - "

" - ] - }, - { - "cell_type": "markdown", - "id": "27da2957", - "metadata": {}, - "source": [ - "### Setup: Clone repo and run setup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "27e68f91", - "metadata": {}, - "outputs": [], - "source": [ - "!git clone --depth 1 --branch main https://github.com/unslothai/unsloth.git\n", - "%cd /content/unsloth\n", - "\n", - "# Run setup script\n", - "!chmod +x studio/setup.sh\n", - "!./studio/setup.sh" - ] - }, - { - "cell_type": "markdown", - "id": "3e1771a9", - "metadata": {}, - "source": [ - "### Start Unsloth Studio" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "277e431e", - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "sys.path.insert(0, '/content/unsloth/studio/backend')\n", - "\n", - "from colab import start\n", - "start()" - ] - }, - { - "cell_type": "markdown", - "id": "f2b0c6a1", - "metadata": {}, - "source": [ - "And we're done! If you have any questions on Unsloth, we have a [Discord](https://discord.gg/unsloth) channel! If you find any bugs or want to keep updated with the latest LLM stuff, or need help, join projects etc, feel free to join our Discord!\n", - "\n", - "Some other resources:\n", - "1. Looking to use Unsloth locally? Read our [Installation Guide](https://unsloth.ai/docs/get-started/install) for details on installing Unsloth on Windows, Docker, AMD, Intel GPUs.\n", - "2. Learn how to do Reinforcement Learning with our [RL Guide and notebooks](https://unsloth.ai/docs/get-started/reinforcement-learning-rl-guide).\n", - "3. Read our guides and notebooks for [Text-to-speech (TTS)](https://unsloth.ai/docs/basics/text-to-speech-tts-fine-tuning) and [vision](https://unsloth.ai/docs/basics/vision-fine-tuning) model support.\n", - "4. Explore our [LLM Tutorials Directory](https://unsloth.ai/docs/models/tutorials-how-to-fine-tune-and-run-llms) to find dedicated guides for each model.\n", - "5. Need help with Inference? Read our [Inference & Deployment page](https://unsloth.ai/docs/basics/inference-and-deployment) for details on using vLLM, llama.cpp, Ollama etc.\n", - "\n", - "
\n", - " \n", - " \n", - " \n", - "\n", - " Join Discord if you need help + ⭐️ Star us on Github ⭐️\n", - "\n", - " This notebook is licensed AGPL-3.0\n", - "
" - ] - } - ], - "metadata": { - "accelerator": "GPU", - "colab": { - "gpuType": "T4", - "include_colab_link": true, - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 5 + }, + { + "cell_type": "markdown", + "id": "e4206349", + "metadata": {}, + "source": [ + "

" + ] + }, + { + "cell_type": "markdown", + "id": "27da2957", + "metadata": {}, + "source": [ + "### Setup: Clone repo and run setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27e68f91", + "metadata": {}, + "outputs": [], + "source": [ + "!git clone --depth 1 --branch main https://github.com/unslothai/unsloth.git\n", + "%cd /content/unsloth\n", + "\n", + "# Run setup script\n", + "!chmod +x studio/setup.sh\n", + "!./studio/setup.sh" + ] + }, + { + "cell_type": "markdown", + "id": "3e1771a9", + "metadata": {}, + "source": [ + "### Start Unsloth Studio" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "277e431e", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.insert(0, \"/content/unsloth/studio/backend\")\n", + "\n", + "from colab import start\n", + "start()" + ] + }, + { + "cell_type": "markdown", + "id": "f2b0c6a1", + "metadata": {}, + "source": [ + "And we're done! If you have any questions on Unsloth, we have a [Discord](https://discord.gg/unsloth) channel! If you find any bugs or want to keep updated with the latest LLM stuff, or need help, join projects etc, feel free to join our Discord!\n", + "\n", + "Some other resources:\n", + "1. Looking to use Unsloth locally? Read our [Installation Guide](https://unsloth.ai/docs/get-started/install) for details on installing Unsloth on Windows, Docker, AMD, Intel GPUs.\n", + "2. Learn how to do Reinforcement Learning with our [RL Guide and notebooks](https://unsloth.ai/docs/get-started/reinforcement-learning-rl-guide).\n", + "3. Read our guides and notebooks for [Text-to-speech (TTS)](https://unsloth.ai/docs/basics/text-to-speech-tts-fine-tuning) and [vision](https://unsloth.ai/docs/basics/vision-fine-tuning) model support.\n", + "4. Explore our [LLM Tutorials Directory](https://unsloth.ai/docs/models/tutorials-how-to-fine-tune-and-run-llms) to find dedicated guides for each model.\n", + "5. Need help with Inference? Read our [Inference & Deployment page](https://unsloth.ai/docs/basics/inference-and-deployment) for details on using vLLM, llama.cpp, Ollama etc.\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + " Join Discord if you need help + ⭐️ Star us on Github ⭐️\n", + "\n", + " This notebook is licensed AGPL-3.0\n", + "
" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "include_colab_link": true, + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 } From 2a8d6b2b8256862efe311862f68a9c907f354351 Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 11:31:09 -0700 Subject: [PATCH 08/42] Update Unsloth_Studio_Colab.ipynb --- studio/Unsloth_Studio_Colab.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/studio/Unsloth_Studio_Colab.ipynb b/studio/Unsloth_Studio_Colab.ipynb index 3f1149c290..82bc460068 100644 --- a/studio/Unsloth_Studio_Colab.ipynb +++ b/studio/Unsloth_Studio_Colab.ipynb @@ -16,10 +16,10 @@ "\n", "### Unsloth Studio\n", "\n", - "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start).\n", + "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start). Currently, installation may take 30+ mins so use a newer GPU.\n", "\n", "\n", - "We are actively working on making Unsloth Studio install on Colab T4 GPUs faster. Currently, installation may take 30+ mins so use a newer GPU.\n", + "We are actively working on making Unsloth Studio install on Colab T4 GPUs faster.\n", "\n", "[Features](https://unsloth.ai/docs/new/unsloth-studio#features) • [Quickstart](https://unsloth.ai/docs/new/unsloth-studio/start) • [Data Recipes](https://unsloth.ai/docs/new/unsloth-studio/data-recipe) • [Studio Chat](https://unsloth.ai/docs/new/unsloth-studio/chat) • [Export](https://unsloth.ai/docs/new/unsloth-studio/export)" ] From 93ab09d19506fa2f652b89f9f0c4caf8dd85b7e2 Mon Sep 17 00:00:00 2001 From: Manan Shah <52329525+Manan17@users.noreply.github.com> Date: Tue, 17 Mar 2026 13:58:34 -0500 Subject: [PATCH 09/42] [Feature] compare for 2 diff models (#4356) * compare for 2 diff models * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * resolving gemini comments * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix(studio): refine model-load toast stop action and compare selector sizing (#4369) Co-authored-by: imagineer99 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Daniel Han Co-authored-by: imagineer99 --- .../chat/components/model-load-status.tsx | 22 +++++++++----- .../chat/hooks/use-chat-model-runtime.ts | 30 +++++++++---------- .../src/features/chat/shared-composer.tsx | 2 +- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/studio/frontend/src/features/chat/components/model-load-status.tsx b/studio/frontend/src/features/chat/components/model-load-status.tsx index 19eff054f7..ad9946b0fe 100644 --- a/studio/frontend/src/features/chat/components/model-load-status.tsx +++ b/studio/frontend/src/features/chat/components/model-load-status.tsx @@ -4,8 +4,10 @@ import { Progress } from "@/components/ui/progress"; import { Spinner } from "@/components/ui/spinner"; import { Button } from "@/components/ui/button"; +import { XIcon } from "lucide-react"; type ModelLoadDescriptionProps = { + title?: string | null; message?: string | null; progressPercent?: number | null; progressLabel?: string | null; @@ -17,6 +19,7 @@ function clampProgress(value: number): number { } export function ModelLoadDescription({ + title, message, progressPercent, progressLabel, @@ -25,10 +28,14 @@ export function ModelLoadDescription({ const hasProgress = typeof progressPercent === "number"; return ( -
+
+
+ +
+ {title ?

{title}

: null} {hasProgress ? ( -
+
{progressLabel} {Math.round(clampProgress(progressPercent))}% @@ -36,18 +43,19 @@ export function ModelLoadDescription({
) : message ? ( -

{message}

+

{message}

) : null}
{onStop ? ( ) : null}
diff --git a/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts b/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts index 6927b1871f..cfdd4e774a 100644 --- a/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts +++ b/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts @@ -3,7 +3,6 @@ import { createElement, useCallback, useRef, useState } from "react"; import { toast } from "sonner"; -import { Spinner } from "@/components/ui/spinner"; import { ModelLoadDescription } from "../components/model-load-status"; import { getDownloadProgress, @@ -34,12 +33,10 @@ type SelectedModelInput = { }; const MODEL_LOAD_TOAST_CLASSNAMES = { - toast: "items-start gap-2.5 pr-8", - content: "gap-0.5", + toast: "items-start gap-2.5", + content: "gap-0.5 flex-1 min-w-0", title: "leading-5", - description: "mt-0", - closeButton: - "!left-auto !right-1.5 !top-1.5 !translate-x-0 !translate-y-0 !border-transparent !bg-transparent !shadow-none hover:!bg-transparent hover:opacity-70", + description: "mt-0 w-full", } as const; const LORA_SUFFIX_RE = /_(\d{9,})$/; @@ -200,12 +197,14 @@ export function useChatModelRuntime() { const renderLoadDescription = useCallback( ( + title: string, message: string, progressPercent?: number | null, progressLabel?: string | null, onStop?: () => void, ) => createElement(ModelLoadDescription, { + title, message, progressPercent, progressLabel, @@ -448,18 +447,19 @@ export function useChatModelRuntime() { } } + const toastTitle = isDownloaded ? "Starting model…" : "Downloading model…"; const toastId = toast( - isDownloaded ? "Starting model…" : "Downloading model…", + null, { - icon: createElement(Spinner, { className: "size-4" }), description: renderLoadDescription( + toastTitle, loadingDescription, isDownloaded ? null : 0, isDownloaded ? null : "Preparing download", cancelLoading, ), duration: Infinity, - closeButton: true, + closeButton: false, classNames: MODEL_LOAD_TOAST_CLASSNAMES, onDismiss: (dismissedToast) => { if (loadToastIdRef.current !== dismissedToast.id) { @@ -505,18 +505,18 @@ export function useChatModelRuntime() { }); if (loadToastDismissedRef.current) return; toast( - "Downloading model…", + null, { id: toastId, - icon: createElement(Spinner, { className: "size-4" }), description: renderLoadDescription( + "Downloading model…", loadingDescription, pct, progressLabel, cancelLoading, ), duration: Infinity, - closeButton: true, + closeButton: false, classNames: MODEL_LOAD_TOAST_CLASSNAMES, onDismiss: (dismissedToast) => { if (loadToastIdRef.current !== dismissedToast.id) return; @@ -542,17 +542,17 @@ export function useChatModelRuntime() { if (progressInterval) clearInterval(progressInterval); return; } - toast("Starting model…", { + toast(null, { id: toastId, - icon: createElement(Spinner, { className: "size-4" }), description: renderLoadDescription( + "Starting model…", "Download complete. Loading the model into memory.", 100, "Download complete", cancelLoading, ), duration: Infinity, - closeButton: true, + closeButton: false, classNames: MODEL_LOAD_TOAST_CLASSNAMES, onDismiss: (dismissedToast) => { if (loadToastIdRef.current !== dismissedToast.id) return; diff --git a/studio/frontend/src/features/chat/shared-composer.tsx b/studio/frontend/src/features/chat/shared-composer.tsx index c2ca25a658..018c3ba410 100644 --- a/studio/frontend/src/features/chat/shared-composer.tsx +++ b/studio/frontend/src/features/chat/shared-composer.tsx @@ -363,7 +363,7 @@ export function SharedComposer({ // Side 1: load → generate → wait if (handle1 && model1?.id) { toast("Loading Model 1…", { id: toastId, description: name1, duration: Infinity }); - await ensureModelLoaded(model1); + const status = await ensureModelLoaded(model1); toast("Generating with Model 1…", { id: toastId, description: name1, duration: Infinity }); const done = handle1.waitForRunEnd(); handle1.startRun(); From 523ebf1e2f24b06ff552288887e038723ed67d5f Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 15:42:38 -0700 Subject: [PATCH 10/42] Update Unsloth_Studio_Colab.ipynb --- studio/Unsloth_Studio_Colab.ipynb | 226 +++++++++++++++--------------- 1 file changed, 113 insertions(+), 113 deletions(-) diff --git a/studio/Unsloth_Studio_Colab.ipynb b/studio/Unsloth_Studio_Colab.ipynb index 82bc460068..c6a5378b85 100644 --- a/studio/Unsloth_Studio_Colab.ipynb +++ b/studio/Unsloth_Studio_Colab.ipynb @@ -1,21 +1,21 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "6b87de59", - "metadata": {}, - "source": [ - "To run this, press \"*Runtime*\" and press \"*Run all*\" on a **free** Tesla T4 Google Colab instance!\n", - "
\n", - "\n", - "\n", - " Join Discord if you need help + ⭐ Star us on Github ⭐\n", - "
\n", - "\n", - "To install Unsloth Studio on your local device, follow [our guide](https://unsloth.ai/docs/new/unsloth-studio/install). Unsloth Studio is licensed [AGPL-3.0](https://github.com/unslothai/unsloth/blob/main/studio/LICENSE.AGPL-3.0).\n", - "\n", - "### Unsloth Studio\n", - "\n", + "cells": [ + { + "cell_type": "markdown", + "id": "6b87de59", + "metadata": {}, + "source": [ + "To run this, press \"*Runtime*\" and press \"*Run all*\" on a **free** Tesla T4 Google Colab instance!\n", + "
\n", + "\n", + "\n", + " Join Discord if you need help + ⭐ Star us on Github ⭐\n", + "
\n", + "\n", + "To install Unsloth Studio on your local device, follow [our guide](https://unsloth.ai/docs/new/unsloth-studio/install). Unsloth Studio is licensed [AGPL-3.0](https://github.com/unslothai/unsloth/blob/main/studio/LICENSE.AGPL-3.0).\n", + "\n", + "### Unsloth Studio\n", + "\n", "Train and run open models with [**Unsloth Studio**](https://unsloth.ai/docs/new/unsloth-studio/start). Currently, installation may take 30+ mins so use a newer GPU.\n", "\n", "\n", @@ -23,101 +23,101 @@ "\n", "[Features](https://unsloth.ai/docs/new/unsloth-studio#features) • [Quickstart](https://unsloth.ai/docs/new/unsloth-studio/start) • [Data Recipes](https://unsloth.ai/docs/new/unsloth-studio/data-recipe) • [Studio Chat](https://unsloth.ai/docs/new/unsloth-studio/chat) • [Export](https://unsloth.ai/docs/new/unsloth-studio/export)" ] - }, - { - "cell_type": "markdown", - "id": "e4206349", - "metadata": {}, - "source": [ - "

" - ] - }, - { - "cell_type": "markdown", - "id": "27da2957", - "metadata": {}, - "source": [ - "### Setup: Clone repo and run setup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "27e68f91", - "metadata": {}, - "outputs": [], - "source": [ - "!git clone --depth 1 --branch main https://github.com/unslothai/unsloth.git\n", - "%cd /content/unsloth\n", - "\n", - "# Run setup script\n", - "!chmod +x studio/setup.sh\n", - "!./studio/setup.sh" - ] - }, - { - "cell_type": "markdown", - "id": "3e1771a9", - "metadata": {}, - "source": [ - "### Start Unsloth Studio" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "277e431e", - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "sys.path.insert(0, \"/content/unsloth/studio/backend\")\n", - "\n", - "from colab import start\n", - "start()" - ] - }, - { - "cell_type": "markdown", - "id": "f2b0c6a1", - "metadata": {}, - "source": [ - "And we're done! If you have any questions on Unsloth, we have a [Discord](https://discord.gg/unsloth) channel! If you find any bugs or want to keep updated with the latest LLM stuff, or need help, join projects etc, feel free to join our Discord!\n", - "\n", - "Some other resources:\n", - "1. Looking to use Unsloth locally? Read our [Installation Guide](https://unsloth.ai/docs/get-started/install) for details on installing Unsloth on Windows, Docker, AMD, Intel GPUs.\n", - "2. Learn how to do Reinforcement Learning with our [RL Guide and notebooks](https://unsloth.ai/docs/get-started/reinforcement-learning-rl-guide).\n", - "3. Read our guides and notebooks for [Text-to-speech (TTS)](https://unsloth.ai/docs/basics/text-to-speech-tts-fine-tuning) and [vision](https://unsloth.ai/docs/basics/vision-fine-tuning) model support.\n", - "4. Explore our [LLM Tutorials Directory](https://unsloth.ai/docs/models/tutorials-how-to-fine-tune-and-run-llms) to find dedicated guides for each model.\n", - "5. Need help with Inference? Read our [Inference & Deployment page](https://unsloth.ai/docs/basics/inference-and-deployment) for details on using vLLM, llama.cpp, Ollama etc.\n", - "\n", - "
\n", - " \n", - " \n", - " \n", - "\n", - " Join Discord if you need help + ⭐️ Star us on Github ⭐️\n", - "\n", - " This notebook is licensed AGPL-3.0\n", - "
" - ] - } - ], - "metadata": { - "accelerator": "GPU", - "colab": { - "gpuType": "T4", - "include_colab_link": true, - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "name": "python" - } }, - "nbformat": 4, - "nbformat_minor": 5 + { + "cell_type": "markdown", + "id": "e4206349", + "metadata": {}, + "source": [ + "

" + ] + }, + { + "cell_type": "markdown", + "id": "27da2957", + "metadata": {}, + "source": [ + "### Setup: Clone repo and run setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27e68f91", + "metadata": {}, + "outputs": [], + "source": [ + "!git clone --depth 1 --branch main https://github.com/unslothai/unsloth.git\n", + "%cd /content/unsloth\n", + "\n", + "# Run setup script\n", + "!chmod +x studio/setup.sh\n", + "!./studio/setup.sh" + ] + }, + { + "cell_type": "markdown", + "id": "3e1771a9", + "metadata": {}, + "source": [ + "### Start Unsloth Studio" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "277e431e", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.insert(0, '/content/unsloth/studio/backend')\n", + "\n", + "from colab import start\n", + "start()" + ] + }, + { + "cell_type": "markdown", + "id": "f2b0c6a1", + "metadata": {}, + "source": [ + "And we're done! If you have any questions on Unsloth, we have a [Discord](https://discord.gg/unsloth) channel! If you find any bugs or want to keep updated with the latest LLM stuff, or need help, join projects etc, feel free to join our Discord!\n", + "\n", + "Some other resources:\n", + "1. Looking to use Unsloth locally? Read our [Installation Guide](https://unsloth.ai/docs/get-started/install) for details on installing Unsloth on Windows, Docker, AMD, Intel GPUs.\n", + "2. Learn how to do Reinforcement Learning with our [RL Guide and notebooks](https://unsloth.ai/docs/get-started/reinforcement-learning-rl-guide).\n", + "3. Read our guides and notebooks for [Text-to-speech (TTS)](https://unsloth.ai/docs/basics/text-to-speech-tts-fine-tuning) and [vision](https://unsloth.ai/docs/basics/vision-fine-tuning) model support.\n", + "4. Explore our [LLM Tutorials Directory](https://unsloth.ai/docs/models/tutorials-how-to-fine-tune-and-run-llms) to find dedicated guides for each model.\n", + "5. Need help with Inference? Read our [Inference & Deployment page](https://unsloth.ai/docs/basics/inference-and-deployment) for details on using vLLM, llama.cpp, Ollama etc.\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + " Join Discord if you need help + ⭐️ Star us on Github ⭐️\n", + "\n", + " This notebook is licensed AGPL-3.0\n", + "
" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "include_colab_link": true, + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 } From 03736a82ba3113f86f849158f9c7c48e88d4ce3a Mon Sep 17 00:00:00 2001 From: Wasim Yousef Said Date: Wed, 18 Mar 2026 00:04:11 +0100 Subject: [PATCH 11/42] Relax frontend unused local check (#4388) --- studio/frontend/tsconfig.app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/frontend/tsconfig.app.json b/studio/frontend/tsconfig.app.json index 216210eacd..33b2035b9a 100644 --- a/studio/frontend/tsconfig.app.json +++ b/studio/frontend/tsconfig.app.json @@ -18,7 +18,7 @@ /* Linting */ "strict": true, - "noUnusedLocals": true, + "noUnusedLocals": false, "noUnusedParameters": true, "erasableSyntaxOnly": true, "noFallthroughCasesInSwitch": true, From e138a3d48b1fa1153ce5c99779ccd4cfa20c65d6 Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 16:08:40 -0700 Subject: [PATCH 12/42] Update install instructions.md --- README.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 169fc80ea6..31d7a188df 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,7 @@ Unsloth Studio works on **Windows, Linux, WSL** and **macOS**. * **macOS:** Currently supports chat only; **MLX training** is coming very soon * **Multi-GPU:** Available now, with a major upgrade on the way -#### Windows, MacOS Linux or WSL: -``` -pip install unsloth -unsloth studio setup -unsloth studio -H 0.0.0.0 -p 8888 -``` -Use our [Docker image](https://hub.docker.com/r/unsloth/unsloth) ```unsloth/unsloth``` container. Read our [Docker Guide](https://unsloth.ai/docs/get-started/install/docker). -#### Git from source +#### Windows, MacOS, Linux or WSL: ``` git clone https://github.com/unslothai/unsloth.git cd unsloth @@ -63,6 +56,7 @@ pip install -e . unsloth studio setup unsloth studio -H 0.0.0.0 -p 8888 ``` +Use our [Docker image](https://hub.docker.com/r/unsloth/unsloth) ```unsloth/unsloth``` container. Read our [Docker Guide](https://unsloth.ai/docs/get-started/install/docker). ### Unsloth Core (code-based) #### Windows, Linux, WSL From 8bca62aa78a96b5e6e4dab25a9391bd6cd0eeb4d Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 18:48:00 -0700 Subject: [PATCH 13/42] Dual License clarification.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 31d7a188df..d5d4c9715a 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,11 @@ You can cite the Unsloth repo as follows: ``` If you trained a model with 🦥Unsloth, you can use this cool sticker!   +### License +Unsloth uses a dual-licensing model of Apache 2.0 and AGPL-3.0. The core Unsloth package remains licensed under **[Apache 2.0](https://github.com/unslothai/unsloth?tab=Apache-2.0-1-ov-file)**, while certain optional components, such as the Unsloth Studio UI are licensed under **[AGPL-3.0](https://github.com/unslothai/unsloth?tab=AGPL-3.0-2-ov-file)**. + +This structure helps support ongoing Unsloth development while keeping the project open source and enabling the broader ecosystem to continue growing. + ### Thank You to - The [llama.cpp library](https://github.com/ggml-org/llama.cpp) that lets users run and save models with Unsloth - The Hugging Face team and their libraries: [transformers](https://github.com/huggingface/transformers) and [TRL](https://github.com/huggingface/trl) From 75da2e00c2f419708f6c6e26776f3835a2cfb9d7 Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:04:04 -0700 Subject: [PATCH 14/42] Update install instructions.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d5d4c9715a..692887088e 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,20 @@ Unsloth Studio works on **Windows, Linux, WSL** and **macOS**. #### Windows, MacOS, Linux or WSL: ``` +pip install unsloth +unsloth studio setup +unsloth studio -H 0.0.0.0 -p 8888 +``` +Use our [Docker image](https://hub.docker.com/r/unsloth/unsloth) ```unsloth/unsloth``` container. Read our [Docker Guide](https://unsloth.ai/docs/get-started/install/docker). + +You can also install directly from source: +``` git clone https://github.com/unslothai/unsloth.git cd unsloth pip install -e . unsloth studio setup unsloth studio -H 0.0.0.0 -p 8888 ``` -Use our [Docker image](https://hub.docker.com/r/unsloth/unsloth) ```unsloth/unsloth``` container. Read our [Docker Guide](https://unsloth.ai/docs/get-started/install/docker). ### Unsloth Core (code-based) #### Windows, Linux, WSL From 0c8d407793b287f751b7b5844cc21f480659bcb3 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Tue, 17 Mar 2026 20:40:21 -0700 Subject: [PATCH 15/42] Rename cli/ to unsloth_cli/ to fix namespace collision with stringzilla (#4393) * Rename cli/ to unsloth_cli/ to fix namespace collision with stringzilla stringzilla installs a namespace package at cli/ (cli/split.py, cli/wc.py) in site-packages without an __init__.py. When unsloth is installed as an editable package (pip install -e .), the entry point script does `from cli import app` which finds stringzilla's namespace cli/ first and fails with `ImportError: cannot import name 'app' from 'cli'`. Non-editable installs happened to work because unsloth's cli/__init__.py overwrites the namespace directory, but this is fragile and breaks if stringzilla is installed after unsloth. Renaming to unsloth_cli/ avoids the collision entirely and fixes both editable and non-editable install paths. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update stale cli/ references in comments and license files --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- COPYING | 2 +- LICENSE | 2 +- cli.py | 2 +- pyproject.toml | 2 +- {cli => unsloth_cli}/__init__.py | 10 +++++----- {cli => unsloth_cli}/commands/__init__.py | 0 {cli => unsloth_cli}/commands/export.py | 0 {cli => unsloth_cli}/commands/inference.py | 0 {cli => unsloth_cli}/commands/studio.py | 4 ++-- {cli => unsloth_cli}/commands/train.py | 4 ++-- {cli => unsloth_cli}/commands/ui.py | 6 +++++- {cli => unsloth_cli}/config.py | 0 {cli => unsloth_cli}/options.py | 0 13 files changed, 18 insertions(+), 14 deletions(-) rename {cli => unsloth_cli}/__init__.py (68%) rename {cli => unsloth_cli}/commands/__init__.py (100%) rename {cli => unsloth_cli}/commands/export.py (100%) rename {cli => unsloth_cli}/commands/inference.py (100%) rename {cli => unsloth_cli}/commands/studio.py (97%) rename {cli => unsloth_cli}/commands/train.py (97%) rename {cli => unsloth_cli}/commands/ui.py (96%) rename {cli => unsloth_cli}/config.py (100%) rename {cli => unsloth_cli}/options.py (100%) diff --git a/COPYING b/COPYING index cb7331bd35..4213fd700d 100644 --- a/COPYING +++ b/COPYING @@ -661,4 +661,4 @@ For more information on this, and how to apply and follow the GNU AGPL, see . Files under unsloth/*, tests/*, scripts/* are Apache 2.0 licensed. -Files under studio/*, cli/* which is optional to install are AGPLv3 licensed. \ No newline at end of file +Files under studio/*, unsloth_cli/* which is optional to install are AGPLv3 licensed. \ No newline at end of file diff --git a/LICENSE b/LICENSE index 8c3c43e374..e1600b0c03 100644 --- a/LICENSE +++ b/LICENSE @@ -188,7 +188,7 @@ Copyright [2024-] [Unsloth AI. Inc team, Daniel Han-Chen & Michael Han-Chen] Files under unsloth/*, tests/*, scripts/* are Apache 2.0 licensed. - Files under studio/*, cli/* which is optional to install are AGPLv3 licensed. + Files under studio/*, unsloth_cli/* which is optional to install are AGPLv3 licensed. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cli.py b/cli.py index 0965b424e8..534babed2c 100644 --- a/cli.py +++ b/cli.py @@ -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 -from cli import app +from unsloth_cli import app if __name__ == "__main__": app() diff --git a/pyproject.toml b/pyproject.toml index f7112aa89e..d9898c6a95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ ] [project.scripts] -unsloth = "cli:app" +unsloth = "unsloth_cli:app" [tool.setuptools.dynamic] version = {attr = "unsloth.models._utils.__version__"} diff --git a/cli/__init__.py b/unsloth_cli/__init__.py similarity index 68% rename from cli/__init__.py rename to unsloth_cli/__init__.py index 434ee4d2ed..3b9043c5bf 100644 --- a/cli/__init__.py +++ b/unsloth_cli/__init__.py @@ -3,11 +3,11 @@ import typer -from cli.commands.train import train -from cli.commands.inference import inference -from cli.commands.export import export, list_checkpoints -from cli.commands.ui import ui -from cli.commands.studio import studio_app +from unsloth_cli.commands.train import train +from unsloth_cli.commands.inference import inference +from unsloth_cli.commands.export import export, list_checkpoints +from unsloth_cli.commands.ui import ui +from unsloth_cli.commands.studio import studio_app app = typer.Typer( help = "Command-line interface for Unsloth training, inference, and export.", diff --git a/cli/commands/__init__.py b/unsloth_cli/commands/__init__.py similarity index 100% rename from cli/commands/__init__.py rename to unsloth_cli/commands/__init__.py diff --git a/cli/commands/export.py b/unsloth_cli/commands/export.py similarity index 100% rename from cli/commands/export.py rename to unsloth_cli/commands/export.py diff --git a/cli/commands/inference.py b/unsloth_cli/commands/inference.py similarity index 100% rename from cli/commands/inference.py rename to unsloth_cli/commands/inference.py diff --git a/cli/commands/studio.py b/unsloth_cli/commands/studio.py similarity index 97% rename from cli/commands/studio.py rename to unsloth_cli/commands/studio.py index da5198ad75..829f086b7d 100644 --- a/cli/commands/studio.py +++ b/unsloth_cli/commands/studio.py @@ -14,7 +14,7 @@ studio_app = typer.Typer(help = "Unsloth Studio commands.") STUDIO_HOME = Path.home() / ".unsloth" / "studio" -# __file__ is cli/commands/studio.py — two parents up is the package root +# __file__ is unsloth_cli/commands/studio.py -- two parents up is the package root # (either site-packages or the repo root for editable installs). _PACKAGE_ROOT = Path(__file__).resolve().parent.parent.parent @@ -33,7 +33,7 @@ def _find_run_py() -> Optional[Path]: No CWD dependency — works from any directory. Since studio/ is now a proper package (has __init__.py), it lives in - site-packages after pip install, right next to cli/. + site-packages after pip install, right next to unsloth_cli/. """ # 1. Relative to __file__ (site-packages or editable repo root) run_py = _PACKAGE_ROOT / "studio" / "backend" / "run.py" diff --git a/cli/commands/train.py b/unsloth_cli/commands/train.py similarity index 97% rename from cli/commands/train.py rename to unsloth_cli/commands/train.py index 665956a80c..1157620092 100644 --- a/cli/commands/train.py +++ b/unsloth_cli/commands/train.py @@ -7,8 +7,8 @@ from typing import Optional import typer -from cli.config import Config, load_config -from cli.options import add_options_from_config +from unsloth_cli.config import Config, load_config +from unsloth_cli.options import add_options_from_config @add_options_from_config(Config) diff --git a/cli/commands/ui.py b/unsloth_cli/commands/ui.py similarity index 96% rename from cli/commands/ui.py rename to unsloth_cli/commands/ui.py index 79a76e629b..eb6a8a69e8 100644 --- a/cli/commands/ui.py +++ b/unsloth_cli/commands/ui.py @@ -25,7 +25,11 @@ def ui( ), ): """Launch the Unsloth web UI backend server (alias for 'unsloth studio').""" - from cli.commands.studio import _studio_venv_python, _find_run_py, STUDIO_HOME + from unsloth_cli.commands.studio import ( + _studio_venv_python, + _find_run_py, + STUDIO_HOME, + ) # Re-execute in studio venv if available and not already inside it studio_venv_dir = STUDIO_HOME / ".venv" diff --git a/cli/config.py b/unsloth_cli/config.py similarity index 100% rename from cli/config.py rename to unsloth_cli/config.py diff --git a/cli/options.py b/unsloth_cli/options.py similarity index 100% rename from cli/options.py rename to unsloth_cli/options.py From fd72376a7e6db53484617aea0dae4a806a49201e Mon Sep 17 00:00:00 2001 From: DoubleMathew Date: Tue, 17 Mar 2026 22:47:26 -0500 Subject: [PATCH 16/42] Fix/studio full finetuning (#4391) * Wire Studio full finetuning into training loaders * Preserve load_model positional compatibility --- studio/backend/core/training/trainer.py | 24 +++++++++++++++++------- studio/backend/core/training/worker.py | 6 ++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/studio/backend/core/training/trainer.py b/studio/backend/core/training/trainer.py index 0aa6d0922e..bc252d1fa5 100644 --- a/studio/backend/core/training/trainer.py +++ b/studio/backend/core/training/trainer.py @@ -466,6 +466,7 @@ class UnslothTrainer: is_dataset_image: bool = False, is_dataset_audio: bool = False, trust_remote_code: bool = False, + full_finetuning: bool = False, ) -> bool: """Load model for training (supports both text and vision models)""" self.load_in_4bit = load_in_4bit # Store for training_meta.json @@ -612,6 +613,7 @@ class UnslothTrainer: dtype = None, auto_model = CsmForConditionalGeneration, load_in_4bit = False, + full_finetuning = full_finetuning, token = hf_token, trust_remote_code = trust_remote_code, ) @@ -626,6 +628,7 @@ class UnslothTrainer: model_name = model_name, dtype = None, load_in_4bit = False, + full_finetuning = full_finetuning, auto_model = WhisperForConditionalGeneration, whisper_language = "English", whisper_task = "transcribe", @@ -646,6 +649,7 @@ class UnslothTrainer: max_seq_length = max_seq_length, dtype = None, load_in_4bit = load_in_4bit, + full_finetuning = full_finetuning, token = hf_token, trust_remote_code = trust_remote_code, ) @@ -684,6 +688,7 @@ class UnslothTrainer: max_seq_length = max_seq_length, dtype = torch.float32, # Spark-TTS requires float32 load_in_4bit = False, + full_finetuning = full_finetuning, token = hf_token, trust_remote_code = trust_remote_code, ) @@ -697,6 +702,7 @@ class UnslothTrainer: model_name, max_seq_length = max_seq_length, load_in_4bit = False, + full_finetuning = full_finetuning, token = hf_token, trust_remote_code = trust_remote_code, ) @@ -712,6 +718,7 @@ class UnslothTrainer: max_seq_length = max_seq_length, dtype = None, load_in_4bit = load_in_4bit, + full_finetuning = full_finetuning, token = hf_token, trust_remote_code = trust_remote_code, ) @@ -724,6 +731,7 @@ class UnslothTrainer: max_seq_length = max_seq_length, dtype = None, # Auto-detect load_in_4bit = load_in_4bit, + full_finetuning = full_finetuning, token = hf_token, trust_remote_code = trust_remote_code, ) @@ -755,6 +763,7 @@ class UnslothTrainer: max_seq_length = max_seq_length, dtype = None, # Auto-detect load_in_4bit = load_in_4bit, + full_finetuning = full_finetuning, token = hf_token, trust_remote_code = trust_remote_code, ) @@ -779,13 +788,14 @@ class UnslothTrainer: self._source_code_retried = True logger.info(f"\n'could not get source code' — retrying once...\n") return self.load_model( - model_name, - max_seq_length, - load_in_4bit, - hf_token, - is_dataset_image, - is_dataset_audio, - trust_remote_code, + model_name = model_name, + max_seq_length = max_seq_length, + load_in_4bit = load_in_4bit, + hf_token = hf_token, + is_dataset_image = is_dataset_image, + is_dataset_audio = is_dataset_audio, + trust_remote_code = trust_remote_code, + full_finetuning = full_finetuning, ) error_msg = str(e) error_lower = error_msg.lower() diff --git a/studio/backend/core/training/worker.py b/studio/backend/core/training/worker.py index 57559ded54..284fcf228d 100644 --- a/studio/backend/core/training/worker.py +++ b/studio/backend/core/training/worker.py @@ -444,12 +444,16 @@ def run_training_process( _tqdm_thread = _th.Thread(target = _monitor_tqdm, daemon = True) _tqdm_thread.start() + training_type = config.get("training_type", "LoRA/QLoRA") + use_lora = training_type == "LoRA/QLoRA" + # ── 4c. Load training model (uses VRAM — dataset already formatted) ── _send_status(event_queue, "Loading model...") success = trainer.load_model( model_name = model_name, max_seq_length = config["max_seq_length"], load_in_4bit = config["load_in_4bit"], + full_finetuning = not use_lora, hf_token = hf_token, is_dataset_image = config.get("is_dataset_image", False), is_dataset_audio = config.get("is_dataset_audio", False), @@ -473,8 +477,6 @@ def run_training_process( return # ── 4d. Prepare model (LoRA or full finetuning) ── - training_type = config.get("training_type", "LoRA/QLoRA") - use_lora = training_type == "LoRA/QLoRA" if use_lora: _send_status(event_queue, "Configuring LoRA adapters...") success = trainer.prepare_model_for_training( From ca87669937200dfe6a32794c7ec89a8b228fa65a Mon Sep 17 00:00:00 2001 From: Coenraad Loubser Date: Wed, 18 Mar 2026 05:57:27 +0200 Subject: [PATCH 17/42] Unused return value causes build failures (#4385) * Unused return value causes build failures * Update toast messages to include model loading status --- studio/frontend/src/features/chat/shared-composer.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/studio/frontend/src/features/chat/shared-composer.tsx b/studio/frontend/src/features/chat/shared-composer.tsx index 018c3ba410..89b65d4d99 100644 --- a/studio/frontend/src/features/chat/shared-composer.tsx +++ b/studio/frontend/src/features/chat/shared-composer.tsx @@ -363,8 +363,8 @@ export function SharedComposer({ // Side 1: load → generate → wait if (handle1 && model1?.id) { toast("Loading Model 1…", { id: toastId, description: name1, duration: Infinity }); - const status = await ensureModelLoaded(model1); - toast("Generating with Model 1…", { id: toastId, description: name1, duration: Infinity }); + const status1 = await ensureModelLoaded(model1); + toast("Generating with Model 1…", { id: toastId, description: `${name1} (${status1})`, duration: Infinity }); const done = handle1.waitForRunEnd(); handle1.startRun(); await done; @@ -377,8 +377,8 @@ export function SharedComposer({ if (needsLoad) { toast("Loading Model 2…", { id: toastId, description: name2, duration: Infinity }); } - await ensureModelLoaded(model2); - toast("Generating with Model 2…", { id: toastId, description: name2, duration: Infinity }); + const status2 = await ensureModelLoaded(model2); + toast("Generating with Model 2…", { id: toastId, description: `${name2} (${status2})`, duration: Infinity }); const done = handle2.waitForRunEnd(); handle2.startRun(); await done; From 3a28446a54b4a967b1452c94f32b3e96991bb3df Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Tue, 17 Mar 2026 21:32:38 -0700 Subject: [PATCH 18/42] Trim ~255 MB of unused packages from Studio setup (#4395) * Comment out large unused packages from Studio setup requirements Audited all packages installed by `unsloth studio setup` against actual imports in unsloth, unsloth_zoo, and studio/backend. The following have zero imports anywhere and are the largest offenders by disk size: - gradio (148 MB) in studio.txt -- Studio uses React + FastAPI, not Gradio - executorch (41.5 MB) in extras-no-deps.txt -- no imports found - scikit-learn (31.8 MB) in extras.txt -- no imports found - MeCab (19.9 MB) in extras.txt -- Japanese tokenizer, no imports found - coremltools (10.2 MB) in extras.txt -- Apple CoreML, no imports found - uroman (4.0 MB) in extras.txt -- romanization tool, no imports found Total savings: ~255 MB (~32% of the 805 MB installed by setup). Each line is commented out with the package size annotated so they can be re-enabled easily if needed in the future. * Restore scikit-learn -- needed by sentence_transformers sentence_transformers is installed with --no-deps in extras-no-deps.txt, so its sklearn dependency is not auto-resolved. Multiple modules in sentence_transformers import sklearn at the top level (evaluation, util/similarity), so removing scikit-learn would break embedding jobs. --- studio/backend/requirements/extras-no-deps.txt | 2 +- studio/backend/requirements/extras.txt | 8 ++++---- studio/backend/requirements/studio.txt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/studio/backend/requirements/extras-no-deps.txt b/studio/backend/requirements/extras-no-deps.txt index 29bd421a0a..3bdce81cc1 100644 --- a/studio/backend/requirements/extras-no-deps.txt +++ b/studio/backend/requirements/extras-no-deps.txt @@ -8,7 +8,7 @@ snac # TRL and related packages trl==0.23.1 git+https://github.com/meta-pytorch/OpenEnv.git -executorch>=1.0.1 +# executorch>=1.0.1 # 41.5 MB - no imports in unsloth/zoo/studio torch-c-dlpack-ext sentence_transformers==5.2.0 transformers==4.57.1 diff --git a/studio/backend/requirements/extras.txt b/studio/backend/requirements/extras.txt index 51ef69cf5d..170b1c9ec8 100644 --- a/studio/backend/requirements/extras.txt +++ b/studio/backend/requirements/extras.txt @@ -4,7 +4,7 @@ tomli-w # ExecuTorch dependencies ruamel.yaml -coremltools +# coremltools # 10.2 MB - Apple CoreML, no imports in unsloth/zoo/studio expecttest flatbuffers hydra-core @@ -15,7 +15,7 @@ pytest<9.0 pytest-json-report pytest-rerunfailures==15.1 pytest-xdist -# Also needed by sentence_transformers +# Also needed by sentence_transformers (installed with --no-deps in extras-no-deps.txt) scikit-learn==1.7.1 # Additional extras @@ -26,8 +26,8 @@ omegaconf einx pyloudnorm openai-whisper -uroman -MeCab +# uroman # 4.0 MB - romanization, no imports found +# MeCab # 19.9 MB - Japanese tokenizer, no imports found loguru flatten_dict ffmpy diff --git a/studio/backend/requirements/studio.txt b/studio/backend/requirements/studio.txt index da0b4f382b..186ba82fe0 100644 --- a/studio/backend/requirements/studio.txt +++ b/studio/backend/requirements/studio.txt @@ -10,7 +10,7 @@ datasets==4.3.0 pyjwt easydict addict -gradio>=4.0.0 +# gradio>=4.0.0 # 148 MB - Studio uses React + FastAPI, not Gradio huggingface-hub==0.36.2 structlog>=24.1.0 diceware From f3f52e2d84f281d5574ddda3bd226807d7bca489 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Tue, 17 Mar 2026 22:07:21 -0700 Subject: [PATCH 19/42] Use blobless clone in README install instructions (#4403) Reduces clone size from ~50MB to ~5MB by skipping blobs that are no longer in the current tree but still in git history. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 692887088e..dae34e12c3 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Use our [Docker image](https://hub.docker.com/r/unsloth/unsloth) ```unsloth/unsl You can also install directly from source: ``` -git clone https://github.com/unslothai/unsloth.git +git clone --filter=blob:none https://github.com/unslothai/unsloth.git cd unsloth pip install -e . unsloth studio setup From 9232126734a2a8a7088edb1f52b9c71082f38ced Mon Sep 17 00:00:00 2001 From: Lee Jackson <130007945+Imagineer99@users.noreply.github.com> Date: Wed, 18 Mar 2026 05:39:51 +0000 Subject: [PATCH 20/42] fix(studio): use explicit Cancel for model load toast (#4377) --- .../features/chat/components/model-load-status.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/studio/frontend/src/features/chat/components/model-load-status.tsx b/studio/frontend/src/features/chat/components/model-load-status.tsx index ad9946b0fe..afec327a0f 100644 --- a/studio/frontend/src/features/chat/components/model-load-status.tsx +++ b/studio/frontend/src/features/chat/components/model-load-status.tsx @@ -4,7 +4,6 @@ import { Progress } from "@/components/ui/progress"; import { Spinner } from "@/components/ui/spinner"; import { Button } from "@/components/ui/button"; -import { XIcon } from "lucide-react"; type ModelLoadDescriptionProps = { title?: string | null; @@ -28,11 +27,11 @@ export function ModelLoadDescription({ const hasProgress = typeof progressPercent === "number"; return ( -
+
-
+
{title ?

{title}

: null} {hasProgress ? (
@@ -49,13 +48,13 @@ export function ModelLoadDescription({ {onStop ? ( ) : null}
From 24753290ba5b109e9240b92f90900756ee321337 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Tue, 17 Mar 2026 22:50:55 -0700 Subject: [PATCH 21/42] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dae34e12c3..2f7dd9c748 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ Unsloth Studio works on **Windows, Linux, WSL** and **macOS**. #### Windows, MacOS, Linux or WSL: ``` -pip install unsloth +pip install --upgrade pip && pip install uv +uv pip install unsloth --torch-backend=auto unsloth studio setup unsloth studio -H 0.0.0.0 -p 8888 ``` @@ -58,9 +59,10 @@ Use our [Docker image](https://hub.docker.com/r/unsloth/unsloth) ```unsloth/unsl You can also install directly from source: ``` +pip install --upgrade pip && pip install uv git clone --filter=blob:none https://github.com/unslothai/unsloth.git cd unsloth -pip install -e . +uv pip install -e . --torch-backend=auto unsloth studio setup unsloth studio -H 0.0.0.0 -p 8888 ``` From 767c31b0e084fc1188a0e3e35a09123303fc0984 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Tue, 17 Mar 2026 22:53:11 -0700 Subject: [PATCH 22/42] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f7dd9c748..faf2bec141 100644 --- a/README.md +++ b/README.md @@ -70,13 +70,14 @@ unsloth studio -H 0.0.0.0 -p 8888 ### Unsloth Core (code-based) #### Windows, Linux, WSL ```bash -pip install unsloth +pip install --upgrade pip && pip install uv +uv pip install unsloth --torch-backend=auto ``` For Windows, `pip install unsloth` works only if you have Pytorch installed. Read our [Windows Guide](https://unsloth.ai/docs/get-started/install/windows-installation). You can use the same Docker image as Unsloth Studio. #### AMD, Intel -For RTX 50x, B200, 6000 GPUs: `pip install unsloth`. Read our guides for: [Blackwell](https://unsloth.ai/docs/blog/fine-tuning-llms-with-blackwell-rtx-50-series-and-unsloth) and [DGX Spark](https://unsloth.ai/docs/blog/fine-tuning-llms-with-nvidia-dgx-spark-and-unsloth).
+For RTX 50x, B200, 6000 GPUs: `uv pip install unsloth --torch-backend=auto`. Read our guides for: [Blackwell](https://unsloth.ai/docs/blog/fine-tuning-llms-with-blackwell-rtx-50-series-and-unsloth) and [DGX Spark](https://unsloth.ai/docs/blog/fine-tuning-llms-with-nvidia-dgx-spark-and-unsloth).
To install Unsloth on **AMD** and **Intel** GPUs, follow our [AMD Guide](https://unsloth.ai/docs/get-started/install/amd) and [Intel Guide](https://unsloth.ai/docs/get-started/install/intel). ## ✨ Free Notebooks From 67d3519cab9fde8603d89bd6303864e6ca852cb8 Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Tue, 17 Mar 2026 23:04:54 -0700 Subject: [PATCH 23/42] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index faf2bec141..e60b1f98d9 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,10 @@ Unsloth can be used in two ways: through **[Unsloth Studio](https://unsloth.ai/d Unsloth Studio works on **Windows, Linux, WSL** and **macOS**. * **CPU:** Supported for **chat inference only** -* **NVIDIA GPUs:** Training works on RTX 30/40/50, Blackwell, DGX Spark, DGX Station and more +* **NVIDIA:** Training works on RTX 30/40/50, Blackwell, DGX Spark, Station and more * **macOS:** Currently supports chat only; **MLX training** is coming very soon +* **AMD:** Chat works. Train with [Unsloth Core](#unsloth-core-code-based). Studio support is coming soon. +* **Coming soon:** Training support for Apple MLX, AMD, and Intel. * **Multi-GPU:** Available now, with a major upgrade on the way #### Windows, MacOS, Linux or WSL: From 65acefd2a67b6cf496beb2eb1b3fdadb7802d9bb Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Wed, 18 Mar 2026 03:17:01 -0700 Subject: [PATCH 24/42] feat(studio): infinite scroll for recommended models list (#4414) * feat(studio): infinite scroll for recommended models list The model selector showed a hard cap of 4 GGUFs + 4 safetensors in the Recommended section. Users who wanted to browse more had to search manually on Hugging Face. Backend: increase the default model pool from 8+8 to 40+40 (the HF fetch already pulls 80, so no extra network cost). Frontend: replace the static 4+4 cap with on-demand lazy loading. A page counter tracks how many groups of 4 to show per category. An IntersectionObserver on a sentinel div at the bottom of the list increments the page when the user scrolls down. Models are interleaved in groups of 4 GGUFs then 4 hub models per page for a balanced view. Key implementation details: - Callback ref for the sentinel so the observer attaches reliably on first popover open (useRef would miss the initial mount) - Observer disconnects after each fire and re-attaches via useEffect with a 100ms layout delay to prevent runaway page loading - VRAM info fetched incrementally via useRecommendedModelVram on the visible slice only - recommendedSet uses visible IDs so HF search dedup stays correct * refactor: address review feedback on recommended infinite scroll - Simplify visibleRecommendedIds: use findIndex to locate the GGUF/hub split point instead of re-filtering the entire array each time. recommendedIds is already sorted GGUF-first, so a single slice is enough. - Fix VRAM refetch churn: pass the full recommendedIds (stable across page increments) to useRecommendedModelVram instead of the growing visibleRecommendedIds slice. The hook derives its stableKey from the sorted+joined input, so passing the same pool on every page avoids redundant HF modelInfo requests. --- studio/backend/core/inference/orchestrator.py | 10 +-- .../assistant-ui/model-selector/pickers.tsx | 74 ++++++++++++++++--- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/studio/backend/core/inference/orchestrator.py b/studio/backend/core/inference/orchestrator.py index 42de014a8d..6ff7fd2cbf 100644 --- a/studio/backend/core/inference/orchestrator.py +++ b/studio/backend/core/inference/orchestrator.py @@ -130,17 +130,17 @@ class InferenceOrchestrator: ) if resp.status_code == 200: models = resp.json() - # Top 8 GGUFs (frontend deduplicates against downloaded, - # so we fetch extra to always fill 4 slots) + # Top 40 GGUFs - frontend pages through them on-demand via + # infinite scroll, so we send a deep pool. gguf_ids = [ m["id"] for m in models if m.get("id", "").upper().endswith("-GGUF") - ][:8] - # Top 8 non-GGUF hub models + ][:40] + # Top 40 non-GGUF hub models hub_ids = [ m["id"] for m in models if not m.get("id", "").upper().endswith("-GGUF") - ][:8] + ][:40] if gguf_ids: self._top_gguf_cache = gguf_ids logger.info("Top GGUF models: %s", gguf_ids) diff --git a/studio/frontend/src/components/assistant-ui/model-selector/pickers.tsx b/studio/frontend/src/components/assistant-ui/model-selector/pickers.tsx index 78881384b2..328cba3acd 100644 --- a/studio/frontend/src/components/assistant-ui/model-selector/pickers.tsx +++ b/studio/frontend/src/components/assistant-ui/model-selector/pickers.tsx @@ -35,7 +35,7 @@ import { checkVramFit, estimateLoadingVram } from "@/lib/vram"; import { Search01Icon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; import { Trash2Icon } from "lucide-react"; -import { useCallback, useEffect, useMemo, useState, type ReactNode } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react"; import { toast } from "sonner"; import type { LoraModelOption, @@ -455,21 +455,43 @@ export function HubModelPicker({ const all = dedupe([...models.map((model) => model.id), value ?? ""]) .filter((id) => !downloadedSet.has(id.toLowerCase())) .filter((id) => !chatOnly || isGgufRepo(id)); - // Cap at 4 GGUFs + 4 non-GGUFs so the list stays manageable + // Sort: GGUFs first, then hub models const gguf: string[] = []; const hub: string[] = []; for (const id of all) { - if (isGgufRepo(id) && gguf.length < 4) gguf.push(id); - else if (!isGgufRepo(id) && hub.length < 4) hub.push(id); + if (isGgufRepo(id)) gguf.push(id); + else hub.push(id); } return [...gguf, ...hub]; }, [models, value, downloadedSet, chatOnly]); + // Infinite scroll paging for the recommended section + const [recommendedPage, setRecommendedPage] = useState(1); + // Reset page when the underlying list changes + useEffect(() => { setRecommendedPage(1); }, [models, chatOnly]); + + const visibleRecommendedIds = useMemo(() => { + const hubStartIndex = recommendedIds.findIndex((id) => !isGgufRepo(id)); + const allGguf = hubStartIndex === -1 ? recommendedIds : recommendedIds.slice(0, hubStartIndex); + const allHub = hubStartIndex === -1 ? [] : recommendedIds.slice(hubStartIndex); + // Interleave in chunks of 4: [4 gguf, 4 hub, 4 gguf, 4 hub, ...] + const result: string[] = []; + for (let p = 0; p < recommendedPage; p++) { + result.push(...allGguf.slice(p * 4, (p + 1) * 4)); + result.push(...allHub.slice(p * 4, (p + 1) * 4)); + } + return result; + }, [recommendedIds, recommendedPage]); + + const hasMoreRecommended = visibleRecommendedIds.length < recommendedIds.length; + + // Fetch VRAM info for the full pool once (recommendedIds is stable across + // page increments) so we don't re-fetch on every scroll. const { paramCountById: recommendedParamCountById } = useRecommendedModelVram(recommendedIds); const showHfSection = debouncedQuery.trim().length > 0; - const recommendedSet = useMemo(() => new Set(recommendedIds), [recommendedIds]); + const recommendedSet = useMemo(() => new Set(visibleRecommendedIds), [visibleRecommendedIds]); const hfIds = useMemo(() => { if (!showHfSection) return []; @@ -519,7 +541,7 @@ export function HubModelPicker({ string, { est: number; status: VramFitStatus | null; detail: string | null } >(); - for (const id of recommendedIds) { + for (const id of visibleRecommendedIds) { const totalParams = recommendedParamCountById.get(id); if (totalParams) { const est = estimateLoadingVram(totalParams, "qlora"); @@ -531,10 +553,36 @@ export function HubModelPicker({ } } return map; - }, [recommendedIds, recommendedParamCountById, gpu]); + }, [visibleRecommendedIds, recommendedParamCountById, gpu]); const { scrollRef, sentinelRef } = useInfiniteScroll(fetchMore, results.length); + // Sentinel + IntersectionObserver for recommended infinite scroll. + // We disconnect after each fire so the observer doesn't loop while + // React re-renders; the effect re-creates it on the next page. + // Uses a callback ref for the sentinel so we detect mount/unmount reliably. + const [recommendedSentinel, setRecommendedSentinel] = useState(null); + const recommendedSentinelRef = useCallback((node: HTMLDivElement | null) => { + setRecommendedSentinel(node); + }, []); + useEffect(() => { + if (!recommendedSentinel || !hasMoreRecommended) return; + const root = scrollRef.current; + if (!root) return; + const obs = new IntersectionObserver( + ([e]) => { + if (e.isIntersecting) { + obs.disconnect(); + setRecommendedPage((p) => p + 1); + } + }, + { threshold: 0, root }, + ); + // Small delay so the browser finishes layout after the previous page render + const timer = setTimeout(() => obs.observe(recommendedSentinel), 100); + return () => { clearTimeout(timer); obs.disconnect(); }; + }, [recommendedSentinel, hasMoreRecommended, recommendedPage, scrollRef]); + /** Handle clicking a model row — GGUF repos expand, others load directly. */ const handleModelClick = useCallback( (id: string) => { @@ -622,12 +670,12 @@ export function HubModelPicker({ {!showHfSection && cachedReady ? ( <> {"\uD83E\uDDA5"} Recommended - {recommendedIds.length === 0 ? ( + {visibleRecommendedIds.length === 0 ? (
No default models.
) : ( - recommendedIds.map((id) => { + visibleRecommendedIds.map((id) => { const vram = recommendedVramMap.get(id); return (
@@ -651,6 +699,14 @@ export function HubModelPicker({ ); }) )} + {hasMoreRecommended && ( + <> +
+
+ +
+ + )} ) : null} From 7b07ad0fa30953b31987a9e6512ff3e210394f25 Mon Sep 17 00:00:00 2001 From: Wasim Yousef Said Date: Wed, 18 Mar 2026 11:47:13 +0100 Subject: [PATCH 25/42] fix(studio): UI fixes for chat and studio routes (#4419) Co-authored-by: Daniel Han --- .../assistant-ui/model-selector.tsx | 2 +- .../studio/sections/dataset-section.tsx | 4 +- .../studio/sections/model-section.tsx | 2 +- .../studio/sections/params-section.tsx | 83 +++++++++++++++---- .../features/studio/tour/steps/base-model.tsx | 2 +- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/studio/frontend/src/components/assistant-ui/model-selector.tsx b/studio/frontend/src/components/assistant-ui/model-selector.tsx index 2df72139d8..0332b3ca8a 100644 --- a/studio/frontend/src/components/assistant-ui/model-selector.tsx +++ b/studio/frontend/src/components/assistant-ui/model-selector.tsx @@ -151,7 +151,7 @@ function ModelSelectorContent({ +
+
+