nx_forge_model.nx source
↩ module page · 285 lines · 11419 B
1// nx_forge_model.nx -- FORGE F3 rung 2: the MODEL BACKEND for the driver. Turns a model serve's
2// HTTP /gen response into a candidate .nx file, and composes the prompt the model sees. Same loop
3// as rung 1 -- the backend just PRODUCES the candidate that fg_run then judges byte-exact.
4// fm_compose_prompt(pack, task, repair, out, cap) pack v1 + task statement + (optional) the
5// verbatim repair context from a prior failed cycle -> prompt file.
6// fm_build_gen_body(prompt, plen, max_new, mode, out) the serve's POST /gen JSON body.
7// fm_post_gen(a,b,c,d, port, body, blen, resp, rescap) TCP POST /gen to a.b.c.d:port over the
8// proven nx_http_client primitives; returns response bytes (header+body).
9// fm_extract_text(resp, rlen, out, cap) pull the JSON "text" value, unescaping \n \t \" \\ \/
10// \r and \uXXXX (low byte) -> the raw model output. -1 if absent.
11// fm_strip_fences(src, n, out) drop a leading ```lang fence line + trailing ``` (the pilot's
12// hand extraction stage, now an organ). Idempotent on unfenced text.
13// fm_stub_serve_once(port, respfile) an in-process single-shot serve (gate fixture): binds,
14// accepts one client, replies with respfile's bytes as a /gen JSON -> lets
15// the gate prove the REAL loopback round-trip with no external model.
16// Rung 2 proves the model-stage mechanics sovereignly; pointing fm_post_gen at 127.0.0.1:11434
17// (the no-float serve) or an API egress is a live address swap, not new logic.
18// license_tier: ORIGINAL
19import "nx_forge.nx"
20import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
21import "nx_http_client.nx"
22
23func fm_hexval(c: i64) -> i64 {
24 if c >= 48 && c <= 57 { return c - 48 }
25 if c >= 97 && c <= 102 { return c - 97 + 10 }
26 if c >= 65 && c <= 70 { return c - 65 + 10 }
27 return 0
28}
29
30// compose the model prompt: pack v1 + task + optional repair context. Returns length (-1 on fail).
31func fm_compose_prompt(packpath: *u8, task: *u8, repairpath: *u8, out: *u8, cap: i64) -> i64 {
32 let pn: i64 = fc_read(packpath, out, cap)
33 if pn <= 0 { return 0 - 1 }
34 var o: i64 = pn
35 let h: *u8 = "\n\nTASK\n----\n" as *u8
36 var i: i64 = 0
37 while h[i] != (0 as u8) { out[o] = h[i]; o = o + 1; i = i + 1 }
38 i = 0
39 while task[i] != (0 as u8) {
40 if o >= cap { return 0 - 1 }
41 out[o] = task[i]
42 o = o + 1
43 i = i + 1
44 }
45 if (repairpath as i64) != 0 {
46 let rfd: i64 = sys_openat_rd(repairpath)
47 if rfd >= 0 {
48 let hh: *u8 = "\n\nPRIOR ATTEMPT FAILED -- the sovereign toolchain reported (fix exactly this, stay in the verified subset):\n" as *u8
49 var j: i64 = 0
50 while hh[j] != (0 as u8) { out[o] = hh[j]; o = o + 1; j = j + 1 }
51 var go: i64 = 1
52 while go == 1 {
53 let room: i64 = cap - o
54 if room <= 1 { go = 0 }
55 if go == 1 {
56 let p: *u8 = out + o
57 let r: i64 = sys_read(rfd, p, room)
58 if r <= 0 { go = 0 }
59 if r > 0 { o = o + r }
60 }
61 }
62 sys_close(rfd)
63 }
64 }
65 out[o] = 0 as u8
66 return o
67}
68
69// JSON body for POST /gen. mode 0=i32 (lossless), 1=i8 (fast).
70func fm_build_gen_body(prompt: *u8, plen: i64, max_new: i64, mode: i64, out: *u8) -> i64 {
71 var o: i64 = 0
72 let a: *u8 = "{\"prompt\":\"" as *u8
73 var i: i64 = 0
74 while a[i] != (0 as u8) { out[o] = a[i]; o = o + 1; i = i + 1 }
75 o = fc_json_esc_bytes(out, o, prompt, plen)
76 let b: *u8 = "\",\"max_new\":" as *u8
77 i = 0
78 while b[i] != (0 as u8) { out[o] = b[i]; o = o + 1; i = i + 1 }
79 let ml: i64 = std_itoa(max_new, out + o)
80 o = o + ml
81 let c: *u8 = ",\"mode\":" as *u8
82 i = 0
83 while c[i] != (0 as u8) { out[o] = c[i]; o = o + 1; i = i + 1 }
84 let mdl: i64 = std_itoa(mode, out + o)
85 o = o + mdl
86 out[o] = 125 as u8
87 o = o + 1
88 return o
89}
90
91// minimal JSON string-escape of src[0,n) into dst at off (", \, newline, tab, CR)
92func fc_json_esc_bytes(dst: *u8, off: i64, src: *u8, n: i64) -> i64 {
93 var o: i64 = off
94 var i: i64 = 0
95 while i < n {
96 let c: i64 = src[i] as i64
97 if c == 34 { dst[o] = 92 as u8; o = o + 1; dst[o] = 34 as u8; o = o + 1 }
98 if c == 92 { dst[o] = 92 as u8; o = o + 1; dst[o] = 92 as u8; o = o + 1 }
99 if c == 10 { dst[o] = 92 as u8; o = o + 1; dst[o] = 110 as u8; o = o + 1 }
100 if c == 9 { dst[o] = 92 as u8; o = o + 1; dst[o] = 116 as u8; o = o + 1 }
101 if c == 13 { dst[o] = 92 as u8; o = o + 1; dst[o] = 114 as u8; o = o + 1 }
102 if c != 34 && c != 92 && c != 10 && c != 9 && c != 13 { dst[o] = c as u8; o = o + 1 }
103 i = i + 1
104 }
105 return o
106}
107
108// find the JSON "text":" value and unescape it into out; returns len or -1
109func fm_extract_text(resp: *u8, rlen: i64, out: *u8, cap: i64) -> i64 {
110 let key: *u8 = "\"text\":\"" as *u8
111 let kl: i64 = std_slen(key)
112 var start: i64 = 0 - 1
113 var i: i64 = 0
114 let stop: i64 = rlen - kl
115 while i <= stop {
116 var j: i64 = 0
117 var hit: i64 = 1
118 while j < kl {
119 let idx: i64 = i + j
120 let a: i64 = resp[idx] as i64
121 let b: i64 = key[j] as i64
122 if a != b { hit = 0; j = kl }
123 if a == b { j = j + 1 }
124 }
125 if hit == 1 { start = i + kl; i = stop + 1 }
126 if hit == 0 { i = i + 1 }
127 }
128 if start < 0 { return 0 - 1 }
129 var o: i64 = 0
130 var p: i64 = start
131 var go: i64 = 1
132 while go == 1 {
133 if p >= rlen { go = 0 }
134 if o >= cap { go = 0 }
135 if go == 1 {
136 let c: i64 = resp[p] as i64
137 if c == 34 { go = 0 }
138 if c == 92 {
139 let p1: i64 = p + 1
140 if p1 < rlen {
141 let e: i64 = resp[p1] as i64
142 if e == 110 { out[o] = 10 as u8; o = o + 1; p = p + 2 }
143 if e == 116 { out[o] = 9 as u8; o = o + 1; p = p + 2 }
144 if e == 114 { out[o] = 13 as u8; o = o + 1; p = p + 2 }
145 if e == 34 { out[o] = 34 as u8; o = o + 1; p = p + 2 }
146 if e == 92 { out[o] = 92 as u8; o = o + 1; p = p + 2 }
147 if e == 47 { out[o] = 47 as u8; o = o + 1; p = p + 2 }
148 if e == 117 {
149 let h3: i64 = p + 5
150 if h3 < rlen {
151 let d0: i64 = fm_hexval(resp[p + 2] as i64)
152 let d1: i64 = fm_hexval(resp[p + 3] as i64)
153 let d2: i64 = fm_hexval(resp[p + 4] as i64)
154 let d3: i64 = fm_hexval(resp[p + 5] as i64)
155 let hi: i64 = d0 * 4096 + d1 * 256 + d2 * 16 + d3
156 out[o] = (hi % 256) as u8
157 o = o + 1
158 p = p + 6
159 }
160 if h3 >= rlen { go = 0 }
161 }
162 if e != 110 && e != 116 && e != 114 && e != 34 && e != 92 && e != 47 && e != 117 {
163 out[o] = e as u8
164 o = o + 1
165 p = p + 2
166 }
167 }
168 if p1 >= rlen { go = 0 }
169 }
170 if c != 34 && c != 92 {
171 out[o] = c as u8
172 o = o + 1
173 p = p + 1
174 }
175 }
176 }
177 out[o] = 0 as u8
178 return o
179}
180
181// strip a leading ```lang fence and the trailing ```; idempotent on unfenced text. Returns len.
182func fm_strip_fences(src: *u8, n: i64, out: *u8) -> i64 {
183 // find first ```
184 var f0: i64 = 0 - 1
185 var i: i64 = 0
186 let stop: i64 = n - 3
187 while i <= stop {
188 let c0: i64 = src[i] as i64
189 let c1: i64 = src[i + 1] as i64
190 let c2: i64 = src[i + 2] as i64
191 if c0 == 96 && c1 == 96 && c2 == 96 { f0 = i; i = stop + 1 }
192 if f0 < 0 { i = i + 1 }
193 }
194 if f0 < 0 {
195 var k: i64 = 0
196 while k < n { out[k] = src[k]; k = k + 1 }
197 out[n] = 0 as u8
198 return n
199 }
200 // content starts after the newline following the opening fence
201 var cs: i64 = f0 + 3
202 var sc: i64 = 1
203 while sc == 1 {
204 if cs >= n { sc = 0 }
205 if sc == 1 {
206 let c: i64 = src[cs] as i64
207 cs = cs + 1
208 if c == 10 { sc = 0 }
209 }
210 }
211 // find last ``` at or after cs
212 var f1: i64 = n
213 var j: i64 = cs
214 let stop2: i64 = n - 3
215 while j <= stop2 {
216 let d0: i64 = src[j] as i64
217 let d1: i64 = src[j + 1] as i64
218 let d2: i64 = src[j + 2] as i64
219 if d0 == 96 && d1 == 96 && d2 == 96 { f1 = j }
220 j = j + 1
221 }
222 var o: i64 = 0
223 var p: i64 = cs
224 while p < f1 { out[o] = src[p]; o = o + 1; p = p + 1 }
225 out[o] = 0 as u8
226 return o
227}
228
229// TCP POST /gen to a.b.c.d:port with body; response (header+body) into resp. Returns bytes (-1 err).
230func fm_post_gen(a: i64, b: i64, c: i64, d: i64, port: i64, body: *u8, blen: i64, resp: *u8, rescap: i64) -> i64 {
231 let fd: i64 = sys_socket(2, 1, 0)
232 if fd < 0 { return 0 - 1 }
233 let addr: *u8 = sys_mmap(16) as *u8
234 nx_http_client_sockaddr_ipv4(addr, a, b, c, d, port)
235 let cr: i64 = nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS)
236 if cr < 0 { sys_close(fd); return 0 - 1 }
237 let req: *u8 = sys_mmap(262144) as *u8
238 let host: *u8 = "127.0.0.1" as *u8
239 let ct: *u8 = "application/json" as *u8
240 let rl: i64 = nx_http_client_build_request_post("/gen" as *u8, 4, host, 9, ct, 16, body, blen, req)
241 let wr: i64 = sys_write(fd, req, rl)
242 if wr != rl { sys_close(fd); return 0 - 1 }
243 let got: i64 = _drain(fd, resp, rescap)
244 sys_close(fd)
245 return got
246}
247
248// in-process single-shot stub serve (gate fixture): reply with respfile bytes as /gen JSON, exit.
249func fm_stub_serve_once(port: i64, respfile: *u8) -> i64 {
250 let fd: i64 = sys_socket(2, 1, 0)
251 if fd < 0 { return 0 - 1 }
252 let opt: *i64 = sys_mmap(8) as *i64
253 opt[0] = 1
254 __syscall(54, fd, 1, 2, opt as i64, 4, 0)
255 let addr: *u8 = sys_mmap(16) as *u8
256 addr[0] = 2 as u8
257 addr[1] = 0 as u8
258 addr[2] = ((port >> 8) & 255) as u8
259 addr[3] = (port & 255) as u8
260 var z: i64 = 4
261 while z < 16 { addr[z] = 0 as u8; z = z + 1 }
262 if sys_bind(fd, addr, 16) < 0 { sys_close(fd); return 0 - 2 }
263 if sys_listen(fd, 16) < 0 { sys_close(fd); return 0 - 3 }
264 let cfd: i64 = sys_accept(fd)
265 if cfd < 0 { sys_close(fd); return 0 - 4 }
266 let rq: *u8 = sys_mmap(65536) as *u8
267 sys_read(cfd, rq, 65536)
268 let bodybuf: *u8 = sys_mmap(65536) as *u8
269 let bn: i64 = fc_read(respfile, bodybuf, 65536)
270 let hdr: *u8 = sys_mmap(256) as *u8
271 var o: i64 = 0
272 let h1: *u8 = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: " as *u8
273 var i: i64 = 0
274 while h1[i] != (0 as u8) { hdr[o] = h1[i]; o = o + 1; i = i + 1 }
275 let dl: i64 = std_itoa(bn, hdr + o)
276 o = o + dl
277 let h2: *u8 = "\r\nConnection: close\r\n\r\n" as *u8
278 i = 0
279 while h2[i] != (0 as u8) { hdr[o] = h2[i]; o = o + 1; i = i + 1 }
280 sys_write(cfd, hdr, o)
281 sys_write(cfd, bodybuf, bn)
282 sys_close(cfd)
283 sys_close(fd)
284 return bn
285}