Skip to content
Alexandre Mellado edited this page Nov 9, 2025 · 11 revisions

Installing MASPY

To install MASPY you can use package-management system pip:

pip install maspy-ml

To update your already installed version of MASPY to the latest one, you can use:

pip install maspy-ml -U

MASPY needs Python 3.12+ to run correctly.

Using MASPY

Import

To use the Framework you need this simple import from maspy import * , nothing more or less.

Everything for MASPY to run correctly in imported this way.

About MASPY

The MASPY Framework is made of five main classes.

  • The Agent Class for the managing beliefs, goals and plans.
  • The Environment Class for providing perception and interaction context to agents
  • The Communication Class for agents to exchange messages and information
  • The Admin Class for configuration and control of the system
  • The Learning Class for Modelling an Environment Instance into ML ready training

maspy-CLASSES

Each Agent follows the BDI reasoning and each cycle occors as presented in the following diagram:

maspy-REASONING_learn

Creating a new Agent

To create a new agent, you only need to extend Agent in your class, this adds all of the necessary logic to execute an agent. the following snippet shows how to create an DummyAgent.

To create an instance of any agent, only the Extension is needed.

Technically, this is a MASPY Agent:

Dummy Agent

from maspy import *

class DummyAgent(Agent):
    pass

my_agent = DummyAgent()
named_agent = DummyAgent("Ag")

When the snippet above is run, this is the printed result:

Starting MASPY Program
# Admin #> Registering Agent DummyAgent:('DummyAgent', 1)
Channel:default> Connecting agent DummyAgent:('DummyAgent', 1)
# Admin #> Registering Agent DummyAgent:('Ag', 1)
Channel:default> Connecting agent DummyAgent:('Ag', 1)

It will execute indeterminably, while doing nothing.

Initial Beliefs and Goals

The agent can start with some inital Beliefs or Goals.

For most of theses explanations, the code from "examples/ex_parking.py" will be used.

from maspy import *

class Driver(Agent):
    def __init__(self, agent_name=None):
        super().__init__(agent_name)
        self.add(Belief("budget",(rnd.randint(6,10),rnd.randint(12,20)),adds_event=False))
        self.add(Goal("park"))

driver = Driver("Drv")

Managing Beliefs and Goals

Here are some info about Beliefs and Goals being created and removed.

  • This function adds a goal to the agent;
  • The first field represents the goal key and must always be a string;
  • The second field represents arguments of the goal and will always be a tuple;
    • Each argument can have any structure, with each position of the tuple representing a different one;
  • The third field represents the goal source. It is "self" by default, or another agent.
  • adding or removing a goal always creates an event for agent, which will try to find a applicable plan.
agent = DummyAgent("Ag")
agent.add( Goal(Name, Values, Source) )
agent.rm( Goal(Name, Values, Source) )
        
agent.add( Goal("check_house", {"Area": [50,100], "Rooms": 5}, ("Seller",27) ) )
agent.add( Goal("SendInfo", ("Information",["List","of","Information",42]) ) )
agent.rm( Goal("walk", source=("trainer",2)) )
  • This function adds a belief to the agent;
  • The first an second field work exaclty the same way as the goal's
  • The third field represents the belief source. It is "self" by default, another agent or an environment.
  • The fourth field dictates if the adding or removing the belief will generate a new event.
    • By default it does, but sometimes one does not want a group of beliefs to be considerend new events
agent = DummyAgent("Ag")
agent.add( Belief(Name, Values, Source, Adds_Event) )
agent.rm( Belief(Name, Values, Source, Adds_Event) )

agent.add( Belief("Dirt", (("remaining",3),[(2,2),(3,7),(5,1)])) )
agent.rm( Belief("spot",("A",4,"free"),"Parking",False) )
agent.add( Belief("velocity",57) )

Defining plans

To define plans it is also really simple, it only needs the @pl decoration. This decoration must contain the plan change {gain, lose or test}, the data that changed {Belief(s) or Goal(s)} and optionally a context needed to be true to execute the plan {Belief(s) or Goal(s)}.

    change: TypeVar('gain'|'lose'|'test')
    changed_data: Iterable[Belief | Goal] | Belief | Goal
    context: Iterable[Belief | Goal] | Belief | Goal

    @pl(change, changed_data, context)
    def foo(self,src, *changed_data.values, *context.values):

