File: basics.rst

package info (click to toggle)
errbot 6.1.7%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 3,712 kB
  • sloc: python: 13,831; makefile: 164; sh: 97
file content (137 lines) | stat: -rw-r--r-- 3,695 bytes parent folder | download
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'])