Fix meshnet-node model and shard flag parsing.
Unify --model and --model-id so catalog names use the tracker path, and allow --shard-start/--shard-end with --model instead of requiring --model-id. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -388,6 +388,107 @@ def test_legacy_start_treats_repo_model_as_model_id(monkeypatch):
|
||||
assert captured["model_id"] == "Qwen/Qwen2.5-0.5B-Instruct"
|
||||
|
||||
|
||||
def test_legacy_start_catalog_model_with_pinned_shards(monkeypatch):
|
||||
"""Catalog model names accept --shard-start/--shard-end without --model-id."""
|
||||
from meshnet_node.cli import main
|
||||
|
||||
captured = {}
|
||||
|
||||
def fake_run_startup(*args, **kwargs):
|
||||
captured.update(kwargs)
|
||||
class _FakeNode:
|
||||
chat_completion_count = 0
|
||||
def stop(self): pass
|
||||
return _FakeNode()
|
||||
|
||||
monkeypatch.setattr(sys, "argv", [
|
||||
"meshnet-node", "start",
|
||||
"--tracker", "http://192.168.0.179:8080",
|
||||
"--model", "Qwen3.6-35B-A3B",
|
||||
"--shard-start", "0",
|
||||
"--shard-end", "44",
|
||||
"--port", "0",
|
||||
])
|
||||
|
||||
with patch("meshnet_node.startup.run_startup", side_effect=fake_run_startup):
|
||||
with patch("time.sleep", side_effect=KeyboardInterrupt):
|
||||
try:
|
||||
main()
|
||||
except SystemExit as exc:
|
||||
assert exc.code == 0
|
||||
|
||||
assert captured["model"] == "Qwen3.6-35B-A3B"
|
||||
assert captured["model_id"] is None
|
||||
assert captured["shard_start"] == 0
|
||||
assert captured["shard_end"] == 44
|
||||
|
||||
|
||||
def test_legacy_start_model_id_alias_for_catalog_name(monkeypatch):
|
||||
"""--model-id with a catalog name routes through the tracker preset path."""
|
||||
from meshnet_node.cli import main
|
||||
|
||||
captured = {}
|
||||
|
||||
def fake_run_startup(*args, **kwargs):
|
||||
captured.update(kwargs)
|
||||
class _FakeNode:
|
||||
chat_completion_count = 0
|
||||
def stop(self): pass
|
||||
return _FakeNode()
|
||||
|
||||
monkeypatch.setattr(sys, "argv", [
|
||||
"meshnet-node", "start",
|
||||
"--tracker", "http://192.168.0.179:8080",
|
||||
"--model-id", "Qwen3.6-35B-A3B",
|
||||
"--port", "0",
|
||||
])
|
||||
|
||||
with patch("meshnet_node.startup.run_startup", side_effect=fake_run_startup):
|
||||
with patch("time.sleep", side_effect=KeyboardInterrupt):
|
||||
try:
|
||||
main()
|
||||
except SystemExit as exc:
|
||||
assert exc.code == 0
|
||||
|
||||
assert captured["model"] == "Qwen3.6-35B-A3B"
|
||||
assert captured["model_id"] is None
|
||||
|
||||
|
||||
def test_legacy_start_hf_repo_with_pinned_shards(monkeypatch):
|
||||
"""HF repo --model with pinned shards still enters the torch startup path."""
|
||||
from meshnet_node.cli import main
|
||||
|
||||
captured = {}
|
||||
|
||||
def fake_run_startup(*args, **kwargs):
|
||||
captured.update(kwargs)
|
||||
class _FakeNode:
|
||||
chat_completion_count = 0
|
||||
def stop(self): pass
|
||||
return _FakeNode()
|
||||
|
||||
monkeypatch.setattr(sys, "argv", [
|
||||
"meshnet-node", "start",
|
||||
"--tracker", "http://192.168.0.179:8081",
|
||||
"--model", "Qwen/Qwen2.5-0.5B-Instruct",
|
||||
"--shard-start", "12",
|
||||
"--shard-end", "23",
|
||||
"--port", "0",
|
||||
])
|
||||
|
||||
with patch("meshnet_node.startup.run_startup", side_effect=fake_run_startup):
|
||||
with patch("time.sleep", side_effect=KeyboardInterrupt):
|
||||
try:
|
||||
main()
|
||||
except SystemExit as exc:
|
||||
assert exc.code == 0
|
||||
|
||||
assert captured["model"] == "Qwen2.5-0.5B-Instruct"
|
||||
assert captured["model_id"] == "Qwen/Qwen2.5-0.5B-Instruct"
|
||||
assert captured["shard_start"] == 12
|
||||
assert captured["shard_end"] == 23
|
||||
|
||||
|
||||
def test_legacy_start_falls_back_to_env_tracker_and_model(monkeypatch):
|
||||
"""`meshnet-node start` uses env defaults when tracker/model flags are omitted."""
|
||||
import importlib
|
||||
|
||||
@@ -1603,6 +1603,47 @@ def test_preset_model_startup_starts_heartbeat(tmp_path, monkeypatch):
|
||||
tracker.stop()
|
||||
|
||||
|
||||
def test_preset_model_startup_honors_pinned_shard_range(tmp_path, monkeypatch):
|
||||
"""Explicit --shard-start/--shard-end override tracker auto-assignment."""
|
||||
import meshnet_node.startup as startup_mod
|
||||
|
||||
monkeypatch.setattr(
|
||||
startup_mod,
|
||||
"detect_hardware",
|
||||
lambda: {"device": "cpu", "gpu_name": None, "vram_mb": 0, "ram_mb": 16 * 1024},
|
||||
)
|
||||
heartbeat_calls = []
|
||||
monkeypatch.setattr(
|
||||
startup_mod,
|
||||
"_start_heartbeat",
|
||||
lambda *args, **kwargs: heartbeat_calls.append((args, kwargs)),
|
||||
)
|
||||
|
||||
tracker = TrackerServer(model_presets={"stub-model": {"layers_start": 0, "layers_end": 15}})
|
||||
tracker_port = tracker.start()
|
||||
tracker_url = f"http://127.0.0.1:{tracker_port}"
|
||||
try:
|
||||
node = run_startup(
|
||||
tracker_url=tracker_url,
|
||||
model="stub-model",
|
||||
shard_start=0,
|
||||
shard_end=5,
|
||||
wallet_path=tmp_path / "wallet.json",
|
||||
cache_dir=tmp_path / "shards",
|
||||
)
|
||||
try:
|
||||
assert len(heartbeat_calls) == 1
|
||||
args, kwargs = heartbeat_calls[0]
|
||||
reg_payload = args[2]
|
||||
assert reg_payload["shard_start"] == 0
|
||||
assert reg_payload["shard_end"] == 5
|
||||
assert reg_payload["managed_assignment"] is False
|
||||
finally:
|
||||
node.stop()
|
||||
finally:
|
||||
tracker.stop()
|
||||
|
||||
|
||||
def test_real_model_startup_registers_downloaded_inventory_without_checksum(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
|
||||
Reference in New Issue
Block a user