ModSAF Agent Layer Language

Version 2.0

John Dowding

November 14, 1996


This document describes the representation and functionality supported by the ModSAF agent layer, as implemented by the ModSAF library liblesaf. This library provides the interface between ModSAF and the contextual interpretation agent in CommandTalk. The interface is not limited to this use, but can support other agents that need to communicate with a ModSAF simulation. The first section of this document provides some necessary background to understanding the Open Agent Architecture. This is followed by a description of the command data types used in the ModSAF agent language, then by a detailed list of all the commands currently supported by the agent interface.

This document presumes a significant background knowledge of ModSAF's persistent object (PO) database. This information can be found in the ModSAF documentation for libpo. While this background is necessary to understand some of the finer details, a general understanding of the agent language can be obtained without it.

Changes in this release

This release incorporates a large number of improvments over the previous release, including additional functions, extensions to previously existing functions, and a new set of message types that are generated by ModSAF whenever new objects are added to the PO database. These functions are new in this release:

These functions have been extended in this release:

Lastly, ModSAF will now broadcast messages whenever persistent objects are created, modified, or destroyed, whether these changes resulted from actions initialized through MALL, or through the GUI. This allows much greater interoperability between the GUI and other interfaces.


Messages in the Open Agent Architecture are implemented as strings which encode Prolog terms. Although agents can be written in a variety of programming languages, the first agents were written in Prolog, and Prolog term syntax has proven to be a general method of encoding agent messages. The Open Agent Architecture library provides constructor and selector functions for manipulating Prolog terms.

In the Open Agent Architecture, every message sent is considered a query, and generates a set of responses. As each agent is initialized, it broadcasts the types of queries it answers to a facilitator.

Prolog Term Syntax

As a necessary background to understanding Open Agent Architecture messages, this section provides a brief introduction to Prolog term syntax. If you are familiar with Prolog term syntax, skip ahead to the next section.

A Prolog term is either a constant, a variable, or a compound term.

Functor(Arg1, Arg2, ..., ArgN)

There is a special case of a compound term called a list. A list is just a syntactic variant of a regular compound term, where the Functor is omitted, and the arguments are printed in square brackets, and separated by commas:

[Arg1, Arg2, ..., ArgN]

A list that contains no elements is treated as a special case, and is represented by the atom [].

When Prolog variables take on the values of other terms, they are said to become instantiated. When a Prolog term contains no uninstantiated variables, it is ground. If two terms are such that they could represent the same term by instantiating variables, then the two terms are said to be unifiable.

We will use some standard notations for describing Prolog terms. The notation Functor() refers to a Prolog term whose functor is Functor. The notation Functor/Arity refers to a prolog term whose functor is Functor, and that has Arity arguments. The calling pattern for a function is expressed by preceding each argument with either a +, -, or ? character. The + character indicates that the position must be instantiated in the call, the - character indicates that the position must not be instantiated, and the ? character indicates that the position may or may not be instantiated.

ModSAF Queries

The ModSAF agent layer responds to only one type of query. This query will always be a compound term whose functor is the atom modsaf, with just one argument.


Since an agent query may have zero, one, or more solutions, the solutions are expressed as a Prolog list. Each element of this list should be unifiable with the original query.

[modsaf(...), modsaf(...), ..., modsaf(...)]

Data Types

This section describes the common data representations that are used across the various MALL functions. Most often, these correspond directly to ModSAF data types or structures, but sometimes just enforce a common representation for the interface, for instance requring all speeds to be expressed in meters per second.

Persistent Object (PO) Identifiers

Every object in the PO database has a unique identifier that consists of a site, a host, and an object. These are represented as a list of 3 integers, [Site, Host, Object].

Vehicle Identifiers

Vehicle Identiers appear like PO identifiers, as a list of 3 integers, [Site, Host, Vehicle]. However, only actual simulated vehicles have Vehicle Identifiers, excluding command entities, and other persistent object types. Vehicle Identifiers are required to issue some task frames that refer to specific individual vehicles, such as 'Follow Vehicle', and 'Embark'. If a persistent object has a vehicle identifier, it can be obtained through the function poid_to_vehicle_id().

Simulation Addresses

