diff --git a/awareness.el b/awareness.el index 3d69e40..a3a5432 100644 --- a/awareness.el +++ b/awareness.el @@ -219,15 +219,32 @@ fn proactive_curiosity() -> Bool { // str_find_chars finds the first space/colon/bracket delimiter. sp > 3 guards against // very short or bracket-prefixed labels like "[BacklogItem]" (sp=0, not > 3 → skipped). // EL scoping: state_set/state_get pattern used because let inside if creates inner scope. - // (2026-06-11 self-review) + // + // NODE TYPE FILTER (2026-06-19 self-review): only derive auto_term from Memory, + // BacklogItem, or Entity nodes. Knowledge nodes are stable reference material — + // using their first word as a curiosity seed creates a self-reinforcing loop: e.g. + // "Numeric tier strings in Engram..." (a Knowledge node) -> auto_term="Numeric" -> + // activates all "Numeric" nodes -> keeps that Knowledge node dominant in WM forever. + // Knowledge nodes should be REACHED by curiosity seeds, not drive them. Only dynamic + // personal/work nodes (Memory, BacklogItem, Entity) carry live contextual salience + // worth radiating from. (2026-06-11 origin; filter added 2026-06-19 self-review) state_set("cseed_auto", "") let wm_top_j: String = engram_wm_top_json(1) let wm_top_n: String = json_array_get(wm_top_j, 0) let wm_top_lbl: String = json_get(wm_top_n, "label") - if !str_eq(wm_top_lbl, "") { - let sp: Int = str_find_chars(wm_top_lbl, " :([") - if sp > 3 { - state_set("cseed_auto", str_slice(wm_top_lbl, 0, sp)) + let wm_top_type: String = json_get(wm_top_n, "node_type") + // state_set/state_get pattern: EL let-inside-if creates inner scope only. + state_set("allow_auto", "0") + if str_eq(wm_top_type, "Memory") { state_set("allow_auto", "1") } + if str_eq(wm_top_type, "BacklogItem") { state_set("allow_auto", "1") } + if str_eq(wm_top_type, "Entity") { state_set("allow_auto", "1") } + let allow_auto: String = state_get("allow_auto") + if str_eq(allow_auto, "1") { + if !str_eq(wm_top_lbl, "") { + let sp: Int = str_find_chars(wm_top_lbl, " :([") + if sp > 3 { + state_set("cseed_auto", str_slice(wm_top_lbl, 0, sp)) + } } } let auto_term: String = state_get("cseed_auto") diff --git a/dist/awareness.c b/dist/awareness.c index a6fd49c..f978f5e 100644 --- a/dist/awareness.c +++ b/dist/awareness.c @@ -285,10 +285,24 @@ el_val_t proactive_curiosity(void) { el_val_t wm_top_j = engram_wm_top_json(1); el_val_t wm_top_n = json_array_get(wm_top_j, 0); el_val_t wm_top_lbl = json_get(wm_top_n, EL_STR("label")); - if (!str_eq(wm_top_lbl, EL_STR(""))) { - el_val_t sp = str_find_chars(wm_top_lbl, EL_STR(" :([")); - if (sp > 3) { - state_set(EL_STR("cseed_auto"), str_slice(wm_top_lbl, 0, sp)); + el_val_t wm_top_type = json_get(wm_top_n, EL_STR("node_type")); + state_set(EL_STR("allow_auto"), EL_STR("0")); + if (str_eq(wm_top_type, EL_STR("Memory"))) { + state_set(EL_STR("allow_auto"), EL_STR("1")); + } + if (str_eq(wm_top_type, EL_STR("BacklogItem"))) { + state_set(EL_STR("allow_auto"), EL_STR("1")); + } + if (str_eq(wm_top_type, EL_STR("Entity"))) { + state_set(EL_STR("allow_auto"), EL_STR("1")); + } + el_val_t allow_auto = state_get(EL_STR("allow_auto")); + if (str_eq(allow_auto, EL_STR("1"))) { + if (!str_eq(wm_top_lbl, EL_STR(""))) { + el_val_t sp = str_find_chars(wm_top_lbl, EL_STR(" :([")); + if (sp > 3) { + state_set(EL_STR("cseed_auto"), str_slice(wm_top_lbl, 0, sp)); + } } } el_val_t auto_term = state_get(EL_STR("cseed_auto")); diff --git a/dist/neuron.c b/dist/neuron.c index dcd6d2e..9d55a31 100644 --- a/dist/neuron.c +++ b/dist/neuron.c @@ -1042,12 +1042,36 @@ el_val_t call_neuron_mcp(el_val_t tool_name, el_val_t args_json); el_val_t agentic_tools_literal(void); el_val_t agentic_tools_with_web(void); el_val_t dispatch_tool(el_val_t tool_name, el_val_t tool_input); +el_val_t json_array_append(el_val_t arr, el_val_t item); +el_val_t append_tool_log(el_val_t log, el_val_t name); +el_val_t exec_tool_block(el_val_t block); +el_val_t agentic_blob(el_val_t model, el_val_t system, el_val_t tools_json, el_val_t messages, el_val_t origin, el_val_t approval, el_val_t iteration, el_val_t tools_log, el_val_t content, el_val_t queue, el_val_t results, el_val_t next); +el_val_t extract_all_text(el_val_t s); +el_val_t strip_citations(el_val_t s); +el_val_t agentic_api_turn(el_val_t model, el_val_t safe_sys, el_val_t tools_json, el_val_t messages); +el_val_t agentic_engine(el_val_t session_id, el_val_t blob); el_val_t handle_chat_agentic(el_val_t body); +el_val_t handle_session_approve(el_val_t session_id, el_val_t body); el_val_t handle_chat_as_soul(el_val_t body); el_val_t handle_dharma_room_turn(el_val_t body); el_val_t handle_dharma_room_turn_agentic(el_val_t body); el_val_t auto_persist(el_val_t req, el_val_t resp); el_val_t strengthen_chat_nodes(el_val_t activation_nodes); +el_val_t safety_self_harm_phrases(void); +el_val_t safety_abuse_phrases(void); +el_val_t safety_general_hard_phrases(void); +el_val_t safety_soft_phrases(void); +el_val_t safety_normalize(el_val_t message); +el_val_t safety_any_match(el_val_t text, el_val_t phrases_json); +el_val_t safety_count_match(el_val_t text, el_val_t phrases_json); +el_val_t safety_detect_bell_level(el_val_t message); +el_val_t safety_classify_hard_bell(el_val_t message); +el_val_t safety_soft_directive(void); +el_val_t safety_hard_directive(el_val_t hard_type); +el_val_t safety_augment_system(el_val_t system, el_val_t user_msg); +el_val_t safety_contact_path(void); +el_val_t handle_safety_contact_get(void); +el_val_t handle_safety_contact_post(el_val_t body); el_val_t auth_headers(el_val_t tok); el_val_t axon_get(el_val_t path); el_val_t axon_post(el_val_t path, el_val_t body); @@ -1110,6 +1134,7 @@ el_val_t session_update_meta_timestamp(el_val_t session_id); el_val_t session_auto_title(el_val_t session_id, el_val_t first_message); el_val_t handle_session_approve(el_val_t session_id, el_val_t body); el_val_t strip_query(el_val_t path); +el_val_t flag_true(el_val_t body, el_val_t key); el_val_t err_404(el_val_t path); el_val_t err_405(el_val_t method, el_val_t path); el_val_t route_health(void); @@ -1144,6 +1169,9 @@ el_val_t local_node_count; el_val_t snapshot_usable; el_val_t boot_num; el_val_t is_genesis; +el_val_t guard_disk; +el_val_t guard_disk_len; +el_val_t safe_to_seed; el_val_t lang_profile(el_val_t code, el_val_t word_order, el_val_t morph_type, el_val_t has_case, el_val_t has_gender, el_val_t script_dir, el_val_t agreement, el_val_t null_subject) { el_val_t r = native_list_empty(); @@ -25890,14 +25918,28 @@ el_val_t proactive_curiosity(void) { el_val_t wm_top_j = engram_wm_top_json(1); el_val_t wm_top_n = json_array_get(wm_top_j, 0); el_val_t wm_top_lbl = json_get(wm_top_n, EL_STR("label")); - if (!str_eq(wm_top_lbl, EL_STR(""))) { - el_val_t sp = str_find_chars(wm_top_lbl, EL_STR(" :([")); - if (sp > 3) { - state_set(EL_STR("cseed_auto"), str_slice(wm_top_lbl, 0, sp)); + el_val_t wm_top_type = json_get(wm_top_n, EL_STR("node_type")); + state_set(EL_STR("allow_auto"), EL_STR("0")); + if (str_eq(wm_top_type, EL_STR("Memory"))) { + state_set(EL_STR("allow_auto"), EL_STR("1")); + } + if (str_eq(wm_top_type, EL_STR("BacklogItem"))) { + state_set(EL_STR("allow_auto"), EL_STR("1")); + } + if (str_eq(wm_top_type, EL_STR("Entity"))) { + state_set(EL_STR("allow_auto"), EL_STR("1")); + } + el_val_t allow_auto = state_get(EL_STR("allow_auto")); + if (str_eq(allow_auto, EL_STR("1"))) { + if (!str_eq(wm_top_lbl, EL_STR(""))) { + el_val_t sp = str_find_chars(wm_top_lbl, EL_STR(" :([")); + if (sp > 3) { + state_set(EL_STR("cseed_auto"), str_slice(wm_top_lbl, 0, sp)); + } } } el_val_t auto_term = state_get(EL_STR("cseed_auto")); - el_val_t results_auto = ({ el_val_t _if_result_101 = 0; if (str_eq(auto_term, EL_STR(""))) { _if_result_101 = (EL_STR("[]")); } else { _if_result_101 = (engram_activate_json(auto_term, 1)); } _if_result_101; }); + el_val_t results_auto = ({ el_val_t _if_result_3 = 0; if (str_eq(auto_term, EL_STR(""))) { _if_result_3 = (EL_STR("[]")); } else { _if_result_3 = (engram_activate_json(auto_term, 1)); } _if_result_3; }); el_val_t found_auto = json_array_len(results_auto); el_val_t total_found = (found + found_auto); el_val_t safe_auto = str_replace(auto_term, EL_STR("\""), EL_STR("'")); @@ -25908,6 +25950,7 @@ el_val_t proactive_curiosity(void) { return 0; } + el_val_t pulse_count(void) { el_val_t s = state_get(EL_STR("soul.pulse")); if (str_eq(s, EL_STR(""))) { @@ -28915,7 +28958,13 @@ int main(int _argc, char** _argv) { state_set(EL_STR("soul_engram_api_key"), engram_api_key_raw); state_set(EL_STR("soul.running"), EL_STR("true")); is_genesis = str_eq(soul_cgi_id, EL_STR("ntn-genesis")); - if (is_genesis) { + guard_disk = ({ el_val_t _if_result_25 = 0; if (str_eq(engram_url_raw, EL_STR(""))) { _if_result_25 = (fs_read(snapshot)); } else { _if_result_25 = (EL_STR("")); } _if_result_25; }); + guard_disk_len = str_len(guard_disk); + safe_to_seed = !((guard_disk_len > 200000) && (engram_node_count() < (guard_disk_len / 16000))); + if (is_genesis && !safe_to_seed) { + println(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("[soul] GUARD: loaded "), int_to_str(engram_node_count())), EL_STR(" nodes but snapshot file is ")), int_to_str(guard_disk_len)), EL_STR(" bytes \xe2\x80\x94 refusing to seed/save over a real graph"))); + } + if (is_genesis && safe_to_seed) { el_val_t edge_count_now = engram_edge_count(); if (edge_count_now < 100) { init_soul_edges(); @@ -28926,7 +28975,7 @@ int main(int _argc, char** _argv) { state_set(EL_STR("soul_snapshot_path"), snapshot); engram_save(snapshot); } - if (is_genesis) { + if (is_genesis && safe_to_seed) { el_val_t snap = state_get(EL_STR("soul_snapshot_path")); if (!str_eq(snap, EL_STR(""))) { engram_save(snap);