UNPKG

9.49 kBMarkdownView Raw
1# Modules
2
3An agent can be extended with modules, offering additional functionality.
4evejs comes with a number of built in modules. Usage:
5
6 agent.extend(moduleName);
7 agent.moduleName = agent.loadModule(moduleName);
8
9Evejs contains the following built-in modules:
10
11- [Babble](#babble)
12- [Pattern](#pattern)
13- [Request](#request)
14- [RPC](#rpc)
15
16
17## Babble
18
19Babble enables dynamic communication flows between agents by means of
20conversations. A conversation is modeled as a control flow diagram containing
21blocks `ask`, `tell`, `listen`, `iif`, `decide`, and `then`. Each block can
22link to a next block in the control flow. Conversations are dynamic:
23a scenario is build programmatically, and the blocks can dynamically determine
24the next block in the scenario. During a conversation, a context is available
25to store the state of the conversation.
26
27Evejs can be used together with [babble](https://github.com/enmasseio/babble),
28extending the agents with support for dynamic communication flows.
29
30Usage:
31
32 agent.extend('babble');
33
34The full API and documentation can be found at the project page of babble:
35
36https://github.com/enmasseio/babble
37
38Example:
39
40Create a file **BabbleAgent.js** with the following contents:
41
42```js
43var babble = require('babble');
44var eve = require('evejs');
45
46function BabbleAgent(id, props) {
47 // execute super constructor
48 eve.Agent.call(this, id);
49
50 this.props = props;
51
52 // babblify the agent
53 this.extend('babble');
54
55 // add a conversation listener
56 this.listen('hi')
57 .listen(function (message, context) {
58 console.log(context.from + ': ' + message);
59 return message;
60 })
61 .decide(function (message, context) {
62 return (message.indexOf('age') != -1) ? 'age' : 'name';
63 }, {
64 'name': babble.tell('hi, my name is ' + this.id),
65 'age': babble.tell('hi, my age is ' + this.props.age)
66 });
67
68 // connect to all transports provided by the system
69 this.connect(eve.system.transports.getAll());
70}
71
72// extend the eve.Agent prototype
73BabbleAgent.prototype = Object.create(eve.Agent.prototype);
74BabbleAgent.prototype.constructor = BabbleAgent;
75
76// have a conversation with an other agent
77BabbleAgent.prototype.talk = function (to) {
78 var name = this.id;
79 var age = this.props.age;
80
81 this.tell(to, 'hi')
82 .tell(function (message, context) {
83 if (Math.random() > 0.5) {
84 return 'my name is ' + name;
85 } else {
86 return 'my age is ' + age;
87 }
88 })
89 .listen(function (message, context) {
90 console.log(context.from + ': ' + message);
91 });
92};
93
94module.exports = BabbleAgent;
95```
96
97Usage:
98
99```js
100var BabbleAgent = require('./BabbleAgent');
101
102// create two agents
103var emma = new BabbleAgent('emma', {age: 27});
104var jack = new BabbleAgent('jack', {age: 25});
105
106// let jack have a conversation with emma
107jack.talk('emma');
108```
109
110
111## Pattern
112
113The `'pattern'` module extends an agent with support for pattern listening.
114Incoming messages can be matched against patterns.
115The agent will be extended with functions `listen` and `unlisten`. Cannot be
116used in conjunction with module `'babble'`.
117
118Usage:
119
120 agent.extend('pattern' [, options]);
121
122Available options:
123
124- `stopPropagation: boolean`
125 When true, a message will not be propagated to other pattern listeners as
126 soon as there is a match with one of the listeners. Thus, up to one listener
127 is triggered on an incoming message. Default value is false.
128
129 When false (default), a message will be delivered at all matching pattern
130 listeners. When true, a message will be be delivered at the first matching
131 pattern listener only.
132
133Methods:
134
135- `Agent.listen(pattern: string | RegExp | Function, callback: Function)`
136 Register an pattern listener, which is triggered when a message comes in which
137 matches given pattern. The pattern can be a string (exact match), a
138 regular expression, or a test function which is invoked as `pattern(message)`.
139 When a message matches the pattern, the `callback` function is invoked as
140 `callback(from, message)`.
141
142- `Agent.unlisten(pattern: string | RegExp | Function, callback: Function)`
143 Unregister a registered pattern listener.
144
145Example:
146
147Save the following code as **PatternAgent.js**:
148
149```js
150var eve = require('evejs');
151
152function PatternAgent(id) {
153 // execute super constructor
154 eve.Agent.call(this, id);
155
156 // extend the agent with pattern listening functionality
157 this.extend('pattern');
158
159 // listen for messages containing 'hello' (case insensitive)
160 this.listen(/hello/i, function (from, message) {
161 // reply to the greeting
162 this.send(from, 'Hi ' + from + ', nice to meet you!');
163 });
164
165 // listen for any message
166 this.listen(/./, function (from, message) {
167 console.log(from + ' said: ' + message);
168 });
169
170 // connect to all transports provided by the system
171 this.connect(eve.system.transports.getAll());
172}
173
174// extend the eve.Agent prototype
175PatternAgent.prototype = Object.create(eve.Agent.prototype);
176PatternAgent.prototype.constructor = PatternAgent;
177
178module.exports = PatternAgent;
179```
180
181Usage:
182
183```js
184var PatternAgent = require('./PatternAgent');
185
186// create two agents
187var agent1 = new PatternAgent('agent1');
188var agent2 = new PatternAgent('agent2');
189
190// send a message to agent 1
191agent2.send('agent1', 'Hello agent1!');
192```
193
194
195## Request
196
197The `'request'` module adds support for sending requests and awaiting a reply.
198
199Usage:
200
201 agent.extend('request' [, options]);
202
203Available options:
204
205- `timeout: number`
206 Specify the timeout for a request in milliseconds. When no reply is received
207 before the timeout is exceeded, the requests promise is rejected.
208 Default value is 60000 ms.
209
210Methods:
211
212- `Agent.request(to: string | Object, message: string, message: *)`
213 Send a request. The function returns a promise which resolves with the reply
214 comes in.
215
216Example:
217
218Create a file **RequestAgent.js** containing:
219
220```js
221var eve = require('evejs');
222
223function RequestAgent(id) {
224 // execute super constructor
225 eve.Agent.call(this, id);
226
227 // extend the agent with support for requests
228 this.extend('request');
229
230 // connect to all transports provided by the system
231 this.connect(eve.system.transports.getAll());
232}
233
234// extend the eve.Agent prototype
235RequestAgent.prototype = Object.create(eve.Agent.prototype);
236RequestAgent.prototype.constructor = RequestAgent;
237
238// implement the receive method
239RequestAgent.prototype.receive = function (from, message) {
240 console.log(from + ' said: ' + message);
241
242 // return value is send back as reply in case of a request
243 return 'Hi ' + from + ', nice to meet you!';
244};
245
246module.exports = RequestAgent;
247```
248
249Usage:
250
251```js
252var RequestAgent = require('./RequestAgent');
253
254// create two agents
255var agent1 = new RequestAgent('agent1');
256var agent2 = new RequestAgent('agent2');
257
258// send a request to agent 1, await the response
259agent2.request('agent1', 'Hello agent1!')
260 .then(function(reply) {
261 console.log('reply: ' + reply);
262 });
263```
264
265
266## RPC
267
268The RPC module allows your agents to communicate using JSON RPC 2.0. This can be used over all transport implementations. When using the HTTP transport, the request and reply are performed in the same HTTP session.
269
270Usage:
271```
272 agent.rpc = agent.loadModule('rpc',options);
273```
274In the options you can define which functions you want to open up the the RPC module. You can supply these as an Object or an Array of function names. The possible ways to define the options are shown here:
275
276```
277agent.add = function (params, [from]) {return params.a + params.b; }
278var options = ['add']
279```
280```
281agent.add = function (params, [from]) {return params.a + params.b; }
282var options = {add: agent.add};
283```
284```
285agent.rpcFunctions = {};
286agent.rpcFunctions.add = function (params, [from]) {return params.a + params.b; }
287var options = agent.rpcFunctions;
288```
289
290Methods:
291
292- `agent.request(to: string | Object, {method: String, params: *, [id: String, jsonrpc: '2.0']})`
293 Send a request. The function returns a promise which resolves with the reply comes in. Only the 'method' and the 'params' fields are required. Evejs will give the message an UUID and add the jsonrpc field as required by the JSON RPC 2.0 spec. The reply is delivered in the JSON RPC response format.
294
295Example:
296
297Using the `rpc` module, agents can easily send a message and await a response.
298Create a file **RPCAgent.js** containing:
299
300```js
301var eve = require('evejs');
302
303function RPCAgent(id, props) {
304 // execute super constructor
305 eve.Agent.call(this, id);
306
307 this.props = props;
308
309 // load the RPC module
310 this.rpc = this.loadModule('rpc', this.rpcFunctions);
311
312 // connect to all transports provided by the system
313 this.connect(eve.system.transports.getAll());
314}
315
316// extend the eve.Agent prototype
317RPCAgent.prototype = Object.create(eve.Agent.prototype);
318RPCAgent.prototype.constructor = RPCAgent;
319
320// create an object containing all RPC functions.
321RPCAgent.prototype.rpcFunctions = {};
322
323// create an RPC function
324RPCAgent.prototype.rpcFunctions.add = function(params, from) {
325 return params.a + params.b;
326};
327
328module.exports = RPCAgent;
329```
330
331Usage:
332
333```js
334var RPCAgent = require('./RPCAgent');
335
336// create two agents
337var agent1 = new RPCAgent('agent1');
338var agent2 = new RPCAgent('agent2');
339
340// send a message to agent1
341var message = {method:'add', params: {a:1, b:3}};
342agent2.rpc.request('agent1', message).then(function(reply) {
343 console.log('The agent told me that', params.a, '+', params.b, '=', reply.result);
344 });
345}
346```