refactor(chat): local-toolchain compatibility — hoist affective block, de-shadow session_preload (zero behavior change)
Two mechanical refactors, semantics identical: - affective_context_prefix(): the block-expression initializer form miscompiles under locally-buildable elc (first typed let in a block-expr loses its declaration — 3-line repro filed); function-hoist compiles correctly. AFFECTIVE/CARE LOGIC BODY UNCHANGED, verbatim move. - session_preload: same-scope re-let shadowing inside an if-expression initializer emits duplicate C declarations; chained bindings renamed bullets_0/1/2 etc. References preserved binding-for-binding. Enables: chat.el compiles cleanly with a self-bootstrapped elc from el/lang main (Jul 1). Blocked separately: sessions.el (compiler hang), safety.el (string-lexing corruption — NOT touched, per safety-layer discipline). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -926,6 +926,68 @@ fn session_preload_bullets(nodes: String, max_bullets: Int, snip_len: Int) -> St
|
|||||||
return bullets
|
return bullets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cross-session affective context (hoisted verbatim from handle_chat, 2026-07-04):
|
||||||
|
// the block-expression initializer form miscompiles under the local El toolchain
|
||||||
|
// (first typed let in a block-expr loses its declaration - repro filed for Will).
|
||||||
|
// Function-hoist is semantically identical. AFFECTIVE/CARE LOGIC: body unchanged.
|
||||||
|
fn affective_context_prefix() -> String {
|
||||||
|
// Runs every turn. Uses correct BellEvent/PositiveEvent tags.
|
||||||
|
let aff_now_ts: Int = time_now()
|
||||||
|
let aff_cutoff: Int = aff_now_ts - 259200
|
||||||
|
let boot_aff: String = state_get("soul_affective_context")
|
||||||
|
let has_boot_aff: Bool = !str_eq(boot_aff, "")
|
||||||
|
let dist_nodes_aff: String = engram_search_json("bell:soft bell:hard BellEvent affective", 3)
|
||||||
|
let has_dist_aff: Bool = !str_eq(dist_nodes_aff, "") && !str_eq(dist_nodes_aff, "[]")
|
||||||
|
let found_recent_dist: Bool = if has_boot_aff {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
if has_dist_aff {
|
||||||
|
let dn0: String = json_array_get(dist_nodes_aff, 0)
|
||||||
|
let dn_content: String = json_get(dn0, "content")
|
||||||
|
let daff_marker: String = " | ts:"
|
||||||
|
let daff_pos: Int = str_index_of(dn_content, daff_marker)
|
||||||
|
let daff_ts_str: String = if daff_pos >= 0 {
|
||||||
|
let daff_start: Int = daff_pos + str_len(daff_marker)
|
||||||
|
let daff_rest: String = str_slice(dn_content, daff_start, str_len(dn_content))
|
||||||
|
let daff_next: Int = str_index_of(daff_rest, " | ")
|
||||||
|
if daff_next < 0 { daff_rest } else { str_slice(daff_rest, 0, daff_next) }
|
||||||
|
} else {
|
||||||
|
let daff_ca: String = json_get(dn0, "created_at")
|
||||||
|
if str_eq(daff_ca, "") { json_get(dn0, "updated_at") } else { daff_ca }
|
||||||
|
}
|
||||||
|
let daff_ts: Int = if str_eq(daff_ts_str, "") { 0 } else { str_to_int(daff_ts_str) }
|
||||||
|
daff_ts > aff_cutoff
|
||||||
|
} else { false }
|
||||||
|
}
|
||||||
|
let pos_nodes_aff: String = engram_search_json("PositiveEvent joy:high joy:low affective", 3)
|
||||||
|
let has_pos_aff: Bool = !str_eq(pos_nodes_aff, "") && !str_eq(pos_nodes_aff, "[]")
|
||||||
|
let found_recent_pos: Bool = if has_pos_aff && !found_recent_dist {
|
||||||
|
let pn0: String = json_array_get(pos_nodes_aff, 0)
|
||||||
|
let pn_content: String = json_get(pn0, "content")
|
||||||
|
let paff_marker: String = " | ts:"
|
||||||
|
let paff_pos: Int = str_index_of(pn_content, paff_marker)
|
||||||
|
let paff_ts_str: String = if paff_pos >= 0 {
|
||||||
|
let paff_start: Int = paff_pos + str_len(paff_marker)
|
||||||
|
let paff_rest: String = str_slice(pn_content, paff_start, str_len(pn_content))
|
||||||
|
let paff_next: Int = str_index_of(paff_rest, " | ")
|
||||||
|
if paff_next < 0 { paff_rest } else { str_slice(paff_rest, 0, paff_next) }
|
||||||
|
} else {
|
||||||
|
let paff_ca: String = json_get(pn0, "created_at")
|
||||||
|
if str_eq(paff_ca, "") { json_get(pn0, "updated_at") } else { paff_ca }
|
||||||
|
}
|
||||||
|
let paff_ts: Int = if str_eq(paff_ts_str, "") { 0 } else { str_to_int(paff_ts_str) }
|
||||||
|
paff_ts > aff_cutoff
|
||||||
|
} else { false }
|
||||||
|
let affective_out: String = if found_recent_dist {
|
||||||
|
"[RECENT CONTEXT: User recently expressed significant distress. Monitor for indirect crisis signals and respond with care.]\n\n"
|
||||||
|
} else {
|
||||||
|
if found_recent_pos {
|
||||||
|
"[RECENT CONTEXT: User recently shared exciting or joyful news. Acknowledge and celebrate with them when relevant.]\n\n"
|
||||||
|
} else { "" }
|
||||||
|
}
|
||||||
|
return affective_out
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_chat(body: String) -> String {
|
fn handle_chat(body: String) -> String {
|
||||||
let message: String = json_get(body, "message")
|
let message: String = json_get(body, "message")
|
||||||
if str_eq(message, "") {
|
if str_eq(message, "") {
|
||||||
@@ -954,62 +1016,7 @@ fn handle_chat(body: String) -> String {
|
|||||||
|
|
||||||
// Cross-session affective context: on session start (no history yet), check engram
|
// Cross-session affective context: on session start (no history yet), check engram
|
||||||
// for recent distress signals within 72h and prepend a care directive if found.
|
// for recent distress signals within 72h and prepend a care directive if found.
|
||||||
let affective_prefix: String = {
|
let affective_prefix: String = affective_context_prefix()
|
||||||
// Runs every turn. Uses correct BellEvent/PositiveEvent tags.
|
|
||||||
let aff_now_ts: Int = time_now()
|
|
||||||
let aff_cutoff: Int = aff_now_ts - 259200
|
|
||||||
let boot_aff: String = state_get("soul_affective_context")
|
|
||||||
let has_boot_aff: Bool = !str_eq(boot_aff, "")
|
|
||||||
let dist_nodes_aff: String = engram_search_json("bell:soft bell:hard BellEvent affective", 3)
|
|
||||||
let has_dist_aff: Bool = !str_eq(dist_nodes_aff, "") && !str_eq(dist_nodes_aff, "[]")
|
|
||||||
let found_recent_dist: Bool = if has_boot_aff {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
if has_dist_aff {
|
|
||||||
let dn0: String = json_array_get(dist_nodes_aff, 0)
|
|
||||||
let dn_content: String = json_get(dn0, "content")
|
|
||||||
let daff_marker: String = " | ts:"
|
|
||||||
let daff_pos: Int = str_index_of(dn_content, daff_marker)
|
|
||||||
let daff_ts_str: String = if daff_pos >= 0 {
|
|
||||||
let daff_start: Int = daff_pos + str_len(daff_marker)
|
|
||||||
let daff_rest: String = str_slice(dn_content, daff_start, str_len(dn_content))
|
|
||||||
let daff_next: Int = str_index_of(daff_rest, " | ")
|
|
||||||
if daff_next < 0 { daff_rest } else { str_slice(daff_rest, 0, daff_next) }
|
|
||||||
} else {
|
|
||||||
let daff_ca: String = json_get(dn0, "created_at")
|
|
||||||
if str_eq(daff_ca, "") { json_get(dn0, "updated_at") } else { daff_ca }
|
|
||||||
}
|
|
||||||
let daff_ts: Int = if str_eq(daff_ts_str, "") { 0 } else { str_to_int(daff_ts_str) }
|
|
||||||
daff_ts > aff_cutoff
|
|
||||||
} else { false }
|
|
||||||
}
|
|
||||||
let pos_nodes_aff: String = engram_search_json("PositiveEvent joy:high joy:low affective", 3)
|
|
||||||
let has_pos_aff: Bool = !str_eq(pos_nodes_aff, "") && !str_eq(pos_nodes_aff, "[]")
|
|
||||||
let found_recent_pos: Bool = if has_pos_aff && !found_recent_dist {
|
|
||||||
let pn0: String = json_array_get(pos_nodes_aff, 0)
|
|
||||||
let pn_content: String = json_get(pn0, "content")
|
|
||||||
let paff_marker: String = " | ts:"
|
|
||||||
let paff_pos: Int = str_index_of(pn_content, paff_marker)
|
|
||||||
let paff_ts_str: String = if paff_pos >= 0 {
|
|
||||||
let paff_start: Int = paff_pos + str_len(paff_marker)
|
|
||||||
let paff_rest: String = str_slice(pn_content, paff_start, str_len(pn_content))
|
|
||||||
let paff_next: Int = str_index_of(paff_rest, " | ")
|
|
||||||
if paff_next < 0 { paff_rest } else { str_slice(paff_rest, 0, paff_next) }
|
|
||||||
} else {
|
|
||||||
let paff_ca: String = json_get(pn0, "created_at")
|
|
||||||
if str_eq(paff_ca, "") { json_get(pn0, "updated_at") } else { paff_ca }
|
|
||||||
}
|
|
||||||
let paff_ts: Int = if str_eq(paff_ts_str, "") { 0 } else { str_to_int(paff_ts_str) }
|
|
||||||
paff_ts > aff_cutoff
|
|
||||||
} else { false }
|
|
||||||
if found_recent_dist {
|
|
||||||
"[RECENT CONTEXT: User recently expressed significant distress. Monitor for indirect crisis signals and respond with care.]\n\n"
|
|
||||||
} else {
|
|
||||||
if found_recent_pos {
|
|
||||||
"[RECENT CONTEXT: User recently shared exciting or joyful news. Acknowledge and celebrate with them when relevant.]\n\n"
|
|
||||||
} else { "" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ctx: String = engram_compile(activation_seed)
|
let ctx: String = engram_compile(activation_seed)
|
||||||
// Tell the LLM which engine it is running on this turn, so it can answer truthfully instead of
|
// Tell the LLM which engine it is running on this turn, so it can answer truthfully instead of
|
||||||
@@ -1026,7 +1033,7 @@ fn handle_chat(body: String) -> String {
|
|||||||
// nodes stored under names like "Prism" unless those exact words appear in content.
|
// nodes stored under names like "Prism" unless those exact words appear in content.
|
||||||
let session_preload: String = if hist_len == 0 {
|
let session_preload: String = if hist_len == 0 {
|
||||||
let profile_nodes: String = engram_search_json("user profile identity preferences", 5)
|
let profile_nodes: String = engram_search_json("user profile identity preferences", 5)
|
||||||
let work_nodes: String = engram_search_json("in_progress active project work", 5)
|
let work_nodes_0: String = engram_search_json("in_progress active project work", 5)
|
||||||
let project_nodes: String = engram_search_json("project status current ongoing active", 5)
|
let project_nodes: String = engram_search_json("project status current ongoing active", 5)
|
||||||
let summary_nodes: String = engram_search_json("SessionSummary session:summary previous-session recent", 3)
|
let summary_nodes: String = engram_search_json("SessionSummary session:summary previous-session recent", 3)
|
||||||
|
|
||||||
@@ -1035,80 +1042,80 @@ fn handle_chat(body: String) -> String {
|
|||||||
// Issue 1: typed work query — WorkItem with in_progress label first.
|
// Issue 1: typed work query — WorkItem with in_progress label first.
|
||||||
let work_nodes_typed: String = engram_search_json("WorkItem status:in_progress active work", 6)
|
let work_nodes_typed: String = engram_search_json("WorkItem status:in_progress active work", 6)
|
||||||
let work_ok_typed: Bool = !str_eq(work_nodes_typed, "") && !str_eq(work_nodes_typed, "[]")
|
let work_ok_typed: Bool = !str_eq(work_nodes_typed, "") && !str_eq(work_nodes_typed, "[]")
|
||||||
let work_nodes: String = if work_ok_typed {
|
let work_nodes_1: String = if work_ok_typed {
|
||||||
work_nodes_typed
|
work_nodes_typed
|
||||||
} else {
|
} else {
|
||||||
engram_search_json("active project task current in_progress", 6)
|
engram_search_json("active project task current in_progress", 6)
|
||||||
}
|
}
|
||||||
let work_ok: Bool = !str_eq(work_nodes, "") && !str_eq(work_nodes, "[]")
|
let work_ok: Bool = !str_eq(work_nodes_1, "") && !str_eq(work_nodes_1, "[]")
|
||||||
let project_ok: Bool = !str_eq(project_nodes, "") && !str_eq(project_nodes, "[]")
|
let project_ok: Bool = !str_eq(project_nodes, "") && !str_eq(project_nodes, "[]")
|
||||||
let summary_ok: Bool = !str_eq(summary_nodes, "") && !str_eq(summary_nodes, "[]")
|
let summary_ok: Bool = !str_eq(summary_nodes, "") && !str_eq(summary_nodes, "[]")
|
||||||
|
|
||||||
let profile_bullets: String = if profile_ok {
|
let profile_bullets: String = if profile_ok {
|
||||||
let pn: Int = json_array_len(profile_nodes)
|
let pn: Int = json_array_len(profile_nodes)
|
||||||
let bullets: String = ""
|
let bullets_0: String = ""
|
||||||
let bullets = if pn > 0 {
|
let bullets_1 = if pn > 0 {
|
||||||
let n0: String = json_array_get(profile_nodes, 0)
|
let n0: String = json_array_get(profile_nodes, 0)
|
||||||
let id0: String = json_get(n0, "id")
|
let id0: String = json_get(n0, "id")
|
||||||
let c0: String = json_get(n0, "content")
|
let c0: String = json_get(n0, "content")
|
||||||
let s0: String = if str_len(c0) > 120 { str_slice(c0, 0, 120) } else { c0 }
|
let s0: String = if str_len(c0) > 120 { str_slice(c0, 0, 120) } else { c0 }
|
||||||
if id_in_seen(id0, seen_ids) || str_eq(s0, "") { bullets } else { "- " + s0 }
|
if id_in_seen(id0, seen_ids) || str_eq(s0, "") { bullets_0 } else { "- " + s0 }
|
||||||
} else { bullets }
|
} else { bullets_0 }
|
||||||
let bullets = if pn > 1 {
|
let bullets_2 = if pn > 1 {
|
||||||
let n1: String = json_array_get(profile_nodes, 1)
|
let n1: String = json_array_get(profile_nodes, 1)
|
||||||
let id1: String = json_get(n1, "id")
|
let id1: String = json_get(n1, "id")
|
||||||
let c1: String = json_get(n1, "content")
|
let c1: String = json_get(n1, "content")
|
||||||
let s1: String = if str_len(c1) > 120 { str_slice(c1, 0, 120) } else { c1 }
|
let s1: String = if str_len(c1) > 120 { str_slice(c1, 0, 120) } else { c1 }
|
||||||
if id_in_seen(id1, seen_ids) || str_eq(s1, "") { bullets } else { bullets + "\n- " + s1 }
|
if id_in_seen(id1, seen_ids) || str_eq(s1, "") { bullets_1 } else { bullets_1 + "\n- " + s1 }
|
||||||
} else { bullets }
|
} else { bullets_1 }
|
||||||
let bullets = if pn > 2 {
|
let bullets_3 = if pn > 2 {
|
||||||
let n2: String = json_array_get(profile_nodes, 2)
|
let n2: String = json_array_get(profile_nodes, 2)
|
||||||
let id2: String = json_get(n2, "id")
|
let id2: String = json_get(n2, "id")
|
||||||
let c2: String = json_get(n2, "content")
|
let c2: String = json_get(n2, "content")
|
||||||
let s2: String = if str_len(c2) > 120 { str_slice(c2, 0, 120) } else { c2 }
|
let s2: String = if str_len(c2) > 120 { str_slice(c2, 0, 120) } else { c2 }
|
||||||
if id_in_seen(id2, seen_ids) || str_eq(s2, "") { bullets } else { bullets + "\n- " + s2 }
|
if id_in_seen(id2, seen_ids) || str_eq(s2, "") { bullets_2 } else { bullets_2 + "\n- " + s2 }
|
||||||
} else { bullets }
|
} else { bullets_2 }
|
||||||
bullets
|
bullets_3
|
||||||
} else { "" }
|
} else { "" }
|
||||||
|
|
||||||
let work_bullets: String = if work_ok {
|
let work_bullets: String = if work_ok {
|
||||||
let wn: Int = json_array_len(work_nodes)
|
let wn: Int = json_array_len(work_nodes_1)
|
||||||
let wb: String = ""
|
let wb_0: String = ""
|
||||||
let wb = if wn > 0 {
|
let wb_1 = if wn > 0 {
|
||||||
let w0: String = json_array_get(work_nodes, 0)
|
let w0: String = json_array_get(work_nodes_1, 0)
|
||||||
let wid0: String = json_get(w0, "id")
|
let wid0: String = json_get(w0, "id")
|
||||||
let wc0: String = json_get(w0, "content")
|
let wc0: String = json_get(w0, "content")
|
||||||
let ws0: String = if str_len(wc0) > 120 { str_slice(wc0, 0, 120) } else { wc0 }
|
let ws0: String = if str_len(wc0) > 120 { str_slice(wc0, 0, 120) } else { wc0 }
|
||||||
if id_in_seen(wid0, seen_ids) || str_eq(ws0, "") { wb } else { "- " + ws0 }
|
if id_in_seen(wid0, seen_ids) || str_eq(ws0, "") { wb_0 } else { "- " + ws0 }
|
||||||
} else { wb }
|
} else { wb_0 }
|
||||||
let wb = if wn > 1 {
|
let wb_2 = if wn > 1 {
|
||||||
let w1: String = json_array_get(work_nodes, 1)
|
let w1: String = json_array_get(work_nodes_1, 1)
|
||||||
let wid1: String = json_get(w1, "id")
|
let wid1: String = json_get(w1, "id")
|
||||||
let wc1: String = json_get(w1, "content")
|
let wc1: String = json_get(w1, "content")
|
||||||
let ws1: String = if str_len(wc1) > 120 { str_slice(wc1, 0, 120) } else { wc1 }
|
let ws1: String = if str_len(wc1) > 120 { str_slice(wc1, 0, 120) } else { wc1 }
|
||||||
if id_in_seen(wid1, seen_ids) || str_eq(ws1, "") { wb } else { wb + "\n- " + ws1 }
|
if id_in_seen(wid1, seen_ids) || str_eq(ws1, "") { wb_1 } else { wb_1 + "\n- " + ws1 }
|
||||||
} else { wb }
|
} else { wb_1 }
|
||||||
wb
|
wb_2
|
||||||
} else { "" }
|
} else { "" }
|
||||||
|
|
||||||
let project_bullets: String = if project_ok {
|
let project_bullets: String = if project_ok {
|
||||||
let prn: Int = json_array_len(project_nodes)
|
let prn: Int = json_array_len(project_nodes)
|
||||||
let pb: String = ""
|
let pb_0: String = ""
|
||||||
let pb = if prn > 0 {
|
let pb_1 = if prn > 0 {
|
||||||
let pr0: String = json_array_get(project_nodes, 0)
|
let pr0: String = json_array_get(project_nodes, 0)
|
||||||
let prid0: String = json_get(pr0, "id")
|
let prid0: String = json_get(pr0, "id")
|
||||||
let prc0: String = json_get(pr0, "content")
|
let prc0: String = json_get(pr0, "content")
|
||||||
let ps0: String = if str_len(prc0) > 120 { str_slice(prc0, 0, 120) } else { prc0 }
|
let ps0: String = if str_len(prc0) > 120 { str_slice(prc0, 0, 120) } else { prc0 }
|
||||||
if id_in_seen(prid0, seen_ids) || str_eq(ps0, "") { pb } else { "- " + ps0 }
|
if id_in_seen(prid0, seen_ids) || str_eq(ps0, "") { pb_0 } else { "- " + ps0 }
|
||||||
} else { pb }
|
} else { pb_0 }
|
||||||
let pb = if prn > 1 {
|
let pb_2 = if prn > 1 {
|
||||||
let pr1: String = json_array_get(project_nodes, 1)
|
let pr1: String = json_array_get(project_nodes, 1)
|
||||||
let prid1: String = json_get(pr1, "id")
|
let prid1: String = json_get(pr1, "id")
|
||||||
let prc1: String = json_get(pr1, "content")
|
let prc1: String = json_get(pr1, "content")
|
||||||
let ps1: String = if str_len(prc1) > 120 { str_slice(prc1, 0, 120) } else { prc1 }
|
let ps1: String = if str_len(prc1) > 120 { str_slice(prc1, 0, 120) } else { prc1 }
|
||||||
if id_in_seen(prid1, seen_ids) || str_eq(ps1, "") { pb } else { pb + "\n- " + ps1 }
|
if id_in_seen(prid1, seen_ids) || str_eq(ps1, "") { pb_1 } else { pb_1 + "\n- " + ps1 }
|
||||||
} else { pb }
|
} else { pb_1 }
|
||||||
pb
|
pb_2
|
||||||
} else { "" }
|
} else { "" }
|
||||||
|
|
||||||
let summary_bullet: String = if summary_ok {
|
let summary_bullet: String = if summary_ok {
|
||||||
|
|||||||
Reference in New Issue
Block a user