Add Ollama provider, portable memory, cultivation digest, refugee importer, GLM-OCR spike
- P0: unified soul binary with engram_node_full fix, read-back-verify, search fix - P0: move API keys from plaintext plists to macOS Keychain - P0: fix MCP backend URL (port 8742 → 7770) - P1.6: memory-export/import scripts (AES-256-CBC, versioned .neuronmem format) - P1.7: nightly cultivation digest with sharpness metric (launchd at 23:55) - P2.10: Ollama provider in agentic loop (SOUL_LLM_PROVIDER=ollama) - P3.12: refugee importer for ChatGPT/Screenpipe/generic formats - P3.13: GLM-OCR spike — SHIP IT (mlx-vlm, 1.59GB, photo-to-memory.sh)
This commit is contained in:
+1
-2
@@ -679,8 +679,7 @@ el_val_t handle_chat(el_val_t body) {
|
||||
el_val_t thread_snip = ({ el_val_t _if_result_112 = 0; if ((str_len(last_content) > 250)) { _if_result_112 = (str_slice(last_content, 0, 250)); } else { _if_result_112 = (last_content); } _if_result_112; });
|
||||
el_val_t activation_seed = ({ el_val_t _if_result_113 = 0; if (!str_eq(thread_snip, EL_STR(""))) { _if_result_113 = (el_str_concat(el_str_concat(thread_snip, EL_STR(" ")), message)); } else { _if_result_113 = (message); } _if_result_113; });
|
||||
el_val_t affective_prefix = EL_NULL;
|
||||
EL_NULL;
|
||||
Int = time_now();
|
||||
el_val_t aff_now_ts = time_now();
|
||||
el_val_t aff_cutoff = (aff_now_ts - 259200);
|
||||
el_val_t boot_aff = state_get(EL_STR("soul_affective_context"));
|
||||
el_val_t has_boot_aff = !str_eq(boot_aff, EL_STR(""));
|
||||
|
||||
+34
-24028
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -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
|
||||
|
||||
-5
@@ -656,8 +656,3 @@ el_val_t generate_tree(el_val_t rule_id_str, el_val_t slots) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
el_runtime_init_args(_argc, _argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+28
-28
@@ -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
|
||||
|
||||
-5
@@ -392,8 +392,3 @@ el_val_t lang_code(el_val_t profile) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
el_runtime_init_args(_argc, _argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+23
-3
@@ -34,7 +34,18 @@ el_val_t tier_canonical(void) {
|
||||
}
|
||||
|
||||
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags) {
|
||||
return engram_node_full(content, EL_STR("Memory"), label, el_from_float(0.5), el_from_float(0.5), el_from_float(0.8), EL_STR("Working"), tags);
|
||||
el_val_t id = engram_node_full(content, EL_STR("Memory"), label, el_from_float(0.5), el_from_float(0.5), el_from_float(0.8), EL_STR("Working"), tags);
|
||||
if (str_eq(id, EL_STR(""))) {
|
||||
println(el_str_concat(EL_STR("[memory] write rejected by engram (empty id): label="), label));
|
||||
return EL_STR("");
|
||||
}
|
||||
el_val_t readback = engram_get_node_json(id);
|
||||
if (str_eq(readback, EL_STR("")) || str_eq(readback, EL_STR("{}"))) {
|
||||
println(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] WRITE VERIFY FAILED: label="), label), EL_STR(" id=")), id), EL_STR(" \xe2\x80\x94 node absent after write")));
|
||||
return EL_STR("");
|
||||
}
|
||||
println(el_str_concat(el_str_concat(EL_STR("[memory] write verified: "), id), EL_STR(" ok")));
|
||||
return id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -136,7 +147,12 @@ el_val_t mem_boot_count_inc(void) {
|
||||
el_val_t tags = EL_STR("[\"soul-meta\",\"boot-counter\"]");
|
||||
el_val_t boot_node_id = engram_node_full(content, EL_STR("Memory"), EL_STR("soul:boot_count"), el_from_float(0.9), el_from_float(0.9), el_from_float(1.0), EL_STR("Canonical"), tags);
|
||||
if (str_eq(boot_node_id, EL_STR(""))) {
|
||||
println(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: engram write failed \xe2\x80\x94 boot counter node lost (count="), int_to_str(next)), EL_STR(")")));
|
||||
println(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: write rejected (empty id) \xe2\x80\x94 boot counter node lost (count="), int_to_str(next)), EL_STR(")")));
|
||||
return next;
|
||||
}
|
||||
el_val_t boot_readback = engram_get_node_json(boot_node_id);
|
||||
if (str_eq(boot_readback, EL_STR("")) || str_eq(boot_readback, EL_STR("{}"))) {
|
||||
println(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id="), boot_node_id), EL_STR(" count=")), int_to_str(next)));
|
||||
}
|
||||
return next;
|
||||
return 0;
|
||||
@@ -149,7 +165,11 @@ el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content)
|
||||
el_val_t safe_content = str_replace(content, EL_STR("\""), EL_STR("'"));
|
||||
el_val_t payload = 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("{\"trigger\":\""), safe_trigger), EL_STR("\"")), EL_STR(",\"kind\":\"")), kind), EL_STR("\"")), EL_STR(",\"content\":\"")), safe_content), EL_STR("\"")), EL_STR(",\"boot\":")), int_to_str(boot)), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
|
||||
el_val_t tags = EL_STR("[\"internal-state\",\"pre-reasoning\",\"InternalStateEvent\"]");
|
||||
return engram_node_full(payload, EL_STR("InternalStateEvent"), el_str_concat(EL_STR("state-event:"), kind), el_from_float(0.85), el_from_float(0.8), el_from_float(0.9), EL_STR("Episodic"), tags);
|
||||
el_val_t event_id = engram_node_full(payload, EL_STR("InternalStateEvent"), el_str_concat(EL_STR("state-event:"), kind), el_from_float(0.85), el_from_float(0.8), el_from_float(0.9), EL_STR("Episodic"), tags);
|
||||
if (str_eq(event_id, EL_STR(""))) {
|
||||
println(el_str_concat(EL_STR("[memory] mem_emit_state_event: write rejected (empty id): kind="), kind));
|
||||
}
|
||||
return event_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -180,7 +180,7 @@ el_val_t api_persisted(el_val_t id) {
|
||||
return 0;
|
||||
}
|
||||
el_val_t node = engram_get_node_json(id);
|
||||
return (!str_eq(node, EL_STR("")) && !str_eq(node, EL_STR("null")));
|
||||
return ((!str_eq(node, EL_STR("")) && !str_eq(node, EL_STR("null"))) && !str_eq(node, EL_STR("{}")));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+2
-7
@@ -193,10 +193,10 @@ el_val_t realize_question_lang(el_val_t predicate, el_val_t tense, el_val_t aspe
|
||||
loc_part = core;
|
||||
}
|
||||
if (str_eq(code, EL_STR("ja"))) {
|
||||
return el_str_concat(loc_part, EL_STR(" か"));
|
||||
return el_str_concat(loc_part, EL_STR(" \xe3\x81\x8b"));
|
||||
}
|
||||
if (str_eq(code, EL_STR("hi"))) {
|
||||
return el_str_concat(loc_part, EL_STR(" क्या"));
|
||||
return el_str_concat(loc_part, EL_STR(" \xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xaf\xe0\xa4\xbe"));
|
||||
}
|
||||
if (str_eq(code, EL_STR("fi"))) {
|
||||
return el_str_concat(loc_part, EL_STR("-ko"));
|
||||
@@ -314,8 +314,3 @@ el_val_t realize(el_val_t form) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
el_runtime_init_args(_argc, _argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -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
|
||||
|
||||
-5
@@ -291,8 +291,3 @@ el_val_t sem_realize_lang(el_val_t frame, el_val_t lang_code) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
el_runtime_init_args(_argc, _argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -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
|
||||
|
||||
+140
-2
@@ -25258,7 +25258,18 @@ el_val_t tier_canonical(void) {
|
||||
}
|
||||
|
||||
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags) {
|
||||
return engram_node_full(content, EL_STR("Memory"), label, el_from_float(el_from_float(0.5)), el_from_float(el_from_float(0.5)), el_from_float(el_from_float(0.8)), EL_STR("Working"), tags);
|
||||
el_val_t id = engram_node_full(content, EL_STR("Memory"), label, el_from_float(el_from_float(0.5)), el_from_float(el_from_float(0.5)), el_from_float(el_from_float(0.8)), EL_STR("Working"), tags);
|
||||
if (str_eq(id, EL_STR(""))) {
|
||||
println(el_str_concat(EL_STR("[memory] write rejected by engram (empty id): label="), label));
|
||||
return EL_STR("");
|
||||
}
|
||||
el_val_t readback = engram_get_node_json(id);
|
||||
if (str_eq(readback, EL_STR("")) || str_eq(readback, EL_STR("{}"))) {
|
||||
println(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] WRITE VERIFY FAILED: label="), label), EL_STR(" id=")), id), EL_STR(" \xe2\x80\x94 node absent after write")));
|
||||
return EL_STR("");
|
||||
}
|
||||
println(el_str_concat(el_str_concat(EL_STR("[memory] write verified: "), id), EL_STR(" ok")));
|
||||
return id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27028,6 +27039,27 @@ el_val_t next_bridge_id(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* === P2.10: Convert Anthropic tools format to OpenAI function-calling format === */
|
||||
el_val_t anthropic_tools_to_openai(el_val_t tools_json) {
|
||||
el_val_t len = json_array_len(tools_json);
|
||||
if (len <= 0) { return EL_STR("[]"); }
|
||||
el_val_t result = EL_STR("[");
|
||||
el_val_t i = 0;
|
||||
while (i < len) {
|
||||
el_val_t tool = json_array_get(tools_json, i);
|
||||
el_val_t tname = json_get(tool, EL_STR("name"));
|
||||
el_val_t tdesc = json_safe(json_get(tool, EL_STR("description")));
|
||||
el_val_t tschema = json_get_raw(tool, EL_STR("input_schema"));
|
||||
if (str_eq(tschema, EL_STR(""))) { tschema = EL_STR("{\"type\":\"object\",\"properties\":{}}"); }
|
||||
el_val_t oai_tool = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"type\":\"function\",\"function\":{\"name\":\""), tname), EL_STR("\",\"description\":\"")), tdesc), EL_STR("\",\"parameters\":")), tschema), EL_STR("}}"));
|
||||
if (i > 0) { result = el_str_concat(result, EL_STR(",")); }
|
||||
result = el_str_concat(result, oai_tool);
|
||||
i = (i + 1);
|
||||
}
|
||||
return el_str_concat(result, EL_STR("]"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t agentic_loop(el_val_t session_id, el_val_t model, el_val_t safe_sys, el_val_t tools_json, el_val_t messages_in, el_val_t h, el_val_t tools_log_in) {
|
||||
el_val_t api_url = EL_STR("https://api.anthropic.com/v1/messages");
|
||||
el_val_t messages = messages_in;
|
||||
@@ -27039,6 +27071,87 @@ el_val_t agentic_loop(el_val_t session_id, el_val_t model, el_val_t safe_sys, el
|
||||
el_val_t pend_tool_id = EL_STR("");
|
||||
el_val_t pend_tool_name = EL_STR("");
|
||||
el_val_t pend_tool_input = EL_STR("");
|
||||
/* === P2.10: OLLAMA/OPENAI-COMPAT PROVIDER BRANCH === */
|
||||
{
|
||||
el_val_t _ol_prov = env(EL_STR("SOUL_LLM_PROVIDER"));
|
||||
if (str_eq(_ol_prov, EL_STR("ollama"))) {
|
||||
el_val_t _ol_model = env(EL_STR("SOUL_LLM_MODEL"));
|
||||
if (str_eq(_ol_model, EL_STR(""))) { _ol_model = env(EL_STR("OLLAMA_MODEL")); }
|
||||
if (str_eq(_ol_model, EL_STR(""))) { _ol_model = EL_STR("llama3.1"); }
|
||||
el_val_t _ol_base = env(EL_STR("OLLAMA_API_BASE"));
|
||||
if (str_eq(_ol_base, EL_STR(""))) { _ol_base = EL_STR("http://localhost:11434"); }
|
||||
el_val_t _ol_url = el_str_concat(_ol_base, EL_STR("/v1/chat/completions"));
|
||||
println(el_str_concat(el_str_concat(el_str_concat(EL_STR("[soul] provider: ollama @ "), _ol_base), EL_STR(" (model: ")), el_str_concat(_ol_model, EL_STR(")"))));
|
||||
el_val_t _ol_oai_tools = anthropic_tools_to_openai(tools_json);
|
||||
/* Build initial OpenAI-format messages: prepend system message to existing turns */
|
||||
el_val_t _ol_sys_msg = el_str_concat(el_str_concat(EL_STR("{\"role\":\"system\",\"content\":\""), safe_sys), EL_STR("\"}"));
|
||||
el_val_t _ol_msgs_inner = str_slice(messages_in, 1, (str_len(messages_in) - 1));
|
||||
el_val_t _ol_msgs = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("["), _ol_sys_msg), EL_STR(",")), _ol_msgs_inner), EL_STR("]"));
|
||||
el_val_t _ol_h = el_map_new(0);
|
||||
map_set(_ol_h, EL_STR("content-type"), EL_STR("application/json"));
|
||||
el_val_t _ol_keep = 1;
|
||||
el_val_t _ol_iter = 0;
|
||||
el_val_t _ol_final = EL_STR("");
|
||||
while (_ol_keep && (_ol_iter < 8)) {
|
||||
el_val_t _ol_req = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"model\":\""), _ol_model), EL_STR("\",\"messages\":")), _ol_msgs), EL_STR(",\"stream\":false,\"tools\":")), _ol_oai_tools), EL_STR("}"));
|
||||
el_val_t _ol_resp = http_post_with_headers(_ol_url, _ol_req, _ol_h);
|
||||
if (str_eq(_ol_resp, EL_STR("")) || str_starts_with(_ol_resp, EL_STR("{\"error\""))) {
|
||||
return EL_STR("{\"error\":\"llm unavailable\",\"reply\":\"\"}");
|
||||
}
|
||||
el_val_t _ol_choices = json_get_raw(_ol_resp, EL_STR("choices"));
|
||||
if (str_eq(_ol_choices, EL_STR("")) || str_eq(_ol_choices, EL_STR("null"))) {
|
||||
return EL_STR("{\"error\":\"no choices in response\",\"reply\":\"\"}");
|
||||
}
|
||||
el_val_t _ol_c0 = json_array_get(_ol_choices, 0);
|
||||
el_val_t _ol_c0_msg = json_get_raw(_ol_c0, EL_STR("message"));
|
||||
el_val_t _ol_content = json_get(_ol_c0_msg, EL_STR("content"));
|
||||
el_val_t _ol_tcs = json_get_raw(_ol_c0_msg, EL_STR("tool_calls"));
|
||||
el_val_t _ol_has_tc = (!str_eq(_ol_tcs, EL_STR("")) && !str_eq(_ol_tcs, EL_STR("null")));
|
||||
el_val_t _ol_text = EL_STR("");
|
||||
if (!str_eq(_ol_content, EL_STR("")) && !str_eq(_ol_content, EL_STR("null"))) { _ol_text = _ol_content; }
|
||||
el_val_t _ol_tname = EL_STR("");
|
||||
el_val_t _ol_tid = EL_STR("");
|
||||
el_val_t _ol_tinput = EL_STR("");
|
||||
if (_ol_has_tc) {
|
||||
el_val_t _ol_tc0 = json_array_get(_ol_tcs, 0);
|
||||
_ol_tid = json_get(_ol_tc0, EL_STR("id"));
|
||||
el_val_t _ol_fn = json_get_raw(_ol_tc0, EL_STR("function"));
|
||||
_ol_tname = json_get(_ol_fn, EL_STR("name"));
|
||||
_ol_tinput = json_get(_ol_fn, EL_STR("arguments"));
|
||||
}
|
||||
el_val_t _ol_is_tool = (_ol_has_tc && !str_eq(_ol_tname, EL_STR("")));
|
||||
el_val_t _ol_result_raw = EL_STR("");
|
||||
if (_ol_is_tool) { _ol_result_raw = dispatch_tool(_ol_tname, _ol_tinput); }
|
||||
el_val_t _ol_result = _ol_result_raw;
|
||||
if (str_len(_ol_result_raw) > 6000) { _ol_result = el_str_concat(str_slice(_ol_result_raw, 0, 6000), EL_STR("...[truncated]")); }
|
||||
if (_ol_has_tc) {
|
||||
el_val_t _ol_tq = el_str_concat(el_str_concat(EL_STR("\""), _ol_tname), EL_STR("\""));
|
||||
if (str_eq(tools_log, EL_STR(""))) { tools_log = _ol_tq; } else { tools_log = el_str_concat(el_str_concat(tools_log, EL_STR(",")), _ol_tq); }
|
||||
}
|
||||
/* arguments must be re-serialized as JSON string for OpenAI assistant message */
|
||||
el_val_t _ol_tinput_escaped = el_str_concat(el_str_concat(EL_STR("\""), json_safe(_ol_tinput)), EL_STR("\""));
|
||||
if (_ol_is_tool) {
|
||||
/* Append assistant tool_call message and tool result to messages */
|
||||
el_val_t _ol_asst_tc = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"role\":\"assistant\",\"content\":null,\"tool_calls\":[{\"id\":\""), _ol_tid), EL_STR("\",\"type\":\"function\",\"function\":{\"name\":\"")), _ol_tname), EL_STR("\",\"arguments\":")), _ol_tinput_escaped), EL_STR("}}]}"));
|
||||
el_val_t _ol_tool_msg = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"role\":\"tool\",\"tool_call_id\":\""), _ol_tid), EL_STR("\",\"content\":\"")), json_safe(_ol_result)), EL_STR("\"}"));
|
||||
el_val_t _ol_cur_inner = str_slice(_ol_msgs, 1, (str_len(_ol_msgs) - 1));
|
||||
_ol_msgs = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("["), _ol_cur_inner), EL_STR(",")), _ol_asst_tc), EL_STR(",")), _ol_tool_msg), EL_STR("]"));
|
||||
} else {
|
||||
_ol_final = _ol_text;
|
||||
_ol_keep = 0;
|
||||
}
|
||||
_ol_iter = (_ol_iter + 1);
|
||||
}
|
||||
if (str_eq(_ol_final, EL_STR(""))) {
|
||||
return EL_STR("{\"error\":\"no response\",\"reply\":\"\"}");
|
||||
}
|
||||
el_val_t _ol_safe_final = json_safe(_ol_final);
|
||||
el_val_t _ol_tools_arr = EL_STR("[]");
|
||||
if (!str_eq(tools_log, EL_STR(""))) { _ol_tools_arr = el_str_concat(el_str_concat(EL_STR("["), tools_log), EL_STR("]")); }
|
||||
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"reply\":\""), _ol_safe_final), EL_STR("\",\"model\":\"")), _ol_model), EL_STR("\",\"agentic\":true,\"tools_used\":")), _ol_tools_arr), EL_STR("}"));
|
||||
}
|
||||
}
|
||||
/* === END OLLAMA BRANCH === */
|
||||
while (keep_going && (iteration < 8)) {
|
||||
el_val_t req_body = 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("{\"model\":\""), model), EL_STR("\"")), EL_STR(",\"max_tokens\":4096")), EL_STR(",\"system\":\"")), safe_sys), EL_STR("\"")), EL_STR(",\"tools\":")), tools_json), EL_STR(",\"messages\":")), messages), EL_STR("}"));
|
||||
el_val_t raw_resp = http_post_with_headers(api_url, req_body, h);
|
||||
@@ -27236,7 +27349,16 @@ el_val_t handle_dharma_room_turn(el_val_t body) {
|
||||
}
|
||||
el_val_t clean_response = clean_llm_response(raw_response);
|
||||
el_val_t snap_path = state_get(EL_STR("soul_snapshot_path"));
|
||||
el_val_t discard_id = engram_node(clean_response, EL_STR("episodic"), el_from_float(el_from_float(0.6)));
|
||||
el_val_t utterance_tags = EL_STR("[\"soul-utterance\",\"episodic\"]");
|
||||
el_val_t discard_id = engram_node_full(clean_response, EL_STR("Conversation"), EL_STR("soul:utterance"), el_from_float(el_from_float(0.6)), el_from_float(el_from_float(0.6)), el_from_float(el_from_float(0.8)), EL_STR("Episodic"), utterance_tags);
|
||||
if (!str_eq(discard_id, EL_STR(""))) {
|
||||
el_val_t utterance_verify = engram_get_node_json(discard_id);
|
||||
if (str_eq(utterance_verify, EL_STR("")) || str_eq(utterance_verify, EL_STR("{}"))) {
|
||||
println(el_str_concat(el_str_concat(EL_STR("[memory] WRITE VERIFY FAILED: soul:utterance id="), discard_id), EL_STR(" \xe2\x80\x94 node absent after write")));
|
||||
} else {
|
||||
println(el_str_concat(el_str_concat(EL_STR("[memory] write verified: "), discard_id), EL_STR(" ok")));
|
||||
}
|
||||
}
|
||||
if (!str_eq(snap_path, EL_STR(""))) {
|
||||
el_val_t discard_save = engram_save(snap_path);
|
||||
}
|
||||
@@ -27750,6 +27872,14 @@ el_val_t handle_api_remember(el_val_t body) {
|
||||
el_val_t base_tags = ({ el_val_t _if_result_308 = 0; if (str_eq(tags_raw, EL_STR(""))) { _if_result_308 = (EL_STR("[\"Memory\"]")); } else { _if_result_308 = (tags_raw); } _if_result_308; });
|
||||
el_val_t final_tags = ({ el_val_t _if_result_309 = 0; if (str_eq(project, EL_STR(""))) { _if_result_309 = (base_tags); } else { el_val_t inner = str_slice(base_tags, 1, (str_len(base_tags) - 1)); _if_result_309 = (el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("["), inner), EL_STR(",\"project:")), project), EL_STR("\"]"))); } _if_result_309; });
|
||||
el_val_t id = engram_node_full(content, EL_STR("Memory"), EL_STR("memory:remembered"), el_from_float(sal), el_from_float(sal), el_from_float(el_from_float(0.9)), EL_STR("Episodic"), final_tags);
|
||||
if (str_eq(id, EL_STR(""))) {
|
||||
return EL_STR("{\"ok\":false,\"error\":\"write_not_persisted\",\"id\":\"\"}");
|
||||
}
|
||||
el_val_t remember_readback = engram_get_node_json(id);
|
||||
if (str_eq(remember_readback, EL_STR("")) || str_eq(remember_readback, EL_STR("{}"))) {
|
||||
println(el_str_concat(el_str_concat(EL_STR("[neuron-api] WRITE VERIFY FAILED remember id="), id), EL_STR(" \xe2\x80\x94 node absent after write")));
|
||||
return el_str_concat(el_str_concat(EL_STR("{\"ok\":false,\"error\":\"write_not_persisted\",\"id\":\""), id), EL_STR("\"}"));
|
||||
}
|
||||
return el_str_concat(el_str_concat(EL_STR("{\"id\":\""), id), EL_STR("\",\"ok\":true}"));
|
||||
return 0;
|
||||
}
|
||||
@@ -27804,6 +27934,14 @@ el_val_t handle_api_capture_knowledge(el_val_t body) {
|
||||
el_val_t full = ({ el_val_t _if_result_317 = 0; if (str_eq(title, EL_STR(""))) { _if_result_317 = (content); } else { _if_result_317 = (el_str_concat(el_str_concat(title, EL_STR(": ")), content)); } _if_result_317; });
|
||||
el_val_t tags = EL_STR("[\"Knowledge\",\"captured\"]");
|
||||
el_val_t id = engram_node_full(full, EL_STR("Knowledge"), EL_STR("knowledge:captured"), el_from_float(el_from_float(0.85)), el_from_float(el_from_float(0.8)), el_from_float(el_from_float(0.9)), EL_STR("Episodic"), tags);
|
||||
if (str_eq(id, EL_STR(""))) {
|
||||
return EL_STR("{\"ok\":false,\"error\":\"write_not_persisted\",\"id\":\"\"}");
|
||||
}
|
||||
el_val_t captured_readback = engram_get_node_json(id);
|
||||
if (str_eq(captured_readback, EL_STR("")) || str_eq(captured_readback, EL_STR("{}"))) {
|
||||
println(el_str_concat(el_str_concat(EL_STR("[neuron-api] WRITE VERIFY FAILED capture id="), id), EL_STR(" \xe2\x80\x94 node absent after write")));
|
||||
return el_str_concat(el_str_concat(EL_STR("{\"ok\":false,\"error\":\"write_not_persisted\",\"id\":\""), id), EL_STR("\"}"));
|
||||
}
|
||||
return el_str_concat(el_str_concat(EL_STR("{\"id\":\""), id), EL_STR("\",\"ok\":true}"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
-5
@@ -334,8 +334,3 @@ el_val_t entry_form(el_val_t entry, el_val_t n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
el_runtime_init_args(_argc, _argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user