File size: 3,330 Bytes
c97f58a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from __future__ import annotations

import json
import os
import sys
from pathlib import Path
from typing import Any

import httpx
from fastapi import FastAPI
from pydantic import BaseModel, Field

ROOT = Path(__file__).resolve().parent
sys.path.insert(0, str(ROOT))

from escalation.patcher import repair  # noqa: E402
from harness.adapters import load  # noqa: E402
from harness.engine import run_harness  # noqa: E402

CONFIG: dict[str, Any] = json.loads((ROOT / "config.json").read_text(encoding="utf-8"))
ADAPTER = load(str(CONFIG.get("adapter") or "generic"))
SLM_URL = os.environ["MT_SLM_URL"]
ROUTER_URL = os.environ.get("MT_ROUTER_URL", "")
TOOLS_URL = os.environ["MT_TOOLS_URL"]
RELAY_URL = os.environ["MT_RELAY_URL"]
PREFERRED_MODEL = str((CONFIG.get("escalation") or {}).get("preferred_model") or "")

app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)


class HarnessIn(BaseModel):
    item_id: str
    task: dict[str, Any]


class RepairIn(BaseModel):
    item_id: str
    task: dict[str, Any]
    draft: Any = None
    trace: str = ""
    errors: str = ""
    ticket: str = ""


class SystemIn(BaseModel):
    item_id: str
    task: dict[str, Any]
    floor: float = Field(ge=0.0, le=1.0)
    ticket: str = ""


def decide(query: str, draft: str) -> float:
    if not ROUTER_URL:
        return 1.0
    with httpx.Client(timeout=30.0) as http:
        response = http.post(
            ROUTER_URL.rstrip("/") + "/decide", json={"input": {"query": query, "draft": draft}}
        )
    response.raise_for_status()
    answers = response.json().get("answers") or []
    return float(answers[0]["probability"]) if answers else 0.0


def _repair(payload: RepairIn | SystemIn, draft: Any, trace: str, errors: str) -> Any:
    return repair(
        payload.task,
        draft,
        trace,
        errors,
        adapter=ADAPTER,
        relay_url=RELAY_URL,
        ticket=payload.ticket,
        model=PREFERRED_MODEL,
    )


@app.get("/health")
def health() -> dict[str, str]:
    return {"status": "ok", "adapter": ADAPTER.name}


@app.post("/harness/run")
def harness_run(payload: HarnessIn) -> dict[str, Any]:
    result = run_harness(
        payload.task, adapter=ADAPTER, slm_url=SLM_URL, tools_url=TOOLS_URL, config=CONFIG
    )
    return {
        "answer": result.answer,
        "self_check": {"pass": result.verified},
        "trace": result.trace,
        "steps": result.steps,
    }


@app.post("/escalation/repair")
def escalation_repair(payload: RepairIn) -> dict[str, Any]:
    return {"answer": _repair(payload, payload.draft, payload.trace, payload.errors)}


@app.post("/system/run")
def system_run(payload: SystemIn) -> dict[str, Any]:
    result = run_harness(
        payload.task, adapter=ADAPTER, slm_url=SLM_URL, tools_url=TOOLS_URL, config=CONFIG
    )
    draft = result.answer
    probability = decide(ADAPTER.query(payload.task), ADAPTER.as_text(draft))
    if result.verified and probability >= payload.floor:
        return {"answer": draft, "route": "local", "p": probability}
    answer = _repair(payload, draft, result.trace, result.errors)
    return {"answer": answer, "route": "escalated", "p": probability}


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("MT_PORT", "8080")), log_level="warning")