The Environment Interface Standard (EIS) is an attempt to provide a common interface between agents and the environments the inhabit. The idea of the initiative is to standardise how an agent language interacts with an environment. This means that language developers need only to link their programming language to the interface and then they have access to all of the environments that have been developed for that interface.
For ASTRA, the approach that has been taken to linking agents to the interface has been based on a core language level integration. This support includes a statement for executing actions in the environment, a formula for querying environment beliefs, and an event for triggering behaviours. Additionally, a custom API has been developed to provide additional support for working with EIS environments.
Launching / Connecting to an Environment
EIS environments are deployed as jar files. To use one, you should copy the jar file into the base directory of your Eclipse project (the project folder).
An example of this can be seen above, where the Test project contains the Vacworld EIS Environment, which is released as the file ita-2.2.0.jar.
When working with EIS environments, the first thing that needs to be done is for the environment to be actually loaded into the EIS Interface. In ASTRA, this is done via an action that is defined as part of the EIS API:
package examples;
agent Vac {
module EIS ei;
rule +!main(list args) {
ei.launch("vacworld", "ita-2.2.0.jar");
ei.join("vacworld");
}
}
The launch(…) action installs the VacWorld environment into the EIS interface and makes it accessible to ASTRA agents through the “vacworld” identifier. This action only needs to be performed once by a single agent. Other agents need only to connect to the EIS environment by using the join(…) action:
package examples;
agent Vac2 {
module EIS ei;
rule +!main(list args) {
eis.join("vacworld");
}
}
As we will see later, it is possible for a single agent deployment to interact with more than one EIS environment at a time. Because of this, many of the actions and terms have been overloaded to work with both a specified environment and a default environment. The default environment is the last environment that the agent joined. This, however can be overridden with the EIS API setDefaultEnvironment(…) action. For completeness, an agent can get its current default environment identifier using the the EIS API.defaultEnvironment() term.
Linking agents to Entities
EIS Environments expose a set of entities that can be controlled by one or more agents. Each entity is associated with a unique identifier (name), a type and an associated set of actions and perceptions. Information about the actions and perceptions available for each entity / entity type is not available through EIS, but is instead is normally described in the supporting documentation for each environment.
To link an agent to an entity, all you need is the name of the entity and, where more than one environment is involved, the id of the environment. Linking an agent to an entity is supported through three EIS API actions:link(), link(entity), link(envId, entity). The first of these actions links the agent to an entity in the default environment with the same name as the agent; the second action links the agent to an entity in the default environment with the provided entity name and third action links the agent to an entity in the specified environment with the given entity name. To illustrate this, the program below links the agent to the gripperentity in the default environment (as we only use one environment in this example) which is the TowerEnvironment.
package examples;
agent Tower {
module EIS ei;
initial !init();
rule +!init() {
ei.launch("tower", "towerenv.jar");
ei.join("tower");
ei.link("gripper");
}
}
Starting an Environment
Some environments start automatically when loaded, while others must be started by an agent. To start an environment one of the connected agents must execute one of the following two EIS API actions: startEnv()or startEnv(envId). We illustrate this by extending the example Tower program above:
package examples;
agent Tower {
module EIS ei;rule +!main(list args) {
ei.launch("tower", "towerenv.jar");
ei.join("tower");
ei.link("gripper");
ei.startEnv();
}
}
Sometimes it is not clear whether the environment needs to be started. In this case, the current state of the environment can be identified by using one of the following EIS API terms: getState() or getState(envId). Normally, an environment will be created in a “paused” state. Once the environment has been started, it moves into a “running” state. The following code uses one of these terms to provide a better general solution to starting the environment:
package examples;
agent Tower {
module EIS ei;
rule +!main(list args) {
eis.launch("tower", "towerenv.jar");
eis.join("tower");
eis.link("gripper");
if (eis.getState() == "paused") eis.startEnv();
}
}
Sensing in EIS Environments
EIS provides a standard model for agent-environment interaction in which the agent periodically senses the environment, generating a set of perceptions. Interleaved between the sensor invocations, the agent is able to perform actions in the environment. One consequence of this model is that EIS provides a standard format for the perceptions that it generates. The normal mechanism for handling this is to convert that format into whatever format is used by the associated agent language. This enforces replication of effort – raw data is converted into an intermediary format which is then converted into a final format – can have a significant impact on the performance of the agent language. It also raises the issue of how to distinguish between beliefs generated by the agent and beliefs that arise from the EIS perceptions. The solution in Jason, for example, is the use of annotated beliefs.
In ASTRA, a different approach is adopted:
- The percepts generated by EIS are stored in their intermediary format in a separate belief base, with one belief base per environment.
- Each time the agent senses its environment, the new percepts are compared against the previous percepts to identify what changes have occurred. These changes are used to create custom EIS events that can be handled by plan rules.
- A custom EIS formula allows the agent to query a specified EIS belief base. This can be either the default environment belief base of a specified belief base.
As indicated above, querying of the percepts generated by an EIS environment is done using a custom formula notation. For example, the below code extends the Tower program to check whether the gripper his holding block “a”:
package examples;
agent Tower {
module EIS ei;
module Console C;
rule +!main(list args) {
ei.launch("tower", "towerenv.jar");
ei.init();
ei.join();
ei.link("gripper");
if (ei.getState() == "paused") ei.startEnv();
if (ei.holding("a")) {
C.println("the gripper is holding block a");
} else {
C.println("the gripper is NOT holding block a");
}
}
}
This custom formula allows you to write code that checks the percepts from the EIS environment, but sometimes you want to trigger some behaviour based on the addition or retraction of some percept. This can be handled through a custom EIS event type as is indicated in the code below:
package examples;
agent Tower {
module EIS ei;
module Console C;
rule +!main(list args) {
ei.launch("tower", "towerenv.jar");
ei.init();
ei.join();
ei.link("gripper");
if (ei.getState() == "paused") ei.startEnv();
}
rule +$ei.event(holding(string X)) {
C.println("the gripper is holding " + X);
}
rule -$eis.event(holding(string X)) {
C.println("the gripper is no longer holding " + X);
}
}
As can be seen in this second example, EIS events are treated in much the same way as standard belief events. The difference is the syntax, and the inclusion of two fields: id and entity. These fields hold the id of the environment in which the event occurred (here id would be bound to “tower”) and the name of the entity that generated the percept (here the entity would be “gripper”).
This may seen a little overly complex compared to the formula used to query the percept, but there is good reason for it: ASTRA allows an agent to join multiple EIS environments and to control multiple EIS entities. For the purposes of an agent that is linked to only one environment and one entity, these fields can be ignored. Further information on how to link an agent to multiple environments and/or multiple entities is provided in later sections of this lesson.
Acting in the Environment (T.B.C.)
T.B.C.
Working with Complex Environments
Here, we focus on how to work with more complex environments that may have many entities of diverse types. Such environments add more complexity because developers typically want to associate different agent types with different entity types.
Once an environment has been loaded, and an agent has been linked to it, you are able to retrieve a list of the entities in the environment. To get a list of the entities that are not linked to an agent, you can used theEIS API terms: freeEntities() orfreeEntities(id). The former term returns a list of free entities registered to the current default environment, and the latter term returns a list of free entities for the environment with the given identifier.
Once you know the names of the entities, you can check their type by using the EIS API terms:getEntityType(entity) and getEntityType(id, entity). As with the previous terms one assumes the default environment and the second allows you to specify the environment.
The above terms allow you to query an EIS environment to find out what entities exist and what their types are. The example below imagines a “soccer based environment” with four types of entity: goalkeeper, defender, midfielder, attacker. As can be seen different agents are created depending on the type of entity.
package examples;
agent Launcher {
module EIS ei;
module Prelude P;
module System S;
module Console C;
rule +!main(list args) {
ei.launch("soccerworld", "soccer.jar");
ei.join();
int i =0;
list entities = ei.freeEntities();
forall(string entity : entities) {
string type = ei.getEntityType(entity);
if (type == "goalkeeper") {
S.createAgent("p"+i, "examples.Goalkeeper");
} else if (type == "defender") {
S.createAgent("p"+i, "examples.Defender");
} else if (type == "midfielder") {
S.createAgent("p"+i, "examples.Midfielder");
} else if (type == "attacker") {
S.createAgent("p"+i, "examples.Attacker");
} else {
C.println("Unknown type: " + type + " for entity: " + entity);
}
i = i + 1;
}
}
}