Resuming the the driver example, you can implement a plan the following way:

from maspy import *

class Driver(Agent):
    def __init__(self, agent_name=None):
        super().__init__(agent_name)
        self.add(Belief("budget",(rnd.randint(6,10),rnd.randint(12,20)),adds_event=False))
        self.add(Goal("park"))

    # This plan will be executed whenever the agent gains the goal "checkPrice"
    # Every plan needs at least self and src, plus the arguments from the trigger and context
    # for this plan, the context is the belief of a budget with wanted and max prices
    @pl(gain,Goal("checkPrice", Any),Belief("budget",(Any, Any)))
    def check_price(self, src, given_price, budget):
        ...

driver = Driver("Drv")

Running the agents

Running the system is simple, given the utilities support we have in place. The Admin module contains a few useful methods to start and manage the system.

Starting all agents

In case you only need to start all agents, the following snippet is enough.

driver1 = Driver("Drv")
driver2 = Driver("Drv")

Admin().start_system()

In this example, both agents have the same name "Drv".

For communication to not be ambiguous, the Admin names them "Drv_1" and "Drv_2".

Communication between Agents

After starting the agents they may use the default channel or be connected to private one.

from maspy import *

class Manager(Agent):
    def __init__(self, agt_name=None):
        super().__init__(agt_name,show_exec=False,show_cycle=False)
        self.add(Belief("spotPrice",rnd.randint(12,20),adds_event=False))

    @pl(gain,Goal("sendPrice"),Belief("spotPrice", Any))
    def send_price(self,src,spot_price):
        # The agent manager sends a goal to the manager via the Parking channel
        self.send(src,achieve,Goal("checkPrice",spot_price),"Parking")

class Driver(Agent):
    def __init__(self, agt_name=None):
        super().__init__(agt_name,show_exec=False,show_cycle=False)
        self.add(Belief("budget",(rnd.randint(6,10),rnd.randint(12,20)),adds_event=False))
        self.add(Goal("park"))
    
    @pl(gain,Goal("park"))
    def ask_price(self,src):
        # The agent driver sends a goal to the manager via the Parking channel
        self.send("Manager", achieve, Goal("sendPrice"),"Parking")

park_ch = Channel("Parking")
manager = Manager()
driver = Driver("Drv")
Admin().connect_to([manager,driver],park_ch)

The following are the different directives to send messages between agents.

self.send(<target>, <directive>, <info>, optional[<channel>])

Directives:
tell 		-> Add Belief on target
untell		-> Remove Belief from target
achieve 	-> Add Goal to target
unachieve	-> Remove Goal from target
askOne		-> Ask for Belief from target
askOneReply	-> Ask for Belief from target and wait for Reply
askAll		-> Ask for all similar Beliefs from target
askAllReply	-> Ask for all similar Beliefs from target and wait for Reply
tellHow		-> Add Plan on target
untellHow	-> Remove Plan from target
askHow 		-> Ask for Plan from target
askHowReply	-> Ask for Plan from target and wait for Reply

Environment

MASPY also gives an abstraction to model the environment.

Here's how you create a parking lot for the manager and driver from before:

Creating an environment

from maspy import *

class Park(Environment):
    def __init__(self, env_name=None):
        super().__init__(env_name)
        # This creates in the environment a percept for connected agents to perceive.
        # This specific percept does not create a event when percieved by an agent 
        self.create(Percept("spot",(1,"free"),adds_event=False))

    def park_spot(self, agt, spot_id):
        # The function get gives you percepts from the environment
        # It has various filters to make this search more precise
        spot = self.get(Percept("spot",(spot_id,"free")))
        if spot:
            # This function is used to modify the arguments of an percept.
            self.change(spot,(spot_id,driver))

            # You could also remove the old and create the new
            self.remove(spot)
            self.create(Percept("spot",(spot_id,driver)))

    def leave_spot(self, agt):
        spot = self.get(Percept("spot",("ID",driver)))
        if spot:
            self.change(spot,(spot.values[0],"free"))

