feat(memory): emotional salience tagging and cross-session distress persistence
Neuron Soul CI / build (pull_request) Successful in 5m36s
Neuron Soul CI / build (pull_request) Successful in 5m36s
- auto_persist: detect bell level (soft/hard) on every user message using safety_detect_bell_level; write a dedicated BellEvent engram node with calibrated salience alongside the Conversation node when a bell fires. Tag the Conversation node with bell:soft/bell:hard and 'affective' for direct discovery without scanning all chat nodes. - auto_persist: track per-session bell count, dominant level, and last signal in state (session_bell_count/level/signal keys) so downstream functions can act on the emotional history without re-scanning engram. - engram_compile: include the top-1 most recent BellEvent node within 72h in every context build. Distress context from earlier turns (same or recent session) automatically travels into all subsequent LLM calls. - hist_trim_with_bell_guard: replace hist_trim at the handle_chat call site. Before evicting the oldest turn from the 20-turn window, inspect the user message for bell signals. If a bell was present, write a preservation BellEvent to engram before dropping the turn so the full message survives the rolling window. - session_hist_save: after writing the history node, check session bell counters. On the first save where bell_count > 0, write a session:emotional-summary BellEvent node with distress signal, count, and dominant level. A state flag prevents duplicate writes on subsequent saves in the same session.
This commit is contained in:
+42
@@ -368,6 +368,48 @@ fn session_hist_save(session_id: String, hist: String) -> Void {
|
||||
el_from_float(0.6), el_from_float(0.6), el_from_float(0.9),
|
||||
"Episodic", tags
|
||||
)
|
||||
|
||||
// Session boundary emotional summary — written once per session the first time
|
||||
// a bell event has fired. The summary node is findable by future sessions via
|
||||
// broad affective queries ("session:emotional-summary" or "bell distress session").
|
||||
// It is NOT rewritten on every save — the state flag prevents duplicate nodes.
|
||||
let summary_written_key: String = "session_bell_summary_written:" + session_id
|
||||
let already_written: String = state_get(summary_written_key)
|
||||
if str_eq(already_written, "") {
|
||||
let bell_count_key: String = "session_bell_count:" + session_id
|
||||
let bell_count_raw: String = state_get(bell_count_key)
|
||||
let bell_count: Int = if str_eq(bell_count_raw, "") { 0 } else { str_to_int(bell_count_raw) }
|
||||
if bell_count > 0 {
|
||||
let bell_level_key: String = "session_bell_level:" + session_id
|
||||
let bell_signal_key: String = "session_bell_signal:" + session_id
|
||||
let dominant_level: String = state_get(bell_level_key)
|
||||
let last_signal: String = state_get(bell_signal_key)
|
||||
let eff_level: String = if str_eq(dominant_level, "") { "soft" } else { dominant_level }
|
||||
let eff_signal: String = if str_eq(last_signal, "") { "(no signal captured)" } else { last_signal }
|
||||
let ts_now: Int = time_now()
|
||||
let summary_content: String = "session:emotional-summary"
|
||||
+ " | session:" + session_id
|
||||
+ " | bell_count:" + int_to_str(bell_count)
|
||||
+ " | dominant_level:" + eff_level
|
||||
+ " | last_signal:" + eff_signal
|
||||
+ " | ts:" + int_to_str(ts_now)
|
||||
let summary_tags: String = "[\"session-emotional-summary\",\"affective\",\"bell:" + eff_level + "\",\"BellEvent\"]"
|
||||
let summary_sal: String = if str_eq(eff_level, "hard") { el_from_float(0.95) } else { el_from_float(0.85) }
|
||||
let sum_discard: String = engram_node_full(
|
||||
summary_content,
|
||||
"BellEvent",
|
||||
"session:emotional-summary",
|
||||
summary_sal,
|
||||
summary_sal,
|
||||
el_from_float(1.0),
|
||||
"Episodic",
|
||||
summary_tags
|
||||
)
|
||||
// Mark written so we do not create duplicate summary nodes as the
|
||||
// session continues accumulating more turns.
|
||||
state_set(summary_written_key, "1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// session_update_meta_timestamp — update the updated_at field in the session:meta node.
|
||||
|
||||
Reference in New Issue
Block a user