# Request options

Options on `POST /v1/systemone` beyond `state`, `questions`, `model` and `subject`. Each says what it costs.

## `quality`: speed or accuracy

```json
{"quality": "fast"}        // the default: the engine alone
{"quality": "balanced"}    // the answers the engine is least sure of are answered again by the second tier
{"quality": "best"}        // most answers are answered again
```

Above `fast`, every answer gets `right_probability`: Jepela's estimate that the engine's answer is right, from the answer's probabilities, the kind of question and how much of the state the engine read. An answer below the level's cut-off (0.47 for `balanced`, 0.91 for `best`) is answered again by the second tier, a larger and slower model that is sent the state as text (memory and computed facts first; of an array whose oldest elements Jepela left out, the same elements, so the second tier's answer and `first` are about the same text) and the same question, and reads it with its own window, not the engine's. At both levels two kinds of answer always go on: one whose state the engine could not read in full, and every answer of a decision that read remembered lines or computed facts, because connecting such a fact to the situation is where the engine is weakest. The second tier's answer replaces the engine's, which stays beside it as `first`, and has `tier: 2`. The response's `quality` gives the `level`, the cut-off `below`, the questions `asked_again` and, per question, `why`: `unsure`, `cut` or `memory`.

If the second tier does not answer within its time budget (1 second), is busy or fails, the decision is still answered: those questions keep the engine's own answer, marked `tier: 1`, and `quality.fallback` gives the `questions` and the `reason`, for example "the second tier did not answer within 1 s". `asked_again` still lists every question that was sent on.

Measured on 2,503 public benchmark questions with known answers (choices, scores and yes/no; 2026-09-30), the half of the benchmark not used to set the cut-offs:

| `quality` | Right | Answered again |
|---|---|---|
| `fast` | 64.6% | none |
| `balanced` | 81.8% | 31.4% |
| `best` | 92.3% | 88.6% |

Sending every answer on was right as often as `best` (92.3%), so `best` leaves the answers the engine is surest of with the engine. How many answers go on depends on your questions.

A level's extra time is the second tier's time on the answers it takes; `usage.engine_ms` includes it, so your own traffic shows what a level adds. `fast` is the engine as it always was.

A temperature fitted on your labels (see Quality) is fitted on, and applied to, the engine's own answers; the second tier's answers keep their probabilities. The quality report scores the answer you received, whichever tier gave it. `balanced` and `best` are billed as `fast` is; `usage.tier2_questions` counts the answers the second tier gave and `usage.tier2_input_tokens` the tokens it read for them. `balanced` and `best` need the second tier: where it is not running, the request is refused with a 422 that says so. `fast` works everywhere.

## `method`: how choice questions are answered

```json
{"method": "auto"}      // the default: choices of more than 20 options are matched, the rest go to the engine
{"method": "engine"}    // the engine reads every option; above 20 options in two rounds
{"method": "match"}     // every choice question is matched, whatever its size
```

Matching turns the state (with its memory lines first) and each option's description into vectors and picks the closest option; the options are turned into vectors once and cached, while the state and its memory lines are turned into a vector for that call only and not kept. Each answer says which method produced it (`"method": "match"` or `"engine"`), matched answers carry `similarity` (the best and second-best cosine), and `usage.match_questions` counts them. Scores and yes/no questions always go to the engine, and `"method": "match"` on a request without a choice question is a 422. Measured on 2026-09-27 on BANKING77 (600 bank messages, 77 intents), on a GPU test server: matching 65.2% right in a median of 12 ms and 23 tokens billed; the engine reading all 77 options 62.2% in 57 ms and 812 tokens (see Choice). A matched question is billed for the tokens it read: the state and memory lines, not the options. The matching model reads at most 512 tokens (its search prefix and two special tokens included): a string or an object from its start, an array as the engine reads it, its newest elements (see Choice); a matched question's `reading` has `method` `match` and says what it read, and a state it did not read whole brings the `state_cut` warning. Windows do not apply to a matched question.

## `robust`: answers that do not depend on the option order

```json
{"robust": true}                 // three orders
{"robust": {"orders": 5}}        // one to five
```

The engine's answer to a choice moves when its options are reordered. With `robust`, Jepela asks each choice in fixed orders built from the sorted option names and averages them, so your order no longer matters. The answer has `orders` and `agreement`, the share of orders that picked the winner; a low agreement is a question to look at. A 2-option choice has 2 orders. Scores, yes/no questions and choices of more than 20 options (matched, or answered in two rounds with `method: "engine"`) are not reordered and are billed once. Billed per order used. Measured: six caller orders of the same options gave one answer every time, agreement 1.0 (measured through the gateway, 2026-09-23).

## `windows`: long states

```json
{"windows": true}
{"windows": {"combine": {"fraud": "max", "tone": "mean"}}}
```

The engine reads about 475 tokens of state on the English checkpoint (see State). With `windows`, a state that is cut is read in overlapping windows (neighbours share 32 tokens), at most 16; a longer state is read up to the 16th window, `windows.covered_all` is false and the `state_cut` warning stays. Windows read a string or an object from its start; an array too long for 16 windows is read from its end, so the windows keep its newest elements, as one pass does (see State). Every window has the memory and computed lines in front of it. Answers are combined per question: by default the highest yes for a noul, the highest level for a score, and the most confident window for a choice (`min` does the same for a choice; `mean` averages). A state that is not cut is read once, as without `windows`. The answer's `windows` has `count`, `covered_all`, `state_tokens` and `tokens_per_window`, and each answer's `window` names the window it came from (null with `mean`). Measured: a card number past the cut moved a yes/no answer from 0.00 to 1.00 (3 windows, measured through the gateway, 2026-09-23). Billed per window.

## `derive` and `values`: facts computed in code

The engine does not do arithmetic or dates. Compute them in code and show the engine the result:

```json
{"state": {"pump": "pump-13", "reading": {"bearing_temperature_c": 78}},
 "values": {"limit": 75},
 "derive": {"over": "reading.bearing_temperature_c > limit",
            "limit": {"when": "reading.bearing_temperature_c > limit",
                      "fact": "Pump-13 is above its bearing temperature limit right now; a technician must look at pump-13 today and a maintenance ticket is required."}}}
```

Expressions read `values` and the state's fields. A bare name (`limit`) is read from `values` first and from the state only when `values` has no such field, so a field of the state, which may come from someone else, never replaces a value you send; `values.limit` and `state.limit` name one of them. Expressions may use comparisons, `and`/`or`/`not`, arithmetic and the functions `days_since`, `days_between`, `len`, `lower`, `contains`, `number`, `abs`, `min`, `max`, `round`; nothing else runs. `days_since` counts from `values.today` when it is sent, otherwise from the server's date. A number written in text (`"USD 1,250.00"`, `"78 C"`) is compared as a number: the first number in the text, with a minus sign only where it is not a hyphen in a name (`"pump-13 reads 78"` is 78). Jepela is English-first. When a number has one kind of separator, a comma before exactly three digits separates thousands (`1,250` is 1250, `100,000` is 100000) and a dot is the decimal point (`1.250` is 1.25), also at the start of a number (`.5` is 0.5, `-.5` is -0.5, `$.99` is 0.99). Scientific notation is read when the exponent is attached to digits with at most one dot and ends the word (`1.5e3` is 1500, `2E-4` is 0.0002, `6.02e23`); `5e`, `e3` and a code such as `4e3x` hold no exponent (`item 5e` is 5), and `1,250e3` or `1.5e3.2` is not one number. The European way is read only when the number shows it: both a dot and a comma (`EUR 2.500,00` is 2500, `1.234.567,89`), a comma before one or two digits (`1,25` is 1.25), dots between thousands (`1.234.567`), or spaces between thousands with a decimal comma (`1 250,00` is 1250). An apostrophe or a narrow space between thousands (`1'234.50`) and the Indian grouping (`1,23,456`) are read too. What is not one number is not read: a date (`16.10.2026`, `2026-10-16`), a range (`5-10`), or digits with a plain space and no decimal comma (`1 250` may be one number or two). Then the `derive` is refused with a 422 that says why and a rule is skipped with a `rule_broken` warning, rather than a false fact. Tip: to be sure of a number, send it in `values` as a JSON number (`{"total": 1250}`); a number is read from text only when the field holds text. A plain expression adds a line such as `over is true: reading.bearing_temperature_c > limit, where reading.bearing_temperature_c is 78, limit is 75.`; a `when` form adds its `fact` (or `else`) only as the condition says. The lines are placed first: under `Computed by the system:` in a text or array state, as a `computed_facts` key in an object state (an array that is too long would lose them first, as it is cut from its start, so Jepela leaves out its oldest elements instead and `reading.turns_dropped` says how many; see State); `derived` in the answer lists every value. Measured with the `when` form above and a choice ignore / log / ticket / stop: at 78 °C p(ticket) went from 0.09 to 0.81 on the English checkpoint (0.19 to 0.52 on typed-decisions); at 70 °C the condition is false, no fact is added, and the answer stays at 0.09 (measured through the gateway, 2026-09-23). The same expressions drive memory rules (see Rules in memory). Free.

Limits: at most 20 `derive` names, each starting with a letter, with at most 40 letters, digits or underscores; an expression has at most 300 characters, a `fact` or `else` at most 500; `values` is an object of at most 50 fields; a number beyond about 10^308, written in the expression or in text or given by arithmetic, is refused, and `round` takes at most 308 digits either way. A `derive` that cannot be evaluated on the request (a field it reads is missing, a number it compares cannot be read) is refused with a 422 that says why.

## `cache`: identical requests

```json
{"cache": true}
```

An identical request (same state, questions, model and options) from the same account that does not use a subject's memory returns the stored answers without new engine work; `usage.cached` says so. The cache holds the engine's answers (probabilities and option names), never the state, in the gateway's memory, never on disk:

- **Only for the same engine.** An answer is stored under the engine's build (the hash of its code, its device and its precision), and a repeat is looked up under the build the engine showed last: every engine answer shows it, and when the last look is 30 seconds old the gateway asks the engine's health check (no engine work, at most every 30 seconds). So once an engine change is seen, the next request is asked of the engine again, and no answer of the build before is given.
- **While the engine is briefly away.** A repeat is still answered from the cache, by the build seen last, with the build that gave the answer in `engine.runtime.version`; a request the cache does not hold fails with 502 as before. After a restart of the gateway, the cache is used once the engine has been seen.
- **At most 24 hours.** An answer is served for at most 24 hours after the engine gave it, and at most the gateway's 2,000 most recently used answers are kept. A restart empties the cache.
- **Deleted with your records.** `POST /v1/decisions/delete` removes your cached answers at once; those of a deleted account go within the hour.

Billed like the first call.

## `memory`

`use`, `top_k`, `min_share`, `names`, `question_words`, `focus`, `compare`, `explain` and `placebo`: see Memory. Only the answer you asked for is billed; the extra passes of `compare`, `explain` and `placebo` are free.

## Not accepted

`context` is refused with a 422: Jepela builds the context from the subject's memory and `derive`; send those instead.

`assets` and `images` (pictures), in the request or in a question, are refused with a 422 when they hold anything, and nothing is charged: Jepela reads text only, so describe what a picture shows in the state. Any other field Jepela does not read, at the top of the request, in `memory` or in a question (whose fields are `type`, `instructions` and `criteria`, as TypeSafe documents them), is answered as usual without it, and the answer has an `unknown_field` warning naming it and the closest field Jepela reads ("unknown field subjet; did you mean subject?"). Check `warnings` after a change to your request: a misspelt `subject` is a decision without memory.

## The limit per request

A request may need at most 400 engine questions, counting one per question, one per option order of a robust choice, and for a choice of more than 20 options read by the engine one per group of 20 plus one for the final round; a matched choice is not an engine question. Above that the request is refused with a 422 that says how many it needed.
