home » user manual » nuinscript

The Nuinscript agent scripting language

As previously mentioned (here), Nuin agents form intentions to act out plans. Internally, the plans are Java objects, and can be generated in variety of different ways, including by directly invoking the action constructors. However, the most convenient way, currently, is to write agent scripts in Nuinscript, which is parsed into the Java objects used by the interpreter. Our goal with Nuinscript is to provide a compact notation that allows the agent developer to concetrate on high level descriptions of the agent's activity. By contrast, programming such behaviours in Java, for example, can make the overall structure of the operation of the agent hard to discern.

This section of the user manual gives an overview of the various constructs available in Nuinscript. A forthcoming reference manual will give more details, but this is not available yet.

Overall structure

A Nuinscript script is read from a file, denoted by a URL (see agent configuration). The script file may contain any of the following, in any order (though prefixes have to be declared before they are used):

Each of these is described in detail below. Note that Nuinscript is case-sensitive.

Prefix declarations

All symbolic constants in Nuin are URI's. This provides a means of disambiguating symbols with similar names but different namespaces, which are likely to occur in open agent systems. It also makes interoperation with Semantic Web knowledge sources easier. However, in programs URI's are often ungainly, and, being quite long, tend to obscure structure. For this reason, RDF/XML, N3 and other languages permit URI's to be shorted to q-name form, or prefix:name. Nuin also supports this style of abbreviation. Prefixes are declared in Nuinscript programs with the use keyword:

 use ex for <http://example.org/foo#>.

This allows subsequent code in that file to use ex: as a prefix. So ex:CD is equivalent to <http://example.org/foo#CD>. Some prefixes are built-in to Nuin, as listed in Table 1.

Prefix URI
acl http://www.nuin.org/ontology/fipa/acl#
(see note below)
action http://www.nuin.org/ontology/action#
config http://www.nuin.org/ontology/config#
event http://www.nuin.org/ontology/event#
fipa http://www.nuin.org/ontology/fipa/faa#
(see note below)
jade http://www.nuin.org/ontology/jade#
(see note below)
ks http://www.nuin.org/ontology/ks#
ksconfig http://www.nuin.org/ontology/ksConfig#
lib http://www.nuin.org/ontology/lib#
parsers http://www.nuin.org/ontology/parsers#
query http://www.nuin.org/ontology/query#
selfModel http://www.nuin.org/ontology/selfModel#
svc http://www.nuin.org/ontology/service#
sl http://www.nuin.org/ontology/fipa/sl#
(see note below)
nuin http://www.nuin.org/ns#
owl http://www.w3.org/2002/07/owl#
rdf http://www.w3.org/1999/02/22-rdf-syntax-ns#
rdfs http://www.w3.org/2000/01/rdf-schema#

Table 1: built-in prefixes

Note: that constants in the FIPA and Jade ontologies are currently in the Nuin namespace. This is deliberate, though undesirable. We do not have the authority, morally or technically, to assign namespaces in the Internet domains of FIPA or Jade. Until such time as the organisations responsible for those domains create an suitable set of public URI's, or open a namespace for general use, we have to use our own namespace to define these names. Developers should be aware that these URI's will (hopefully) change at some point in future.

At the Java level, namespaces are managed by the PrefixManager.

Knowledge store declarations

A script can contain any number of collections of initial data for the agent's knowledge bases. In Nuin, all knowledge bases are termed, in general, knowledge sources; knowledge sources that actually store asserted data (as opposed to presenting some interface capability) are knowledge stores. Initialising a knowledge store through the script is not the only way of ensuring that agents start up with a certain amount of background knowledge (for example, an alternative is for the agent to connect to a persistent RDF store), but it is convenient for many uses.

Every knowledge source is labelled with a KsIdentifier, identifying the role of the KS to the agent. By default, each agent is expected to have one KS that defines its beliefs; this KS is labelled with the identifier ks:B. If identifier is assigned to an agent's KS, it will default to ks:B. It is an error for an agent to have more than one KS labelled beliefs.

