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:
Leonid Pershin
2026-08-21 05:40:22 +03:00
parent 82e36129cd
commit dc1fde9e3e
17 changed files with 464 additions and 152 deletions
+19 -10
View File
@@ -5,6 +5,7 @@ from __future__ import annotations
import json
import subprocess
import sys
import time
from pathlib import Path
JOBS = Path("/tmp/gpu-rent-ollama-models.json")
@@ -12,6 +13,7 @@ MARKER = Path("/mnt/swarm_data/.gpu-rent-ollama-pulling")
def listed() -> set[str]:
"""Exact tags from `ollama list` (NAME column), e.g. qwen2.5:7b."""
try:
out = subprocess.check_output(["ollama", "list"], text=True, stderr=subprocess.DEVNULL)
except (subprocess.CalledProcessError, FileNotFoundError):
@@ -23,11 +25,21 @@ def listed() -> set[str]:
parts = line.split()
if parts:
names.add(parts[0])
# also bare name without tag
names.add(parts[0].split(":")[0])
return names
def already_have(have: set[str], wanted: str) -> bool:
"""Exact tag match only — qwen2.5:3b must not satisfy qwen2.5:7b."""
if wanted in have:
return True
# ollama list sometimes omits :latest
if ":" not in wanted and f"{wanted}:latest" in have:
return True
if wanted.endswith(":latest") and wanted.rsplit(":", 1)[0] in have:
return True
return False
def main() -> int:
if not JOBS.is_file():
print("no jobs file", file=sys.stderr)
@@ -38,23 +50,20 @@ def main() -> int:
return 0
have = listed()
MARKER.parent.mkdir(parents=True, exist_ok=True)
MARKER.write_text("1\n", encoding="utf-8")
MARKER.write_text(f"{int(time.time())}\n", encoding="utf-8")
failed = 0
try:
for i, name in enumerate(models, 1):
name = str(name).strip()
if not name:
continue
bare = name.split(":")[0]
if name in have or bare in have:
# Prefer exact tag match when possible
exact = any(h == name or h.startswith(name + ":") or name.startswith(h) for h in have)
if name in have or exact:
print(f"[{i}/{len(models)}] уже есть {name}")
continue
if already_have(have, name):
print(f"[{i}/{len(models)}] уже есть {name}")
continue
print(f"[{i}/{len(models)}] ollama pull {name}")
try:
subprocess.check_call(["ollama", "pull", name])
have.add(name)
except subprocess.CalledProcessError as exc:
failed += 1
print(f"FAIL pull {name}: {exc}", file=sys.stderr)