* Studio: add `unsloth chat` CLI command Interactive chat REPL on the shared Studio backend: trained-model picker when no model is given, /think and /compare toggles (adapter toggle on CUDA, side-by-side base-model load on MLX), markdown streaming, and connect-if-running Studio server mode so models stay warm across sessions and are shared with the UI. * fix settings * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix error handling and compare base precision * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix chat CLI backend imports and GGUF drafter loading * Hide split thinking tags in chat CLI streams --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Lee Jackson <130007945+Imagineer99@users.noreply.github.com> Co-authored-by: imagineer99 <samleejackson0@gmail.com>
90 lines
2.7 KiB
Python
90 lines
2.7 KiB
Python
# 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 os as _os
|
|
import sys as _sys
|
|
|
|
import typer
|
|
from importlib.metadata import version as package_version, PackageNotFoundError
|
|
|
|
|
|
from unsloth_cli.commands.train import train
|
|
from unsloth_cli.commands.inference import inference
|
|
from unsloth_cli.commands.chat import chat
|
|
from unsloth_cli.commands.export import export, list_checkpoints
|
|
from unsloth_cli.commands.studio import (
|
|
run as studio_run,
|
|
studio_app,
|
|
_expand_attached_np_short,
|
|
)
|
|
|
|
|
|
# Canonicalise `-np<N>` only under the `unsloth` console-script;
|
|
# third-party scripts that import unsloth_cli keep their argv intact.
|
|
_entry_base = _os.path.basename(_sys.argv[0]).lower() if _sys.argv else ""
|
|
if _entry_base in {"unsloth", "unsloth.exe"}:
|
|
_expand_attached_np_short()
|
|
del _entry_base
|
|
|
|
|
|
def show_version(value: bool):
|
|
if value:
|
|
try:
|
|
version = package_version("unsloth")
|
|
except PackageNotFoundError:
|
|
version = "unknown"
|
|
typer.echo(f"unsloth {version}")
|
|
raise typer.Exit()
|
|
|
|
|
|
app = typer.Typer(
|
|
help = "Command-line interface for Unsloth training, inference, and export.",
|
|
context_settings = {"help_option_names": ["-h", "--help"]},
|
|
)
|
|
|
|
|
|
@app.callback()
|
|
def main(
|
|
version: bool = typer.Option(
|
|
None,
|
|
"--version",
|
|
"-V",
|
|
callback = show_version,
|
|
is_eager = True,
|
|
help = "Show version and exit.",
|
|
),
|
|
):
|
|
if (
|
|
_sys.platform == "win32"
|
|
): # this block catches unsloth running inside of System32 or any subdirs, this WILL cause errors if not prevented.
|
|
_cwd = _os.path.normcase(_os.path.normpath(_os.getcwd()))
|
|
_system32 = _os.path.normcase(
|
|
_os.path.normpath(_os.path.join(_os.environ.get("WINDIR", r"C:\Windows"), "System32"))
|
|
)
|
|
if _cwd == _system32 or _cwd.startswith(_system32 + _os.sep):
|
|
typer.secho(
|
|
"Refusing to run Unsloth inside System32 as it will lead to Errors.\n"
|
|
"cd to a normal working directory and try again.",
|
|
fg = "red",
|
|
err = True,
|
|
)
|
|
raise typer.Exit(code = 1)
|
|
|
|
|
|
app.command()(train)
|
|
app.command()(inference)
|
|
app.command()(chat)
|
|
app.command()(export)
|
|
app.command("list-checkpoints")(list_checkpoints)
|
|
app.add_typer(studio_app, name = "studio", help = "Unsloth Studio commands.")
|
|
|
|
# Top-level `unsloth run` aliases `unsloth studio run`; same context
|
|
# so unknown flags still pass through to llama-server.
|
|
app.command(
|
|
"run",
|
|
context_settings = {
|
|
"allow_extra_args": True,
|
|
"ignore_unknown_options": True,
|
|
},
|
|
help = "Alias for `unsloth studio run`.",
|
|
)(studio_run)
|