Add capture wanted and harden Assistent wanted-queue merge.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-21 21:29:00 +03:00
co-authored by Cursor
parent 08120194f9
commit 6c45a7560e
4 changed files with 78 additions and 8 deletions
+59 -7
View File
@@ -3,6 +3,7 @@
from __future__ import annotations
import json
import re
import shutil
from collections.abc import Callable
from dataclasses import dataclass, field
@@ -420,14 +421,15 @@ def merge_wanted_models_from_vm(cfg: Config, host: str, log: Log) -> int:
).strip()
if not raw:
return 0
try:
data = yaml.safe_load(raw) or {}
except Exception as exc:
log(f"wanted-models: bad yaml — {exc}")
return 0
if not isinstance(data, dict):
return 0
items: list[ModelCaptureItem] = []
data: dict = {}
try:
parsed = yaml.safe_load(raw) or {}
if isinstance(parsed, dict):
data = parsed
except Exception as exc:
log(f"wanted-models: yaml parse — {exc}; fallback line scan")
for kind, rows in data.items():
if kind not in MODEL_DIRS or not isinstance(rows, list):
continue
@@ -451,6 +453,56 @@ def merge_wanted_models_from_vm(cfg: Config, host: str, log: Log) -> int:
source="wanted",
)
)
# Recover entries lost to duplicate YAML keys (old Assistent writers appended
# a fresh `lora:` block each time; PyYAML keeps only the last).
kind = "lora"
pending_url = None
pending_title = None
pending_vid = None
seen_urls = {i.url for i in items}
def flush_pending() -> None:
nonlocal pending_url, pending_title, pending_vid
if not pending_url or pending_url in seen_urls:
pending_url = pending_title = pending_vid = None
return
vid_i = pending_vid or extract_version_id(pending_url)
items.append(
ModelCaptureItem(
kind=kind if kind in MODEL_DIRS else "lora",
url=pending_url,
title=str(pending_title or Path(pending_url).name),
version_id=vid_i,
source="wanted",
)
)
seen_urls.add(pending_url)
pending_url = pending_title = pending_vid = None
for line in raw.splitlines():
t = line.strip()
m_kind = re.match(r"^([A-Za-z0-9_-]+):\s*$", t)
if m_kind and not t.startswith("-"):
flush_pending()
kind = m_kind.group(1).strip().lower()
continue
m_url = re.match(r"^-\s*url:\s*[\"']?(.+?)[\"']?\s*$", t)
if m_url:
flush_pending()
pending_url = m_url.group(1).strip()
continue
if not pending_url:
continue
m_title = re.match(r"^title:\s*[\"']?(.+?)[\"']?\s*$", t)
if m_title:
pending_title = m_title.group(1).strip()
continue
m_vid = re.match(r"^version_id:\s*(\d+)\s*$", t)
if m_vid:
pending_vid = int(m_vid.group(1))
flush_pending()
if not items:
return 0
added, skipped = merge_models_yaml(Path(cfg.models_manifest), items, dry_run=False)
+16
View File
@@ -986,6 +986,22 @@ def capture_models_cmd(
_die(exc)
@capture_app.command("wanted")
def capture_wanted_cmd() -> None:
"""Только очередь Assistent (.gpu-rent-wanted-models.yaml) → models.yaml."""
try:
from gpu_rent.capture import merge_wanted_models_from_vm
cfg, host = _live()
n = merge_wanted_models_from_vm(cfg, host, log)
if n:
log(f"wanted→models.yaml: +{n}")
else:
log("wanted→models.yaml: пусто или уже есть")
except GpuRentError as exc:
_die(exc)
@capture_app.command("extensions")
def capture_extensions_cmd(
dry_run: bool = typer.Option(False, "--dry-run"),