Generate only when it applies
In Jev, every field is generated on its own. Its documentation puts it plainly: "every question is evaluated in parallel and in isolation against the same state."
Our last post went one step further: with depends_on, a later field sees the answers of earlier ones. But every field still ran. An earlier answer could change what a field said, never whether it was asked.
Now it can. With when, earlier answers decide which fields TypeLLM generates next, all in one API call.
Sort an email, then ask what that kind needs
An inbox gets invoices, meeting requests and job applications. Each needs something different: an amount, a date, a role. Ask one question first, what kind of email this is, and let its answer decide which follow-up runs:
from typellm import TypeLLMClient
client = TypeLLMClient(api_key="...")
response = client.generate(context=email, questions={
"kind": {"type": "string",
"enum": ["invoice", "meeting_request", "job_application"]},
"amount_due": {"type": "number", "when": {"kind": "invoice"}},
"meeting_date": {"type": "string", "when": {"kind": "meeting_request"}},
"role": {"type": "string", "enum": ["engineering", "design", "sales"],
"when": {"kind": "job_application"}},
})For an invoice ("Amount due: $1,240.00 by October 15"), the API returns:
response.result # {"kind": "invoice", "amount_due": 1240}
response.skipped # ["meeting_date", "role"]A meeting request takes the meeting branch instead and returns "meeting_date": "2026-10-14"; a job application returns its role. Each follow-up is a typed field of its own: a number, a string, an enum.
Why not just ask everything?
Typed outputs always return a value in the field's type, even when the question makes no sense. Asked of the same invoice without when, the follow-ups for a meeting date and a job role came back as the string "null" and "engineering": well-typed, and meaningless. With when, those fields are skipped instead: they have no key in the result, and response.skipped lists them.
What a condition can test
when maps earlier fields to a test of their answers:
"when": {"kind": "invoice"} # equals
"when": {"kind": ["invoice", "receipt"]} # one of
"when": {"kind": {"not_in": ["spam"]}} # none of
"when": {"amount": {"gte": 1000}} # gt, gte, lt, lte
"when": {"score": {"gt": 0, "lte": 60}} # all must pass
"when": {"tip": {"ne": None}} # not null- No
depends_onneeded. The fields a condition names become dependencies, so the field also sees their answers. - Skips carry on. A field that depends on a skipped field is skipped too: its input does not exist.
- Mistakes fail early. A misspelt option, a comparison on a text field or an unknown field is an error before anything runs.
Why one call, not your own code?
You could do this yourself: call once to classify, read the answer, then call again with the right follow-up. Doing it in one call is better in four ways.
- The email is read once. Every step continues from the same cached prefix, so the email is processed once, not once per call.
- It is billed once. The TypeLLM API bills what you send in a call, counting the context once. Two calls send, and pay for, the email twice.
- No glue code. No parsing the first answer, no
if, no second request to build. The branch lives in the schema, and the answers come back together, withskippedsaying what did not apply. - No round trip in the middle. The condition is checked between steps on the server, so your code never waits on a first answer just to send a second request.
Try it
when is in TypeLLM 0.5.1 and the TypeLLM API. Run the email example in the playground or read the conditional fields docs.