nx_actor_role_llm_v2_real_test.nx source
↩ module page · 262 lines · 11195 B
1// nx_actor_role_llm_v2_real_test.nx -- REAL end-to-end smoke driving the
2// v2 LLM actor through actual transformer forward.
3//
4// Where nx_actor_role_llm_v2_test.nx is wiring-only, THIS smoke builds
5// a real 12-tensor synthetic Llama GGUF (n_layers=1, hidden=2, head=2,
6// vocab=4, ffn=4, all-zero F32 weights), a real BPE vocab, and drives
7// the v2 actor adapter through INIT -> RUN -> EMIT. RUN actually
8// invokes nx_llm_generate_one_v2 which executes:
9//
10// tokenize prompt -> nx_embedding_lookup -> RoPE + RMSNorm +
11// multi-head attention + SwiGLU FFN + output norm + output proj
12// + temperature + top_k + nx_sample_categorical -> token id
13//
14// Per the operator constraint: "real testing of real world capabilities
15// bits up". No constructor-rejection-only paper proof; this exercises
16// the entire other-agent runner stack through the actor system.
17//
18// Composes [[feedback-real-playtest-loop-not-just-logs]] +
19// [[feedback-four-pillar-code-hygiene-untracked-imports]] (additive
20// fix landed; preventative scanner shipped; this is the demonstration
21// of the now-safe end-to-end path).
22
23import "nx_syscalls.nx"
24import "nx_tier.nx"
25import "nx_le.nx"
26import "nx_tensor.nx"
27import "nx_bpe.nx"
28import "nx_model_spec.nx"
29import "nx_prng.nx"
30import "nx_gguf.nx"
31import "nx_gguf_load.nx"
32import "nx_llm_run_v2.nx"
33import "nx_actor.nx"
34import "nx_message.nx"
35import "nx_actor_role_llm_v2.nx"
36
37// ===== GGUF fixture builders (same shape as v2 runner test) =====
38
39func _write_ti(buf: *u8, off: i64,
40 name: *u8, name_len: i64,
41 n_dims: i64, dim_0: i64, dim_1: i64,
42 ggml_type: i64, data_offset: i64) -> i64 {
43 nx_le_write_u64(buf, off, name_len)
44 var o: i64 = off + 8
45 var i: i64 = 0
46 while i < name_len { buf[o + i] = name[i]; i = i + 1 }
47 o = o + name_len
48 nx_le_write_u32(buf, o, n_dims); o = o + 4
49 nx_le_write_u64(buf, o, dim_0); o = o + 8
50 if n_dims >= 2 { nx_le_write_u64(buf, o, dim_1); o = o + 8 }
51 nx_le_write_u32(buf, o, ggml_type); o = o + 4
52 nx_le_write_u64(buf, o, data_offset); o = o + 8
53 return o
54}
55
56func _mk_blk_name(suffix: *u8, suffix_len: nx_int, out: *u8) -> nx_int {
57 out[0]=0x62; out[1]=0x6c; out[2]=0x6b; out[3]=0x2e
58 out[4]=0x30; out[5]=0x2e
59 var i: nx_int = 0
60 while i < suffix_len { out[6 + i] = suffix[i]; i = i + 1 }
61 return 6 + suffix_len
62}
63
64func main() -> i64 {
65 let now: nx_size = 1000000
66
67 // ===== Stage 1: build synthetic GGUF byte buffer =====
68 let buf: *u8 = sys_mmap(4096)
69 buf[0]=0x47; buf[1]=0x47; buf[2]=0x55; buf[3]=0x46
70 buf[4]=3
71 nx_le_write_u64(buf, 8, 12)
72 nx_le_write_u64(buf, 16, 0)
73
74 let n_te: *u8 = sys_mmap(17)
75 n_te[0]=0x74; n_te[1]=0x6f; n_te[2]=0x6b; n_te[3]=0x65
76 n_te[4]=0x6e; n_te[5]=0x5f; n_te[6]=0x65; n_te[7]=0x6d
77 n_te[8]=0x62; n_te[9]=0x64; n_te[10]=0x2e; n_te[11]=0x77
78 n_te[12]=0x65; n_te[13]=0x69; n_te[14]=0x67; n_te[15]=0x68
79 n_te[16]=0x74
80
81 let n_on: *u8 = sys_mmap(18)
82 n_on[0]=0x6f; n_on[1]=0x75; n_on[2]=0x74; n_on[3]=0x70
83 n_on[4]=0x75; n_on[5]=0x74; n_on[6]=0x5f; n_on[7]=0x6e
84 n_on[8]=0x6f; n_on[9]=0x72; n_on[10]=0x6d; n_on[11]=0x2e
85 n_on[12]=0x77; n_on[13]=0x65; n_on[14]=0x69; n_on[15]=0x67
86 n_on[16]=0x68; n_on[17]=0x74
87
88 let n_ow: *u8 = sys_mmap(13)
89 n_ow[0]=0x6f; n_ow[1]=0x75; n_ow[2]=0x74; n_ow[3]=0x70
90 n_ow[4]=0x75; n_ow[5]=0x74; n_ow[6]=0x2e; n_ow[7]=0x77
91 n_ow[8]=0x65; n_ow[9]=0x69; n_ow[10]=0x67; n_ow[11]=0x68
92 n_ow[12]=0x74
93
94 let s_an: *u8 = sys_mmap(16)
95 s_an[0]=0x61; s_an[1]=0x74; s_an[2]=0x74; s_an[3]=0x6e
96 s_an[4]=0x5f; s_an[5]=0x6e; s_an[6]=0x6f; s_an[7]=0x72
97 s_an[8]=0x6d; s_an[9]=0x2e; s_an[10]=0x77; s_an[11]=0x65
98 s_an[12]=0x69; s_an[13]=0x67; s_an[14]=0x68; s_an[15]=0x74
99
100 let s_q: *u8 = sys_mmap(13)
101 s_q[0]=0x61; s_q[1]=0x74; s_q[2]=0x74; s_q[3]=0x6e
102 s_q[4]=0x5f; s_q[5]=0x71; s_q[6]=0x2e; s_q[7]=0x77
103 s_q[8]=0x65; s_q[9]=0x69; s_q[10]=0x67; s_q[11]=0x68; s_q[12]=0x74
104
105 let s_k: *u8 = sys_mmap(13)
106 s_k[0]=0x61; s_k[1]=0x74; s_k[2]=0x74; s_k[3]=0x6e
107 s_k[4]=0x5f; s_k[5]=0x6b; s_k[6]=0x2e; s_k[7]=0x77
108 s_k[8]=0x65; s_k[9]=0x69; s_k[10]=0x67; s_k[11]=0x68; s_k[12]=0x74
109
110 let s_v: *u8 = sys_mmap(13)
111 s_v[0]=0x61; s_v[1]=0x74; s_v[2]=0x74; s_v[3]=0x6e
112 s_v[4]=0x5f; s_v[5]=0x76; s_v[6]=0x2e; s_v[7]=0x77
113 s_v[8]=0x65; s_v[9]=0x69; s_v[10]=0x67; s_v[11]=0x68; s_v[12]=0x74
114
115 let s_o: *u8 = sys_mmap(18)
116 s_o[0]=0x61; s_o[1]=0x74; s_o[2]=0x74; s_o[3]=0x6e
117 s_o[4]=0x5f; s_o[5]=0x6f; s_o[6]=0x75; s_o[7]=0x74
118 s_o[8]=0x70; s_o[9]=0x75; s_o[10]=0x74; s_o[11]=0x2e
119 s_o[12]=0x77; s_o[13]=0x65; s_o[14]=0x69; s_o[15]=0x67
120 s_o[16]=0x68; s_o[17]=0x74
121
122 let s_fn: *u8 = sys_mmap(15)
123 s_fn[0]=0x66; s_fn[1]=0x66; s_fn[2]=0x6e; s_fn[3]=0x5f
124 s_fn[4]=0x6e; s_fn[5]=0x6f; s_fn[6]=0x72; s_fn[7]=0x6d
125 s_fn[8]=0x2e; s_fn[9]=0x77; s_fn[10]=0x65; s_fn[11]=0x69
126 s_fn[12]=0x67; s_fn[13]=0x68; s_fn[14]=0x74
127
128 let s_fg: *u8 = sys_mmap(15)
129 s_fg[0]=0x66; s_fg[1]=0x66; s_fg[2]=0x6e; s_fg[3]=0x5f
130 s_fg[4]=0x67; s_fg[5]=0x61; s_fg[6]=0x74; s_fg[7]=0x65
131 s_fg[8]=0x2e; s_fg[9]=0x77; s_fg[10]=0x65; s_fg[11]=0x69
132 s_fg[12]=0x67; s_fg[13]=0x68; s_fg[14]=0x74
133
134 let s_fu: *u8 = sys_mmap(13)
135 s_fu[0]=0x66; s_fu[1]=0x66; s_fu[2]=0x6e; s_fu[3]=0x5f
136 s_fu[4]=0x75; s_fu[5]=0x70; s_fu[6]=0x2e; s_fu[7]=0x77
137 s_fu[8]=0x65; s_fu[9]=0x69; s_fu[10]=0x67; s_fu[11]=0x68; s_fu[12]=0x74
138
139 let s_fd: *u8 = sys_mmap(15)
140 s_fd[0]=0x66; s_fd[1]=0x66; s_fd[2]=0x6e; s_fd[3]=0x5f
141 s_fd[4]=0x64; s_fd[5]=0x6f; s_fd[6]=0x77; s_fd[7]=0x6e
142 s_fd[8]=0x2e; s_fd[9]=0x77; s_fd[10]=0x65; s_fd[11]=0x69
143 s_fd[12]=0x67; s_fd[13]=0x68; s_fd[14]=0x74
144
145 let n_an: *u8 = sys_mmap(32); let l_an: nx_int = _mk_blk_name(s_an, 16, n_an)
146 let n_q: *u8 = sys_mmap(32); let l_q: nx_int = _mk_blk_name(s_q, 13, n_q)
147 let n_k: *u8 = sys_mmap(32); let l_k: nx_int = _mk_blk_name(s_k, 13, n_k)
148 let n_v: *u8 = sys_mmap(32); let l_v: nx_int = _mk_blk_name(s_v, 13, n_v)
149 let n_o: *u8 = sys_mmap(32); let l_o: nx_int = _mk_blk_name(s_o, 18, n_o)
150 let n_fn: *u8 = sys_mmap(32); let l_fn: nx_int = _mk_blk_name(s_fn, 15, n_fn)
151 let n_fg: *u8 = sys_mmap(32); let l_fg: nx_int = _mk_blk_name(s_fg, 15, n_fg)
152 let n_fu: *u8 = sys_mmap(32); let l_fu: nx_int = _mk_blk_name(s_fu, 13, n_fu)
153 let n_fd: *u8 = sys_mmap(32); let l_fd: nx_int = _mk_blk_name(s_fd, 15, n_fd)
154
155 var p: i64 = 24
156 p = _write_ti(buf, p, n_te, 17, 2, 4, 2, NX_GGML_TYPE_F32, 0)
157 p = _write_ti(buf, p, n_on, 18, 1, 2, 1, NX_GGML_TYPE_F32, 32)
158 p = _write_ti(buf, p, n_ow, 13, 2, 2, 4, NX_GGML_TYPE_F32, 40)
159 p = _write_ti(buf, p, n_an, l_an, 1, 2, 1, NX_GGML_TYPE_F32, 72)
160 p = _write_ti(buf, p, n_q, l_q, 2, 2, 2, NX_GGML_TYPE_F32, 80)
161 p = _write_ti(buf, p, n_k, l_k, 2, 2, 2, NX_GGML_TYPE_F32, 96)
162 p = _write_ti(buf, p, n_v, l_v, 2, 2, 2, NX_GGML_TYPE_F32, 112)
163 p = _write_ti(buf, p, n_o, l_o, 2, 2, 2, NX_GGML_TYPE_F32, 128)
164 p = _write_ti(buf, p, n_fn, l_fn, 1, 2, 1, NX_GGML_TYPE_F32, 144)
165 p = _write_ti(buf, p, n_fg, l_fg, 2, 2, 4, NX_GGML_TYPE_F32, 152)
166 p = _write_ti(buf, p, n_fu, l_fu, 2, 2, 4, NX_GGML_TYPE_F32, 184)
167 p = _write_ti(buf, p, n_fd, l_fd, 2, 4, 2, NX_GGML_TYPE_F32, 216)
168
169 let data_off: i64 = (p + 31) / 32 * 32
170 var zi: nx_int = 0
171 while zi < 248 { buf[data_off + zi] = 0; zi = zi + 1 }
172
173 // ===== Stage 2: parse GGUF =====
174 let hdr: *NxGgufHeader = sys_mmap(NX_GGUF_HDR_BYTES) as *NxGgufHeader
175 if nx_gguf_parse(buf, 4096, hdr) != NX_GGUF_OK { return 1 }
176 if hdr.n_tensors != 12 { return 2 }
177
178 // ===== Stage 3: model spec =====
179 let spec: *NxModelSpec = nx_model_spec_new()
180 spec.n_layers = 1
181 spec.hidden_dim = 2
182 spec.n_heads = 1
183 spec.head_dim = 2
184 spec.n_kv_heads = 1
185 spec.ffn_dim = 4
186 spec.vocab_size = 4
187 spec.max_seq_len = 8
188 if nx_model_spec_validate(spec) != NX_MS_OK { return 3 }
189
190 // ===== Stage 4: BPE vocab (4 single-byte tokens) =====
191 let bpe: *NxBpeVocab = nx_bpe_vocab_new(256, 16, 8)
192 let ba: *u8 = sys_mmap(1); ba[0] = 0x61
193 let bb: *u8 = sys_mmap(1); bb[0] = 0x62
194 let bc: *u8 = sys_mmap(1); bc[0] = 0x63
195 let bd: *u8 = sys_mmap(1); bd[0] = 0x64
196 nx_bpe_add_token(bpe, ba, 1)
197 nx_bpe_add_token(bpe, bb, 1)
198 nx_bpe_add_token(bpe, bc, 1)
199 nx_bpe_add_token(bpe, bd, 1)
200
201 // ===== Stage 5: prompt + prng =====
202 let prompt: *u8 = sys_mmap(1); prompt[0] = 0x61
203 let prng: *i64 = sys_mmap(8) as *i64
204 nx_prng_init(prng, 0xcafebabe)
205
206 // ===== Stage 6: build v2 LLM actor adapter =====
207 let ctx: *NxLlmV2ActorCtx = nx_lv_actor_new(
208 spec, buf, hdr, bpe, prompt, 1,
209 1024, 4, prng, 10000, 724)
210 if (ctx as i64) == 0 { return 4 }
211 if ctx.current_phase != NX_LV_PHASE_INIT { return 5 }
212
213 // ===== Stage 7: substrate scheduler + bus + listener =====
214 let sched: *NxActorScheduler = nx_ac_sched_new(4, 1000000, 8, now)
215 nx_ac_spawn(sched, 4001, 1, 80, 0, now)
216 let bus: *NxMessageBus = nx_ms_bus_new(4, 8, 8)
217 nx_ms_register(bus, 4001)
218 nx_ms_register(bus, 4002)
219 nx_ms_subscribe(bus, 4002, NX_MS_KIND_LLM_TOKEN)
220 nx_ms_subscribe(bus, 4002, NX_MS_KIND_ERROR_REPORT)
221
222 // ===== Stage 8: drive actor INIT -> RUN -> EMIT -> DONE =====
223 if nx_lv_actor_step(ctx, sched, bus, 4001, now + 100) != NX_LV_V_STEPPED { return 6 }
224 if ctx.current_phase != NX_LV_PHASE_RUN { return 7 }
225
226 // RUN actually executes the full transformer forward through the
227 // other-agent runner. With all-zero weights the logits are uniform
228 // so the sampler returns a token in [0, vocab_size).
229 let v_run: nx_int = nx_lv_actor_step(ctx, sched, bus, 4001, now + 200)
230 if ctx.current_phase != NX_LV_PHASE_EMIT { return 8 }
231 if v_run != NX_LV_V_STEPPED { return 9 }
232 // Real runner returned a non-negative token
233 if ctx.runner_result < 0 { return 10 }
234 if ctx.runner_result >= 4 { return 11 }
235 if ctx.runner_verdict != NX_LR2_OK { return 12 }
236
237 // EMIT pushes LLM_TOKEN (not ERROR_REPORT) because runner_result >= 0
238 let v_emit: nx_int = nx_lv_actor_step(ctx, sched, bus, 4001, now + 300)
239 if v_emit != NX_LV_V_COMPLETED { return 13 }
240 if ctx.current_phase != NX_LV_PHASE_DONE { return 14 }
241 if nx_lv_actor_is_done(ctx) != 1 { return 15 }
242
243 // ===== Stage 9: listener received LLM_TOKEN with the real token =====
244 if nx_ms_pending(bus, 4002) != 1 { return 16 }
245 let m: *NxMessage = nx_ms_receive(bus, 4002)
246 if m.kind != NX_MS_KIND_LLM_TOKEN { return 17 }
247 if m.sender_actor_id != 4001 { return 18 }
248 let recv_token: nx_int = m.payload_handle as nx_int
249 if recv_token != ctx.runner_result { return 19 }
250 if recv_token < 0 { return 20 }
251 if recv_token >= 4 { return 21 }
252
253 // ===== Stage 10: scheduler marks COMPLETED (not FAILED) =====
254 let a: *NxActor = nx_ac_find(sched, 4001)
255 if a.state != NX_AC_STATE_COMPLETED { return 22 }
256
257 // ===== Stage 11: accessors return the real values =====
258 if nx_lv_actor_token(ctx) != ctx.runner_result { return 23 }
259 if nx_lv_actor_runner_verdict(ctx) != NX_LR2_OK { return 24 }
260
261 return 0
262}