flowinquiry v1examples/inquiry/temporal/inquiry.flow · dandori doc
A decision model picks the kind of a customer's inquiry and says how sure it is; an agent reads the inquiry for an order number and its point, and for its kind too, which the flow takes when the decision model is not sure enough of its own. A rule decides the desk that takes it and how soon it is answered; another agent drafts the first reply; and a ticket goes into the desk's system. The decision model picks, agents read and write (models the company runs itself pick and read, Claude writes), and the rule decides. Written for Temporal: the decision and the agents are activities dandori writes; the kind is asked at a server of the System One API, the API of TypeSafe's Jev (`url`; here the company's Ollama), the reading is sent to a server of Open Responses (`url`; the same Ollama), and the draft to Claude with the key the worker has; the rule runs in the worker of the workflow as a local activity, its answer kept in the history as a marker; and filing the ticket is an activity you write
flow| Line | Call | Calls | Retries | Timeout | When it fails |
|---|---|---|---|---|---|
| 66 | reading = read_inquiry(…) | agent · gpt-oss:20b · http://ollama.internal:11434/v1 | 2 times every 10 seconds (failure, timeout) | 1 minute | timeout, failure → line 67 |
| 68 | by_hand = file_ticket(…) | a task you write, key | 2 times every 5 seconds (failure, timeout) | — | timeout, failure → the workflow fails |
| 71 | kind = pick_kind(…) | jev · nimble:9b-q4_K_M · http://ollama.internal:11434/v1 · confidence 0.8 else unsure | 2 times every 1 second (failure, timeout) | 10 seconds | unsure, timeout, failure → line 72 |
| 73 | decision = routing(…) | rule inquiry_routing.rule, a local activity on Temporal | 2 times, after 1 second and 2 (failure, timeout) | 10 seconds | timeout, failure → the workflow fails |
| 78 | draft = draft_reply(…) | agent claude · claude-sonnet-5 | — | 1 minute | timeout, failure → line 79 |
| 80 | t = file_ticket(…) | a task you write, key | 2 times every 5 seconds (failure, timeout) | — | timeout, failure → the workflow fails |
| Line | End |
|---|---|
| 69 | succeed ticket_id = by_hand.ticket_id, desk = general |
| 81 | succeed ticket_id = t.ticket_id, desk = decision.desk |
Pick a step to see what the checker knows there. Pick a scenario on the left to light up the way its run goes; the number beside a step is how often the run passes it.
inquiry v1A decision model picks the kind of a customer's inquiry and says how sure it is; an agent reads the inquiry for an order number and its point, and for its kind too, which the flow takes when the decision model is not sure enough of its own. A rule decides the desk that takes it and how soon it is answered; another agent drafts the first reply; and a ticket goes into the desk's system. The decision model picks, agents read and write (models the company runs itself pick and read, Claude writes), and the rule decides. Written for Temporal: the decision and the agents are activities dandori writes; the kind is asked at a server of the System One API, the API of TypeSafe's Jev (`url`; here the company's Ollama), the reading is sent to a server of Open Responses (`url`; the same Ollama), and the draft to Claude with the key the worker has; the rule runs in the worker of the workflow as a local activity, its answer kept in the history as a marker; and filing the ticket is an activity you write
inquiry: Inquiryticket_id: string, desk: routing.deskexamples/inquiry/temporal/inquiry.flowreading = read_inquiry(…) line 6666 let reading = read_inquiry(text: inquiry.text) 67 on failure =>
agent · gpt-oss:20b · http://ollama.internal:11434/v1timeout, failure → line 6743 # A model on the company's own Ollama reads the text, through Open Responses; the schema of 44 # Reading holds its answer to one of the rule's kinds. 45 task read_inquiry(text: string) -> Reading 46 agent "Read the text of a customer's inquiry, choose its kind, take out the order number if one is written, and sum up its point in one sentence. If no order number is written, give null." 47 model "gpt-oss:20b" 48 effort low 49 url "http://ollama.internal:11434/v1" 50 plaintext "The model server is reached only inside the cluster network, which the service mesh encrypts" 51 timeout 60 seconds 52 retry 2 times every 10 seconds
by_hand = file_ticket(…) line 68 68 let by_hand = file_ticket(inquiry_id: inquiry.id, desk: general, within: 24, subject: "An inquiry that could not be read", text: inquiry.text, draft: none)
keytimeout, failure → the workflow fails60 # The ticket goes into the desk's system through its client library, in code you write. 61 task file_ticket(inquiry_id: string, desk: routing.desk, within: duration[h], subject: string, text: string, draft: string?) -> Ticket 62 key 63 retry 2 times every 5 seconds
succeed ticket_id = by_hand.ticket_id, desk = general line 69 69 succeed ticket_id = by_hand.ticket_id, desk = general
kind = pick_kind(…) line 7171 let kind = pick_kind(text: inquiry.text) 72 on unsure, failure => let kind = reading.kind
jev · nimble:9b-q4_K_M · http://ollama.internal:11434/v1 · confidence 0.8 else unsureunsure, timeout, failure → line 7227 # A decision model on the company's own Ollama picks one of the rule's kinds, knowing what each 28 # means, and says how sure it is, through the System One API; the model is named with its tag, so 29 # that it does not move to another one, whose answers would be sure in another way. 30 task pick_kind(text: string) -> routing.kind 31 jev "Which kind of inquiry is this?" 32 returns "The customer wants to send an item back or exchange it" 33 delivery "A parcel is late, lost or damaged, or the customer asks where it is" 34 billing "A charge, an invoice, a payment or a refund" 35 other "None of the above" 36 model "nimble:9b-q4_K_M" 37 url "http://ollama.internal:11434/v1" 38 plaintext "The model server is reached only inside the cluster network, which the service mesh encrypts" 39 confidence 0.8 else unsure 40 timeout 10 seconds 41 retry 2 times every 1 second
let kind = reading.kind line 72 72 on unsure, failure => let kind = reading.kind
decision = routing(…) line 73 73 let decision = routing(kind: kind, member: inquiry.member)
inquiry_routing.rule, a local activity on Temporaltimeout, failure → the workflow fails4 use rule routing from "../rules/inquiry_routing.rule" 5 local
let subject = "An inquiry about {kind}" line 74 74 let subject = "An inquiry about {kind}"
match reading.order_id line 7575 match reading.order_id 76 some order_id => let subject = "An inquiry about {kind} (order {order_id})" 77 none => pass
let subject = "An inquiry about {kind} (order {order_id… line 76 76 some order_id => let subject = "An inquiry about {kind} (order {order_id})"
draft = draft_reply(…) line 7878 let draft = draft_reply(kind: kind, point: reading.point, order_id: reading.order_id, within: decision.within) 79 on failure => let draft: string? = none
agent claude · claude-sonnet-5timeout, failure → line 7954 task draft_reply(kind: routing.kind, point: string, order_id: string?, within: duration[h]) -> string 55 agent claude "Draft the first reply to the inquiry, politely, in three sentences at most. `within` is the number of hours before the reply is due. Promise nothing that cannot be kept." 56 model "claude-sonnet-5" 57 effort medium 58 timeout 60 seconds
let draft = none line 79 79 on failure => let draft: string? = none
t = file_ticket(…) line 80 80 let t = file_ticket(inquiry_id: inquiry.id, desk: decision.desk, within: decision.within, subject: subject, text: inquiry.text, draft: draft)
keytimeout, failure → the workflow fails60 # The ticket goes into the desk's system through its client library, in code you write. 61 task file_ticket(inquiry_id: string, desk: routing.desk, within: duration[h], subject: string, text: string, draft: string?) -> Ticket 62 key 63 retry 2 times every 5 seconds
succeed ticket_id = t.ticket_id, desk = decision.desk line 81 81 succeed ticket_id = t.ticket_id, desk = decision.desk
end: succeedsThe flow runs to its end, and the workflow succeeds.
reading = read_inquiry(…) okkind = pick_kind(…) okdecision = routing(…) oklet subject = "An inquiry about {kind}"match reading.order_id → nonedraft = draft_reply(…) okt = file_ticket(…) oksucceed ticket_id = t.ticket_id, desk = decision.deskreading = read_inquiry(…) failure failure failure → on failureby_hand = file_ticket(…) oksucceed ticket_id = by_hand.ticket_id, desk = generalreading = read_inquiry(…) failure failure failure → on failureby_hand = file_ticket(…) failure failure failure → not handled herereading = read_inquiry(…) failure okkind = pick_kind(…) ok → on unsure, failurelet kind = reading.kinddecision = routing(…) failure failure failure → not handled herereading = read_inquiry(…) okreading = read_inquiry(…) okkind = pick_kind(…) ok → on unsure, failurelet kind = reading.kinddecision = routing(…) okreading = read_inquiry(…) okkind = pick_kind(…) failure okdecision = routing(…) okreading = read_inquiry(…) okkind = pick_kind(…) okreading = read_inquiry(…) okkind = pick_kind(…) okdecision = routing(…) oklet subject = "An inquiry about {kind}"match reading.order_id → some order_idlet subject = "An inquiry about {kind} (order {order_id…draft = draft_reply(…) failure → on failurelet draft = nonet = file_ticket(…) failure failure failure → not handled herereading = read_inquiry(…) okkind = pick_kind(…) okdecision = routing(…) oklet subject = "An inquiry about {kind}"match reading.order_id → nonedraft = draft_reply(…) failure → on failurelet draft = nonet = file_ticket(…) failure oksucceed ticket_id = t.ticket_id, desk = decision.deskreading = read_inquiry(…) okkind = pick_kind(…) okdecision = routing(…) oklet subject = "An inquiry about {kind}"match reading.order_id → nonedraft = draft_reply(…) okreading = read_inquiry(…) okkind = pick_kind(…) okdecision = routing(…) oklet subject = "An inquiry about {kind}"match reading.order_id → nonedraft = draft_reply(…) okt = file_ticket(…) okreading = read_inquiry(…) failure failure failure → on failureby_hand = file_ticket(…) failure oksucceed ticket_id = by_hand.ticket_id, desk = generalreading = read_inquiry(…) failure failure failure → on failureby_hand = file_ticket(…) ok