From 15f90003c02ac5ad191df0bd8ef18aaeca4dfd27 Mon Sep 17 00:00:00 2001 From: bigmerge Date: Fri, 14 Aug 2026 21:52:56 -0500 Subject: [PATCH] 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. --- engram/src/server.el | 286 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) diff --git a/engram/src/server.el b/engram/src/server.el index 541d9ec..28c2496 100644 --- a/engram/src/server.el +++ b/engram/src/server.el @@ -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 .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")