Docs · Advanced

Advanced

Send state and typed questions. Get structured answers your code can use directly.

Question types

Three primitives. Mix them in one request. Every question sees the same state, runs in parallel, and returns under the id you chose. Ids are for your code — they are not sent to the model. Write the full question in instructions.

Ask for one snap judgment per question. “Does this message convey urgency?” is a good question. “Analyze this and determine the best course of action” is not — split that into small questions and compose the answers in code.

Noul

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

Choice

Options are unordered. Use null when an option needs no extra detail.

{
  "type": "choice",
  "instructions": "Which team should handle this?",
  "criteria": {
    "billing": "Payments, invoicing, refunds",
    "technical": "Bugs, outages, integrations",
    "sales": "Pricing, upgrades, new accounts",
    "other": "None of the listed teams"
  }
}
{
  "type": "choice",
  "choice": "technical",
  "probabilities": { "billing": 0.08, "technical": 0.85, "sales": 0.05, "other": 0.02 },
  "confidence": 0.82
}

Score

At least two ordered levels.

{
  "type": "score",
  "instructions": "How frustrated is the customer?",
  "criteria": ["Calm", "Frustrated", "Very angry"]
}
{
  "type": "score",
  "score": 1.6,
  "legend": { "0": "Calm", "1": "Frustrated", "2": "Very angry" },
  "probabilities": { "0": 0.05, "1": 0.3, "2": 0.65 },
  "confidence": 0.78
}

State

One state per request. A string, object, or array of text. Jev is text-only. Put facts in state and judgments in questions.

{
  "ticket": {
    "subject": "Duplicate charge",
    "messages": [
      { "from": "customer", "text": "I was charged twice. Please refund the duplicate." },
      { "from": "support", "text": "We are checking the charges." }
    ]
  },
  "order": {
    "id": "A-104",
    "charges": [
      { "amount_usd": 49, "status": "captured" },
      { "amount_usd": 49, "status": "captured" }
    ]
  },
  "refund_policy": "Duplicate charges are eligible for a refund."
}

For structured state, name fields in instructions with a dotted path in backticks.

{
  "refund_requested": {
    "type": "noul",
    "instructions": "Does `ticket.messages[0].text` request a refund?"
  },
  "policy_supports_refund": {
    "type": "noul",
    "instructions": "Does `refund_policy` support the refund requested in `ticket.messages[0].text`, given `order.charges`?"
  }
}

Many questions, one call

Send every question that uses the same state together, including speculative ones your code might ignore. Adding questions barely changes latency. A second request is only needed when the next question depends on the first answer — fetch more state, change options, or build something that did not exist yet.

{
  "model": "openjev",
  "state": {
    "ticket_message": "My flight was cancelled. Can I get a refund?",
    "refund_policy": "Cancelled flights are eligible for a full refund."
  },
  "questions": {
    "refund_requested": {
      "type": "noul",
      "instructions": "Does `ticket_message` request a refund?"
    },
    "request_type": {
      "type": "choice",
      "instructions": "What is the main request in `ticket_message`?",
      "criteria": {
        "refund": "The customer wants money returned",
        "rebooking": "The customer wants a replacement flight",
        "information": "The customer is asking for information only"
      }
    },
    "frustration": {
      "type": "score",
      "instructions": "How frustrated does the customer appear in `ticket_message`?",
      "criteria": ["Calm and neutral", "Concerned but civil", "Very angry"]
    }
  }
}

Confidence

Choice and Score answers include confidence (0 to 1), derived from how peaked the probability distribution is. The answer tells you what; confidence tells you whether to act. Noul has no separate confidence — the probability is the signal.

Raise the threshold when the action is expensive or irreversible. You still get the full probabilities if you want a different statistic than ours.

const action = answers.action;
if (action.confidence < 0.5) routeToHuman(state);
else if (action.choice === "approve_transfer" && action.confidence < 0.9) confirmFirst(state);
else execute(action.choice);

Errors

Quick start: Call OpenJEV.