A simulation address uniquies identies a single machine involved in a simulation. It is represented as a list of 2 integers, [Site, Host].


Universal Transverse Mercator coordinates are used to describe every location in the simulated world. UTM coordinates are represented by a 5 argument term:

utm(ZoneNumber, ZoneLetter, MapSheet, Easting, Northing)


Many agent layer commands take locations as an argument, such as objectives to assault, or map locations to center on. There are two basic ways to express locations, as UTM coordinates, and as locations of known persistent objects. Currently, units, points, and lines have known locations, so persistent object identifiers for these can be substituted for UTM coordinates. The underlying ModSAF functions may require that these arguments be of a specific type (such as point or x-y coordinate), so the agent layer will always coerce locations into objects of the appropriate type.

Magnetic Headings

Magnetic headings are integers, 0-360, that indicate a direction. These are used to orient points and units.


Speeds are floating point numbers, and are always expressed in meters per second.

Symbolic Constants

Much of the specific unit and task information contained in ModSAF is stored in data files that are loaded at run time. These files are written in RDR format. To make the interface with ModSAF as streamlined as possible, we use the same symbolic constants that ModSAF uses to refer to domain-specific information.

Symbolic constants are always Prolog atoms in the agent language. They may need to be quoted if they do not start with a lower case letter.

While the set of legal symbolic constants is subject to change with each ModSAF version, the most common values used in MALL are unlikely to change. Included below are some of the more common types.

Lines can have several diffent styles of arrow heads. These styles are represented with the symbolic constants noArrowHead, lineArrowHead, and blockArrowHead.

Boolean values are represented using the symbolic constants true and false.

Colors are represented using these symbolic constants: OCOverlayDefault, OCBlack, OCYellow, OCRed, OCGreen, and OCBlue.

Force Identifiers are represented using these symbolic constants: distinguishedForceID, otherForceID, observerForceID, and targetForceID.

Line Styles are represented using these symbolic constants: LSplain, LSfrontA, LSfrontB, LSminefieldAT, LSminefieldAP, LSberm, LSATDitchA, LSATDitchB, LSwire, LSminefieldMarker, LSbreachLaneMarker, and LScommunication.

Point Styles are represented using these symbolic constants: PSgeneral, PScoordinating, PScontact, PScontrol, PSfortification, PSTAI, PSNAI, PSdecision, PSTRP, PSorientation, PSentryExit, PSinitial, PSenRoute, PStarget, PSrendezvous, PSegress, and PSpenetration.


In addition to those relatively closed classes, there are two classes that are used extensively in MALL that change routinely with every new ModSAF release. These are unit types, and task models.

Unit types are symbolic constants that identiy every distinct type of unit in ModSAF. These are enumerated in:

<ModSAF Version>/common/data/units.rdr

Any unit type declared in units.rdr can be created through MALL.

Task models are symbolic constants that identify the distinct tasks that combine in ModSAF taskframes. The taskframes and their corresponding task models are defined in:

<ModSAF Version>/common/src/ModSAF/taskframes.rdr>

Unfortunately, not all models can be accessed through MALL. Since MALL depends on libtaskutil, only those models that have been properly initialized in libtaskutil can be used.


Formations are atoms, such as column, line, wedge, and vee. Although formations are not symbolic constants, legal formation atoms can be found in the units.rdr data file.

Querying the PO Database

These functions together provide a relational interface to the persistent object database. These functions are used by the contextual interpretation agent to determine the state of the simulation in order to properly determine referents for noun phrases, and interpret new commands correctly in context. Only a subset of the features for objects in the PO database are included in these queries.

list_entities(entity(?POID, ?Marking, ?Type, ?UTM, ?Force, ?Commander, ?TaskFrame, ?Overlay, ?Appearance))

list_entities/1 queries the PO database for a subset of the information contained in UnitClass objects.

list_hhours(h_hour(?POID, ?Name, ?Force, ?Defined, ?Time))

list_hhours/1 queries the PO database for a subset of the information contained in HHourClass objects.

list_lines(line(?POID, ?NumPoints, ?Points, ?BeginArrow, ?EndArrow,?Color, ?Closed, ?Dashed, ?Splined, ?Style, ?Thickness, ?Width, ?Overlay))