The general form of the knowledge store declaration is as follows (where square brackets denote optional syntax):

 axioms [ks identifier] [standardised] [ontology uri [, uri]* ]
    [contains sentence .  [sentence .]* ]
 end.

The ks identifier is a term or symbol labelling this knowledge store. If the keyword standardised is used, the store is permitted to use meaning-preserving transformations (e.g. commutativity of conjunction and disjunction) to re-order the operands of a sentence into a standard order. This makes building retrieval indexes for the KS easier, and some queries more robust.

A knowledge store may be associated with one or more ontologies. See the reasoner documentation for details on the use of ontologies. Each ontology is identified by URI, which may be specified in namespace:name form if a suitable prefix has been defined.

Finally, a knowledge store may specify a set of initial sentences that are asserted into the KS before the agent starts. Each sentence is terminated with a full-stop (aka period, '.').

A simple example knowledge store:

 axioms ex:geography standardised contains
   ex:connected( city:Bristol, city:London, train ).
   ex:connected( city:Bristol, city:London, motorway( m4 ) ).
   ex:connected( city:Bristol, city:Birmingham, motorway( [m5, m6] ) ).
 end. 

Plan declarations

See other sections of this user manual for more details on the representation of plans. The outline of a plan declaration is:

 plan [plan ID]
     [ weight integer ]
     [ comment string ]
     [ label string ]
     [ postcondition sentence ]
     [ trigger trigger-expression ]
     [ do action-expression ]
     [ with intention (var | symbol) 
        [vars var [, var]* ] ]
 end.
      

The use of the various elements of the plan declaration are covered elsewhere. Since this section of the manual is focussed on the script syntax, we will only expand here the syntax and use of the various action expressions.

General composition of action expressions

The body of a plan is a single action expression. Multiple actions can be composed together to form a single expression with two operators: ; (semicolon) composes two actions sequentially, so that the second is performed after the completion of the first, and | (pipe symbol) composes actions as a choice between two operations. In principle, this is a non-deterministic choice (following the semantics of the logical frameworks the operator was derived from). In practice, the alt operator attempts the left-hand operand action first, and tries the right hand operand only if the left-hand fails. The precedence of the sequence operator is higher than that for alt, so an expression: 'a0 | a1 ; a2' parses as: 'a0 | (a1 ; a2)'. The grammar allows parentheses to be used to group operands together, so the action "either a0 or a1, followed by a2" is coded as: '(a0 | a1) ; a2'.

Actions, when executed by the interpreter, return one of four result states. They are:

An action that succeeds allows the interpreter to move on to the next action in the action expression. So, in an action expression 'a0 ; a1' once a0 succeeds the interpreter can begin executing a1.

Some actions changes the agent's environment, so that choices that were available before the action are not available afterwards. Suppose a robot is at a junction in a maze, with a choice of two paths: left and right. We might model this as a choice of two actions: go(left) | go(right). However, this does not work as written because, having made the choice to go left, the robot is no longer at the junction where it could alternatively choose to go right. So, if by going left the robot fails to find its destination, the interpreter cannot naively backtrack to the alt choice and execute the go(right) action. These issues are well-known in AI, and we do not claim to have anything approaching a complete solution in Nuin. However, to allow some degree of support for this problem, we allow actions to return two success conditions, one which implicitly cuts off prior choices, and one which allows backtracking though past choice points. For readers familiar with Prolog, this is similar to the cut operator (i.e '!') applied automatically.

Of course, the action may also fail to complete successfully. This state is conveyed through the failure return state. A failed action will cause the interpreter to search for an alternative (if it has not yet committed). Note that the current backtracking code is being overhauled. Backtracking in Nuin does not work properly in the 0.2 release; some caution is advised!

