This FAQ is not completely update for Jason 3.2, where (1) Gradle is used to handle classpath and Jade (previously these aspects were handled in the .mas2j ); (2) jEdit is not supported. If you would like to see this FAQ updated in some question, add an issue at GitHub.
|
General
Why is the platform called Jason?
Jason initially stood for “Java-based Agentspeak interpreter used with Saci for multi-agent distribution Over the Net”. Since it not based only on SACI anymore (other infrastructures are available) and the acronyms was quite “forced”, we decided the use Jason as a proper name for the interpreter.
The name is also somehow inspired by in Greek mythology. Click here for an entry on Jason in the Perseus Encyclopaedia (Perseus is an excellent source of Classics, maintained by Tufts University).
Internal Actions
How to create a new internal actions?
The following steps will help you to define your internal action (IA). The steps 1-4,6 are automatically done by Jason IDE, see menu Plugin→Jason→New internal action".
-
In your MAS project directory, create a sub-directory called
myLib
(user’s internal actions must be placed in a Java package, which provides a library of actions). In case this package directory is under your project directory, Jason automatically sets the classpath. -
Copy an existing Jason internal action (
Jason/src/stdlib/concat.java
, for instance) to themyLib
directory. This file will be used as a skeleton for your new IA. -
Rename the file
myLib/concat.java
tomyLib/myIA.java
. -
Edit this file and change the
package
name tomyLib
, and the class name tomyIA
.The code will likely look like
myLib/myIA.javapackage myLib; import jason.asSemantics.*; import jason.asSyntax.*; public class myIA extends DefaultInternalAction { public Object execute(TransitionSystem ts, Unifier un, Term[] args) throws Exception { .... } }
-
Code the
execute
method in order to implement the internal action. -
Compile the new class
cd <your project directory> javac -classpath ...../Jason/lib/jason.jar:. myLib/myIA.java
-
Use the new IA in AgentSpeak sources, for example:
+a(X) : true <- ... ; myLib.myIA(A,B); ... .
Environment
Is it possible to call an internal action from the environment?
Most of the internal actions (IAs) are developed from an agent
perspective, since they are conceived to be called by agents. Thus the
execute
method needs an agent’s TransitionSystem
(TS) to be executed
(e.g. .myname
only makes sense when called by an agent).
How to discover the name of the agents in the environment initialisation?
As the environment is created before the agents, the set of agents is
empty when the environment is created and thus the method
getEnvironmentInfraTier().getRuntimeServices().getAgentsNames()
cannot
be used. However, if the set of agents is defined only by the .mas2j
project file (i.e., no agent is dynamically created), the name of the
agents can be obtained from that file.
For instance, a project file called ag-names.mas2j
can be passed as
parameter to the environment as in the following example:
MAS ag_names {
environment: TestEnv("ag-names.mas2j")
agents: a #10; b;
}
The following code (in the environment initialisation) can then get all the names:
public void init(String[] args) {
// args[0] is the name of the project file
try {
// parse that file
jason.mas2j.parser.mas2j parser =
new jason.mas2j.parser.mas2j(new FileInputStream(args[0]));
MAS2JProject project = parser.mas();
List<String> names = new ArrayList<String>();
// get the names from the project
for (AgentParameters ap : project.getAgents()) {
String agName = ap.name;
for (int cAg = 0; cAg < ap.qty; cAg++) {
String numberedAg = agName;
if (ap.qty > 1) {
numberedAg += (cAg + 1);
}
names.add(numberedAg);
}
}
}
logger.info("Agents' name: "+names);
...
}
MAS Execution
How to delay the MAS execution?
If you have an environment class, the easiest way is simply adding a
thread sleep
in the executeAction
method. For example:
...
public boolean executeAction(String agent, Term action) {
...
try {
Thread.sleep(500);
} catch (Exception e) {}
...
}
In case the agents do not act in the environment or there is no environment class, you should write a controller class (see Control Class).
For instance, the controller class could be:
package myPkg;
import ...
public class MyExecutionControl extends ExecutionControl {
protected void allAgsFinished() {
try {
Thread.sleep(500);
} catch (Exception e) {}
}
}
To use this controller, the project file must be
MAS test {
...
executionControl: myPkg.MyExecutionControl
agents: ...
}
Is it possible to add/remove an agent to/from a running MAS?
The internal action .createagent
can be used to dynamically add a new
agent into the running MAS. For example, when the plan:
+a : true
<- ... ;
.create_agent(bob, "myAgent.asl");
... .
is executed, it will create a new agent called bob
based on the
AgentSpeak code available at file myAgent.asl
.
Analogously, the internal action .killagent(<agent name>)
removes the
agent identified by <agent name>
from the current MAS. The
demos/create-agent
project that comes with the Jason distribution
files has examples of using these features.
New agents can also be created in the user Java code, for example:
public class myEnv extends Environment {
...
public boolean executeAction(String ag, Term action) {
...
getEnvironmentInfraTier().getRuntimeServices().
.createAgent(
"anotherAg", // agent name
"ag1.asl", // AgentSpeak source
null, // default agent class
null, // default architecture class
null, // default belief base parameters
null); // default settings
}
}
The interface, used in the code above, provides useful services transparently from the underlying infrastructure. The interface’s methods include agent creation, agent killing, and halting the system (see the API documentation for more information).
Which execution modes are available?
Jason is distributed with three execution modes:
-
Asynchronous: all agents run asynchronously. An agent goes to its next reasoning cycle as soon as it has finished its current cycle. This is the default execution mode.
-
Synchronous: all agents perform one reasoning cycle at every global execution step. When an agent finished its reasoning cycle, it informs the Jason controller and waits for a carry on signal. The Jason controller waits until all agents have finished their reasoning cycles and then sends the carry on signal to them.
To use this execution mode, you have to set up a controller class in the .mas2j configuration, for example:
MAS test { infrastructure: Local environment: testEnv executionControl: jason.control.ExecutionControl agents: ... }
The
jason.control.ExecutionControl
class implements exactly the Jason controller for the synchronous execution mode described above. -
Debug: this execution mode is similar to the synchronous mode, except that the controller will also wait until the user clicks on a Step button before sending the carry on signal to the agents.
To use this execution mode you can just press the debug button rather than the run button of the IDE, or you can set up a debug controller class in the .mas2j configuration, for example:
MAS test { infrastructure: Local environment: testEnv executionControl: jason.control.ExecutionControlGUI agents: ... }
The
jason.control.ExecutionControlGUI
class implements the Jason controlle with a GUI for debugging. This graphical tool is called Jason’s Mind Inspector, as it allows users to observe all changes in agents’ mental attitudes after a (number of) reasoning cycle(s).
How can I control agents’ execution?
If you have other specific needs for controlling agents’ execution, you
have to implement an ExecutionControl
sub-class and specify it in the
.mas2j file.
You will most likely have to override the following methods:
public void receiveFinishedCycle(String agName, boolean breakpoint) {
super.receiveFinishedCycle(agName, breakpoint);
... your code ...
}
protected void allAgsFinished() {
... your code ...
}
These methods are called by Jason when one agent has finished its reasoning cycle and when all agents have finished the current global execution step.
To signal the agents to carry on, your class can use the following code:
fJasonControl.informAllAgsToPerformCycle();
You should have a look at the ExecutionControlGUI
class for an example
of how to do this, and the API documentation for further available
methods inherited from ExecutionControl
.
Is it possible to use only the Jason BDI engine?
If you want to use only the Jason interpreter for a variant of AgentSpeak, you can implement your own agent class where the Jason available infrastructures are not used. This class must function as an overall agent architecture for the AgentSpeak interpreter, i.e., it has to send percepts to the interpreter and get the agent actions (which result from the AgentSpeak reasoning cycles).
Suppose you need a simple agent that interprets and reasons according to the following AgentSpeak source:
+x(N) : N < 3 <- do(0).
+x(N) : N >= 3 <- do(50).
The following class implements the required architecture (the complete
code is available in the demos
directory in the Jason distribution). This
code simply adds x(10)
into the agent’s belief base through perception
and get the output action, in this case do(50)
.
public class SimpleJasonAgent extends AgArch {
public static void main(String[] a) {
...
SimpleJasonAgent ag = new SimpleJasonAgent();
ag.run();
}
public SimpleJasonAgent() {
// set up the Jason agent and the
// TransitionSystem (the BDI Engine where the AgentSpeak
// Semantics is implemented)
Agent ag = new Agent();
new TransitionSystem(ag, new Circumstance(), new Settings(), this);
ag.initAg("demo.asl"); // demo.asl is the file containing the code of the agent
}
public String getAgName() {
return "bob";
}
public void run() {
while (isRunning()) {
// calls the Jason engine to perform one reasoning cycle
getTS().reasoningCycle();
}
}
// this method just add some perception for the agent
public List<Literal> perceive() {
List<Literal> l = new ArrayList<Literal>();
l.add(Literal.parseLiteral("x(10)"));
return l;
}
// this method gets the agent actions
public void act(ActionExec action) {
getTS().getLogger().info("Agent " + getAgName() + " is doing: " + action.getActionTerm());
// return confirming the action execution was OK
action.setResult(true);
actionExecuted(action);
}
public boolean canSleep() {
return true;
}
public boolean isRunning() {
return true;
}
public void sleep() {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
public void sendMsg(jason.asSemantics.Message m) throws Exception {
}
public void broadcast(jason.asSemantics.Message m) throws Exception {
}
public void checkMail() {
}
}
To run this agent:
export CLASSPATH= ../../lib/jason.jar:. javac SimpleJasonAgent.java java SimpleJasonAgent
The output will be
[bob] Agent bob is doing: do(50)
Of course, the AgentSpeak code in this example cannot use communicative actions, since the specific architecture given above does not implement communication.
Debug tools
How to setup verbosity of an agent?
The verbosity is set in the options defined for the agent in the project file. For instance
... agents: ag1 [verbose=2]; ...
A number between 0 and 2 should be specified. The higher the number, the more information about that agent is printed out in the Jason console. The default is in fact 1, not 0; verbose 1 prints out only the actions that agents perform in the environment and the messages exchanged between them. Verbose 2 is for debugging (it corresponds to the java log level FINE).
How to log the overall execution?
Jason uses the Java logging API to output messages into the console (the default console is
called MASConsole). To change the log level or device, edit the file logging.properties
.
The default configuration file has comments that
helps you customise your log. For instance, to output messages both into
an XML file and in the console, you only need to set the log handler as
in the following line:
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
To get only console output (without the MASConsole GUI):
handlers = java.util.logging.ConsoleHandler
How to log agents’ mind states?
Besides running the system in debug mode, we can define options for an agent such that the current state of its mind is shown or stored in files.
To show the current mind state in the screen, add the following option in the project:
agents: bob [mindinspector="gui(cycle,html)"];
In this case the screen is updated each reasoning cycle. If you want to store all the states in a kind of history, add a third argument as in the example below.
bob [mindinspector="gui(cycle,html,history)"];
In the place of cycle, you can write the refresh interval in mili-seconds:
bob [mindinspector="gui(2000,html,history)"];
You can also see the history of minds in a browser with the following configuration:
bob [mindinspector="web(cycle,html,history)"];
The URL is typically http://locaslhost:3272.
To store the history of minds in files, use the following configuration:
bob [mindinspector="file(cycle,xml,log)"];
The last parameter is the name of the directory where files will be stored. Each file corresponds to a sample of the mind. They are XML files with suitable style sheets to be viewed in browsers.
Infrastructures
What are infrastructures for?
An infrastructure provides the following services for the MAS:
-
communication (e.g., the local infrastructure implements communication based on KQML whilst JADE implements it using FIPA-ACL),
-
control of the agent life cycle (creation, running, destruction).
Which infrastructures are available?
The current distribution has the following infrastructures:
- Local
-
this infrastructure runs all agents in the same host. It provides fast startup and high performance for systems that can be executed in a single computer. It is also useful to test and develop (prototype) systems. Local is the default infrastructure.
- Jade
-
provides distribution and communication using Jade, which is based on FIPA-ACL. With this infrastructure, all tools available with JADE (e.g., Sniffer and Inspector) are also available to monitor and inspect agents.
Since Jason agents use KQML and JADE uses FIPA-ACL, we opted to translate the messages from KQML to FIPA-ACL and vice-versa to maintain the AgentSpeak programming the same for all infrastructures. The following table summarises the translation of the basic performatives:FIPA-ACL KQML inform
tell
query-ref
askOne
request
achieve
You can find more information about this infrastructure in the Jason-JADE tutorial.
How to select an infrastructure?
In the .mas2j
project file, use the infrastructure
entry to select
an infrastructure, for example to use Local:
MAS auction {
infrastructure: Local
agents: ag1; ag2; ag3;
}
and to use Jade:
MAS auction {
infrastructure: Jade
agents: ag1; ag2; ag3;
}
JADE applications only work with Gradle and must be executed with ./gradlew runJade
.
Note that the agents do not need to be changed for different infrastructures. The Jason Agent Architecture binds them to the available infrastructure.
When should I use the JADE infrastructures?
The local infrastructure does not support:
-
execution of the agents at distributed hosts, and
-
interoperability with non-Jason agents.
If you need any of these features, you should choose the JADE infrastructure (or implement/plug a new infrastructure for/into Jason yourself). The interoperability with non-Jason agents is achieved by JADE through FIPA-ACL communication.
JADE
How to customise the JADE container?
All parameters normally used to start a JADE container can be set in the task runJade
of file build.gradle
.
How to start a Jason agent with jade.Boot
?
The JADE agent wrapper should be used to start a Jason agent using jade.Boot
. For example, to start a Jason agent called bob
based on the AgentSpeak source code in file auctioneer.asl
,
execute the following command in a shell:
java jade.Boot "bob:jason.infra.jade.JadeAgArch(auctionner.asl)"
To start up also a simulated environment (implemented, for instance, in
the Env
class):
java jade.Boot -agents "\ environment:jason.infra.jade.JadeEnvironment(Env) \ bob:jason.infra.jade.JadeAgArch(auctionner.asl)"
The arguments for the environment have to follow the class name, for example:
java jade.Boot -agents "environment:jason.infra.jade.JadeEnvironment(Env,arg1,arg2)"
In the case you need to start a more customised agent (architecture, belief base, …), you can write (or reuse) a Jason project file with all the usual agent’s parameters and then start the agent from this file. E.g.
jade.Boot -agents "bob:jason.infra.jade.JadeAgArch(j-project,test.mas2j,bob)"
The parameter j-project
indicates that the following parameter
(test.mas2j
in the above example) is the Jason project. The third parameter
is the name of the agent as defined in the .mas2j file.
The same approach can be used for the environment:
jade.Boot -agents "j_environment:jason.infra.jade.JadeEnvironment(j-project,test.mas2j)"
AgentSpeak Language
What exactly are the cases where negative events of the forms -!p
and -?p
are generated?
A test goal ?p
in the body of a plan first checks the belief base,
and if it fails, it still tries to generate an internal event +?p
.
This is because the test goal might have been meant to be a more
sophisticated query for which the programmer created a whole plan with
+?p
as triggering event, then that plan could be executed to satisfy
the test goal. Events -!p
and -?p
are only generated if an
executing plan for +!g
and +?g
(respectively) fail. Here’s what
the manual says about this:
Events for handling plan failure are already available in Jason,
although they are not formalised in the semantics yet. If an action
fails or there is no applicable plan for a subgoal in the plan being
executed to handle an internal event with a goal addition +!g
, then
the whole failed plan is removed from the top of the intention and an
internal event for -!g
associated with that same intention is
generated. If the programmer provided a plan that has a triggering event
matching -!g
and is applicable, such plan will be pushed on top of
the intention, so the programmer can specify in the body of such plan
how that particular failure is to be handled. If no such plan is
available, the whole intention is discarded and a warning is printed out
to the console. Effectively, this provides a means for programmers to
“clean up” after a failed plan and before backtracking (that is,
to make up for actions that had already been executed but left things in
an inappropriate state for next attempts to achieve the goal). For
example, for an agent that persist on a goal !g
for as long as there
are applicable plans for +!g
, suffices it to include a plan -g! : true ← true.
in the plan library. Note that the body can be empty as
a goal is only removed from the body of a plan when the intended means
chosen for that goal finishes successfully. It is also simple to specify
a plan which, under specific conditions, chooses to drop the intention
altogether (by means of a standard internal action mentioned below).
As from version 2.5, Jason uses a different semantics for failures in
contingency plans. Previously, writing a contingency plan (i.e., a
plan of the form -!g : …
) meant the programmer knew how to control
a goal failure. It might include having other goals which might
themselves fail, but a contingency plan should not itself be allowed
to fail; a failure in the contingency plan would delete the whole
intention stack. However, if a plan for +!g2
failed and there were
no -!g2
plans given, if achieving that instance of g2
was needed
as part of a plan to achieve g1
, g1
would in turn fail as well
(possibly triggering -!g1
plans, if there were any).
The new semantics also allows failures in contingency plans to fail
other goals appearing below it in the intention stack. Note that the
fact that there was a failure in the contingency plans remains
explicitly represented in the intention stack, so that the an agent
could, in principle, reason about those failures in deciding on how to
act further. When a contingency plan -!g2
fails, the failure
cascades down the intention stack until a plan for a achieving a goal
!g1
which does have contingency plans -!g1
is found; in that
case, the event -!g1
is posted, so an applicable plan for that event
will be at the top of the intention stack and the failed -!g2 : …
plan will be right below it within the stack. Only in case no such
plan is found the whole intention is removed from the intention set
(and a message to say so is printed in the console, as usual).
Does +p
(or -p
) in a plan body cause two effects, i.e. updating the belief base and generating the events +p
(or -p
)?
Yes, it causes both effects. Note, importantly, that one of the interpreter configuration options allow the user to choose whether the event (if it is by chance relevant to any plans the agent has) will be treated as internal (pushed on top of that same intention) or external (a new intention – i.e., a new focus of attention – is created).
Does ?p
in a plan body cause two effects, i.e. testing p from the belief base and generating the events +?p
? Is -?p
generated when a test goal ?p
fails? When does the test goal ?p
fail?
When ?p
is executed, first the interpreter tries a simple query to
the belief base. If that doesn’t succeed, before failing the intention,
first an internal event for +?g
is generated, if there are no
applicable plans for such event, then the plan fails (fails
normally, i.e., for the "no applicable plans" reason) — there
could be still a -?g
plan to be tried; if there’s none, the
intention is discarded and a message printed to the console to let the
user know.
It is claimed that open-world assumption is available. What does this mean? Do we have a three-valued logic?
No, we don’t use three-valued logic, strictly speaking. There is a
strong negation operator ~
. When assuming open world, the user
models the environment with a set of propositions known to be explicitly
true and a set of propositions known to be explicitly false of the
environment at a certain moment in time (the latter are literals
preceded by the ~ operator). Of course, there is still default negation
(as usual in logic programming languages), so you can say, in the
context of a plan, not p(t) & not ~p(t)
to check if the agent is
uncertain about p(t)
. Note that it’s completely up to the user to
prevent paraconsistency (or to use it, if they so wish). You could add
internal beliefs (or have beliefs from perception of the environment)
that p(t) is true and that p(t) is also true: Jason won’t do consistency
checks for you! But you can easily implement such consistency check, or
indeed have more elaborate belief revisions algorithms by overriding the
belief update and belief revision methods in Jason (the belief revision
method by default does nothing). Finally, note that strong negation can
also appear in the triggering events, plan body, and anywhere a literal
can appear.
What’s the difference between ! and !!?
The difference between ! and !! is that the latter causes the goal to be
pursued as a separate intention. Within the body of a plan in one
intention, if you have !g1; !g2
the agent will attempt to achieve g2
only after achieving (or finishing executing a plan for) g1. If you say
!!g1; !g2
the agent will then have another separate intention to
achieve g1 and can immediately start attempting to achieve g2. What will
be done first (executing a bit of the intention with g1 or the old
intention with g2) will depend on the choices that the intention
selection function makes.
You may have noticed !! is often used at the end of recursive plans (when the recursive call does not have free variables to be instantiated) as in the following code:
+!g : end_recursion_context.
+!g : true <- action1; !!g.
In this case, the !! is used to avoid Jason creating long stacks of (empty) plans, so the operator just allows Jason to process the recursion more efficiently.
Jason 1.4.0 implements tail recursion optimisation and thus we don’t need to worry about the stack size anymore. The above code should be written as:
+!g : end_recursion_context.
+!g : true <- action1; !g.
Why is Jason’s plan failure mechanism different from other agent platforms?
Some other platforms handle plan failure in the following way. When a plan is selected as an intended means to achieve a goal (more generally, to handle an event), other applicable plans might be available or indeed other instantiations of the plan’s variables (to make the context a logical consequence of the belief base) might be possible. Those platforms then make a note of all those plans and plan instantiations. If the plan currently being executed fails, another plan is chosen from that set of plans initially recorded as alternative plans for handling that event. This has the great advantage that the platform does not have to check for applicable plans again, and has as disadvantage the fact that possibly the agent’s beliefs have changed and so plans considered applicable at the time the first plan was selected, are actually no longer applicable (yet they will be attempted, which increases the chances of the chosen alternative plan failing as well).
In Jason, we opted for a different approach. When a plan with a triggering
event +!g
fails, we generate an event -!g
and if the
programmer provided a plan for that event, and that plan is currently
applicable, that plan is pushed on top of the intention where the failed
plan is. In the general case, the programmer will have included in that
-!g
plan another attempt to achieve g
. When this happens,
all relevant plans will be checked again to find the set of currently
applicable plans. Under the assumption that the contexts have been well
defined by the programmer, only plans that now stand a chance of
succeeding will be applicable. Differently from the above mechanism,
here we have the advantage of being better updated on the set of
actually applicable plans, but might be less efficient in that more
checks need to be done.
Another disadvantage of this approach is that to make sure a plan will
only be tried once (if in a particular application this is important,
although this is not always the case, surely), as it happens in other
platforms, the user will have to use, e.g., the belief base to keep
track of the previously attempted plans, or else to have the applicable
plan selection function checking the failed plans in the stack of plans
forming that intention (note that the failed plans are still there and
will only be removed, without executing further, when the respective
plan for -!g
finishes) to decide which ones not to use anymore.
Off course the latter requires considerable Java programming). For the
first alternative, there is work on plan patterns and pre-processing
directives which take care of automating this for the programmer.
On the other hand, there is an extra advantage of the use of the Jason plan
failure handling mechanism. Pure backtracking as used in logic
programming might not always make sense in an agent program. Recall that
besides sub-goals, plan bodies have actions. These actions, by
definition, change something that is outside the agent itself (i.e., the
environment), so they cannot automatically be undone by the
interpreter in the process of backtracking. It is therefore possible
that none of the plans originally written (with a particular set of
initial situations in mind) to achieve the goal will be applicable
anymore. At least in some cases, it might be sensible to let the
-!g
plan perform the necessary actions to bring the environment
back to a reasonable state in which the original plans to achieve
the goal can then be used again, rather than writing more alternative
plans for the original goal considering all possible situations in which
the agent can find itself when attempting to achieve the goal.
Which information is available for failure handling plans ?
When a plan fails, the plan that handles the corresponding event (that
has the form of -!g
) may use failure information to provide a suitable
solution. This information is provided by two means:
- Internal actions
-
the internal action
.current_intention(I)
unifiesI
with a representation of the stack of the current intention. By inspecting this stack, the context of the failure can be discovered.It follows an example of
I
(provided by the execution of the example available indemos/failure
):intention(1, [ im(l__6[source(self)], { .current_intention(I); ... }, [map(I,...),...]), im(l__5[source(self)], { .fail }, []), im(l__4[source(self)], { !g5(X); .print(endg4) }, [map(X,failure)]), im(l__3[source(self)], { !g4(X); .print(endg3) }, [map(X,failure)]), im(l__2[source(self)], { !g3(X); .print(endg2) }, [map(X,failure)]), im(l__1[source(self)], { !g2(X); .print(endg1) }, [map(X,failure)]), im(l__0[source(self)], { !g1(X); .print("End, X=",X) }, [map(X,failure)]) ] )
You can find more information in the documentation of the .current_intention pre-defined internal action.
- Annotations
-
every failure event is annotated with at least the following information:
-
error(<atom: error id>)
: the identification of the type of failure; values used by Jason are:-
no_applicable
: failure caused by no applicable plan; -
no_relevant
: failure caused by no relevant plan; -
no_option
: failure caused by no option being selected by the selectOption function; -
constraint_failed
: failure caused by a constraint in the plan that was not satisfied; -
ia_failed
: failure caused by an error in an internal action (it throws an exception or returned false); -
action_failed
: the failure was caused by a failure in the execution of an action in the environment (i.e., the action execution returnedfalse
); -
ask_failed
: the failure is caused by the lack of response to an ask message (with deadline); -
wrong_arguments
: failure caused by wrong number or type of arguments given to an internal action; -
unknown
: other causes;
-
-
error_msg(<string>)
: the human readable message of the error -
code(<literal>)
: the plan body literal that failed; -
code_src(<string>)
: the file name with the source code where the plan that failed is defined; -
code_line(<int>)
: the line number within that file.
An example of failure event and its annotations:
-!g[error(ia_failed), error_msg("internal action .my_name failed"), code(".my_name(bob)"), code_src("/tmp/x.asl"), code_line(18)]
Note that the plan that handles this event is not obliged to use any these annotations, or it could make use of a subset of them, for example:
-!g[error(ia_failed)] <- ... plan to handle error of type 'ia_failed' -!g[error(no_applicable)] <- ... plan to handle error of type 'no_applicable' -!g[code_src("/tmp/x.asl")] <- ... plan to handle error in plans of file x.asl
The internal actions defined by the user can add new annotations to indicate particular types of errors (see the API documentation of JasonException for more information about that).
-
How can an agent know (and reason about) its own goals?
Jason provides a set of internal actions to help agents to reason about their intentional state (the list of these internal actions is available here). This topic is also discussed in the BDI Hello World tutorial.
As a simple example, the following code allows the agent to discover the identifier of the current goal and the state of others.
// creates 4 intentions
!start(a).
!start(b).
!start(c).
!start(d).
+!start(X) // simple loop printing X
<- .print(X);
.wait( math.random(1000)+1000 );
!inspect(X);
!start(X).
// this plan uses BDI internal actions to discover the current goal
+!inspect(X)
<- .intention(Id,State,Stack,current); // gets the state of the current intention
.print("current intention number is ",Id," and its state is ",State);
Stack = [Top|_]; // get the intended means in the top of current intention
Top = im(Label, { +!Goal },PlanBody,Unifier);
.print("current goal is ",Goal," being pursued by plan ",Label);
Goal =.. [NameSpace,Functor,Terms,Annots];
.print("its functor is '",Functor,"' and terms are ",Terms);
// prints out all other intentions
for ( .intention(_,OtherState,[ im(_, { +!OtherGoal },_,_) |_]) & OtherGoal \== Goal) {
.print("another goal of mine is ",OtherGoal," in state ",OtherState);
}.
The most important internal action used in the example is .intention
.
The output is:
a b c d current intention number is 3 and its state is running current goal is inspect(c)[source(self)] being pursued by plan p__2[code_line(14),code_src("file:sample_agent.asl"),source(self)] its functor is 'inspect' and terms are [c] another goal of mine is start(b)[source(self)] in state waiting[reason(wait(2)[time(1802)])] another goal of mine is start(d)[source(self)] in state waiting[reason(wait(4)[time(1965)])] another goal of mine is start(a)[source(self)] in state waiting[reason(wait(1)[time(1667)])]