From 036fab47fae97b1e9af2010511997cd0b3358237 Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Sun, 14 Jun 2026 20:15:37 -0400 Subject: [PATCH] bend: handler returns formatted string + http-listener ships strings raw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous attempt to ship a pretty summary via an (summary "...") field inside the structured response broke on the asm (WAT) tier because read-from-string isn't a primitive there — the demo extraction fell through to the raw fallback and dumped the entire escaped S-expression. Two-part fix that works on all three tiers: http-listener (gpu-worker.lsp:1103-1116) — POST response builder now checks if the handle-request return value is a string and ships it as the raw HTTP body in that case. S-expression returns still go through write-to-string. One-line guard, no impact on ping/health/cuda-shake-fanout/cuda-sim-ops-bin which all keep returning structured S-exps. handle-cuda-secp256k1-bench — returns the formatted summary string directly instead of an (ok ... (summary ...)) wrapping. Drops the now-redundant structured fields; every number lives inside the human-readable text already. asm / c / python demo just calls (display (bend!-call "(cuda-secp256k1-bench N)")) and the formatted output panel renders identically on all tiers. Demo simplified accordingly: three (display (bend!-call …)) calls with newlines between, no read-from-string / assoc / pair? dance. --- examples/cuda-fanout/gpu-worker.lsp | 25 +++++++++++++++---------- wasm/app/demos/bend-gpu.lsp | 23 ++++++++--------------- www/playground/demos/bend-gpu.lsp | 23 ++++++++--------------- 3 files changed, 31 insertions(+), 40 deletions(-) diff --git a/examples/cuda-fanout/gpu-worker.lsp b/examples/cuda-fanout/gpu-worker.lsp index aa81ce3..af3b47e 100644 --- a/examples/cuda-fanout/gpu-worker.lsp +++ b/examples/cuda-fanout/gpu-worker.lsp @@ -450,15 +450,12 @@ (display count) (display " gpu-ms=") (display gpu-ms) (display " mkeys-s=") (display gpu-rate) (newline) - (list 'ok - (list 'n count) - (list 'gen-ms gen-ms) - (list 'gpu-ms gpu-ms) - (list 'gpu-mkeys-per-sec gpu-rate) - (list 'cpu-rate-mkeys-per-sec cpu-rate) - (list 'cpu-est-sec cpu-est-sec) - (list 'speedup-est speedup) - (list 'summary summary))))))))))))) + ;; Return the formatted summary string directly + ;; (caught by http-listener's string? guard, sent + ;; raw — no S-exp escape soup in the playground + ;; output). The structured fields all live inside + ;; the human text. + summary))))))))))) ;; Format a non-negative integer with thousand-separator commas. ;; (with-commas 100000000) → "100,000,000". @@ -1103,7 +1100,15 @@ ((string=? method "POST") (let* ((sexp (read-from-string body)) (resp (handle-request sexp)) - (resp-text (write-to-string resp))) + ;; Pre-formatted text responses (e.g. the bench's + ;; pretty summary) come back as a string; send raw + ;; so the browser sees clean multi-line text + ;; instead of an escape-quoted "\"...\\n...\"". + ;; Structured S-exp responses still get + ;; write-to-string. + (resp-text (cond + ((string? resp) resp) + (else (write-to-string resp))))) (write-http-response client 200 resp-text "text/plain; charset=utf-8") (tcp-close client))) diff --git a/wasm/app/demos/bend-gpu.lsp b/wasm/app/demos/bend-gpu.lsp index 98ede0e..564176a 100644 --- a/wasm/app/demos/bend-gpu.lsp +++ b/wasm/app/demos/bend-gpu.lsp @@ -12,29 +12,22 @@ ; on a single CPU core (libsecp256k1 ~50K keys/s) the same workload ; would take more than half an hour. ; -; The output panel shows the formatted result the worker built for -; us. read-from-string + assoc are portable across all three tiers -; so this same source file runs identically under asm / c / python. +; The bench op returns a pre-formatted multi-line string (the http +; listener detects string responses and ships them raw, no S-exp +; escape soup) so the playground output panel shows clean prose on +; every tier — asm / c / python all use the same demo source. (display ";; 1. probe round-trip ...") (newline) -(define r1 (bend!-call "(ping)")) -(display " (ping) → ") (display r1) (newline) +(display " (ping) → ") (display (bend!-call "(ping)")) (newline) (newline) (display ";; 2. worker telemetry ...") (newline) -(define r2 (bend!-call "(health)")) -(display " (health) → ") (display r2) (newline) +(display " (health) → ") (display (bend!-call "(health)")) (newline) (newline) -(display ";; 3. heavy GPU compute ...") (newline) -(display ";; sit tight — this is real math, not a mock") (newline) +(display ";; 3. heavy GPU compute — sit tight, this is real math") (newline) (newline) -(define r3 (bend!-call "(cuda-secp256k1-bench 100000000)")) -(define parsed (read-from-string r3)) -(define summary-pair (assoc 'summary (cdr parsed))) -(cond - ((pair? summary-pair) (display (car (cdr summary-pair))) (newline)) - (else (display "raw response: ") (display r3) (newline))) +(display (bend!-call "(cuda-secp256k1-bench 100000000)")) (newline) (newline) (print "(your laptop never did the math — it just watched it complete)") diff --git a/www/playground/demos/bend-gpu.lsp b/www/playground/demos/bend-gpu.lsp index 98ede0e..564176a 100644 --- a/www/playground/demos/bend-gpu.lsp +++ b/www/playground/demos/bend-gpu.lsp @@ -12,29 +12,22 @@ ; on a single CPU core (libsecp256k1 ~50K keys/s) the same workload ; would take more than half an hour. ; -; The output panel shows the formatted result the worker built for -; us. read-from-string + assoc are portable across all three tiers -; so this same source file runs identically under asm / c / python. +; The bench op returns a pre-formatted multi-line string (the http +; listener detects string responses and ships them raw, no S-exp +; escape soup) so the playground output panel shows clean prose on +; every tier — asm / c / python all use the same demo source. (display ";; 1. probe round-trip ...") (newline) -(define r1 (bend!-call "(ping)")) -(display " (ping) → ") (display r1) (newline) +(display " (ping) → ") (display (bend!-call "(ping)")) (newline) (newline) (display ";; 2. worker telemetry ...") (newline) -(define r2 (bend!-call "(health)")) -(display " (health) → ") (display r2) (newline) +(display " (health) → ") (display (bend!-call "(health)")) (newline) (newline) -(display ";; 3. heavy GPU compute ...") (newline) -(display ";; sit tight — this is real math, not a mock") (newline) +(display ";; 3. heavy GPU compute — sit tight, this is real math") (newline) (newline) -(define r3 (bend!-call "(cuda-secp256k1-bench 100000000)")) -(define parsed (read-from-string r3)) -(define summary-pair (assoc 'summary (cdr parsed))) -(cond - ((pair? summary-pair) (display (car (cdr summary-pair))) (newline)) - (else (display "raw response: ") (display r3) (newline))) +(display (bend!-call "(cuda-secp256k1-bench 100000000)")) (newline) (newline) (print "(your laptop never did the math — it just watched it complete)")