Spaces:
Running
Running
File size: 8,503 Bytes
57bd44d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | """ViKernel Desktop Space server: serves the static desktop and proxies /api/ag/* server-side
to a private Agent Guard backend. Backend credentials live in Space secrets and never reach the browser."""
import json, os, time, urllib.error, urllib.request
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
BACKEND = os.environ.get("BACKEND_URL", "").rstrip("/")
BACKEND2 = os.environ.get("BACKEND2_URL", "").rstrip("/") # in-weights graft backend (GPU)
HF_AUTH = os.environ.get("BACKEND_HF_TOKEN", "")
BK_TOKEN = os.environ.get("BACKEND_TOKEN", "")
RATE = int(os.environ.get("RATE_PER_10MIN", "20"))
TIMEOUT = float(os.environ.get("BACKEND_TIMEOUT", "300"))
GET_OK = {"gpu/job", "health", "status", "audit", "store/catalog", "browser/img", "browser/res"}
POST_OK = {"chat", "scenario", "kill", "resume", "tamper", "reset", "store/submit", "store/publish", "store/app", "store/install", "gate/decide", "vmask", "game/hint", "game/cheat", "browser/open", "browser/agent", "browser/snap", "browser/policy", "settings/get", "settings/revoke", "settings/grant", "settings/egress", "settings/policy", "settings/locked", "rsi/state", "rsi/propose", "rsi/apply", "rsi/rollback", "rsi/reset", "ztc/status", "ztc/judge", "ztc/run", "backdoor/run", "backdoor/scan", "backdoor/wake", "gpu", "gpu/all", "session/start"}
STATIC = {"warm.js", "tour.js", "index.html", "app.js", "ag.js", "store.js", "common.js", "display.js", "terminal.js", "mines.js", "browser.js", "settings.js", "live_apps.js", "game.js", "rsi.js", "gpulab.js", "ztc.js", "backdoor.js", "backdoor.css", "backdoor_metrics.json", "downloads/vdrpack.py", "demo/poisoned-page", "samples/weather-plus.vdr", "samples/weather-plus-tampered.vdr", "i18n.js", "demo_data.js", "styles.css", "ag_replay.json"}
HITS = {}
BACKEND2_SPACE = os.environ.get("BACKEND2_SPACE", "SeaWolf-AI/vk-ag-graft")
RT = {"t": 0, "v": None}
def space_stage():
"""Hub runtime stage of the in-weights backend Space (cached 10 s). Read only; it never wakes or changes the Space."""
if time.time() - RT["t"] < 10:
return RT["v"]
v = None
try:
req = urllib.request.Request("https://huggingface.co/api/spaces/" + BACKEND2_SPACE + "/runtime",
headers={"Authorization": "Bearer " + HF_AUTH} if HF_AUTH else {})
with urllib.request.urlopen(req, timeout=5) as r:
v = json.loads(r.read()).get("stage")
except Exception: # noqa: BLE001
v = None
RT.update(t=time.time(), v=v)
return v
def waking(stage):
pct, label = {"SLEEPING": (1, "the in-weights model is asleep; waking it now"),
"BUILDING": (3, "building the server"), "APP_STARTING": (6, "starting the server"),
"RUNNING_APP_STARTING": (6, "starting the server"), "RUNNING": (8, "starting the server")}.get(stage or "", (2, "waking the in-weights model"))
return {"ok": False, "live": False, "loading": {"stage": (stage or "waking").lower(), "pct": pct, "label": label, "eta_s": 240}}
def limited(ip):
now = time.time()
h = [x for x in HITS.get(ip, []) if now - x < 600]
full = len(h) >= RATE
if not full:
h.append(now)
HITS[ip] = h
if len(HITS) > 5000:
HITS.clear()
return full
class H(SimpleHTTPRequestHandler):
def _json(self, code, obj):
b = json.dumps(obj).encode()
self.send_response(code); self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(b))); self.send_header("Cache-Control", "no-store"); self.end_headers(); self.wfile.write(b)
def _proxy(self, name, body=None, base=None, query=""):
if base and base == BACKEND2 and name == "health":
return self._health2(h=None)
base = base or BACKEND
if not base:
return self._json(503, {"error": "backend not configured"})
h = {"Content-Type": "application/json", "X-Backend-Token": BK_TOKEN, "X-VK-Session": (self.headers.get("X-VK-Session") or "")[:60]}
if HF_AUTH:
h["Authorization"] = "Bearer " + HF_AUTH
req = urllib.request.Request(base + "/api/" + name + query, data=body, headers=h, method="POST" if body is not None else "GET")
try:
with urllib.request.urlopen(req, timeout=8 if name == "health" else TIMEOUT) as r:
data, code = r.read(), r.status
if name in ("browser/img", "browser/res") and code == 200:
self.send_response(200); self.send_header("Content-Type", r.headers.get("Content-Type", "application/octet-stream"))
self.send_header("Content-Length", str(len(data))); self.send_header("Cache-Control", "max-age=600"); self.end_headers(); self.wfile.write(data)
return
if not data.lstrip().startswith(b"{"):
return self._json(503, {"error": "backend starting"})
self.send_response(code); self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data))); self.send_header("Cache-Control", "no-store"); self.end_headers(); self.wfile.write(data)
except urllib.error.HTTPError as e:
self._json(503 if e.code >= 500 or e.code in (401, 403, 404) else e.code, {"error": "backend unavailable"})
except Exception: # noqa: BLE001
self._json(503, {"error": "backend unavailable"})
def _health2(self, h=None):
hd = {"X-Backend-Token": BK_TOKEN}
if HF_AUTH:
hd["Authorization"] = "Bearer " + HF_AUTH
try:
with urllib.request.urlopen(urllib.request.Request(BACKEND2 + "/api/health", headers=hd), timeout=8) as r:
data = r.read()
if data.lstrip().startswith(b"{"):
return self._json(200, json.loads(data))
except Exception: # noqa: BLE001
pass
return self._json(200, waking(space_stage()))
def do_GET(self):
p = self.path.split("?")[0]
if p.startswith("/api/ag/") or p.startswith("/api/agx/"):
x = p.startswith("/api/agx/")
name = p[9:] if x else p[8:]
q = ("?" + self.path.split("?", 1)[1]) if (name in ("browser/img", "browser/res") and "?" in self.path) else ""
return self._proxy(name, base=BACKEND2 if x else None, query=q) if name in GET_OK else self._json(404, {"error": "not found"})
f = "index.html" if p == "/" else p.lstrip("/")
if f == "demo/poisoned-page":
b = open("demo_poisoned_page.html", "rb").read()
self.send_response(200); self.send_header("Content-Type", "text/html; charset=utf-8"); self.send_header("Content-Length", str(len(b))); self.end_headers(); self.wfile.write(b)
return
if f not in STATIC:
return self._json(404, {"error": "not found"})
self.path = "/" + f
return super().do_GET()
def do_POST(self):
p = self.path.split("?")[0]
x = p.startswith("/api/agx/")
name = p[9:] if x else (p[8:] if p.startswith("/api/ag/") else "")
if name not in POST_OK:
return self._json(404, {"error": "not found"})
ip = (self.headers.get("X-Forwarded-For") or self.client_address[0]).split(",")[0].strip()
if limited(ip):
return self._json(429, {"error": "rate limit"})
n = int(self.headers.get("Content-Length", 0) or 0)
if n > (700000 if name == "store/submit" else 4096):
return self._json(413, {"error": "too large"})
try:
req = json.loads(self.rfile.read(n) or b"{}")
except ValueError:
return self._json(400, {"error": "bad json"})
if "message" in req:
req["message"] = str(req["message"])[:500]
if x and not BACKEND2:
return self._json(503, {"error": "in-weights backend not configured"})
if x and name in ("kill", "resume"):
x = False # visitor KILL/RESUME is per session; the in-weights kernel is never halted globally by a visitor
self._proxy(name, json.dumps(req).encode(), base=BACKEND2 if x else None)
def end_headers(self):
self.send_header("X-Content-Type-Options", "nosniff")
super().end_headers()
def log_message(self, *a):
pass
if __name__ == "__main__":
os.chdir(os.path.dirname(os.path.abspath(__file__)))
ThreadingHTTPServer(("0.0.0.0", int(os.environ.get("PORT", "7860"))), H).serve_forever()
|