Some actions have a long enough duration that they require more than one step of the interpreter to complete. This is true of compound actions (such as sequence and alternative), which don't complete until all of their sub-actions have completed. It is also true of actions that suspend the parent intention until some later condition occurs. However, it may also be the case that an action simply takes a long time (real or simulation) to complete. In each of these cases, the action returns the not completed state, and it will be re-scheduled by the interpreter.

The following sections outline the individual action types that are currently supported by the script parser.

index of script actions

» achieve » add goal » add sub-goal » agent name
» assert » commit » deny » dispatch
» drop intention » drop goal » evaluate expression » fail
» has intention » has plan » has sub-goal » holds
» intend » invoke » invoke service (@) » maintain
» occurred » post » resume » retract
» send » shutdown » substitute vars » suspend for
» unification

Script action: achieve a postcondition

Synopsis: achieve sentence
Example: achieve has(cupOfTea, ArthurDent)

Form an intention that the given sentence becomes true. In general, we would like this to invoke goal-directed problem solving to achieve the given sentence. In the current implementation, a much weaker and more restricted form is available. Specifically, the goal sentence will attempt to schedule as intention-that intentions plans whose postcondition is structurally isomorphic with that sentence, allowing for unification of values. So 'achieve p(?x) && q(?x)' will match a plan post-condition of 'achieve p(1) && q(1)' but not 'achieve p(1) && q(2)'.

Script action: adding a goal (desire) to the agent

Synopsis: add goal [( agent-ID )] predicate [as var]
Example: add goal(person:ian) attendConference( "AAMAS 2004" ) as ?g

The agent maintains a set of explicit goals that it has, corresponding to the D modality in the BDI model. These are a set of logical predicates that denote the set of states of the world that the agent would like to bring about (as opposed to the intentions, which can represent states that it is committed to bringing about). Add goal gives a means of adding predicates to a goal base labelled with the identity of the actor holding the goal. This makes it possible, for example, for an agent to have an explicit separation between its own goals, and those of its human owner. The owner may have the goal to go to New York in July 2004, consequently the agent may have goals of arranging travel and accomodation, etc.

Each goal predicate added to the goal base is assigned a unique identifier as a UUID symbol. It may be desireable for the agent to use this identifier in subsequent interactions (e.g. as a reply-with field in an outoing ACL message. The add goal action therefore has the option of assigning the goal ID to a variable given in the as clause of the action.

Script action: add a sub-goal to a goal

Synopsis: add subgoal [( agent-ID )] predicate to reference goal-ref]
       add subgoal [( agent-ID )] reference goal-ref to reference goal-ref]
Example: drop goal(person:ian) ref ?g

Add a sub-goal to an existing goal in the goal base. Building hierarchical structures of goals and sub-goals is helpful in some agent applications to allow the agent to focus on the appropriate tasks at hand, and co-ordinate multiple behaviours.

Script action: test the agent name

Synopsis: agentName( var )
Example: agentName( ?nm )

Succeeds if the given variable, which may be bound or unbound, unifies with the unique name of this agent. The unique name is either specified in the configuration file, or assigned to the agent on startup as a UUID-based URN.

Script action: assert a sentence into the KB

Synopsis: assert sentence using context context-ID
       assert sentence [in ks-ID]
Example: assert ex:p(?x) && ex:q(42) in ex:ks1

Assert a sentence into the nominated KS, or using the KS identified by the nominated knowledge context. If no KS or context is specified, the sentence is by default asserted into the agent's beliefs.

Script action: commit

Synopsis: commit

Causes the agent interpreter to commit to the current course of action, which in practice means that choice points prior to the commit will be discarded. Note: backtracking behaviour in Nuin 0.2 is incomplete.

Script action: deny a sentence in the KB

Synopsis: deny sentence using context context-ID
       deny sentence [in ks-ID]
Example: deny ex:p(a)

