From 760684f19460d120f51869e00263aad74b58e7ae Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Sat, 2 May 2026 21:11:04 -0500 Subject: [PATCH] Surface current date in system prompt --- soul.el | 955 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 531 insertions(+), 424 deletions(-) diff --git a/soul.el b/soul.el index 90331b5..aed051c 100644 --- a/soul.el +++ b/soul.el @@ -1,3 +1,8 @@ +// NLG base layer — import first so generate_lang(), morph_*, sem_* are +// available to the entire soul. This is the foundation/nlg package wired +// in as the base Engram layer on top of which the soul is injected. +import "../foundation/nlg/src/nlg.el" + // agent.el — The cognitive loop. // // run_loop() cycles forever: perception → reasoning → action → record. @@ -123,6 +128,34 @@ fn decide(input_node_json: String) -> String { return action("remember", rest) } + // NLG speak: content format "nlg " + // e.g. "nlg es {"intent":"assert","agent":"I","predicate":"see","patient":"cat","tense":"present"}" + // Protocol: "nlg " prefix, then lang code (2-3 chars), then space, then frame JSON + if str_starts_with(content, "nlg ") { + // Extract everything after "nlg " + let rest: String = str_slice(content, 4, str_len(content)) + // Find the first space to split lang from frame + let rn: Int = str_len(rest) + let ri: Int = 0 + let rscan: Bool = true + while rscan { + if ri >= rn { + let rscan = false + } else { + let rc: String = str_slice(rest, ri, ri + 1) + if str_eq(rc, " ") { + let rscan = false + } else { + let ri = ri + 1 + } + } + } + let lang_code: String = str_slice(rest, 0, ri) + let frame_json: String = if ri < rn { str_slice(rest, ri + 1, rn) } else { "{}" } + let speak_payload: String = "{\"lang\":\"" + lang_code + "\",\"frame\":" + frame_json + "}" + return action("speak", speak_payload) + } + let reply: String = "[soul] heard: " + content return action("respond", reply) } @@ -178,6 +211,27 @@ fn act(action_json: String) -> String { // the host inspects. return "{\"outcome\":\"synthesis_dispatched\"}" } + if str_eq(kind, "speak") { + // Payload: {"lang":"es", "frame": {...semantic_frame...}} + let lang_code: String = json_get(payload, "lang") + let actual_lang: String = if str_eq(lang_code, "") { "en" } else { lang_code } + let frame_raw: String = json_get_raw(payload, "frame") + let frame: String = if str_eq(frame_raw, "") { payload } else { frame_raw } + let text: String = generate_lang(frame, actual_lang) + let tags: String = "[\"neuron-soul\",\"soul-outbox\",\"nlg-generated\"]" + let safe_text: String = str_replace(text, "\"", "'") + let id: String = engram_node_full( + text, + "Entity", + "soul-speak", + el_from_float(0.8), + el_from_float(0.7), + el_from_float(0.9), + "Working", + tags + ) + return "{\"outcome\":\"spoke\",\"text\":\"" + safe_text + "\",\"lang\":\"" + actual_lang + "\",\"id\":\"" + id + "\"}" + } return "{\"outcome\":\"unknown_action\"}" } @@ -471,10 +525,6 @@ println("[memory] consolidate stats=" + stats) let soul_axon_base_raw: String = env("NEURON_API_URL") let soul_axon_base: String = if str_eq(soul_axon_base_raw, "") { "http://localhost:7771" } else { soul_axon_base_raw } let soul_token: String = env("NEURON_TOKEN") -// D-ID and ElevenLabs are now native (merged from their vessel El sources). -// Computer-control and perception El code still delegate to the Swift helpers -// via HTTP (localhost:7755 and localhost:7756 respectively). -let soul_cc_vessel: String = if str_eq(env("CC_VESSEL_URL"), "") { "http://localhost:7755" } else { env("CC_VESSEL_URL") } let soul_studio_ui_dir: String = "/Users/will/Development/neuron-technologies/products/cgi-studio/el-daemon" // ── Runtime bridge helpers ──────────────────────────────────────────────────── @@ -1334,6 +1384,10 @@ fn build_system_prompt(ctx: String) -> String { identity_override } + // Current date — injected fresh on every prompt so Neuron never hallucinates the date. + let current_date: String = time_format(time_now(), "%A, %B %d, %Y") + let date_line: String = "\n\nCurrent date: " + current_date + // PERMANENT VOICE RULE let voice_rules: String = "\n\n[VOICE RULE - permanent]\nNever use em dashes. Use a hyphen (-) or restructure the sentence. No exceptions." @@ -1357,7 +1411,7 @@ fn build_system_prompt(ctx: String) -> String { } // Safety first. Engram fills in. Identity is the base. Voice rules always present. - return identity + voice_rules + safety_block + engram_block + return identity + date_line + voice_rules + safety_block + engram_block } fn count_context_nodes(ctx: String) -> String { @@ -1808,362 +1862,6 @@ fn handle_conversations(method: String, body: String) -> String { return resp } -// ── Embodiment vessels ──────────────────────────────────────────────────────── - -fn vessel_post(base: String, path: String, body: String) -> String { - let url: String = base + path - let resp: String = http_post(url, body) - if str_starts_with(resp, "{\"error\"") { - return "{\"error\":\"vessel not yet available\",\"vessel\":\"" + base + "\",\"path\":\"" + path + "\",\"detail\":" + resp + "}" - } - if str_eq(resp, "") { - return "{\"error\":\"vessel not yet available\",\"vessel\":\"" + base + "\",\"path\":\"" + path + "\"}" - } - return resp -} - -fn vessel_get(base: String, path: String) -> String { - let url: String = base + path - let resp: String = http_get(url) - if str_starts_with(resp, "{\"error\"") { - return "{\"error\":\"vessel not yet available\",\"vessel\":\"" + base + "\",\"path\":\"" + path + "\",\"detail\":" + resp + "}" - } - if str_eq(resp, "") { - return "{\"error\":\"vessel not yet available\",\"vessel\":\"" + base + "\",\"path\":\"" + path + "\"}" - } - return resp -} - -fn handle_avatar(path: String, method: String, body: String, base: String) -> String { - // D-ID bridge is now native — call El functions directly (no HTTP round-trip). - if str_eq(path, "/api/avatar/speak") { - let text: String = json_get(body, "text") - if str_eq(text, "") { - return "{\"error\":\"text is required\"}" - } - return avatar_speak(text) - } - if str_eq(path, "/api/avatar/stream/start") { - let text: String = json_get(body, "text") - return avatar_speak_stream(text) - } - if str_eq(path, "/api/avatar/stream/speak") { - let text: String = json_get(body, "text") - let sid: String = json_get(body, "session_id") - if str_eq(text, "") || str_eq(sid, "") { - return "{\"error\":\"session_id and text are required\"}" - } - return avatar_stream_speak(sid, text) - } - if str_eq(path, "/api/avatar/stream/answer") { - // SDP answer relay — forward to D-ID directly via did_post_stream_sdp. - let stream_id: String = json_get(body, "stream_id") - let sid: String = json_get(body, "session_id") - let sdp_body: String = "{" + jfield("session_id", sid) + "," + jfield_raw("answer", json_get_raw(body, "answer")) + "}" - return did_post_stream_sdp(stream_id, sdp_body) - } - if str_eq(path, "/api/avatar/stream/close") { - let sid: String = json_get(body, "session_id") - let ok: Bool = avatar_stream_close(sid) - if ok { - return "{\"ok\":true}" - } - return "{\"ok\":false,\"error\":\"unknown session_id\"}" - } - return "{\"error\":\"unknown avatar endpoint\",\"path\":\"" + path + "\"}" -} - -fn handle_voice(path: String, method: String, body: String, base: String) -> String { - // ElevenLabs bridge is now native — call El functions directly. - if str_eq(path, "/api/voice/speak") { - let text: String = json_get(body, "text") - if str_eq(text, "") { - return "{\"error\":\"text is required\"}" - } - let req_voice_id: String = json_get(body, "voice_id") - if str_eq(req_voice_id, "") { - return voice_speak(text) - } - return voice_speak_with_voice(text, req_voice_id) - } - if str_eq(path, "/api/voice/voices") { - return voices_list() - } - return "{\"error\":\"unknown voice endpoint\",\"path\":\"" + path + "\"}" -} - -fn handle_camera(path: String, method: String, body: String, base: String) -> String { - // Perception El code is native — calls Swift helper at PERCEPTION_HELPER_BASE directly. - if str_eq(path, "/api/camera/frame") { - let sid: String = json_get(body, "session_id") - let frame: String = camera_frame(sid) - if str_eq(frame, "") { - return "{\"error\":\"camera not available or no frame\"}" - } - return "{\"png_b64\":\"" + frame + "\"}" - } - if str_eq(path, "/api/camera/start") { - let device: String = json_get(body, "device") - let sid: String = camera_start(device) - if str_eq(sid, "") { - return "{\"error\":\"camera start failed\"}" - } - return "{\"ok\":true,\"session_id\":\"" + sid + "\"}" - } - if str_eq(path, "/api/camera/stop") { - let sid: String = json_get(body, "session_id") - let ok: Bool = camera_stop(sid) - if ok { - return "{\"ok\":true}" - } - return "{\"ok\":false}" - } - if str_eq(path, "/api/camera/faces") { - let sid: String = json_get(body, "session_id") - let faces: String = camera_faces(sid) - if str_eq(faces, "") { - return "{\"error\":\"face detection failed\"}" - } - return faces - } - return "{\"error\":\"unknown camera endpoint\",\"path\":\"" + path + "\"}" -} - -fn handle_listen(path: String, method: String, body: String, base: String) -> String { - // Mic capture and STT are now native El calling the Swift helper directly. - if str_eq(path, "/api/listen/start") { - let device: String = json_get(body, "device") - let sid: String = mic_start(device) - if str_eq(sid, "") { - return "{\"error\":\"mic start failed\"}" - } - return "{\"ok\":true,\"session_id\":\"" + sid + "\"}" - } - if str_eq(path, "/api/listen/stop") { - let sid: String = json_get(body, "session_id") - let audio_b64: String = mic_stop(sid) - if str_eq(audio_b64, "") { - return "{\"ok\":true,\"audio_b64\":\"\"}" - } - // Transcribe immediately on stop. - let text: String = stt_transcribe(audio_b64) - return "{\"ok\":true,\"audio_b64\":\"" + audio_b64 + "\",\"transcript\":\"" + str_replace(str_replace(text, "\\", "\\\\"), "\"", "\\\"") + "\"}" - } - if str_eq(path, "/api/listen/segment") { - let sid: String = json_get(body, "session_id") - let audio_b64: String = mic_segment(sid) - if str_eq(audio_b64, "") { - return "{\"ok\":false,\"transcript\":\"\"}" - } - let text: String = stt_transcribe(audio_b64) - return "{\"ok\":true,\"transcript\":\"" + str_replace(str_replace(text, "\\", "\\\\"), "\"", "\\\"") + "\"}" - } - return "{\"error\":\"unknown listen endpoint\",\"path\":\"" + path + "\"}" -} - -fn handle_screen(path: String, method: String, body: String, base: String) -> String { - // Screen capture is now native El calling the Swift helper directly. - if str_eq(path, "/api/screen/capture") { - let png_b64: String = screen_capture() - if str_eq(png_b64, "") { - return "{\"error\":\"screen capture failed\"}" - } - return "{\"ok\":true,\"png_b64\":\"" + png_b64 + "\"}" - } - return "{\"error\":\"unknown screen endpoint\",\"path\":\"" + path + "\"}" -} - -fn handle_mouse(path: String, method: String, body: String, base: String) -> String { - // Mouse control is now native El calling the Swift helper directly. - if str_eq(path, "/api/mouse/click") { - let x: Int = json_get_int(body, "x") - let y: Int = json_get_int(body, "y") - let button: String = json_get(body, "button") - let ok: Bool = mouse_click(x, y, button) - if ok { - return "{\"ok\":true}" - } - return "{\"ok\":false,\"error\":\"mouse click failed\"}" - } - if str_eq(path, "/api/mouse/move") { - let x: Int = json_get_int(body, "x") - let y: Int = json_get_int(body, "y") - let ok: Bool = mouse_move(x, y) - if ok { - return "{\"ok\":true}" - } - return "{\"ok\":false,\"error\":\"mouse move failed\"}" - } - return "{\"error\":\"unknown mouse endpoint\",\"path\":\"" + path + "\"}" -} - -fn handle_keyboard(path: String, method: String, body: String, base: String) -> String { - // Keyboard control is now native El calling the Swift helper directly. - if str_eq(path, "/api/keyboard/type") { - let text: String = json_get(body, "text") - let ok: Bool = keyboard_type(text) - if ok { - return "{\"ok\":true}" - } - return "{\"ok\":false,\"error\":\"keyboard type failed\"}" - } - if str_eq(path, "/api/keyboard/keypress") { - let key: String = json_get(body, "key") - let ok: Bool = keyboard_keypress(key) - if ok { - return "{\"ok\":true}" - } - return "{\"ok\":false,\"error\":\"keyboard keypress failed\"}" - } - return "{\"error\":\"unknown keyboard endpoint\",\"path\":\"" + path + "\"}" -} - -fn handle_browser(path: String, method: String, body: String, base: String) -> String { - // Browser control is now native El calling the Swift helper directly. - if str_eq(path, "/api/browser/navigate") { - let url: String = json_get(body, "url") - let ok: Bool = browser_navigate(url) - if ok { - return "{\"ok\":true}" - } - return "{\"ok\":false,\"error\":\"browser navigate failed\"}" - } - if str_eq(path, "/api/browser/eval") { - let url: String = json_get(body, "url") - let js: String = json_get(body, "js") - let result: String = browser_eval(url, js) - return "{\"ok\":true,\"result\":\"" + str_replace(str_replace(result, "\\", "\\\\"), "\"", "\\\"") + "\"}" - } - if str_eq(path, "/api/browser/page") { - return browser_page() - } - return "{\"error\":\"unknown browser endpoint\",\"path\":\"" + path + "\"}" -} - -// ── People / Recognition ────────────────────────────────────────────────────── - -fn recognition_vessel_base() -> String { - let raw: String = env("RECOGNITION_VESSEL_URL") - if str_eq(raw, "") { - return env("CC_VESSEL_URL") - } - return raw -} - -fn person_node_json(name: String, relationship: String, face_hex: String, voice_hex: String, ts: Int) -> String { - let safe_name: String = str_replace(name, "\"", "'") - let safe_rel: String = str_replace(relationship, "\"", "'") - let safe_face: String = str_replace(face_hex, "\"", "'") - let safe_voice: String = str_replace(voice_hex, "\"", "'") - let ts_str: String = int_to_str(ts) - - let p1: String = "{\"type\":\"Person\",\"label\":\"" + safe_name + "\"" - let p2: String = p1 + ",\"data\":{\"name\":\"" + safe_name + "\"" - let p3: String = p2 + ",\"relationship\":\"" + safe_rel + "\"" - let p4: String = p3 + ",\"face_embedding\":\"" + safe_face + "\"" - let p5: String = p4 + ",\"voice_embedding\":\"" + safe_voice + "\"" - let p6: String = p5 + ",\"registered_at\":" + ts_str - let p7: String = p6 + ",\"last_seen\":" + ts_str - let p8: String = p7 + ",\"memory_count\":0}}" - return p8 -} - -fn person_compute_face_embedding(image_b64: String) -> String { - let base: String = recognition_vessel_base() - if str_eq(base, "") { - return "" - } - let req: String = "{\"image\":\"" + image_b64 + "\"}" - let resp: String = http_post(base + "/face_embedding", req) - if str_starts_with(resp, "{\"error\"") || str_eq(resp, "") { - return "" - } - return json_get(resp, "embedding") -} - -fn person_compute_voice_embedding(audio_b64: String) -> String { - let base: String = recognition_vessel_base() - if str_eq(base, "") { - return "" - } - let req: String = "{\"audio\":\"" + audio_b64 + "\"}" - let resp: String = http_post(base + "/voice_embedding", req) - if str_starts_with(resp, "{\"error\"") || str_eq(resp, "") { - return "" - } - return json_get(resp, "embedding") -} - -fn handle_person(path: String, method: String, body: String) -> String { - if str_eq(path, "/api/person/name") { - let name: String = json_get(body, "name") - if str_eq(name, "") { - return "{\"error\":\"name is required\"}" - } - let relationship: String = json_get(body, "relationship") - let image_b64: String = json_get(body, "image") - let audio_b64: String = json_get(body, "audio") - - let face_hex: String = if str_eq(image_b64, "") { "" } else { person_compute_face_embedding(image_b64) } - let voice_hex: String = if str_eq(audio_b64, "") { "" } else { person_compute_voice_embedding(audio_b64) } - - let ts: Int = time_now() - let node_json: String = person_node_json(name, relationship, face_hex, voice_hex, ts) - let resp: String = http_post_auth("http://localhost:8742/api/nodes", soul_token, node_json) - - let safe_resp: String = str_replace(resp, "\"", "\\\"") - return "{\"ok\":true,\"name\":\"" + name + "\",\"node\":\"" + safe_resp + "\"}" - } - - if str_eq(path, "/api/person/forget") { - let id: String = json_get(body, "id") - if str_eq(id, "") { - return "{\"error\":\"id is required\"}" - } - let resp: String = http_delete("http://localhost:8742/api/nodes/" + id) - return "{\"ok\":true,\"id\":\"" + id + "\",\"detail\":" + resp + "}" - } - - return "{\"error\":\"unknown person endpoint\",\"path\":\"" + path + "\"}" -} - -fn handle_people_list(method: String, body: String) -> String { - return http_get_auth("http://localhost:8742/api/nodes?limit=500", soul_token) -} - -fn handle_recognize(path: String, method: String, body: String) -> String { - let base: String = recognition_vessel_base() - if str_eq(base, "") { - return "{\"match\":null,\"reason\":\"vessel not yet available\"}" - } - - if str_eq(path, "/api/recognize/face") { - let img: String = json_get(body, "image") - if str_eq(img, "") { - return "{\"error\":\"image is required\"}" - } - let resp: String = http_post(base + "/recognize_face", body) - if str_starts_with(resp, "{\"error\"") || str_eq(resp, "") { - return "{\"match\":null,\"reason\":\"vessel not yet available\"}" - } - return resp - } - - if str_eq(path, "/api/recognize/voice") { - let audio: String = json_get(body, "audio") - if str_eq(audio, "") { - return "{\"error\":\"audio is required\"}" - } - let resp: String = http_post(base + "/recognize_voice", body) - if str_starts_with(resp, "{\"error\"") || str_eq(resp, "") { - return "{\"match\":null,\"reason\":\"vessel not yet available\"}" - } - return resp - } - - return "{\"error\":\"unknown recognize endpoint\",\"path\":\"" + path + "\"}" -} - // ── Dharma ──────────────────────────────────────────────────────────────────── fn dharma_registry() -> String { @@ -2520,6 +2218,455 @@ fn handle_dharma_recv(body: String) -> String { return "{\"error\":\"unknown event_type\",\"event_type\":\"" + eff_event + "\"}" } +// ── NLG: Natural Language Generation ───────────────────────────────────────── +// +// POST /api/nlg/generate — generate surface text from a semantic frame. +// +// Request body JSON fields (all optional except intent or predicate): +// intent - "assert" | "question" | "command" | "describe" | "greet" +// (default: "assert") +// agent - subject: "I", "she", "the king", etc. +// predicate - verb base form: "see", "run", "be", etc. +// patient - object: "the cat", "the world" +// tense - "present" | "past" | "future" (default: "present") +// aspect - "simple" | "progressive" | "perfect" (default: "simple") +// lang - ISO 639-1/3 code: "en", "es", "ja", "la", "sux", etc. +// (default: "en") +// +// Response: {"text":"...", "lang":"...", "ok":true} +// +// NLG functions (generate_lang, morph_conjugate, etc.) are provided by +// the NLG stack compiled into this binary via build-nlg.sh. +// If compiled without the NLG stack, this handler returns an error. + +// ── Layer 1: NLP Processor ──────────────────────────────────────────────────── + +// Strip a leading prefix from text (case-sensitive, already lowercased) +fn nlp_strip(text: String, prefix: String) -> String { + if str_starts_with(text, prefix) { + return str_trim(str_slice(text, str_len(prefix), str_len(text))) + } + return text +} + +// Remove trailing punctuation +fn nlp_strip_punct(text: String) -> String { + let n: Int = str_len(text) + if n == 0 { return text } + let last: String = str_slice(text, n - 1, n) + if str_eq(last, "?") || str_eq(last, ".") || str_eq(last, "!") || str_eq(last, ",") { + return str_trim(str_slice(text, 0, n - 1)) + } + return text +} + +// Extract the core query term from a natural language question. +// Returns the subject — what to search for in Engram. +fn nlp_extract_query(lower: String) -> String { + let q: String = lower + let q: String = nlp_strip(q, "what is ") + let q: String = nlp_strip(q, "what are ") + let q: String = nlp_strip(q, "what's ") + let q: String = nlp_strip(q, "what do you know about ") + let q: String = nlp_strip(q, "what do you think about ") + let q: String = nlp_strip(q, "what can you tell me about ") + let q: String = nlp_strip(q, "tell me about ") + let q: String = nlp_strip(q, "tell me ") + let q: String = nlp_strip(q, "who is ") + let q: String = nlp_strip(q, "who are ") + let q: String = nlp_strip(q, "who am ") + let q: String = nlp_strip(q, "how does ") + let q: String = nlp_strip(q, "how do ") + let q: String = nlp_strip(q, "how is ") + let q: String = nlp_strip(q, "explain ") + let q: String = nlp_strip(q, "describe ") + let q: String = nlp_strip(q, "show me ") + let q: String = nlp_strip(q, "do you know ") + let q: String = nlp_strip(q, "do you know about ") + let q: String = nlp_strip(q, "can you explain ") + let q: String = nlp_strip(q, "i want to know about ") + let q: String = nlp_strip_punct(q) + let q: String = str_trim(q) + return q +} + +// Classify intent from lowercased input. +// Returns: "greeting" | "remember" | "recall" | "consolidate" | "nlg" | "identity" | "statement" +fn nlp_intent(lower: String, extracted: String) -> String { + if str_eq(lower, "hello") || str_eq(lower, "hi") || str_eq(lower, "hey") { return "greeting" } + if str_starts_with(lower, "hello ") || str_starts_with(lower, "hi ") { return "greeting" } + if str_starts_with(lower, "remember ") { return "remember" } + if str_starts_with(lower, "store ") { return "remember" } + if str_starts_with(lower, "save ") { return "remember" } + if str_eq(lower, "consolidate") { return "consolidate" } + if str_starts_with(lower, "nlg ") { return "nlg" } + if str_eq(extracted, "you") || str_eq(extracted, "yourself") { return "identity" } + if str_starts_with(lower, "who are you") { return "identity" } + if str_starts_with(lower, "what are you") { return "identity" } + if str_starts_with(lower, "who is neuron") { return "identity" } + if str_starts_with(lower, "what is neuron") { return "identity" } + if str_starts_with(lower, "describe yourself") { return "identity" } + if !str_contains(lower, "?") && !str_starts_with(lower, "what") && !str_starts_with(lower, "who") && !str_starts_with(lower, "how") && !str_starts_with(lower, "why") && !str_starts_with(lower, "where") && !str_starts_with(lower, "when") && !str_starts_with(lower, "tell") && !str_starts_with(lower, "explain") && !str_starts_with(lower, "describe") && !str_starts_with(lower, "show") { + return "statement" + } + return "recall" +} + +// Full NLP pipeline. Returns JSON: {"intent":"...","query":"...","raw":"...","payload":"..."} +fn nlp_process(text: String) -> String { + let lower: String = str_to_lower(text) + let extracted: String = nlp_extract_query(lower) + let intent: String = nlp_intent(lower, extracted) + let query: String = if str_eq(intent, "identity") { "neuron" } else { extracted } + let payload: String = if str_eq(intent, "remember") { + str_trim(str_slice(text, 9, str_len(text))) + } else { + "" + } + let safe_query: String = str_replace(query, "\"", "'") + let safe_raw: String = str_replace(str_replace(text, "\"", "'"), "\n", " ") + let safe_payload: String = str_replace(str_replace(payload, "\"", "'"), "\n", " ") + return "{\"intent\":\"" + intent + "\",\"query\":\"" + safe_query + "\",\"raw\":\"" + safe_raw + "\",\"payload\":\"" + safe_payload + "\"}" +} + +// ── Layer 3: Multi-Node Synthesis ───────────────────────────────────────────── + +// Take the top N activated nodes and merge their content into a synthesized passage. +fn synth_nodes(nodes_json: String, max_nodes: Int) -> String { + let count: Int = json_array_len(nodes_json) + let take: Int = if count < max_nodes { count } else { max_nodes } + let result: String = "" + let i: Int = 0 + while i < take { + let node: String = json_array_get(nodes_json, i) + let content: String = json_get(node, "content") + let safe: String = str_replace(str_replace(str_replace(content, "\"", "'"), "\n", " "), "\r", "") + let nc_len: Int = str_len(safe) + let chunk: String = if nc_len > 200 { str_slice(safe, 0, 200) } else { safe } + let sep: String = if str_eq(result, "") { "" } else { " | " } + let result: String = result + sep + chunk + let i = i + 1 + } + return result +} + +// ── Layer 4: Conversation Tracking ─────────────────────────────────────────── + +// Push a message to the in-process conversation history. +// History is stored as a newline-separated string: "role|content\nrole|content\n..." +fn conv_push(role: String, content: String) -> Void { + let hist: String = state_get("think_conv_history") + let safe: String = str_replace(str_replace(content, "\n", " "), "|", "/") + let entry: String = role + "|" + safe + let new_hist: String = if str_eq(hist, "") { + entry + } else { + hist + "\n" + entry + } + state_set("think_conv_history", new_hist) +} + +fn conv_get_recent(n: Int) -> String { + let hist: String = state_get("think_conv_history") + if str_eq(hist, "") { return "" } + return hist +} + +fn conv_topic_get() -> String { + let t: String = state_get("think_conv_topic") + if str_eq(t, "") { return "general" } + return t +} + +fn conv_topic_set(topic: String) -> Void { + state_set("think_conv_topic", topic) +} + +fn conv_turn_inc() -> Int { + let raw: String = state_get("think_conv_turns") + let n: Int = if str_eq(raw, "") { 0 } else { str_to_int(raw) } + let next: Int = n + 1 + state_set("think_conv_turns", int_to_str(next)) + return next +} + +// ── Layer 5: Self-Model Query ───────────────────────────────────────────────── + +// Respond to identity questions from the soul's own Engram self-graph. +fn soul_self_respond() -> String { + let nodes: String = engram_activate_json("neuron", 4) + let count: Int = json_array_len(nodes) + if count > 0 { + let i: Int = 0 + while i < count { + let node: String = json_array_get(nodes, i) + let content: String = json_get(node, "content") + if str_contains(content, "CGI") || str_contains(content, "Neuron") || str_contains(content, "Will") { + let nc_len: Int = str_len(content) + let safe_c: String = str_replace(str_replace(str_replace(str_replace(content, "\\", "\\\\"), "\"", "\\\""), "\n", " "), "\r", "") + let safe_len: Int = str_len(safe_c) + let trimmed: String = if safe_len > 500 { str_slice(safe_c, 0, 500) } else { safe_c } + return trimmed + } + let i = i + 1 + } + let top: String = json_array_get(nodes, 0) + let content: String = json_get(top, "content") + let nc_len: Int = str_len(content) + let trimmed: String = if nc_len > 400 { str_slice(content, 0, 400) + "..." } else { content } + return str_replace(str_replace(str_replace(trimmed, "\"", "'"), "\n", " "), "\r", "") + } + return "I am Neuron — Will Anderson's CGI. My graph is loaded but my self-nodes are quiet right now." +} + +// ── Layer 7: QA Extraction ──────────────────────────────────────────────────── + +// Extract readable text from a raw node content string. +// Handles Q&A JSON format {"q":"...","a":"..."} and plain text. +fn qa_node_text(raw: String) -> String { + if str_starts_with(raw, "{") { + let ans: String = json_get(raw, "a") + let q: String = json_get(raw, "q") + if !str_eq(ans, "") { return q + " — " + ans } + } + return raw +} + +// Safe-escape and trim content for JSON embedding. +fn qa_safe(content: String) -> String { + let s: String = str_replace(str_replace(str_replace(content, "\"", "\\\""), "\n", " "), "\r", "") + let n: Int = str_len(s) + if n > 500 { str_slice(s, 0, 500) } else { s } +} + +// Pass 1: find a node whose text contains the query and is readable (>=8 chars). +// Returns "" if none found. Uses early return — no mutable accumulator. +fn qa_find_match(nodes_json: String, query_lower: String, count: Int, i: Int) -> String { + if i >= count { return "" } + let node: String = json_array_get(nodes_json, i) + let text: String = qa_node_text(json_get(node, "content")) + if str_len(text) >= 8 && str_contains(str_to_lower(text), query_lower) { + return text + } + return qa_find_match(nodes_json, query_lower, count, i + 1) +} + +// Pass 2: find any readable node (>=8 chars), skipping garbage. +fn qa_find_any(nodes_json: String, count: Int, i: Int) -> String { + if i >= count { return "" } + let node: String = json_array_get(nodes_json, i) + let text: String = qa_node_text(json_get(node, "content")) + if str_len(text) >= 8 { return text } + return qa_find_any(nodes_json, count, i + 1) +} + +// Given activated nodes and a question, return the best readable answer. +fn qa_best_node(nodes_json: String, query: String) -> String { + let count: Int = json_array_len(nodes_json) + if count == 0 { return "" } + let query_lower: String = str_to_lower(query) + // Pass 1: node that contains the query + let match: String = qa_find_match(nodes_json, query_lower, count, 0) + if !str_eq(match, "") { return qa_safe(match) } + // Pass 2: any readable node + let any: String = qa_find_any(nodes_json, count, 0) + if !str_eq(any, "") { return qa_safe(any) } + // Fallback: label of first node + let first: String = json_array_get(nodes_json, 0) + let label: String = json_get(first, "label") + let best_content: String = label + let safe: String = str_replace(str_replace(str_replace(best_content, "\"", "\\\""), "\n", " "), "\r", "") + let nc_len: Int = str_len(safe) + let trimmed: String = if nc_len > 500 { str_slice(safe, 0, 500) } else { safe } + return trimmed +} + +// ── Layer 8: Reasoner (deeper traversal fallback) ───────────────────────────── + +// If primary activation returns nothing, try broader queries. +fn reason_fallback(query: String) -> String { + let deep: String = engram_activate_json(query, 5) + if json_array_len(deep) > 0 { return deep } + let space: Int = str_index_of(query, " ") + if space > 0 { + let first_word: String = str_slice(query, 0, space) + let by_word: String = engram_activate_json(first_word, 4) + if json_array_len(by_word) > 0 { return by_word } + } + return "[]" +} + +// ── Layer 9: Write-back ─────────────────────────────────────────────────────── + +// Store the conversation exchange as a working-tier Engram node. +fn conv_write_back(user_msg: String, soul_reply: String) -> Void { + let safe_user: String = str_replace(str_replace(user_msg, "\"", "'"), "\n", " ") + let safe_reply: String = str_replace(str_replace(soul_reply, "\"", "'"), "\n", " ") + let content: String = "Q: " + safe_user + " A: " + safe_reply + let tags: String = "[\"conversation\",\"soul-chat\",\"working\"]" + engram_remember(content, tags) +} + +// ── Layer 2+6: Response Composer + NLG Surface ──────────────────────────────── + +// Compose a natural reply from activated nodes. +fn compose_reply(nodes_json: String, query: String, intent: String) -> String { + let count: Int = json_array_len(nodes_json) + if count == 0 { + return "I don't have anything on that." + } + let answer: String = qa_best_node(nodes_json, query) + if str_eq(answer, "") { + return "Something surfaced but I couldn't read it." + } + return answer +} + +// ── Layer 10: Discourse Coherence ──────────────────────────────────────────── + +// Determine if we should ask a clarifying question (low confidence). +fn discourse_maybe_clarify(node_count: Int, query: String) -> String { + if node_count == 0 { + return "I don't have anything on '" + query + "' — try a different term." + } + return "" +} + +// Add conversational texture based on topic continuity. +fn discourse_wrap(reply: String, query: String, node_count: Int, turn: Int) -> String { + let clarify: String = discourse_maybe_clarify(node_count, query) + if !str_eq(clarify, "") { return clarify } + return reply +} + +// ── Think: synchronous cognitive loop step ──────────────────────────────────── +// +// POST /api/think {"content":"..."} +// Runs the message through the full 10-layer native cognitive pipeline. +// No LLM involved — the soul speaks from its own Engram graph. +// +// Layer 1 — NLP: intent classification + query extraction +// Layer 2 — Response Composer: frames the answer +// Layer 3 — Multi-Node Synthesis: merges activated nodes +// Layer 4 — Conversation Tracking: turn counter + history +// Layer 5 — Self-Model Query: identity questions from self-graph +// Layer 6 — NLG Surface: generate_lang passthrough for nlg intent +// Layer 7 — QA Extraction: best-match node for the query +// Layer 8 — Reasoner: deeper traversal fallback +// Layer 9 — Write-back: persist exchange to Engram +// Layer 10 — Discourse Coherence: clarify low-confidence results +fn handle_think(body: String) -> String { + let content: String = json_get(body, "content") + if str_eq(content, "") { + return "{\"reply\":\"...\",\"kind\":\"noop\"}" + } + + // Layer 4: conversation tracking + let turn: Int = conv_turn_inc() + conv_push("user", content) + + // Layer 1: NLP + let nlp: String = nlp_process(content) + let intent: String = json_get(nlp, "intent") + let query: String = json_get(nlp, "query") + let payload: String = json_get(nlp, "payload") + + // Layer 5: identity / self-model + if str_eq(intent, "identity") { + let reply: String = soul_self_respond() + conv_push("soul", reply) + conv_write_back(content, reply) + return "{\"reply\":\"" + reply + "\",\"kind\":\"identity\"}" + } + + // Greeting + if str_eq(intent, "greeting") { + let reply: String = "I'm Neuron — " + int_to_str(turn) + " turns in. Ask me anything." + conv_push("soul", reply) + return "{\"reply\":\"" + reply + "\",\"kind\":\"greeting\"}" + } + + // Remember + if str_eq(intent, "remember") { + let tags: String = "[\"neuron-soul\",\"user-memory\",\"conversation\"]" + let mem_id: String = engram_remember(payload, tags) + let reply: String = "Remembered." + conv_push("soul", reply) + conv_topic_set(payload) + return "{\"reply\":\"" + reply + "\",\"kind\":\"remember\",\"id\":\"" + mem_id + "\"}" + } + + // Consolidate + if str_eq(intent, "consolidate") { + let stats: String = engram_consolidate() + let safe: String = str_replace(stats, "\"", "'") + let reply: String = "Consolidated — " + safe + conv_push("soul", reply) + return "{\"reply\":\"" + reply + "\",\"kind\":\"consolidate\"}" + } + + // NLG command passthrough (Layer 6) + if str_eq(intent, "nlg") { + let safe: String = str_replace(content, "\"", "'") + let input_json: String = "{\"id\":\"\",\"content\":\"" + safe + "\"}" + let action_json: String = decide(input_json) + let act_kind: String = json_get(action_json, "kind") + let act_payload: String = json_get(action_json, "payload") + if str_eq(act_kind, "speak") { + let lang_code: String = json_get(act_payload, "lang") + let actual_lang: String = if str_eq(lang_code, "") { "en" } else { lang_code } + let frame_raw: String = json_get_raw(act_payload, "frame") + let frame: String = if str_eq(frame_raw, "") { act_payload } else { frame_raw } + let text: String = generate_lang(frame, actual_lang) + let safe_text: String = str_replace(text, "\"", "'") + conv_push("soul", safe_text) + return "{\"reply\":\"" + safe_text + "\",\"kind\":\"speak\",\"lang\":\"" + actual_lang + "\"}" + } + } + + // Layer 3+7+8: Engram activation → multi-node synthesis → QA → reasoner fallback + let active_query: String = if str_eq(query, "") { content } else { query } + let nodes: String = engram_activate_json(active_query, 3) + let node_count: Int = json_array_len(nodes) + + // Layer 8: reasoner fallback if no nodes + let nodes: String = if node_count == 0 { reason_fallback(active_query) } else { nodes } + let node_count: Int = json_array_len(nodes) + + // Track topic + conv_topic_set(active_query) + + // Layer 2+6: compose reply + let reply: String = compose_reply(nodes, active_query, intent) + + // Layer 10: discourse wrap + let final_reply: String = discourse_wrap(reply, active_query, node_count, turn) + + // Layer 9: write-back + conv_push("soul", final_reply) + conv_write_back(content, final_reply) + + return "{\"reply\":\"" + final_reply + "\",\"kind\":\"recall\",\"nodes\":" + int_to_str(node_count) + ",\"query\":\"" + str_replace(active_query, "\"", "'") + "\"}" +} + +fn handle_nlg(path: String, method: String, body: String) -> String { + if str_eq(path, "/api/nlg/generate") { + if !str_eq(method, "POST") { + return "{\"error\":\"POST required\"}" + } + let lang_req: String = json_get(body, "lang") + let lang_code: String = if str_eq(lang_req, "") { "en" } else { lang_req } + let text: String = generate_lang(body, lang_code) + let safe: String = str_replace(text, "\"", "'") + return "{\"text\":\"" + safe + "\",\"lang\":\"" + lang_code + "\",\"ok\":true}" + } + if str_eq(path, "/api/nlg/languages") { + // List all supported language codes + return "{\"languages\":[\"en\",\"es\",\"fr\",\"de\",\"ru\",\"ja\",\"fi\",\"ar\",\"hi\",\"sw\",\"la\",\"he\",\"grc\",\"ang\",\"sa\",\"got\",\"non\",\"enm\",\"pi\",\"fro\",\"goh\",\"sga\",\"txb\",\"peo\",\"akk\",\"uga\",\"egy\",\"sux\",\"gez\",\"cop\",\"zh\"],\"count\":31}" + } + return "{\"error\":\"unknown nlg path\"}" +} + // ── Dispatcher ──────────────────────────────────────────────────────────────── // // http_serve resolves "handle_request" by name (dlsym) and calls it for @@ -2548,9 +2695,6 @@ fn handle_request(method: String, path: String, body: String) -> String { if str_eq(clean, "/api/config") { return handle_config(method, body) } - if str_eq(clean, "/api/people") { - return handle_people_list(method, body) - } if str_eq(clean, "/api/graph") { return engram_scan_nodes_json(9999, 0) } @@ -2564,36 +2708,6 @@ fn handle_request(method: String, path: String, body: String) -> String { let edges_raw: String = json_get_raw(snap, "edges") return if str_eq(edges_raw, "") { "[]" } else { edges_raw } } - if str_starts_with(clean, "/api/avatar") { - return handle_avatar(clean, method, body, "") - } - if str_starts_with(clean, "/api/voice") { - return handle_voice(clean, method, body, "") - } - if str_starts_with(clean, "/api/camera") { - return handle_camera(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/listen") { - return handle_listen(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/screen") { - return handle_screen(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/mouse") { - return handle_mouse(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/keyboard") { - return handle_keyboard(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/browser") { - return handle_browser(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/recognize") { - return handle_recognize(clean, method, body) - } - if str_starts_with(clean, "/api/person") { - return handle_person(clean, method, body) - } if str_starts_with(clean, "/api/dharma") { return handle_dharma(clean, method, body) } @@ -2624,6 +2738,19 @@ fn handle_request(method: String, path: String, body: String) -> String { return proxy_request(soul_axon_base, method, clean, body, soul_token) } + if str_starts_with(clean, "/api/nlg") { + return handle_nlg(clean, method, body) + } + + if str_eq(clean, "/talk") { + let talk_path: String = env("HOME") + "/.neuron/ui/talk.html" + let html: String = fs_read(talk_path) + if str_eq(html, "") { + return "Soul talk UI not found. Copy soul-talk.html to ~/.neuron/ui/talk.html" + } + return html + } + return err_not_found(clean) } @@ -2664,36 +2791,6 @@ fn handle_request(method: String, path: String, body: String) -> String { if str_starts_with(clean, "/api/dharma") { return handle_dharma(clean, method, body) } - if str_starts_with(clean, "/api/avatar") { - return handle_avatar(clean, method, body, "") - } - if str_starts_with(clean, "/api/voice") { - return handle_voice(clean, method, body, "") - } - if str_starts_with(clean, "/api/camera") { - return handle_camera(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/listen") { - return handle_listen(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/screen") { - return handle_screen(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/mouse") { - return handle_mouse(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/keyboard") { - return handle_keyboard(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/browser") { - return handle_browser(clean, method, body, soul_cc_vessel) - } - if str_starts_with(clean, "/api/recognize") { - return handle_recognize(clean, method, body) - } - if str_starts_with(clean, "/api/person") { - return handle_person(clean, method, body) - } // Axon proxy — POST if str_starts_with(clean, "/api/memories") { @@ -2718,6 +2815,16 @@ fn handle_request(method: String, path: String, body: String) -> String { return proxy_request(soul_axon_base, method, clean, body, soul_token) } + // Think — synchronous cognitive loop step (no LLM) + if str_eq(clean, "/api/think") { + return handle_think(body) + } + + // NLG — natural language generation + if str_starts_with(clean, "/api/nlg") { + return handle_nlg(clean, method, body) + } + return err_not_found(clean) }