Skip to content

JEV Decisions (TypeSafe)

JEV is TypeSafe's decision model. You give it a piece of context (state) and a set of typed questions (questions), and a single call returns structured answers: every answer comes with a probability distribution instead of free-form text you have to parse yourself. It suits judgment and classification work such as ticket routing, intent detection, content moderation, and sentiment scoring.

Create a decision

POST https://ciyuanx.io/inference/jev/api/alpha/decisions

Note

This endpoint does not live under the /v1 compatibility layer, and its request body differs from Chat Completions, so you cannot call it with the OpenAI SDK — send a plain HTTP request as shown below. The alpha in the path means the API is still early and fields may change.

bash
curl https://ciyuanx.io/inference/jev/api/alpha/decisions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "jev",
    "state": "Help! My payouts have been failing for 3 days.",
    "questions": {
      "is_urgent": {
        "type": "noul",
        "instructions": "Does this message convey urgency?",
        "criteria": {
          "true": "Explicitly time-sensitive",
          "false": "No urgency expressed"
        }
      },
      "department": {
        "type": "choice",
        "instructions": "Which team should handle this?",
        "criteria": {
          "billing": "Payments, invoicing, refunds",
          "technical": "Bugs, outages, integrations",
          "sales": "Pricing, upgrades, new accounts"
        }
      },
      "frustration": {
        "type": "score",
        "instructions": "How frustrated is the customer?",
        "criteria": ["Calm", "Frustrated", "Very angry"]
      }
    }
  }'
python
import requests

response = requests.post(
    "https://ciyuanx.io/inference/jev/api/alpha/decisions",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer YOUR_API_KEY",
    },
    json={
        "model": "jev",
        "state": "Help! My payouts have been failing for 3 days.",
        "questions": {
            "is_urgent": {
                "type": "noul",
                "instructions": "Does this message convey urgency?",
                "criteria": {
                    "true": "Explicitly time-sensitive",
                    "false": "No urgency expressed",
                },
            },
            "department": {
                "type": "choice",
                "instructions": "Which team should handle this?",
                "criteria": {
                    "billing": "Payments, invoicing, refunds",
                    "technical": "Bugs, outages, integrations",
                    "sales": "Pricing, upgrades, new accounts",
                },
            },
            "frustration": {
                "type": "score",
                "instructions": "How frustrated is the customer?",
                "criteria": ["Calm", "Frustrated", "Very angry"],
            },
        },
    },
)

answers = response.json()["answers"]
print(answers["department"]["choice"])  # billing
print(answers["frustration"]["score"])  # 1.04
print(answers["is_urgent"]["noul"])     # 0.95
typescript
const response = await fetch(
  "https://ciyuanx.io/inference/jev/api/alpha/decisions",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer YOUR_API_KEY",
    },
    body: JSON.stringify({
      model: "jev",
      state: "Help! My payouts have been failing for 3 days.",
      questions: {
        is_urgent: {
          type: "noul",
          instructions: "Does this message convey urgency?",
          criteria: {
            true: "Explicitly time-sensitive",
            false: "No urgency expressed",
          },
        },
        department: {
          type: "choice",
          instructions: "Which team should handle this?",
          criteria: {
            billing: "Payments, invoicing, refunds",
            technical: "Bugs, outages, integrations",
            sales: "Pricing, upgrades, new accounts",
          },
        },
        frustration: {
          type: "score",
          instructions: "How frustrated is the customer?",
          criteria: ["Calm", "Frustrated", "Very angry"],
        },
      },
    }),
  },
);

const { answers } = await response.json();
console.log(answers.department.choice); // billing
console.log(answers.frustration.score); // 1.04
console.log(answers.is_urgent.noul); // 0.95

Request parameters

ParameterTypeRequiredDescription
modelstringYesModel ID; use jev. The response reports the exact version that served the request
statestringYesThe context to judge, such as a user message, an email, or a conversation transcript
questionsobjectYesThe set of questions. You choose the keys, and answers come back under those same keys

Each question in questions has this shape:

FieldTypeRequiredDescription
typestringYesQuestion type: noul, choice, or score
instructionsstringYesPlain-language description of what this question asks
criteriaobject or arrayYesThe judging criteria; the shape depends on type