Asserts the falsity of a sentence form the nominated KS, or using the KS identified by the nominated knowledge context. In most KS's, this is equivalent to asserting the negation of the sentence, and this is typically the way that deny is implemented..

Script action: add a dispatch rule to a context

Synopsis: dispatch [spec] to ks-name [priority p] [in context-ID]
Example: dispatch p 2 to ex:pKS priority 10
          dispatch ns <http://my.com/ontology> to ex:ontKS

Adds a dispatch rule to the named KS context object (or the default context if none is specified). The context object helps the agent to manage access to multiple knowledge sources, by providing rules that direct updates and queries to specific sources, depending on either predicate name and arity, or namespace prefix. Experimental feature, use with caution.

Script action: dropping an intention

Synopsis: drop intention intention-ID

Recognised by the script parser but not implemented yet.

Script action: drop a goal (desire)

Synopsis: drop goal [( agent-ID )] [predicate] [reference goal-ref]
Example: drop goal(person:ian) ref ?g

Removes a goal from the specified goal base, either by explicit reference or by matching the structure of the goal predicate.

Script action: evaluate an expression

Synopsis: var|int|double is arith-expr
Example: ?x is 10 + 3 * 4

Succeeds if the value or variable on the left hand side unifies with the result of evaluating the right hand side as an arithmetic expression. The arithmetic operators available are currently: + - * / () %. The rhs expression can contain variables bound to numerical values; these will be substituted before the expression is evaluated. The multiplication and division operators take precedence over the addition and subtraction operators, so the above example would evaluate to 22.

In addition to the arithmetic operators, the expression evaluator will evaluate the following functions:

Script action: fail

Synopsis: fail

Action that only returns the failure action status. This will cause the interpreter to backtrack to the previous choice point, or, if there isn't one, to terminate the intention with a failed status.

Script action: test whether the agent has a given intention

Synopsis: has intention to plan-ID
      has intention achieve sentence
Example: has intention to ex:relocateTo( ?city )

Succeeds if the argument denotes a currently active or suspended intetion that the agent has.

Script action: test whether the agent has a named plan

Synopsis: has plan plan-ID
Example: has plan ex:attendConference( ?conf, ?city )

Succeeds if the agent has in its plan library a plan whose name matches the given plan-ID term.

Script action: test whether the agent has a sub-goal of a given goal

Synopsis: has subGoal [( agent-ID )] goal-ref of goal-ref
      has intention achieve sentence
Example: has subGoal( ex:user ) sellShares( ?stock, ?qty ) of reference ?parent

Succeeds if the argument denotes a current sub-goal, of a given goal, in the given goal-base, or the default goal base if none is specified. Both the sub-goal and parent goal may be specified as predicates or goal references.

Script action: test whether a sentence holds in a ks

Synopsis: holds [premise] sentence [using context context-ID] [in ks-ID]
Example: holds ex:name( ex:ian, ?x ) in ex:ontKS

Succeeds if the given sentence can be proved in the given knowledge source or context. The sentence may be non-ground, in which case the action suceeds if a consistent set of bindings can be found for the variables. Forthcoming modifications will improve the ability to capture all such sets of variable assignments, not just the first.

Script action: intend another plan as a separate intention

Synopsis: intend plan-ID
Example: intend buy( movieTicket, adult(2), "Last Samurai")

Creates a new intention-to perform the given plan. This intention is added to the set of active plans maintained by the agent interpreter, and the current intention carries on immediately. That is, the intend action does not wait for the intended plan to complete. For this alternative semantics, see action invoke.

Script action: invoke a plan

Synopsis: invoke plan-ID
Example: invoke ex:moveTo( ex:corridor27 )

Create a new intention-to perform the named plan. Unlike the intend action, invoke waits for the invoked plan to terminate before continuing. If the invoked plan fails, this action also fails.

Script action: invoke an method on a plug-in service

Synopsis: @ [ [type =] symbol ] service-entrypoint
Examples: @ lib:getIntentionID( ?id )
        @ [type=svc:messageService] action:bind

