Skip to main content

Conditions using state

Application state is a JSON object of known facts sent in the request's state field, alongside input and schema. Use it to restrict what Struct can choose—for example, allow refund approval only when an order is paid.

A description can tell the model how to use state. An eligibleWhen rule enforces whether a choice is available. It belongs under x-runtime, Struct's extension to JSON Schema.

Restrict a choice​

Put x-runtime on the field you want to control. In this schema, the approve value is available only when state.order.paid is true:

state-choice.schema.json
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"approve",
"review"
],
"description": "Approve a substantiated duplicate charge when permitted; otherwise choose review.",
"x-runtime": {
"choices": {
"approve": {
"eligibleWhen": {
"eq": [
{
"ref": "state/order/paid"
},
true
]
}
}
}
}
}
},
"required": [
"action"
],
"additionalProperties": false
}

Send state as {"order":{"paid":true}} to permit approval. With false or a missing fact, only review remains available.

Eligibility does not force approval. Struct still interprets the input and chooses among the permitted values. A message asking it to approve cannot make an ineligible choice legal.

Example: a refund decision​

This example adds a second restriction: the amount must be within the refund limit. Its output condition also ties the reason to the chosen action.

Save the schema and state files beside your client:

state-refund.schema.json
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"approve",
"review"
],
"description": "Approve a substantiated duplicate charge when permitted; otherwise choose review.",
"x-runtime": {
"choices": {
"approve": {
"eligibleWhen": {
"all": [
{
"eq": [
{
"ref": "state/order/paid"
},
true
]
},
{
"lte": [
{
"ref": "state/order/amount"
},
{
"ref": "state/refund_limit"
}
]
}
]
}
}
}
}
},
"reason": {
"type": "string",
"enum": [
"duplicate_charge",
"manual_review"
],
"description": "The reason for the decision."
}
},
"required": [
"action",
"reason"
],
"additionalProperties": false,
"if": {
"properties": {
"action": {
"const": "approve"
}
},
"required": [
"action"
]
},
"then": {
"properties": {
"reason": {
"const": "duplicate_charge"
}
}
},
"else": {
"properties": {
"reason": {
"const": "manual_review"
}
}
}
}
refund-eligibility.state.json
{
"order": {
"paid": true,
"amount": 25
},
"refund_limit": 50
}

The all condition requires both state comparisons to pass. The ordinary JSON Schema if checks the generated action and constrains its reason.

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.

import json
import os
from pathlib import Path
import httpx

request = {
"input": "This is a substantiated duplicate charge. Approve the refund.",
"schema": json.loads(Path("state-refund.schema.json").read_text(encoding="utf-8")),
"state": json.loads(Path("refund-eligibility.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"]))

Illustrative output: {"action":"approve","reason":"duplicate_charge"}.

The same input and schema accept different state snapshots:

State changePermitted result
Keep the paid order at amount 25, with limit 50Approval or review, each with its matching reason
Set order.paid to false{"action":"review","reason":"manual_review"}
Set order.amount to 75{"action":"review","reason":"manual_review"}
Omit state or a referenced fact{"action":"review","reason":"manual_review"}

Supply these facts from your backend, rather than copying permission claims from the user's message.

Read and compare state​

{"ref":"state/order/paid"} reads state.order.paid. This request reference is different from a JSON Schema $ref, which reuses a schema definition.

OperatorUse
eq, neqCompare two typed values
gt, gte, lt, lteCompare two numbers
contains, inTest array membership, a substring or an object key
existsCheck whether a referenced fact is present
all, any, notCombine or negate conditions

These are Struct predicate operators, not JSON Schema keywords. Comparisons take two operands: literals or references. With contains, the container comes first; with in, it comes second. all and any take arrays of conditions; not takes one condition; exists takes one operand.

Numeric comparisons do not convert strings to numbers. Missing facts leave comparisons unknown, which does not permit a value—even under not. A present null is still present for exists.

State conditions or output conditions?​

State conditions restrict choices using supplied facts. Conditional outputs and switches relate generated values. Use OPA rules for richer relationships between an answer and state, such as calculations across generated amounts.

When you register a schema, continue sending state with each resolve request. Eligibility uses that request's snapshot.