nx_actor_role_llm_test.nx source
↩ module page · 146 lines · 6659 B
1// nx_actor_role_llm_test.nx -- integration smoke proving the actor adapter
2// actually drives the other-agent LLM primitives.
3
4import "nx_syscalls.nx"
5import "nx_tier.nx"
6import "nx_tensor.nx"
7import "nx_actor.nx"
8import "nx_message.nx"
9import "nx_actor_role_llm.nx"
10
11// Helper: fill an i64 storage with a deterministic pattern so embedding
12// + matmul produce non-trivial output.
13func _fill_q10(t: *NxTensor, base: i64, stride: i64) -> i64 {
14 let p: *i64 = t.storage as *i64
15 var i: nx_int = 0
16 while i < t.numel {
17 p[i] = base + (i as i64) * stride
18 i = i + 1
19 }
20 return 0
21}
22
23func main() -> i64 {
24 let now: nx_size = 1000000
25
26 // 1: phase + verdict enums
27 if nx_lr_phase_is_valid(NX_LR_PHASE_INIT) != 1 { return 1 }
28 if nx_lr_phase_is_valid(NX_LR_PHASE_DONE) != 1 { return 2 }
29 if nx_lr_phase_is_valid(-1) != 0 { return 3 }
30 if nx_lr_phase_is_valid(6) != 0 { return 4 }
31 if NX_LR_PHASE_N != 6 { return 5 }
32
33 if nx_lr_ac_v_is_valid(NX_LR_AC_V_STEPPED) != 1 { return 6 }
34 if nx_lr_ac_v_is_valid(NX_LR_AC_V_NULL) != 1 { return 7 }
35
36 // 2: build synthetic 4-vocab x 4-hidden embedding table (the other agent's NxTensor)
37 let shape_buf: *u8 = sys_mmap(16)
38 let shape: *i64 = shape_buf as *i64
39 shape[0] = 4 // vocab
40 shape[1] = 4 // hidden
41 let err_buf: *u8 = sys_mmap(8)
42 let err_p: *i64 = err_buf as *i64
43 let embed_table: *NxTensor = nx_t_alloc(NX_DT_I64, shape, 2, err_p)
44 if err_p[0] != NX_T_OK { return 8 }
45 _fill_q10(embed_table, 100, 7) // 100, 107, 114, ..., distinct rows
46
47 // 3: build synthetic 4-hidden x 4-vocab output projection
48 let shape2_buf: *u8 = sys_mmap(16)
49 let shape2: *i64 = shape2_buf as *i64
50 shape2[0] = 4 // hidden
51 shape2[1] = 4 // vocab
52 let out_proj: *NxTensor = nx_t_alloc(NX_DT_I64, shape2, 2, err_p)
53 if err_p[0] != NX_T_OK { return 9 }
54 _fill_q10(out_proj, 50, 3)
55
56 // 4: construct LLM actor ctx with prompt_token=1, temp_q10=1024 (1.0), top_k=2
57 let ctx: *NxLlmActorCtx = nx_lr_actor_new(embed_table, out_proj, 1, 4, 4, 1024, 2, 42)
58 if (ctx as i64) == 0 { return 10 }
59 if ctx.prompt_token_id != 1 { return 11 }
60 if ctx.vocab_size != 4 { return 12 }
61 if ctx.hidden_dim != 4 { return 13 }
62 if ctx.current_phase != NX_LR_PHASE_INIT { return 14 }
63 if ctx.generated_token_id != -1 { return 15 }
64 if nx_lr_actor_phase(ctx) != NX_LR_PHASE_INIT { return 16 }
65 if nx_lr_actor_is_done(ctx) != 0 { return 17 }
66
67 // 5: invalid construction rejected
68 if nx_lr_actor_new(embed_table, out_proj, -1, 4, 4, 1024, 2, 42) != (0 as *NxLlmActorCtx) { return 18 }
69 if nx_lr_actor_new(embed_table, out_proj, 4, 4, 4, 1024, 2, 42) != (0 as *NxLlmActorCtx) { return 19 }
70 if nx_lr_actor_new(embed_table, out_proj, 1, 0, 4, 1024, 2, 42) != (0 as *NxLlmActorCtx) { return 20 }
71 if nx_lr_actor_new(embed_table, out_proj, 1, 4, 4, 0, 2, 42) != (0 as *NxLlmActorCtx) { return 21 }
72 if nx_lr_actor_new(embed_table, out_proj, 1, 4, 4, 1024, 0, 42) != (0 as *NxLlmActorCtx) { return 22 }
73
74 // 6: build supporting scheduler + message bus + subscribe
75 let sched: *NxActorScheduler = nx_ac_sched_new(4, 1000000, 8, now)
76 nx_ac_spawn(sched, 7001, 1, 80, 0, now) // LLM actor
77 nx_ac_spawn(sched, 7002, 4, 70, 0, now) // listener actor (audio)
78 let bus: *NxMessageBus = nx_ms_bus_new(4, 8, 8)
79 nx_ms_register(bus, 7001)
80 nx_ms_register(bus, 7002)
81 nx_ms_subscribe(bus, 7002, NX_MS_KIND_LLM_TOKEN)
82
83 // 7: drive phases. Step from INIT -> EMBED -> PROJ -> SAMPLE -> EMIT -> DONE = 5 steps.
84 if nx_lr_actor_step(ctx, sched, bus, 7001, now + 100) != NX_LR_AC_V_STEPPED { return 23 }
85 if ctx.current_phase != NX_LR_PHASE_EMBED { return 24 }
86
87 if nx_lr_actor_step(ctx, sched, bus, 7001, now + 200) != NX_LR_AC_V_STEPPED { return 25 }
88 if ctx.current_phase != NX_LR_PHASE_PROJ { return 26 }
89 // After EMBED, hidden_state[0..hidden] should equal embed_table row 1 = entries 107..128
90 let hs_p: *i64 = ctx.hidden_state.storage as *i64
91 if hs_p[0] != 100 + 4 * 7 { return 27 } // row 1, col 0 = 128
92
93 if nx_lr_actor_step(ctx, sched, bus, 7001, now + 300) != NX_LR_AC_V_STEPPED { return 28 }
94 if ctx.current_phase != NX_LR_PHASE_SAMPLE { return 29 }
95
96 if nx_lr_actor_step(ctx, sched, bus, 7001, now + 400) != NX_LR_AC_V_STEPPED { return 30 }
97 if ctx.current_phase != NX_LR_PHASE_EMIT { return 31 }
98 // After SAMPLE, generated_token_id must be in [0, vocab)
99 let tok: nx_int = nx_lr_actor_token(ctx)
100 if tok < 0 { return 32 }
101 if tok >= 4 { return 33 }
102
103 // 8: bus should not have an LLM_TOKEN yet (EMIT hasn't run)
104 if nx_ms_pending(bus, 7002) != 0 { return 34 }
105
106 // 9: EMIT step -- pushes msg + marks done
107 let v_complete: nx_int = nx_lr_actor_step(ctx, sched, bus, 7001, now + 500)
108 if v_complete != NX_LR_AC_V_COMPLETED { return 35 }
109 if ctx.current_phase != NX_LR_PHASE_DONE { return 36 }
110 if nx_lr_actor_is_done(ctx) != 1 { return 37 }
111
112 // 10: listener mailbox should have the token
113 if nx_ms_pending(bus, 7002) != 1 { return 38 }
114 let msg: *NxMessage = nx_ms_receive(bus, 7002)
115 if msg.kind != NX_MS_KIND_LLM_TOKEN { return 39 }
116 if msg.sender_actor_id != 7001 { return 40 }
117 if (msg.payload_handle as nx_int) != tok { return 41 }
118
119 // 11: scheduler tracks LLM actor as COMPLETED
120 let llm: *NxActor = nx_ac_find(sched, 7001)
121 if llm.state != NX_AC_STATE_COMPLETED { return 42 }
122
123 // 12: stepping past DONE is idempotent
124 if nx_lr_actor_step(ctx, sched, bus, 7001, now + 600) != NX_LR_AC_V_COMPLETED { return 43 }
125 if ctx.current_phase != NX_LR_PHASE_DONE { return 44 }
126 // No new message produced
127 if nx_ms_pending(bus, 7002) != 0 { return 45 }
128
129 // 13: second independent LLM actor with a different prompt token produces
130 // a DIFFERENT hidden_state (proves embedding lookup is row-specific)
131 let ctx2: *NxLlmActorCtx = nx_lr_actor_new(embed_table, out_proj, 3, 4, 4, 1024, 2, 42)
132 nx_lr_actor_step(ctx2, sched, bus, 7001, now) // INIT->EMBED
133 nx_lr_actor_step(ctx2, sched, bus, 7001, now) // EMBED->PROJ; hidden_state filled
134 let hs2_p: *i64 = ctx2.hidden_state.storage as *i64
135 // Row 3 col 0 = 100 + 3*4*7 = 184
136 if hs2_p[0] != 184 { return 46 }
137
138 // 14: null guards
139 let null_ctx: *NxLlmActorCtx = (0 as i64) as *NxLlmActorCtx
140 if nx_lr_actor_step(null_ctx, sched, bus, 7001, now) != NX_LR_AC_V_NULL { return 47 }
141 if nx_lr_actor_phase(null_ctx) != NX_LR_PHASE_DONE { return 48 }
142 if nx_lr_actor_token(null_ctx) != -1 { return 49 }
143 if nx_lr_actor_is_done(null_ctx) != 0 { return 50 }
144
145 return 0
146}