Branch on the state¶
when() sends the run to one of two nodes and branch() to one of several, depending on the state after a node.
When you need it¶
Use a route when what runs next depends on a node's result: an urgent ticket, the language of a message, or a category.
Steps¶
- Write a router: a function of the state that returns a
boolforwhen(), or a key forbranch(). - For two targets, put
a >> when(router, target, otherwise=other)inflow(). - For more targets, put
a >> branch(router, {key: node, ...})inflow(); a mapping value may beEND. - Give every target its own way out, such as
target >> END. - Check the routes with
graph.to_mermaid().
Complete example¶
classify sets the topic of a support ticket, and branch() sends the ticket to one of three queues:
from nodestep import END, START, BaseState, Graph, branch, node
class Ticket(BaseState):
text: str = ""
topic: str = ""
queue: str = ""
@node
def classify(state: Ticket) -> dict:
text = state.text.lower()
if "invoice" in text:
return {"topic": "billing"}
if "error" in text:
return {"topic": "bugs"}
return {"topic": "other"}
@node
def billing(state: Ticket) -> dict:
return {"queue": "billing team"}
@node
def bugs(state: Ticket) -> dict:
return {"queue": "engineering"}
@node
def front_desk(state: Ticket) -> dict:
return {"queue": "front desk"}
def by_topic(state: Ticket) -> str:
return state.topic
routes = {"billing": billing, "bugs": bugs, "other": front_desk}
graph = Graph(Ticket, name="support").flow(
START >> classify,
classify >> branch(by_topic, routes),
billing >> END,
bugs >> END,
front_desk >> END,
)
for text in ["Where is my invoice?", "The app shows an error", "Do you ship to Oslo?"]:
result = graph.invoke({"text": text})
print(f"{text} -> {result.state.queue}")
Where is my invoice? -> billing team
The app shows an error -> engineering
Do you ship to Oslo? -> front desk
The router reads the state after classify has run. graph.to_mermaid() draws the flow, with the keys as labels:
graph TD
START([START])
classify["classify"]
START START-classify@--> classify
billing["billing"]
billing billing-END@--> END([END])
bugs["bugs"]
bugs bugs-END@--> END([END])
front_desk["front_desk"]
front_desk front_desk-END@--> END([END])
classify classify-billing@-->|"billing"| billing
classify classify-bugs@-->|"bugs"| bugs
classify classify-front_desk@-->|"other"| front_desk
Good to know¶
- A key that is not in the mapping fails the run, with no fallback (Rules and defaults).
- A
when()predicate must return abool; anything else raisesGraphExecutionErrorwhen the run gets there (Rules and defaults). - A target without a way out raises
GraphConfigErrorwhenflow()runs (Rules and defaults). - A node can also choose its next step by returning
Command(goto=...)(Graphs and flow).