2. Basic Flow Definition¶
2.1. Flows are like plugins¶
They are defined by a
.flow file, similar to the plugin ones:
[Core] Name = MyFlows. Module = myflows.py [Documentation] Description = my documentation. [Python] Version = 2+
Now in the
myflows.py file you will have pretty familiar structure with a
BotFlow as type and @botflow
as flow decorator:
from errbot import botflow, FlowRoot, BotFlow class MyFlows(BotFlow): """ Conversation flows for Errbot""" @botflow def example(self, flow: FlowRoot): """ Docs for the flow example comes here """ # [...]
Errbot will pass the root of the flow as the only parameter to you flow definition so you can build your graph from there.
2.2. Making a simple graph¶
Within your flow, you can connect commands together. For example to make a simple linear flow between !first, !second and !third:
@botflow def example(self, flow: FlowRoot): first_step = flow.connect('first') # first is a command name from any loaded plugin. second_step = first_step.connect('second') third_step = second_step.connect('third')
You can represent this flow like this:
O is the state “not started” for the flow
You can start this flow manually by doing
!flows start example.
The bot will tell you that it expects a
Once you have executed
!first, you will be in that state:
The bot will tell you that it expect
2.3. Making a flow start automatically¶
Now, usually flows are linked to a first action you users want to do. For example:
!report init or first commands like that that suggests that you will have a follow up.
To trigger automatically a flow on those first commands you can use
@botflow def example(self, flow: FlowRoot): first_step = flow.connect('first', auto_trigger=True) second_step = first_step.connect('second') third_step = second_step.connect('third')
You can still represent this flow like this:
BUT, when a user will execute a
!first command, the bot will instantly instantiate a Flow in this state:
And tell the user that !second is the follow up.
2.4. Flow ending¶
If a node has no more children and a user passed it, it will automatically ends the flow.
Sometimes, with loops etc, you might want to explicitly mark an END FlowNode with a predicate, you can do it like this, for example for a guessing game plugin:
In the flow code…
from errbot import botflow, FlowRoot, BotFlow, FLOW_END class GuessFlows(BotFlow): """ Conversation flows related to polls""" @botflow def guess(self, flow: FlowRoot): """ This is a flow that can set a guessing game.""" # setup Flow game_created = flow.connect('tryme', auto_trigger=True) one_guess = game_created.connect('guessing') one_guess.connect(one_guess) # loop on itself one_guess.connect(FLOW_END, predicate=lambda ctx: ctx['ended'])