simodocs

Asking questions

Question types

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 Decision A statement is true or false noul: P(true)
Choice Decision One of several options applies choice, probabilities
Score Decision Something sits on an ordered scale score: expected level
Fill Read (preview) A value has to be written or computed value, parsed
Extract Read (preview) A value appears verbatim in the input value or values
Locate 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.

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"})

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.

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"})

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:

"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"}

Score: a level on a scale

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

from simoai import Score

"mood": Score("How upset is the customer?", ["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.

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),
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.

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"]

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.

from simoai import Locate

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

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"}