Extending SPADE with plugins

This release of SPADE is designed as a very light version of the platform (compared with SPADE<3.0) which provides only the core features that a MAS platform should have. This implies that some of the features that were provided by previous versions of the platform are now not included.

How makes that sense? Well, all that previous features are not lost, but are going to be turned into plugins that you can connect to your MAS application.

This way it is very easy to add new features to SPADE without disturbing the core development.

We have planned three different ways to design plugins for the SPADE platform, but of course we are open to suggestions.

Warning

A plugin needs to comply with some requirements to be accepted as a SPADE plugin and be listed as an official plugin on the main page:

  1. It must be open source (of course!) and published in PyPi.
  2. The package must be called spade-* (e.g.: spade-bdi, spade-owl, etc.) and be imported as import spade_*.
  3. It must be tested.
  4. It must follow the PEP8.

You can develop new behaviours, new mixins that modify behaviours, and of course new libraries that your agents can use inside your behaviours. Let’s see some examples of each of these ones:

New Behaviours

Developing new behaviours is as easy as creating a new class that inherits from spade.behaviour.CyclicBehaviour (or any of its subclassed behaviours) and overload the methods that are needed. Pay atention to the methods that are related with the control flow of a behaviour like _step, done and _run. And remember that you should not overload the methods that are reserved for the user to be overloaded: on_start, run and on_end.

Example:

class BDIBehaviour(spade.behaviour.PeriodicBehaviour):

    async def _step(self):
        # the bdi stuff

    def add_belief(self, ...):
        ...
    def add_desire(self, ...):
        ...
    def add_intention(self, ...):
        ...
    def done(self):
        # the done evaluation

    ...

New Mixins

Some cases you don’t want to add a new behaviour, but to add new features to current behaviours. This can be done by means of mixins. A mixin is a class that a behaviour can inherit from, in addition to the original parent class, making use of the multiple inheritance of python. This way, when we are creating our agent and we implement its behaviour which is (for example) a cyclic behaviour and we want to add this behaviour a feature that is provided by a plugin called spade-p2p that allows the agent to send P2P messages (by modifying the send and receive methods of the behaviour) we should do the following:

from spade_p2p import P2PMixin

class MyNewBehaviour(P2PMixin, CyclicBehaviour):
    ...
    async def run(self):
        ...
        self.send(my_message, p2p=True)
        ...

Warning

The order of your mixins is important! The base behaviour class must be always the last one in the method resolution order.

Hint

Remember that if you need to call the parent function of the base behaviour (or any other mixin in the method resolution order), you must use the super() function (see the following example).

To develop this example mixin you should do the following:

class P2PMixin(object):
    async def send(self, msg, p2p=False):
        if p2p:
            await self.send_p2p(msg)
        else:
            await super().send(msg)


    async def send_p2p(self, msg):
        ...

New Libraries

Finally, the easiest way to add new features to your agents is by means of libraries. If you want your agents to support, for example, the OWL content language, you don’t need to change spade, just make a library that handles it. Example:

from spade_owl import parse as owl_parse
from spade_owl import dump as owl_dump

class MyBehaviour(spade.behaviour.CyclicBehaviour):
    async def run(self):
        msg = await self.receive()

        owl_content = owl_parse(msg.content)
        # do wat you want with the owl content

        reply.content = owl_dump(...my owl reply...)

        await self.send(reply)