File size: 2,512 Bytes
76d666a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Test UI + API for the union command agent.  python ui/app.py  ->  http://localhost:8000
Model (numpy runtime) -> executor plan (dry-run by default) -> optional execution with risk gating."""
import json, os, sys, platform as _pf
HERE = os.path.dirname(os.path.abspath(__file__)); ROOT = os.path.dirname(HERE)
sys.path.insert(0, os.path.join(ROOT, "model")); sys.path.insert(0, os.path.join(ROOT, "executor"))
from fastapi import FastAPI  # noqa
from fastapi.responses import HTMLResponse, JSONResponse  # noqa
from pydantic import BaseModel  # noqa
from runtime import CommandModel  # noqa
import executor as EX  # noqa

MODEL = CommandModel(os.path.join(ROOT, "model"))
CAT = EX.CATALOG
app = FastAPI(title="union command agent")

class Req(BaseModel):
    text: str; platform: str = "auto"; execute: bool = False; allow_caution: bool = False; confirm: str = ""
class Batch(BaseModel):
    texts: list; platform: str = "auto"

def _plat(p): return EX.platform_name() if p in ("auto", "", None) else ("win" if p.startswith("win") else "pi")

def handle(text, platform="auto", execute=False, allow_caution=False, confirm=""):
    plat = _plat(platform); out = MODEL.predict(text); cmd = {k: v for k, v in out.items() if k != "_meta"}
    p = EX.plan(cmd, plat, text); ok, why = EX.gate(p, allow_caution, confirm or None)
    res = {"text": text, "platform": plat, "model": cmd, "meta": out["_meta"], "plan": p.to_dict(), "gate": {"ok": ok, "reason": why}, "spec": CAT.get(cmd["action"], {}), "run": None}
    if execute:
        res["run"] = EX.run(p, cmd, dry_run=False) if ok else {"status": "blocked", "output": why, "command": p.command}
    return res

@app.get("/", response_class=HTMLResponse)
def index(): return open(os.path.join(HERE, "static", "index.html"), encoding="utf-8").read()
@app.get("/api/info")
def info(): return {"actions": len(CAT), "host": _pf.node(), "os": _pf.system(), "platform": EX.platform_name(), "model_params": int(sum(v.size for v in MODEL.W.values()))}
@app.get("/api/prompts")
def prompts(): return json.load(open(os.path.join(HERE, "prompts.json"), encoding="utf-8"))
@app.get("/api/catalog")
def catalog(): return CAT
@app.post("/api/predict")
def predict(r: Req): return handle(r.text, r.platform, r.execute, r.allow_caution, r.confirm)
@app.post("/api/batch")
def batch(b: Batch): return [handle(t, b.platform) for t in b.texts if t.strip()]

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=int(os.environ.get("PORT", 8000)))