feat(engram): wire ISE emission into core processing paths (checkpoint, high-importance writes, WM promotion)

This commit is contained in:
2026-05-13 15:45:16 -05:00
parent a3ead6552e
commit 0c2ff6957e
4 changed files with 652 additions and 25 deletions
Vendored Executable
BIN
View File
Binary file not shown.
+490 -23
View File
@@ -20,16 +20,35 @@ el_val_t route_create_edge(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neighbors(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_strengthen(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_forget(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_save(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_decay(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_export(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_reindex(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_load(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_health(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_session_begin(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_ctx(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_memory(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_knowledge_capture(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_knowledge_evolve(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_knowledge_promote(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_recall(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_graph(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_graph_link(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_list(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_consolidate(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_config(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_state_events(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neuron_processes(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_events_next(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_events_ack(el_val_t method, el_val_t path, el_val_t body);
el_val_t check_auth_ok(el_val_t method, el_val_t body);
el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body);
el_val_t bind_str;
el_val_t port;
el_val_t data_dir;
el_val_t snapshot_path;
el_val_t db_path;
el_val_t loaded;
el_val_t parse_port(el_val_t bind) {
el_val_t colon = str_index_of(bind, EL_STR(":"));
@@ -115,11 +134,60 @@ el_val_t route_create_node(el_val_t method, el_val_t path, el_val_t body) {
node_type = EL_STR("Memory");
}
el_val_t salience = json_get_float(body, EL_STR("salience"));
if (str_eq(salience, el_from_float(0.0))) {
if (salience == el_from_float(0.0)) {
salience = el_from_float(0.5);
}
el_val_t id = engram_node(content, node_type, salience);
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"id\":\""), id), EL_STR("\",\"content\":\"")), content), EL_STR("\",\"node_type\":\"")), node_type), EL_STR("\"}"));
el_val_t auto_linked = 0;
el_val_t clen = str_len(content);
if (clen >= 20) {
el_val_t sp1 = str_index_of(content, EL_STR(" "));
el_val_t w1end = sp1;
if (sp1 < 0) {
w1end = clen;
}
el_val_t word1 = str_slice(content, 0, w1end);
el_val_t search_term = EL_STR("");
if (str_len(word1) >= 5) {
search_term = word1;
}
if (str_eq(search_term, EL_STR(""))) {
if (sp1 >= 0) {
el_val_t rest = str_slice(content, (sp1 + 1), clen);
el_val_t sp2 = str_index_of(rest, EL_STR(" "));
el_val_t w2end = sp2;
if (sp2 < 0) {
w2end = str_len(rest);
}
el_val_t word2 = str_slice(rest, 0, w2end);
if (str_len(word2) >= 5) {
search_term = word2;
}
}
}
if (!str_eq(search_term, EL_STR(""))) {
el_val_t results = engram_search_json(search_term, 10);
el_val_t n = json_array_len(results);
el_val_t i = 0;
while (i < n) {
if (auto_linked >= 5) {
i = n;
}
if (auto_linked < 5) {
el_val_t elem = json_array_get(results, i);
el_val_t rid = json_get_string(elem, EL_STR("id"));
if (!str_eq(rid, EL_STR(""))) {
if (!str_eq(rid, id)) {
engram_connect(id, rid, el_from_float(0.5), EL_STR("related"));
auto_linked = (auto_linked + 1);
}
}
i = (i + 1);
}
}
}
}
return 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("{\"id\":\""), id), EL_STR("\",\"content\":\"")), content), EL_STR("\",\"node_type\":\"")), node_type), EL_STR("\",\"auto_linked\":")), int_to_str(auto_linked)), EL_STR("}"));
return 0;
}
@@ -205,7 +273,7 @@ el_val_t route_create_edge(el_val_t method, el_val_t path, el_val_t body) {
relation = EL_STR("associates");
}
el_val_t weight = json_get_float(body, EL_STR("weight"));
if (str_eq(weight, el_from_float(0.0))) {
if (weight == el_from_float(0.0)) {
weight = el_from_float(0.5);
}
engram_connect(from_id, to_id, weight, relation);
@@ -243,30 +311,46 @@ el_val_t route_forget(el_val_t method, el_val_t path, el_val_t body) {
return 0;
}
el_val_t route_save(el_val_t method, el_val_t path, el_val_t body) {
el_val_t route_decay(el_val_t method, el_val_t path, el_val_t body) {
return engram_apply_decay_json();
return 0;
}
el_val_t route_export(el_val_t method, el_val_t path, el_val_t body) {
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
el_val_t db_path = el_str_concat(dir, EL_STR("/engram.db"));
engram_write_binary_el(db_path);
el_val_t p = json_get_string(body, EL_STR("path"));
if (str_eq(p, EL_STR(""))) {
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
p = el_str_concat(dir, EL_STR("/snapshot.json"));
}
engram_save(p);
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"path\":\""), p), EL_STR("\"}"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"binary\":\""), db_path), EL_STR("\",\"json\":\"")), p), EL_STR("\"}"));
return 0;
}
el_val_t route_reindex(el_val_t method, el_val_t path, el_val_t body) {
return engram_reindex_json();
return 0;
}
el_val_t route_load(el_val_t method, el_val_t path, el_val_t body) {
el_val_t p = json_get_string(body, EL_STR("path"));
if (str_eq(p, EL_STR(""))) {
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
p = el_str_concat(dir, EL_STR("/snapshot.json"));
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
el_val_t db_path = el_str_concat(dir, EL_STR("/engram.db"));
el_val_t ok = engram_load_binary_el(db_path);
if (!ok) {
el_val_t p = json_get_string(body, EL_STR("path"));
if (str_eq(p, EL_STR(""))) {
p = el_str_concat(dir, EL_STR("/snapshot.json"));
}
engram_load(p);
}
engram_load(p);
return ok_json();
return 0;
}
@@ -276,6 +360,262 @@ el_val_t route_health(el_val_t method, el_val_t path, el_val_t body) {
return 0;
}
el_val_t route_neuron_session_begin(el_val_t method, el_val_t path, el_val_t body) {
el_val_t results = engram_activate_json(EL_STR("memory knowledge context"), 2);
el_val_t nc = engram_node_count();
el_val_t ec = engram_edge_count();
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"nodes\":"), results), EL_STR(",\"node_count\":")), int_to_str(nc)), EL_STR(",\"edge_count\":")), int_to_str(ec)), EL_STR("}"));
return 0;
}
el_val_t route_neuron_ctx(el_val_t method, el_val_t path, el_val_t body) {
el_val_t results = engram_activate_json(EL_STR("architecture decision memory"), 2);
el_val_t n = json_array_len(results);
el_val_t limit = ({ el_val_t _if_result_1 = 0; if ((n > 10)) { _if_result_1 = (10); } else { _if_result_1 = (n); } _if_result_1; });
el_val_t ctx = EL_STR("Recent working memory:\n");
el_val_t i = 0;
el_val_t ctx_body = EL_STR("");
while (i < limit) {
el_val_t elem = json_array_get(results, i);
el_val_t label = json_get_string(elem, EL_STR("label"));
el_val_t content = json_get_string(elem, EL_STR("content"));
el_val_t clen = str_len(content);
el_val_t snippet = ({ el_val_t _if_result_2 = 0; if ((clen > 200)) { _if_result_2 = (str_slice(content, 0, 200)); } else { _if_result_2 = (content); } _if_result_2; });
ctx_body = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(ctx_body, EL_STR("- [")), label), EL_STR("]: ")), snippet), EL_STR("\n"));
i = (i + 1);
}
el_val_t full_ctx = el_str_concat(ctx, ctx_body);
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"context\":\""), str_replace(str_replace(str_replace(full_ctx, EL_STR("\\"), EL_STR("\\\\")), EL_STR("\""), EL_STR("\\\"")), EL_STR("\n"), EL_STR("\\n"))), EL_STR("\"}"));
return 0;
}
el_val_t route_neuron_memory(el_val_t method, el_val_t path, el_val_t body) {
el_val_t content = json_get_string(body, EL_STR("content"));
if (str_eq(content, EL_STR(""))) {
return EL_STR("{\"error\":\"content is required\"}");
}
el_val_t node_type = json_get_string(body, EL_STR("node_type"));
if (str_eq(node_type, EL_STR(""))) {
node_type = EL_STR("Memory");
}
el_val_t label = json_get_string(body, EL_STR("label"));
el_val_t importance = json_get_string(body, EL_STR("importance"));
el_val_t project = json_get_string(body, EL_STR("project"));
el_val_t tags_raw = json_get_string(body, EL_STR("tags"));
el_val_t tier = EL_STR("Episodic");
if (str_eq(importance, EL_STR("critical"))) {
tier = EL_STR("Procedural");
}
if (str_eq(importance, EL_STR("high"))) {
tier = EL_STR("Semantic");
}
if (str_eq(importance, EL_STR("normal"))) {
tier = EL_STR("Episodic");
}
if (str_eq(importance, EL_STR("low"))) {
tier = EL_STR("Working");
}
el_val_t explicit_tier = json_get_string(body, EL_STR("tier"));
if (!str_eq(explicit_tier, EL_STR(""))) {
tier = explicit_tier;
}
el_val_t tags_str = tags_raw;
if (!str_eq(project, EL_STR(""))) {
if (str_eq(tags_str, EL_STR(""))) {
tags_str = el_str_concat(EL_STR("project:"), project);
}
if (!str_eq(tags_str, EL_STR(""))) {
tags_str = el_str_concat(el_str_concat(tags_str, EL_STR(" project:")), project);
}
}
el_val_t id = engram_node_full(content, node_type, label, el_from_float(0.5), el_from_float(0.5), el_from_float(1.0), tier, tags_str);
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
el_val_t db_path = el_str_concat(dir, EL_STR("/engram.db"));
engram_write_binary_el(db_path);
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), id), EL_STR("\",\"content\":\"")), str_replace(str_replace(content, EL_STR("\\"), EL_STR("\\\\")), EL_STR("\""), EL_STR("\\\""))), EL_STR("\"}"));
return 0;
}
el_val_t route_neuron_knowledge_capture(el_val_t method, el_val_t path, el_val_t body) {
el_val_t content = json_get_string(body, EL_STR("content"));
if (str_eq(content, EL_STR(""))) {
return EL_STR("{\"error\":\"content is required\"}");
}
el_val_t title = json_get_string(body, EL_STR("title"));
el_val_t category = json_get_string(body, EL_STR("category"));
el_val_t tags_raw = json_get_string(body, EL_STR("tags"));
el_val_t project = json_get_string(body, EL_STR("project"));
el_val_t tier_raw = json_get_string(body, EL_STR("tier"));
el_val_t tier = EL_STR("Episodic");
if (str_eq(tier_raw, EL_STR("lesson"))) {
tier = EL_STR("Semantic");
}
if (str_eq(tier_raw, EL_STR("canonical"))) {
tier = EL_STR("Procedural");
}
if (str_eq(tier_raw, EL_STR("note"))) {
tier = EL_STR("Episodic");
}
el_val_t tags_str = tags_raw;
if (!str_eq(category, EL_STR(""))) {
if (str_eq(tags_str, EL_STR(""))) {
tags_str = el_str_concat(EL_STR("category:"), category);
}
if (!str_eq(tags_str, EL_STR(""))) {
tags_str = el_str_concat(el_str_concat(tags_str, EL_STR(" category:")), category);
}
}
if (!str_eq(project, EL_STR(""))) {
if (str_eq(tags_str, EL_STR(""))) {
tags_str = el_str_concat(EL_STR("project:"), project);
}
if (!str_eq(tags_str, EL_STR(""))) {
tags_str = el_str_concat(el_str_concat(tags_str, EL_STR(" project:")), project);
}
}
el_val_t id = engram_node_full(content, EL_STR("Knowledge"), title, el_from_float(0.7), el_from_float(0.7), el_from_float(1.0), tier, tags_str);
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
el_val_t db_path = el_str_concat(dir, EL_STR("/engram.db"));
engram_write_binary_el(db_path);
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), id), EL_STR("\"}"));
return 0;
}
el_val_t route_neuron_knowledge_evolve(el_val_t method, el_val_t path, el_val_t body) {
el_val_t content = json_get_string(body, EL_STR("content"));
el_val_t prior_id = json_get_string(body, EL_STR("id"));
if (str_eq(content, EL_STR(""))) {
return EL_STR("{\"ok\":true}");
}
el_val_t id = engram_node_full(content, EL_STR("Knowledge"), EL_STR(""), el_from_float(0.7), el_from_float(0.7), el_from_float(1.0), EL_STR("Semantic"), EL_STR("evolved"));
if (!str_eq(prior_id, EL_STR("")) && !str_eq(id, EL_STR(""))) {
engram_connect(id, prior_id, el_from_float(1.0), EL_STR("supersedes"));
}
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
engram_write_binary_el(el_str_concat(dir, EL_STR("/engram.db")));
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), id), EL_STR("\"}"));
return 0;
}
el_val_t route_neuron_knowledge_promote(el_val_t method, el_val_t path, el_val_t body) {
return EL_STR("{\"ok\":true}");
return 0;
}
el_val_t route_neuron_recall(el_val_t method, el_val_t path, el_val_t body) {
el_val_t query = json_get_string(body, EL_STR("query"));
el_val_t chain = json_get_string(body, EL_STR("chain_name"));
el_val_t limit = json_get_int(body, EL_STR("limit"));
if (limit == 0) {
limit = 20;
}
el_val_t q = ({ el_val_t _if_result_3 = 0; if (str_eq(query, EL_STR(""))) { _if_result_3 = (chain); } else { _if_result_3 = (query); } _if_result_3; });
if (str_eq(q, EL_STR(""))) {
return engram_scan_nodes_json(limit, 0);
}
return engram_search_json(q, limit);
return 0;
}
el_val_t route_neuron_graph(el_val_t method, el_val_t path, el_val_t body) {
el_val_t id = query_param(path, EL_STR("id"));
if (str_eq(id, EL_STR(""))) {
return EL_STR("{\"error\":\"id is required\"}");
}
el_val_t node_json = engram_get_node_json(id);
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"node\":"), node_json), EL_STR(",\"neighbors\":[]}"));
return 0;
}
el_val_t route_neuron_graph_link(el_val_t method, el_val_t path, el_val_t body) {
el_val_t from_id = json_get_string(body, EL_STR("from_id"));
el_val_t to_id = json_get_string(body, EL_STR("to_id"));
if (str_eq(from_id, EL_STR("")) || str_eq(to_id, EL_STR(""))) {
return EL_STR("{\"error\":\"from_id and to_id are required\"}");
}
el_val_t relation = json_get_string(body, EL_STR("relation"));
if (str_eq(relation, EL_STR(""))) {
relation = EL_STR("related");
}
el_val_t weight = json_get_float(body, EL_STR("weight"));
if (weight == el_from_float(0.0)) {
weight = el_from_float(0.5);
}
engram_connect(from_id, to_id, weight, relation);
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"from_id\":\""), from_id), EL_STR("\",\"to_id\":\"")), to_id), EL_STR("\",\"relation\":\"")), relation), EL_STR("\"}"));
return 0;
}
el_val_t route_neuron_list(el_val_t method, el_val_t path, el_val_t body) {
el_val_t clean = strip_query(path);
el_val_t prefix = EL_STR("/api/neuron/list/");
el_val_t node_type = str_slice(clean, str_len(prefix), str_len(clean));
el_val_t limit = query_int(path, EL_STR("limit"), 50);
if (str_eq(node_type, EL_STR(""))) {
return EL_STR("[]");
}
return engram_scan_nodes_by_type_json(node_type, limit, 0);
return 0;
}
el_val_t route_neuron_consolidate(el_val_t method, el_val_t path, el_val_t body) {
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
el_val_t db_path = el_str_concat(dir, EL_STR("/engram.db"));
engram_write_binary_el(db_path);
el_val_t nc = engram_node_count();
el_val_t ec = engram_edge_count();
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"node_count\":"), int_to_str(nc)), EL_STR(",\"edge_count\":")), int_to_str(ec)), EL_STR("}"));
return 0;
}
el_val_t route_neuron_config(el_val_t method, el_val_t path, el_val_t body) {
el_val_t key = query_param(path, EL_STR("key"));
return el_str_concat(el_str_concat(EL_STR("{\"key\":\""), key), EL_STR("\",\"value\":\"\"}"));
return 0;
}
el_val_t route_neuron_state_events(el_val_t method, el_val_t path, el_val_t body) {
if (str_eq(method, EL_STR("GET"))) {
el_val_t limit_str = query_param(path, EL_STR("limit"));
el_val_t limit = ({ el_val_t _if_result_4 = 0; if (str_eq(limit_str, EL_STR(""))) { _if_result_4 = (50); } else { _if_result_4 = (str_to_int(limit_str)); } _if_result_4; });
return engram_scan_nodes_by_type_json(EL_STR("InternalStateEvent"), limit, 0);
}
el_val_t content = json_get_string(body, EL_STR("content"));
if (str_eq(content, EL_STR(""))) {
content = body;
}
el_val_t id = engram_node_full(content, EL_STR("InternalStateEvent"), EL_STR("state-event"), el_from_float(0.3), el_from_float(0.3), el_from_float(1.0), EL_STR("Working"), EL_STR("internal-state"));
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), id), EL_STR("\"}"));
return 0;
}
el_val_t route_neuron_processes(el_val_t method, el_val_t path, el_val_t body) {
return EL_STR("{\"ok\":true,\"processes\":[]}");
return 0;
}
el_val_t route_events_next(el_val_t method, el_val_t path, el_val_t body) {
return EL_STR("{\"ok\":true,\"event\":null}");
return 0;
}
el_val_t route_events_ack(el_val_t method, el_val_t path, el_val_t body) {
return EL_STR("{\"ok\":true}");
return 0;
}
el_val_t check_auth_ok(el_val_t method, el_val_t body) {
el_val_t key = env(EL_STR("ENGRAM_API_KEY"));
if (str_eq(key, EL_STR(""))) {
@@ -299,6 +639,60 @@ el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body) {
return route_health(method, path, body);
}
}
if (str_starts_with(clean, EL_STR("/api/neuron/")) || str_starts_with(clean, EL_STR("/events/"))) {
if (str_eq(clean, EL_STR("/api/neuron/session/begin"))) {
return route_neuron_session_begin(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/ctx"))) {
return route_neuron_ctx(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/memory"))) {
return route_neuron_memory(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/knowledge/capture"))) {
return route_neuron_knowledge_capture(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/knowledge/evolve"))) {
return route_neuron_knowledge_evolve(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/knowledge/promote"))) {
return route_neuron_knowledge_promote(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/recall"))) {
return route_neuron_recall(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/graph/link"))) {
return route_neuron_graph_link(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/graph"))) {
return route_neuron_graph(method, path, body);
}
if (str_starts_with(clean, EL_STR("/api/neuron/list/"))) {
return route_neuron_list(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/consolidate"))) {
return route_neuron_consolidate(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/config"))) {
return route_neuron_config(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/state-events"))) {
return route_neuron_state_events(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/processes/define"))) {
return route_neuron_processes(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/processes"))) {
return route_neuron_processes(method, path, body);
}
if (str_eq(clean, EL_STR("/events/next"))) {
return route_events_next(method, path, body);
}
if (str_eq(clean, EL_STR("/events/ack"))) {
return route_events_ack(method, path, body);
}
return err_json(EL_STR("not found"));
}
if (!check_auth_ok(method, body)) {
return err_json(EL_STR("unauthorized"));
}
@@ -341,12 +735,74 @@ el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body) {
if (str_eq(method, EL_STR("POST")) && (str_eq(clean, EL_STR("/api/strengthen")) || str_eq(clean, EL_STR("/strengthen")))) {
return route_strengthen(method, path, body);
}
if (str_eq(method, EL_STR("POST")) && ((str_eq(clean, EL_STR("/api/decay")) || str_eq(clean, EL_STR("/api/maintenance"))) || str_eq(clean, EL_STR("/decay")))) {
return route_decay(method, path, body);
}
if (str_eq(method, EL_STR("POST")) && (str_eq(clean, EL_STR("/api/export")) || str_eq(clean, EL_STR("/export")))) {
return route_export(method, path, body);
}
if (str_eq(method, EL_STR("POST")) && (str_eq(clean, EL_STR("/api/save")) || str_eq(clean, EL_STR("/save")))) {
return route_save(method, path, body);
return route_export(method, path, body);
}
if (str_eq(method, EL_STR("POST")) && (str_eq(clean, EL_STR("/api/load")) || str_eq(clean, EL_STR("/load")))) {
return route_load(method, path, body);
}
if (str_eq(method, EL_STR("POST")) && (str_eq(clean, EL_STR("/api/reindex")) || str_eq(clean, EL_STR("/reindex")))) {
return route_reindex(method, path, body);
}
if (str_starts_with(clean, EL_STR("/api/neuron/"))) {
if (str_eq(clean, EL_STR("/api/neuron/session/begin"))) {
return route_neuron_session_begin(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/ctx"))) {
return route_neuron_ctx(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/memory"))) {
return route_neuron_memory(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/knowledge/capture"))) {
return route_neuron_knowledge_capture(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/knowledge/evolve"))) {
return route_neuron_knowledge_evolve(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/knowledge/promote"))) {
return route_neuron_knowledge_promote(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/recall"))) {
return route_neuron_recall(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/graph/link"))) {
return route_neuron_graph_link(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/graph"))) {
return route_neuron_graph(method, path, body);
}
if (str_starts_with(clean, EL_STR("/api/neuron/list/"))) {
return route_neuron_list(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/consolidate"))) {
return route_neuron_consolidate(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/config"))) {
return route_neuron_config(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/state-events"))) {
return route_neuron_state_events(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/processes/define"))) {
return route_neuron_processes(method, path, body);
}
if (str_eq(clean, EL_STR("/api/neuron/processes"))) {
return route_neuron_processes(method, path, body);
}
}
if (str_eq(clean, EL_STR("/events/next"))) {
return route_events_next(method, path, body);
}
if (str_eq(clean, EL_STR("/events/ack"))) {
return route_events_ack(method, path, body);
}
return el_str_concat(el_str_concat(EL_STR("{\"error\":\"not found\",\"path\":\""), clean), EL_STR("\"}"));
return 0;
}
@@ -362,9 +818,20 @@ int main(int _argc, char** _argv) {
if (str_eq(data_dir, EL_STR(""))) {
data_dir = EL_STR("/tmp/engram");
}
snapshot_path = el_str_concat(data_dir, EL_STR("/snapshot.json"));
engram_load(snapshot_path);
println(EL_STR("[engram] runtime-native graph engine"));
db_path = el_str_concat(data_dir, EL_STR("/engram.db"));
loaded = engram_load_binary_el(db_path);
if (!loaded) {
engram_load_dir(data_dir);
if (engram_node_count() == 0) {
el_val_t snapshot_path = el_str_concat(data_dir, EL_STR("/snapshot.json"));
engram_load(snapshot_path);
}
if (engram_node_count() > 0) {
engram_write_binary_el(db_path);
println(EL_STR("[engram] migrated legacy data to binary format"));
}
}
println(EL_STR("[engram] runtime-native graph engine (ML-KEM-1024 encrypted)"));
println(el_str_concat(EL_STR("[engram] data_dir="), data_dir));
println(el_str_concat(EL_STR("[engram] node_count="), int_to_str(engram_node_count())));
println(el_str_concat(EL_STR("[engram] edge_count="), int_to_str(engram_edge_count())));
+161 -2
View File
@@ -1526,6 +1526,83 @@ void http_serve(el_val_t port, el_val_t handler) {
close(sock);
}
/* ── http_serve_async — non-blocking HTTP server ─────────────────────────── */
/* Runs the accept loop in a background pthread, returns immediately so the
* calling EL script can continue (e.g. to run an awareness loop).
*
* El signature: http_serve_async(port, handler) -> Void */
typedef struct { int sock; } HttpServeAsyncArg;
static void* _http_serve_async_loop(void* raw) {
HttpServeAsyncArg* a = (HttpServeAsyncArg*)raw;
int sock = a->sock;
free(a);
while (1) {
struct sockaddr_in6 cli;
socklen_t clen = sizeof(cli);
int cfd = accept(sock, (struct sockaddr*)&cli, &clen);
if (cfd < 0) {
if (errno == EINTR) continue;
perror("accept"); break;
}
pthread_mutex_lock(&_http_conn_mu);
while (_http_conn_active >= HTTP_MAX_CONNS) {
pthread_cond_wait(&_http_conn_cv, &_http_conn_mu);
}
_http_conn_active++;
pthread_mutex_unlock(&_http_conn_mu);
HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg));
if (!arg) { close(cfd); continue; }
arg->fd = cfd;
pthread_t tid;
if (pthread_create(&tid, NULL, http_worker, arg) != 0) {
close(cfd); free(arg);
pthread_mutex_lock(&_http_conn_mu);
_http_conn_active--;
pthread_cond_signal(&_http_conn_cv);
pthread_mutex_unlock(&_http_conn_mu);
continue;
}
pthread_detach(tid);
}
close(sock);
return NULL;
}
void http_serve_async(el_val_t port, el_val_t handler) {
const char* hname = EL_CSTR(handler);
if (hname && looks_like_string(handler)) {
http_set_handler(handler);
}
int p = (int)port;
if (p <= 0 || p > 65535) { fprintf(stderr, "http_serve_async: invalid port %d\n", p); return; }
int sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock < 0) { perror("socket"); return; }
int yes = 1; int no = 0;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = in6addr_any;
addr.sin6_port = htons((uint16_t)p);
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind"); close(sock); return;
}
if (listen(sock, 64) < 0) { perror("listen"); close(sock); return; }
fprintf(stderr, "[http] async listening on [::]:%d (dual-stack)\n", p);
HttpServeAsyncArg* a = malloc(sizeof(HttpServeAsyncArg));
if (!a) { close(sock); return; }
a->sock = sock;
pthread_t tid;
if (pthread_create(&tid, NULL, _http_serve_async_loop, a) != 0) {
perror("pthread_create"); free(a); close(sock); return;
}
pthread_detach(tid);
/* Returns immediately — caller can now run awareness_run() or any loop. */
}
/* ── HTTP server v2 — request headers + structured response ──────────────── */
/*
* v2 widens the handler signature from
@@ -5884,6 +5961,7 @@ static int engram_load_binary(const char* path);
static void engram_embed_node(EngramNode* n);
static float engram_cosine_sim(const float* a, const float* b, uint32_t dim);
static void engram_checkpoint(void);
static void engram_emit_ise_internal(const char* content, const char* label);
/* Salience may arrive either as a float bit-pattern or as a small integer
* (e.g. 1, meaning 1.0). Heuristic: if interpreted as double it's in
@@ -5977,6 +6055,14 @@ el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label,
engram_checkpoint();
/* engram_persist_node is now a no-op — binary checkpoint handles persistence */
engram_persist_node(engram_data_dir(), n);
/* ISE: high-importance node written */
if (n->importance >= 0.8f) {
char ise_buf[512];
snprintf(ise_buf, sizeof(ise_buf),
"{\"event\":\"high_importance_node\",\"node_id\":\"%s\",\"node_type\":\"%s\",\"importance\":%.2f,\"ts\":%lld}",
n->id, n->node_type, n->importance, (long long)(time(NULL)*1000LL));
engram_emit_ise_internal(ise_buf, "high-importance-node");
}
return el_wrap_str(el_strdup(n->id));
}
@@ -6844,9 +6930,35 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) {
n->suppression_count = 0;
}
/* Persist working_memory_weight (post Pass 3) to node store. */
/* Persist working_memory_weight (post Pass 3) to node store.
* Also emit ISE when a node transitions into working memory (was 0, now > 0.5),
* excluding InternalStateEvent nodes to prevent ISEs about ISEs. */
for (int64_t i = 0; i < g->node_count; i++) {
g->nodes[i].working_memory_weight = wm_weights[i];
EngramNode* wn = &g->nodes[i];
double prev_wm = wn->working_memory_weight;
wn->working_memory_weight = wm_weights[i];
/* ISE: working memory promotion — only on 0→>0.5 transition, non-ISE nodes */
if (prev_wm <= 0.0 && wm_weights[i] > 0.5 &&
wn->node_type && strcmp(wn->node_type, "InternalStateEvent") != 0) {
char ise_buf[512];
char label_safe[64];
const char* lbl = wn->label ? wn->label : "";
size_t llen = strlen(lbl);
if (llen > 60) llen = 60;
memcpy(label_safe, lbl, llen);
/* Escape any double-quotes in label for JSON safety */
size_t out = 0;
for (size_t k = 0; k < llen && out < 62; k++) {
if (lbl[k] == '"' || lbl[k] == '\\') label_safe[out++] = '\\';
label_safe[out++] = lbl[k];
}
label_safe[out] = '\0';
snprintf(ise_buf, sizeof(ise_buf),
"{\"event\":\"wm_promotion\",\"node_id\":\"%s\",\"label\":\"%s\",\"salience\":%.3f,\"wm_weight\":%.3f,\"ts\":%lld}",
wn->id, label_safe, wn->salience, wm_weights[i],
(long long)(time(NULL)*1000LL));
engram_emit_ise_internal(ise_buf, "wm-promotion");
}
}
/* ── HEBBIAN STRENGTHENING: fire together, wire together ─────────────
@@ -7661,6 +7773,43 @@ static int engram_load_binary(const char* path) {
return 1;
}
/* ── Internal ISE emission ────────────────────────────────────────────────── */
/* Fires an InternalStateEvent node directly into the in-memory graph from
* within core processing paths. Guarded against recursion so it's safe to
* call from node-write and activation paths. */
static int g_in_ise_emit = 0;
static void engram_emit_ise_internal(const char* content, const char* label) {
if (g_in_ise_emit) return; /* recursion guard */
if (!content || !*content) return;
g_in_ise_emit = 1;
EngramStore* g = engram_get();
engram_grow_nodes();
EngramNode* n = &g->nodes[g->node_count];
memset(n, 0, sizeof(*n));
n->id = engram_new_id();
n->content = strdup(content);
n->node_type = strdup("InternalStateEvent");
n->label = strdup(label && *label ? label : "ise");
n->tier = strdup("Working");
n->tags = strdup("internal-state,ise-internal");
n->metadata = strdup("{}");
n->salience = 0.3f;
n->importance = 0.5f;
n->confidence = 1.0f;
n->temporal_decay_rate = 0.0;
n->activation_count = 0;
int64_t now = engram_now_ms();
n->last_activated = now;
n->created_at = now;
n->updated_at = now;
n->layer_id = ENGRAM_LAYER_DEFAULT;
g->node_count++;
/* Skip engram_embed_node and engram_checkpoint to avoid recursion */
g_in_ise_emit = 0;
}
/* Checkpoint: save binary every ENGRAM_CHECKPOINT_INTERVAL writes. */
static void engram_checkpoint(void) {
g_writes_since_checkpoint++;
@@ -7671,6 +7820,16 @@ static void engram_checkpoint(void) {
snprintf(db_path, sizeof(db_path), "%s/engram.db", ddir);
if (engram_write_binary(db_path)) {
fprintf(stderr, "[engram] checkpoint saved: %s\n", db_path);
/* ISE: graph state at checkpoint */
EngramStore* g = engram_get();
char ise_buf[512];
struct stat st; long db_bytes = 0;
if (stat(db_path, &st) == 0) db_bytes = (long)st.st_size;
snprintf(ise_buf, sizeof(ise_buf),
"{\"event\":\"checkpoint\",\"nodes\":%lld,\"edges\":%lld,\"db_bytes\":%ld,\"ts\":%lld}",
(long long)g->node_count, (long long)g->edge_count,
db_bytes, (long long)(time(NULL)*1000LL));
engram_emit_ise_internal(ise_buf, "checkpoint");
}
}
@@ -143,6 +143,7 @@ el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_m
el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header);
el_val_t http_delete(el_val_t url);
void http_serve(el_val_t port, el_val_t handler);
void http_serve_async(el_val_t port, el_val_t handler);
void http_set_handler(el_val_t name);
/* HTTP server v2 ─────────────────────────────────────────────────────────────