# Question types

Source: https://docs.temprl.org/guide/question-types

> The six Simo question types - Noul, Choice and Score for calibrated decisions, and Fill, Extract and Locate for typed values - with arguments and examples.

Every question has an id (its key in `questions`) and comes back as one answer under that id. **Decisions** pick among fixed answers with a calibrated probability for each. **Reads** write a value constrained to its type.

| Type | Family | Ask it when | Main answer field |
|---|---|---|---|
| [`Noul`](#noul-yes-or-no) | Decision | A statement is true or false | `noul`: P(true) |
| [`Choice`](#choice-one-of-several) | Decision | One of several options applies | `choice`, `probabilities` |
| [`Score`](#score-a-level-on-a-scale) | Decision | Something sits on an ordered scale | `score`: expected level |
| [`Fill`](#fill-write-a-value) | Read (preview) | A value has to be written or computed | `value`, `parsed` |
| [`Extract`](#extract-copy-from-the-input) | Read (preview) | A value appears verbatim in the input | `value` or `values` |
| [`Locate`](#locate-find-it-in-an-image) | Read (preview) | You need where something is in an image | `coordinates`, `center` |

## Noul: yes or no

A statement, answered with the probability that it is true. Phrase it as a statement, not a question.

**Python**

```python
from simoai import Noul

"done":  Noul("The task is finished")
"risky": Noul("The next action is risky",
              criteria={"true": "it deletes data or moves money", "false": "it only reads"})
```

**JSON**

```json
"done":  {"type": "noul", "instructions": "The task is finished"},
"risky": {"type": "noul", "instructions": "The next action is risky",
          "criteria": {"true": "it deletes data or moves money", "false": "it only reads"}}
```

`criteria` is optional: descriptions of what true and false mean, when the statement alone is ambiguous. The answer is `{"type": "noul", "noul": 0.97}`; in the SDK, `.result` is `noul >= 0.5`.

## Choice: one of several

Pick one option. Options are a map from the key you get back to a description that helps the model. 2 to 256 options.

**Python**

```python
from simoai import Choice

"team": Choice("Which team should handle this ticket?",
               {"billing": "refunds and payments",
                "shipping": "delivery and tracking",
                "tech": "website and app problems"})
```

**JSON**

```json
"team": {"type": "choice", "instructions": "Which team should handle this ticket?",
         "criteria": {"billing": "refunds and payments",
                      "shipping": "delivery and tracking",
                      "tech": "website and app problems"}}
```

The answer has `choice` (the most likely key), `probabilities` (one per option, summing to 1) and `confidence`.

### Arguments for a choice

A `Choice` can generate arguments for the option the model picked, in the same request. Only the chosen option's arguments are produced, which makes this the natural way to pick a tool call:

**Python**

```python
"next": Choice("What should the agent do next?",
               {"click": "click an element", "type": "type text", "stop": "the task is done"},
               args={"click": {"target": Extract("the element to click")},
                     "type":  {"text": Fill("the text to type", max_tokens=32)}})

r["next"].choice        # "click"
r["next"].arg_values    # {"target": "Sign up"}
```

**JSON**

```json
"next": {"type": "choice", "instructions": "What should the agent do next?",
         "criteria": {"click": "click an element", "type": "type text", "stop": "the task is done"},
         "args": {"click": {"target": {"type": "extract", "instructions": "the element to click",
                                       "kind": "text", "many": false, "max_tokens": 64}},
                  "type":  {"text": {"type": "fill", "instructions": "the text to type",
                                     "kind": "text", "max_tokens": 32}}}}
```

## Score: a level on a scale

A position on an ordered scale. Any number of levels, listed from lowest to highest.

**Python**

```python
from simoai import Score

"mood": Score("How upset is the customer?", ["calm", "annoyed", "angry", "furious"])
```

**JSON**

```json
"mood": {"type": "score", "instructions": "How upset is the customer?",
         "criteria": ["calm", "annoyed", "angry", "furious"]}
```

`score` is the **expected level**, 0-based: `2.4` on this scale sits between "angry" and "furious". `probabilities` has one entry per level, keyed by its index (`"0"`, `"1"`, …, with the names in `legend`), and `confidence` is the largest of them.

## Fill: write a value

Generate a short value: a number, a count, a summary, a code. Output is constrained to its type, so an `int` is always an integer and a `json_list` always parses.

**Python**

```python
from simoai import Fill

"amount":  Fill("the amount due, in dollars", kind="number"),       # parsed -> float
"count":   Fill("how many items are in the order", kind="int"),    # parsed -> int
"colors":  Fill("the colors mentioned", kind="json_list"),         # parsed -> list of strings
"code":    Fill("the discount code", pattern=r"[A-Z]{3}-\d{4}"),   # must match the regex
"summary": Fill("the customer's request in a few words", max_tokens=24),
```

**JSON**

```json
"amount":  {"type": "fill", "instructions": "the amount due, in dollars", "kind": "number", "max_tokens": 16},
"count":   {"type": "fill", "instructions": "how many items are in the order", "kind": "int", "max_tokens": 16},
"colors":  {"type": "fill", "instructions": "the colors mentioned", "kind": "json_list", "max_tokens": 16},
"code":    {"type": "fill", "instructions": "the discount code", "kind": "text", "pattern": "[A-Z]{3}-\\d{4}", "max_tokens": 16},
"summary": {"type": "fill", "instructions": "the customer's request in a few words", "kind": "text", "max_tokens": 24}
```

| Argument | Values | Default |
|---|---|---|
| `kind` | `text`, `int`, `number`, `json_list` | `text` |
| `pattern` | A regex the value must match (only with `kind="text"`) | none |
| `max_tokens` | 1 to 256 | 16 |

The answer has `value` (the text), `parsed` (the typed value), `valid` (whether it satisfied its type) and `confidence`. When `max_tokens` cuts a value short, `valid` can be `false`.

## Extract: copy from the input

Pull a value out of the state, verbatim where possible. With `many=True`, get every match as a list.

**Python**

```python
from simoai import Extract

"order":  Extract("the order number, exactly as written", max_tokens=8),  # value  -> "A-1042"
"orders": Extract("every order number mentioned", many=True),             # values -> ["A-1042", "B-2210"]
```

**JSON**

```json
"order":  {"type": "extract", "instructions": "the order number, exactly as written", "kind": "text", "many": false, "max_tokens": 8},
"orders": {"type": "extract", "instructions": "every order number mentioned", "kind": "text", "many": true, "max_tokens": 64}
```

`max_tokens` is 1 to 512 (default 64). In the wire format, `"list_format": "json"` makes a `many` extract come back from a JSON list instead of one item per line; the result is the same `values` list.

## Locate: find it in an image

Where something is in an image of the state. Needs an image in `media`.

**Python**

```python
from simoai import Locate

"pay_btn": Locate("the Pay button"),                 # in the first image
"change":  Locate("what changed", image=2),          # in the second image
```

**JSON**

```json
"pay_btn": {"type": "extract", "kind": "coordinates", "instructions": "the Pay button",
            "image": 1, "scale": "rel1000", "max_tokens": 64}
```

The answer has `coordinates` (a box `[x1, y1, x2, y2]`), `center` (`[x, y]`) and `image_size` (`[width, height]`), in pixels. When the thing is not visible, `coordinates` and `center` are `null`. The SDK maps answers back to the pixels of the image you passed in; over raw HTTP they are in the pixels of the image you sent.

| Argument | Meaning | Default |
|---|---|---|
| `image` | Which image, 1-based (the N of `<image:N>`) | 1 |
| `scale` | How coordinates are expressed to the model: `rel1000` (a 0-1000 grid) or `pixels`. The answer is in pixels either way | `rel1000` |
| `max_tokens` | Output budget | 64 |

## Plain dictionaries

Anywhere the SDK accepts a question object, a dict in the wire format works too, which is handy for questions stored in JSON files:

```python
{"type": "noul", "instructions": "The task is finished"}
{"type": "extract", "instructions": "every SKU", "kind": "text", "many": True, "list_format": "json"}
```
