From 0c5b9667730e720bdd42b28e335d7c48363de255 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Mon, 22 Jun 2026 12:09:00 -0500 Subject: [PATCH] fix(chat): fix auto_persist timestamp extraction and bell label uniqueness - engram_compile: BellEvent nodes do not carry created_at in the engram node JSON; extract the unix timestamp from the embedded ' | ts:NNNNN' pattern in the content string instead. Fall back to created_at/updated_at if the marker is absent. Guard str_to_int against empty string so the 72h recency check never silently treats every node as epoch-0 stale. - auto_persist: append the current unix timestamp to the BellEvent label ('bell:soft:1749876543') to make it unique per turn. The previous label ('bell:soft') was the same for every soft bell, causing engram to treat all subsequent writes as updates to the same node. --- chat.el | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/chat.el b/chat.el index 8a8e0ca..c0beeab 100644 --- a/chat.el +++ b/chat.el @@ -53,8 +53,22 @@ fn engram_compile(intent: String) -> String { let cutoff_ts: Int = now_ts - 259200 let recent_bell: String = if bell_ok { let bn0: String = json_array_get(bell_nodes, 0) - let bn_ts_raw: String = json_get(bn0, "created_at") - let bn_ts: Int = str_to_int(bn_ts_raw) + // created_at is not present in engram node JSON for BellEvent nodes. + // Extract the timestamp embedded in the content string as " | ts:NNNNN". + // Fall back to created_at / updated_at JSON fields if the marker is absent. + let bn_content: String = json_get(bn0, "content") + let ts_marker: String = " | ts:" + let ts_pos: Int = str_index_of(bn_content, ts_marker) + let bn_ts_raw: String = if ts_pos >= 0 { + let ts_start: Int = ts_pos + str_len(ts_marker) + let rest: String = str_slice(bn_content, ts_start, str_len(bn_content)) + let next_sep: Int = str_index_of(rest, " | ") + if next_sep < 0 { rest } else { str_slice(rest, 0, next_sep) } + } else { + let ca: String = json_get(bn0, "created_at") + if str_eq(ca, "") { json_get(bn0, "updated_at") } else { ca } + } + let bn_ts: Int = if str_eq(bn_ts_raw, "") { 0 } else { str_to_int(bn_ts_raw) } if bn_ts > cutoff_ts { bn0 } else { "" } } else { "" } let affective_part: String = if !str_eq(recent_bell, "") { recent_bell } else { "" } @@ -1270,10 +1284,12 @@ fn auto_persist(req: String, resp: String) -> Void { let sal_c: String = if str_eq(bell_level, "hard") { el_from_float(1.0) } else { el_from_float(0.95) } let bell_tags: String = "[\"safety\",\"bell\",\"bell:" + bell_level + "\",\"affective\",\"BellEvent\"]" + let bell_ts_str: String = int_to_str(time_now()) + let bell_label: String = "bell:" + bell_level + ":" + bell_ts_str let bell_node_id: String = engram_node_full( bell_content, "BellEvent", - "bell:" + bell_level, + bell_label, sal_a, sal_b, sal_c,