AF-TeleoReactive

From Agent Factory

Jump to: navigation, search

Contents

Introduction

AF-TeleoReactive (AF-TR) is an implementation of Nils Nilsson's TeleoReactive agents formalism. Which was created to address the issue of computing and organizing actions of autonomous agents in dynamic environments. AF-TR was developed using the Agent Factory Common Language Framework as part of the final year thesis of an undergraduate of the School of Computer Science and Informatics in UCD.

The language was adapted in order to fit into the Agent Factory Common Language Framework, as such it utilizes Actions, Sensors and Modules to provide interaction with the environment. Further to this AF-TR provides a mechanism for the reuse of agent code through the use of the #extends keyword in the agent definition.

From a tool perspective, the language comes with a basic inspection tool that is designed to be integrated with the Agent Factory Debugger together with a basic code editor that are provided as part of the Agent Factory Eclipse Plugin.


Language Overview

To gain a basic understanding of the teleo-reactive programming, we recommend that you read Nils Nilsson's paper Teleo-reactive programs for agent control. This document assumes that you have read this document, and focuses mainly on explaining how to program the Agent Factory variant of the langauge.

AF-TeleoReactive programs contain a belief set upon which a number of inference rules are applied to generate more beliefs.

Beliefs: In AF-TeleoReactive, beliefs take the form of grounded predicate formulae. For example, the belief that Socrates is mortal would take the form: is(Socrates, mortal).

Functions: In AF-TeleoReactive, functions define the actions of the agent. Functions take the form of a declaration containing a number of parameters and a set of production rules. Production rules consist of a condition and an Action in the form Condition -> Action, where conditions represent beliefs within the belief set and Actions are represented by Actions of the Agent. The example given below is taken from the AF-EISTowerWorld package.

   function makeTower(?tower){
       isTower(?tower) -> nil
       ordered(?tower) -> unpile(head(?tower))
       (tail(?tower) == []) -> moveTable(head(?tower))
       isTower(tail(?tower)) -> move(head(?tower), head(tail(?tower)))
       true -> makeTower(tail(?tower))
   }

In this example the function is called with a single parameter, an ordered list denoting the tower to be built, upon the invocation of the function the variable ?tower is bound in all of the rules of the function. The conditions of the production rules are scanned from top to bottom until a condition evaluates to true, the corresponding action is then triggered.

If the ?tower variable was the list [A, B, C, D] and the belief set contained the belief isTower([B, C, D]), then the condition isTower(tail(?tower)) would be bound to isTower(tail([A, B, C, D])) and evaluated to isTower([B, C, D]), the corresponding Action move(head([A, B, C, D]), head(tail([A, B, C, D]))) is then triggered which evaluates to move(A, B) and the block A is moved on top of the block B.


The Core Language

To get you started, in the language, we will present a number of simple examples that illustrate both how to write an AF-TR program, and how to use the Core API (basic actions and sensors) that is available by default for all AF-TR agents (in fact, this Core API is available to all agent programming languages implemented using the Common Language Framework). In later lessons, we will explain both how to use other APIs and how to develop your own APIs.

Printing to the Console

AF-TR provides two basic actions for outputting to the console: .print(...) and .println(...). These actions are basically wrappers for the Java System.out.print(...) and the System.out.println(...) methods. The simplest program demonstrates how to use these actions is the "hello world" program that prints out hello world to the console, which is given below:

 #agent Hello
   function main{
       true -> .println("Hello World")
   }

This program prints the text "Hello World" to the console once.

Writing and Running an AF-TR Agent Program

To write and run an AF-TR agent program, you need to install the Agent Factory Eclipse Plugin. Once you have the plugin installed, you should perform the following steps:

  1. Create a new Agent Factory Project: The first step is to create an Agent Factory project. To do this select "File->New->Project..." and select "New Agent Factory Project" from the "Agent Factory" category. Click on the "Next" button and enter a name for the project (here enter "HelloWorld"). Click "Finish" and you are done!
  2. Create an AF-TeleoReactive Program File: Now, you need to create the source code file in which you will write your AF-TR program. To do this, select "File->New->Other" and select "New Teleo-Reactive Agent file" from the "Agent Factory" category. Click on the "Next" button and enter a name for the file (here, enter "hello.aftr" as the filename). Now, click "Finish". Open the created file and replace the text with printing example above.
  3. Write the Agent Speak Program: Next, you need to write your agent program. For this step, lets use the example agent program from the previous section.
  4. Create a Run Configuration class to deploy the program: The final step requires that you write a Run Configuration class to deploy the program. Two examples of this kind of class is given in the following sections. Java-based configurations are used over configuration files to allow maximum flexibility when deploying agent platforms (i.e. it can be used stand alone, integrated into an EJB container, deployed as an OSGi service, ...).

The next subsections outline two ways of deploying an agent program. The approach you choose depends upon whether or not you wish to debug the agent program. First we will look at debugging, and afterwards, we will look at deploying.

Writing a Debugger Run Configuration

