TypeSafe compatibility
TypeSafe's closed Jev model created the "System One" category of decision models. Ollaya's /v1/* API is wire-identical to TypeSafe's, as defined by the wire schema and error handling of typesafe-sdk 0.7.1, so code written for TypeSafe runs against open models on your own machine.
Point the SDK at Ollaya
The official TypeSafe Python SDK 0.7.1 works unchanged. Set these environment variables:
export TYPESAFE_BASE_URL=http://localhost:11435
export TYPESAFE_API_KEY=local # the SDK needs a non-empty key; any value works
export TYPESAFE_DEFAULT_MODEL=winnow:e4b # otherwise the SDK sends its default, "jev-latest"
export NO_PROXY=localhost,127.0.0.1 # keep local requests off any system proxy- Default model.
winnow:e4bis the recommended model. It scores 0.724 on typed decisions, against the 0.738 TypeSafe reports for Jev and within a few thousandths of the best open models, and answers five questions in 113 ms on an RTX 5090. Without an NVIDIA GPU, uselaya, which answers in a fraction of a second on a CPU. - API key. Ollaya accepts any key, unless the server sets
OLLAYA_API_KEY; then the SDK's key must match it. - Request IDs. Every response carries
x-typesafe-request-id, soresponse.request_idworks. - Retries. The SDK times out after 10 s and retries. The first request to a model waits while it loads, and a load that outlives the request continues, so the retry finds the model warm.
- System proxies. On a Mac with a system HTTP proxy, the TypeSafe SDK (like
httpx) sends requests forlocalhostthrough the proxy too, ignoring the system's exception list. Your states then pass through the proxy, and while Ollaya is down the SDK reports502 status code (no body)instead of a refused connection. SetNO_PROXY=localhost,127.0.0.1next toTYPESAFE_BASE_URL. - Warm-up and timings. To load a model before the first request, send
{"model": "winnow:e4b", "keep_alive": -1}to/api/decide(nostate)./v1/*responses carry no timings, as TypeSafe's don't;/api/decidereportstotal_duration,load_durationandeval_duration.
Libraries
Libraries that reach Ollaya through this API. To add one, open a pull request with a line here: its link, what it does and how it reaches Ollaya.
- gut (Python). Judgment calls as one line of code:
gut.likely(text, "is spam"),gut.classifyandgut.rateanswer YES, NO or UNSURE.gut.JevBackend.ollaya("winnow:e4b")asks Ollaya through the TypeSafe SDK and readsOLLAYA_HOSTandOLLAYA_API_KEY. Install withpip install "gutfeel[jev]"; see its Ollaya notes. - LiteLLM (Python, and its proxy).
litellm.systemoneandlitellm.decisionswith thetypesafe/provider, and a guardrail that drops stale tool results before an LLM call. It reaches Ollaya throughapi_baseorTYPESAFE_API_BASE; see Integrations. - LangChain (Python and JS).
TypeSafeClassifier, a runnable, plus experimental agent middleware that routes between models and blocks risky tool calls. It reaches Ollaya throughbase_url/baseUrlorTYPESAFE_BASE_URL; see Integrations. - Vercel AI SDK (TypeScript).
@ai-sdk/typesafe-ai, decision models forexperimental_decide. It reaches Ollaya throughbaseURLorTYPESAFE_AI_BASE_URL, ending in/v1; see Integrations. - DSPy (Python).
Choice,NoulandScoreoutput fields for signatures, answered bydspy.experimental.TypeSafe. It reaches Ollaya throughbase_urlorTYPESAFE_BASE_URL; see Integrations. - llama-index-jev (Python, community). A LlamaIndex reranker and router selector. It reaches Ollaya through
TYPESAFE_BASE_URL; see Integrations.
Endpoints
| Endpoint | Description |
|---|---|
POST /v1/systemone | Decide. Request: model, state (required) and questions. Response: exactly model, answers and usage. |
POST /v1/decisions | Alias of /v1/systemone |
GET /v1/models | The models on this machine: name, description, release_date |
Request and response
curl http://localhost:11435/v1/systemone \
-H "Authorization: Bearer local" \
-d '{
"model": "laya",
"state": "Can I get an invoice for last month?",
"questions": {
"intent": {
"type": "choice",
"instructions": "What does the customer want?",
"criteria": {
"invoice": "Needs an invoice or receipt",
"refund": "Wants money back",
"other": "Anything else"
}
}
}
}'{
"model": "laya:en",
"answers": {
"intent": {
"type": "choice",
"choice": "invoice",
"confidence": 0.9547,
"probabilities": {"invoice": 0.9698, "refund": 0.0172, "other": 0.013}
}
},
"usage": {"input_tokens": 43, "output_tokens": 0}
}model in the response is the checkpoint that answered: laya is a router, and this English request went to laya:en. TypeSafe's schema allows this ("may differ from the alias supplied in the request"). Values have 4 decimals, and probabilities follow the order of criteria.
curl http://localhost:11435/v1/models -H "Authorization: Bearer local"{
"models": [
{
"name": "laya:en",
"description": "English decision model (ModernBERT-large): guardrails, email and ticket triage.",
"release_date": "2026-09-23"
},
{
"name": "laya:latest",
"description": "Routes each request to laya:en or laya:multilingual by the text's script and language.",
"release_date": "2026-09-23"
},
{
"name": "laya:multilingual",
"description": "Decision model for 100+ languages (mmBERT-base).",
"release_date": "2026-09-23"
}
]
}/v1/models lists the models pulled to this machine, routers included; it doesn't list the registry.
Errors
Errors carry TypeSafe's status codes, and a body the SDK reads correctly: a string error (which the SDK shows), a machine-readable code, and on 422 TypeSafe's detail list of validation issues. See errors for every code.
{"error": "model \"jev-latest:latest\" not found, try pulling it first", "code": "MODEL_NOT_FOUND"}What is different
Compatibility covers the API, not the model:
- Model names are Ollaya's (
laya,laya:en), so setTYPESAFE_DEFAULT_MODELor passmodel. - Missing
instructions. When a question has none, the model reads the question id in its place, so name questions descriptively (is_urgent,tone). - Limits. At most 256 questions per request, 2–255 choices and 2–10 score levels. Each model also has an option budget: about 125 options for
laya:en, 250 forlaya:multilingual. - Long states. TypeSafe reads up to 65,536 tokens; an open model's context is shorter (512 tokens for
laya:en, 1,024 forlaya:multilingual, including the questions). When a state doesn't fit,/v1/*returns422 STATE_TRUNCATEDrather than answering from part of it. Use a model with a longer context, shorten the state, or call/api/decide, which truncates and reportsstate_truncated. /v1/*stays pure. Native fields such askeep_aliveandextrasare ignored there; routing, timings and truncation are reported on/api/decide.- Quality comes from open models, so it differs from Jev's by task:
laya:typed-decisions, which trains on this dataset, scores 0.767 on typed-decisions, against the 0.738 TypeSafe reports for Jev.- The base Laya checkpoints are near chance zero-shot on typed-decisions (0.357 for
laya:en). - Choice questions with many options (more than ~20) are weaker: 0.425 on Banking77, against 0.870 for Jev.
Measure on your own data before switching production traffic. The Laya page has the details.
Not affiliated
Ollaya is an independent open-source project. It is not affiliated with or endorsed by TypeSafe.