code wiki / (root) / nx_companion_rel.nx

nx_companion_rel.nx source

↩ module page · 157 lines · 8637 B

1// nx_companion_rel.nx -- R1d of the ELDER AI companion spine: RELATIONSHIP STATE. Distinct from episodic 2// memory (R1b = the raw immutable log of everything said): this is the evolving SUMMARY of who the user is to 3// Elder -- relationship stage, trust level, durable facts about the person, their recent mood. It is what lets 4// the companion at month 6 relate differently than at day 1, grounded in real shared history. Keyed per 5// (persona,user) so one persona holds a separate, private relationship with each person. Stored in the 6// canonical nx_registry over seg_store (additive: every update is a new version, get returns latest, history 7// kept -- rule 13). never-brick: trust is CLAMPED to 0..100; facts APPEND (never overwrite/lose). All fields 8// are DATA (rule 11/25) -- no policy, no censor; the relationship is whatever the record says it is. 9// license_tier: ORIGINAL 10import "nx_registry.nx" 11import "nx_tabrec.nx" 12const REL_MAGIC_16384: i64 = 16384 13const REL_MAGIC_8192: i64 = 8192 14 15const REL_PREFIX: *u8 = "knowledge/relstate-" as *u8 16const REL_KP: *u8 = "rel:" as *u8 17const REL_IDX: *u8 = "__relidx__" as *u8 18 19// record fields (rule 11): stage \t trust \t facts \t mood \t highlights 20const RF_STAGE: i64 = 0 21const RF_TRUST: i64 = 1 22const RF_FACTS: i64 = 2 23const RF_MOOD: i64 = 3 24const RF_HL: i64 = 4 25 26const TRUST_MAX: i64 = 100 27const TRUST_MIN: i64 = 0 28 29func rel_cpz(dst: *u8, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ dst[i]=s[i]; i=i+1 } dst[i]=0 as u8; return i } 30func rel_catn(d: *u8, o: i64, v: i64) -> i64 { 31 let t: *u8 = sys_mmap(24); var m: i64=v; var k: i64=0 32 if m < 0 { m = 0 } 33 if m == 0 { t[0]=48 as u8; k=1 } 34 while m > 0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 35 var w: i64=o; var i: i64=0 36 while i < k { d[w]=t[k-1-i]; w=w+1; i=i+1 } 37 return w 38} 39// id = "<persona>:<user>" (NUL-terminated); reg_* prepends REL_KP 40func rel_id(buf: *u8, persona: *u8, user: *u8) -> i64 { 41 var o: i64=0; var i: i64=0 42 while persona[i]!=(0 as u8){ buf[o]=persona[i]; o=o+1; i=i+1 } 43 buf[o]=0x3A as u8; o=o+1 44 i=0; while user[i]!=(0 as u8){ buf[o]=user[i]; o=o+1; i=i+1 } 45 buf[o]=0 as u8 46 return o 47} 48 49// ---- store / load ------------------------------------------------------------------------------------ 50func rel_update_pfx(prefix: *u8, persona: *u8, user: *u8, stage: *u8, trust: i64, facts: *u8, mood: *u8, hl: *u8) -> i64 { 51 var t: i64 = trust 52 if t > TRUST_MAX { t = TRUST_MAX } 53 if t < TRUST_MIN { t = TRUST_MIN } 54 let id: *u8 = sys_mmap(512); rel_id(id, persona, user) 55 let rec: *u8 = sys_mmap(REL_MAGIC_16384); var o: i64=0 56 o=tr_cat(rec,o,stage); o=tr_tab(rec,o) 57 o=rel_catn(rec,o,t); o=tr_tab(rec,o) 58 o=tr_cat(rec,o,facts); o=tr_tab(rec,o) 59 o=tr_cat(rec,o,mood); o=tr_tab(rec,o) 60 o=tr_cat(rec,o,hl) 61 return reg_put(prefix, REL_KP, REL_IDX, id, rec, o) 62} 63func rel_get_pfx(prefix: *u8, persona: *u8, user: *u8, ptrout: *i64, lenout: *i64) -> i64 { 64 let id: *u8 = sys_mmap(512); rel_id(id, persona, user) 65 return reg_get(prefix, REL_KP, id, ptrout, lenout) 66} 67// copy field idx into out (NUL-terminated, bounded by cap); returns field length (0 if empty/absent) 68func rel_getf(rec: *u8, rlen: i64, idx: i64, out: *u8, cap: i64) -> i64 { 69 let f: *i64 = sys_mmap(16) as *i64 70 if tr_field(rec, 0, rlen, idx, f) == 0 { out[0]=0 as u8; return 0 } 71 let n: i64 = f[1] 72 var w: i64=0 73 while w < n { if w < cap-1 { out[w]=rec[f[0]+w] } w=w+1 } 74 var term: i64=n; if term > cap-1 { term=cap-1 } 75 out[term]=0 as u8 76 return n 77} 78// load all 5 fields into caller buffers; returns trust (>=0), or -1 if the (persona,user) has no record yet. 79func rel_read5(prefix: *u8, persona: *u8, user: *u8, stageb: *u8, factsb: *u8, moodb: *u8, hlb: *u8, cap: i64) -> i64 { 80 let p: *i64 = sys_mmap(16) as *i64 81 let l: *i64 = sys_mmap(16) as *i64 82 if rel_get_pfx(prefix, persona, user, p, l) != 1 { return 0 - 1 } 83 let rec: *u8 = p[0] as *u8 84 let rlen: i64 = l[0] 85 rel_getf(rec, rlen, RF_STAGE, stageb, cap) 86 rel_getf(rec, rlen, RF_FACTS, factsb, cap) 87 rel_getf(rec, rlen, RF_MOOD, moodb, cap) 88 rel_getf(rec, rlen, RF_HL, hlb, cap) 89 let f: *i64 = sys_mmap(16) as *i64 90 var t: i64 = 0 91 if tr_field(rec, 0, rlen, RF_TRUST, f) == 1 { t = tr_atoi(rec, f[0], f[1]) } 92 return t 93} 94 95// ---- mutators (read-modify-write; additive facts, clamped trust) ------------------------------------- 96func rel_note_fact_pfx(prefix: *u8, persona: *u8, user: *u8, fact: *u8) -> i64 { 97 let cap: i64 = REL_MAGIC_8192 98 let sb: *u8 = sys_mmap(cap); let fb: *u8 = sys_mmap(cap); let mb: *u8 = sys_mmap(cap); let hb: *u8 = sys_mmap(cap) 99 var t: i64 = rel_read5(prefix, persona, user, sb, fb, mb, hb, cap) 100 if t < 0 { rel_cpz(sb, "new" as *u8); fb[0]=0 as u8; mb[0]=0 as u8; hb[0]=0 as u8; t = 0 } 101 // facts_new = facts + ("; " if non-empty) + fact (APPEND -- never lose a prior fact) 102 let fn: *u8 = sys_mmap(cap * 2); var o: i64=0 103 var i: i64=0; while fb[i]!=(0 as u8){ fn[o]=fb[i]; o=o+1; i=i+1 } 104 if o > 0 { fn[o]=0x3B as u8; o=o+1; fn[o]=0x20 as u8; o=o+1 } // "; " 105 i=0; while fact[i]!=(0 as u8){ fn[o]=fact[i]; o=o+1; i=i+1 } 106 fn[o]=0 as u8 107 return rel_update_pfx(prefix, persona, user, sb, t, fn, mb, hb) 108} 109func rel_bump_trust_pfx(prefix: *u8, persona: *u8, user: *u8, delta: i64) -> i64 { 110 let cap: i64 = REL_MAGIC_8192 111 let sb: *u8 = sys_mmap(cap); let fb: *u8 = sys_mmap(cap); let mb: *u8 = sys_mmap(cap); let hb: *u8 = sys_mmap(cap) 112 var t: i64 = rel_read5(prefix, persona, user, sb, fb, mb, hb, cap) 113 if t < 0 { rel_cpz(sb, "new" as *u8); fb[0]=0 as u8; mb[0]=0 as u8; hb[0]=0 as u8; t = 0 } 114 t = t + delta 115 if t > TRUST_MAX { t = TRUST_MAX } 116 if t < TRUST_MIN { t = TRUST_MIN } 117 return rel_update_pfx(prefix, persona, user, sb, t, fb, mb, hb) 118} 119func rel_set_stage_pfx(prefix: *u8, persona: *u8, user: *u8, stage: *u8) -> i64 { 120 let cap: i64 = REL_MAGIC_8192 121 let sb: *u8 = sys_mmap(cap); let fb: *u8 = sys_mmap(cap); let mb: *u8 = sys_mmap(cap); let hb: *u8 = sys_mmap(cap) 122 var t: i64 = rel_read5(prefix, persona, user, sb, fb, mb, hb, cap) 123 if t < 0 { fb[0]=0 as u8; mb[0]=0 as u8; hb[0]=0 as u8; t = 0 } 124 return rel_update_pfx(prefix, persona, user, stage, t, fb, mb, hb) 125} 126func rel_set_mood_pfx(prefix: *u8, persona: *u8, user: *u8, mood: *u8) -> i64 { 127 let cap: i64 = REL_MAGIC_8192 128 let sb: *u8 = sys_mmap(cap); let fb: *u8 = sys_mmap(cap); let mb: *u8 = sys_mmap(cap); let hb: *u8 = sys_mmap(cap) 129 var t: i64 = rel_read5(prefix, persona, user, sb, fb, mb, hb, cap) 130 if t < 0 { rel_cpz(sb, "new" as *u8); fb[0]=0 as u8; hb[0]=0 as u8; t = 0 } 131 return rel_update_pfx(prefix, persona, user, sb, t, fb, mood, hb) 132} 133 134// ---- projection: relationship-state -> context fragment (deterministic) ------------------------------ 135func rel_context_pfx(prefix: *u8, persona: *u8, user: *u8, out: *u8, cap: i64) -> i64 { 136 let bcap: i64 = REL_MAGIC_8192 137 let sb: *u8 = sys_mmap(bcap); let fb: *u8 = sys_mmap(bcap); let mb: *u8 = sys_mmap(bcap); let hb: *u8 = sys_mmap(bcap) 138 let t: i64 = rel_read5(prefix, persona, user, sb, fb, mb, hb, bcap) 139 if t < 0 { out[0]=0 as u8; return 0 } 140 var o: i64 = 0 141 o = tr_cat(out, o, "Relationship stage: " as *u8); o = tr_cat(out, o, sb) 142 o = tr_cat(out, o, ". Trust: " as *u8); o = rel_catn(out, o, t); o = tr_cat(out, o, "/100" as *u8) 143 o = tr_cat(out, o, ". What you know about them: " as *u8); o = tr_cat(out, o, fb) 144 o = tr_cat(out, o, ". Their recent mood: " as *u8); o = tr_cat(out, o, mb) 145 o = tr_cat(out, o, "." as *u8) 146 out[o] = 0 as u8 147 return o 148} 149 150// production-prefix wrappers 151func rel_update(persona: *u8, user: *u8, stage: *u8, trust: i64, facts: *u8, mood: *u8, hl: *u8) -> i64 { return rel_update_pfx(REL_PREFIX, persona, user, stage, trust, facts, mood, hl) } 152func rel_get(persona: *u8, user: *u8, ptrout: *i64, lenout: *i64) -> i64 { return rel_get_pfx(REL_PREFIX, persona, user, ptrout, lenout) } 153func rel_note_fact(persona: *u8, user: *u8, fact: *u8) -> i64 { return rel_note_fact_pfx(REL_PREFIX, persona, user, fact) } 154func rel_bump_trust(persona: *u8, user: *u8, delta: i64) -> i64 { return rel_bump_trust_pfx(REL_PREFIX, persona, user, delta) } 155func rel_set_stage(persona: *u8, user: *u8, stage: *u8) -> i64 { return rel_set_stage_pfx(REL_PREFIX, persona, user, stage) } 156func rel_set_mood(persona: *u8, user: *u8, mood: *u8) -> i64 { return rel_set_mood_pfx(REL_PREFIX, persona, user, mood) } 157func rel_context(persona: *u8, user: *u8, out: *u8, cap: i64) -> i64 { return rel_context_pfx(REL_PREFIX, persona, user, out, cap) }