Share one AI across the mesh instead of confining it to the owner

Curated state copied to every node is state that can disagree, so the index,
the model and the shared memory stay on the owner and each node reaches them
over the SSH trust onboarding already builds. Chats stay on the node that had
them; memory and bug reports stay the owner's to write.
This commit is contained in:
Gmer4Lfe
2026-08-20 19:53:28 -04:00
parent 4accd6b67e
commit 0621f66889
11 changed files with 1013 additions and 541 deletions
+19 -7
View File
@@ -586,16 +586,28 @@ function vv_is_ai_host(): bool {
// its definition is missing is worse than no gate. Reads AI_ENABLED directly for the same
// reason. Fail-closed on anything but the literal "true", matching the conf's own contract.
// May this node show AI features — the assistant docks, the findings strips, the AI rows on the
// Monitor card. No longer "am I host1": a node without a GPU borrows the owner's model over the
// mesh, so every node in the mesh gets the assistant. What it does not get is the AI tab; see
// vv_ai_owner_ui_on().
// Monitor card. No longer "am I the owner": the mesh shares one AI, and every node reaches it
// through include/ai_rpc.php. What a mirror does not get is the AI tab; see vv_ai_owner_ui_on().
//
// Still fails closed. A node with no local URL and no owner URL resolves to nothing, and an
// assistant that cannot reach a model is worse than an absent one.
// The two halves are asymmetric on purpose. The owner still fails closed on its own URL, because
// a missing local URL there is a conf error nothing can work around. A mirror does not test
// reachability at all: it is one SSH round trip away from the answer, on a link that goes down
// and comes back, and hiding the entire assistant on a transient blip is worse than showing it
// and reporting the failure in place. vv_ai_rpc() names every transport failure precisely so this
// gate does not have to guess at one.
//
// It lives here rather than in include/ai.php because the pages that need it do not all load that
// file; the Scheduler loads only config.php, and a gate that silently answers false where its
// definition is missing is worse than no gate.
function vv_ai_ui_on(): bool {
if (strtolower(trim(vv_conf_vars()['AI_ENABLED'] ?? 'false')) !== 'true') return false;
$host = strtoupper(vv_ai_model_host());
return trim((string)(vv_conf_vars()[$host . '_OLLAMA_URL'] ?? '')) !== '';
if (vv_ai_is_owner()) {
return trim((string)(vv_conf_vars()[strtoupper(vv_ai_owner_host()) . '_OLLAMA_URL'] ?? '')) !== '';
}
// A mirror needs somewhere to send the request. Without a hostname for the owner there is no
// round trip to attempt, and that is a conf gap rather than a transient one.
return trim((string)(vv_conf_vars()[strtoupper(vv_ai_owner_host())] ?? '')) !== '';
}
// May this node show the AI tab. Owner only, and deliberately so: that page carries the bug