Docs / Decision models
Decision models
A decision model answers typed questions about a piece of text or JSON. It picks one option, scores on a scale, or answers yes or no, with a probability for every option. It does not generate text. The first one in the catalog is Laya, an open model under the Apache-2.0 licence. In the dashboard these are listed as RLCD.
Laya runs in your own cloud account, like every deployment, behind one HTTPS endpoint with its own keys. The endpoint speaks a TypeSafe-compatible API, so the TypeSafe Python and JavaScript clients work with it.
What ships
One pinned download (1.7 GB) with two checkpoints that both stay loaded on one GPU:
- English: the general checkpoint. The model name
layauses it. - Typed decisions: a specialist for agent traces,
customer service, invoices and security incidents. Send
laya-typed-decisionsto use it. Automatic routing never picks it on its own.
Laya answers English only. A request in another language gets a clear error instead of a poor answer.
Deploy it
- Start a new deployment and choose RLCD on the first step, then Laya.
- Pick the hardware. Laya needs one GPU with 8 GB or more.
- Set the budget cap and deletion timer, and a schedule if you want one.
- Review the summary and confirm. The summary lists the engine, the API, the routing policy and both checkpoints.
| Provider | Hardware | Status |
|---|---|---|
| RunPod | 1 × L4 24 GB | Deployed and tested end to end on 2026-09-25 |
| AWS | g6.xlarge, 1 × L4 24 GB | Offered, not yet booted by us |
| Verda | 1 × A100 80 GB, FIN-03 | Offered, not yet booted by us |
Decision models run on-demand on the node-local gateway. Weight staging, spot capacity, edge gateways and idle auto-stop are not available for them yet. Stop them with the deletion timer, the budget cap, a schedule, or the Stop button.
Call it
The base URL is the endpoint itself, without /v1: the
clients add /v1/systemone. The deployment's Connect tab shows
these snippets filled in with your endpoint and key.
curl
curl https://abc12345.gw.llmhangar.com/v1/systemone \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "laya",
"state": {"message": "My account was charged twice. Please refund it."},
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should handle this request?",
"criteria": {"billing": "Payments and refunds", "support": "Product help"}
},
"urgency": {
"type": "score",
"instructions": "How urgently does this need attention?",
"criteria": ["Routine", "Soon", "Immediate"]
},
"refund_requested": {
"type": "noul",
"instructions": "Does the customer request a refund?"
}
}
}'
Python
pip install typesafe-sdk
import typesafe_sdk as ts
client = ts.TypeSafeClient(
api_key="YOUR_API_KEY",
base_url="https://abc12345.gw.llmhangar.com",
)
result = client.system_one(
{"message": "My account was charged twice. Please refund it."},
{
"team": {
"type": "choice",
"instructions": "Which team should handle this request?",
"criteria": {"billing": "Payments and refunds", "support": "Product help"},
},
"refund_requested": {
"type": "noul",
"instructions": "Does the customer request a refund?",
},
},
model="laya",
)
print(result.choices["team"].choice)
print(result.nouls["refund_requested"].noul)
JavaScript
npm i @typesafe-ai/sdk
import { TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient({
apiKey: "YOUR_API_KEY",
baseURL: "https://abc12345.gw.llmhangar.com",
});
const result = await client.systemOne({
model: "laya",
state: { message: "My account was charged twice. Please refund it." },
questions: {
refund_requested: { type: "noul", instructions: "Does the customer request a refund?" },
},
});
console.log(result.answers.refund_requested.noul);
Environment variables
Both clients read these, so the code above needs no arguments once they are set:
export TYPESAFE_BASE_URL="https://abc12345.gw.llmhangar.com"
export TYPESAFE_API_KEY="YOUR_API_KEY"
export TYPESAFE_DEFAULT_MODEL="laya"
Requests and answers
- State is a string, a JSON object or a JSON array. An array is one state, not a batch.
- Questions are named, and every answer comes back under the same name. One request can mix all three types.
- choice takes a map of option names to descriptions and returns the chosen option, a probability for every option and a confidence.
- score takes an ordered list of levels, lowest first, and returns the probability-weighted level, a probability per level, the legend and a confidence.
- noul is a yes or no question. It returns the
probability of yes, and optional
trueandfalsecriteria describe what counts as each. - A choice with one option, or a score with one level, is answered with probability 1 without running the model.
- The response's
modelnames the checkpoint that answered, for examplelaya-english@55cf4c4e. usage.input_tokenscounts the tokens of every question row, with the state counted once per question. Output tokens are always 0.
Confidence for choice and score is
(k × p_max − 1) / (k − 1) over k
options, and 1 for a single option. It reproduces the confidence examples
in TypeSafe's public documentation, but TypeSafe does not publish its
formula, so treat it as an approximation. Treat every probability as the
model's estimate, not a calibrated likelihood: check it against your own
examples before you rely on a threshold.
Model names
| Name | Answers with |
|---|---|
laya | Automatic routing: the English checkpoint |
laya-english | The English checkpoint |
laya-typed-decisions | The typed-decisions specialist |
convaiinnovations/laya | Same as laya |
convaiinnovations/laya-typed-decisions | Same as laya-typed-decisions |
GET /v1/models lists these names.
Limits
- English only. Every request passes a language check on the state first, whatever the model name. A state in another language gets a 422. The check is a heuristic: short or ambiguous text in a Latin-script language can pass as English, and the English checkpoint will answer it.
- Short inputs. The state can be about 300 tokens on the English checkpoint and about 750 on the specialist, and each choice option up to 48 tokens. A request that would not fit is refused with a 422 naming the part to shorten. Nothing is cut silently.
- Up to 64 questions per request, and 1 MB of request body.
Errors
| Status | When |
|---|---|
| 401 | No key, or a key this deployment does not accept |
| 404 | Any path other than POST /v1/systemone and GET /v1/models |
| 413 | A body over 1 MB |
| 422 | A request that does not validate, an unknown model name, a language other than English, or an input over the limits. detail lists every problem with its location. |
| 503 | The service is starting or stopping, or its GPU failed. Retry after the Retry-After seconds. |
| 529 | Too many requests are queued. Retry after the Retry-After seconds. |
Every response carries an x-request-id header. Quote it
when you ask us about a request.
Health
LLM Hangar checks the running service every minute. If its GPU fails, the service stops answering (503) and restarts. If it keeps failing after a few minutes of retries, the deployment is stopped and held, so a schedule cannot start it again. The deployment page then offers Retry runtime.
Measured
- On one NVIDIA L4: 95% of evaluation requests answered within about 60 ms, with about 4 GB of GPU memory and 4 GB of host memory in use.
- On RunPod: ready 1 minute 50 seconds after confirming, including the download. A resume onto new compute was ready in 45 seconds.
- Rates we last checked: RunPod Secure Cloud L4 $0.49/hr (2026-09-25), AWS g6.xlarge $0.805/hr on-demand in us-east-1, and Verda A100 80 GB $1.79/hr at list price. Your provider sets the rate and bills you directly.
Before we release a Laya image we check its accuracy against fixed question sets: 0.875 on 48 hand-written English questions and 0.882 on 306 questions from the typed-decisions test split. These are regression checks, not a quality claim for your data.