Choice questions, each of which returns one value. Here it runs on
a small cafe menu and one hard-coded order.
How the cart builder works
The input is one sentence:Choice question returns one option, not a whole cart. The application therefore uses
two stages:
- Find the items. Repeatedly ask which remaining menu item the order mentions.
Remove each selected item from the next request. Stop when Jev selects
nothing_else. - Fill the fields. For each found item, send one request with a
Choicequestion per known field. Your code assembles the returned values into the cart.
Finding an unknown number of items with a loop
The number of ordered items is not known in advance. Each request asks which remaining menu item appears first in the order. The loop in your code then:- saves the selected item;
- removes it from the next request’s options; and
- sends the full order again with the shorter option list.
Choice question must select an option, so every request also includes
nothing_else. That option tells the loop to stop when the order contains no remaining
menu item.
Filling the known fields
After the item loop, the application knows which schema applies to each item. The latte schema hassize and milk fields. The application sends both field questions to Jev in
one request. The muffin has no fields, so it needs no field request.
Setup
TYPESAFE_API_KEY. Every API call is cached in
json_cache.json.
Download it into the folder you run this code from to replay the published numbers
instead of calling the API, or leave it out to run everything live.
Numbers below came from jev-1.14.0 on 2026-10-29.
Creating the menu
The menu has four items, and only the latte has fields. Each item’s description carries the words a customer would use to order it. Jev matches the order against these descriptions.fields is the item’s own schema. Each field is a
list of allowed values, and those values are the options of that field’s Choice question.
Finding the items in the order
Before each request, the loop builds a fresh option set from the items not yet found and adds thenothing_else sentinel. The order
is the request’s state, and the question changes from one request to
the next. The loop stops when nothing_else is selected.
The loop also caps its requests, so a bad answer can never make it loop forever. It ends
when the sentinel is selected, the menu runs out, or the cap is reached.
latte. To handle quantities, add a quantity field to each item’s schema,
with values such as one, two and three.
Filling in a found item’s fields
For each found item, we build oneChoice question per known field and send them together
in one system_one call against the same order. This is the
fan-out pattern.
Each field question also includes unspecified, so a field the customer did not mention
gets that option instead of a forced concrete value.
An item with no fields skips the call entirely.
The assembled cart
This step makes no TypeSafe calls. It prints the cart assembled from the single-value answers collected above.Try it in the playground
The link below holds the first item-finding request: the full order as the state, and oneChoice question over the four menu items plus nothing_else. The loop above repeats
that request, each time without the item it just found. Edit the order there and the
answer changes with it.
What’s next
- Primitives is the reference for the question types and the fields each answer carries.
- The parallel questions cookbook measures what sending the field questions in one request saves against asking them one at a time.
- The function calling cookbook turns a sentence into a call
to one of your own functions the same way: one
Choicequestion picks the function, and one per argument fills its values. It handles an argument the user didn’t mention with a separate yes/no question instead of anunspecifiedoption. - Confidence covers reading a confidence value as a signal.

