Branch on probabilities
Use a probability threshold when the next part of an answer depends on how strongly Struct favors a decision. For example, route a reported duplicate charge for automatic handling only when the probability assigned to true reaches your threshold; otherwise request review.
The runtime tests the measured candidate distribution and applies the corresponding schema branch. You do not ask the model to generate a confidence number or send a second request to choose the branch. The answer names a route; your application decides what action to take.
Route above a threshold
This schema asks whether a charge was duplicated. P(...) denotes probability, so P(duplicate = true) means the probability Struct assigns to true for the duplicate field. It returns route: "automatic" when that probability is at least 0.95, and route: "review" otherwise. No state or policy is required.
Save the schema beside your client:
{
"type": "object",
"properties": {
"duplicate": {
"type": "boolean",
"description": "True only when the input explicitly reports being charged more than once for the same purchase; otherwise false.",
"x-runtime": {
"probabilities": true
}
},
"route": {
"enum": [
"automatic",
"review"
]
}
},
"required": [
"duplicate",
"route"
],
"additionalProperties": false,
"if": {
"x-runtime": {
"probability": {
"path": "/duplicate",
"minimum": 0.95,
"value": true
}
}
},
"then": {
"properties": {
"route": {
"const": "automatic"
}
}
},
"else": {
"properties": {
"route": {
"const": "review"
}
}
}
}
Before you run this example
Call https://api.blatent.ai from your server. Set your API key in the same terminal where you run the example:
export BLATENT_API_KEY='YOUR_SERVICE_KEY'
Python requires Python 3.10+ and HTTPX:
python -m pip install "httpx>=0.28,<1"
TypeScript requires Node.js 24+ and uses its built-in fetch. The cURL examples require curl and jq.
Save the displayed files and the selected client in one directory. Run the client there with python example.py, node example.ts or bash example.sh. Downloads use the example's name in place of example.
- Python
- TypeScript
- cURL
import json
import os
from pathlib import Path
import httpx
request = {
"input": "The customer was charged twice for the same purchase. The duplicate charge is confirmed.",
"schema": json.loads(Path("probability-routing.schema.json").read_text(encoding="utf-8")),
}
with httpx.Client(
base_url="https://api.blatent.ai",
headers={"Authorization": f"Bearer {os.environ['BLATENT_API_KEY']}"},
timeout=195,
) as client:
response = client.post("/v1/resolve", json=request)
response.raise_for_status()
print(json.dumps(response.json()["output"]))
import { readFileSync } from "node:fs";
const request = {
"input": "The customer was charged twice for the same purchase. The duplicate charge is confirmed.",
"schema": JSON.parse(readFileSync("probability-routing.schema.json", "utf8")),
};
const response = await fetch(
"https://api.blatent.ai" + "/v1/resolve",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BLATENT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(request),
signal: AbortSignal.timeout(195_000),
},
);
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(JSON.stringify((await response.json()).output));
set -eu
body=$(jq -n --argjson body '{"input":"The customer was charged twice for the same purchase. The duplicate charge is confirmed."}' \
--slurpfile f0 'probability-routing.schema.json' \
'$body | setpath(["schema"]; $f0[0])')
curl --fail-with-body --silent --show-error \
"https://api.blatent.ai/v1/resolve" \
-H "Authorization: Bearer $BLATENT_API_KEY" \
-H 'Content-Type: application/json' \
--data-binary "$body"
Illustrative output: {"duplicate":true,"route":"automatic"}. The full response also includes the distribution at probabilities["/duplicate"]. Python and TypeScript print output; cURL prints the full response.
Two annotations work together:
| Annotation | Where it belongs | What it does |
|---|---|---|
"probabilities": true | Inside x-runtime on the decision field's schema | Collect the distribution over that field's candidates |
"probability": {...} | Inside the if schema's x-runtime | Compare a probability with your threshold |
The plural probabilities enables measurement. The singular probability refers to that measurement. then and else are ordinary JSON Schema branches: both add constraints to the surrounding schema. Declare the route and its allowed values in the surrounding object first.
Select the probability to test
| Part | Meaning |
|---|---|
path: "/duplicate" | The output field whose distribution is measured; not a path into the schema |
value: true | The particular candidate whose probability to test |
minimum: 0.95 | Require a probability of at least 95% |
For a categorical field, the same rule can name a candidate such as value: "billing". Preserve its JSON type: Boolean true and the string "true" are different candidates.
If you omit value, the rule tests the probability of whichever answer Struct selected. This is useful for deciding whether to accept a classification or ask for review, regardless of which category won. It is different from requiring a particular answer:
| Rule | When the selected answer is false with probability 99% |
|---|---|
Test value: true against 95% | Does not pass: P(true) is 1% |
Omit value and test against 95% | Passes: the selected false has probability 99% |
For approval-like rules, name the approving candidate explicitly. If your rule requires both a selected value and a probability threshold, put the ordinary properties and required tests alongside x-runtime inside if; both conditions must hold.
The direct if.x-runtime.probability.path addresses the output from its root. For example, /assessment/duplicate refers to a field inside assessment. The decision field and its parent objects must be required in the supported object form.
Inclusive and strict thresholds
Thresholds are numbers between 0 and 1. Use the comparison that matches your rule:
Inside if.x-runtime.probability | Meaning | Switch comparison |
|---|---|---|
minimum | At least the threshold | gte |
exclusiveMinimum | Strictly above it | gt |
maximum | At most the threshold | lte |
exclusiveMaximum | Strictly below it | lt |
You can supply lower and upper bounds together. An invalid threshold or a reference to an unmeasured field is rejected; it is not treated as a low-probability answer.
Choose among several tiers
A switch can select a probability through on.probability instead of selecting an output value through on.path. This example tests the same named candidate at two thresholds:
Probability assigned to duplicate = true | Route |
|---|---|
| At least 95% | automatic |
| At least 50%, but below 95% | review |
| Below 50% | decline |
{
"type": "object",
"properties": {
"duplicate": {
"type": "boolean",
"description": "True only when the input explicitly reports being charged more than once for the same purchase; otherwise false.",
"x-runtime": {
"probabilities": true
}
},
"route": {
"enum": [
"automatic",
"review",
"decline"
]
}
},
"required": [
"duplicate",
"route"
],
"additionalProperties": false,
"x-runtime": {
"switch": {
"on": {
"probability": {
"path": "/duplicate",
"value": true
}
},
"cases": [
{
"when": {
"gte": 0.95
},
"then": {
"properties": {
"route": {
"const": "automatic"
}
}
}
},
{
"when": {
"gte": 0.5
},
"then": {
"properties": {
"route": {
"const": "review"
}
}
}
}
],
"default": {
"properties": {
"route": {
"const": "decline"
}
}
}
}
}
}
Before you run this example
Call https://api.blatent.ai from your server. Set your API key in the same terminal where you run the example:
export BLATENT_API_KEY='YOUR_SERVICE_KEY'
Python requires Python 3.10+ and HTTPX:
python -m pip install "httpx>=0.28,<1"
TypeScript requires Node.js 24+ and uses its built-in fetch. The cURL examples require curl and jq.
Save the displayed files and the selected client in one directory. Run the client there with python example.py, node example.ts or bash example.sh. Downloads use the example's name in place of example.
- Python
- TypeScript
- cURL
import json
import os
from pathlib import Path
import httpx
request = {
"input": "The customer was charged twice for the same purchase. The duplicate charge is confirmed.",
"schema": json.loads(Path("probability-switch.schema.json").read_text(encoding="utf-8")),
}
with httpx.Client(
base_url="https://api.blatent.ai",
headers={"Authorization": f"Bearer {os.environ['BLATENT_API_KEY']}"},
timeout=195,
) as client:
response = client.post("/v1/resolve", json=request)
response.raise_for_status()
print(json.dumps(response.json()["output"]))
import { readFileSync } from "node:fs";
const request = {
"input": "The customer was charged twice for the same purchase. The duplicate charge is confirmed.",
"schema": JSON.parse(readFileSync("probability-switch.schema.json", "utf8")),
};
const response = await fetch(
"https://api.blatent.ai" + "/v1/resolve",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BLATENT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(request),
signal: AbortSignal.timeout(195_000),
},
);
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(JSON.stringify((await response.json()).output));
set -eu
body=$(jq -n --argjson body '{"input":"The customer was charged twice for the same purchase. The duplicate charge is confirmed."}' \
--slurpfile f0 'probability-switch.schema.json' \
'$body | setpath(["schema"]; $f0[0])')
curl --fail-with-body --silent --show-error \
"https://api.blatent.ai/v1/resolve" \
-H "Authorization: Bearer $BLATENT_API_KEY" \
-H 'Content-Type: application/json' \
--data-binary "$body"
Cases are checked in order. Put the highest threshold first because the first match wins; the explicit default handles all remaining probabilities. As with value switches, branches constrain the answer and do not execute the named action.
For switch.on.probability, path is relative to the output object containing the switch. A switch inside assessment therefore uses /duplicate for its own field, rather than /assessment/duplicate.
Apply a threshold to each supplied item
Use a switch inside a for-each loop to assess each item independently. This example answers two product checks and marks each answer for automatic handling or review. Here value is deliberately omitted: a confident false is just as useful as a confident true.
{
"$schema": "urn:blatent:json-schema:template-draft-v1",
"type": "array",
"maxItems": 4,
"x-runtime": {
"forEach": {
"ref": "state/checks",
"as": "check"
}
},
"items": {
"type": "object",
"properties": {
"route": {
"enum": [
"automatic",
"review"
]
},
"id": {
"x-runtime": {
"bind": {
"const": {
"ref": "check/id"
}
}
}
},
"answer": {
"type": "boolean",
"x-runtime": {
"probabilities": true,
"bind": {
"description": {
"ref": "check/description"
}
}
}
}
},
"required": [
"id",
"answer",
"route"
],
"additionalProperties": false,
"x-runtime": {
"switch": {
"on": {
"probability": {
"path": "/answer"
}
},
"cases": [
{
"when": {
"gte": 0.95
},
"then": {
"properties": {
"route": {
"const": "automatic"
}
}
}
}
],
"default": {
"properties": {
"route": {
"const": "review"
}
}
}
}
}
}
}
{
"checks": [
{
"id": "waterproof",
"description": "True if the product is waterproof; false otherwise."
},
{
"id": "hooded",
"description": "True if the product has a hood; false otherwise."
}
]
}
Before you run this example
Call https://api.blatent.ai from your server. Set your API key in the same terminal where you run the example:
export BLATENT_API_KEY='YOUR_SERVICE_KEY'
Python requires Python 3.10+ and HTTPX:
python -m pip install "httpx>=0.28,<1"
TypeScript requires Node.js 24+ and uses its built-in fetch. The cURL examples require curl and jq.
Save the displayed files and the selected client in one directory. Run the client there with python example.py, node example.ts or bash example.sh. Downloads use the example's name in place of example.
- Python
- TypeScript
- cURL
import json
import os
from pathlib import Path
import httpx
request = {
"input": "A lightweight waterproof jacket with no hood.",
"schema": json.loads(Path("probability-checks.schema.json").read_text(encoding="utf-8")),
"state": json.loads(Path("probability-checks.state.json").read_text(encoding="utf-8")),
}
with httpx.Client(
base_url="https://api.blatent.ai",
headers={"Authorization": f"Bearer {os.environ['BLATENT_API_KEY']}"},
timeout=195,
) as client:
response = client.post("/v1/resolve", json=request)
response.raise_for_status()
print(json.dumps(response.json()["output"]))
import { readFileSync } from "node:fs";
const request = {
"input": "A lightweight waterproof jacket with no hood.",
"schema": JSON.parse(readFileSync("probability-checks.schema.json", "utf8")),
"state": JSON.parse(readFileSync("probability-checks.state.json", "utf8")),
};
const response = await fetch(
"https://api.blatent.ai" + "/v1/resolve",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BLATENT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(request),
signal: AbortSignal.timeout(195_000),
},
);
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(JSON.stringify((await response.json()).output));
set -eu
body=$(jq -n --argjson body '{"input":"A lightweight waterproof jacket with no hood."}' \
--slurpfile f0 'probability-checks.schema.json' \
--slurpfile f1 'probability-checks.state.json' \
'$body | setpath(["schema"]; $f0[0]) | setpath(["state"]; $f1[0])')
curl --fail-with-body --silent --show-error \
"https://api.blatent.ai/v1/resolve" \
-H "Authorization: Bearer $BLATENT_API_KEY" \
-H 'Content-Type: application/json' \
--data-binary "$body"
The template dialect expands the supplied checks before generation. Each result keeps its bound id, generates an answer, and applies its own 95% threshold to choose route. The local switch uses /answer for every item. Returned distributions use full output paths such as /0/answer and /1/answer; each route uses its corresponding item's distribution.
The list supplies the checks and their descriptions. It does not supply or invent the probabilities. Changing the list preserves the same template and reference rules.
Choose and evaluate your threshold
These are normalized preferences among the allowed candidates, not calibrated probabilities that an answer is correct. A 95% threshold is an example, not a recommended value for every task. Evaluate accuracy, review rate and failures on representative inputs, including confident mistakes.
Collecting a complete distribution can add inference work compared with choosing only an answer. Reuse a measured field for related routing rules, and measure latency with your actual candidates and branches. A threshold does not replace permission checks or trusted application facts.
Use candidate probabilities when you only need to inspect the distribution, output conditions for rules based on generated values, and state conditions for rules based on supplied facts. These downloadable examples use required Boolean decisions and finite routes. Other combinations still need to fit the service's supported schema forms.