Skip to main content
Version: Next

TypeSafe Models

TypeSafe Jev is a decision model, not a chat model. It takes unstructured input and a set of typed questions, and returns a structured answer to each question with calibrated probabilities. Spice serves TypeSafe models through the SQL decision functions (ai_if, ai_probability, ai_classify, ai_score, and ai_decide) and the POST /v1/decisions endpoint. They cannot be used with /v1/chat/completions or /v1/responses.

Chat models answer decisions too, with uncalibrated probabilities. See Decisions.

Configuration​

Specify typesafe:<model> in the from field and provide a TypeSafe API key.

models:
- from: typesafe:jev
name: jev
params:
typesafe_api_key: ${secrets:TYPESAFE_API_KEY}

The model after typesafe: is sent to TypeSafe as follows:

fromTypeSafe model
typesafe:jevjev-latest
typesafejev-latest
typesafe:jev-latestjev-latest
typesafe:jev-previewjev-preview
typesafe:jev-1.13.0jev-1.13.0 (version pin)

typesafe/jev is accepted as an alternative spelling of typesafe:jev.

ParamDescriptionDefault
typesafe_api_keyThe TypeSafe API key. typesafe_ai_api_key is accepted as an alias.-
typesafe_endpointThe TypeSafe API base URL.https://api.typesafe.ai
max_concurrencyMaximum number of concurrent requests to this model.Provider default
requests_per_minute_limitMaximum requests per minute to this model.Provider default

When typesafe_api_key is not set, Spice loads the key from the TYPESAFE_API_KEY secret, and then from TYPESAFE_AI_API_KEY. If neither is found, the model fails to load.

Load-time check​

When the model loads, Spice lists the models available to the API key. The model fails to load if the key is rejected, or if the configured model is not offered to the account. A version pin such as typesafe:jev-1.13.0 skips the offered-model check, but still requires a valid key. For example, an invalid key fails with:

Failed to load LLM: jev. Evaluation health check failed: HTTP 401 Unauthorized: {"detail":{"error_type":"authentication_error","message":"Cannot authenticate with the server. Please check your API key and try again."}}

Decisions​

Name the model in a SQL decision function with model => 'jev', or omit model when the TypeSafe model is the only decision model in the Spicepod:

SELECT id FROM tickets WHERE ai_if(body, 'Does this convey urgency?', model => 'jev');

Or send a request to POST /v1/decisions with the model name, the input, and a list of questions:

curl -X POST http://localhost:8090/v1/decisions \
-H 'Content-Type: application/json' \
-d '{
"model": "jev",
"input": "Help! My payouts have been failing for 3 days.",
"questions": [
{"type": "predicate", "name": "urgent", "instructions": "Does this convey urgency?"}
]
}'

The response carries model, the model version that answered, and answers, one per question in question order. The question types, answer fields, ai_decide result, and error status codes are described in Decisions.

In ai_decide, which uses TypeSafe's question grammar, instructions and the noul and choice criteria descriptions accept a string, an object, an array, or null. A score question's criteria is different: it is a list of 2 to 10 levels and every level must be non-null, so a null level is rejected. See the TypeSafe documentation for structured instructions and the API reference.

TypeSafe models do not take reasoning_effort: a /v1/decisions request that sets it for a TypeSafe model returns 400 with code unsupported_parameter.

A request to /v1/chat/completions that names a TypeSafe model returns 400 and directs the caller to /v1/decisions.

Decision requests are recorded in runtime.task_history as ai_decision tasks (POST /v1/decisions) or ai_decide tasks (SQL), and are counted in the same model request, duration, and token metrics as chat requests, labeled by model.