diff --git a/unsloth_cli/commands/start.py b/unsloth_cli/commands/start.py index fce4eaf8b5..7c991289f3 100644 --- a/unsloth_cli/commands/start.py +++ b/unsloth_cli/commands/start.py @@ -327,6 +327,13 @@ def _split_repo_variant(model: str) -> tuple: return repo, variant +def _display_model_spec(model: str, variant: Optional[str]) -> str: + """Return a user-facing model name that includes the selected GGUF variant.""" + repo, inline_variant = _split_repo_variant(model) + selected_variant = variant or inline_variant + return f"{repo}:{selected_variant}" if selected_variant else model + + def _fail(message: str) -> NoReturn: typer.echo(message, err = True) raise typer.Exit(code = 1) @@ -739,7 +746,8 @@ def _start_studio_server(base: str, model: str, load: LoadOptions) -> subprocess command += ["--tensor-parallel"] log_path = Path(tempfile.gettempdir()) / f"unsloth-start-server-{os.getpid()}.log" - typer.echo(f"Starting Unsloth server for {model}…") + typer.echo("Starting Unsloth server") + typer.echo(f"Model: {_display_model_spec(model, load.gguf_variant)}") typer.echo(f"Server log: {log_path}") # 0600: the `unsloth run` banner in this log carries the minted sk-unsloth- key, and # the tempdir is world-traversable. Unlink first so a stale looser-mode file (pid @@ -795,7 +803,6 @@ def _start_studio_server(base: str, model: str, load: LoadOptions) -> subprocess progress.complete() progress.close() progress = None - typer.echo(f"Unsloth server ready at {base}.") return server time.sleep(2.0) finally: @@ -1135,11 +1142,7 @@ def _resolve_model( f"Switching the Unsloth server from {active_id} to {requested}. " "This unloads the current model for every attached session." ) - typer.echo( - f"Loading {requested} - please wait…" - if load_has_overrides - else f"Loading {requested} on the Unsloth server (this can take a while)…" - ) + typer.echo(f"Loading model: {_display_model_spec(requested, load.gguf_variant)}") # Mirror `unsloth run`'s load knobs; keep the default payload as just # model_path so a bare `--model` load is unchanged. payload = {"model_path": requested} @@ -1748,10 +1751,8 @@ def _run( env, wsl_env_bridge = _wsl_shim_env(command, env, unset_env) _print_env(env, command, unset_env = unset_env, wsl_env_bridge = wsl_env_bridge) if _keep_auto_served(): - typer.echo( - f"Unsloth Studio is still running at {base}. " - "Stop it with `unsloth studio stop`." - ) + typer.echo(f"Unsloth Studio is still running at {base}.") + typer.echo("Stop it with: unsloth studio stop") return try: code = _launch(command, env, install_hint = install_hint, unset_env = unset_env) @@ -1766,10 +1767,8 @@ def _run( typer.echo(f"The auto-started Unsloth server at {base} stopped during the session.") raise typer.Exit(code = code) if is_loopback_url(base): - typer.echo( - f"Unsloth Studio is still running at {base}. " - "Stop it with `unsloth studio stop`." - ) + typer.echo(f"Unsloth Studio is still running at {base}.") + typer.echo("Stop it with: unsloth studio stop") else: typer.echo(f"The remote Unsloth server is still running at {base}.") raise typer.Exit(code = code) diff --git a/unsloth_cli/tests/test_start.py b/unsloth_cli/tests/test_start.py index 3e13f960b2..4b97bda3e9 100644 --- a/unsloth_cli/tests/test_start.py +++ b/unsloth_cli/tests/test_start.py @@ -825,7 +825,7 @@ def test_connect_codex_matches_requested_model_case_insensitively(fake_studio, t assert profile["model"] == MODEL["id"] -def test_resolve_model_matches_loaded_canonical_case_after_load(monkeypatch): +def test_resolve_model_matches_loaded_canonical_case_after_load(monkeypatch, capsys): calls = [] state = {"loaded": False} @@ -863,6 +863,9 @@ def test_resolve_model_matches_loaded_canonical_case_after_load(monkeypatch): assert entry["id"] == "unsloth/gemma-4-E2B-it-GGUF" assert any(c[1].endswith("/api/inference/load") for c in calls) + output = capsys.readouterr().out + assert "Loading model: unsloth/gemma-4-e2b-it-gguf:UD-Q4_K_XL\n" in output + assert "please wait" not in output def test_resolve_model_loads_when_catalog_hit_is_not_loaded(monkeypatch): @@ -1792,8 +1795,10 @@ def test_start_studio_server_builds_command_and_waits(monkeypatch, capsys): assert captured["kwargs"].get("start_new_session") is True # own process group assert server.pid == 4321 output = capsys.readouterr().out - assert "Starting Unsloth server for unsloth/Qwen3-1.7B-GGUF:UD-Q4_K_XL…" in output + assert "Starting Unsloth server\n" in output + assert "Model: unsloth/Qwen3-1.7B-GGUF:UD-Q4_K_XL\n" in output assert "No Unsloth server at" not in output + assert "server ready" not in output def test_start_studio_server_polls_progress_from_early_key(monkeypatch): @@ -1850,9 +1855,10 @@ def test_start_studio_server_polls_progress_from_early_key(monkeypatch): "created", ) in created assert created.count("poll") == 2 - ready = ("echo", f"Unsloth server ready at {BASE}.") - assert created[-3:] == ["complete", "close", ready] - assert created.index("close") < created.index(ready) + assert created[-2:] == ["complete", "close"] + assert not any( + isinstance(event, tuple) and "server ready" in event[-1] for event in created + ) def test_load_model_with_progress_uses_selected_gguf_size(monkeypatch, capsys): @@ -2014,7 +2020,7 @@ def test_attached_server_prints_stop_hint_after_agent_exits(fake_studio, monkeyp assert result.exit_code == 0, result.output assert f"Unsloth Studio is still running at {BASE}." in result.output - assert "unsloth studio stop" in result.output + assert "Stop it with: unsloth studio stop\n" in result.output def test_no_launch_recipe_does_not_print_stop_hint(fake_studio):