Voxta docs

Decisions

A model that picks from a fixed list instead of writing, for the chat's multiple-choice questions — who speaks next, which action to take, whether a tool call may run.

Decisions answers multiple-choice questions. It is handed the chat and a fixed list of options, and returns one of them with a probability attached. It generates no text, so there is nothing to parse and nothing to wait for token by token.

New in Voxta Server 1.11. It is set in the right panel's Services tab, just below Action Inference.

What it answers

Much of what Action Inference is asked is a choice, not a sentence:

QuestionOptions
Who speaks next (chat flow)the characters, and the user
Which action the character takesthe actions in the layer, plus "none"
Whether a risky tool call may run without asking yourun it, ask you, refuse it

A decisions model never writes a string, so it cannot fill in an action's arguments. Anything that needs one stays on Action Inference.

When Action Inference answers instead

  • An action with arguments. If any action in a layer takes arguments, the whole layer goes to Action Inference.
  • Too many options. More options than the service can handle (26 on the local modules).
  • Declined answers. An answer that was not on the list, one under the Minimum Confidence setting (Voxta Cloud and OpenRouter), or, on a local model, one the model barely wanted to give.
  • Decisions set to None, or no module able to answer them.

If the decisions service fails (an error, the service is down), the question is not retried on Action Inference: no action is taken, and a tool call review asks you instead.

Choosing where decisions go

In the right panel, open Decisions and pick a Module:

  • Same as Action Inference — the default. Decisions go to whatever module runs Action Inference: its loaded model on ExLlamaV3 or llama.cpp, its decisions model on Voxta Cloud or OpenRouter. If that module has no decisions support, Action Inference answers everything. If Action Inference is off, so are decisions.
  • A module with its own decisions model — Voxta Cloud or OpenRouter, picked by name, whatever runs Action Inference.
  • None (use Action Inference) — decisions off; Action Inference answers everything, as before 1.11.

Adding Voxta Cloud or OpenRouter never switches decisions over on its own. They answer only through Same as Action Inference or when you pick them.

Modules

Voxta Cloud and OpenRouter

These use Jev, a decision model, through OpenRouter's Decisions API, which is in beta. Voxta Cloud relays the same API.

Decisions have presets of their own, separate from the text generation presets:

  • Model — OpenRouter's built-in preset uses typesafe/jev-1.13; the list also offers typesafe/jev-latest and takes a custom slug. Only a decision model belongs here, not a chat model. Voxta Cloud's preset is Automatic and lets the cloud choose.
  • Minimum Confidence (advanced) — how sure the model has to be before its answer is used. Below it, the question goes to Action Inference; with no Action Inference, nothing is chosen. Default 0 takes every answer.

Testing either module runs one real decision, so you can check it works before turning it on.

ExLlamaV3 and llama.cpp

ExLlamaV3 and llama.cpp answer with the model already loaded for Action Inference, reading each option's probability instead of generating a reply. No second model is loaded and there are no Decisions settings: they use the Action Inference settings.

They are reached only through Same as Action Inference, with Action Inference running on that module.

On 12 action inference cases (RTX 4090), against the default JSON-with-rationale output:

ModelBeforeWith Decisions
Gemma 4 12B on ExLlamaV3961 ms281 ms, same accuracy
Qwen 3.8 27B on llama.cpp8.0 s0.41 s

HTTP API

Your own programs can ask Voxta a decision directly, the way they can ask it for text through the OpenAI-compatible /v1/chat/completions. POST /v1/decisions takes the same request as TypeSafe's and OpenRouter's Decisions API, so a client written for Jev works by changing its base URL and key.

It is answered by the Decisions service of your default services configuration, with its module, preset and Minimum Confidence. It needs an API key with the Inference scope, sent as a bearer token.

curl http://localhost:5384/v1/decisions \
  -H "Authorization: Bearer $VOXTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "Kate slams the door and walks out without a word.",
    "questions": {
      "mood": {
        "type": "choice",
        "instructions": "How does Kate feel?",
        "criteria": {
          "angry": "Furious, fed up, storming off",
          "delighted": "Cheerful, pleased, having a wonderful time"
        }
      }
    }
  }'
{
  "model": "typesafe/jev-1.13",
  "answers": {
    "mood": {
      "type": "choice",
      "choice": "angry",
      "confidence": 0.97,
      "probabilities": { "angry": 0.98, "delighted": 0.02 }
    }
  }
}
  • state is what the model reads: text, or an object or array, which is read as JSON.
  • questions maps your own ids to questions. Each has instructions (the question, in one line) and criteria (option name to the description that tells it apart), with at least two options. Only choice questions are supported. Each is asked on its own, in order, and shows up in the inference logs.
  • model is ignored: the configured service picks it. The response names the model that answered, and backend and provider when the service reports them.
  • A declined question comes back with "choice": null: an answer not on the list, one under the Minimum Confidence, or, on a local model, one it barely wanted to give. The other questions are still answered.
  • Errors come back as {"detail": "..."}: 400 for a malformed question or more options than the service can handle (26 on the local modules), 503 when no decisions service is set, 502 when the service fails.

On this page