diff --git a/elp/src/elp.elh b/elp/src/elp.elh index ab8a621..f9d2323 100644 --- a/elp/src/elp.elh +++ b/elp/src/elp.elh @@ -1,7 +1,7 @@ // auto-generated by elc --emit-header — do not edit extern fn sem_get(json: String, key: String) -> String -extern fn generate_frame(frame: Any) -> String -extern fn generate_frame_lang(frame: Any, lang_code: String) -> String -extern fn build_form_from_json(semantic_form_json: String, lang_code: String) -> Any +extern fn generate_frame(frame: [String]) -> String +extern fn generate_frame_lang(frame: [String], lang_code: String) -> String +extern fn build_form_from_json(semantic_form_json: String, lang_code: String) -> [String] extern fn generate(semantic_form_json: String) -> String extern fn generate_lang(semantic_form_json: String, lang_code: String) -> String diff --git a/elp/src/grammar.elh b/elp/src/grammar.elh index ef8cf80..f678627 100644 --- a/elp/src/grammar.elh +++ b/elp/src/grammar.elh @@ -1,22 +1,22 @@ -// auto-generated by elc --emit-header - do not edit -extern fn slots_get(slots: Any, key: String) -> String -extern fn slots_set(slots: Any, key: String, val: String) -> Any -extern fn make_slots(k0: String, v0: String) -> Any -extern fn make_slots2(k0: String, v0: String, k1: String, v1: String) -> Any -extern fn make_slots3(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String) -> Any -extern fn make_slots4(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String) -> Any -extern fn make_slots5(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String, k4: String, v4: String) -> Any -extern fn rule_id(rule: Any) -> String -extern fn rule_lhs(rule: Any) -> String -extern fn rule_rhs_len(rule: Any) -> Int -extern fn rule_rhs(rule: Any, idx: Int) -> String -extern fn make_rule(id: String, lhs: String, r0: String) -> Any -extern fn make_rule2(id: String, lhs: String, r0: String, r1: String) -> Any -extern fn make_rule3(id: String, lhs: String, r0: String, r1: String, r2: String) -> Any -extern fn make_rule4(id: String, lhs: String, r0: String, r1: String, r2: String, r3: String) -> Any -extern fn build_rules() -> Any -extern fn get_rules() -> Any -extern fn find_rule(rule_id_str: String) -> Any +// auto-generated by elc --emit-header — do not edit +extern fn slots_get(slots: [String], key: String) -> String +extern fn slots_set(slots: [String], key: String, val: String) -> [String] +extern fn make_slots(k0: String, v0: String) -> [String] +extern fn make_slots2(k0: String, v0: String, k1: String, v1: String) -> [String] +extern fn make_slots3(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String) -> [String] +extern fn make_slots4(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String) -> [String] +extern fn make_slots5(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String, k4: String, v4: String) -> [String] +extern fn rule_id(rule: [String]) -> String +extern fn rule_lhs(rule: [String]) -> String +extern fn rule_rhs_len(rule: [String]) -> Int +extern fn rule_rhs(rule: [String], idx: Int) -> String +extern fn make_rule(id: String, lhs: String, r0: String) -> [String] +extern fn make_rule2(id: String, lhs: String, r0: String, r1: String) -> [String] +extern fn make_rule3(id: String, lhs: String, r0: String, r1: String, r2: String) -> [String] +extern fn make_rule4(id: String, lhs: String, r0: String, r1: String, r2: String, r3: String) -> [String] +extern fn build_rules() -> [[String]] +extern fn get_rules() -> [[String]] +extern fn find_rule(rule_id_str: String) -> [String] extern fn make_leaf(label: String, word: String) -> String extern fn make_node1(label: String, child0: String) -> String extern fn make_node2(label: String, child0: String, child1: String) -> String @@ -24,15 +24,15 @@ extern fn make_node3(label: String, child0: String, child1: String, child2: Stri extern fn make_node4(label: String, child0: String, child1: String, child2: String, child3: String) -> String extern fn nlg_is_ws(c: String) -> Bool extern fn skip_ws(s: String, pos: Int) -> Int -extern fn scan_token(s: String, start: Int) -> Any +extern fn scan_token(s: String, start: Int) -> [String] extern fn render_tree(tree: String) -> String -extern fn gram_word_order(profile: Any) -> String -extern fn gram_order_constituents(subj: String, verb: String, obj: String, profile: Any) -> String -extern fn gram_build_vp(verb: String, aux: String, profile: Any) -> String -extern fn gram_question_strategy(profile: Any) -> String +extern fn gram_word_order(profile: [String]) -> String +extern fn gram_order_constituents(subj: String, verb: String, obj: String, profile: [String]) -> String +extern fn gram_build_vp(verb: String, aux: String, profile: [String]) -> String +extern fn gram_question_strategy(profile: [String]) -> String extern fn is_pronoun(word: String) -> Bool -extern fn build_np(referent: String, slots: Any) -> String +extern fn build_np(referent: String, slots: [String]) -> String extern fn build_pp(loc: String) -> String -extern fn build_vp_body(slots: Any) -> String -extern fn build_vp_from_slots(slots: Any) -> String -extern fn generate_tree(rule_id_str: String, slots: Any) -> String +extern fn build_vp_body(slots: [String]) -> String +extern fn build_vp_from_slots(slots: [String]) -> String +extern fn generate_tree(rule_id_str: String, slots: [String]) -> String diff --git a/elp/src/realizer.elh b/elp/src/realizer.elh index 5bf5696..445f6fe 100644 --- a/elp/src/realizer.elh +++ b/elp/src/realizer.elh @@ -1,10 +1,10 @@ -// auto-generated by elc --emit-header - do not edit +// auto-generated by elc --emit-header — do not edit extern fn agent_person(agent: String) -> String extern fn agent_number(agent: String) -> String extern fn realize_np(referent: String, number: String) -> String -extern fn realize_vp_lang(base_verb: String, tense: String, aspect: String, person: String, number: String, profile: Any) -> Any -extern fn realize_question_lang(predicate: String, tense: String, aspect: String, person: String, number: String, agent: String, patient: String, location: String, profile: Any) -> String +extern fn realize_vp_lang(base_verb: String, tense: String, aspect: String, person: String, number: String, profile: [String]) -> [String] +extern fn realize_question_lang(predicate: String, tense: String, aspect: String, person: String, number: String, agent: String, patient: String, location: String, profile: [String]) -> String extern fn capitalize_first(s: String) -> String extern fn add_punct(s: String, intent: String) -> String -extern fn realize_lang(form: Any, profile: Any) -> String -extern fn realize(form: Any) -> String +extern fn realize_lang(form: [String], profile: [String]) -> String +extern fn realize(form: [String]) -> String diff --git a/elp/src/semantics.elh b/elp/src/semantics.elh index 68304f8..80f930e 100644 --- a/elp/src/semantics.elh +++ b/elp/src/semantics.elh @@ -1,18 +1,18 @@ -// auto-generated by elc --emit-header - do not edit -extern fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) -> Any -extern fn sem_frame_lang(intent: String, subject: String, obj: String, modifiers: String, lang_code: String) -> Any -extern fn sem_frame_simple(intent: String, subject: String) -> Any -extern fn sem_frame_obj(intent: String, subject: String, obj: String) -> Any -extern fn sem_intent(frame: Any) -> String -extern fn sem_subject(frame: Any) -> String -extern fn sem_object(frame: Any) -> String -extern fn sem_modifiers(frame: Any) -> String -extern fn sem_lang(frame: Any) -> String +// auto-generated by elc --emit-header — do not edit +extern fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) -> [String] +extern fn sem_frame_lang(intent: String, subject: String, obj: String, modifiers: String, lang_code: String) -> [String] +extern fn sem_frame_simple(intent: String, subject: String) -> [String] +extern fn sem_frame_obj(intent: String, subject: String, obj: String) -> [String] +extern fn sem_intent(frame: [String]) -> String +extern fn sem_subject(frame: [String]) -> String +extern fn sem_object(frame: [String]) -> String +extern fn sem_modifiers(frame: [String]) -> String +extern fn sem_lang(frame: [String]) -> String extern fn sem_first_modifier(mods: String) -> String extern fn sem_intent_to_realize(intent: String) -> String -extern fn sem_to_spec(frame: Any) -> Any -extern fn sem_to_spec_full(frame: Any, verb: String, tense: String, aspect: String) -> Any +extern fn sem_to_spec(frame: [String]) -> [String] +extern fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String) -> [String] extern fn sem_realize_greet(subject: String) -> String -extern fn sem_realize(frame: Any) -> String -extern fn sem_realize_full(frame: Any, verb: String, tense: String, aspect: String) -> String -extern fn sem_realize_lang(frame: Any, lang_code: String) -> String +extern fn sem_realize(frame: [String]) -> String +extern fn sem_realize_full(frame: [String], verb: String, tense: String, aspect: String) -> String +extern fn sem_realize_lang(frame: [String], lang_code: String) -> String diff --git a/engram/dist/engram b/engram/dist/engram index 95430e2..7480045 100755 Binary files a/engram/dist/engram and b/engram/dist/engram differ diff --git a/engram/dist/engram.c b/engram/dist/engram.c index 6bbcf52..da21925 100644 --- a/engram/dist/engram.c +++ b/engram/dist/engram.c @@ -23,6 +23,7 @@ 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_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_sync(el_val_t method, el_val_t path, el_val_t body); el_val_t route_emit_ise(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); @@ -277,6 +278,21 @@ el_val_t route_health(el_val_t method, el_val_t path, el_val_t body) { return 0; } +el_val_t route_sync(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 snap_path = el_str_concat(dir, EL_STR("/snapshot.json")); + engram_save(snap_path); + el_val_t snap = fs_read(snap_path); + if (str_eq(snap, EL_STR(""))) { + return EL_STR("{\"nodes\":[],\"edges\":[]}"); + } + return snap; + return 0; +} + el_val_t route_emit_ise(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(""))) { @@ -364,6 +380,9 @@ 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/load")) || str_eq(clean, EL_STR("/load")))) { return route_load(method, path, body); } + if (str_eq(method, EL_STR("GET")) && str_eq(clean, EL_STR("/api/sync"))) { + return route_sync(method, path, body); + } return el_str_concat(el_str_concat(EL_STR("{\"error\":\"not found\",\"path\":\""), clean), EL_STR("\"}")); return 0; } diff --git a/engram/src/server.el b/engram/src/server.el index 35cc61f..e676d32 100644 --- a/engram/src/server.el +++ b/engram/src/server.el @@ -206,6 +206,28 @@ fn route_health(method: String, path: String, body: String) -> String { "{\"status\":\"ok\",\"engine\":\"engram-runtime-native\"}" } +// route_sync — return a snapshot of non-ISE/non-Working nodes for the soul daemon +// to merge into its in-process graph via engram_load_merge. +// +// The soul calls GET /api/sync every SOUL_REFRESH_MS (default 10 min) to pull +// new Knowledge/Memory/BacklogItem nodes from the authoritative HTTP Engram into +// its in-process working store. Previously this returned 404 "not found", causing +// the soul to write the error JSON to a temp file and attempt an empty merge. +// +// Strategy: save the current snapshot to disk, read it back, return the full +// snapshot JSON. The soul's engram_load_merge handles large files gracefully +// (it skips nodes already present by ID). Auth-exempt: same-host internal call. +// (2026-06-27 self-review: added this route to fix silent 10-min sync failures) +fn route_sync(method: String, path: String, body: String) -> String { + let dir: String = env("ENGRAM_DATA_DIR") + if str_eq(dir, "") { let dir = "/tmp/engram" } + let snap_path: String = dir + "/snapshot.json" + engram_save(snap_path) + let snap: String = fs_read(snap_path) + if str_eq(snap, "") { return "{\"nodes\":[],\"edges\":[]}" } + return snap +} + // route_emit_ise — write an InternalStateEvent node from the soul daemon. // // Endpoint: POST /api/neuron/state-events @@ -330,6 +352,11 @@ fn handle_request(method: String, path: String, body: String) -> String { return route_load(method, path, body) } + // Sync — soul daemon periodic pull of non-ISE knowledge into in-process graph + if str_eq(method, "GET") && str_eq(clean, "/api/sync") { + return route_sync(method, path, body) + } + "{\"error\":\"not found\",\"path\":\"" + clean + "\"}" }