list_lines/1 queries the PO database for a subset of the information contained in LineClass objects.

list_mine_fields(mine_field(?POID, ?Overlay, ?Style, ?Color, ?Text, ?Munition, ?Detonator, ?Commander, ?Simulator, ?Type, ?Simulated, ?Methodology, ?Variant))

list_mine_fields/1 queries the PO database for a subset of the information contained in MinefieldClass objects

If the value for Type is minefieldTypeArea, then Variant will have this structure:

list_overlays(overlay(?POID, ?Name, ?Color, ?Scratch, ?Working, ?Force))

list_overlays/1 queries the PO database for a subset of the information contained in OverlayClass objects.

list_points(point(?POID, ?UTM, ?Name, ?Style, ?Color, ?Dashed, ?Direction. ?Overlay))

list_points/1 queries the PO database for a subset of the information contained in PointClass objects.

list_task_frames(task_frame(?POID, ?Name, ?Opaque, ?Unit, ?NextStackFrame, ?PreviousMissionFrame, ?SponsoringTask, ?EnablingTasks))

list_task_frames/1 queries the PO database for a subset of the information contained in TaskFrameClass objects.

list_task_authorizations(task_authorization(?POID, ?ProposedTaskFrame, ?ModifiedTaskFrame, ?UnitPOID, ?Authorized, ?Reason))

list_task_authorizations/1 queries the PO database for a subset of the information contained in TaskAuthorizationClass objects. TaskAuthorizationClass objects are created whenever a command is given 'on-order', which causes a button to appear in the GUI on the menu bar to allow the user to provide the anticipated command.

Currently, task authorizations are only used in the agent language for on-order enabling tasks. In this case, the ProposedTaskFrame and ModifiedTaskFrame are empty, that is, they get the value [0,0,0].

list_texts(text(?POID, ?AssociatedObject, ?Text))

list_texts/1 queries the PO database for a subset of the information contained in TextClass objects.

list_tasks(task(?POID, ?Model, ?TaskFrame, ?Primary))

task_specific_data(+POID, +Model, ?Data)

task_specific_data/3 queries the PO database for information contained in the task-specific portion of TaskClass objects. Since the contents of this area depend on the task model, this query can only be made when the POID and the model are already known. These can be determined by making list_tasks() queries.


where Parameter is a valid parameter name for this model, and DataType is an appropriate data type for the resulting value. Parameter names and data types can be found in appropriate rdr file for the model. An example is given below, where the SM_UMixedTravel task is queried for its route and speed parameters. The route parameter is of type point(), and the speed parameter is of type float():

task_specific_data([1,1,128],'SM_UMixedTravel', [route(point(Route)),speed(float(Speed))])

Creating Objects

create_entity(+Marking, +Type, ?Location, +Force, +Modifiers, -POID)

create_entity/6 creates a new UnitClass object in the PO database. If no Location is given, the user is placed in the point editor to allow a location for the new unit to be selected with the mouse.

create_hhour(+Name, +Force, +Defined, ?Time, -POID)

create_hhour/5 creates a new HHourClass object in the PO database.

create_line(?Name, +Points, +Modifiers, -POID)

create_line/4 creates a new LineClass object in the PO database. If Name is given and non-empty, then it will also create a new TextClass object, and associate this with the LineClass object.

create_minefield(-Name, +Points, +Density, +Modifiers, -POID)

create_minefield/5 creates a new MinefieldClass object in the PO database. create_minefield creates minefields of type minefieldTypeArea.

create_point(?Name, ?UTM, ?Modifiers, -POID)

create_point/3 creates a new PointClass object in the PO database. If UTM is not given, the user is placed in the point editor to allow them to select a location for the new point with the mouse.


delete/1 removes the persistent object from the PO database.


All commands that will eventually turn into taskframes in the ModSAF execution matrix are given a common structure. This generic structure has been designed to make supporting new taskframes and task parameters as easy to implement as possible. The atomic values used in this term can be found by inspecting the taskframes.rdr files, and the data types for the individual parameters can be found in the rdr file for the particular tasks.

action(+TaskFrameName, +UnitPOID, +Parameters, -POID)

