Declare the AI owner, and let every node borrow its model over the mesh

vv_is_ai_host() was `=== 'host1'`, which made a physical fact — that is where the
GPU is — look like a rule. AI_OWNER_HOST declares it, so the card can move to a
rebuilt host3 or a friend's spare.

The gate was also doing two jobs. Assistant docks and findings strips now ask
whether a model is reachable, so a node without a GPU gets them by borrowing;
the AI tab asks whether this is the owner, because that page carries the bug
reports, the index and the model configuration — the surface where the
vocabulary assumes you built the mesh.

Resolution is local, then owner, then anyone else declaring a model, pinned once
it answers. Pinned rather than re-derived per call: a mesh that re-decides every
request eventually decides differently mid-conversation, and a chat whose second
turn lands on another machine has no history there. Cleared only on a transport
failure, and only when there is somewhere else to go — a single-node mesh whose
model is down should say so, not report AI as unconfigured.
This commit is contained in:
Gmer4Lfe
2026-08-14 22:54:26 -04:00
parent b708a90548
commit 2bda4cdaf8
7 changed files with 149 additions and 8 deletions
+4 -1
View File
@@ -1164,7 +1164,10 @@ function vv_ai_ask_model(string $prompt, int $timeout = 120): ?string {
'ignore_errors' => true,
]]);
$raw = @file_get_contents(rtrim($cfg['url'], '/') . '/api/chat', false, $ctx);
if ($raw === false) return null;
// Unpin on failure so the next resolution steps to another node that has a model. A refusal
// or a bad reply is not a failure of the endpoint — only not reaching it is, which is why
// this sits on the transport result and not on the parse below.
if ($raw === false) { vv_ai_model_failed($cfg['model_host'] ?? ''); return null; }
$d = json_decode($raw, true);
return $d['message']['content'] ?? null;
}