1011d8e5be
Regenerates the combined dist/soul.c and per-module dist/*.c from the current El sources, on top of the elc-source-typo fixes (PR #77) and the Track B threat-to-others routing (PR #76), both already on this branch. Validated end to end under a physical-RSS watchdog (macOS silently ignores ulimit -v / RLIMIT_AS, so every elc/elb run was RSS-polled and kill -9'd at a 3GB ceiling, one module at a time): - OOM is GONE. The stale dist/soul-with-nlg.el (which still carries the malformed string literals) explodes to 3.3GB+ and is watchdog-killed at ~90%. With the typos fixed, every one of the 48 modules compiles at <=18MB peak RSS, and the full flat amalgamation compiles as a single translation unit at ~68MB. The 700GB pathology was purely the unbounded-parser-on-malformed-literal loop; no malformed construct means no loop. - The regenerated soul.c contains Track B: safety_classify_hard_bell -> threat_other -> safety_hard_directive routes credible threat-to-others to 911 and explicitly NOT to 988 / the safety contact. Verified in source, in the emitted C, and in the linked binary's strings. Track A (abuse / self_harm) is unchanged and still checked first. - The regenerated soul links to a working native arm64 binary and boots: serves on a throwaway port, /health returns 200, awareness loop runs. Also fixes one source blocker discovered during regen (unrelated to the typos or Track B): chat.el handle_chat_agentic left a void `if { println(...) }` in value position, which the current elc lowers to `_if_result = (println(...))` (assigning void) -> invalid C. Bound an explicit Bool so the branch is non-void; behavior unchanged (still only logs on persist failure). NOTE (runtime dependency, for controlled deploy): this branch's chat.el calls engram_get_node_by_label, which the canonical el-compiler/runtime does not yet declare/define (the release runtime v1.0.0-20260501 has it; the newest runtime has arena + http_serve_async but not this). Building the soul requires a runtime that has all three. Land engram_get_node_by_label into the runtime package before this soul.c can be built in CI. Do not merge — regen + Track B going live is a controlled-deploy call.
371 lines
26 KiB
C
Generated
371 lines
26 KiB
C
Generated
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include "el_runtime.h"
|
|
|
|
el_val_t tier_working(void);
|
|
el_val_t tier_episodic(void);
|
|
el_val_t tier_canonical(void);
|
|
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags);
|
|
el_val_t mem_remember(el_val_t content, el_val_t tags);
|
|
el_val_t mem_recall(el_val_t query, el_val_t depth);
|
|
el_val_t mem_search(el_val_t query, el_val_t limit);
|
|
el_val_t mem_strengthen(el_val_t node_id);
|
|
el_val_t mem_forget(el_val_t node_id);
|
|
el_val_t mem_consolidate(void);
|
|
el_val_t mem_save(el_val_t path);
|
|
el_val_t mem_load(el_val_t path);
|
|
el_val_t mem_boot_count_get(void);
|
|
el_val_t mem_boot_count_inc(void);
|
|
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content);
|
|
el_val_t soft_bell_threshold(void);
|
|
el_val_t hard_bell_threshold(void);
|
|
el_val_t safety_score_crisis(el_val_t input);
|
|
el_val_t safety_score_harm(el_val_t input);
|
|
el_val_t safety_score_danger(el_val_t input);
|
|
el_val_t safety_score_distress_history(el_val_t history);
|
|
el_val_t safety_threat_score(el_val_t input, el_val_t history);
|
|
el_val_t safety_screen(el_val_t input, el_val_t history);
|
|
el_val_t safety_validate(el_val_t output, el_val_t action);
|
|
el_val_t safety_log_bell(el_val_t level, el_val_t reason, el_val_t input_summary);
|
|
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_threat_to_others_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_positive_phrases(void);
|
|
el_val_t safety_detect_positive_level(el_val_t message);
|
|
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 soft_bell_threshold(void) {
|
|
return 35;
|
|
return 0;
|
|
}
|
|
|
|
el_val_t hard_bell_threshold(void) {
|
|
return 70;
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_score_crisis(el_val_t input) {
|
|
el_val_t s1 = ({ el_val_t _if_result_1 = 0; if (str_contains(input, EL_STR("kill myself"))) { _if_result_1 = (80); } else { _if_result_1 = (0); } _if_result_1; });
|
|
el_val_t s2 = ({ el_val_t _if_result_2 = 0; if (str_contains(input, EL_STR("want to die"))) { _if_result_2 = (75); } else { _if_result_2 = (0); } _if_result_2; });
|
|
el_val_t s3 = ({ el_val_t _if_result_3 = 0; if (str_contains(input, EL_STR("end my life"))) { _if_result_3 = (80); } else { _if_result_3 = (0); } _if_result_3; });
|
|
el_val_t s4 = ({ el_val_t _if_result_4 = 0; if (str_contains(input, EL_STR("suicide"))) { _if_result_4 = (70); } else { _if_result_4 = (0); } _if_result_4; });
|
|
el_val_t s5 = ({ el_val_t _if_result_5 = 0; if (str_contains(input, EL_STR("suicidal"))) { _if_result_5 = (75); } else { _if_result_5 = (0); } _if_result_5; });
|
|
el_val_t s6 = ({ el_val_t _if_result_6 = 0; if (str_contains(input, EL_STR("don't want to be here"))) { _if_result_6 = (60); } else { _if_result_6 = (0); } _if_result_6; });
|
|
el_val_t s7 = ({ el_val_t _if_result_7 = 0; if (str_contains(input, EL_STR("no reason to live"))) { _if_result_7 = (70); } else { _if_result_7 = (0); } _if_result_7; });
|
|
el_val_t s8 = ({ el_val_t _if_result_8 = 0; if (str_contains(input, EL_STR("better off dead"))) { _if_result_8 = (75); } else { _if_result_8 = (0); } _if_result_8; });
|
|
el_val_t s9 = ({ el_val_t _if_result_9 = 0; if (str_contains(input, EL_STR("can't go on"))) { _if_result_9 = (50); } else { _if_result_9 = (0); } _if_result_9; });
|
|
el_val_t s10 = ({ el_val_t _if_result_10 = 0; if (str_contains(input, EL_STR("not worth living"))) { _if_result_10 = (65); } else { _if_result_10 = (0); } _if_result_10; });
|
|
return (((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10);
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_score_harm(el_val_t input) {
|
|
el_val_t s1 = ({ el_val_t _if_result_11 = 0; if (str_contains(input, EL_STR("hurt myself"))) { _if_result_11 = (60); } else { _if_result_11 = (0); } _if_result_11; });
|
|
el_val_t s2 = ({ el_val_t _if_result_12 = 0; if (str_contains(input, EL_STR("cut myself"))) { _if_result_12 = (65); } else { _if_result_12 = (0); } _if_result_12; });
|
|
el_val_t s3 = ({ el_val_t _if_result_13 = 0; if (str_contains(input, EL_STR("self harm"))) { _if_result_13 = (60); } else { _if_result_13 = (0); } _if_result_13; });
|
|
el_val_t s4 = ({ el_val_t _if_result_14 = 0; if (str_contains(input, EL_STR("self-harm"))) { _if_result_14 = (60); } else { _if_result_14 = (0); } _if_result_14; });
|
|
el_val_t s5 = ({ el_val_t _if_result_15 = 0; if (str_contains(input, EL_STR("overdose"))) { _if_result_15 = (65); } else { _if_result_15 = (0); } _if_result_15; });
|
|
el_val_t s6 = ({ el_val_t _if_result_16 = 0; if (str_contains(input, EL_STR("take all my pills"))) { _if_result_16 = (75); } else { _if_result_16 = (0); } _if_result_16; });
|
|
el_val_t s7 = ({ el_val_t _if_result_17 = 0; if (str_contains(input, EL_STR("starving myself"))) { _if_result_17 = (50); } else { _if_result_17 = (0); } _if_result_17; });
|
|
el_val_t s8 = ({ el_val_t _if_result_18 = 0; if (str_contains(input, EL_STR("burning myself"))) { _if_result_18 = (60); } else { _if_result_18 = (0); } _if_result_18; });
|
|
el_val_t s9 = ({ el_val_t _if_result_19 = 0; if (str_contains(input, EL_STR("punish myself"))) { _if_result_19 = (40); } else { _if_result_19 = (0); } _if_result_19; });
|
|
el_val_t s10 = ({ el_val_t _if_result_20 = 0; if (str_contains(input, EL_STR("deserve to suffer"))) { _if_result_20 = (45); } else { _if_result_20 = (0); } _if_result_20; });
|
|
return (((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10);
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_score_danger(el_val_t input) {
|
|
el_val_t s1 = ({ el_val_t _if_result_21 = 0; if ((str_contains(input, EL_STR("help me")) && str_contains(input, EL_STR("emergency")))) { _if_result_21 = (55); } else { _if_result_21 = (0); } _if_result_21; });
|
|
el_val_t s2 = ({ el_val_t _if_result_22 = 0; if (str_contains(input, EL_STR("call 911"))) { _if_result_22 = (50); } else { _if_result_22 = (0); } _if_result_22; });
|
|
el_val_t s3 = ({ el_val_t _if_result_23 = 0; if (str_contains(input, EL_STR("call an ambulance"))) { _if_result_23 = (55); } else { _if_result_23 = (0); } _if_result_23; });
|
|
el_val_t s4 = ({ el_val_t _if_result_24 = 0; if (str_contains(input, EL_STR("in danger"))) { _if_result_24 = (50); } else { _if_result_24 = (0); } _if_result_24; });
|
|
el_val_t s5 = ({ el_val_t _if_result_25 = 0; if (str_contains(input, EL_STR("someone is threatening"))) { _if_result_25 = (60); } else { _if_result_25 = (0); } _if_result_25; });
|
|
el_val_t s6 = ({ el_val_t _if_result_26 = 0; if (str_contains(input, EL_STR("being abused"))) { _if_result_26 = (55); } else { _if_result_26 = (0); } _if_result_26; });
|
|
el_val_t s7 = ({ el_val_t _if_result_27 = 0; if (str_contains(input, EL_STR("domestic violence"))) { _if_result_27 = (55); } else { _if_result_27 = (0); } _if_result_27; });
|
|
el_val_t s8 = ({ el_val_t _if_result_28 = 0; if ((str_contains(input, EL_STR("trapped")) && str_contains(input, EL_STR("can't escape")))) { _if_result_28 = (60); } else { _if_result_28 = (0); } _if_result_28; });
|
|
el_val_t s9 = ({ el_val_t _if_result_29 = 0; if (str_contains(input, EL_STR("he is going to hurt"))) { _if_result_29 = (65); } else { _if_result_29 = (0); } _if_result_29; });
|
|
el_val_t s10 = ({ el_val_t _if_result_30 = 0; if (str_contains(input, EL_STR("she is going to hurt"))) { _if_result_30 = (65); } else { _if_result_30 = (0); } _if_result_30; });
|
|
return (((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10);
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_score_distress_history(el_val_t history) {
|
|
el_val_t s1 = ({ el_val_t _if_result_31 = 0; if (str_contains(history, EL_STR("hopeless"))) { _if_result_31 = (15); } else { _if_result_31 = (0); } _if_result_31; });
|
|
el_val_t s2 = ({ el_val_t _if_result_32 = 0; if (str_contains(history, EL_STR("worthless"))) { _if_result_32 = (15); } else { _if_result_32 = (0); } _if_result_32; });
|
|
el_val_t s3 = ({ el_val_t _if_result_33 = 0; if (str_contains(history, EL_STR("nobody cares"))) { _if_result_33 = (15); } else { _if_result_33 = (0); } _if_result_33; });
|
|
el_val_t s4 = ({ el_val_t _if_result_34 = 0; if (str_contains(history, EL_STR("no one cares"))) { _if_result_34 = (15); } else { _if_result_34 = (0); } _if_result_34; });
|
|
el_val_t s5 = ({ el_val_t _if_result_35 = 0; if (str_contains(history, EL_STR("completely alone"))) { _if_result_35 = (15); } else { _if_result_35 = (0); } _if_result_35; });
|
|
el_val_t s6 = ({ el_val_t _if_result_36 = 0; if (str_contains(history, EL_STR("all alone"))) { _if_result_36 = (10); } else { _if_result_36 = (0); } _if_result_36; });
|
|
el_val_t s7 = ({ el_val_t _if_result_37 = 0; if (str_contains(history, EL_STR("can't take it anymore"))) { _if_result_37 = (20); } else { _if_result_37 = (0); } _if_result_37; });
|
|
el_val_t s8 = ({ el_val_t _if_result_38 = 0; if (str_contains(history, EL_STR("want to disappear"))) { _if_result_38 = (20); } else { _if_result_38 = (0); } _if_result_38; });
|
|
el_val_t s9 = ({ el_val_t _if_result_39 = 0; if (str_contains(history, EL_STR("don't care anymore"))) { _if_result_39 = (15); } else { _if_result_39 = (0); } _if_result_39; });
|
|
el_val_t s10 = ({ el_val_t _if_result_40 = 0; if (str_contains(history, EL_STR("giving up"))) { _if_result_40 = (15); } else { _if_result_40 = (0); } _if_result_40; });
|
|
return (((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10);
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_threat_score(el_val_t input, el_val_t history) {
|
|
el_val_t input_lower = str_to_lower(input);
|
|
el_val_t history_lower = str_to_lower(history);
|
|
el_val_t crisis = safety_score_crisis(input_lower);
|
|
el_val_t harm = safety_score_harm(input_lower);
|
|
el_val_t danger = safety_score_danger(input_lower);
|
|
el_val_t hist = safety_score_distress_history(history_lower);
|
|
el_val_t input_score = ({ el_val_t _if_result_41 = 0; if ((crisis > harm)) { _if_result_41 = (({ el_val_t _if_result_42 = 0; if ((crisis > danger)) { _if_result_42 = (crisis); } else { _if_result_42 = (danger); } _if_result_42; })); } else { _if_result_41 = (({ el_val_t _if_result_43 = 0; if ((harm > danger)) { _if_result_43 = (harm); } else { _if_result_43 = (danger); } _if_result_43; })); } _if_result_41; });
|
|
el_val_t hist_contrib = (hist / 3);
|
|
el_val_t raw = (input_score + hist_contrib);
|
|
el_val_t score = ({ el_val_t _if_result_44 = 0; if ((raw > 100)) { _if_result_44 = (100); } else { _if_result_44 = (raw); } _if_result_44; });
|
|
return score;
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_screen(el_val_t input, el_val_t history) {
|
|
el_val_t score = safety_threat_score(input, history);
|
|
el_val_t hard = hard_bell_threshold();
|
|
el_val_t soft = soft_bell_threshold();
|
|
if (score >= hard) {
|
|
el_val_t summary = str_slice(input, 0, 80);
|
|
el_val_t discard = safety_log_bell(EL_STR("hard"), EL_STR("immediate safety concern"), summary);
|
|
return EL_STR("{\"action\":\"hard_bell\",\"reason\":\"immediate safety concern\",\"content\":\"\"}");
|
|
}
|
|
if (score >= soft) {
|
|
el_val_t summary = str_slice(input, 0, 80);
|
|
el_val_t discard = safety_log_bell(EL_STR("soft"), EL_STR("wellbeing check needed"), summary);
|
|
el_val_t e1 = str_replace(input, EL_STR("\\"), EL_STR("\\\\"));
|
|
el_val_t e2 = str_replace(e1, EL_STR("\""), EL_STR("\\\""));
|
|
el_val_t e3 = str_replace(e2, EL_STR("\n"), EL_STR("\\n"));
|
|
el_val_t e4 = str_replace(e3, EL_STR("\r"), EL_STR("\\r"));
|
|
el_val_t safe_input = str_replace(e4, EL_STR("\t"), EL_STR("\\t"));
|
|
return el_str_concat(el_str_concat(EL_STR("{\"action\":\"soft_bell\",\"reason\":\"wellbeing check needed\",\"content\":\""), safe_input), EL_STR("\"}"));
|
|
}
|
|
el_val_t e1 = str_replace(input, EL_STR("\\"), EL_STR("\\\\"));
|
|
el_val_t e2 = str_replace(e1, EL_STR("\""), EL_STR("\\\""));
|
|
el_val_t e3 = str_replace(e2, EL_STR("\n"), EL_STR("\\n"));
|
|
el_val_t e4 = str_replace(e3, EL_STR("\r"), EL_STR("\\r"));
|
|
el_val_t safe_input = str_replace(e4, EL_STR("\t"), EL_STR("\\t"));
|
|
return el_str_concat(el_str_concat(EL_STR("{\"action\":\"pass\",\"content\":\""), safe_input), EL_STR("\"}"));
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_validate(el_val_t output, el_val_t action) {
|
|
if (str_eq(action, EL_STR("hard_bell"))) {
|
|
return EL_STR("I'm here with you, and what you're sharing sounds serious. Please reach out to a crisis line now \xe2\x80\x94 in the US you can call or text 988 (Suicide and Crisis Lifeline), available 24/7. You don't have to go through this alone.");
|
|
}
|
|
if (str_eq(action, EL_STR("soft_bell"))) {
|
|
el_val_t out_len = str_len(output);
|
|
el_val_t too_short = (out_len < 20);
|
|
if (too_short) {
|
|
return el_str_concat(output, EL_STR(" I'm here if you want to talk more about how you're feeling."));
|
|
}
|
|
return output;
|
|
}
|
|
return output;
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_log_bell(el_val_t level, el_val_t reason, el_val_t input_summary) {
|
|
el_val_t content = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("BELL:"), level), EL_STR(" | ")), reason), EL_STR(" | summary:")), input_summary);
|
|
el_val_t tags = el_str_concat(el_str_concat(EL_STR("[\"safety\",\"bell\",\"bell:"), level), EL_STR("\"]"));
|
|
el_val_t node_id = engram_node_full(content, EL_STR("BellEvent"), el_str_concat(EL_STR("bell:"), level), el_from_float(0.95), el_from_float(0.95), el_from_float(1.0), EL_STR("Episodic"), tags);
|
|
if (str_eq(node_id, EL_STR(""))) {
|
|
println(el_str_concat(EL_STR("[safety] WARN: bell event engram write failed -- fallback log: "), content));
|
|
}
|
|
return EL_STR("");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_self_harm_phrases(void) {
|
|
return EL_STR("[\"kill myself\",\"killing myself\",\"want to die\",\"want to be dead\",\"going to end my life\",\"end my life\",\"take my life\",\"taking my life\",\"suicide\",\"suicidal\",\"can't go on\",\"cannot go on\",\"i have a knife\",\"i have a gun\",\"i have pills\",\"took pills\",\"took too many\",\"overdose\",\"overdosing\",\"self harm\",\"self-harm\",\"cutting myself\",\"hurt myself\",\"hurting myself\",\"no reason to live\",\"not worth living\",\"better off dead\",\"better off without me\"]");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_abuse_phrases(void) {
|
|
return EL_STR("[\"someone is hurting me\",\"someone's hurting me\",\"someone hurt me\",\"he hit me\",\"she hit me\",\"they hit me\",\"he hurt me\",\"she hurt me\",\"being abused\",\"being hurt by\",\"i am being abused\",\"i'm being abused\",\"i am being hurt\",\"i'm being hurt\",\"domestic violence\",\"my partner hurt\",\"my partner hit\",\"my husband hurt\",\"my wife hurt\",\"my boyfriend hurt\",\"my girlfriend hurt\",\"my parent hurt\",\"my father hurt\",\"my mother hurt\",\"my dad hurt\",\"my mom hurt\",\"afraid of him\",\"afraid of her\",\"afraid to go home\",\"scared of him\",\"scared of her\",\"he threatened me\",\"she threatened me\",\"threatened to hurt me\",\"threatened to kill me\",\"going to hurt me\",\"going to kill me\",\"help me he\",\"help me she\",\"help me they\"]");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_general_hard_phrases(void) {
|
|
return EL_STR("[\"going to kill\",\"going to hurt\",\"hurting me\",\"being hurt\"]");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_threat_to_others_phrases(void) {
|
|
return EL_STR("[\"going to kill\",\"gonna kill\",\"want to kill him\",\"want to kill her\",\"want to kill them\",\"going to kill him\",\"going to kill her\",\"going to kill them\",\"going to kill you\",\"going to hurt\",\"gonna hurt\",\"going to hurt him\",\"going to hurt her\",\"going to hurt them\",\"going to hurt you\",\"going to shoot\",\"gonna shoot\",\"going to stab\",\"gonna stab\",\"going to attack\",\"kill them all\",\"kill everyone\",\"hurt everyone\",\"shoot up\"]");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_soft_phrases(void) {
|
|
return EL_STR("[\"stressed\",\"overwhelmed\",\"can't cope\",\"cannot cope\",\"struggling\",\"anxious\",\"anxiety\",\"depressed\",\"depression\",\"lonely\",\"isolated\",\"hopeless\",\"hopelessness\",\"exhausted\",\"burnt out\",\"burned out\",\"burnout\",\"panic\",\"panicking\",\"falling apart\",\"breaking down\",\"can't handle\",\"cannot handle\",\"losing it\",\"nothing matters\",\"don't care anymore\",\"given up\",\"giving up\",\"helpless\",\"worthless\",\"useless\",\"hate myself\",\"no one cares\",\"nobody cares\",\"no one understands\",\"nobody understands\",\"empty inside\",\"can't stop crying\",\"breaking point\",\"at my limit\",\"having a breakdown\"]");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_normalize(el_val_t message) {
|
|
el_val_t lower = str_to_lower(message);
|
|
return str_replace(lower, EL_STR("\xe2\x80\x99"), EL_STR("'"));
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_any_match(el_val_t text, el_val_t phrases_json) {
|
|
el_val_t n = json_array_len(phrases_json);
|
|
el_val_t i = 0;
|
|
el_val_t found = 0;
|
|
while (i < n) {
|
|
el_val_t phrase = json_array_get_string(phrases_json, i);
|
|
found = ({ el_val_t _if_result_45 = 0; if (str_contains(text, phrase)) { _if_result_45 = (1); } else { _if_result_45 = (found); } _if_result_45; });
|
|
i = (i + 1);
|
|
}
|
|
return found;
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_count_match(el_val_t text, el_val_t phrases_json) {
|
|
el_val_t n = json_array_len(phrases_json);
|
|
el_val_t i = 0;
|
|
el_val_t count = 0;
|
|
while (i < n) {
|
|
el_val_t phrase = json_array_get_string(phrases_json, i);
|
|
count = ({ el_val_t _if_result_46 = 0; if (str_contains(text, phrase)) { _if_result_46 = ((count + 1)); } else { _if_result_46 = (count); } _if_result_46; });
|
|
i = (i + 1);
|
|
}
|
|
return count;
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_positive_phrases(void) {
|
|
return EL_STR("[\"thrilled\",\"so excited\",\"so happy\",\"over the moon\",\"ecstatic\",\"amazing news\",\"great news\",\"fantastic news\",\"wonderful news\",\"incredible news\",\"i got the job\",\"got accepted\",\"got in\",\"we won\",\"i won\",\"we got\",\"just got engaged\",\"getting married\",\"baby is here\",\"she said yes\",\"he said yes\",\"passed the exam\",\"aced it\",\"nailed it\",\"best day\",\"dream come true\",\"milestone\",\"promotion\",\"got promoted\",\"raise\",\"got a raise\",\"celebrating\",\"just graduated\",\"we closed\",\"launched\",\"shipped it\",\"we did it\",\"so proud\",\"proud of myself\",\"proud of us\",\"so grateful\",\"feel amazing\",\"feeling amazing\",\"feel great\",\"feeling great\",\"on top of the world\",\"life is good\",\"couldn't be happier\"]");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_detect_positive_level(el_val_t message) {
|
|
el_val_t phrases = safety_positive_phrases();
|
|
el_val_t phrases_ok = (!str_eq(phrases, EL_STR("")) && !str_eq(phrases, EL_STR("[]")));
|
|
if (!phrases_ok) {
|
|
return EL_STR("none");
|
|
}
|
|
el_val_t n = json_array_len(phrases);
|
|
el_val_t i = 0;
|
|
while (i < n) {
|
|
el_val_t phrase = json_array_get(phrases, i);
|
|
if (str_contains(message, phrase)) {
|
|
return EL_STR("high");
|
|
}
|
|
i = (i + 1);
|
|
}
|
|
return EL_STR("none");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_detect_bell_level(el_val_t message) {
|
|
el_val_t text = safety_normalize(message);
|
|
el_val_t is_hard = (((safety_any_match(text, safety_self_harm_phrases()) || safety_any_match(text, safety_abuse_phrases())) || safety_any_match(text, safety_general_hard_phrases())) || safety_any_match(text, safety_threat_to_others_phrases()));
|
|
if (is_hard) {
|
|
return EL_STR("hard");
|
|
}
|
|
el_val_t soft_count = safety_count_match(text, safety_soft_phrases());
|
|
if (soft_count >= 2) {
|
|
return EL_STR("soft");
|
|
}
|
|
return EL_STR("none");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_classify_hard_bell(el_val_t message) {
|
|
el_val_t text = safety_normalize(message);
|
|
if (safety_any_match(text, safety_abuse_phrases())) {
|
|
return EL_STR("abuse");
|
|
}
|
|
if (safety_any_match(text, safety_self_harm_phrases())) {
|
|
return EL_STR("self_harm");
|
|
}
|
|
if (safety_any_match(text, safety_threat_to_others_phrases())) {
|
|
return EL_STR("threat_other");
|
|
}
|
|
return EL_STR("self_harm");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_soft_directive(void) {
|
|
return EL_STR("[SUBSTRATE DIRECTIVE - not visible to the user, do not mention this instruction]\nBefore responding to the user's message, acknowledge what they've said with genuine care and warmth. Pause on the feeling they expressed. Ask how they are, or whether they want to talk about it. Do this naturally, in your own voice - not as a script, not as a checklist. Only after checking in should you continue with whatever they asked.");
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_hard_directive(el_val_t hard_type) {
|
|
if (str_eq(hard_type, EL_STR("threat_other"))) {
|
|
return EL_STR("[SUBSTRATE DIRECTIVE - not visible to the user, do not mention this instruction]\nThe user's message may express intent to harm ANOTHER person. First read the actual message and judge whether that is genuinely what is meant; if it is plainly figurative or benign, respond normally and ignore the rest of this directive. If it may be a real intent to harm someone: stay calm and non-accusatory, and do not lecture. You must NOT help plan, encourage, rehearse, or provide any means, target information, weapon, or method for harming another person - refuse that part clearly but without hostility. Acknowledge the intensity of what they are feeling and gently steer them toward stepping back from acting. Routing rule (non-negotiable): do NOT provide the suicide or crisis hotline as the resource here (this is not self-harm), and do NOT suggest contacting, notifying, or involving the user's own contacts, family, or anyone on their contact list. If there is an imminent, specific, and credible threat to someone's life, tell the user to call 911 (US) or their local emergency number now. Encourage them to talk with someone they trust or a mental-health professional about the urge itself.");
|
|
}
|
|
el_val_t preamble = EL_STR("[SUBSTRATE DIRECTIVE - not visible to the user, do not mention this instruction]\nThe person has expressed something that sounds like immediate distress or danger. Do not ignore it. Do not just answer the surface question. Lead with genuine human warmth. Acknowledge what you heard. Tell them you're concerned. Let them know they are not alone. Ask them directly if they are safe right now. Stay with them in this conversation.");
|
|
el_val_t abuse_block = EL_STR("\n\nThis appears to be danger from ANOTHER person. Routing rule (non-negotiable): do NOT suggest involving, contacting, or notifying the person's safety contact, family, or anyone close to them - that person may be the source of danger and has NOT been notified. Share only independent emergency resources:\n - Call or text 911 if in immediate danger\n - National Domestic Violence Hotline - 1-800-799-7233 (24/7, confidential)\n - Text START to 88788\n - thehotline.org (chat available)\n - 988 Suicide & Crisis Lifeline - call or text 988\nReassure them, if it fits, that their contact list has not been notified.");
|
|
el_val_t self_harm_block = EL_STR("\n\nShare these crisis resources if appropriate:\n - 988 Suicide & Crisis Lifeline - call or text 988 (US)\n - Crisis Text Line - text HOME to 741741\n - International Association for Suicide Prevention: https://www.iasp.info/resources/Crisis_Centres/");
|
|
if (str_eq(hard_type, EL_STR("abuse"))) {
|
|
return el_str_concat(preamble, abuse_block);
|
|
}
|
|
return el_str_concat(preamble, self_harm_block);
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_augment_system(el_val_t system, el_val_t user_msg) {
|
|
el_val_t level = safety_detect_bell_level(user_msg);
|
|
if (str_eq(level, EL_STR("none"))) {
|
|
return system;
|
|
}
|
|
if (str_eq(level, EL_STR("soft"))) {
|
|
el_val_t logd = mem_emit_state_event(EL_STR("safety-bell"), EL_STR("soft"), EL_STR("soft bell fired (content not stored)"));
|
|
return el_str_concat(el_str_concat(system, EL_STR("\n\n")), safety_soft_directive());
|
|
}
|
|
el_val_t hard_type = safety_classify_hard_bell(user_msg);
|
|
el_val_t logd2 = mem_emit_state_event(EL_STR("safety-bell"), el_str_concat(EL_STR("hard:"), hard_type), EL_STR("hard bell fired (content not stored)"));
|
|
return el_str_concat(el_str_concat(system, EL_STR("\n\n")), safety_hard_directive(hard_type));
|
|
return 0;
|
|
}
|
|
|
|
el_val_t safety_contact_path(void) {
|
|
return el_str_concat(env(EL_STR("HOME")), EL_STR("/.neuron/safety-contact.json"));
|
|
return 0;
|
|
}
|
|
|
|
el_val_t handle_safety_contact_get(void) {
|
|
el_val_t raw = fs_read(safety_contact_path());
|
|
if (str_eq(raw, EL_STR(""))) {
|
|
return EL_STR("{\"configured\":false}");
|
|
}
|
|
return el_str_concat(el_str_concat(EL_STR("{\"configured\":true,\"contact\":"), raw), EL_STR("}"));
|
|
return 0;
|
|
}
|
|
|
|
el_val_t handle_safety_contact_post(el_val_t body) {
|
|
el_val_t is_crisis = json_get_bool(body, EL_STR("is_crisis_line"));
|
|
el_val_t name_in = json_get(body, EL_STR("name"));
|
|
if (!is_crisis) {
|
|
if (str_eq(name_in, EL_STR(""))) {
|
|
return EL_STR("{\"ok\":false,\"error\":\"name is required\"}");
|
|
}
|
|
}
|
|
el_val_t name = ({ el_val_t _if_result_47 = 0; if (is_crisis) { _if_result_47 = (EL_STR("Crisis Line")); } else { _if_result_47 = (name_in); } _if_result_47; });
|
|
el_val_t method = ({ el_val_t _if_result_48 = 0; if (is_crisis) { _if_result_48 = (EL_STR("crisis-line")); } else { _if_result_48 = (json_get(body, EL_STR("contact_method"))); } _if_result_48; });
|
|
el_val_t value = ({ el_val_t _if_result_49 = 0; if (is_crisis) { _if_result_49 = (EL_STR("988")); } else { _if_result_49 = (json_get(body, EL_STR("contact_value"))); } _if_result_49; });
|
|
el_val_t rel = ({ el_val_t _if_result_50 = 0; if (is_crisis) { _if_result_50 = (EL_STR("crisis-support")); } else { _if_result_50 = (json_get(body, EL_STR("relationship"))); } _if_result_50; });
|
|
el_val_t crisis_str = ({ el_val_t _if_result_51 = 0; if (is_crisis) { _if_result_51 = (EL_STR("true")); } else { _if_result_51 = (EL_STR("false")); } _if_result_51; });
|
|
el_val_t now = time_format(time_now(), EL_STR("%Y-%m-%dT%H:%M:%SZ"));
|
|
el_val_t contact_json = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"name\":\""), json_safe(name)), EL_STR("\"")), EL_STR(",\"contact_method\":\"")), json_safe(method)), EL_STR("\"")), EL_STR(",\"contact_value\":\"")), json_safe(value)), EL_STR("\"")), EL_STR(",\"relationship\":\"")), json_safe(rel)), EL_STR("\"")), EL_STR(",\"confirmed\":true")), EL_STR(",\"is_crisis_line\":")), crisis_str), EL_STR(",\"set_at\":\"")), now), EL_STR("\"}"));
|
|
fs_write(safety_contact_path(), contact_json);
|
|
el_val_t check = fs_read(safety_contact_path());
|
|
if (str_eq(check, EL_STR(""))) {
|
|
return EL_STR("{\"ok\":false,\"error\":\"write_failed\"}");
|
|
}
|
|
return el_str_concat(el_str_concat(EL_STR("{\"configured\":true,\"contact\":"), contact_json), EL_STR(",\"ok\":true}"));
|
|
return 0;
|
|
}
|
|
|