Allowing agents to interact with an environment

from maspy import *

class Park(Environment):
    def __init__(self, env_name=None):
        super().__init__(env_name)
        self.create(Percept("spot",(1,"free"),adds_event=False))

    def park_spot(self, agt, spot_id):
        spot = self.get(Percept("spot",(spot_id,"free")))
        if spot:
            self.change(spot,(spot_id,driver))

class Driver(Agent)
    @pl(gain,Goal("park",("Park_Name", Any)))
    def park_on_spot(self,src,park_name,spot_id):
        # This agent functions makes the connection with an environment or channel
        # Just give it Channel(Name) or Envrionment(Name) to add it to the agent 
        self.connect_to(Environment(park_name))

        # After the connection, the agent can execute the envrionment plan directly
        self.park_spot(spot_id)

Simplest System with Every Class

from maspy import *

class SimpleEnv(Environment):
    def env_act(self, agt, agent2):
        self.print(f"Contact between {agt} and {agent2}")

class SimpleAgent(Agent):
    @pl(gain,Goal("say_hello", Any))
    def send_hello(self,src,agent):
        self.send(agent,tell,Belief("Hello"),"SimpleChannel")

    @pl(gain,Belief("Hello"))
    def recieve_hello(self,src):
        self.print(f"Hello received from {src}")
        self.env_act(src)

if __name__ == "__main__":
    Admin().set_logging(show_exec=True)
    agent1 = SimpleAgent()
    agent2 = SimpleAgent()
    env = SimpleEnv()
    ch = Channel("SimpleChannel")
    Admin().connect_to([agent1,agent2],[env,ch])
    agent1.add(Goal("say_hello",(agent2.my_name,)))
    Admin().start_system()

This code will generate the following prints:

# Admin #> Starting MASPY Program
# Admin #> Registering Agent SimpleAgent:('SimpleAgent', 1)
# Admin #> Registering Channel:default
Channel:default> Connecting agent SimpleAgent:('SimpleAgent', 1)
# Admin #> Registering Agent SimpleAgent:('SimpleAgent', 2)
Channel:default> Connecting agent SimpleAgent:('SimpleAgent', 2)
# Admin #> Registering Environment SimpleEnv:SimpleEnv
# Admin #> Registering Channel:SimpleChannel
Environment:SimpleEnv> Connecting agent SimpleAgent:('SimpleAgent', 1)
Channel:SimpleChannel> Connecting agent SimpleAgent:('SimpleAgent', 1)
Environment:SimpleEnv> Connecting agent SimpleAgent:('SimpleAgent', 2)
Channel:SimpleChannel> Connecting agent SimpleAgent:('SimpleAgent', 2)
Agent:SimpleAgent_1> Adding Goal say_hello(SimpleAgent_2)[self]
Agent:SimpleAgent_1> New Event: gain,Goal say_hello(SimpleAgent_2)[self]
# Admin #> Starting Agents
Agent:SimpleAgent_1> Running gain : Goal say_hello(typing.Any)[self], [], send_hello() )
Channel:SimpleChannel> SimpleAgent_1 sending tell:Belief Hello(())[SimpleAgent_1] to SimpleAgent_2
Agent:SimpleAgent_2> Adding Belief Hello(())[SimpleAgent_1]
Agent:SimpleAgent_2> New Event: gain,Belief Hello(())[SimpleAgent_1]
Agent:SimpleAgent_2> Running gain : Belief Hello(())[self], [], recieve_hello() )
Agent:SimpleAgent_2> Hello received from SimpleAgent_1
Environment:SimpleEnv> Contact between SimpleAgent_2 and SimpleAgent_1
# Admin #> [Closing System]
# Admin #> Still running agent(s):
SimpleAgent_1 | SimpleAgent_2 |
# Admin #> Ending MASPY Program

This program must be terminated using a ctrl+c. Otherwise the system would continue running indeterminately.