action/4 creates a pair of new TaskFrameClass objects in the PO database(a preparatory taskframe and an actual taskframe) and assigns them to the unit.

ParameterName(DataType(Value), Model)

The possible values for the ParameterName, DataType, and Model can be found in the taskframes.rdr file, and in the rdr files for the individual tasks.

The default behavior for an action() command is to place the new preparatory and actual taskframes in the next empty spot in the execution matrix for the unit given by UnitPOID. Actions can be modified by putting a wrapper around the action() term.


When an action() command is inserted in a replace() wrapper, the indicated action replaces the currently executing action in the execution matrix for the unit.


When an action() command is inserted in a replace_temp() wrapper, the indicated action is pushed onto the execution matrix stack, and temporarily replaces the current action. The current action can be continued with the resume() command.

Control Methods


control_method/1 creates new enabling tasks in the PO database. The enabling tasks coordinate the transition from one taskframe to the next.

control_method(on_order(+UnitPOID, +TaskFramePOID))

When the method is on_order/2, a new on-order enabling task is created. The unit will then transition from the previous taskframe to this one when an explicit order is given in the GUI, or when a move_out() command is given.

control_method(action_time(+UnitPOID, +TaskFramePOID, +Time))

When the method is action_time/3, a new HHourClass object is created in the PO database, and is set at Time, and an enabling task is created to cause a transition to this taskframe at that time.

control_method(after_duration(+UnitPOID, +TaskFramePOID, +Duration))

after_duration/3 causes a transtion to the taskframe from the previous taskframe after the specified duration.

.control_method(control_measure(+UnitPOID, +TaskFramePOID, +Location, +ControllingUnit, +Criterion))

control_measure/5 causes a transition to the taskframe when ControllingUnit reaches the point or line specified by Location.

Modification Commands

These commands allow you to modify the parameters of existing persistent objects.

modify_action(+TaskFramePOID, +Model, +Parameters)

modify_action/3 lets you modify one or more parameters of an existing task.

ParameterName(+DataType(NewValue), -DataType(OldValue))

The possible values for the ParameterName, DataType, and Model can be found in the taskframes.rdr file, and in the rdr files for the individual tasks. The previous value is returned in OldValue to accomodate the undo facility.

modify_point(+PointPOID, +Modifiers)

modify_point/2 allows you to modify any of the parameters of a point that are allowed by create_point/4.

ParameterName(NewValue, OldValue)

The possible parameters are name, location, color, dashed, direction, and style. The legal values for those parameters are specified in the documentation for create_point/4.

Dialog Modes

CommandTalk uses a notion of dialog state to help determine how some commands should be interpreted. Currently, this is implemented as two distinct modes, setup mode and simulation mode. During setup mode, command will tend to be interpreted as future commands to be placed in the execution matrix to be carried out at a later time, while in simulation mode commands will tend to be interpreted to affect the action that the unit is performing right then.




Immediate Intervention Commands

Immediate intervention commands modify the currently executing taskframe by placing a transparent taskframe on the top of the stack. The original frame can be continued with the resume() command.


rt_slower/1 decreases the unit's speed by 25%.


rt_faster/1 increases the unit's speed by 25%.

rt_change_speed(+Unit, +Speed)

rt_change_speed/2 sets the unit's speed to the given speed.

rt_change_formation(+Unit, +Formation)

rt_change_formation/2 changes a unit's traveling formation.

Display Commands

We provide a variety of commands to control what is shown on the display. These can move around to display different portions of the tactical map, change the magnification scale, and show and remove specific terrain features.

center(+Location, -PreviousLocation)

center/1 redraws the plan view display, making Location the new center of the display.

center_relative_to(+Location, +Magnetic, -PreviousLocation)

center_relative_to/2 redraws the plan view display centered on a point that is in the direction given by Magnetic with respect to Location.


zoom_in/0 redraws the plan view display, decreasing the map scale by roughly a factor of two.


zoom_out/0 redraws the plan view display, increasing the map scale by roughly a factor of two.

zoom_in(+Location, -PreviousLocation)

zoom_in/1 performs a center(Location), followed by a zoom_in.

zoom_out(+Location, -PreviousLocation)

zoom_out/2 redraws the plan view display, increasing the map scale by roughly a factor of two.


