diff --git a/.claude/memory/project-status.md b/.claude/memory/project-status.md index 65f2246..446f722 100644 --- a/.claude/memory/project-status.md +++ b/.claude/memory/project-status.md @@ -42,3 +42,4 @@ Historical handoff note: `/mnt/c/Users/popov/Downloads/neuron-tai-alpha-handoff- - Verification: downloader/startup targeted subset passes (`pytest tests/test_node_startup.py -k "download_shard or same_shard"`). Full `tests/test_node_startup.py` has 46 passed and 4 unrelated Windows chmod/path separator failures. - Live Windows confirmation: `meshnet-node start --tracker http://192.168.0.179:8080 --model Qwen3.6-35B-A3B` reuses `F:\_STORAGE\models\qwen3.6-35b-a3b`, prints `Cached at`, registers, and reaches ready as node `5gMLrmyB-26b1f8a4204a`. - Follow-up fix: preset-model startup now starts the heartbeat thread after registration; without this, the node appeared briefly on the dashboard and was purged on first inference/route after heartbeat expiry. Tracker dashboard now has a "Console output" panel backed by `/v1/console` for node register/expiry, routing failures, and proxy events. +- Qwen3.6-35B-A3B reserve-based split is expected: an 79 GB CPU node may be assigned layers 0-36, and a second node fills 37-39. Do not "fix" this by bypassing the 20% assignment reserve unless the shard-planning policy changes. diff --git a/packages/node/meshnet_node/startup.py b/packages/node/meshnet_node/startup.py index af570b4..72d98a4 100644 --- a/packages/node/meshnet_node/startup.py +++ b/packages/node/meshnet_node/startup.py @@ -139,22 +139,33 @@ def _hardware_label(device: str, gpu_name: str | None = None) -> str: return "CPU" -def _max_assignable_layers(memory_mb: int, total_layers: int | None) -> int: +def _max_assignable_layers( + memory_mb: int, + total_layers: int | None, + bytes_per_layer: int | None = None, +) -> int: if total_layers is None or total_layers <= 0 or memory_mb <= 0: return 0 budget_bytes = memory_mb * 1024 * 1024 - return min(total_layers, int((budget_bytes * 0.8) // _DEFAULT_BYTES_PER_LAYER)) + layer_bytes = bytes_per_layer or _DEFAULT_BYTES_PER_LAYER + return min(total_layers, int((budget_bytes * 0.8) // layer_bytes)) -def _shard_budget_line(memory_mb: int, memory_source: str, total_layers: int | None, quantization: str) -> str: +def _shard_budget_line( + memory_mb: int, + memory_source: str, + total_layers: int | None, + quantization: str, + bytes_per_layer: int | None = None, +) -> str: memory_gb = memory_mb / 1024 gb_str = f"{memory_gb:.1f} GB" budget_quantization = "bfloat16" if quantization == "auto" else quantization if total_layers is None or total_layers <= 0: return f"Memory budget: {gb_str} {memory_source}; shard budget: unknown model layer count" - max_layers = _max_assignable_layers(memory_mb, total_layers) + max_layers = _max_assignable_layers(memory_mb, total_layers, bytes_per_layer=bytes_per_layer) # Remaining capacity after one full model load (rough estimate) - shard_bytes = max_layers * _DEFAULT_BYTES_PER_LAYER + shard_bytes = max_layers * (bytes_per_layer or _DEFAULT_BYTES_PER_LAYER) remaining_gb = (memory_mb * 1024 * 1024 - shard_bytes) / (1024 ** 3) remaining_str = f"; {remaining_gb:.1f} GB remaining after full load" if remaining_gb > 1 else "" return ( @@ -164,6 +175,23 @@ def _shard_budget_line(memory_mb: int, memory_source: str, total_layers: int | N ) +def _assignment_bytes_per_layer(assignment: dict, quantization: str) -> int | None: + bytes_per_layer = assignment.get("bytes_per_layer") + if isinstance(bytes_per_layer, int) and bytes_per_layer > 0: + return bytes_per_layer + if not isinstance(bytes_per_layer, dict): + return None + keys = [quantization, "bfloat16", "bf16", "int8", "nf4"] + for key in keys: + value = bytes_per_layer.get(key) + if isinstance(value, int) and value > 0: + return value + for value in bytes_per_layer.values(): + if isinstance(value, int) and value > 0: + return value + return None + + def _post_json(url: str, payload: dict, timeout: float = 10.0) -> dict: data = json.dumps(payload).encode() req = urllib.request.Request( diff --git a/packages/tracker/meshnet_tracker/dashboard.html b/packages/tracker/meshnet_tracker/dashboard.html index 39c88de..f9793d7 100644 --- a/packages/tracker/meshnet_tracker/dashboard.html +++ b/packages/tracker/meshnet_tracker/dashboard.html @@ -75,6 +75,7 @@

Model usage (RPM)

loading…

Node throughput

loading…

Console output

loading…
+

Inference history

loading...