Skip to main content

Exact totals

Use an arithmetic policy when a model must extract or propose values and a derived value must agree with them. The model handles interpretation; OPA enforces the calculation.

Here the input is “train ticket EUR 12.50; lunch EUR 7.50.” The answer contains the extracted amounts in cents and their total. The policy requires positive amounts and an exact sum.

Define the fields and the rule​

The schema bounds the number of items and requests integer cents. Rego's every checks each amount; sum checks their relationship to the total.

checked-sum.schema.json
{
"type": "object",
"properties": {
"amounts_cents": {
"type": "array",
"minItems": 1,
"maxItems": 8,
"description": "Extract each receipt amount in order as integer cents. EUR 12.50 means 1250. Do not include a separate total as a line item.",
"items": {
"type": "integer"
}
},
"total_cents": {
"type": "integer",
"description": "The sum of the extracted amounts, in integer cents."
}
},
"required": [
"amounts_cents",
"total_cents"
],
"additionalProperties": false
}
package totals

default allow := false

allow if {
every amount in input.output.amounts_cents { amount > 0 }
input.output.total_cents == sum(input.output.amounts_cents)
}

Extract and check​

This complete request needs only an API key, the schema and the policy. It has no state or permission dependency.

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": "Extract the amounts from this receipt: train ticket EUR 12.50; lunch EUR 7.50. Return the line amounts and their total in cents.",
"policy": {
"engine": "opa",
"entrypoint": "data.totals.allow",
"modules": {
"checked-sum.rego": Path("checked-sum.rego").read_text(encoding="utf-8"),
},
},
"policy_max_retries": 8,
"schema": json.loads(Path("checked-sum.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"]))

Illustrative output: {"amounts_cents":[1250,750],"total_cents":2000}.

CandidatePolicy result
[1250, 750], total 2000Allowed
[1250, 750], total 1999Denied
[-1, 2001], total 2000Denied: a line is not positive

What this does and does not check​

The policy guarantees the arithmetic relationship. It does not prove that every receipt amount was extracted correctly. A different set of positive amounts could also satisfy the sum. Evaluate extraction separately, or add checks against trusted source values when those are available.

For an example that checks extracted literals against the original prose and lets the model construct a formula, see Extract facts and calculate.

If all amounts are already known and summing is the entire task, calculate the answer in ordinary code. This pattern is useful when interpretation is necessary and calculation errors must not reach the caller.

Struct may revisit a failed candidate within its retry budget. If it cannot find a compliant result, it returns an error. See policy recovery.