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.
This commit is contained in:
Gmer4Lfe
2026-08-21 07:59:50 -04:00
parent 111c70d6b4
commit 9c15df8e22
2 changed files with 76 additions and 4 deletions
+61
View File
@@ -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'] ?? [],
];