USERMI

Making TaskableAgents Distributed...

Tom Ioerger, 11/18/00


The idea is that, through a TACL command (which could be typed into the shell, or automatically run as part of init.TACL) called 'usermi', the agent starts starts an RMI server object called a MsgQueue. The argument you give is the name it gets bound to.

   (usermi agent0)
Then other agents (or client processes) can send messages to the agent. They automatically get stamped with the sender's name (ID, supplied by sender) and time. Each time through the loop, the agent checks for messages, pops them out of the queue, and asserts them into the Jare KB. The format of asserted messages is as a fact with predicate name 'message', a message counter (interger, starts at 0), the sender ID string, the time (in ms since 1970), and finally the message. Visually:
   (message [count] [sender] [time] [message])
Messages can be arbitrary strings, as long as they are parsable by Jare. My suggestion is to enclose the whole message in parens, so it appears as a fourth term in message facts (i.e. having a constant arity of 4). Note that, although there are many different types of communications (e.g. KQML performatives), MsgQueues do not represent message types explicitly. Therefore, if you want to indicate that a message is a TELL or ASK, etc., you must indicate so within the message string itself (as an extra-logical tag on (or attitude toward) a sentence, or other arguments). Then it is up to the TRL+inference engine to decompose and interpret such messages. Here are some examples:
   (message 1 a-neighbor 974622840421 (tell (destroyed enemy-regiment-12)))
   (message 2 salesman-15 974622843765 (bid old-green-lamp 15))
   (message 3 commander 974622852346 (do (construct bridge concrete route-60 brazos-river)))
   (message 4 student-7 974622862300 (ask (captial hawaii ?x)))
To use this distributed feature, there are two things that must be done first:
  1. be sure you are running 'rmiregistry', and
  2. use the following flag to run the agent: 'java -Djava.security.policy=policy TaskableAgents.Agent' with an appropriate policy file (try 'make runagent', which runs this command with the policy flag set)
Note, if you DON'T want to use RMI, you can always just run 'java TaskableAgents.Agent' as before.

Once messages are placed in the KB, they may be detected and handled by TRL methods. The general gist of the approach is: implement a while loop that checks for new messages, and when found, do something about them and then retract them. For example, an message like (inform (location unitA 59 62)) from another agent might get asserted as a direct location fact, perhaps depending on how trusted the other agent is.

I should implement a TELL operator for talking to other agents.


Example

Here is a simple example of a multi-agent interaction. The idea is that I want to start my agent up as 'agent0', and I am going to use MsgQueue Client program to send it a message as 'client1'. The configuration files used in this example are: First, we bring up the agent and initialize the handle_inform_messages task...
bradley# make runagent
java -Djava.security.policy=policy TaskableAgents.Agent

executing: ((read builtin.TRL))
executing: ((usermi agent0))
MsgQueue created
executing: ((batch test.KB))
reading: test.KB
executing: ((read test.TRL))
executing: ((start (handle_inform_messages)))

constructing ITask handle_inform_messages
task binding [] to []
constructing IMethod M_handle_inform_messages
method binding [] to []
ghost: 0
contingent: 2
PNodeContingent evaluating: ((true))
ghost: 3
contingent: 7
PNodeContingent evaluating: ((not (message ?num ?agent ?time (tell ?fact))))
ghost: 8
atomic: 11
constructing IOper NOP
oper binding [] to []
Then, in a separate window on the same machine (bradley), we start up the client, and send 'tell' message about the location of some unit.
bradley# java MsgQueue.Client client1 agent0

client1> say (tell (location unit 2 3))
input: say (tell (location unit 2 3))
sending: (tell (location unit 2 3))

client1> quit

bradley#
The agent grabs the message from the MsgQueue and asserts it (as a 'message' fact) to the KB. Then the TRL method for handle_inform_messages recognizes it, retracts it, and (since it implicitly trusts any user, according to the trivial Horn-clause definition of 'trusted' in test.KB) it asserts the location information directly as a fact.
>(step)
received message from client1 at Sun Nov 19 14:34:07 GMT+06:00 2000
>>>(tell (location unit 2 3))
asserting: (message 0 client1 974622847139 (tell (location unit 2 3)))
executing: ((step))
*** NOP
repairing ITask handle_inform_messages
repairing IMeth M_handle_inform_messages
repairing IOper
ghost: 9
resetEnv: 10
contingent: 7
PNodeContingent evaluating: ((not (message ?num ?agent ?time (tell ?fact))))
ghost: 6
contingent: 13
PNodeContingent evaluating: ((message ?num ?agent ?time (tell ?fact)))
ghost: 14
atomic: 16
constructing IOper PRINT
oper binding [?msg] to ["tell message received"]
result for toptask=0

>(query (message ?a ?b ?c ?d))
executing: ((query (message ?a ?b ?c ?d)))
((message 0 client1 974622847139 (tell (location unit 2 3))))

>(step)
executing: ((step))
*** "tell message received"
repairing ITask handle_inform_messages
repairing IMeth M_handle_inform_messages
repairing IOper
ghost: 15
atomic: 18
constructing IOper RETRACT
predicate: [message, 0, client1, 974622847139, [tell, [location, unit, 2, 3]]]
result for toptask=0

>(step)
executing: ((step))
*** retracting in Jare: [message, 0, client1, 974622847139, [tell, [location, unit, 2, 3]]]
repairing ITask handle_inform_messages
repairing IMeth M_handle_inform_messages
repairing IOper
ghost: 17
contingent: 20
PNodeContingent evaluating: ((trusted client1))
ghost: 21
atomic: 22
constructing IOper ASSERT
predicate: [location, unit, 2, 3]
result for toptask=0

>(step)
executing: ((step))
*** asserting to Jare: [location, unit, 2, 3]
repairing ITask handle_inform_messages
repairing IMeth M_handle_inform_messages
repairing IOper
ghost: 4
resetEnv: 5
contingent: 2
PNodeContingent evaluating: ((true))
ghost: 3
contingent: 7
PNodeContingent evaluating: ((not (message ?num ?agent ?time (tell ?fact))))
ghost: 8
atomic: 11
constructing IOper NOP
oper binding [] to []
result for toptask=0

>(query (message ?a ?b ?c ?d))
executing: ((query (message ?a ?b ?c ?d)))

>(query (location ?a ?b ?c))
executing: ((query (location ?a ?b ?c)))
((location unit 2 3))
Eventually, the agent settles back into doing NOP's...
>(step)
executing: ((step))
*** NOP
repairing ITask handle_inform_messages
repairing IMeth M_handle_inform_messages
repairing IOper
ghost: 9
resetEnv: 10
contingent: 7
PNodeContingent evaluating: ((not (message ?num ?agent ?time (tell ?fact))))
ghost: 8
atomic: 11
constructing IOper NOP
oper binding [] to []
result for toptask=0

>quit
quit
bradley#