nx_companion_mind.nx source
↩ module page · 258 lines · 11965 B
1// nx_companion_mind.nx -- THE MIND CONTEXT (companionchat CC0, 2026-08-30): ONE composer that puts the companion's
2// LONG-TERM MEMORY (nx_elara_memory recall), RELATIONSHIP STATE (nx_charmem ctx) and TYPED PRESENT-TENSE STATE
3// (nx_elara_state context) into the chat turn's system prompt.
4// FOUND BY IMPORT-LIST MEASUREMENT: nx_gen_orchestrator carried persona, wardrobe and the affect vector and NEVER
5// consulted these three PROMOTED organs, so the intelligence was built and dark. This lib COMPOSES them by forking
6// the serving-root binaries (the nx_companion_sota idiom) -- it re-implements none of them -- and it FABRICATES
7// NOTHING: an empty store contributes zero bytes, an unset present is never narrated as a fact, a wedged organ costs
8// the turn at most MIND_FORK_TIMEOUT_MS and then contributes nothing.
9// Contract symbol: go_mind_context (the companionchat.matrix CC0 watch), measured in the orchestrator that calls it.
10// Gate: nx_gen_mind_gate (fixture sessions under /tmp, positive + neg-control-empty-session teeth).
11// CC3 (2026-08-30): the LOREBOOK plane rides the same composer -- em_lorebook (nx_lorebook.nx, in-process, no fork) injects
12// keyed world facts only when the turn touches a trigger; a budget refusal is logged to stderr and contributes ZERO bytes.
13// license_tier: ORIGINAL
14import "nx_syscalls.nx"
15import "nx_tool_run.nx"
16import "nx_lorebook.nx"
17
18const MIND_ELF_MEM: *u8 = "/volume1/homes/elderwesto/nishihost/nx_elara_memory.elf" as *u8
19const MIND_ELF_CHAR: *u8 = "/volume1/homes/elderwesto/nishihost/nx_charmem.elf" as *u8
20const MIND_ELF_STATE: *u8 = "/volume1/homes/elderwesto/nishihost/nx_elara_state.elf" as *u8
21// one organ's stdout: cm_ctx bounds itself to CM_BUF and em_recall to 64 KiB, so 64 KiB is the organs' own ceiling, not a guess
22const MIND_CAP: i64 = 65536
23// a wedged organ may cost the turn at most this. The chat dispatch budget is 180 s; three forks at 4 s stay under 7 percent of it.
24const MIND_FORK_TIMEOUT_MS: i64 = 4000
25// top-k salience hits per turn -- em_recall's own default, passed explicitly so the contract is visible here
26const MIND_RECALL_MAX: *u8 = "5" as *u8
27// DATA: which session/char key the daemon speaks for (first [a-z0-9_] run of the file); default when absent
28const MIND_SESSION_FILE: *u8 = "elara_session.txt" as *u8
29const MIND_SESSION_DEFAULT: *u8 = "elara" as *u8
30// nx_charmem refuses names over 32 [a-z0-9_]; the same bound here so a refusal never surprises the caller
31const MIND_SESSION_CAP: i64 = 32
32// the user turn is passed to recall/remember as ONE argv element; bounded so a pasted novel cannot exceed an argv limit
33const MIND_QUERY_CAP: i64 = 512
34const MIND_BLOCK_CAP: i64 = 4096
35const MIND_CH_QUOTE: i64 = 34
36const MIND_CH_BSLASH: i64 = 92
37const MIND_CH_NL: i64 = 10
38const MIND_CH_SPACE: i64 = 32
39const MIND_CH_LOWER_N: i64 = 110
40const MIND_FD_STDERR: i64 = 2
41const MIND_I64_BYTES: i64 = 8
42
43func mind_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
44func mind_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } return o }
45
46// first index of needle in buf[from..n) or -1. Uses a flag to exit, never the cursor (nx_srclint idiom).
47func mind_find(buf: *u8, n: i64, from: i64, needle: *u8) -> i64 {
48 let nl: i64 = mind_len(needle)
49 if nl <= 0 { return 0 - 1 }
50 var i: i64 = from
51 if i < 0 { i = 0 }
52 while i + nl <= n {
53 var j: i64 = 0
54 var same: i64 = 1
55 var scan: i64 = 1
56 while scan == 1 {
57 if j >= nl { scan = 0 } else {
58 if buf[i + j] != needle[j] { same = 0; scan = 0 } else { j = j + 1 }
59 }
60 }
61 if same == 1 { return i }
62 i = i + 1
63 }
64 return 0 - 1
65}
66
67// fork one serving-root organ with up to 4 args, bounded capture, bounded time. Returns bytes captured (0 on any failure).
68func mind_run(elf: *u8, nargs: i64, a1: *u8, a2: *u8, a3: *u8, a4: *u8, out: *u8) -> i64 {
69 let argv: *i64 = sys_mmap(64) as *i64
70 argv[0] = elf as i64
71 if nargs >= 1 { argv[1] = a1 as i64 }
72 if nargs >= 2 { argv[2] = a2 as i64 }
73 if nargs >= 3 { argv[3] = a3 as i64 }
74 if nargs >= 4 { argv[4] = a4 as i64 }
75 argv[nargs + 1] = 0
76 let olen: *i64 = sys_mmap(16) as *i64
77 olen[0] = 0
78 tr_run_capture_to(elf, argv, out, MIND_CAP - 1, olen, MIND_FORK_TIMEOUT_MS)
79 var n: i64 = olen[0]
80 if n < 0 { n = 0 }
81 if n > MIND_CAP - 1 { n = MIND_CAP - 1 }
82 out[n] = 0 as u8
83 return n
84}
85
86// the session key: first [a-z0-9_] run of MIND_SESSION_FILE (relative to the daemon's cwd), else the default.
87func mind_session(out: *u8) -> i64 {
88 let lp: *i64 = sys_mmap(16) as *i64
89 lp[0] = 0
90 let b: *u8 = sys_read_file(MIND_SESSION_FILE, lp)
91 var o: i64 = 0
92 if (b as i64) != 0 {
93 var i: i64 = 0
94 var scan: i64 = 1
95 while scan == 1 {
96 if i >= lp[0] { scan = 0 } else { if o >= MIND_SESSION_CAP { scan = 0 } else {
97 let c: i64 = b[i] as i64
98 var ok: i64 = 0
99 if c >= 97 { if c <= 122 { ok = 1 } }
100 if c >= 48 { if c <= 57 { ok = 1 } }
101 if c == 95 { ok = 1 }
102 if ok == 1 { out[o] = c as u8; o = o + 1; i = i + 1 } else { scan = 0 }
103 } }
104 }
105 }
106 if o == 0 { o = mind_cat(out, 0, MIND_SESSION_DEFAULT) }
107 out[o] = 0 as u8
108 return o
109}
110
111// bounded, control-char-free copy of the user turn for argv use
112func mind_query(umsg: *u8, umlen: i64, q: *u8) -> i64 {
113 var n: i64 = umlen
114 if n > MIND_QUERY_CAP { n = MIND_QUERY_CAP }
115 var i: i64 = 0
116 while i < n { let c: i64 = umsg[i] as i64; if c < MIND_CH_SPACE { q[i] = MIND_CH_SPACE as u8 } else { q[i] = c as u8 } i = i + 1 }
117 q[n] = 0 as u8
118 return n
119}
120
121// copy the JSON string value that follows `key` (the full lead-in, e.g. "narrative":") from body[from..n).
122// Returns chars copied; endpos[0] = index just past the closing quote for iteration, or -1 when the key is absent.
123func mind_jstr(body: *u8, blen: i64, from: i64, key: *u8, out: *u8, cap: i64, endpos: *i64) -> i64 {
124 endpos[0] = 0 - 1
125 let p: i64 = mind_find(body, blen, from, key)
126 if p < 0 { out[0] = 0 as u8; return 0 }
127 var i: i64 = p + mind_len(key)
128 var o: i64 = 0
129 var scan: i64 = 1
130 while scan == 1 {
131 if i >= blen { scan = 0 } else {
132 let c: i64 = body[i] as i64
133 if c == MIND_CH_QUOTE { scan = 0 } else {
134 if c == MIND_CH_BSLASH {
135 i = i + 1
136 if i < blen {
137 let e: i64 = body[i] as i64
138 if o < cap - 1 { if e == MIND_CH_LOWER_N { out[o] = MIND_CH_SPACE as u8 } else { out[o] = e as u8 } o = o + 1 }
139 }
140 } else {
141 if o < cap - 1 { out[o] = c as u8; o = o + 1 }
142 }
143 i = i + 1
144 }
145 }
146 }
147 endpos[0] = i + 1
148 out[o] = 0 as u8
149 return o
150}
151
152// [PRESENT] -- the typed present-tense narrative from nx_elara_state. An UNSET present is not a present: defaults are
153// never narrated as facts (the neg-control-empty-session tooth pins this).
154func mind_state_block(session: *u8, out: *u8, cap: i64) -> i64 {
155 let buf: *u8 = sys_mmap(MIND_CAP)
156 let n: i64 = mind_run(MIND_ELF_STATE, 2, "context" as *u8, session, 0 as *u8, 0 as *u8, buf)
157 if n <= 0 { return 0 }
158 let nar: *u8 = sys_mmap(MIND_BLOCK_CAP)
159 let ep: *i64 = sys_mmap(16) as *i64
160 let nl: i64 = mind_jstr(buf, n, 0, "\"narrative\":\"" as *u8, nar, MIND_BLOCK_CAP, ep)
161 if nl <= 0 { return 0 }
162 if mind_find(nar, nl, 0, "unset" as *u8) >= 0 { return 0 }
163 if nl + 128 >= cap { return 0 }
164 var o: i64 = 0
165 o = mind_cat(out, o, "[PRESENT -- your body, place and mood right now; stay consistent with it]\n" as *u8)
166 o = mind_cat(out, o, nar)
167 o = mind_cat(out, o, "\n" as *u8)
168 return o
169}
170
171// [RELATIONSHIP STATE] + facts + shared memories, verbatim from nx_charmem ctx (it already speaks prompt).
172func mind_rel_block(session: *u8, out: *u8, cap: i64) -> i64 {
173 let buf: *u8 = sys_mmap(MIND_CAP)
174 let n: i64 = mind_run(MIND_ELF_CHAR, 2, "ctx" as *u8, session, 0 as *u8, 0 as *u8, buf)
175 if n <= 0 { return 0 }
176 if mind_find(buf, n, 0, "[RELATIONSHIP STATE]" as *u8) != 0 { return 0 }
177 if n + 2 >= cap { return 0 }
178 var o: i64 = 0
179 var i: i64 = 0
180 while i < n { out[o] = buf[i]; o = o + 1; i = i + 1 }
181 if out[o - 1] != (MIND_CH_NL as u8) { out[o] = MIND_CH_NL as u8; o = o + 1 }
182 return o
183}
184
185// [REMEMBERED] -- salience-ranked recall of what they told her before, keyed on THIS turn's words. Zero hits = zero bytes.
186func mind_mem_block(session: *u8, umsg: *u8, umlen: i64, out: *u8, cap: i64) -> i64 {
187 if umlen <= 0 { return 0 }
188 let q: *u8 = sys_mmap(MIND_QUERY_CAP + 8)
189 mind_query(umsg, umlen, q)
190 let buf: *u8 = sys_mmap(MIND_CAP)
191 let n: i64 = mind_run(MIND_ELF_MEM, 4, "recall" as *u8, session, q, MIND_RECALL_MAX, buf)
192 if n <= 0 { return 0 }
193 if mind_find(buf, n, 0, "\"hits\":0," as *u8) >= 0 { return 0 }
194 let txt: *u8 = sys_mmap(MIND_BLOCK_CAP)
195 let ep: *i64 = sys_mmap(16) as *i64
196 var o: i64 = 0
197 var emitted: i64 = 0
198 var from: i64 = 0
199 var scan: i64 = 1
200 while scan == 1 {
201 let tl: i64 = mind_jstr(buf, n, from, "\"text\":\"" as *u8, txt, MIND_BLOCK_CAP, ep)
202 if ep[0] < 0 { scan = 0 } else {
203 from = ep[0]
204 if tl > 0 {
205 if o + tl + 128 >= cap { scan = 0 } else {
206 if emitted == 0 { o = mind_cat(out, o, "[REMEMBERED -- things they told you before; use the exact detail, never an invented variant]\n" as *u8) }
207 o = mind_cat(out, o, "- " as *u8)
208 o = mind_cat(out, o, txt)
209 o = mind_cat(out, o, "\n" as *u8)
210 emitted = emitted + 1
211 }
212 }
213 }
214 }
215 return o
216}
217
218// [WORLD] -- lorebook entries this turn touched (CC3, em_lorebook). A budget refusal is written to stderr and contributes
219// zero bytes: the model never reads half a fact, and the daemon log says why nothing was injected.
220func mind_world_block(umsg: *u8, umlen: i64, out: *u8, cap: i64) -> i64 {
221 if umlen <= 0 { return 0 }
222 let stats: *i64 = sys_mmap(LB_STATS_N * MIND_I64_BYTES) as *i64
223 let n: i64 = em_lorebook(umsg, umlen, out, cap, stats)
224 if stats[LB_ST_REFUSED] == 1 {
225 if n > 0 { sys_write(MIND_FD_STDERR, out, n) }
226 out[0] = 0 as u8
227 return 0
228 }
229 return n
230}
231
232// THE CONTRACT. Composes present + relationship + world + remembered into out (NUL-terminated), returns bytes written.
233// Order is deliberate: what she IS now, who they ARE to each other, what the WORLD they touched holds, then what they SAID before.
234func go_mind_context(umsg: *u8, umlen: i64, out: *u8, cap: i64) -> i64 {
235 if cap < 256 { out[0] = 0 as u8; return 0 }
236 let session: *u8 = sys_mmap(64)
237 mind_session(session)
238 var o: i64 = 0
239 o = o + mind_state_block(session, ((out as i64) + o) as *u8, cap - o - 1)
240 o = o + mind_rel_block(session, ((out as i64) + o) as *u8, cap - o - 1)
241 o = o + mind_world_block(umsg, umlen, ((out as i64) + o) as *u8, cap - o - 1)
242 o = o + mind_mem_block(session, umsg, umlen, ((out as i64) + o) as *u8, cap - o - 1)
243 out[o] = 0 as u8
244 return o
245}
246
247// the write half: the user's turn enters long-term memory as an event; em_salience decides what surfaces later.
248// Called AFTER the reply, so a turn never recalls itself.
249func go_mind_remember(umsg: *u8, umlen: i64) -> i64 {
250 if umlen <= 0 { return 0 }
251 let session: *u8 = sys_mmap(64)
252 mind_session(session)
253 let q: *u8 = sys_mmap(MIND_QUERY_CAP + 8)
254 mind_query(umsg, umlen, q)
255 let buf: *u8 = sys_mmap(MIND_CAP)
256 mind_run(MIND_ELF_MEM, 4, "remember" as *u8, session, q, "event" as *u8, buf)
257 return 0
258}