From 9c15df8e22ab111b1fb733c9b1484ca50e16def7 Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Fri, 21 Aug 2026 07:59:50 -0400 Subject: [PATCH] Report the owner's model and index on a mirror's Monitor card A mirror was probing an Ollama it does not have and an index it never builds, so the card read "unreachable / not built" about the wrong machine while the model it actually uses was up. The card now names whose figures it is showing. --- Plugin/unraid/include/ai.php | 61 +++++++++++++++++++++++++++++++++ Plugin/unraid/pages/monitor.php | 19 +++++++--- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/Plugin/unraid/include/ai.php b/Plugin/unraid/include/ai.php index 995bb25..a4449b2 100644 --- a/Plugin/unraid/include/ai.php +++ b/Plugin/unraid/include/ai.php @@ -547,7 +547,64 @@ function vv_ai_recent_logs(int $max = 40): array { return $out; } +// The figures every AI surface draws: the banner, the Scheduler dock and the Monitor card. +// +// On a mirror these describe the owner, because on a mirror there is nothing local to describe. +// Collected locally it probed an Ollama that is not installed and an index that is never built, +// and the Monitor card said "Ollama unreachable / Index not built" — both true of that box and +// both the wrong question, since the model it actually uses was up the whole time. +// +// Routed here rather than in the cache writer so that every consumer follows. api/ai.php already +// sends the stats *action* to the owner, so the tab was right while the card was wrong; this is +// what makes the two agree. function vv_ai_stats(): array { + return vv_ai_is_owner() ? vv_ai_stats_local() : vv_ai_stats_shared(); +} + +// What the owner reports about itself, fetched once and cached by the caller. A transport failure +// is reported as a failed health check rather than as absent hardware: "cannot reach the owner" +// and "the owner has no model" are different faults with different fixes, and the local-collection +// version could only ever express the second one. +function vv_ai_stats_shared(): array { + require_once __DIR__ . '/ai_rpc.php'; + + $status = 200; + $owner = vv_ai_owner_host(); + $name = trim((string)(vv_conf_vars()[strtoupper($owner)] ?? $owner)); + $r = vv_ai_rpc('stats', [], false, $status); + + if (($r['ok'] ?? false) && is_array($r['stats'] ?? null)) { + $stats = $r['stats']; + $stats['served_by'] = $name; // so a surface can say whose numbers these are + return $stats; + } + + $why = (string)($r['error'] ?? 'no response from the AI owner'); + return [ + 'enabled' => vv_ai_enabled(), + 'model' => '', + 'embed_model' => '', + 'url' => '', + 'k' => 0, + 'served_by' => $name, + // Shapes kept identical to the local collection. The Monitor card reads runtime.reachable + // and index.exists directly, and a missing key there renders as a broken card rather than + // as the outage it is. + 'index' => ['exists' => false, 'chunks' => 0, 'stale' => false], + 'runtime' => ['reachable' => false, 'loaded' => false, 'offload_pct' => null], + 'loaded' => null, + 'health' => [[ + 'id' => 'owner', + 'label' => 'AI owner', + 'state' => 'bad', + 'detail' => $why, + 'fix' => "Check that $name is up and that this node's SSH key still reaches it", + ]], + 'ts' => time(), + ]; +} + +function vv_ai_stats_local(): array { $cfg = vv_ai_config(); return [ 'enabled' => $cfg['enabled'], @@ -596,6 +653,10 @@ function vv_ai_stats_cached(bool $live = false): array { function vv_ai_monitor_block(array $stats): array { return [ 'model' => $stats['model'] ?? '', + // Empty on the owner, the owner's hostname on a mirror. The card draws a model and an + // index that live on another machine, and a dashboard that shows one node's figures under + // another node's heading is the kind of quiet wrongness this project keeps finding. + 'served_by' => $stats['served_by'] ?? '', 'runtime' => $stats['runtime'] ?? [], 'index' => $stats['index'] ?? [], ]; diff --git a/Plugin/unraid/pages/monitor.php b/Plugin/unraid/pages/monitor.php index 9bd5c2a..4626e58 100644 --- a/Plugin/unraid/pages/monitor.php +++ b/Plugin/unraid/pages/monitor.php @@ -31,7 +31,9 @@ // No GPU, no UPS, no VMs — the corresponding card is absent rather than showing zeros // or an error. The page is built to be correct on hardware lacking any given part. The // AI row is the same rule applied to a subsystem rather than a device: it exists only -// where vv_ai_ui_on() is true, which is the AI host with AI_ENABLED set. +// where vv_ai_ui_on() is true, which is any node in the mesh with AI_ENABLED set. On a +// node that is not the AI owner the figures describe the owner's model and index, and the +// card names it — see 'served_by' in vv_ai_monitor_block(). // // The assistant here starts on General Chat, where the AI tab starts on Varaverk Assistant. // Different jobs. The tab is where you go to interrogate the installation; this is the @@ -310,10 +312,11 @@ $_vv_doc_vars = array_merge(vv_conf_vars(), ['SCRIPTS_DIR' => SCRIPTS_DIR]); Cards here size to their content instead. -->
- + it is not here. On a node that is not the AI owner these figures describe the owner's + model and index, and the card names it. api/ai.php gates each action independently, so + this is presentation rather than access control. -->