1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
Basic Flow Definition
=====================
Flows are like plugins
----------------------
They are defined by a ``.flow`` file, similar to the plugin ones:
.. code-block:: ini
[Core]
Name = MyFlows
Module = myflows
[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:
.. code-block:: python
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 your flow definition so you can build your graph
from there.
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``:
.. code-block:: python
@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:
.. figure:: basics_1.svg
:align: center
O is the state "not started" for the flow ``example``.
You can start this flow manually by doing ``!flows start example``.
The bot will tell you that it expects a ``!first`` command:
.. figure:: basics_3.svg
:align: center
Once you have executed ``!first``, you will be in that state:
.. figure:: basics_2.svg
:align: center
The bot will tell you that it expects ``!second``, etc.
.. figure:: basics_4.svg
:align: center
Making a flow start automatically
---------------------------------
Now, usually flows are linked to a first action your users want to do. For example: ``!poll new``, ``!vm create``,
``!report init`` or first commands like that that suggests that you will have a follow-up.
To trigger a flow automatically on those first commands, you can use ``auto_trigger``.
.. code-block:: python
@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:
.. figure:: basics_1.svg
:align: center
BUT, when a user will execute a ``!first`` command, the bot will instantly instantiate a Flow in this state:
.. figure:: basics_2.svg
:align: center
And tell the user that ``!second`` is the follow-up.
Flow ending
-----------
If a node has no more children and a user passed it, it will automatically end 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:
.. figure:: end.svg
:align: center
In the flow code...
.. code-block:: python
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'])
|