feat(mother): Phase 1a — machine_id + local LLM schema
Schema (mother_schema.sql): - Added machine_id TEXT UNIQUE column to hive_nodes - Idempotent migration ALTER TABLE + constraint - Extended derive_capabilities(): ollama_available, llama_cpp_available with model lists, plus inference_tier (local-fast/slow/remote-only) MCP (node-register-mcp): - Accepts optional machine_id argument (null for unsecured nodes) - Passes through to INSERT/UPSERT with NULLIF for empty strings - COALESCE preserves existing machine_id on conflict (don't lose stable identity if hostname changes) Sam & Hermes
This commit is contained in:
parent
c35bbd273a
commit
14697a07dd
2 changed files with 44 additions and 4 deletions
|
|
@ -22,6 +22,9 @@ END $$;
|
|||
CREATE TABLE IF NOT EXISTS hive_nodes (
|
||||
id SERIAL PRIMARY KEY,
|
||||
hostname TEXT NOT NULL UNIQUE,
|
||||
-- Stable identity across reboots (generated on first password set).
|
||||
-- NULL for unsecured nodes; used for UPSERT deduplication.
|
||||
machine_id TEXT UNIQUE,
|
||||
-- Provisioning medium: live-usb | disk | vps | mother | unknown.
|
||||
node_type TEXT NOT NULL DEFAULT 'unknown',
|
||||
last_seen TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
|
@ -35,6 +38,13 @@ CREATE TABLE IF NOT EXISTS hive_nodes (
|
|||
);
|
||||
-- Add node_type to tables migrated from the old usb_nodes definition.
|
||||
ALTER TABLE hive_nodes ADD COLUMN IF NOT EXISTS node_type TEXT NOT NULL DEFAULT 'unknown';
|
||||
ALTER TABLE hive_nodes ADD COLUMN IF NOT EXISTS machine_id TEXT;
|
||||
-- Make unique if not already; ignore duplicate-key errors from pre-existing NULLs.
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'hive_nodes_machine_id_key') THEN
|
||||
ALTER TABLE hive_nodes ADD CONSTRAINT hive_nodes_machine_id_key UNIQUE (machine_id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_status ON hive_nodes (status);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_last_seen ON hive_nodes (last_seen DESC);
|
||||
|
|
@ -102,6 +112,29 @@ BEGIN
|
|||
IF wifi IS NOT NULL AND jsonb_array_length(wifi) > 0 THEN
|
||||
caps := caps || '{"has_wifi": true}'::JSONB;
|
||||
END IF;
|
||||
-- Local LLM detection (ollama + llama.cpp probes from hw-probe).
|
||||
IF NEW.hw_profile->'local_llm' IS NOT NULL THEN
|
||||
IF NEW.hw_profile->'local_llm'->'ollama'->>'available' = 'true' THEN
|
||||
caps := caps || jsonb_build_object(
|
||||
'ollama_available', true,
|
||||
'ollama_models', NEW.hw_profile->'local_llm'->'ollama'->'models'
|
||||
);
|
||||
END IF;
|
||||
IF NEW.hw_profile->'local_llm'->'llama_cpp'->>'available' = 'true' THEN
|
||||
caps := caps || jsonb_build_object(
|
||||
'llama_cpp_available', true,
|
||||
'llama_cpp_models', NEW.hw_profile->'local_llm'->'llama_cpp'->'models'
|
||||
);
|
||||
END IF;
|
||||
END IF;
|
||||
-- Inference tier: what this node can run locally.
|
||||
IF caps->>'has_gpu' = 'true' AND (caps->>'ollama_available' = 'true' OR caps->>'llama_cpp_available' = 'true') THEN
|
||||
caps := caps || '{"inference_tier": "local-fast"}'::JSONB;
|
||||
ELSIF caps->>'can_run_local_llm' = 'true' OR caps->>'ollama_available' = 'true' OR caps->>'llama_cpp_available' = 'true' THEN
|
||||
caps := caps || '{"inference_tier": "local-slow"}'::JSONB;
|
||||
ELSE
|
||||
caps := caps || '{"inference_tier": "remote-only"}'::JSONB;
|
||||
END IF;
|
||||
NEW.capabilities := caps;
|
||||
NEW.last_cap_sync := now();
|
||||
RETURN NEW;
|
||||
|
|
|
|||
|
|
@ -8,11 +8,15 @@
|
|||
# can_run_local_llm, has_wifi, etc. on INSERT/UPDATE.
|
||||
#
|
||||
# Expected input:
|
||||
# {"jsonrpc":"2.0","method":"tools/call","id":1,"params":{"name":"node_register","arguments":{"hostname":"clawdie-node","node_type":"live-usb","hw_profile":{...}}}}
|
||||
# {"jsonrpc":"2.0","method":"tools/call","id":1,"params":{"name":"node_register","arguments":{"hostname":"clawdie-node","node_type":"live-usb","machine_id":"a1b2...","hw_profile":{...}}}}
|
||||
#
|
||||
# Output on success:
|
||||
# {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"registered\":true,\"hostname\":\"clawdie-node\",\"capabilities\":{...}}"}]}}
|
||||
#
|
||||
# machine_id is optional (null for unsecured nodes). When present, it provides
|
||||
# stable identity across hostname changes and is passed through to the
|
||||
# hive_nodes.machine_id UNIQUE column.
|
||||
#
|
||||
# Security: psql :'variable' substitution expands to a safely single-quoted SQL
|
||||
# string literal — no shell interpolation touches the JSON blobs.
|
||||
#
|
||||
|
|
@ -31,6 +35,7 @@ INPUT=$(cat)
|
|||
ID=$(echo "$INPUT" | jq -r '.id // "1"')
|
||||
HOSTNAME=$(echo "$INPUT" | jq -r '.params.arguments.hostname // ""')
|
||||
NODE_TYPE=$(echo "$INPUT" | jq -r '.params.arguments.node_type // "unknown"')
|
||||
MACHINE_ID=$(echo "$INPUT" | jq -r '.params.arguments.machine_id // ""')
|
||||
HW_PROFILE=$(echo "$INPUT" | jq -c '.params.arguments.hw_profile // {}')
|
||||
|
||||
# node_type is a small enum; validate so a bad value can't land an odd row.
|
||||
|
|
@ -59,12 +64,14 @@ fi
|
|||
# would continue past a failed statement and exit 0, hiding failures. stderr is
|
||||
# folded into RESULT so the error branch can report what went wrong.
|
||||
RESULT=$(psql -d "$DB" -tA -v ON_ERROR_STOP=1 \
|
||||
-v hostname="$HOSTNAME" -v node_type="$NODE_TYPE" -v hw_profile="$HW_PROFILE" 2>&1 <<'PSQL'
|
||||
-v hostname="$HOSTNAME" -v node_type="$NODE_TYPE" \
|
||||
-v machine_id="$MACHINE_ID" -v hw_profile="$HW_PROFILE" 2>&1 <<'PSQL'
|
||||
BEGIN;
|
||||
INSERT INTO hive_nodes (hostname, node_type, hw_profile, status, last_seen)
|
||||
VALUES (:'hostname', :'node_type', (:'hw_profile')::jsonb, 'online', now())
|
||||
INSERT INTO hive_nodes (hostname, node_type, machine_id, hw_profile, status, last_seen)
|
||||
VALUES (:'hostname', :'node_type', NULLIF(:'machine_id', ''), (:'hw_profile')::jsonb, 'online', now())
|
||||
ON CONFLICT (hostname) DO UPDATE
|
||||
SET node_type = EXCLUDED.node_type,
|
||||
machine_id = COALESCE(NULLIF(EXCLUDED.machine_id, ''), hive_nodes.machine_id),
|
||||
hw_profile = EXCLUDED.hw_profile,
|
||||
status = 'online',
|
||||
last_seen = now();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue