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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user