code wiki / (root) / nx_triple_companion_compose_test.nx

nx_triple_companion_compose_test.nx source

↩ module page · 194 lines · 6967 B

1// nx_triple_companion_compose_test.nx -- heterogeneous 3-modality smoke. 2// 3// Goes beyond [[nx_dual_companion_compose_test]]: instead of two LLM 4// clones, runs THREE actors of DIFFERENT modalities concurrently: 5// 6// NARRATOR (LLM, priority 80) -- nx_actor_role_llm 7// NPC (LLM, priority 60) -- nx_actor_role_llm 8// AUDIO_QC (audio scene grader, priority 50) -- nx_actor_role_audio_grader 9// 10// All three share one scheduler + one message bus + one multiplexer. 11// Each actor calls a DIFFERENT other-agent primitive: 12// NARRATOR/NPC -> embedding_lookup + blas_matmul + sample_categorical 13// AUDIO_QC -> audio_scene_grade 14// 15// This is the smallest-honest demonstration that the parallel-companion 16// substrate handles HETEROGENEOUS modalities, not just N copies of the 17// same primitive. The DND companion north star is one of these 18// scenarios (LLM narrative + NPC dialogue + ambient audio grading 19// + game action processing) running in coherent interleaved fashion. 20 21import "nx_syscalls.nx" 22import "nx_tier.nx" 23import "nx_tensor.nx" 24import "nx_actor.nx" 25import "nx_message.nx" 26import "nx_stream_multiplexer.nx" 27import "nx_actor_role_llm.nx" 28import "nx_actor_role_audio_grader.nx" 29 30func _fill_q10(t: *NxTensor, base: i64, stride: i64) -> i64 { 31 let p: *i64 = t.storage as *i64 32 var i: nx_int = 0 33 while i < t.numel { 34 p[i] = base + (i as i64) * stride 35 i = i + 1 36 } 37 return 0 38} 39 40func main() -> i64 { 41 let now: nx_size = 1000000 42 43 // 1: LLM weights (shared between NARRATOR + NPC) 44 let shape_buf: *u8 = sys_mmap(16) 45 let shape: *i64 = shape_buf as *i64 46 shape[0] = 4 47 shape[1] = 4 48 let err_buf: *u8 = sys_mmap(8) 49 let err_p: *i64 = err_buf as *i64 50 let embed_table: *NxTensor = nx_t_alloc(NX_DT_I64, shape, 2, err_p) 51 if err_p[0] != NX_T_OK { return 1 } 52 _fill_q10(embed_table, 100, 5) 53 54 let shape2_buf: *u8 = sys_mmap(16) 55 let shape2: *i64 = shape2_buf as *i64 56 shape2[0] = 4 57 shape2[1] = 4 58 let out_proj: *NxTensor = nx_t_alloc(NX_DT_I64, shape2, 2, err_p) 59 _fill_q10(out_proj, 40, 3) 60 61 // 2: audio scene inputs 62 let bins_buf: *u8 = sys_mmap(64) 63 let bins: *i64 = bins_buf as *i64 64 var b: nx_int = 0 65 while b < 8 { 66 bins[b] = 5000 + ((b * 800) as i64) // ramped spectrum 67 b = b + 1 68 } 69 let rms_buf: *u8 = sys_mmap(128) 70 let rms: *i64 = rms_buf as *i64 71 var f: nx_int = 0 72 while f < 16 { 73 rms[f] = 2500 + ((f * 150) as i64) 74 f = f + 1 75 } 76 77 // 3: shared substrate 78 let sched: *NxActorScheduler = nx_ac_sched_new(8, 1000000, 8, now) 79 let bus: *NxMessageBus = nx_ms_bus_new(8, 16, 8) 80 let mux: *NxStreamMultiplexer = nx_sm_new(16, 50000) 81 82 let NARR: nx_int = 7001 83 let NPC: nx_int = 7002 84 let AUD: nx_int = 7003 85 let LIS: nx_int = 7099 86 87 nx_ac_spawn(sched, NARR, 1, 80, 0, now) 88 nx_ac_spawn(sched, NPC, 1, 60, 0, now) 89 nx_ac_spawn(sched, AUD, 4, 50, 0, now) 90 nx_ac_spawn(sched, LIS, 5, 40, 0, now) 91 92 nx_ms_register(bus, NARR) 93 nx_ms_register(bus, NPC) 94 nx_ms_register(bus, AUD) 95 nx_ms_register(bus, LIS) 96 nx_ms_subscribe(bus, LIS, NX_MS_KIND_LLM_TOKEN) 97 nx_ms_subscribe(bus, LIS, NX_MS_KIND_AUDIO_FRAME) 98 99 // 4: contexts 100 let narr_ctx: *NxLlmActorCtx = nx_lr_actor_new(embed_table, out_proj, 1, 4, 4, 1024, 2, 11) 101 let npc_ctx: *NxLlmActorCtx = nx_lr_actor_new(embed_table, out_proj, 2, 4, 4, 1024, 2, 13) 102 let aud_ctx: *NxAudioGraderCtx = nx_ag_actor_new(bins, 8, rms, 16, 4) 103 if (narr_ctx as i64) == 0 { return 2 } 104 if (npc_ctx as i64) == 0 { return 3 } 105 if (aud_ctx as i64) == 0 { return 4 } 106 107 // 5: pick_next initial state -- NARR is highest priority (80) 108 let first: *NxActor = nx_ac_pick_next(sched) 109 if first.actor_id != NARR { return 5 } 110 111 // 6: interleave 5 LLM-actor steps for NARR, 5 for NPC, 3 for AUD. 112 // All three actors COMPLETE concurrently in this round. 113 var tick: nx_size = now + 100 114 var i: nx_int = 0 115 while i < 5 { 116 nx_lr_actor_step(narr_ctx, sched, bus, NARR, tick) 117 tick = tick + 50 118 i = i + 1 119 } 120 var j: nx_int = 0 121 while j < 5 { 122 nx_lr_actor_step(npc_ctx, sched, bus, NPC, tick) 123 tick = tick + 50 124 j = j + 1 125 } 126 var k: nx_int = 0 127 while k < 3 { 128 nx_ag_actor_step(aud_ctx, sched, bus, AUD, tick) 129 tick = tick + 50 130 k = k + 1 131 } 132 133 // 7: all three actors COMPLETED 134 let na: *NxActor = nx_ac_find(sched, NARR) 135 let nb: *NxActor = nx_ac_find(sched, NPC) 136 let nc: *NxActor = nx_ac_find(sched, AUD) 137 if na.state != NX_AC_STATE_COMPLETED { return 6 } 138 if nb.state != NX_AC_STATE_COMPLETED { return 7 } 139 if nc.state != NX_AC_STATE_COMPLETED { return 8 } 140 141 // 8: LISTENER mailbox has 3 messages: 2 LLM_TOKEN + 1 AUDIO_FRAME 142 if nx_ms_pending(bus, LIS) != 3 { return 9 } 143 144 // 9: tokens valid 145 let narr_tok: nx_int = nx_lr_actor_token(narr_ctx) 146 let npc_tok: nx_int = nx_lr_actor_token(npc_ctx) 147 if narr_tok < 0 { return 10 } 148 if narr_tok >= 4 { return 11 } 149 if npc_tok < 0 { return 12 } 150 if npc_tok >= 4 { return 13 } 151 152 // 10: audio score positive (healthy synthetic scene) 153 if nx_ag_actor_score_q14(aud_ctx) <= 0 { return 14 } 154 155 // 11: drain LISTENER mailbox. Receive order = FIFO = NARR_LLM, NPC_LLM, AUD. 156 let m1: *NxMessage = nx_ms_receive(bus, LIS) 157 if m1.kind != NX_MS_KIND_LLM_TOKEN { return 15 } 158 if m1.sender_actor_id != NARR { return 16 } 159 if (m1.payload_handle as nx_int) != narr_tok { return 17 } 160 161 let m2: *NxMessage = nx_ms_receive(bus, LIS) 162 if m2.kind != NX_MS_KIND_LLM_TOKEN { return 18 } 163 if m2.sender_actor_id != NPC { return 19 } 164 165 let m3: *NxMessage = nx_ms_receive(bus, LIS) 166 if m3.kind != NX_MS_KIND_AUDIO_FRAME { return 20 } 167 if m3.sender_actor_id != AUD { return 21 } 168 if (m3.payload_handle as nx_int) != nx_ag_actor_score_q14(aud_ctx) { return 22 } 169 170 // 12: push to multiplexer with stream classes -- LLM_TEXT > AUDIO_TTS by priority 171 nx_sm_push(mux, NARR, NX_SM_CLASS_LLM_TEXT, 1, 8, narr_tok as nx_size, tick) 172 nx_sm_push(mux, NPC, NX_SM_CLASS_LLM_TEXT, 2, 8, npc_tok as nx_size, tick) 173 nx_sm_push(mux, AUD, NX_SM_CLASS_AUDIO_TTS, 3, 8, nx_ag_actor_score_q14(aud_ctx) as nx_size, tick) 174 if nx_sm_pending_count(mux) != 3 { return 23 } 175 176 // 13: drain -- both LLM_TEXT (priority 80) come before AUDIO_TTS (priority 70) 177 let oc_buf: *u8 = sys_mmap(24) 178 let oc: *i64 = oc_buf as *i64 179 let os: *i64 = (oc_buf + 8) as *i64 180 let oid: *i64 = (oc_buf + 16) as *i64 181 182 nx_sm_next(mux, oc, os, oid, tick + 100) 183 if oc[0] != (NX_SM_CLASS_LLM_TEXT as i64) { return 24 } 184 185 nx_sm_next(mux, oc, os, oid, tick + 200) 186 if oc[0] != (NX_SM_CLASS_LLM_TEXT as i64) { return 25 } 187 188 nx_sm_next(mux, oc, os, oid, tick + 300) 189 if oc[0] != (NX_SM_CLASS_AUDIO_TTS as i64) { return 26 } 190 191 if nx_sm_pending_count(mux) != 0 { return 27 } 192 193 return 0 194}