Locates a plug-in service, by name or by type, and invokes a method on it by passing a term denoting the action to be performed. Nuin uses agent services as a mechanism to allow run-time extensions to the agent's capabilities. Each service has a name, and belongs to a service type. Both are denoted by symbols. The @ action takes a service name or type, and attempts to look up a service with that name or type first it the agent's service registry, and if not found there, the global (shared) service registry. If neither the service name nor type is specified, the @ action will default to service:actionsLibrary, which is a service that exists to provide simple, shared library routines.

The arguments to the library call may be variables. If the variable is bound, the bound value will be passed to the service wrapper; if the variable is unbound it may be used to pass results back from the service invocation.

Script action: maintain a condition

Synopsis: maintain sentence

Recognised by the parser, but not yet implemented.

Script action: test whether a given event pattern has been observed

Synopsis: occurred event-pattern
Example: occurred after event alarm( 10 )

Succeeds if the given trigger expression matches the current event history (i.e. on matches the current event, and each after match the current event or the remebered events). Does not wait for the pattern to become true (see the resume action).

Script action: post an event

Synopsis: post event
Example: post event alarm {type=done(fjord), source=slartibartfast}

Create a new event, and post it to the agent's event queue, where it will be considered by the interpreter in the normal way. Note that since a message is a sub-type of event, this action can be used for the agent to send a message to itself.

Script action: suspend the intention until a given trigger occurs

Synopsis: resume trigger
Example: resume on ?m as message {sender=ex:market}

Causes the intention to suspend until the given trigger pattern becomes true.

Script action: retract a sentence into the KB

Synopsis: retract sentence using context context-ID
       retract sentence [in ks-ID]
Example: retract ex:p(?x) && ex:q(42) in ex:ks1

Removes a sentence form the nominated KS, or using the KS identified by the nominated knowledge context. If no KS or context is specified, the sentence is by default retracted from the agent's beliefs. If the sentence, in the form in which it is retracted, is not asserted into the KS, then nothing will be removed. For example, retracting p(x) will not side-effect the asserted sentence p(x) && q(x).

Script action: send a message

Synopsis: send message
Example: send message() {acl:receiver=[?a], acl:sender=ex:me,
          acl:performative=acl:inform, acl:content=sentence( p(x) )}

Constructs and sends a message via a service instance of type service:messageService. See elsewhere in the manual for more details on messages.

Script action: shutdown

Synopsis: shutdown

Causes the agent interpreter to terminate once the action completes. Once the interpreter terminates, the agents thread will also close. For future extension: there should be some means of ensuring that finalization code, e.g. closing open connections to remote KB's, has a chance to happen before the thread terminates.

Script action: substitute the variables in a value

Synopsis: substituteVars( value0, value1 )
Example: substituteVars( purchase(?quant,?product), ?order )

Succeeds if value1 unifies with value0, assuming that value0 has had all of its bound variables replaced by their bound values. Value1 is often a variable, that will then hold the ground form of value0, but it doesn't have to be.

Script action: suspend the intention for a period of time

Synopsis: suspend for duration
Example: suspend for 1300ms

Causes the intention to suspend for the given duration, then wake up again and resume processing. This can be used to build in some time-dependent behaviour into the script. Note, however, that the semantics is that after the specified duration, the intention will wake up again and go into the normal queue maintained by the interpreter. This means that it will not be less than duration before the intention wakes up, but it may be more. This mechanism is therefore not recommended for building simultions that depend on accurate time-based scheduling.

Script action: test whether two values unify

Synopsis: value0 == value1
        value0 != value1
Example: x( ?a, 0 ) == x( 17, ?b )

Succeeds if the two value terms do (==) or don't (!=) unify.

Other references

The grammar for Nuinscript is available in BNF, as generated by jjdoc.

« prev: knowledge representation | nuinscript | next: events & messages »