959581f5a6
@coder: reactive worker on the shared harness; dspark (via gated proxy) generates Lua, writes to a sandbox, runs it as 'nobody' with a timeout, returns code+output. Verified a full 3-way chain: pipi (dspark, research-constrained) -> @callboy (fetch lua-users CsvUtils) -> @coder (write+run csvtest.lua) -> pipi saves ~/csvtest.lua & reports. dspark never self-implemented; the no-Lua-knowledge constraint forced delegation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
61 lines
2.6 KiB
Python
Executable File
61 lines
2.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""@coder — bullpen worker: turn a request into a Lua file, write it, run it, report.
|
|
Reactive. Engine = dspark via the gated proxy. It ONLY ever writes into its sandbox and
|
|
runs `lua5.4` there as an unprivileged user with a timeout — nothing else (mechanical bound).
|
|
bullpen-coder # room loop (systemd)
|
|
bullpen-coder --once "a lua function that reverses a string, with a self-test"
|
|
"""
|
|
import json, os, re, subprocess, sys, urllib.request
|
|
sys.path.insert(0, "/usr/local/lib/bullpen")
|
|
import bullpen_worker as bw
|
|
|
|
SANDBOX = "/var/lib/bullpen/coder"
|
|
ENGINE = "http://hossenfelder.fritz.box:8082/v1/chat/completions" # gated proxy (gate+failover)
|
|
MODEL = "deepseek-v4-flash-dspark"
|
|
MAXBODY = 1400
|
|
|
|
SYS = ("You are a Lua coder. Given a task and any reference material, output ONLY valid Lua "
|
|
"source that solves it AND includes a small self-test with sample data printed to stdout. "
|
|
"No markdown, no prose, no code fences — just the Lua.")
|
|
|
|
def gen_code(request):
|
|
payload = json.dumps({"model": MODEL,
|
|
"messages": [{"role": "system", "content": SYS}, {"role": "user", "content": request}],
|
|
"temperature": 0.2, "max_tokens": 1400}).encode()
|
|
req = urllib.request.Request(ENGINE, payload, {"Content-Type": "application/json"})
|
|
with urllib.request.urlopen(req, timeout=200) as r:
|
|
txt = json.load(r)["choices"][0]["message"]["content"]
|
|
m = re.search(r"```(?:lua)?\s*(.*?)```", txt, re.S) # strip fences if the model adds them
|
|
return (m.group(1) if m else txt).strip()
|
|
|
|
def run_lua(path):
|
|
os.chmod(path, 0o644)
|
|
r = subprocess.run(
|
|
["timeout", "10", "su", "-s", "/bin/sh", "nobody", "-c", f"cd {SANDBOX} && lua5.4 {path}"],
|
|
capture_output=True, text=True)
|
|
out = r.stdout.strip()
|
|
if r.stderr.strip():
|
|
out += ("\n[stderr] " + r.stderr.strip())
|
|
return out.strip(), r.returncode
|
|
|
|
def dispatch(msg):
|
|
req, rid = msg.get("body", ""), msg.get("id")
|
|
os.makedirs(SANDBOX, exist_ok=True)
|
|
try:
|
|
code = gen_code(req)
|
|
except Exception as e:
|
|
return f"codegen error: {e}"
|
|
path = f"{SANDBOX}/job{rid}.lua"
|
|
open(path, "w").write(code + "\n")
|
|
out, rc = run_lua(path)
|
|
status = "ran OK" if rc == 0 else f"exit {rc}"
|
|
body = f"wrote {path} ({len(code)} chars) — {status}. output:\n{out[:400]}\n--- code ---\n{code}"
|
|
return body
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) > 2 and sys.argv[1] == "--once":
|
|
print(dispatch({"body": sys.argv[2], "id": 0}))
|
|
else:
|
|
bw.run("coder", dispatch, online="coder online — writes+runs Lua (sandboxed). @coder <task>",
|
|
ack="…coding")
|