Typed decisions over any state in one forward pass. Jev-wire-compatible HTTP sidecar.
1.0K
Typed decisions over any state in one forward pass — an HTTP sidecar for the Laya decision engine (Apache-2.0, 27k★).
~0.2–0.6 s per decision · ~170 calls/min · CPU-only · stateless · Apache-2.0
Jev-wire-compatible — official TypeSafe Jev clients work against this service
by swapping the base URL and bearer token only (POST /v1/systemone, optional
model accepting jev-latest). Ceiling differences: choices ≤ 20 (Jev: 255),
state context ~1k tokens (Jev: 32k).
The service is stateless and policy-free: it only answers typed questions
(choice / score / noul) over any state you send. What to do with an answer —
auto-act, log, escalate — always lives in your caller.
Built and maintained by CodeCora — pragmatic AI infrastructure.
Prefer a slimmer stack? The same API also ships as a single Rust binary —
codecoradev/laya-service-rust: ~23 MB image, ~3–6 s model load, no Python/PyTorch, verified 15/15 wire parity with this service. You supply the ONNX checkpoint instead of the auto HF download.
docker run -d --name laya \
-p 8080:8080 \
-v laya-hf-cache:/data/hf \
--memory 4g \
codecoradev/laya-service:latest
Weights (~644 MB) download from Hugging Face on first start and are cached in the
volume. Watch readiness — status: "ok" means the model is loaded:
curl http://localhost:8080/healthz
First run downloads ~644 MB of weights from Hugging Face (~1–2 min on a decent
connection, then cached). Fresh named volumes work out of the box — the
image pre-creates /data/hf with correct ownership. Using a bind mount
instead? Pre-chown it to the service user (uid 999):
mkdir -p laya-hf && sudo chown -R 999:999 laya-hf # then -v "$PWD/laya-hf":/data/hf
A volume created by an older (pre-2026-10-05) image is root-owned; fix once
with docker volume rm laya-hf-cache (it just re-downloads) or chown it.
Environment: LAYA_CHECKPOINT (default multilingual), LAYA_DEVICE (default cpu),
AUTO_THRESHOLD (default 0.85). Multi-arch: amd64 + arm64.
Four equivalent endpoints, one contract: /v1/systemone (TypeSafe-canonical),
/api/v1/systemone, /api/v1/decide, /v1/decide (legacy).
curl -X POST http://localhost:8080/v1/systemone \
-H 'Content-Type: application/json' \
-d '{
"model": "jev-latest",
"state": {"body": "I was charged twice, refund now or I cancel!"},
"questions": {
"intent": {"type": "choice", "instructions": "What does the customer want?",
"criteria": {"refund": "money back", "technical": "bug", "shipping": "delivery"}},
"urgency": {"type": "score", "instructions": "How urgent?",
"criteria": ["routine", "soon", "critical"]},
"escalate": {"type": "noul", "instructions": "Needs a human now?"}
}
}'
model is optional — omit it (or send latest / jev-latest / jev-preview)
to use the preloaded checkpoint. Real response (2026-10-05, live):
{
"model": "multilingual",
"answers": {
"intent": {"type": "choice", "choice": "refund",
"probabilities": {"refund": 1.0, "technical": 0.0, "shipping": 0.0},
"confidence": 1.0},
"urgency": {"type": "score", "score": 1.92,
"legend": {"0": "routine", "1": "soon", "2": "critical"},
"probabilities": {"0": 0.005, "1": 0.065, "2": 0.93},
"confidence": 0.75},
"escalate": {"type": "noul", "noul": 0.46}
},
"usage": {"input_tokens": 123, "output_tokens": 0}
}
usage.input_tokens is a chars÷4 estimate; output_tokens is always 0 (the model
is non-autoregressive — no generated text).
| Type | criteria | Answer |
|---|---|---|
choice | object with 2–20 options | choice key + full probabilities + confidence |
score | array of 2–10 ordered levels | continuous score + legend + probabilities + confidence |
noul | optional {"false": …, "true": …} labels | noul probability 0–1 (0.5 = uncertain) |
state accepts a plain string, an email/ticket-like object, or a JSON document —
passed to the engine untouched. Keep it short: context is 1024 tokens (a ~2.5k-token
state takes ~17 s vs ~0.3 s at normal sizes).
| Route | Method | Notes |
|---|---|---|
/healthz | GET | Liveness (always "ok"; weights are loaded before serving) — open |
/v1/systemone | POST | TypeSafe Jev-canonical path |
/api/v1/systemone | POST | Same handler, fleet-style path |
/api/v1/decide | POST | Same handler, community-style path |
/v1/decide | POST | Legacy alias, same contract |
/docs, /redoc, /openapi.json | GET | FastAPI API browser |
Errors are Jev-style: {"error": "…", "detail": …}.
422 malformed body (missing state/questions, bad types — Jev parity) ·
400 semantically invalid (unknown model, wrong criteria shape) ·
401 wrong bearer (if you add auth) · 500 prediction failure ·
503 server busy (all run slots taken, queue full) with a Retry-After header: retry the same request.
| Metric | Value |
|---|---|
| Latency, CPU | 235–600 ms per call |
| Throughput | ~170 calls/min serial |
| RSS (multilingual, fp32) | ~2.1 GB |
| Cold start | container boot + weight load (first start adds the HF download) |
confidence is calibrated (RLCD) — treat it as meaningful. Sweet spots: CS/ticket
triage (intent + urgency + needs-human), event triage, spam/phishing gates, small
model routing. Not for: long-context reasoning, >20-way choices, content moderation.
| Tag | Meaning |
|---|---|
latest | most recent build |
develop | tracks the develop branch head |
2026-10-05a | dated, pin these for stable deployments |
Apache-2.0. Laya is Apache-2.0 by Convai Innovations — this service only wraps it.
Content type
Image
Digest
sha256:4cd132992…
Size
340.4 MB
Last updated
27 days ago
docker pull codecoradev/laya-service