Workflows
A workflow is several typed fields answered in one call, where later fields can use earlier answers, and run only when they apply. This page builds one for a support ticket, a step at a time.
Start with the context
The context is the input the workflow works on: here, the customer's ticket. Pass it once, as context. Every field reads it, at every step, so you never list it in depends_on; the fields below only name the other fields they need.
ticket = "I was charged twice for my Pro upgrade ($49 each). My renewal is tomorrow. Please fix this today."1. Ask independent questions in parallel
Fields run in parallel by default. Each reads the context on its own, without seeing the other answers.
response = client.generate(context=ticket, questions={
"category": {
"type": "string",
"enum": ["billing", "technical", "account"],
"instructions": "Which team should handle this ticket?",
},
"urgent": {"type": "boolean", "instructions": "Does it need an answer today?"},
})2. Ask questions that depend on earlier answers
A field with depends_on runs after the fields it names, and sees their answers along with the context. handling_advice waits for category and urgent, so its advice follows from them.
response = client.generate(context=ticket, questions={
"category": {
"type": "string",
"enum": ["billing", "technical", "account"],
"instructions": "Which team should handle this ticket?",
},
"urgent": {"type": "boolean", "instructions": "Does it need an answer today?"},
"handling_advice": {
"type": "string",
"instructions": "Suggest next steps for the support agent. Do not claim actions were already taken.",
"depends_on": ["category", "urgent"],
},
})TypeLLM works out the order from depends_on: fields with no inputs pending run together, layer by layer. Results come back in the order you declared them.
- A field without
depends_on, or withdepends_on=[], reads only the context. - A field can depend on several fields, which may be declared later in the input.
- Unknown names, duplicate dependencies, self-dependencies and cycles are rejected before inference.
3. Ask a question only when a condition is met
A refund amount means something for a billing issue, not a bug report. A field with when runs only if earlier answers pass its condition. Otherwise it is skipped: it has no key in result, and response.skipped lists it.
response = client.generate(context=ticket, questions={
"category": {
"type": "string",
"enum": ["billing", "technical", "account"],
"instructions": "Which team should handle this ticket?",
},
"urgent": {"type": "boolean", "instructions": "Does it need an answer today?"},
"handling_advice": {
"type": "string",
"instructions": "Suggest next steps for the support agent. Do not claim actions were already taken.",
"depends_on": ["category", "urgent"],
},
"refund_amount": {
"type": "number",
"instructions": "How much should be refunded, in dollars?",
"when": {"category": "billing"},
},
})For the double charge, category is billing, so refund_amount runs:
For a broken export button, category is technical, so refund_amount is skipped:
ticket = "Since this morning's update, the export button does nothing. I need the report for a meeting on Friday."The fields when names are dependencies, whether or not depends_on lists them, so a conditional field also sees their answers.
Conditions
when maps other fields to a condition on their answers:
"when": {"category": "bug"} # equals
"when": {"category": ["bug", "incident"]} # one of; also {"in": [...]}
"when": {"category": {"not_in": ["feature_request"]}} # none of
"when": {"quantity": {"ne": 0}} # not equal
"when": {"amount": {"gte": 1000}} # gt, gte, lt and lte compare numbers
"when": {"score": {"gt": 0, "lte": 60}} # several operators: all must pass
"when": {"tip": {"ne": None}} # not null- With several fields, every condition must pass.
- Values must be answers the field can give: an enum value,
TrueorFalse, a number, orNonefor a nullable field. Text fields can only be compared withNone. gt,gte,ltandltework on number fields only, and aNoneanswer fails them.- Fields that depend on a skipped field are skipped too, even when their other dependencies ran.
- Conditions run in code on the typed answers, so they add no requests. A skipped field costs only its definition in the call's input tokens.
- An unknown operator, a value the field cannot give, or a condition on an unknown field is rejected before inference.
All in one call
Each example above is one request. TypeLLM runs the layers on the server, checks the conditions between them, and returns every answer together, typed. Your code does not parse one answer to build the next request, and the ticket is read once.