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:
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.
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#