Memory CRUD: add /api/neuron/memory/delete and /api/neuron/memory/update #4

Merged
will.anderson merged 1 commits from feat/memory-delete-update into main 2026-06-10 22:37:56 +00:00
2 changed files with 41 additions and 0 deletions
+35
View File
@@ -421,6 +421,41 @@ fn handle_api_evolve_memory(body: String) -> String {
return "{\"id\":\"" + new_id + "\",\"supersedes\":\"" + prior_id + "\",\"ok\":true}"
}
// handle_api_memory_delete POST /api/neuron/memory/delete {"id":"..."}.
// Hard delete: engram_forget (via mem_forget) removes the node and all
// incident edges from the engram store, so no soft-delete fallback is
// needed. Existence is checked first because engram_forget silently
// no-ops on unknown ids a bad id must return an error, not fake success.
// Blocked for protected identity nodes, same as /memory/forget.
fn handle_api_memory_delete(body: String) -> String {
let node_id: String = json_get(body, "id")
if str_eq(node_id, "") { return api_err("id is required") }
if is_protected_node(node_id) { return api_err_protected(node_id) }
let existing: String = engram_get_node_json(node_id)
if str_eq(existing, "{}") { return api_err("memory not found: " + node_id) }
mem_forget(node_id)
return "{\"ok\":true,\"id\":\"" + node_id + "\",\"deleted\":true}"
}
// handle_api_memory_update POST /api/neuron/memory/update {"id","content"}.
// The engram runtime has no in-place node mutation primitive (only
// node-create, strengthen, forget, connect), so update is evolve-style:
// create a new Memory node with the new content and wire a "supersedes"
// edge back to the prior one same pattern as handle_api_evolve_knowledge.
// Unlike /memory/evolve, id is required and must reference an existing
// node; the actual create+link is delegated to handle_api_evolve_memory.
// Returns {"id":"<newId>","supersedes":"<oldId>","ok":true}.
fn handle_api_memory_update(body: String) -> String {
let prior_id: String = json_get(body, "id")
let content: String = json_get(body, "content")
if str_eq(prior_id, "") { return api_err("id is required") }
if str_eq(content, "") { return api_err("content is required") }
if is_protected_node(prior_id) { return api_err_protected(prior_id) }
let existing: String = engram_get_node_json(prior_id)
if str_eq(existing, "{}") { return api_err("memory not found: " + prior_id) }
return handle_api_evolve_memory(body)
}
// Cultivation path (bypasses identity write protection)
//
// This endpoint performs the same operations as the blocked accumulation-path
+6
View File
@@ -412,6 +412,12 @@ fn handle_request(method: String, path: String, body: String) -> String {
if str_eq(clean, "/api/neuron/memory/forget") {
return handle_api_forget(body)
}
if str_eq(clean, "/api/neuron/memory/delete") {
return handle_api_memory_delete(body)
}
if str_eq(clean, "/api/neuron/memory/update") {
return handle_api_memory_update(body)
}
if str_eq(clean, "/api/neuron/recall") {
return handle_api_recall(method, path, body)
}