Galaxy Communicator Documentation:

Communicator Hub Programs

License / Documentation home / Help and feedback


The Galaxy Communicator uses a configurable Hub. This configurability is accomplished by having the Hub read in a script upon start-up. This script is written in a simple, Hub-specific scripting language. The Hub program, or script, contains information about available servers (name and location) and their externally accessible operations, as well as possible flow of control instructions.

The program file must be specified via the command line option: -pgm_file filename.  If no file is specified, the Hub will exit.

Each directive of the program file must contain no more than one expression, and begin with a valid, system defined identifier name. Blank lines are permitted, and are also used to terminate small declaration blocks (see the rest of the documentation for details). A comment is introduced when the first non-whitespace character of a line is either a semicolon (;). Line breaks in directives are permitted using the \ (backslash) character. Directives are terminated by an unescaped newline.

Identifiers are case sensitive.  However, by convention, identifiers are all upper-case with a trailing colon, :.  Identifiers can be used to specify:

There is no macro expansion or evaluation.  There is also no nesting of rules or scoping, although modules are supported via the PROGRAM: identifier.

Note:  any newlines in the examples below are a side effect of presentation; newlines are permitted in entries in program files only if they are escaped with the backslash character.


The Hub Program File Structure

A Hub program file contains the following constructs: These constructs are used to form the following logical blocks: Although global declarations can be defined anywhere, servers must be defined before programs. Typically a script will specify global variables first, then servers.  The file may also contain one or more program definitions. The frame names of incoming messages which are not replies to messages sent by the Hub names are treated as program names if the named program exists; otherwise, the incoming message is treated as an invocation of a server operation. If no matching program or server operation is found, the message is discarded. See the discussion of how a system works for more details, as well as the documentation on using the Hub in scriptless mode.

The distribution contains a number of program files (default extension .pgm) as examples. See contrib/MITRE/example and contrib/MITRE/demos.


Values

As of version 1.3, the program file reader uses the same underlying reader that's used to digest string representations of frames. As a result, there is a well-defined system of value parsing throughout the program files.

Subfiles