The Agent Factory Debugger is a generic component of Agent Factory that can be customised for different agent languages and architectures. Basic support for using the debugger is provided via the DebuggerRunConfiguration class. To debug an application, you simply extend this class, override the configure() method and then write a very simple main method. We illustrate this with the example code below:

import com.agentfactory.agentspeak.interpreter.TeleoReactiveArchitectureFactory;
import com.agentfactory.agentspeak.debugger.TeleoReactiveStateManagerFactory;
import com.agentfactory.agentspeak.debugger.inspector.TeleoReactiveInspectorFactory;
import com.agentfactory.visualiser.DebuggerRunConfiguration;

public class HelloDebugConfiguration extends DebuggerRunConfiguration {
    public String getName() {
        return "helloworld";
    }

    public String getDomain() {
        return "ucd.ie";
    }

    public void configure() {
        addLanguageSupport(new TeleoReactiveInspectorFactory(), new TeleoReactiveStateManagerFactory());
        super.configure();
        addArchitectureFactory(new TeleoReactiveArchitectureFactory());

        addAgent("Bob", "helloworld.aftr");
    }

    public static void main(String[] args) {
        new HelloDebugConfiguration().configure();
    }
}


The getName() and getDomain() methods are used by the superclasses as part of the platform configuration, removing them will result in a default platform name and domain being applied. The core of the platform configuration is done in the configure() method. The first line of this method configures AF-TeleoReactive support for the Agent Factory Debugger. The second line causes the agent platform to be created. The third line installs architectural support for the AF-TeleoReactive language (basically it links the AF-TeleoReactive interpreter to the Run-Time Environment). Finally, the fourth line creates a helloworld.aftr agent with name "Bob". The main method simply creates an instance of the class and calls the configure() method.

When you run this class (this is just a standard Java class with a main method), the debugger should be loaded, which looks something like this:

To open the agent inspector shown above, you double-click on the agent name in the tree view on the left-hand side. You are then able to start, stop, and step an agent by clicking on the buttons at the top of the corresponding inspector. The various views expose different aspects of the agents internal state.

Writing a Deployment Run Configuration

Deployment Run Configurations are very similar to Debugger Run Configurations. In fact, the only changes you need to make are:

  • Extend DefaultRunConfiguration instead of DebuggerRunConfiguration.
  • Remove any debugger specific code from the configuration (this is anything that appears before the super.configure() line.

The Deployment Run Configuration that is equivalent to the Debugger Run Configuration code given above is:

import com.agentfactory.teleoreactive.interpreter.TeleoReactiveArchitectureFactory;
import com.agentfactory.platform.impl.DefaultRunConfiguration;

public class HelloRunConfiguration extends DefaultRunConfiguration {
    public String getName() {
        return "helloworld";
    }

    public String getDomain() {
        return "ucd.ie";
    }

    public void configure() {
        super.configure();
        addArchitectureFactory(new TeleoReactiveArchitectureFactory());

        addAgent("Bob", "helloworld.aftr");
    }

    public static void main(String[] args) {
        new HelloDebugConfiguration().configure();
    }
}


Self Sensing

The Agent Factory Common Language Framework provides a default sensor, called ".self" that provides basic beliefs about the agent. In its current form, the sensor provides 2 beliefs:

  • name(?name): is a belief about the name of the agent (the variable ?name is replaced by the name)
  • agentID(?x, ?addr): is a belief about the FIPA Agent Identifier of the agent. These identifiers are used for inter-agent communication.

To illustrate how to use these beliefs, we extend the hello world program to include the name of the agent in the string that is printed to the console:

#agent Hello
   function main{
       name(?name) -> .println(?name)
   }

The output of this program depends on the name of the agent you create. For example, the previous section, described how to create and deploy a "helloworld" agent called "Bob". If you modified the .aftr file to match the above program, then running the program would cause the text "Bob" to be printed to the console.


Communicating

The syntactic structure of the messages that are sent between agents, and the underlying transport mechanisms have been developed in compliance with the existing FIPA Standards. Rather than give a detailed overview of these standards, we will start here with simple examples and add further information in later lessons.

Support for communication in AF-AS takes the form of a special sensor that generates events corresponding to messages that are received and the .send(...) action that enables agents to send messages. The format of the message belief is:

message(?performative, ?senderAgentID, ?content)

where ?performative is a message type that is compliant with the communicative acts specified in FIPA ACL; ?senderAgentID is a representation of the senders agent identifier, and is the same as the agent identifier belief outlined in the previous section; and ?content is the content of the message. Similarly, the .send(...) action action takes 2 parameters: the communicative act, and the content of the message.

The two most basic types of messages that can be sent between agents are inform and request messages. These messages capture the sharing of beliefs / information, and asking for help / actions to be performed respectively.

Failing

The actions of an agent can succeed or fail depending on whether the action code executed correctly. The failure action, .fail always fails. An example of this action is use is the following function:

function main{
    ...
    condition -> .fail
    ...
}
    

The production rule in the above function attempts to use the action .fail, by design when an action in a teleo-reactive function fails the interpreter will continuously retry the action until the it has the desired effect. As such when the condition of the above rule is true, the agent will be stuck at that point until the environment changes sufficiently such that another rule is selected.