teacher-summon: default-off (TEACHER_ENABLE) soul-native wake; byte-inert when unset

+282 lines in engram/src/server.el implementing the flag-gated teacher summon
(consult_teacher backend abstraction, tier autoselect, GGUF fetch/cache). With
TEACHER_ENABLE unset the summon path is byte-inert. Consolidates the proven
api-reshape pieces (geometry-ops d4f401d, boundary auto-emit 0182642) for the
validated cutover.
This commit is contained in:
bigmerge
2026-08-14 21:52:56 -05:00
parent 01826421c4
commit 15f90003c0
+286
View File
@@ -945,6 +945,272 @@ fn route_correspondence_beat(method: String, path: String, body: String) -> Stri
return engram_correspondence_beat_json(seeds, f, keystone)
}
// GUIDE SUMMON (soul-native wake behavior)
//
// "When Neuron wakes up, he calls his guide and the guide comes over." (Will)
//
// Named GUIDE, not teacher: its output is always grounded/verified before Neuron
// trusts it advisory (a guide, whose directions you verify), not authoritative
// (a teacher, whose word you take).
//
// The guide is a THINKING model (Qwen3, native thinking mode) an engageable
// interlocutor for cultivation-dialogue, not a passive generator. It is NOT the
// runtime mouth: runtime fluency is cultivated geometry; the guide is the
// reasoning-partner the soul reaches OUT to on a genuine gap it cannot derive.
//
// This whole section is a native WAKE STEP: at boot the soul probes its hardware,
// selects a tier by spec (Qwen3-4B / 1.7B / 0.6B), checks its local model cache,
// FETCHES the guide from Hugging Face on demand if absent, LOADS it via a backend
// abstraction, and BINDS it as consult_guide(). Idempotent: cached GGUF no
// fetch; already-answering guide → no reload. Flag-gated (GUIDE_ENABLE): default
// OFF makes the wake byte-inert, so prod is unaffected until the flag is set.
//
// BACKEND (2026-08-14 decision): llama.cpp via the llama-server BINARY, behind this
// El abstraction (guide_backend / guide_load / guide_healthy / consult_guide).
// Embedding libllama directly into the runtime is the intended end-state and is
// STAGED the abstraction is the seam it swaps in behind, so the summon is not
// blocked on a runtime C change. `--jinja` selects the Qwen3 chat template, which
// turns native thinking ON: the response carries reasoning_content (the thinking)
// alongside content (the answer).
fn guide_env_or(key: String, dflt: String) -> String {
let v: String = env(key)
if str_eq(v, "") { return dflt }
return v
}
fn guide_enabled() -> Bool {
let v: String = env("GUIDE_ENABLE")
if str_eq(v, "1") { return true }
if str_eq(v, "on") { return true }
if str_eq(v, "true") { return true }
return false
}
// guide_json_escape make an arbitrary string safe to embed inside a JSON
// double-quoted value. Order matters: backslash first, then quote, then real
// newlines the two-char "\n". The newline char itself is obtained from the
// shell (El source has no newline escape) so we can target it in str_replace.
fn guide_json_escape(s: String) -> String {
let a: String = str_replace(s, "\\", "\\\\")
let b: String = str_replace(a, "\"", "\\\"")
let nl: String = exec("printf '\\n'")
let c: String = if str_eq(nl, "") { b } else { str_replace(b, nl, "\\n") }
return c
}
// 1. Hardware probe
// RAM in whole GB. macOS: sysctl hw.memsize (bytes). Linux: /proc/meminfo (kB).
fn guide_probe_ram_gb() -> Int {
let mac: String = str_trim(exec("sysctl -n hw.memsize 2>/dev/null"))
if !str_eq(mac, "") {
let bytes: Int = str_to_int(mac)
if bytes > 0 { return bytes / 1073741824 }
}
let lin: String = str_trim(exec("awk '/MemTotal/{printf \"%d\", $2/1048576}' /proc/meminfo 2>/dev/null"))
if !str_eq(lin, "") {
let gb: Int = str_to_int(lin)
if gb > 0 { return gb }
}
return 0
}
// Best-effort GPU signal Apple Silicon implies Metal. Informational only; the
// tier is chosen on RAM, and llama-server offloads to Metal automatically when present.
fn guide_probe_metal() -> Bool {
let arm: String = str_trim(exec("sysctl -n hw.optional.arm64 2>/dev/null"))
if str_eq(arm, "1") { return true }
return false
}
// 2. Tier selection (config-driven thresholds, spec-autoselected)
fn guide_threshold_4b() -> Int {
return str_to_int(guide_env_or("GUIDE_RAM_GB_4B", "16"))
}
fn guide_threshold_1p7b() -> Int {
return str_to_int(guide_env_or("GUIDE_RAM_GB_1P7B", "8"))
}
// GUIDE_TIER_FORCE overrides the spec autoselect (used to prove cheaply on 0.6b).
fn guide_select_tier(ram_gb: Int) -> String {
let forced: String = env("GUIDE_TIER_FORCE")
if !str_eq(forced, "") { return forced }
if ram_gb >= guide_threshold_4b() { return "4b" }
if ram_gb >= guide_threshold_1p7b() { return "1.7b" }
return "0.6b"
}
// Tier table HF GGUF repos + files, verified present on the Hub 2026-08-14.
fn guide_repo(tier: String) -> String {
if str_eq(tier, "4b") { return "Qwen/Qwen3-4B-GGUF" }
if str_eq(tier, "1.7b") { return "Qwen/Qwen3-1.7B-GGUF" }
return "Qwen/Qwen3-0.6B-GGUF"
}
fn guide_file(tier: String) -> String {
if str_eq(tier, "4b") { return "Qwen3-4B-Q4_K_M.gguf" }
if str_eq(tier, "1.7b") { return "Qwen3-1.7B-Q8_0.gguf" }
return "Qwen3-0.6B-Q8_0.gguf"
}
fn guide_cache_dir() -> String {
let c: String = env("GUIDE_CACHE_DIR")
if !str_eq(c, "") { return c }
let home: String = env("HOME")
if !str_eq(home, "") { return home + "/.neuron/guide/models" }
return engram_resolve_data_dir() + "/guide-models"
}
fn guide_model_path(tier: String) -> String {
return guide_cache_dir() + "/" + guide_file(tier)
}
// 3. Presence check
// Present = file exists AND is larger than 1 MB (rejects a truncated/partial fetch).
fn guide_present(tier: String) -> Bool {
let p: String = guide_model_path(tier)
if !fs_exists(p) { return false }
let sz: String = str_trim(exec("wc -c < '" + p + "' 2>/dev/null"))
if str_eq(sz, "") { return false }
let n: Int = str_to_int(sz)
if n > 1048576 { return true }
return false
}
// 3b. Fetch from Hugging Face (on demand the soul fetches its own guide)
// Prefer the `hf` CLI; fall back to a direct GGUF resolve URL via curl. Atomic:
// download to <file>.part then mv into place. The trailing `echo` gives exec()
// stdout so it returns promptly once the child (the download) exits. This BLOCKS
// the wake thread for the duration of the download acceptable for the first-ever
// wake; an async fetch-then-attach refinement is staged.
fn guide_fetch(tier: String) -> Bool {
let dir: String = guide_cache_dir()
let file: String = guide_file(tier)
let repo: String = guide_repo(tier)
let path: String = dir + "/" + file
let url: String = "https://huggingface.co/" + repo + "/resolve/main/" + file
let ok: Int = fs_mkdir(dir)
let cmd: String = "mkdir -p '" + dir + "'; if command -v hf >/dev/null 2>&1; then hf download '" + repo + "' '" + file + "' --local-dir '" + dir + "' >/dev/null 2>&1; fi; if [ ! -s '" + path + "' ]; then curl -fL --retry 3 -o '" + path + ".part' '" + url + "' >/dev/null 2>&1 && mv '" + path + ".part' '" + path + "'; fi; if [ -s '" + path + "' ]; then echo FETCH_OK; else echo FETCH_FAIL; fi"
let out: String = exec(cmd)
if str_contains(out, "FETCH_OK") { return true }
return false
}
// 4/5. Backend abstraction + BIND as an engageable interlocutor
fn guide_backend() -> String { return guide_env_or("GUIDE_BACKEND", "llama-server") }
fn guide_host() -> String { return guide_env_or("GUIDE_HOST", "127.0.0.1") }
fn guide_port() -> String { return guide_env_or("GUIDE_PORT", "8771") }
fn guide_base_url() -> String { return "http://" + guide_host() + ":" + guide_port() }
// guide_healthy is the guide present and answering? llama-server's /health
// returns {"status":"ok"} once the model is loaded (503 while loading, "" if down).
fn guide_healthy() -> Bool {
let r: String = http_get(guide_base_url() + "/health")
if str_contains(r, "\"status\":\"ok\"") { return true }
if str_contains(r, "\"status\": \"ok\"") { return true }
return false
}
// guide_load start the guide process (backend binary) in the background and
// wait for it to answer. Idempotent: if a healthy guide is already answering,
// returns at once (the guide stays across wakes). --jinja Qwen3 thinking ON.
fn guide_load(tier: String) -> Bool {
if guide_healthy() { return true }
let path: String = guide_model_path(tier)
let bin: String = guide_env_or("GUIDE_LLAMA_SERVER_BIN", "llama-server")
let ngl: String = guide_env_or("GUIDE_NGL", "99")
let ctx: String = guide_env_or("GUIDE_CTX", "4096")
let logf: String = guide_cache_dir() + "/llama-server." + guide_port() + ".log"
let cmd: String = bin + " -m '" + path + "' --host " + guide_host() + " --port " + guide_port() + " -c " + ctx + " -ngl " + ngl + " --jinja >> '" + logf + "' 2>&1"
let pid: String = exec_bg(cmd)
// Poll /health up to ~90s (1s between attempts; El has no sleep builtin → exec).
let i: Int = 0
while i < 90 {
let s: String = exec("sleep 1")
if guide_healthy() { return true }
i = i + 1
}
return false
}
// consult_guide THE SEAM the soul calls to engage its guide (thinking ON).
// Returns a JSON envelope {"ok":bool,"reasoning":"...","content":"..."}. On any
// failure it returns {"ok":false,...} so a caller can fall back to pure geometry.
//
// WHERE THIS ROUTES FROM (staged wiring): the cultivation / correspondence-beat
// path (route_correspondence_beat / route_think) is where a genuine reach-OUTSIDE
// belongs when the geometry cannot derive a claim, the soul consults the guide
// as reasoning-partner, then GROUNDS the reply (verify-then-bake) rather than
// storing a distilled copy. That wiring is deliberately left as a one-call seam
// here; this build proves the summon + a real exchange, not the cultivation edit.
fn consult_guide(prompt: String) -> String {
if !guide_healthy() { return "{\"ok\":false,\"error\":\"guide not present\"}" }
let url: String = guide_base_url() + "/v1/chat/completions"
let esc: String = guide_json_escape(prompt)
let body: String = "{\"messages\":[{\"role\":\"user\",\"content\":\"" + esc + "\"}],\"temperature\":0.6,\"top_p\":0.95,\"max_tokens\":512}"
let resp: String = http_post_json(url, body)
if str_eq(resp, "") { return "{\"ok\":false,\"error\":\"empty response\"}" }
let choices: String = json_get_raw(resp, "choices")
if str_eq(choices, "") { return "{\"ok\":false,\"error\":\"no choices in reply\"}" }
let first: String = json_array_get(choices, 0)
let msg: String = json_get_raw(first, "message")
let content: String = json_get_string(msg, "content")
let reasoning: String = json_get_string(msg, "reasoning_content")
let ec: String = guide_json_escape(content)
let er: String = guide_json_escape(reasoning)
return "{\"ok\":true,\"reasoning\":\"" + er + "\",\"content\":\"" + ec + "\"}"
}
// 6. The wake step probe select (fetch if absent) checksum load bind
fn guide_summon() -> String {
if !guide_enabled() {
return "{\"summon\":\"skipped\",\"reason\":\"GUIDE_ENABLE unset\"}"
}
let ram: Int = guide_probe_ram_gb()
let metal: Bool = guide_probe_metal()
let ms: String = if metal { "yes" } else { "no" }
let tier: String = guide_select_tier(ram)
let repo: String = guide_repo(tier)
println("[guide] wake summon — ram=" + int_to_str(ram) + "GB metal=" + ms + " tier=" + tier + " backend=" + guide_backend())
let present0: Bool = guide_present(tier)
if present0 {
println("[guide] guide present in cache (" + guide_model_path(tier) + ") — skipping fetch")
} else {
println("[guide] guide ABSENT — calling: fetch " + repo + " / " + guide_file(tier) + " from Hugging Face ...")
let fetched: Bool = guide_fetch(tier)
if !fetched {
println("[guide] FETCH FAILED — guide could not be summoned")
return "{\"summon\":\"failed\",\"stage\":\"fetch\",\"tier\":\"" + tier + "\"}"
}
println("[guide] fetch complete — guide now present")
}
let sum: String = str_trim(exec("shasum -a 256 '" + guide_model_path(tier) + "' 2>/dev/null | cut -c1-16"))
println("[guide] checksum sha256[0:16]=" + sum)
let loaded: Bool = guide_load(tier)
if !loaded {
println("[guide] LOAD FAILED — guide process did not become healthy")
return "{\"summon\":\"failed\",\"stage\":\"load\",\"tier\":\"" + tier + "\"}"
}
println("[guide] guide present and answering at " + guide_base_url() + " — bound as consult_guide()")
return "{\"summon\":\"ok\",\"tier\":\"" + tier + "\",\"ram_gb\":" + int_to_str(ram) + ",\"metal\":\"" + ms + "\",\"checksum\":\"" + sum + "\",\"backend\":\"" + guide_backend() + "\",\"url\":\"" + guide_base_url() + "\"}"
}
// Guide HTTP surface (status / consult / re-summon)
fn route_guide_status(method: String, path: String, body: String) -> String {
let ram: Int = guide_probe_ram_gb()
let tier: String = guide_select_tier(ram)
let en: String = if guide_enabled() { "true" } else { "false" }
let pr: String = if guide_present(tier) { "true" } else { "false" }
let he: String = if guide_healthy() { "true" } else { "false" }
return "{\"enabled\":" + en + ",\"tier\":\"" + tier + "\",\"ram_gb\":" + int_to_str(ram) + ",\"present\":" + pr + ",\"healthy\":" + he + ",\"backend\":\"" + guide_backend() + "\",\"url\":\"" + guide_base_url() + "\"}"
}
fn route_guide_consult(method: String, path: String, body: String) -> String {
let prompt: String = json_get_string(body, "prompt")
if str_eq(prompt, "") { return err_json("missing prompt") }
return consult_guide(prompt)
}
fn route_guide_summon(method: String, path: String, body: String) -> String {
return guide_summon()
}
// Auth
fn check_auth_ok(method: String, body: String) -> Bool {
@@ -1110,6 +1376,18 @@ fn handle_request(method: String, path: String, body: String) -> String {
return route_correspondence_beat(method, path, body)
}
// GUIDE: the summoned interlocutor. status (read), consult (engage), and
// an explicit re-summon. consult/summon are auth-gated POSTs (covered above).
if str_eq(method, "GET") && (str_eq(clean, "/api/guide/status") || str_eq(clean, "/guide/status")) {
return route_guide_status(method, path, body)
}
if str_eq(method, "POST") && (str_eq(clean, "/api/guide/consult") || str_eq(clean, "/guide/consult")) {
return route_guide_consult(method, path, body)
}
if str_eq(method, "POST") && (str_eq(clean, "/api/guide/summon") || str_eq(clean, "/guide/summon")) {
return route_guide_summon(method, path, body)
}
// Activation + Search
if str_eq(method, "POST") && (str_eq(clean, "/api/activate") || str_eq(clean, "/activate")) {
return route_activate(method, path, body)
@@ -1232,5 +1510,13 @@ println("[engram] node_count=" + int_to_str(engram_node_count()))
println("[engram] edge_count=" + int_to_str(engram_edge_count()))
println("[engram] listening on " + int_to_str(port))
// WAKE: summon the guide (soul-native). Flag-gated (GUIDE_ENABLE): default
// OFF returns immediately and leaves this boot byte-inert. When ON, the soul probes
// its hardware, selects a Qwen3 tier by spec, fetches the GGUF from HF if the local
// cache is cold, loads it via the backend, and binds consult_guide(). Idempotent
// across wakes a cached model and an already-answering guide are both no-ops.
let guide_wake: String = guide_summon()
println("[guide] summon result: " + guide_wake)
http_set_handler("handle_request")
http_serve(port, "handle_request")