Question types

noul — yes/no judgment

criteria uses the keys true and false to describe when the condition holds and when it does not.

json
"is_urgent": {
  "type": "noul",
  "instructions": "Does this message convey urgency?",
  "criteria": {
    "true": "Explicitly time-sensitive",
    "false": "No urgency expressed"
  }
}

The answer returns a single noul field: a probability from 0 to 1 that the condition holds (0.95 means "almost certainly urgent"). This type returns no confidence — the probability itself carries the strength.

choice — single selection

criteria maps each option to what that option means, and the model picks one.

json
"department": {
  "type": "choice",
  "instructions": "Which team should handle this?",
  "criteria": {
    "billing": "Payments, invoicing, refunds",
    "technical": "Bugs, outages, integrations",
    "sales": "Pricing, upgrades, new accounts"
  }
}

The answer returns the selected choice, the probabilities for every option, and a confidence.

score — graded scoring

criteria is an ordered array where the index is the score: item 0 scores 0, item 1 scores 1, and so on.

json
"frustration": {
  "type": "score",
  "instructions": "How frustrated is the customer?",
  "criteria": ["Calm", "Frustrated", "Very angry"]
}

The answer returns a continuous score, a legend mapping indices back to the grade labels, the probabilities for each grade, and a confidence. The score is the probability-weighted expected value, so it usually falls between two grades: in the example, 0 × 0 + 1 × 0.96 + 2 × 0.04 = 1.04.

Response

json
{
  "model": "typesafe/jev-1.13-20260917",
  "answers": {
    "department": {
      "type": "choice",
      "choice": "billing",
      "probabilities": {
        "technical": 0.11,
        "sales": 0,
        "billing": 0.89
      },
      "confidence": 0.83
    },
    "frustration": {
      "type": "score",
      "score": 1.04,
      "legend": {
        "0": "Calm",
        "1": "Frustrated",
        "2": "Very angry"
      },
      "probabilities": {
        "0": 0,
        "1": 0.96,
        "2": 0.04
      },
      "confidence": 0.95
    },
    "is_urgent": {
      "type": "noul",
      "noul": 0.95
    }
  },
  "usage": {
    "input_tokens": 427,
    "output_tokens": 73,
    "cost": 0.000017934
  },
  "id": "gen-dec-1789948229-FmHnDQNsDfVnwWsYaUP1",
  "provider": "TypeSafe"
}

Response fields

Top-level fields:

FieldTypeDescription
modelstringThe model version that served the request, e.g. typesafe/jev-1.13-20260917
answersobjectThe answers, keyed exactly like questions in the request
usageobjectToken usage and cost for this call
idstringUnique request ID; include it when contacting support
providerstringThe upstream provider, here TypeSafe

Answer object fields, by type:

FieldPresent forTypeDescription
typeallstringMatches the type you asked with
noulnoulnumberProbability from 0 to 1 that the condition holds
choicechoicestringThe selected option key
scorescorenumberProbability-weighted score, continuous
legendscoreobjectMaps each index to its grade label
probabilitieschoice, scoreobjectProbability per option / grade, summing to roughly 1
confidencechoice, scorenumberThe model's confidence in the answer, 0 to 1; reported separately from probabilities and not equal to the highest probability

usage fields:

FieldTypeDescription
input_tokensintegerInput tokens (the state plus every question definition)
output_tokensintegerOutput tokens
costnumberCost of this call, in USD

Best practices

Put the judgment in the criteria

  • Let instructions say what to judge and criteria say where each outcome begins and ends — sharpening the boundaries beats lengthening the instructions
  • Question keys become answer keys, so use meaningful names like is_urgent or department and read values straight out of the response

Route on the probabilities

  • Don't look at choice alone; check confidence and probabilities too, and send anything below your threshold to a human
  • score is continuous, so take the argmax of probabilities or round it yourself when you need a discrete grade

Batch your questions

  • Put every question about the same state in one request: the state is sent and billed once, which costs fewer tokens than splitting it across calls

Tip

Answers come back keyed, and their order is not guaranteed to match the order you asked in (the example response above is reordered). Read by key rather than relying on order.