scale_change/1 redraws the plan view display, setting the map scale to 1:Scale.

pan(+Magnetic, +Modifiers, -PreviousLocation)

pan/2 shifts the center of the plan view display in the direction given by Magnetic.


cancel_last_zoom/0 restores the screen magnification to its value prior to the most recent zoom_in, zoom_out, or scale_change.


center_of_screen/1 returns the UTM coordinates of the current center of the screen

resolve_coordinates(+Northing, +Easting, +ReferenceUTM, -UTM)

resolve_coordinates/2 finds the complete UTM coordinates that coorespond to Northing and Easting but that is closest to ReferenceUTM.


show/1 turns on display of a specific terrain feature.


hide/1 turns off display of a specific terrain feature.

Miscellaneous Commands

attach_unit(+Unit, +SuperiorUnit)

attach_unit/2 places Unit under the control of SuperiorUnit. Unit must be lower in the command hierarchy than SuperiorUnit.

move_out(+Unit, +Authorization)

move_out/2 executes a pending on-order control method.


report_status/1 opens the message display window in ModSAF, and prints the current status report for Unit in that window.


report_status(off) removes the message display window.


resume/1 applies when Unit is executing a taskframe that is temporarily replacing some underlying taskframe. The current taskframe is removed, and the unit resumes executing the underlying taskframe.


resume_to_original/1 is like resume/1, except that all temporarily replacing taskframes are removed, down to the original taskframe.


stop_reaction/1 is similar to resume/1, except that it removes taskframes that were introduced by a reaction.


next_phase/1 causes Unit to abandon its current taskframe, and proceed onto the next taskframe in the mission.

roe(+Unit, permission(+Permission))

roe/2 changes the rules of engagement for Unit. Currently only changes to fire permissions are allowed. Eventually, changes to fire type, fire coordination, and target priorities will also be supported.

Miscellaneous Functions

These functions do not effect the ModSAF simulation or display, but provide useful information back to the caller .

distance_between(+Location1, +Location2, -Distance)

distance/3 computes the distance between Location1 and Location2. This is typically used by the contextual interpretation agent when it needs to determine which of two (or more) possible referents for a noun phrase is closest, i.e. "attack the enemy position".

nearest_point_on_line(+Location, +Line, -UTM)

nearest_point_on_line/3 finds the UTM coordinates for the point on Line that is nearest to Location. This is typically used to interpret utterances like "move to line of departure" as a command to move to the point on the line of departure that is nearest to you.

compute_point(+Reference, +Magnetic, +Distance, -UTM)

compute_point/4 finds the UTM coordinates of a point that is Distance meters away from the Reference location in the direction given by Magnetic.

compute_line(+UnitPOID, +Intersects, +Facing, -LinePOID)

compute_line/4 creates a new LineClass object in the PO database. This new line passes through the point given by Intersects, and is oriented towards the point given by Facing. The length of the line is currently a constant 250 meters, but this should be added as a new parameter. The overlay for the new line is taken from the overlay for UnitPOID.

poid_to_vehicle_id(+UnitPOID, -VehicleID)

poid_to_vehicle_id/2 returns the vehicle identifier for a unit that is a vehicle. It failes is UnitPOID is a command entity.


new_scenario/0 removes all objects from the simulation.


load_scenario/1 restores the simulation to the point represented in the saved scenario file.


save_scenario/1 saves the current state of the simulation in the scenario file.

ModSAF Event Notifications

MALL now broadcasts significant changes to the PO database. Agents that want to receive these notifications need to do two things:


When this is done, you will receive new messages from ModSAF in one of the following formats.

new_persistent_object(+ObjectClass, +ObjectInformation)

a new_persistent_object/2 messages is broadcast whenever a new object of an appropriate class is created in the PO database.

changed_persistent_object(+ObjectClass, +ObjectInformation)

a changed_persistent_object/2 messages is generated whenever a persistent object of an appropriate type is modified.

deleted_persistent_object(+ObjectClass, +POID)

a deleted_persistent_object/2 messages is generated whenever a persistent object of an appropriate type is deleted.


This document presents an overview of the ModSAF agent layer language. The language described here is subject to change, in particular, we expect the language to grow along these dimensions in the near future: