---
summary: "Choose decision models and define typed choices, scores, and Boolean judgments"
title: "Decision models"
read_when:
  - Choosing between a chat, utility, or decision model
  - Defining classification or scoring rubrics
  - Calling or implementing the decision model plugin API
---

# Decision models

A **decision model** evaluates supplied evidence against a rubric and returns a
typed answer: a choice, a score, or a Boolean probability. Use it for bounded
judgments such as routing a request, scoring its urgency, or checking whether it
meets a condition.

`decisionModel` is a model role with a shared API. Its providers can use different
model architectures and inference backends. Sharing the interface does not make
their reasoning ability or probabilities interchangeable.

The role and TypeSafe AI adapter were added after released OpenClaw
`2026.9.5`. These instructions apply to development checkouts containing those
features and to later releases that include them. See each provider's setup
page for its host requirements.

| Role            | Typical work                                             | Result                                  |
| --------------- | -------------------------------------------------------- | --------------------------------------- |
| Primary model   | Conversation and agent work                              | Messages and tool calls                 |
| `utilityModel`  | Short language tasks such as titles and summaries        | Generated text                          |
| `decisionModel` | Classification, rubric scoring, and predicate evaluation | Typed answers and probability estimates |

Decision models have a separate **Decision** picker in the Control UI. Selection
chooses the provider for explicit evaluation and supported consumers. The core
`decision_evaluate` tool follows that selection plus ordinary tool policy.
Selection does not start background work or replace the chat model.
Automatic experimental consumers additionally require explicit
[Decision assistance opt-in](/concepts/experimental-features#decision-assistance).
The built-in OpenClaw runtime uses that opt-in for conversational tool filtering
with bounded recent conversation. The selected Decision provider receives that
secondary evidence; see the [privacy and fallback contract](/concepts/experimental-features#conversational-tool-filtering).
Explicit `decision_evaluate` remains independent of Labs.

## Choose a provider and model

Configure the provider plugin before selecting its model:

- [Liquid AI](/providers/liquid-ai) connects directly to hosted d1 and d1 Ultra.
  Install the plugin candidate from a compatible development checkout and
  configure a Liquid AI API key. Text/JSON and inline image evidence use the
  native Decision endpoint; connecting it does not change the chat model.
- [ONNX](/plugins/onnx) runs local CPU classifiers in a persistent subprocess.
  Follow its development-checkout or compatible-package setup, then explicitly
  download the model or prepare a local export. Inference needs no hosted API credential.
- [OpenAI](/providers/openai#decision-models) uses the bundled `openai` plugin
  and the OpenAI Platform Decisions API. Configure an OpenAI API key;
  ChatGPT/Codex subscription credentials do not authorize this endpoint.
  Evaluations send the supplied evidence to OpenAI and incur Platform usage charges.
- [Rerank](/providers/rerank) is bundled and uses any reranker behind a
  `/rerank` endpoint: vLLM, Hugging Face TEI, Infinity, llama.cpp, Cohere,
  Jina, or Voyage. List the endpoint and model under `models.providers.rerank`;
  self-hosted servers need no credential. A reranker answers `boolean`,
  `choice`, and `sort` questions with relevance scores, which suits matching
  judgments such as the Knowledge recall gate, not rubric scoring.
- [SubQ](/plugins/subq) connects to hosted SubQ Snap for text/JSON decisions.
  Configure a protected SubQ credential. This V1 adapter supports text/JSON
  input only; it does not expose the vendor API's image input.
- [TypeSafe AI](/plugins/typesafe) connects to hosted Jev or a self-hosted System One
  server such as Kev. Install and enable the external plugin, then configure a
  protected hosted credential, the existing loopback setting, or a
  [standard model-provider endpoint](/plugins/typesafe#custom-endpoint-and-provider-request-settings)
  through `models.providers.typesafe`. Evaluations send user content to that
  endpoint; hosted calls incur TypeSafe's normal charges. Select `typesafe/kev-latest`
  for Kev; router-backed servers must use their own routing model ID.

The current plugins declare these model references:

| Model reference                      | Model                  | Preparation                                            |
| ------------------------------------ | ---------------------- | ------------------------------------------------------ |
| `onnx/deberta-v3-base-zeroshot-v2.0` | DeBERTa Zero-shot v2   | Download pinned ONNX artifacts                         |
| `onnx/gliclass-base-v3.0`            | GLiClass Base v3       | Download pinned ONNX artifacts                         |
| `onnx/gliclass-edge-v3.0`            | GLiClass Edge v3       | Download pinned ONNX artifacts                         |
| `onnx/gliclass-instruct-base-v1.0`   | GLiClass Instruct Base | Local export                                           |
| `onnx/gliclass-instruct-edge-v1.0`   | GLiClass Instruct Edge | Local export                                           |
| `onnx/gliner2.5-base-v1`             | GLiNER 2.5 Base        | Download pinned ONNX artifacts                         |
| `onnx/gliner2.5-small-v1`            | GLiNER 2.5 Small       | Download pinned ONNX artifacts                         |
| `openai/gpt-6-luna`                  | GPT-6 Luna             | OpenAI Platform API key and Decisions API access       |
| `subq/subq-snap-preview`             | SubQ Snap (preview)    | SubQ credential and account credits                    |
| `typesafe/jev-1.13.0`                | Jev 1.13.0             | TypeSafe credential                                    |
| `typesafe/jev-latest`                | Jev                    | TypeSafe credential; follows the vendor's latest model |
| `typesafe/kev-latest`                | Kev (local server)     | Running System One server and explicit loopback URL    |

Rerank models have no fixed list: any model you configure under
`models.providers.rerank` is selectable as `rerank/<model id>`.

The ONNX, SubQ, and TypeSafe AI plugins are currently unpublished candidates. Their setup pages explain
source-checkout use and the packaged host floor. The table describes the plugins' declared models,
not which artifacts or credentials are ready on your machine.

After provider setup, merge the role selection into your configuration:

```json5
{
  agents: {
    ownership: "explicit",
    defaults: { decisionModel: "onnx/gliclass-edge-v3.0" },
    entries: {
      support: { decisionModel: "typesafe/jev-latest" },
      quiet: { decisionModel: "" },
    },
  },
}
```

An unset agent override inherits the global default. An empty agent override
disables decisions for that agent. An unset or empty global default leaves the
role off. There is no automatic fallback to a conversational model.

For local setup verification, `openclaw onnx models` lists the presets and
`openclaw onnx probe gliclass-edge-v3.0` runs a Choice, Score, and Boolean smoke
evaluation after the model has been downloaded.

## Define a decision

Each request contains shared `state` and a `questions` map. State accepts text,
a JSON object or array, or `null`. Question keys identify answers;
the `instructions` and `criteria` define the judgment. The rubric travels with
each request, so there is no separate rubric-registration step.

| Question type | Criteria                                 | Answer                                                     |
| ------------- | ---------------------------------------- | ---------------------------------------------------------- |
| `choice`      | An object mapping labels to descriptions | `choice` and a `probabilities` object with the same labels |
| `score`       | An ordered array of rubric descriptions  | Fractional `score` and index-aligned `probabilities`       |
| `boolean`     | Descriptions under `true` and `false`    | `probabilityTrue`, from 0 to 1                             |

Use descriptive alternatives and observable score anchors. Give Boolean questions
both descriptions when targeting ONNX. Keep evidence focused on the question;
ONNX's token budget includes the state, instructions, and rubric.

## Agent evaluation tool

`decision_evaluate` is a core tool. An agent receives it when that agent has an
effective `decisionModel`, subject to normal tool policy, explicit denies, and
the active harness's capabilities. An unconfigured agent or one with an empty
per-agent override does not receive the tool. The tool remains eligible whether
or not other experimental consumers use Decision models. Provider plugins still
need their own normal setup.

Call it with explicit shared `state` and a `questions` map:

```json
{
  "state": { "message": "Checkout is failing for all customers." },
  "questions": {
    "escalate": {
      "type": "boolean",
      "instructions": "Does this need incident response?",
      "criteria": {
        "true": { "includes": ["Widespread service outages"] },
        "false": "A routine request can follow normal handling"
      }
    },
    "route": {
      "type": "choice",
      "criteria": { "support": "Service failures", "billing": "Payment questions" }
    },
    "urgency": {
      "type": "score",
      "criteria": ["No disruption", "One workflow blocked", "Widespread outage"]
    }
  }
}
```

State, instructions, and criterion descriptions accept text, JSON objects or
arrays, or `null`. Each question sees the same state and cannot see another
answer in the batch. Use a later call when one question depends on an earlier
answer. The tool collects no ambient conversation. Its trusted calling-agent
binding selects the provider and model; input cannot override that identity or
selection.

The tool preserves this input format and also accepts `contractVersion: 2` with
tagged state: `text`, `json`, `image`, or `list`. This explicit discriminator keeps
existing JSON state from being mistaken for image or list instructions. For example:

```json
{
  "contractVersion": 2,
  "state": { "type": "image", "dataUri": "data:image/png;base64,...", "text": "Listing photo" },
  "questions": {
    "present": { "type": "boolean", "instructions": "Is the product visible?" },
    "region": { "type": "box", "instructions": "the product in the listing photo" }
  }
}
```

The selected provider must declare support for the input and question types.
Images use inline PNG, JPEG, or WebP data, up to 4 MiB decoded; provider limits can
be stricter. Box questions require image state and return normalized edges, not
proof that the target exists. V2 also supports `sort` over list item IDs and
`tags` over named criteria when the provider declares those operations.

Results preserve explicit Boolean answers separately from probabilities,
abstention (`null`), per-question errors, fractional scores, original distributions,
optional confidence, provider metadata and usage, including reported USD cost and
native units. Missing fields stay absent; estimates are not normalized or derived.
V1 providers remain supported through the lossless bridge. Results do not grant
permission to act.
Evidence goes to the selected provider's configured endpoint or local runtime;
only send data authorized for that destination. Provider plugins own credentials,
model loading, transport, and wire-specific validation.

Provider capabilities come from the prepared model catalog or canonical manifest
catalog, also exposed in `models.list.decisionModels`. Unsupported questions and bounds produce actionable,
bounded guidance. Requests are rejected rather than silently truncated or split.
Do not substitute shell or HTTP calls when a configured provider is unavailable,
request credentials in chat, or treat a failure as a negative answer.

Missing credentials, rate limits, overload, and temporary provider errors leave
the configured tool available and return an unavailable result. Configuration
changes follow the existing tool/context refresh lifecycle; execution rechecks
the effective selection and authority. Cancellation propagates to the shared
Decision runtime and must not start fallback work.

## Call from a plugin

Call from a live tool, hook, or other owned operation. Here `api` is the plugin
API, `agentId` identifies the agent owning the work, and `signal` is that
operation's cancellation signal. The consumer needs no provider SDK or API key.

```ts
const outcome = await api.runtime.decisions.evaluate(
  {
    state: { message: "Checkout is failing for all customers." },
    questions: {
      route: {
        type: "choice",
        instructions: "Which team should handle this?",
        criteria: {
          support: "Technical problems and service outages",
          billing: "Invoices, refunds, and incorrect charges",
          sales: "Pricing and purchasing questions",
        },
      },
      urgency: {
        type: "score",
        instructions: "Assess the operational impact.",
        criteria: [
          "No service disruption",
          "Minor inconvenience with a workaround",
          "An important workflow is blocked",
          "A widespread production outage",
        ],
      },
      escalate: {
        type: "boolean",
        instructions: "Does this require human incident response?",
        criteria: {
          true: "A serious service incident needs human attention",
          false: "A routine request can follow normal handling",
        },
      },
    },
  },
  {
    agentId,
    purpose: "support.triage",
    rubricVersion: "1",
    timeoutMs: 30000,
    signal,
  },
);
```

The host selects the provider and model from the owning agent's configuration.
`purpose` identifies the consumer operation; `rubricVersion` identifies its rubric
in result provenance. They do not replace question instructions. Change the
rubric version when its meaning changes. Omit `agentId` only when intentionally
using global-default selection. Optional `assertCurrent` is the caller's own
authority check (for example a revocable data grant); the host re-runs it at every
provider dispatch and retry, and a throw rejects the evaluation before more data
leaves.

An `ok` outcome contains `outcome.result.answers`, keyed by the submitted question
IDs, plus the provider-reported model, optional usage, and provider/rubric/runtime provenance.
A reported alias such as `kev-latest` does not identify a particular loaded checkpoint.
Missing usage or confidence stays absent. For example, these are illustrative answers, not a promised model response:

```json
{
  "route": {
    "type": "choice",
    "choice": "support",
    "probabilities": { "support": 0.97, "billing": 0.02, "sales": 0.01 }
  },
  "urgency": {
    "type": "score",
    "score": 2.85,
    "probabilities": [0, 0, 0.15, 0.85]
  },
  "escalate": { "type": "boolean", "probabilityTrue": 0.96 }
}
```

The host validates the complete batch before returning any answers. Narrow an
answer by its `type` before accessing type-specific fields in TypeScript.

## Interpret scores and probabilities

Scores are **zero-based rubric positions**. The four urgency descriptions above
define a scale from 0 to 3, including fractions. A score of 2.85 lies near the
highest-impact anchor. A display can rescale that position:

```ts
if (outcome.status === "ok") {
  const urgency = outcome.result.answers.urgency;
  if (urgency?.type === "score") {
    const scoreOutOf100 = (100 * urgency.score) / 3;
  }
}
```

The divisor is the last rubric index: `criteria.length - 1`. The display value
is a position on the scale, not a confidence percentage or probability of being
correct. Rubric wording determines what that scale means.

ONNX normalizes actual label logits with softmax. Choice uses the largest value;
Score is the probability-weighted rubric index. TypeSafe preserves Jev's reported
label, score, and probability estimates. Rounded vendor probabilities need not
sum exactly to one, and its reported score need not equal an expectation computed
from those rounded values.

A low Boolean probability favors false; a value near 0.5 gives similar weight to
both outcomes. Missing evidence does not guarantee a value near 0.5. Include an
explicit insufficient-evidence Choice alternative when that outcome matters.
Choice alternatives compete; use separate Boolean questions for independent labels.

Your consumer chooses an action policy, such as escalating when `probabilityTrue`
is at least 0.9. Validate that threshold on representative examples. Probabilities
and optional provider-specific `confidence` values are estimates, not demonstrated
accuracy guarantees. An answer does not grant permission to send a message or
perform another effect.

## Limits and unavailable results

For portable rubrics, use at most 16 questions, 2–64 Choice alternatives, 2–10
meaningful Score anchors, explicit true/false descriptions, and concise evidence.
Provider limits differ:

| Provider    | Choice alternatives | Score levels | Additional limits                                                                  |
| ----------- | ------------------- | ------------ | ---------------------------------------------------------------------------------- |
| ONNX        | 2–64                | 2–64         | Up to 32 questions; 512 tokens per encoded input; one MiB of compiled batch inputs |
| SubQ        | 2–255               | 2–10         | Up to 16 questions; text/JSON state; question IDs at most 100 characters           |
| TypeSafe AI | 2–255               | 2–10         | Subject to the host's batch limits and the vendor input contract                   |

The host bounds JSON evidence to one MiB, 20,000 nodes, and depth 32. V1 accepts
up to 256 questions; V2 accepts up to 400, subject to the selected provider's limit.
Version 2 image state has a separate four-MiB decoded image limit. It admits at most four
requests per provider and caps each deadline at 30 seconds. Optional assistance
leaves the fourth slot for requested evaluations; under contention, the tool
prefilter skips evaluation and retains tools. Provider-specific limits can be
tighter. Unsupported input is rejected instead of silently truncated.

An `unavailable` outcome includes a reason such as `disabled`, `not-configured`,
`unsupported-input`, `overloaded`, or `deadline`. The consumer decides whether to
skip, defer, or use its existing fallback. Caller cancellation, closed consumer
authority, and contract errors reject; do not turn cancellation into fallback work.
See the [SDK contract](/plugins/sdk-overview/capabilities#decision-models-contract-version-1)
for the complete lifecycle and error behavior.

Consumers should build bounded useful evidence, evaluate it once, and retain their
normal behavior when the provider returns `unsupported-input`, including context
overflow. The runtime does not estimate model tokens, truncate evidence, retry,
or choose another provider/model. Input rejection does not open the provider
circuit; cancellation and closed authority remain terminal.

The `decisions` logger records DEBUG outcomes, dispatch status, elapsed time,
question count, supplied JSON byte count, and actual provider usage when available.
JSON bytes are not model tokens. Purpose/provider/model identifiers are hashed;
existing ambient trace correlation is preserved. It logs no submitted text,
rubrics, credentials, or provider error bodies, and does no extra input serialization
when DEBUG is disabled. Generic input-rejection warnings are rate limited. Logs
distinguish the provider result from the caller effect, which remains unobserved here.

For ONNX, cold-loading a large model can exceed the deadline on slower machines.
Keep active models warm when memory permits, or choose a smaller model. See
[ONNX lifecycle and runtime](/plugins/onnx#lifecycle-and-runtime) for cache settings
and the effect of active cancellation. For missing TypeSafe credentials, follow
its [setup instructions](/plugins/typesafe#enable-and-configure).

## Provide models from a plugin

New providers should use the [prepared V2 execution contract](/plugins/sdk-overview/capabilities#prepared-decision-execution-contract-version-2)
with normal provider catalog and auth ownership. V1 remains supported through
lossless codecs; native V2 features require a V2 caller and provider.

A V1 provider plugin implements `DecisionProviderV1` from
`openclaw/plugin-sdk/decisions` and registers it with
`api.registerDecisionProvider(provider)`. Its `id` and `contractVersion: 1`
identify the contract; `evaluate(batch, context)` returns validated typed answers
or a supported unavailable reason. The context includes the selected model,
optional agent ID, composed cancellation signal, monotonic deadline, and an optional
host-owned `isAdmissible()` predicate for automatic consumers. External transports
check that predicate at final synchronous I/O, after awaited preparation; see the
[provider contract](/plugins/sdk-overview/capabilities#decision-models-contract-version-1).

Declare provider ownership and static model metadata in the plugin manifest:

```json
{
  "contracts": { "decisionProviders": ["example-decisions"] },
  "decisionModels": [{ "provider": "example-decisions", "id": "fast", "name": "Fast decisions" }]
}
```

This manifest fragment exposes the selector `example-decisions/fast` in the
separate decision catalog. The consumer uses the same evaluation API for every
provider. It does not register a provider itself.

Providers own model-specific input translation, transport or local inference,
prepared credentials where needed, and physical cleanup on cancellation.
Registration and optional `isReady()` must be synchronous and network-free;
`isReady()` checks prepared credential availability, not model warmup. Omitting it
leaves readiness unconfirmed without blocking evaluation; returning `false`
blocks evaluation until the provider reports ready. Return real model estimates
rather than manufacturing certainty from a label-only response.

The [provider contract](/plugins/sdk-overview/capabilities#decision-models-contract-version-1)
owns the full SDK rules; the [manifest reference](/plugins/manifest/capabilities#decision-models-reference)
owns discovery fields. For existing integrations, use the [ONNX](/plugins/onnx)
or [TypeSafe AI](/plugins/typesafe) setup pages.

## Contract ownership

The Decision SDK separates supplied evidence and typed answers from execution.
Plugins continue to import `openclaw/plugin-sdk/decisions`; V1 and V2 provider
interfaces and evaluation calls keep their existing shapes.

| Responsibility                                                     | Owner                                            |
| ------------------------------------------------------------------ | ------------------------------------------------ |
| Evidence, question and answer shapes                               | Shared Decision contracts                        |
| Declared answer semantics and route support                        | Canonical schemas in the model catalog workspace |
| Native request/response translation and model restrictions         | Provider plugin                                  |
| Credentials, network policy, admission, deadlines and cancellation | OpenClaw host and prepared provider context      |
| Runtime provenance and accepted usage accounting                   | OpenClaw host                                    |

Result validation accepts answer semantics without requiring a catalog route:

```ts
import { validateDecisionResultV2 } from "openclaw/plugin-sdk/decisions";

const valid = validateDecisionResultV2(batch, response, { confidence: "none" });
```

An existing full route capability object remains accepted. This validates the
supplied result against the batch; it does not dispatch a provider, establish
host authority or record accepted usage. Providers still return provider outcomes.
The host attaches provenance during evaluation. Accepted usage is recorded only
after the consuming operation passes its final checks. Keep those host
responsibilities out of codecs and application result handling.
