Refactor LLM runtime handling and enhance CLI documentation
- Updated `resolve_llm_runtime` to prioritize live configuration over legacy notes, ensuring accurate runtime resolution. - Enhanced `tunnel_forwards` to prefer current configuration for LLM runtime, improving tunnel setup logic. - Improved idle-killer logic to handle stale markers and provide clearer warnings in the status output. - Updated CLI documentation in `cli.md` to reflect changes in command behavior and runtime handling. - Enhanced tests to validate new runtime resolution logic and ensure proper handling of configuration states.
This commit is contained in:
+44
-24
@@ -33,7 +33,7 @@ if sys.platform == "win32":
|
||||
pass
|
||||
|
||||
app = typer.Typer(
|
||||
invoke_without_command=True,
|
||||
no_args_is_help=True,
|
||||
pretty_exceptions_enable=False,
|
||||
add_completion=False,
|
||||
help="Прерываемый GPU Selectel + SwarmUI на localhost:17801. Сначала: gpu-rent setup / doctor. Ключи: docs/setup.md",
|
||||
@@ -43,16 +43,12 @@ console = Console(highlight=False, legacy_windows=False)
|
||||
_DEBUG = False
|
||||
|
||||
|
||||
@app.callback(invoke_without_command=True)
|
||||
@app.callback()
|
||||
def _root(
|
||||
ctx: typer.Context,
|
||||
debug: bool = typer.Option(False, "--debug", help="Показать traceback"),
|
||||
) -> None:
|
||||
global _DEBUG
|
||||
_DEBUG = debug
|
||||
if ctx.invoked_subcommand is None:
|
||||
# Без подкоманды → interactive up (как «запуск без параметров»).
|
||||
ctx.invoke(up)
|
||||
|
||||
|
||||
def _die(exc: BaseException) -> None:
|
||||
@@ -62,7 +58,24 @@ def _die(exc: BaseException) -> None:
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
def _print_checks(checks) -> int:
|
||||
def _print_checks(checks, *, quiet: bool = False) -> int:
|
||||
failed = blocking_failed(checks)
|
||||
if quiet:
|
||||
if failed:
|
||||
console.print("[red]doctor: блокирующие проблемы[/red]")
|
||||
for check in failed:
|
||||
console.print(f" • {check.name}: {check.detail}")
|
||||
_print_next_steps(failed)
|
||||
return 1
|
||||
warns = [c for c in checks if not c.ok and not c.blocking]
|
||||
if warns:
|
||||
console.print(f"[yellow]doctor ok[/yellow] ({len(checks)}), предупреждения:")
|
||||
for check in warns:
|
||||
console.print(f" • {check.name}: {check.detail}")
|
||||
else:
|
||||
console.print(f"[green]doctor ok[/green] ({len(checks)} проверок)")
|
||||
return 0
|
||||
|
||||
table = Table(title="gpu-rent doctor", show_lines=False)
|
||||
table.add_column("ok")
|
||||
table.add_column("проверка")
|
||||
@@ -73,7 +86,6 @@ def _print_checks(checks) -> int:
|
||||
block = "да" if check.blocking else "нет"
|
||||
table.add_row(mark, check.name, block, check.detail)
|
||||
console.print(table)
|
||||
failed = blocking_failed(checks)
|
||||
if failed:
|
||||
console.print("\n[red]Сессию начинать нельзя.[/red] См. docs/setup.md")
|
||||
_print_next_steps(failed)
|
||||
@@ -246,6 +258,12 @@ def status() -> None:
|
||||
from gpu_rent.idle_killer import killer_status_lines
|
||||
|
||||
table.add_row("idle-killer", "; ".join(killer_status_lines(cfg, state.floating_ip)))
|
||||
note_k = (state.notes or {}).get("idle_killer")
|
||||
if note_k == "failed":
|
||||
err = (state.notes or {}).get("idle_killer_error") or ""
|
||||
table.add_row("idle-killer arm", f"[red]FAILED[/red] {err}"[:120])
|
||||
elif note_k == "armed":
|
||||
table.add_row("idle-killer arm", "ok (в сессии)")
|
||||
except GpuRentError as exc:
|
||||
table.add_row("диск used/free", f"SSH: {exc}")
|
||||
table.add_row("idle-killer", "нет SSH")
|
||||
@@ -256,16 +274,17 @@ def status() -> None:
|
||||
from gpu_rent.local_watchdog import watchdog_status_lines
|
||||
|
||||
table.add_row("local-watchdog", "; ".join(watchdog_status_lines()))
|
||||
from gpu_rent.llm_runtime import normalize_runtime
|
||||
from gpu_rent.access_card import resolve_llm_runtime
|
||||
|
||||
rt = normalize_runtime(cfg.llm_runtime)
|
||||
rt = resolve_llm_runtime(cfg)
|
||||
noted = (state.notes or {}).get("llm_runtime")
|
||||
if noted:
|
||||
rt = f"{rt} (сессия: {noted})"
|
||||
table.add_row(
|
||||
"LLM",
|
||||
f"{rt}; ollama :{cfg.ollama_local_port} / llamacpp :{cfg.llamacpp_local_port}",
|
||||
)
|
||||
llm_err = (state.notes or {}).get("llm_error")
|
||||
detail = f"{rt}; ollama :{cfg.ollama_local_port} / llamacpp :{cfg.llamacpp_local_port}"
|
||||
if noted and noted != rt:
|
||||
detail += f" (notes: {noted})"
|
||||
if llm_err:
|
||||
detail += f" [red]err: {llm_err[:80]}[/red]"
|
||||
table.add_row("LLM", detail)
|
||||
|
||||
if cfg.auth_ok:
|
||||
try:
|
||||
@@ -296,14 +315,9 @@ def open(
|
||||
cfg = load_config(require_auth=False)
|
||||
if llm:
|
||||
from gpu_rent.llm_runtime import normalize_runtime
|
||||
from gpu_rent.access_card import resolve_llm_runtime
|
||||
|
||||
runtime = normalize_runtime(cfg.llm_runtime)
|
||||
state = load_state()
|
||||
if (state.notes or {}).get("llm_runtime"):
|
||||
try:
|
||||
runtime = normalize_runtime(str(state.notes["llm_runtime"]))
|
||||
except ValueError:
|
||||
pass
|
||||
runtime = resolve_llm_runtime(cfg)
|
||||
if runtime == "ollama":
|
||||
port = cfg.ollama_local_port
|
||||
elif runtime == "llamacpp":
|
||||
@@ -381,6 +395,12 @@ def up(
|
||||
"--no-update",
|
||||
help="Не делать git pull SwarmUI и установленных extensions",
|
||||
),
|
||||
verbose: bool = typer.Option(
|
||||
False,
|
||||
"--verbose",
|
||||
"-v",
|
||||
help="Полный doctor-таблица на up (по умолчанию кратко)",
|
||||
),
|
||||
llm: Optional[str] = typer.Option(
|
||||
None, "--llm", help="none|ollama|llamacpp (override LLM_RUNTIME)"
|
||||
),
|
||||
@@ -401,7 +421,7 @@ def up(
|
||||
from gpu_rent.paths import vars_path
|
||||
|
||||
checks = run_doctor()
|
||||
code = _print_checks(checks)
|
||||
code = _print_checks(checks, quiet=not verbose)
|
||||
if code != 0:
|
||||
raise typer.Exit(1)
|
||||
cfg = load_config(require_auth=True)
|
||||
|
||||
Reference in New Issue
Block a user