Skip to content

Decision API ​

Decision models answer typed questions about a state in one pass: choice, score and noul (calibrated yes/no). Vision-capable decision models also accept images. Browse Decision models

Endpoints
text
POST /v1/systemone
POST /v1/decide
Models and quick start

Browse decision models

bash
self serve kev:0.5b

POST /v1/systemone ​

The canonical decision endpoint. The /v1/decide path is an equivalent alias.

Request body ​

stateJSON valuerequired

Context for the decision. It can be a string, object, array, number, or boolean.

questionsobjectrequired

Named questions to answer. Each key becomes the answer key in the response.

modelstringoptional

Ignored: the server runs one model. Accepted so SDK clients work unchanged.

imagesarrayoptional

Images supplied to vision-capable models. See Vision input.

Question object ​

typechoice | score | noul | number | excerptrequired

Output type requested from the model.

instructionsstringrequired

What the model should decide.

criteriaobject | arrayoptional

Required for choice and score: defines the available choices or rating levels. Omit it for noul.

For number, optionally supply min, max and precision (a non-negative rounding increment, such as 0.01). min must not exceed max. Omit criteria for excerpt.

citebooleanoptional

Request supporting document spans with probabilities. Defaults to false.

Extraction capabilities ​

number, excerpt and cite are additive decision capabilities. Inspect GET /v1/model under capabilities.output before requesting them. Effective support is the intersection of the registry and engine capabilities. A model that does not support the requested type or citations returns HTTP 422 with unsupported_capability before inference. cite: false needs no citation capability. These fields do not enable extraction on existing choice-only models.

number answers contain value (a number or null when not stated), probability, not_stated, nullable confidence, and candidates with value, probability and context. excerpt answers contain nullable text, probability, and, when text is found, start and end character offsets (zero-based, end-exclusive), plus optional parts. Citations appear in a citations array on any answer, with text, start, end and probability. Offsets count Unicode code points, not UTF-8 bytes.

THX-01 uses these shapes for document lookup, verbatim extraction and supporting citations. API support alone does not provide a THX-01 inference runtime.

Example request
bash
curl http://localhost:8080/v1/systemone \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "kev:0.5b",
    "state": {
      "message": "I was charged twice for the same order.",
      "customer_tier": "pro"
    },
    "questions": {
      "department": {
        "type": "choice",
        "instructions": "Which department should handle this?",
        "criteria": {
          "billing": "Payments and refunds",
          "technical": "Technical problems"
        }
      },
      "urgency": {
        "type": "score",
        "instructions": "How urgently should this ticket be handled?",
        "criteria": [
          "Low: routine request with no immediate impact",
          "Medium: customer affected, but a workaround exists",
          "High: customer blocked or money at risk"
        ]
      },
      "refund_required": {
        "type": "noul",
        "instructions": "Does this likely require a refund?"
      }
    }
  }'
python
import requests

response = requests.post(
    "http://localhost:8080/v1/systemone",
    json={
        "state": "Classify this support ticket.",
        "questions": {
            "priority": {
                "type": "choice",
                "instructions": "What priority should this ticket receive?",
                "criteria": {
                    "low": "No immediate impact",
                    "high": "Production or customer impact",
                },
            }
        },
    },
    timeout=60,
)
response.raise_for_status()
print(response.json())
js
const response = await fetch('http://localhost:8080/v1/systemone', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    state: { message: 'The invoice total is wrong.' },
    questions: {
      billing: {
        type: 'choice',
        instructions: 'Is this a billing issue?',
        criteria: { yes: 'Billing issue', no: 'Not a billing issue' }
      }
    }
  })
})

if (!response.ok) throw new Error(await response.text())
console.log(await response.json())
Example response
json
{
  "model": "kev:0.5b",
  "answers": {
    "department": {
      "type": "choice",
      "choice": "billing",
      "probabilities": { "billing": 0.94, "technical": 0.06 },
      "confidence": 0.94
    },
    "urgency": {
      "type": "score",
      "score": 1.8,
      "probabilities": { "0": 0.05, "1": 0.1, "2": 0.85 },
      "confidence": 0.85
    },
    "refund_required": {
      "type": "noul",
      "noul": 0.91,
      "confidence": 0.91
    }
  },
  "usage": {
    "input_tokens": 31,
    "output_tokens": 0,
    "images": 0,
    "latency_ms": 24.7
  }
}

Criteria ​

criteria tells the model which answers or rating levels are available. Its format depends on the question's type.

