"""deepseek-flash-openrouter-gb10: a tiny OpenAI-compatible chat server (stdlib only). POST /v1/chat/completions is forwarded to http://openrouter.ai/api/v1/chat/completions with the model forced to deepseek/deepseek-v4.1-flash. The request goes through the m64 gate (HTTP_PROXY, set by m64): the gate adds the OpenRouter key and sends it on over TLS, so the key never enters this container. Streaming responses (SSE) are relayed chunk by chunk as they arrive. GET /v1/models lists the one model; GET /health is 200. """ import json import os import sys import urllib.error import urllib.request from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer PORT = int(os.environ.get("M64_PORT", "9600")) UPSTREAM = "http://openrouter.ai/api/v1/chat/completions" # plain http: the gate does TLS UPSTREAM_MODEL = "deepseek/deepseek-v4.1-flash" PUBLIC_MODEL = "deepseek-v4.1-flash" MAX_BODY = 32 * 1024 * 1024 TIMEOUT_S = 900 # between two bytes from upstream (a long reasoning pause is fine) CHUNK = 16 * 1024 # urllib's ProxyHandler reads HTTP_PROXY from the environment: every call goes via the gate. OPENER = urllib.request.build_opener(urllib.request.ProxyHandler()) class Handler(BaseHTTPRequestHandler): protocol_version = "HTTP/1.1" server_version = "dsflash-capsule" def log_message(self, fmt, *args): # one short line per request on stderr (not /health) if self.path == "/health": return sys.stderr.write("%s %s\n" % (self.command, fmt % args)) def _json(self, status, obj): data = json.dumps(obj).encode() self.send_response(status) self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(data))) self.end_headers() self.wfile.write(data) def do_GET(self): if self.path == "/health": return self._json(200, {"status": "ok"}) if self.path == "/v1/models": return self._json(200, {"object": "list", "data": [ {"id": PUBLIC_MODEL, "object": "model", "created": 0, "owned_by": "openrouter", "upstream": UPSTREAM_MODEL}, ]}) return self._json(404, {"error": "not found"}) def do_POST(self): if self.path != "/v1/chat/completions": return self._json(404, {"error": "not found"}) try: length = int(self.headers.get("Content-Length") or 0) except ValueError: return self._json(400, {"error": "bad Content-Length"}) if length <= 0 or length > MAX_BODY: return self._json(400 if length <= 0 else 413, {"error": "body missing or too large"}) try: body = json.loads(self.rfile.read(length)) except ValueError: return self._json(400, {"error": "body must be JSON"}) if not isinstance(body, dict): return self._json(400, {"error": "body must be a JSON object"}) body["model"] = UPSTREAM_MODEL req = urllib.request.Request(UPSTREAM, data=json.dumps(body).encode(), method="POST", headers={ "Content-Type": "application/json", "Accept": "text/event-stream" if body.get("stream") is True else "application/json", "X-Title": "m64 deepseek-flash-openrouter-gb10", # No Authorization: the gate sets it (Bearer ) for openrouter.ai. }) try: resp = OPENER.open(req, timeout=TIMEOUT_S) except urllib.error.HTTPError as e: resp = e # relay OpenRouter's own error status and body except (urllib.error.URLError, OSError) as e: return self._json(502, {"error": f"upstream unreachable: {type(e).__name__}"}) with resp: self.send_response(resp.status if hasattr(resp, "status") else resp.code) self.send_header("Content-Type", resp.headers.get("Content-Type", "application/json")) self.send_header("Cache-Control", "no-cache") self.send_header("Transfer-Encoding", "chunked") self.end_headers() try: while True: # read1: whatever has arrived (up to CHUNK), without waiting to fill it. data = resp.read1(CHUNK) if hasattr(resp, "read1") else resp.read(CHUNK) if not data: break self.wfile.write(b"%x\r\n%s\r\n" % (len(data), data)) self.wfile.flush() self.wfile.write(b"0\r\n\r\n") except (BrokenPipeError, ConnectionResetError): self.close_connection = True def main(): server = ThreadingHTTPServer(("0.0.0.0", PORT), Handler) server.daemon_threads = True with open(os.environ["M64_STATUS"], "a") as f: f.write(json.dumps({"phase": "ready", "detail": f"forwarding to {UPSTREAM_MODEL}"}) + "\n") server.serve_forever() if __name__ == "__main__": main()