Support Assistent persona packs via git and local sync.
Replace assistent-personas overlay seed with assistent-extensions SFTP and an assistent: section in extensions.yaml so personalities install like other extensions without private URLs in the public repo. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Unit tests for assistent personas overlay seed helpers."""
|
||||
"""Unit tests for assistent persona-pack seed helpers."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -6,35 +6,29 @@ import json
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from gpu_rent.provision import _safe_persona_id, count_wanted_models_on_vm, seed_assistent_personas
|
||||
from gpu_rent.provision import _safe_persona_id, seed_assistent_personas
|
||||
|
||||
|
||||
def test_safe_persona_id():
|
||||
assert _safe_persona_id("neutral") == "neutral"
|
||||
assert _safe_persona_id("lewd_v2") == "lewd_v2"
|
||||
assert _safe_persona_id("dreamer_v2") == "dreamer_v2"
|
||||
assert _safe_persona_id("../x") is None
|
||||
assert _safe_persona_id("a/b") is None
|
||||
assert _safe_persona_id("") is None
|
||||
|
||||
|
||||
def test_seed_assistent_personas_writes_overlay(tmp_path: Path, monkeypatch):
|
||||
root = tmp_path / "assistent-personas"
|
||||
(root / "_base").mkdir(parents=True)
|
||||
(root / "personas" / "cinema").mkdir(parents=True)
|
||||
(root / "_base" / "assistant.json").write_text(
|
||||
json.dumps({"default_persona": "cinema"}), encoding="utf-8"
|
||||
)
|
||||
(root / "personas" / "cinema" / "persona.json").write_text(
|
||||
json.dumps({"title": "Кино", "accent": "#7aa2f7"}), encoding="utf-8"
|
||||
)
|
||||
(root / "personas" / "cinema" / "bio.json").write_text(
|
||||
json.dumps({"role": "DP"}), encoding="utf-8"
|
||||
)
|
||||
(root / "personas" / "cinema" / "humor.json").write_text(
|
||||
json.dumps({"frequency": "rare"}), encoding="utf-8"
|
||||
def test_seed_assistent_personas_pushes_packs(tmp_path: Path, monkeypatch):
|
||||
root = tmp_path / "assistent-extensions"
|
||||
pack = root / "sample-pack"
|
||||
pack.mkdir(parents=True)
|
||||
(pack / "assistent-pack.yaml").write_text("kind: persona\nid: sample\n", encoding="utf-8")
|
||||
(pack / "persona.json").write_text(
|
||||
json.dumps({"title": "Sample", "accent": "#7aa2f7"}), encoding="utf-8"
|
||||
)
|
||||
(pack / "voice.json").write_text(json.dumps({"tone": ["calm"]}), encoding="utf-8")
|
||||
|
||||
puts: dict[str, str] = {}
|
||||
pushed: list[tuple[str, str]] = []
|
||||
ssh_cmds: list[str] = []
|
||||
|
||||
def fake_put(cfg, host, remote, text, mode=0o644):
|
||||
@@ -46,76 +40,72 @@ def test_seed_assistent_personas_writes_overlay(tmp_path: Path, monkeypatch):
|
||||
return json.dumps({"vram_mib": 24576, "name": "4090", "compute_cap": "8.9"})
|
||||
return ""
|
||||
|
||||
def fake_push(cfg, host, local_root, remote_root, log, *, models):
|
||||
pushed.append((str(local_root), remote_root))
|
||||
log(f"push {Path(local_root).name}")
|
||||
return 2
|
||||
|
||||
monkeypatch.setattr("gpu_rent.provision.put_text", fake_put)
|
||||
monkeypatch.setattr("gpu_rent.provision.run_ssh", fake_ssh)
|
||||
monkeypatch.setattr("gpu_rent.paths.assistent_personas_dir", lambda: root)
|
||||
monkeypatch.setattr("gpu_rent.sync_files.push_tree", fake_push)
|
||||
monkeypatch.setattr("gpu_rent.paths.assistent_extensions_dir", lambda: root)
|
||||
monkeypatch.setattr(
|
||||
"gpu_rent.paths.assistent_personas_example_dir", lambda: tmp_path / "missing"
|
||||
"gpu_rent.paths.assistent_personas_dir", lambda: tmp_path / "no-personas"
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"gpu_rent.paths.assistent_personas_manifest_path", lambda: tmp_path / "no.yaml"
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"gpu_rent.provision.seed_civitai_examples", lambda *a, **k: None
|
||||
)
|
||||
|
||||
cfg = MagicMock()
|
||||
cfg.assistent_personas_dir = str(root)
|
||||
cfg.assistent_extensions_dir = str(root)
|
||||
logs: list[str] = []
|
||||
seed_assistent_personas(cfg, "1.2.3.4", logs.append)
|
||||
|
||||
assert any(p.endswith("personas/cinema/persona.json") for p in puts)
|
||||
assert any(p.endswith("personas/cinema/bio.json") for p in puts)
|
||||
assert any(p.endswith("personas/cinema/humor.json") for p in puts)
|
||||
assert not any(p.endswith("extra.md") for p in puts)
|
||||
assert len(pushed) == 1
|
||||
assert pushed[0][1].endswith("/Assistent/extensions/sample-pack")
|
||||
assert "/mnt/swarm_data/Assistent/_base/assistant.json" in puts
|
||||
asst = json.loads(puts["/mnt/swarm_data/Assistent/_base/assistant.json"])
|
||||
assert asst["default_persona"] == "cinema"
|
||||
assert asst["default_persona"] == "neutral"
|
||||
assert asst["num_ctx"] == 16384
|
||||
assert any("rm -f" in c and "personas.json" in c for c in ssh_cmds)
|
||||
assert any("overlay personas/1" in m for m in logs)
|
||||
assert any("packs/1" in m for m in logs)
|
||||
|
||||
|
||||
def test_seed_skips_exact_if_remote_exists(tmp_path: Path, monkeypatch):
|
||||
root = tmp_path / "assistent-personas"
|
||||
(root / "personas" / "leonid").mkdir(parents=True)
|
||||
(root / "personas" / "leonid" / "persona.json").write_text(
|
||||
'{"title":"L"}', encoding="utf-8"
|
||||
)
|
||||
(root / "personas" / "leonid" / "exact.json").write_text(
|
||||
'{"controls":{"preference_bias":0.9}}', encoding="utf-8"
|
||||
)
|
||||
puts: dict[str, str] = {}
|
||||
def test_seed_skips_empty_pack_dir(tmp_path: Path, monkeypatch):
|
||||
root = tmp_path / "assistent-extensions"
|
||||
(root / "empty").mkdir(parents=True)
|
||||
|
||||
def fake_put(cfg, host, remote, text, mode=0o644):
|
||||
puts[remote] = text
|
||||
pushed: list[str] = []
|
||||
|
||||
def fake_ssh(cfg, host, cmd, check=False, timeout=60):
|
||||
if "exact.json" in cmd and "test -f" in cmd:
|
||||
return "yes"
|
||||
if ".gpu-rent-gpu.json" in cmd:
|
||||
return "{}"
|
||||
return ""
|
||||
def fake_push(cfg, host, local_root, remote_root, log, *, models):
|
||||
pushed.append(remote_root)
|
||||
return 0
|
||||
|
||||
monkeypatch.setattr("gpu_rent.provision.put_text", fake_put)
|
||||
monkeypatch.setattr("gpu_rent.provision.run_ssh", fake_ssh)
|
||||
monkeypatch.setattr("gpu_rent.paths.assistent_personas_dir", lambda: root)
|
||||
monkeypatch.setattr("gpu_rent.provision.put_text", lambda *a, **k: None)
|
||||
monkeypatch.setattr(
|
||||
"gpu_rent.paths.assistent_personas_example_dir", lambda: tmp_path / "missing"
|
||||
"gpu_rent.provision.run_ssh",
|
||||
lambda *a, **k: json.dumps({"vram_mib": 24576}) if ".gpu-rent-gpu" in str(a) else "",
|
||||
)
|
||||
monkeypatch.setattr("gpu_rent.sync_files.push_tree", fake_push)
|
||||
monkeypatch.setattr("gpu_rent.paths.assistent_extensions_dir", lambda: root)
|
||||
monkeypatch.setattr(
|
||||
"gpu_rent.paths.assistent_personas_dir", lambda: tmp_path / "no-personas"
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"gpu_rent.paths.assistent_personas_manifest_path", lambda: tmp_path / "no.yaml"
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"gpu_rent.provision.seed_civitai_examples", lambda *a, **k: None
|
||||
)
|
||||
|
||||
cfg = MagicMock()
|
||||
cfg.assistent_personas_dir = str(root)
|
||||
seed_assistent_personas(cfg, "h", lambda *_: None)
|
||||
assert not any(p.endswith("exact.json") for p in puts)
|
||||
assert any(p.endswith("persona.json") for p in puts)
|
||||
cfg.assistent_extensions_dir = str(root)
|
||||
logs: list[str] = []
|
||||
seed_assistent_personas(cfg, "1.2.3.4", logs.append)
|
||||
|
||||
|
||||
def test_count_wanted_models(monkeypatch):
|
||||
raw = "lora:\n - url: https://civitai.red/x?modelVersionId=1\n title: A\n"
|
||||
|
||||
monkeypatch.setattr(
|
||||
"gpu_rent.provision.run_ssh",
|
||||
lambda *a, **k: raw,
|
||||
)
|
||||
assert count_wanted_models_on_vm(MagicMock(), "h") == 1
|
||||
assert pushed == []
|
||||
assert any("нет assistent-pack.yaml" in m for m in logs)
|
||||
assert any("packs/0" in m for m in logs)
|
||||
|
||||
@@ -221,7 +221,7 @@ def test_chat_eval_mocked_http(monkeypatch, tmp_path):
|
||||
if url.endswith("/API/AssistentGetConfig"):
|
||||
return True, {
|
||||
"success": True,
|
||||
"persona": "leonid",
|
||||
"persona": "neutral",
|
||||
"exact": {
|
||||
"profiles": {"turbo": {"steps": 8, "cfg": 1, "sigma_shift": 1.15}}
|
||||
},
|
||||
@@ -245,14 +245,14 @@ def test_chat_eval_mocked_http(monkeypatch, tmp_path):
|
||||
out = debug_assistent.run_assistent_chat_eval(
|
||||
cfg,
|
||||
message="какой checkpoint?",
|
||||
persona="leonid",
|
||||
persona="neutral",
|
||||
timeout=60,
|
||||
)
|
||||
assert out["ok"] is True
|
||||
assert out["via"] == "local"
|
||||
assert out["model"] == "qwen3-vl:8b"
|
||||
assert out["preferred"] == "qwen3-vl:8b"
|
||||
assert out["persona"] == "leonid"
|
||||
assert out["persona"] == "neutral"
|
||||
assert out["patch"]["steps"] == 4
|
||||
assert out["patch"]["cfg"] == 1
|
||||
assert out["patch"]["aspect"] == "3:4"
|
||||
@@ -317,7 +317,7 @@ def test_assistent_compact_and_roles_local(monkeypatch, tmp_path):
|
||||
],
|
||||
"overlay": {
|
||||
"exists": True,
|
||||
"persona_ids": ["leonid"],
|
||||
"persona_ids": ["neutral"],
|
||||
"roles_present": True,
|
||||
"roles": {
|
||||
"chat": ["qwen3-vl:8b"],
|
||||
|
||||
+27
-1
@@ -3,7 +3,12 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from gpu_rent.errors import ConfigError
|
||||
from gpu_rent.manifests import parse_extensions, parse_models, repo_matches_runtime
|
||||
from gpu_rent.manifests import (
|
||||
parse_extensions,
|
||||
parse_models,
|
||||
remote_root_for,
|
||||
repo_matches_runtime,
|
||||
)
|
||||
|
||||
|
||||
def test_models_skips_version_zero(tmp_path: Path):
|
||||
@@ -77,3 +82,24 @@ def test_extensions_requires_invalid(tmp_path: Path):
|
||||
)
|
||||
with pytest.raises(ConfigError, match="requires"):
|
||||
parse_extensions(path)
|
||||
|
||||
|
||||
def test_extensions_assistent_kind(tmp_path: Path):
|
||||
path = tmp_path / "extensions.yaml"
|
||||
path.write_text(
|
||||
"assistent:\n"
|
||||
" - url: https://example.com/org/sample-pack.git\n"
|
||||
" ref: main\n"
|
||||
" dir: sample-pack\n"
|
||||
" requires: ollama\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
repos = parse_extensions(path)
|
||||
assert len(repos) == 1
|
||||
assert repos[0].kind == "assistent"
|
||||
assert repos[0].directory == "sample-pack"
|
||||
assert remote_root_for(repos[0]) == (
|
||||
"/mnt/swarm_data/Assistent/extensions/sample-pack"
|
||||
)
|
||||
assert repo_matches_runtime(repos[0], "ollama")
|
||||
assert not repo_matches_runtime(repos[0], "none")
|
||||
|
||||
Reference in New Issue
Block a user