choice: pick one named option. Supply a non-empty object:

  • Each key is a value your application can receive, such as "billing".
  • Each value describes when to choose that option, such as "Payments, refunds, and invoices".
  • The response's choice contains the selected key, not its description. probabilities uses the same keys.

For the example, "choice": "billing" means the ticket should go to billing. If no descriptions are needed, a string array such as ["billing", "technical"] is also accepted.

score: rate on an ordered scale. Supply a non-empty array of strings, from lowest to highest. Each string describes a level; its position assigns its numeric value, starting at 0.

For ["low", "medium", "high"], the levels are 0, 1, and 2. The response's score is the probability-weighted average of these values, so it can be fractional: 1.8 means a rating near "high", not an array index to look up directly. probabilities uses the index keys "0", "1", and "2".

noul: estimate whether something is true. Ask a yes/no question in instructions and omit criteria; this type does not accept choices or levels. The response's noul is a probability from 0 to 1: near 0 means no, near 1 means yes. For example, "noul": 0.91 means an estimated 91% probability that a refund is required, not a boolean result.

choice
json
{
  "billing": "Payments, refunds, and invoices",
  "technical": "Bugs and technical problems"
}
score
json
["low", "medium", "high"]

Response body ​

modelstring

ID of the loaded model.

answersobject

One answer for each question, keyed by the question ID. The fields depend on the question type:

Answer typeFields
choicechoice, probabilities, confidence
scorescore, probabilities, confidence
noulnoul, confidence

choice is the selected criteria key. score is the probability-weighted average of the zero-based level indexes in the submitted criteria array. noul is a probability from 0 to 1, where values closer to 1 mean yes/true. confidence and probabilities are model output confidence values.

usageobject

Runtime usage and latency counters.

  • input_tokens and output_tokens count the tokens processed and generated.
  • images is the number of images processed.
  • latency_ms is the time spent running the model.
  • queue_ms is the time the request waited in the queue.
Response
json
{
  "model": "kev:0.5b",
  "answers": {
    "department": {
      "type": "choice",
      "choice": "billing",
      "probabilities": {
        "billing": 0.91,
        "technical": 0.09
      },
      "confidence": 0.91
    },
    "urgency": {
      "type": "score",
      "score": 1.8,
      "probabilities": { "0": 0.05, "1": 0.1, "2": 0.85 },
      "confidence": 0.85
    },
    "refund_required": {
      "type": "noul",
      "noul": 0.97,
      "confidence": 0.97
    }
  },
  "usage": {
    "input_tokens": 23,
    "output_tokens": 0,
    "images": 0,
    "latency_ms": 18.4
  }
}

Vision input ​

Vision models accept an image as an HTTPS URL or a data URI. An image can also be an object with optional name and description fields.

Supported image inputs are HTTPS URLs and JPEG, PNG, or WebP data URIs. Plain HTTP image URLs and private/loopback image addresses are rejected unless the server is started with --allow-http-images or --allow-private-images.

Image object ​

urlstringrequired

HTTPS URL or a JPEG, PNG, or WebP data URI.

namestringoptional

Optional name for the image.

descriptionstringoptional

Optional description of the image.

Example request
bash
curl http://localhost:8080/v1/systemone \
  -H 'Content-Type: application/json' \
  -d '{
    "state": "Inspect this image and decide whether the package is damaged.",
    "images": [
      {
        "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Damaged_fragile_parcel_delivered_to_doorstep.jpg/1280px-Damaged_fragile_parcel_delivered_to_doorstep.jpg",
        "name": "package",
        "description": "Front camera image of the delivered package"
      }
    ],
    "questions": {
      "damaged": {
        "type": "noul",
        "instructions": "Is the package visibly damaged?"
      }
    }
  }'
Example response
json
{
  "model": "decider-vision:2b",
  "answers": {
    "damaged": {
      "type": "noul",
      "noul": 0.87,
      "confidence": 0.87
    }
  },
  "usage": {
    "input_tokens": 118,
    "output_tokens": 0,
    "images": 1,
    "latency_ms": 642.1
  }
}

Decision errors ​

Besides the shared errors, decision requests return:

StatusError typesMeaning
400unsupported_imageThe image is not an HTTPS URL or a JPEG, PNG, or WebP data URI.
413image_too_largeRequest body exceeds 32 MiB.
422unsupported_capabilityMore options than the model supports, or images on a text-only model.
429queue_fullThe request queue is full.
502image_fetch_failedA remote image could not be fetched or decoded.
Error response
json
{
  "error": {
    "type": "unsupported_capability",
    "message": "The loaded decision model does not support image input."
  }
}