OAA 1.0 Tutorial
This is intended to be a brief, step-by-step look at what it takes to
create an OAA agent. For a more in-depth look, see the
OAA Developer's guide.
OAA 1.0 Tutorial
Introduction to OAA
The Open Agent Architecture (OAA) is a multi-agent framework that
focuses on enabling more flexible interactions among a dynamic
community of heterogeneous software agents. The key idea in OAA is
delegation: instead of each agent hard-coding its interactions
(method calls or messages), explaining how and who it
will interact with, OAA agents express interactions in terms of
needs delegated to a Facilitator agent. A Facilitator agent will
coordinate the agent community in achieving the task, providing services
such as parallelism, failure handling, conflict detection, and so forth
that each client agent does not have to worry about itself.
Agents communicate with each other using a logic-based language called
the Interagent Communication Language (ICL).
Typically, agents use
the ICL to register their capabilities
with a Facilitator, and then to make requests of the agent community to
accomplish tasks, read or
write data, and install distributed triggers or
monitors.
ICL Syntax
Since all communicate among agents makes use of the Interagent
Communication Language, it is important to be able to construct and
read ICL messages.
ICL is based on an extension of the Prolog language, and uses Prolog
syntax. In Prolog, there are only several element types in the
language:
- Variables start with an uppercase letter or with the
character '_'. Examples: X, B1, LastName, _123.
- Numbers are written as in most languages. Examples: 123,
3.14159.
- Atoms (can be thought of as strings) either start
with a lowercase letter and contain no "tricky" characters (e.g.
spaces), or else are enclosed by single quotes (').
Note: if you want to include a
single quote inside an atom, you double the single quote (ie. use two
single quotes next to each other. Examples: bob, bob12, 'Bob Jones',
'Bob''s email'.
- Structures have a functor (the function name) and a
list of arguments. The number of arguments is often called the
arity of the structure. Arguments can be of any Prolog type,
including other structures. Examples: employee(1,'Adam
Cheyer',office('EJ217')).
- Lists, although represented internally in Prolog as structures
with arity 2 and with functor '.', have their own syntax. Lists are
enclosed in brackets, with arguments separated by commas. Arguments
may be any Prolog type, including other lists or structures. The
empty list is represented by [].
Examples: [1,2,3], [name('Adam'), age(25)].
Creating an OAA agent is very simple. Every agent must:
- Include the OAA agent library.
- Connect to and register with a Facilitator agent. During
registration, an agent specifies its symbolic name and the list of
capabilities (called solvables) that it can handle. If the agent
offers no services to the community at large, its solvable list may be
the empty list ("[]").
- Provide definitions for several callback functions which allow
the agent to specify code to be performed during initialization and
idle time, and to specify code performing its published capabilities.
During the callback functions, an agent may need to make requests of
the community to perform tasks, read or write data, or install
distributed triggers, and the agent library provides primitives for
each of these functions.
In OAA 1.0, agent capabilities are simply a Prolog-style declaration
such as "a(X)". Incoming requests will be unified with the
declaration, and if unification succeeds, the request will be
forwarded to the agent who published the capability.
Agents may also specify test conditions along with a solvable, written
using the operator ':-'. In the following example, an agent will only
receive requests where X is bound to an integer less than 10:
(a(X) :- X < 10)
Note: OAA capabilities declarations are always in the style of a
relational declaration, returning solutions in a separate argument,
not as a function value. For instance:
// Good
parent(Child, Parent)
// NOT
Parent = parent(Child).
For each capability declaration defined in an agent's solvable list,
the agent must define code to handle the declaration. In OAA 1.0,
this declaration is written in a callback named do_event(), which
supplies the incoming request and an address ID to the requesting
agent. The do_event() callback is expected to perform the function
associated with the request and to success, failure, or multiple
solutions to the query.
Examples:
Prolog:
do_event(_AgentId, a(1)).
C:
int do_event(char *AgentId, char *func, char *args, char **answers) {
int numArgs = list_len(args);
int processed = TRUE;
char arg1 = NULL;
// for solvable: a(X)
if ((strcomp(func, "a") == 0) && (numArgs == 1)) {
NthElt(args, 1, &arg1);
if (is_var(arg1) || (strcomp(arg1, "1") == 0) {
*answers = malloc(BIG_ENOUGH); // Can use malloc to create space for answer
sprintf(*answers, "[a(%d)]", 1); // Stores result into answer space
}
else *answers = strdup("[]"); // Can use strdup to return result
}
else processed = FALSE; // not returning a result for this query
return processed;
}
Agents may make requests of the agent community using the built-in
primitive solve(). Solve() takes a goal to be executed and a list of
control parameters as arguments, and returns success, failure, or
multiple solutions for the goal.
In OAA 1.0, the argument list of control parameters may include:
- address(AgentAddress): which agent should solve the goal
- broadcast: just disseminate the message, do not request results
returned.
- asynchronous: request solutions, but do not block. Solutions
will be returned asynchronously in
solved(FromAgent,Goal,Params,Solutions) messages which should be
handled in do_event().
- solution_limit(N): limits the number of solutions found to N.
- time_limit(N): waits a maximum of N seconds before returning
(failure if no solution found in given amount of time).
- level_limit(N): highest number of hierarchical Facilitator levels
to climb looking for solutions.
- cache: cache all solutions locally and use cache before looking
over the net.
Examples:
C: solve("fax_number('Adam Cheyer', FaxNumber)", "[solution_limit(1)]", &answers);
Prolog: solve(fax_number('Adam Cheyer', FaxNumber), [solution_limit(1)]).
In OAA 1.0, the Facilitator can be used as a blackboard to store data
that is shared among the agent communities. Agents write data on the
Facilitator using write_bb(Variable, Value), and read it with
read_bb(Variable, Value). The Facilitator agent records the source of
the data, and if an agent disconnects, all data written by the agent
is removed from the Facilitator. If an agent wants to know which
agent has written a particular fact, read_bb(AgentId, Variable, Value)
may be used.
Example:
Prolog: write_bb(name, 'Adam Cheyer').
Triggers can be used to monitor communication events (type=event), data changes
(type=data), domain-specific tasks (type=test) such as email arriving,
webpage changing, and so forth, and if the alarm agent is connected,
time (type=alarm).
A trigger must have a type, a recurrence value (when=oneshot,
whenever=recurring), a condition and an action. A user may also
specify an additional test once the main condition matches, and an
OpMask value. The OpMask value is dependent on the trigger type:
- data triggers: OpMask may be on_write, on_replace, on_retract,
on_write_replace, a variable, or a list combining several of these.
- event triggers: OpMask may be on_send, on_receive, a variable, or a list
combining several of these.
OpMasks are not used for time triggers or test triggers.
Examples:
// Agent receives update_data() solvable whenever a new agent
// connects or disconnects to Facilitator (because the agent library
// reads and writes the ksdata() fact on connection/disconnection).
Java: oaa.lib.addRemoteTrigger("data", "whenever", // Type & recurrence
"Op", "data(ksdata,D)", "true", // Condition
"post_query(update_data(Op,D),[broadcast])"); // Action
// Agent will receive an update_event() message every time
// any agent sends or receives any message (useful for logging).
// Except doesn't log its own messages...
Java: oaa.lib.addRemoteTrigger("event", "whenever", // Type & recurrence
"Op", "event(AgentId,Ev)", // Condition
"(AgentId \== " + me.id + ")", // Additional test
"post_query(update_event(Op,AgentId,Ev),[broadcast])");
Here is complete sourcecode to a very simple agent in various
programming languages:
A Facilitator agent must be started before running any other agents,
since other agents will connect to the Facilitator to register. To
start a Facilitator, run the executable "b". The Facilitor will look
for a host and port values on which to start listening -- these values
can be specified on the command line, using environment variables, or
in a special file called "setup.pl".
- command line: b -oaa_host trestle -oaa_port 3456
- environment variables: OAA_HOST=trestle OAA_PORT=3456
- setup.pl (local directory or home directory): contains line
"rootdata(3456, trestle)."
The Facilitator, if it can correctly start, will print:
./b -oaa_host trestle -oaa_port 3456
Loading setup file: '/home/trestle2/cheyer/setup.pl'
Listening on trestle port 3456
Ready.
Sometimes under Windows platforms, the Facilitator is extremely picky
about how the host is specified, and will sometimes refuse IP numbers
or some combinations of DNS names. If this occurs, try using a
variable for the host, and seeing if the Facilitator starts. If it
does, note the host exactly as it is printed in the "Listening on XXX"
message, and record this hostname in the setup.pl file.
Start-It is an agent which can be used to execute and monitor one or
more agents in a community. Start-It reads a configuration file which
specifies the list of agents and their parameters. From this, it
builds a GUI interface which allows a developer to start and stop
individual agents. If an agent dies, Start-it's auto-restart function
can be used to automatically restart the agent.
The Monitor agent is useful for graphically viewing an agent community
and for tracing messages being sent among agents. When the Monitor
agent is run, it will ask the Facilitator for the list of connected
agents and then will display a graphical representation of the
community. Clicking on the icon representing an agent will display
information about it: its host, programming language, agent library
version, and its list of solvables. When the "Record Events" button
is pressed, all communication events among agents will be logged and
can be viewed, stepped through, or searched by using the Event window.
Copyright 1994-98, SRI International.