A program file can be decomposed into subfiles.  To include a subfile into the main program file use:
#include <filename>
The filename should be a string, so double quotes are optional (since it's a single token). If <filename> includes no directory information, the current file directory is used as the default.  Nested includes are permissible.  The contents of included files are incorporated as read in, so #includes can be places anywhere within the program file. If the filename is a relative pathname, it will be interpreted relative to the directory where the program file which contains the reference is located.

Note:  as of version 1.3, logging instructions are no longer ignored in subfiles.


Expression syntax

In addition to the syntax of values, program files can contain a number of different constructs. Here's a fragment of a program file which exemplifies the different constructs, which we will use to elaborate.
SERVICE_TYPE: parser
OPERATIONS: parse_string
INIT: :speed "medium" (:accuracy "high")

SERVICE_PROVIDER: parser
LOCATION: localhost:14000
IN: (:language "English")

PROGRAM: main

RULE: :input_string && :language == "English" --> parser.parse_string
IN: (:string :input_string) :user

Directives

All directive entries in the program file consist of a single logical line. These logical lines can contain newlines if they are escaped with a backslash (\), which must be the last character in the physical line. The first token in each directive entry is the directive, which always ends with a colon (:). Examples in the program file fragment here are SERVICE_TYPE:, INIT:, OPERATIONS:, etc. For readability, we recommend leaving at least one space in between the directive and its value; however, it is not necessary to do so.

Simple values

Directives like PROGRAM: and  SERVICE_TYPE: accept a quoted or unquoted string as a value. This value is interpreted as a string regardless. If a single value is expected, the directive value must be quoted. If multiple values are expected, a sequence of tokens, quoted or unquoted, will be interpreted as the appropriate sequence of string.

Key-value pairs and namespaces

The Hub maintains a number of memory states, which we call namespaces.
 
State description Namespace name
Each token is associated with a state, which is initially populated by a new incoming message and updated by the Hub program token
Each session is associated with a state, which can be updated by servers or by Hub program instructions session
Each server (actually, service provider) the Hub knows about is associated with a state, which can be updated by the server or, in extended syntax mode, by Hub program instructions server
Each message, incoming and outgoing, counts as a state message
Global settings are stored as their own state global

All key-value pairs in the Hub program language have a target namespace, and in some cases a source namespace as well. There are two types of key-value pair formats in program files.

Optional value format

In optional value format, exemplified by the IN: lines in the example program file, there are three format options:
 
Example Interpretation
:user A single key in optional value format is an instruction to draw the value from the source namespace and store it under the identical key in the target namespace. In the case of IN:, the source namespace is the token, and the target namespace is the message.
(:string :input_string) A parenthesized pair where the second element is an unquoted string is an instruction to draw the value from the source namespace under the key named by the second element (:input_string, here) and store it in the target namespace under the key named by the first element (:string, here). In the case of IN:, the source namespace is the token, and the target namespace is the message.
(:language "English") A parenthesized pair where the second element is a literal value is an instruction to store that value ("English", here) in the target namespace under the key named by the first element (:language, here). In the case of IN:, the target namespace is the message.

Obligatory value format

In obligatory value format, exemplified by the INIT: line in the example program file, only literal values are permitted. There are two format options.
 
Example Interpretation
:speed "medium" An unparenthesized pair where the second element is a literal value is an instruction to store that value ("medium", here) in the target namespace under the key named by the first element (:speed, here). In the case of INIT:, the target namespace is the reinitialize message.
(:accuracy "high") A parenthesized pair where the second element is a literal value is an instruction to store that value ("high", here) in the target namespace under the key named by the first element (:accuracy, here). In the case of INIT:, the target namespace is the reinitialize message.

Rule conditions

The RULE: directive, as exemplified in the program file, accepts a complex rule condition expression.

Constructing a rule condition

The grammar for condition expressions is as follows:
<conditions> = <condition> (<connective> <condition>)*
<connective> = & | && | | | || (that is, (2) ampersand(s) or (2) vertical bar(s))
<condition> = (!) <key> | <key> <restriction>
<condition> = ( <conditions> ) (that is, conditions surrounded by parentheses)
<restriction> = (!) <int_comparison> <int>
<int_comparison> = > | < | >= | <= | =(=)
<restriction> = (!) <string> | (!) <string_comparison> <string>
<string_comparison> = % | ^ | =(=)
Whitespace is required between the key and the restriction, but whitespace is optional between the comparison and the value. As noted, parentheses can be used to group the elements explicitly, and these new conditions can be negated, etc.

Note: The % comparison operator still works, but will be deprecated in favor of the ^ comparison in the future.

Examples of valid conditions

condition interpretation
:foo the key is present in the target namespace
!:foo
! :foo
the key is not present in the target namespace
:foo = 5
:foo =5
:foo == 5
:foo 3
etc.
the key value in the target namespace is the specified integer (note that the right hand side can be a key referring to an integer in extended syntax mode)
:foo > 5
:foo < 5
:foo >5
:foo <5
the key value in the target namespace is an integer which is greater (less) than the specified integer (note that the right hand side can be a key referring to an integer in extended syntax mode)
:foo IN ( "a" "b" ) the key value in the target namespace is a member of the specified list, using Gal_ObjectEqual for comparison (note that the right hand side can be a key referring to a list in extended syntax mode)
:foo % bar
:foo ^ bar
:foo % "bar"
:foo ^ "bar"
:foo %"bar"
:foo ^bar
etc.
the key value in the target namespace is a string with the specified substring (note that unquoted literal values are interpreted as keys in extended syntax mode)
:foo ! % bar
:foo !^ bar
:foo !% "bar"
:foo ! ^ "bar"
etc.
the key value in the target namespace is a string which does not contain the specified substring (note that unquoted literal values are interpreted as keys in extended syntax mode)
:foo bar
foo = bar
:foo ="bar"
:foo == bar
etc.
the key value in the target namespace is the specified string (note that quoteless integer values are interpreted as integers, not strings, and that unquoted literal values are interpreted as keys in extended syntax mode)
:foo ! bar
:foo !"bar"
foo != bar
:foo !="bar"
etc.
the key value in the target namespace is not the specifed string (note that quoteless integer values are interpreted as integers, not strings, and that unquoted literal values are interpreted as keys in extended syntax mode)
<condition> & <condition>
<condition> && <condition>
(<condition> & <condition>)
etc.
conjunction of conditions
<condition> | <condition>
<condition> || <condition>
(<condition> | <condition>)
etc.
disjunction of the immediately adjacent conditions

Special cases

Note: these special cases are not supported in extended syntax mode.

Extended syntax mode

As of version 3.0, there is a variant syntax for Hub programs, which we call extended syntax mode, which makes available a wider range of expressions to the Hub program writer and eliminates a number of special cases in the default (or normal) syntax mode. You can switch to this mode using the global directive PGM_SYNTAX:.

Entity reference functions

One of the most important enhancements available in extended syntax mode is a growing set of entity reference functions. These are functions which can appear in most positions a value can appear, e.g., the directives IN:, OUT:, DEL:, PARAM:, SET:, ERROR:, LOG_IN:, LOG_OUT:, CONDITIONS:, and in rule conditions. These functions return values, instead of being or referring to values directly. These functions have the following form:
$<fn>(<arg> ... )
As of version 4.0, there are three such entity reference functions: $id, $bind and $in. We describe the $in function here; we describe the others later.

The $in entity reference function

These $in entity reference function allows us to refer explicitly to namespaces. It has the following form:
$in(<key> <namespace>)
 Here's a variation on our example program file:
PGM_SYNTAX: extended

SERVICE_TYPE: parser
OPERATIONS: parse_string
INIT: :speed "medium" (:accuracy "high")

SERVICE_PROVIDER: parser
LOCATION: localhost:14000
PROPERTIES: (:language "English")

PROGRAM: main

RULE: :input_string && :language == "English" --> parser.parse_string
IN: (:string :input_string) :user $in(:language server)

In this example, we associate a property with the service provider, and import it into the message on the IN: line. These namespace references can occur anywhere that keys can occur (in the directives in which they're available). When present, the specified namespace overrides the default source or target namespace. As a special case, when these namespace references occur in optional value mode in the same position as bare keys, the specified namespace overrides the default source namespace and retains the default target. In this example here, it overrides the default source namespace for IN:.

Consider another example:

RULE: :input_string && :language == "English" --> parser.parse_string
IN: ($in(:lang session) $in(:language server))
This IN: line doesn't add anything to the message; rather, it takes the value of the :language key in the server namespace and stores it as the value of the :lang key in the session namespace, before the message is sent.

These namespace references are available in rule conditions as well:

PGM_SYNTAX: extended

SERVICE_TYPE: parser
OPERATIONS: parse_string
INIT: :speed "medium" (:accuracy "high")
CONDITIONS: :language == $in(:language session)

The CONDITIONS: line here imposes a restriction on the selection of any service provider for the given service type; namely, that the value of the :language key in the default namespace (which is the server namespace for CONDITIONS:) is equal to the value of the :language key in the session namespace. In other words, choose the parser that understands the language the session is being conducted in.

As a side effect of implementing this construct, it is now possible in rule conditions to compare the values of any two keys, which means that unquoted tokens on the right hand side of comparisons are not coerced into strings. Here's an example:

RULE: :a == :b --> foo
In default syntax mode, this rule will be fired if the value of the key :a in the token is the string ":b"; that is, the test is equivalent to :a == ":b". In extended syntax mode, this rule will be fired if the value of the key :a is the same as the value of the key :b.

Summary of differences from default syntax mode

Some of these differences will not make sense until you've read the complete scripting documentation. They are listed here for completeness. Some of the differences refer to previously undocumented exceptional behavior in the default syntax mode, and in many cases are previous attempts to support references to namespaces other than the default namespace. Note that because of the nature of Hub program execution, not all namespaces are available in all directives where the construct is recognized. For each directive where extended syntax makes a difference, the restrictions are noted.


Entity reference function reference

Entity reference functions are available in extended syntax mode. These functions differ from functions in the Builtin server in that they are essentially normal function calls, while the Builtin server incurs the overhead of the dispatch function mechanism. Unlike normal dispatch functions and like normal function calls, these functions can only return a single argument.

We've discussed the $in function already. Here, we describe the other entity reference functions which have been defined so far.

$id(<string>)

The single string argument is the name of a namespace. This function returns the unique ID associated with that namespace. The namespaces which are currently recognized are server and session. For an example of its use, see the section on selecting a provider.

$bind(<arg1>, <arg2>, ... <argn>)

This function is essentially equivalent to Gal_VAReadVarObjectFromString(<arg1>, (n - 1)/2, <arg2>, ..., <argn>). Each argument can be either a value or an entity reference (that is, it can be anything that can be bound). The first argument must evaluate to a string, and each of the alternating remaining arguments must also evaluate to a string (since they're the substitution keys). All memory management is handled internally.

The intended use of this function is for situations where you want to create a frame or other complex object to send to a provider, but some of the values depend on existing keys. Here's an example:
RULE: --> GetAnswer
OUT: :answer

RULE: --> DisplayFrame
IN: (:frame $bind("{c reply :reply $answer }" "$answer" :answer))

Global Declarations

There are a number of global identifiers, which have different effects on the function of the Hub. These identifiers can be used to configure the initial token which is executed by the Hub, or to set global values for logging, or to set other global defaults.
 
global variable identifier description type visible in global namespace?
DOMAIN: Domain name, used by MIT to partition the space of queries into different topic areas, and passed to all servers via the reinitialize message. Default value is Unspecified. string yes
INITIAL_REPLY: Used by the Hub to "seed" the initial token with a string to be presented to the user as a welcome message. It is called a "reply" because in the MIT scripts, the same rules which handle replies are intended to handle this string. This is very idiosyncratic, and should not be used. string yes
INITIAL_TOKEN: A frame which can override some of the default values of the initial token, especially the name of the program invoked. See the section on the initial token. frame no
MODE: There are three legal values for MODE:.

The first, singlethread, allows the user to specify that only the first rule which matches should fire. See the lesson on how the Hub processes incoming messages. As of version 2.1, this entry is superfluous, because it is set by default and cannot be disabled.

The second, pedantic, forces the Hub to exit if it encounters a missing server or operation (default behavior is to warn and continue). But see the IGNORE: directive.

The third, global_read_only, locks the global namespace for writing.

string no
USER_ID: Distinguished string which identifies the "user". This is something of a misnomer, since the Hub can be used by many different people at the same time. It is passed both during reinitialize and in the initial token. It can be used to identify the connecting site to the server. string yes
PGM_SYNTAX: The single legal value extended specifies that all subsequent material in the program file should be interpreted using the rules for extended syntax (new in 3.0)  string no

Here's an example global declaration block:

PGM_SYNTAX: extended

USER_ID: MITRE
INITIAL_TOKEN: {c initialize }
MODE: pedantic

Extended syntax note

The global namespace keys are the directive names themselves. Here's the global namespace which results from the sample global declaration block:
{c global
   DOMAIN: "Unspecified"
   USER_ID: "MITRE"}
Here's a sample rule:
RULE: $in(DOMAIN: global) --> do_it
IN: (:domain $in(DOMAIN: global)) ($in(LOCATION: global) "US") $in(COUNTRY: global)
This rule will fire if the global namespace contains an entry for the DOMAIN: key. It will pass in that value as the :domain key to the do_it operation. It will attempt to set the global LOCATION: to "US", which will have no effect because the global namespace is not writable, and it will attempt to pass in the value of the COUNTRY: key in the global namespace, which will have no effect because the global namespace does not have an entry for that key.

In version 3.0, the global namespace could not be written to, so specifying it as a target namespace had no effect. In 3.1, the global namespace is writable, and it can be write-locked using the global_read_only value of MODE:.


Initial Token

The initial token is constructed as follows:
  1. The frame is first seeded with global default information, as follows:
  2. frame key source type default value
    <frame name> (specified in code)   main
    :domain value of DOMAIN: program file identifier string Unspecified
    :initialize   integer 1
    :reply_string value of INITIAL_REPLY: program file identifier, if present string <none>
    :user_id value of USER_ID: program file identifier, if present string sls
  3. The frame is augmented (or overwritten) from the specification of the INITIAL_TOKEN: entry, if it exists. At this point, the initial token is cached to feed the construction of the reinitialize message.
  4. The frame is augmented (or overwritten) with the contents of the -init command line argument to the Hub executable, if present.
On startup, the Hub processes this token as soon as it's finished its initial round of contacting servers (some of which might be unsuccessful). See the discussion on how the Hub works.


Logging Parameters

Logging parameters can also be defined globally.  These instruct what to log and when.  Logfile instructions are useful for spot checking the system, and the resulting logs display attributes important for debugging. For details, see the logging documentation.

Timestamps are recorded whenever the listed operations are called.  Keys are logged when the input message is sent, or a return is received. This behavior supersedes previous behavior, where keys were logged only when increment_utterance was called.
 
logging identifier description type example visible in global namespace?
LOG_IN: Keys to be recorded when a rule is fired or a message is sent to the Hub (see the rule entry) See the logging documentation. (not global)
LOG_OUT: Keys to be recorded when a rule return is received or a reply is sent from the Hub (see the rule entry) See the logging documentation. (not global)
LOG_DIR: Logfile directory string LOG_DIR:  /usr/logs yes
LOG_HUB_ACTIVITY: Control of logging of Hub events like alarm expiration, servers not found, etc. sequence of strings LOG_HUB_ACTIVITY: system_errors

See the logging documentation.

no
LOG_VERSION: User version string to differentiate logging strategies string LOG_VERSION: "travel demo, version 2.3"

See the logging documentation.

yes
TIMESTAMP: Operations or messages to log with timestamps (dot notation is legal) sequence of strings TIMESTAMP:  create_frame nl.paraphrase_request jupiter.turn_management paraphrase_reply  no
MESSAGE: A message declaration to host message LOG_IN: and LOG_OUT: keys string See the logging documentation. (not global)

(Note that any newlines in this table are a side effect of presentation; newlines are permitted in entries in program files only if they are escaped with the backslash character.)

Special logging session keys

If logging is enabled, each session namespace contains four special keys:
 
key value
:hub_logdir the value of the LOG_DIR: directive
:hub_log_prefix the prefix for the logfile name
:hub_pwd the directory the Hub is running in
:hub_logfile the name of the logfile for the session

So on Unix, the logfile name is <:hub_pwd>/<:hub_logdir>/<:hub_log_prefix>-hublog.txt, or, alternatively, <:hub_logfile>. In extended syntax mode, you can pass these keys to the server as follows:

IN: $in(:hub_logdir session) $in(:hub_log_prefix session) $in(:hub_pwd session) $in(:hub_logfile session)
In default syntax mode, these keys are exceptionally available in the IN: line.


Server Declarations

The Hub keeps track of a set of service types, each of which is associated with a set of available operations, and a set of service providers which implement these operations. These service providers correspond to Communicator-compliant servers.

Service types

The service type block contains the following directives:
 
system identifier description type extended syntax notes
SERVICE_TYPE: unique name of the service being provided. string  
OPERATIONS: list of operations supported by all providers of this service sequence of strings  
INIT: initializes server-specific keys to specified values in the reinitialize() message. obligatory value format  
CLIENT_PORT: a port for the Hub to set up a listener on (alternates with PORT:) integer  
PORT: synonym of CLIENT_PORT: integer  
PROPERTIES: initializes a set of properties which the Hub associates with each service provider for this service type (can be overridden by a PROPERTIES: declaration on the service provider, or by the server itself). obligatory value format  
CONDITIONS: specifies a set of conditions associated with when to select a given service provider; relatively useless unless extended syntax is enabled rule condition Default namespace is server. All namespaces available.
IN: specifies a set of directives to be appended to the IN: line for any rule fired for any service provider for this service type (see the main entry for IN:) optional value format Default source namespace is server, default target namespace is token. All namespaces available.

Here's an example service type block:

SERVICE_TYPE: parser
OPERATIONS: create_frame context_tracking_in
INIT: :default_language "Spanish"
CLIENT_PORT: 11000
PROPERTIES: :dialect "standard"
CONDITIONS: :language == $in(:language session)
IN: :dialect
Note: this block may not contain any blank lines.

Service providers

The program file can also specify a list of service providers for the Hub to contact at startup time (service providers can also contact the Hub using the listener-in-Hub facilities, but these are not listed in the Hub program). The Hub will attempt to maintain a connection with these servers; if it cannot find them, or they disconnect after startup, the Hub will periodically attempt to reconnect.
 
system identifier description type extended syntax notes
SERVICE_PROVIDER: a sequence of tokens corresponding to declared service types. The service provider must implement the union of operations specified for those service types. sequence of strings  
HOST: service provider host name or IP address (see also LOCATION:). Note that the program file parser will not interpret IP addresses as strings unless they're explicitly delimited. string  
INIT: initializes server-specific keys to specified values in the reinitialize()message. Individual key-value pairs override any INIT: declarations on the parent service types obligatory value format  
LOCATION: server host name/IP address and port, separated by a colon; used as an alternative to HOST: and PORT:. Note that the program file parser will not interpret IP addresses as strings unless they're explicitly delimited. string  
PORT: server port (see also LOCATION:) integer  
PROPERTIES: initializes a set of properties which the Hub associates this service provider (individual key-value pairs override any PROPERTIES: declarations on the parent service type, and can also be updated by the server itself) obligatory value format  
CONDITIONS: specifies a set of conditions associated with when to select this service provider; relatively useless unless extended syntax is enabled. If specified on a service provider, all CONDITIONS: on service type parents are ignored. rule condition Default namespace is server. All namespaces available.
IN: specifies a set of directives to be appended to the IN: line for any rule fired for any service provider for this service type (see the main entry for IN:). Individual key-value pairs override any IN: declarations on the parent service types. optional value format Default source namespace is server, default target namespace is token. All namespaces available.
PROVIDER_ID: specifies a string to use as the non-numeric ID portion of an explicit provider name. The value must be a well-formed non-numeric provider ID; i.e., it must be delimited by square brackets. string  

Here's a sample service provider block. Note that the content of INIT:, PROPERTIES:, CONDITIONS: and IN: override the service type values, if present. Also note that the CONDITIONS: line requires extended syntax to be enabled.

SERVICE_PROVIDER: parser
LOCATION: localhost:11000
INIT: :default_language "Spanish"
PROPERTIES: :dialect "standard"
CONDITIONS: :language == $in(:language session)
IN: :dialect
PROVIDER_ID: [myparser]
Note: this block may not contain any blank lines.

Other server directives

There are three other directives which are provided.
 
system identifier description type
SERVER: Introduces a block which defines a service type and its providers simultaneously. All service type and service provider directives are accepted; multiple LOCATION: directives are interpreted as multiple service providers. INIT:, CONDITIONS:, IN:, and PROPERTIES: are associated with the service type rather than any of the providers. If the value includes a non-numeric provider ID prefix, that prefix will be assigned to the first of the providers defined. If the PROVIDER_ID: directive is present in the block, it too applies to the first of the providers defined, and overrides any provider ID prefix on the value of the SERVER: directive. string
SERVERS: Provides a list of service types and providers which are active in this session. If present, the subset of SERVICE_TYPE: and SERVICE_PROVIDER: declarations present in this directive will be used. This can be used to share a single file of type and provider declarations among multiple systems and program files, not all of which are used in any given system configuration. This declaration must precede all type and provider declarations. Legal values are provider names, extended provider names, service type names with a similar optional location suffix, or any legal value for the LOCATION: directive. sequence of strings
IGNORE: Provides a list of rule operations which the Hub can disregard when reading in a program file. Normally, if the Hub encounters a rule with an operation which is not defined, it will issue a warning (or exit in pedantic mode). However, if the operation is in the IGNORE: list, the Hub will not complain. This feature is useful when including program files in many other program files, where the programmer is certain that some of the programs or rules in the included file will never be encountered. The elements in this list are matched precisely against candidate rule RHSs, so they may contain operation name prefixes. sequence of strings

Examples:

SERVERS: parser localhost:17500

SERVER: parser
LOCATION: localhost:17600
OPERATIONS: parse_string
INIT: :default_language "Spanish"

IGNORE: parser.create_frame context_in

Note: the SERVER: block may not contain any blank lines.

The Builtin server

The Hub provides a special server called Builtin which is always available (that is, it does not need to be declared). This server provides support for null operations, session management, etc.


Hub Programs

A Hub program is basically a set of rules that describes a sequence of operations. Hub programs provide an optional level of scripting which developers may exploit to exert additional control over the flow of control of messages. Typically, there is a main program (conventionally named "main") which controls the toplevel flow of control; other uses of subprograms might be to control server-initiated communication for executing subtasks. For example, a program called db_query might control the following sequence of operations: turn_management --> database --> turn_management.

All programs (main and subprograms) consist of:

There is an order associated with when operations and identifiers are evaluated.

A program begins when it is named and ends when the next program is named. All rules and associated keys in between are part of the program.

The following table lists the valid identifiers used in defining programs. Identifiers which are specific to rules are listed later.
 
program identifier description extended syntax notes
ALARM: enabling/disabling time outs. See the section on alarms.  
PROGRAM: name of Hub program (main or subprogram)  
RULE: the specified conditions under which the rule will be executed Default namespace is token. All namespaces except server available (provider hans't been selected yet).


Program Name

A Hub program name is indicated by the PROGRAM:identifier followed by the program name:
PROGRAM: main
The program may have any name.

As of Galaxy Communicator 2.0, the program may also have LOG_IN: and LOG_OUT: designations, which cause keys and values to be written to the Hub log when the program is initially invoked and when it returns a server-to-server subdialogue reply to the server which invoked the program via GalSS_EnvDispatchFrame.


Rules

A Hub program consists of a sequence of rules.  A rule specifies an operation to be executed by a server if and when appropriate conditions are met.  The scripting language supports a subset of boolean operators for composing conditions in a logical expression.  A rule is similar to an if-then statement.

Here is an example of a simple rule:

Rules are fired in the order in which they appear in the program file. Typically, the first rule which matches is the one which is fired, except in the case of certain special control directives. Note that the order in which tokens are returned from multiple rules is not defined.

Constructing a Rule

The RULE: identifier is used to indicate a rule.  It uses the rule condition expressions:

Examples of Valid Rules

Selecting a provider

The rules for selecting a provider to execute the operation on the RHS of the rule are the same as those which govern the selection of providers in scriptless mode. Additionally, the Hub can affect provider selection in a number of ways.

First, the PROVIDER_ID: directive can be used, as we saw, to specify a non-numeric provider ID for a provider. In this case, the argument of the PROVIDER_ID: directive is a string.

Second, the PROVIDER_NAME: directive can be used to specify a provider name or service type name for a rule. In this case, the argument is any entity which evaluates to a string. Here are a few examples:

RULE: --> Parse
PROVIDER_NAME: $in(:preferred_parser session)

RULE: --> Parse
PROVIDER_NAME: "Parser"

RULE: --> Parse
PROVIDER_NAME: "[myparser]"

This rule will select the provider according to the normal rules, but treat the value of the entity reference as a provider name restriction. If there is a conflict between the operation name prefix in the rule RHS and the value of PROVIDER_NAME: (e.g., if they both specify a provider ID), then the value of PROVIDER_NAME: takes precedence.

Finally, the $id entity reference function can be used to retrieve a canonical provider ID to pass to a server for use in bypassing Hub program matching. Here's an example:

RULE: --> Parse
IN: ($in(:parser_used token) $id("server"))
OUT:

RULE: --> DoDialogue
IN: (:parser_used $in(:parser_used token))
...

In this example, we want the dialogue server to know which of a number of available parsers was actually used, in case the dialogue server needs to retrieve any information from it. So we store the provider ID of the server used in the Parse operation in the token namespace, and pass it later to the dialogue server.


Parameters

Order of Operation

There is an order associated with when operations and identifiers are evaluated. All these identifiers are evaluated after the condition matching is checked. The overall order is:
 
key value processing value format comments
(conditions match) Default namespace is token. All namespaces but server available (service provider not chosen yet).    Extended syntax available.
RETRIEVE: From Hub DB to message frame list of tokens (but see note on database parameters) Extended syntax not available.
PARAM: Target namespace is message. obligatory value Extended syntax available.
IN: Default source namespace is token, default target namespace is message. See also the server directives. optional value Extended syntax available.
LOG_IN: Default source namespace is message. Writes to log. optional value Extended syntax available for source namespace.
CONTINUE_REPLY: (n/a) frame For discussion, see the section on Hub continuations. Can be repeated.
CONTINUE_ERROR: (n/a) frame For discussion, see the section on Hub continuations. Can be repeated.
PROVIDER_NAME: Default namespace is token. value which evaluates to a string Imposes restrictions on provider selection. Note that string literals for this entry must have double quotes around them, because this entry can also be a namespace reference (i.e., ":foo" is literal non-numeric provider ID, and and :foo is a reference to the value of that key in the default namespace).
(dispatch function called)      
LOG_OUT: Default source namespace is message (message return). Writes to log. optional value Extended syntax available for source namespace.
STORE: From message return to Hub DB list of tokens Note that STORE: does not work with none!, since there's no message return, but it does work with destroy!. Extended syntax not available.
DEL: From token list of tokens Note that DEL: works with both none! and destroy!. Extended syntax available.
OUT: Default source namespace is message (message return), default target namespace is token. optional value Extended syntax available.
ERROR: Default source namespace is message (message return), default target namespace is token. optional value Evaluated if the dispatch function call returns an error reply, in which case OUT: is not evaluated. Extended syntax available. See the discussion of output parameters.
SET: From rule to token obligatory value Note that SET: works with both none! and destroy!. Extended syntax available.
CONTROL: (n/a) zero or more of the symbols :return, :asynchronous, and :no_result For discussion, see the special control directives

The INIT: directive in the server specification also uses the obligatory value value format.

Note: the RULE: block may not contain any blank lines.

Input Parameters

When a given operation is executed, input parameters are passed in the token to the server.  The IN: identifier is used to specify the list of input parameters.  Any keys not included in the parameter lists are probably ignored by the server. IN: uses the optional value value format; the key-mapping subcase of this format will map keys set by RETRIEVE: and PARAM:

For example,

Note that explicit namespace references provided in extended syntax mode are available for IN:.

Output Parameters

Expected output parameters are identified with OUT: or ERROR:. Output parameters are used to update the token state. Output parameters use the optional value value format.

For example,

The server is marked as busy when there are expected output parameters, and the Hub will send no further messages to this server until it receives a reply.

If the reply from the dispatch function is an error, the default behavior is for the Hub to terminate execution of the current token (and return the token state to the originating server, in the case of a server-to-server subdialogue). In this case, all the appropriate updates, including OUT:, are performed before the token execution is terminated. If the ERROR: directive is present and the reply is an error, then the ERROR: directive is evaluated instead of the OUT: directive and token execution continues (that is, it's as if the reply was a normal reply instead of an error). However, if a reply is not expected, then ERROR: has no effect.

Note that explicit namespace references provided in extended syntax mode are available for output parameters.

Special control directives

The CONTROL: directive allows the user to specify how the program is to proceed after the rule is fired. Three special values of the OUT: directive, none!, abort! and destroy!,  are shorthands for sets of CONTROL: values.

Hub continuations

By specifying values for CONTINUE_REPLY: and CONTINUE_ERROR: in a rule, the programmer can force the Hub to treat new messages from the selected server as reply or error messages. These directives should be used when the programmer wants the Hub to use a synchronous programming model, but the server in question doesn't provide replies. The server is notified that a real reply isn't expected (in fact, the real reply will be discarded if the server provides it), and the Hub won't process the message return until a new message of one of the specified forms is received from the server. The matching is done using Gal_MatchFrame. The new message is treated as a normal reply or error, including for the purposes of timestamps and logging, and all the return parameters (OUT:, STORE:, etc.) are processed normally. See also the Builtin.hub_continue function and the discussion of continuations.

Merge Parameters

Note that explicit namespace references provided in extended syntax mode are available for merge parameters.

Set

The SET: identifier allows token keys to be set to specific values upon return from the server.  SET: uses the obligatory value value format.

For example,

SET: :enable_input_ok 1 :reply_string "Thanks_for_using_Jupiter" :speaker "paul"
sets :enable_input_ok to int 1 and :reply_string to the string "Thanks_for_using_Jupiter" and :speaker to the string "paul".
Note that as a special case, none! works with SET:, even though there's no message return.

Param

The PARAM: identifier allows token keys to be set to specific values before being sent to the server.  PARAM: uses the obligatory value value format.

For example,

PARAM: :reply_string "The phone has disconnected. Terminating session."
sets :reply_string to "The phone has disconnected.  Terminating session"

Del

The DEL:  identifier indicates which keys to delete from the token state upon return from the operation.

Note that as a special case, none! works with DEL:, even though there's no message return.

Database Parameters

For example,
RETRIEVE: :history_frame
IN: :selected_thin_frame
OUT: :request_frame :history_frame :domain
STORE: :history_frame


The RETRIEVE: operation is performed before the argument list is composed for server dispatch, and the STORE: operation is performed after the rule returns, but before the token is updated with the server response.   See the overall order. New in version 1.2: STORE: will search "unmapped" versions of key-mapped OUT: entries if it can't find the value in the mapped values.

RETRIEVE: and STORE: are related to the underlying utterance ID of the Hub (see the increment_utterance message in the builtin server). STORE: stores an element in the slice of the Hub DB associated with the current utterance ID. RETRIEVE:, by default, retrieves an element from the slice of the Hub DB associated with the previous utterance ID. The RETRIEVE: entry allows a optional value version in which the second element is the relative index into the Hub DB. For example, (:a 0)will retrieve the value of :a from the DB associated with the current utterance ID, while (:a -2) will retrieve the value of :a from the DB associated with the current utterance ID - 2. Default is -1.

Note that STORE: works with destroy! but not with none!, since there's no message return in the latter case. However, both work with DEL: and SET:, since although there's no message return, neither DEL: nor SET: depend on the return message.

Other rule parameters

rule identifier description example / syntax
ALARM: enabling/disabling time outs. Used both globally and in rules. See the section on alarms. ALARM: alarm_name enable | disable | <num_secs>
ALARM: global_alarm 20
ALARM: global_alarm disable
ALARM: global_alarm enable global_alarm 20 turn_alarm enable turn_alarm 60
LOCK: one of two possible keys (:hub_get_session_lock, :hub_serve_this_session_only) which control session locking (not documented yet)


Session keys

The session maintains its own session state. By default, the session is populated with log information. It also initializes the :utterance_id key, which is incremented by the builtin server dispatch function increment_utterance.  However, it's convenient to store additional information on the session, which is specific to the current interaction but persists across messages. It's possible to control these values from the server itself, and in extended syntax mode, it's easy to set and retrieve such values using namespace references. In default syntax mode, it's a little trickier.

In default syntax mode, in SET:, IN: and OUT:, keys which start with :hub_session_ are stored in or retrieved from the session rather than the token. The hub_session_ portion of the key is stripped off. Here's an example of this capability in action, first a program file fragment and then the resulting status:

LOG_DIR: .

USER_ID: MITRE

PROGRAM: main

[...]

RULE: --> Builtin.nop
SET: :hub_session_current_status "adequate"

-------------------------------------

{c session
   :utterance_id -1
   :hub_log_prefix "MITRE-20001206-007"
   :hub_logdir "./MITRE/20001206/007/"
   :hub_pwd "/usr/local/GalaxyCommunicator/src"
   :current_status "adequate" }
 

As a special case, a Hub program may use the special values hub_increment_value and hub_decrement_value as values of these session keys in a SET: directive to increment and decrement integer values.


Alarms

Alarms are session-specific variables used for setting time outs in a production system.  Alarms can have three states: If an alarm is enabled with the time set, a system error will be generated when the time reaches zero.  In the normal course of execution, the time should be reset as each rule fires.  If a server dies, a system error will be generated.  The error can be used to end the dialogue by informing the user that the system is down.

The syntax is:

ALARM: alarm_name enable | disable | <num_secs>
The same line may contain enable/disable and <num_secs> for the same alarm.  Two examples are:


Processing occurs from left to right with the enable/disables processed first, then the <num_secs>.   The first example sets the already-enabled global_alarm to 20 seconds.  The second example enables both the global_alarm and the turn_alarm and then sets the first to 20 seconds, the second to 60 seconds.

Alarm Enable

Upon intiation, all alarms are enabled but they are not set unless the <num_secs> is specified.  Once an alarm is enabled, any future change of <num_secs> to a non-zero number is valid.  Setting an alarm with zero <num_secs> is equivalent to the alarm not being set.   For example, Alarms can be set globally so that they do not have to be set in each rule.  To set an alarm globally, set the alarm before any rules are defined.  Any particular server can override the global setting with a specific, local alarm.

Alarm Disable

Disabling an alarm is a higher-level override that sets <num_secs> to zero.  The alarm will not change until the next enable.  Disabling an alarm is useful because there is no easy way to test for an alarm having a time set before resetting it.  For example, one might want to turn off all alarms while waiting for user input.  Disabling an alarm is also useful when trying to debug code.


Alphabetical index of program file elements

; (comment)
# (comment)
#include
$bind
$id
$in
ALARM:
CLIENT_PORT:
CONDITIONS:
CONTINUE_REPLY:
CONTINUE_ERROR:
CONTROL:
DEL:
DOMAIN:
ERROR:
HOST:
IGNORE:
IN:
INIT:
INITIAL_REPLY:
INITIAL_TOKEN:
LOCATION:
LOCK:
LOG_DIR:
LOG_HUB_ACTIVITY:
LOG_IN: (see also the logging documentation)
LOG_OUT: (see also the logging documentation)
LOG_VERSION:
MESSAGE:
MODE:
OPERATIONS:
OUT:
PARAM:
PGM_SYNTAX:
PORT:
PROPERTIES:
PROGRAM:
PROVIDER_NAME:
PROVIDER_ID:
RETRIEVE:
RULE:
SERVER:
SERVERS:
SERVICE_PROVIDER:
SERVICE_TYPE:
SET:
STORE:
TIMESTAMP:
USER_ID:


License / Documentation home / Help and feedback
Last updated August 13, 2002