@indra.ai/deva 1.0.34 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +20 -10
- package/_config.yml +1 -1
- package/examples/hello-world.js +28 -18
- package/index.js +326 -146
- package/package.json +1 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -7,22 +7,31 @@ Deva is a Node.js module designed to simplify the development of multi-agent sys
|
|
|
7
7
|
|
|
8
8
|
The Deva module is a JavaScript library for building multi-agent systems that can communicate with each other and with external services. It provides a unified API for creating agents and defining their behaviors, and includes tools for handling communication between agents and for integrating with third-party APIs. The Deva module is designed to be flexible and customizable, allowing developers to easily create complex systems that can perform a wide range of tasks, from data collection and analysis to chatbot interactions and image generation. The module is written in JavaScript and can be used with Node.js, making it easy to integrate with other JavaScript libraries and tools.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Functions
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Here are some insights about the code you shared:
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
1. Class Structure: The code follows an object-oriented programming approach by defining a `Deva` class. This allows for encapsulation of properties and methods related to the agent.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
2. State Management: The `Deva` class has a state management system represented by the `_state` property and the `_states` object. It allows the agent to transition between different states and perform actions based on the current state.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
3. Event System: The code utilizes an event system by extending the `EventEmitter` class and creating an `events` object. This enables communication and collaboration between different components of the agent and other entities in the system.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
4. Modularity and Inheritance: The code demonstrates modularity by separating functionalities into different objects such as `config`, `lib`, `methods`, and `listeners`. It also showcases inheritance by assigning inherited properties to child Deva instances.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
5. Error Handling: The code includes an error handling mechanism through the `error` method. It allows for uniform error reporting and the execution of custom error handling logic.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
6. Promises: Promises are used in several asynchronous operations, such as initializing the agent, loading Deva models, and handling method calls. Promises ensure that the code can handle asynchronous operations in a structured and controlled manner.
|
|
25
25
|
|
|
26
|
+
7. Event-driven Architecture: The code follows an event-driven architecture where different events trigger specific actions or callbacks. This enables loose coupling and flexibility in the agent's behavior and interactions with other components.
|
|
27
|
+
|
|
28
|
+
8. Extensibility: The code provides hooks for custom logic through methods like `onInit`, `onStart`, `onStop`, `onEnter`, `onExit`, and `onDone`. These allow developers to extend the functionality of the agent by adding custom code at specific stages of its lifecycle.
|
|
29
|
+
|
|
30
|
+
9. Messaging and Communication: The `talk` and `listen` methods facilitate messaging and communication between agents. Agents can ask questions (`ask` method) and receive responses, enabling interaction and collaboration.
|
|
31
|
+
|
|
32
|
+
10. Utility Functions: The code includes utility functions like generating unique IDs (`uid` method), hashing data (`hash` method), and handling event listeners (`listen`, `once`, `ignore` methods).
|
|
33
|
+
|
|
34
|
+
Overall, the code demonstrates the implementation of a flexible and extensible agent framework with state management, event-driven architecture, and various functionalities for communication, error handling, and lifecycle management.
|
|
26
35
|
|
|
27
36
|
## Uses
|
|
28
37
|
|
|
@@ -39,7 +48,7 @@ Additionally, the Deva module can be used by a corporation to automate various i
|
|
|
39
48
|
A scientist could use the Deva module in a number of ways. For example, they could create agents to help with data analysis or modeling, or to interact with other software tools in the research process. The Deva module's ability to dynamically load agents and unify data across different platforms could also be useful in streamlining scientific workflows and collaborations between research groups. Additionally, the natural language processing capabilities of the ChatGPT agent could be utilized to help with tasks such as literature reviews or generating hypotheses. Overall, the Deva module could be a valuable tool for scientists looking to enhance their research process with the help of intelligent agents.
|
|
40
49
|
|
|
41
50
|
|
|
42
|
-
|
|
51
|
+
### Scalability
|
|
43
52
|
|
|
44
53
|
The Deva module has a high potential for scalability because of its dynamic agent loading feature. This means that new agents can be added to the system at runtime without the need for a system restart or manual intervention. The module is also designed to work with state management to track agent processes at different load, process, and exit states. This makes it possible to scale the system horizontally by adding more computing resources to handle increased load, or vertically by adding more powerful hardware to each node in the system. Overall, the Deva module is well suited for building large-scale, distributed agent-based systems that can handle complex and diverse workloads.
|
|
45
54
|
|
|
@@ -458,4 +467,5 @@ The `initDeva()` function will initialize the Deva located under the current Dev
|
|
|
458
467
|
|
|
459
468
|
[Github Repo](https://github.com/indraai/deva)
|
|
460
469
|
[Back to indra.ai](https://indra.ai)
|
|
461
|
-
|
|
470
|
+
|
|
471
|
+
©2023 Quinn Michaels; All Rights Reserved.
|
package/_config.yml
CHANGED
package/examples/hello-world.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
// Copyright (c)
|
|
1
|
+
// Copyright (c)2023 Quinn Michaels
|
|
2
2
|
// Distributed under the MIT software license, see the accompanying
|
|
3
3
|
// file LICENSE.md or http://www.opensource.org/licenses/mit-license.php.
|
|
4
4
|
const Deva = require('../index');
|
|
5
5
|
const HelloWorld = new Deva({
|
|
6
|
+
client: {
|
|
7
|
+
id: 100,
|
|
8
|
+
},
|
|
6
9
|
agent: {
|
|
10
|
+
id: 101,
|
|
7
11
|
key: 'hello',
|
|
8
12
|
name: 'Hello World',
|
|
9
13
|
description: 'The most over complex Hello World in the Universe',
|
|
@@ -32,30 +36,36 @@ const HelloWorld = new Deva({
|
|
|
32
36
|
vars: {
|
|
33
37
|
hello: 'Hello World'
|
|
34
38
|
},
|
|
35
|
-
listeners: {
|
|
39
|
+
listeners: {
|
|
40
|
+
'101:state'(st) {
|
|
41
|
+
console.log(`current state: ${st}`);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
36
44
|
deva: {},
|
|
37
45
|
modules: {},
|
|
38
46
|
func: {
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
state(packet) {
|
|
48
|
+
const ret = `${this._state} ${this.uid(true)} ${this.uid()} ${this.hash(JSON.stringify(packet), 'sha256')}`;
|
|
49
|
+
return Promise.resolve(ret);
|
|
41
50
|
}
|
|
42
51
|
},
|
|
43
52
|
methods: {
|
|
44
|
-
|
|
45
|
-
return this.func.
|
|
53
|
+
state(packet) {
|
|
54
|
+
return this.func.state(packet);
|
|
46
55
|
}
|
|
47
56
|
},
|
|
57
|
+
onError(e, packet) {
|
|
58
|
+
console.log('ERROR\n\n', e, packet);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
onStop() {},
|
|
54
|
-
onEnter() {},
|
|
55
|
-
onExit() {},
|
|
56
|
-
onDone() {},
|
|
57
|
-
onInit() {
|
|
58
|
-
this.start();
|
|
59
|
-
},
|
|
62
|
+
HelloWorld.init().then(done => {
|
|
63
|
+
return HelloWorld.question('/state how are you')
|
|
64
|
+
}).then(answer => {
|
|
65
|
+
console.log('ANSWER', answer.a.text);
|
|
60
66
|
});
|
|
61
|
-
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
// HelloWorld.question('/hello hello there').then(hello => {
|
|
70
|
+
// console.log('hello', hello);
|
|
71
|
+
// });
|
package/index.js
CHANGED
|
@@ -1,14 +1,41 @@
|
|
|
1
|
-
// Copyright (c)
|
|
1
|
+
// Copyright (c)2023 Quinn Michaels
|
|
2
2
|
// Distributed under the MIT software license, see the accompanying
|
|
3
3
|
// file LICENSE.md or http://www.opensource.org/licenses/mit-license.php.
|
|
4
4
|
const {EventEmitter} = require('events');
|
|
5
|
+
const { createHash, randomUUID } = require('crypto');
|
|
6
|
+
|
|
5
7
|
class Deva {
|
|
6
8
|
constructor(opts) {
|
|
7
9
|
opts = opts || {};
|
|
8
10
|
this._uid = this.uid(); // the unique id assigned to the agent at load
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
11
|
+
this._state = 'OFFLINE'; // current state of agent.
|
|
12
|
+
this._states = { // The available states to work with.
|
|
13
|
+
offline: 'OFFLINE',
|
|
14
|
+
init: 'INIT',
|
|
15
|
+
start: 'START',
|
|
16
|
+
stop: 'STOP',
|
|
17
|
+
enter: 'ENTER',
|
|
18
|
+
exit: 'EXIT',
|
|
19
|
+
done: 'DONE',
|
|
20
|
+
wait: 'WAITING',
|
|
21
|
+
data: 'DATA',
|
|
22
|
+
ask: 'ASK',
|
|
23
|
+
question: 'QUESTION',
|
|
24
|
+
answer: 'ANSWER',
|
|
25
|
+
talk: 'TALK',
|
|
26
|
+
listen: 'LISTEN',
|
|
27
|
+
error: 'ERROR',
|
|
28
|
+
story: 'STORY',
|
|
29
|
+
development: 'DEVELOPMENT',
|
|
30
|
+
security: 'SECURITY',
|
|
31
|
+
support: 'SUPPORT',
|
|
32
|
+
services: 'SERVICES',
|
|
33
|
+
systems: 'SYSTEMS',
|
|
34
|
+
solutions: 'SOLUTIONS',
|
|
35
|
+
};
|
|
36
|
+
this._active = false; // the active/birth date.
|
|
11
37
|
this.security = false; // inherited Security features.
|
|
38
|
+
this.support = false; // inherited Support features.
|
|
12
39
|
this.config = opts.config || {}; // local Config Object
|
|
13
40
|
this.events = opts.events || new EventEmitter({}); // Event Bus
|
|
14
41
|
this.lib = opts.lib || {}; // used for loading library functions
|
|
@@ -26,49 +53,44 @@ class Deva {
|
|
|
26
53
|
if (!this[opt]) this[opt] = opts[opt]; // set any remaining opts to this.
|
|
27
54
|
}
|
|
28
55
|
|
|
29
|
-
this.cmdChr = '
|
|
56
|
+
this.cmdChr = '/';
|
|
30
57
|
this.askChr = '#';
|
|
31
58
|
this.inherit = ["events", "config", "lib", "security", "client"];
|
|
32
59
|
this.bind = ["listeners", "methods", "func", "lib", "security", "agent", "client"];
|
|
33
|
-
this.states = {
|
|
34
|
-
offline: 'OFFLINE',
|
|
35
|
-
init: 'INITIALIZE',
|
|
36
|
-
start: 'START',
|
|
37
|
-
stop: 'STOP',
|
|
38
|
-
enter: 'ENTER',
|
|
39
|
-
exit: 'EXIT',
|
|
40
|
-
done: 'DONE',
|
|
41
|
-
wait: 'WAITING',
|
|
42
|
-
ask: 'ASK',
|
|
43
|
-
question: 'QUESTION',
|
|
44
|
-
answer: 'ANSWER',
|
|
45
|
-
error: 'ERROR',
|
|
46
|
-
security: 'SECURITY',
|
|
47
|
-
medic: 'MEDICAL',
|
|
48
|
-
};
|
|
49
60
|
this.messages = {
|
|
50
61
|
offline: 'AGENT OFFLINE',
|
|
51
62
|
loaded: 'DEVAS LOADED',
|
|
52
63
|
stopped: 'DEVAS STOPPED',
|
|
53
64
|
notext: 'NO TEXT',
|
|
65
|
+
notfound: 'NOT FOUND',
|
|
54
66
|
}
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
// set the state of the agent with the passed value to match the valid keys.
|
|
58
70
|
// this will also talk a global state event with the agent data and state.
|
|
59
71
|
// then security can watch all the glorious state change events.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.
|
|
72
|
+
|
|
73
|
+
/**************
|
|
74
|
+
func: state
|
|
75
|
+
params:
|
|
76
|
+
- st: The state flag to set for the Deva that matches to this._states
|
|
77
|
+
describe
|
|
78
|
+
***************/
|
|
79
|
+
state(st) {
|
|
80
|
+
this._state = this._states[st];
|
|
81
|
+
this.talk(`${this.agent.id}:state`, this._state);
|
|
69
82
|
}
|
|
83
|
+
|
|
70
84
|
// Called from the init function to bind the elements defined in the this.bind variable.
|
|
71
85
|
// the assign bind ensures that the *this* scope is available to child elements/functions.
|
|
86
|
+
|
|
87
|
+
/**************
|
|
88
|
+
func: _assignBind
|
|
89
|
+
params: none
|
|
90
|
+
describe:
|
|
91
|
+
The assign bind function will bind the translate functions and parse functions
|
|
92
|
+
of the agent and bind their functionality to the state machine.
|
|
93
|
+
***************/
|
|
72
94
|
_assignBind() {
|
|
73
95
|
return new Promise((resolve, reject) => {
|
|
74
96
|
try {
|
|
@@ -95,13 +117,18 @@ class Deva {
|
|
|
95
117
|
});
|
|
96
118
|
}
|
|
97
119
|
|
|
98
|
-
|
|
99
|
-
|
|
120
|
+
/**************
|
|
121
|
+
func: _assignListeners
|
|
122
|
+
params: none
|
|
123
|
+
describe:
|
|
124
|
+
Assign listeners will take the this.lisners objects and assign the appropriate
|
|
125
|
+
lisnter values for the event bus.
|
|
126
|
+
***************/
|
|
100
127
|
_assignListeners() {
|
|
101
128
|
return new Promise((resolve, reject) => {
|
|
102
129
|
try {
|
|
103
130
|
// set the default listeners for the states of the agent.
|
|
104
|
-
for (let state in this.
|
|
131
|
+
for (let state in this._states) {
|
|
105
132
|
this.events.on(`${this.agent.key}:${state}`, packet => {
|
|
106
133
|
return this[state](packet);
|
|
107
134
|
})
|
|
@@ -124,6 +151,13 @@ class Deva {
|
|
|
124
151
|
|
|
125
152
|
// Some elements will inherit the data of the parent. this object will loop over
|
|
126
153
|
// any children data that theis deva has and assign the inherited information.
|
|
154
|
+
/**************
|
|
155
|
+
func: _assignInherit
|
|
156
|
+
params: none
|
|
157
|
+
describe:
|
|
158
|
+
The assign inherit will make sure the Devas in the current Deva have all the
|
|
159
|
+
inherited properties all setup to collaborate efficiently.
|
|
160
|
+
***************/
|
|
127
161
|
_assignInherit() {
|
|
128
162
|
return new Promise((resolve, reject) => {
|
|
129
163
|
try {
|
|
@@ -143,11 +177,25 @@ class Deva {
|
|
|
143
177
|
}
|
|
144
178
|
|
|
145
179
|
// General handler for when a method is NOT found from a user command.
|
|
180
|
+
/**************
|
|
181
|
+
func: _methodNotFound
|
|
182
|
+
params:
|
|
183
|
+
- packet: The packet to relay when a method is not found.
|
|
184
|
+
describe:
|
|
185
|
+
The _methodNotFound function allows for additional security by firing
|
|
186
|
+
a specfici program functon every single time a interaction happens wehre a
|
|
187
|
+
method is not located. This assits in security and support by identifying
|
|
188
|
+
troubls or users who may be attemptng to explit features.
|
|
189
|
+
|
|
190
|
+
Then we talk a security event that watches all methods and return the packet.
|
|
191
|
+
|
|
192
|
+
This will return a not found text string preventing any furhter processing.
|
|
193
|
+
***************/
|
|
146
194
|
_methodNotFound(packet) {
|
|
147
195
|
packet.a = {
|
|
148
196
|
agent: this.agent || false,
|
|
149
197
|
client: this.client || false,
|
|
150
|
-
text: `${packet.q.meta.method}
|
|
198
|
+
text: `${packet.q.meta.method} ${this.messages.notfound}`,
|
|
151
199
|
meta: {
|
|
152
200
|
key: this.agent.key,
|
|
153
201
|
method: packet.q.meta.method,
|
|
@@ -161,64 +209,123 @@ class Deva {
|
|
|
161
209
|
// quite oftne have to key their transactions. This will provide all agents
|
|
162
210
|
// with the same key generator which can also be modified to link into a remote
|
|
163
211
|
// generator or some other solution if needed.
|
|
164
|
-
|
|
212
|
+
|
|
213
|
+
/**************
|
|
214
|
+
func: uid
|
|
215
|
+
params:
|
|
216
|
+
- guid: This is a true false flag for generating a guid.
|
|
217
|
+
describe:
|
|
218
|
+
The uid function can create two types of id for you.
|
|
219
|
+
1. random GUID - this is good for when you need a uinique record id returned
|
|
220
|
+
2. transport id - The transport id is a number generated to provide a
|
|
221
|
+
numerical number used for transporting records to places
|
|
222
|
+
like social networks, email, other networks where informaton
|
|
223
|
+
is shared.
|
|
224
|
+
***************/
|
|
225
|
+
uid(guid=false) {
|
|
226
|
+
if (guid) return randomUUID()
|
|
165
227
|
const min = Math.floor(Date.now() - (Date.now() / Math.PI));
|
|
166
228
|
const max = Math.floor(Date.now() + (Date.now() * Math.PI));
|
|
167
229
|
return Math.floor(Math.random() * (max - min)) + min;
|
|
168
230
|
}
|
|
169
231
|
|
|
170
|
-
|
|
171
|
-
|
|
232
|
+
/**************
|
|
233
|
+
func: talk
|
|
234
|
+
params:
|
|
235
|
+
- evt: The event the Deva is speaking to listen back for on a once event.
|
|
236
|
+
- resource: The payload resource to send with the talk event.
|
|
237
|
+
describe:
|
|
238
|
+
The talk event allows agents to broadcast events that other Deva can listen
|
|
239
|
+
to and make a response. talk events can be then returned with a talk even id
|
|
240
|
+
to create seamless collaboration between Devas.
|
|
241
|
+
***************/
|
|
172
242
|
talk(evt, resource=false) {
|
|
173
243
|
return this.events.emit(evt, resource);
|
|
174
244
|
}
|
|
175
245
|
|
|
176
|
-
|
|
177
|
-
|
|
246
|
+
/**************
|
|
247
|
+
func: listen
|
|
248
|
+
params:
|
|
249
|
+
- evt: The vent label to listen for
|
|
250
|
+
- callback: The callback function to run when the event fires.
|
|
251
|
+
describe:
|
|
252
|
+
***************/
|
|
178
253
|
listen(evt, callback) {
|
|
179
254
|
return this.events.on(evt, callback);
|
|
180
255
|
}
|
|
181
256
|
|
|
182
|
-
|
|
183
|
-
|
|
257
|
+
/**************
|
|
258
|
+
func: once
|
|
259
|
+
params:
|
|
260
|
+
- evt: The event to listen to for a once call. These event are handy
|
|
261
|
+
when waiting for a key response one time.
|
|
262
|
+
- callback: The callback functoin to run when the event fires.
|
|
263
|
+
describe:
|
|
264
|
+
***************/
|
|
184
265
|
once(evt, callback) {
|
|
185
266
|
return this.events.once(evt, callback);
|
|
186
267
|
}
|
|
187
268
|
|
|
188
|
-
|
|
189
|
-
|
|
269
|
+
/**************
|
|
270
|
+
func: ignore
|
|
271
|
+
params:
|
|
272
|
+
- evt: The event you'd like to ignore.
|
|
273
|
+
- callback: a callback function to execute after removing the event from listerns.
|
|
274
|
+
describe:
|
|
275
|
+
The ignore function allow the removal of events that are in the existing devas lister group.
|
|
276
|
+
***************/
|
|
190
277
|
ignore(evt, callback) {
|
|
191
278
|
return this.events.removeListener(evt, callback);
|
|
192
279
|
}
|
|
193
280
|
|
|
194
|
-
|
|
195
|
-
load
|
|
196
|
-
|
|
281
|
+
/**************
|
|
282
|
+
func: load
|
|
283
|
+
params:
|
|
284
|
+
-deva: The Deva model to load.
|
|
285
|
+
describe:
|
|
286
|
+
This function will enable fast loading of Deva into a system.
|
|
287
|
+
***************/
|
|
288
|
+
load(deva) {
|
|
289
|
+
this.devas[deva.key] = deva;
|
|
197
290
|
// inherit the data to the new deva.
|
|
198
291
|
this.inherit.forEach(inherit => {
|
|
199
|
-
this.devas[
|
|
292
|
+
this.devas[deva.key][inherit] = this[inherit];
|
|
200
293
|
});
|
|
201
|
-
|
|
202
294
|
return Promise.resolve();
|
|
203
295
|
}
|
|
204
296
|
|
|
205
|
-
// Used when unloading a deva dynamically from the set.
|
|
206
|
-
unload(agent) {
|
|
207
|
-
delete this.devas[agent];
|
|
208
|
-
return Promise.resolve();
|
|
209
|
-
}
|
|
210
297
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
298
|
+
/**************
|
|
299
|
+
func: unload
|
|
300
|
+
params:
|
|
301
|
+
- deva: The deva key to unload
|
|
302
|
+
describe: Unload a currently loaded Deva.
|
|
303
|
+
***************/
|
|
304
|
+
unload(deva) {
|
|
305
|
+
delete this.devas[deva];
|
|
306
|
+
return Promise.resolve(`unload:${deva} `);
|
|
307
|
+
}
|
|
217
308
|
|
|
309
|
+
/**************
|
|
310
|
+
func: ask
|
|
311
|
+
params: packet
|
|
312
|
+
describe:
|
|
313
|
+
The ask function gives each agent the ability to ask question to other agents
|
|
314
|
+
in the system. When a question is asked the Agent with the question if it
|
|
315
|
+
detect an ask event it will trigger. Then if an Agent with the matching ask
|
|
316
|
+
event is listening they will respond. The question function uses this to
|
|
317
|
+
create integrated communication between itself and other Deva in it's library.
|
|
318
|
+
|
|
319
|
+
It can also be used in a custom manner to broadcast ask events inside other coe aswell.
|
|
320
|
+
|
|
321
|
+
When the talk has an answer it will respond with a talk event that has the packet id
|
|
322
|
+
so the event is specific to the talk.
|
|
323
|
+
***************/
|
|
218
324
|
ask(packet) {
|
|
219
325
|
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
220
326
|
|
|
221
|
-
this.
|
|
327
|
+
this.state('ask');
|
|
328
|
+
|
|
222
329
|
packet.a = {
|
|
223
330
|
agent: this.agent || false,
|
|
224
331
|
client: this.client || false,
|
|
@@ -252,38 +359,43 @@ class Deva {
|
|
|
252
359
|
else {
|
|
253
360
|
packet.a.text = result;
|
|
254
361
|
}
|
|
255
|
-
// talk back to the once event with the ask key.
|
|
256
362
|
this.talk(`${this.agent.key}:ask:${packet.id}`, packet);
|
|
363
|
+
this.state('wait');
|
|
257
364
|
}).catch(err => {
|
|
258
|
-
this._state = this.states.error;
|
|
259
|
-
// If the ask method fails then a reject error is returned from the this.error
|
|
260
|
-
// interface.
|
|
261
365
|
this.talk(`${this.agent.key}:ask:${packet.id}`, {error:err.toString()});
|
|
262
366
|
return this.error(err, packet);
|
|
263
367
|
})
|
|
264
368
|
}
|
|
265
369
|
catch (e) {
|
|
266
|
-
this._state = this.states.error;
|
|
267
|
-
// if any error is caught in the processing of the ask then it returns and
|
|
268
|
-
// executes the this.error(*) interface.
|
|
269
370
|
this.talk(`${this.agent.key}:ask:${packet.id}`, {error:e.toString()});
|
|
270
371
|
return this.error(e, packet)
|
|
271
372
|
}
|
|
272
373
|
// now when we ask the meta params[0] should be the method
|
|
273
374
|
}
|
|
274
375
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
376
|
+
/**************
|
|
377
|
+
func: question
|
|
378
|
+
example: this.question('#*agent.key *method* *text*')
|
|
379
|
+
example: this.question('#*agent.key* *method* *properties*', {*data*})
|
|
380
|
+
params:
|
|
381
|
+
= TEXT: The text string is the question to process in the current state.
|
|
382
|
+
- DATA: The data is a data array or object that also can be passed to the question.
|
|
383
|
+
describe:
|
|
384
|
+
***************/
|
|
281
385
|
question(TEXT=false, DATA=false) {
|
|
282
|
-
this.
|
|
283
|
-
|
|
386
|
+
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
387
|
+
|
|
388
|
+
this.state('question'); // set the state to question.
|
|
389
|
+
|
|
390
|
+
const id = this.uid(); // generate a unique transport id for the question.
|
|
284
391
|
const t_split = TEXT.split(' ');
|
|
392
|
+
|
|
393
|
+
// check to see if the string is an #ask string to talk to the other Deva.
|
|
285
394
|
const isAsk = t_split[0].startsWith(this.askChr) ? t_split[0].substring(1) : false;
|
|
395
|
+
|
|
396
|
+
// check to see if the string is a command string to run a local method.
|
|
286
397
|
const isCmd = t_split[0].startsWith(this.cmdChr) ? t_split[0].substring(1) : false;
|
|
398
|
+
|
|
287
399
|
// Format the packet for return on the request.
|
|
288
400
|
const orig = TEXT;
|
|
289
401
|
const data = DATA;
|
|
@@ -336,11 +448,11 @@ class Deva {
|
|
|
336
448
|
created: Date.now(),
|
|
337
449
|
}
|
|
338
450
|
|
|
339
|
-
//
|
|
340
|
-
|
|
341
|
-
|
|
451
|
+
// hash the packet and insert the hash into the packet meta object.
|
|
452
|
+
packet.q.meta.hash = this.hash(JSON.stringify(packet.q));
|
|
453
|
+
|
|
454
|
+
// If a question to another Deva with '#' then trigger events
|
|
342
455
|
if (isAsk) {
|
|
343
|
-
this._state = this.states.ask;
|
|
344
456
|
this.talk(`${isAsk}:ask`, packet);
|
|
345
457
|
this.once(`${isAsk}:ask:${packet.id}`, answer => {
|
|
346
458
|
return resolve(answer);
|
|
@@ -350,6 +462,9 @@ class Deva {
|
|
|
350
462
|
else {
|
|
351
463
|
if (typeof this.methods[method] !== 'function') return resolve(this._methodNotFound(packet));
|
|
352
464
|
this.methods[method](packet).then(result => {
|
|
465
|
+
|
|
466
|
+
this.state('answer');
|
|
467
|
+
|
|
353
468
|
const text = typeof result === 'object' ? result.text : result;
|
|
354
469
|
const html = typeof result === 'object' ? result.html : result;
|
|
355
470
|
const data = typeof result === 'object' ? result.data : false;
|
|
@@ -365,7 +480,13 @@ class Deva {
|
|
|
365
480
|
data,
|
|
366
481
|
created: Date.now(),
|
|
367
482
|
};
|
|
368
|
-
|
|
483
|
+
// create a hash for the answer and insert into answer meta.
|
|
484
|
+
packet.a.meta.hash = this.hash(JSON.stringify(packet.a));
|
|
485
|
+
|
|
486
|
+
// create a hash for entire packet and insert into packet
|
|
487
|
+
packet.hash = this.hash(JSON.stringify(packet));
|
|
488
|
+
|
|
489
|
+
this.state('wait');
|
|
369
490
|
return resolve(packet);
|
|
370
491
|
}).catch(err => {
|
|
371
492
|
return this.error(err, packet);
|
|
@@ -378,15 +499,23 @@ class Deva {
|
|
|
378
499
|
});
|
|
379
500
|
}
|
|
380
501
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
502
|
+
/**************
|
|
503
|
+
func: init
|
|
504
|
+
params: none
|
|
505
|
+
describe:
|
|
506
|
+
The main init interface where the chain begins. Where the states fire for
|
|
507
|
+
each process of setting:
|
|
508
|
+
1. Set the Max listeners to control event memory buffer.
|
|
509
|
+
2. Assign the Interited Properties
|
|
510
|
+
3. Assign binding functions and methods to 'this' scoe.
|
|
511
|
+
4. Assign any listeners for additional functionality.
|
|
512
|
+
5. run the onInit custom function if preset or the system start function.
|
|
513
|
+
6. The system start function will create a chain reaction of states that load.
|
|
514
|
+
7. If there is an error the init function rejects the call.
|
|
515
|
+
***************/
|
|
387
516
|
init() {
|
|
517
|
+
this.active = Date.now();
|
|
388
518
|
// set client
|
|
389
|
-
this._state = this.states.init;
|
|
390
519
|
return new Promise((resolve, reject) => {
|
|
391
520
|
this.events.setMaxListeners(this.maxListeners);
|
|
392
521
|
this._assignInherit().then(() => {
|
|
@@ -394,7 +523,8 @@ class Deva {
|
|
|
394
523
|
}).then(() => {
|
|
395
524
|
return this._assignListeners();
|
|
396
525
|
}).then(() => {
|
|
397
|
-
|
|
526
|
+
this.state('init');
|
|
527
|
+
return this.onInit && typeof this.onInit === 'function' ? this.onInit() : this.start();
|
|
398
528
|
}).then(started => {
|
|
399
529
|
return resolve(started)
|
|
400
530
|
}).catch(err => {
|
|
@@ -408,100 +538,144 @@ class Deva {
|
|
|
408
538
|
// e: is the error to pass into the interface.
|
|
409
539
|
// packet: the packet that caused the error.
|
|
410
540
|
error(err,packet=false,reject=false) {
|
|
411
|
-
this.
|
|
412
|
-
|
|
413
|
-
this.talk('error', {
|
|
414
|
-
id: this.uid(),
|
|
415
|
-
agent: this.agent,
|
|
416
|
-
client: this.client,
|
|
417
|
-
error: err.toString('utf8'),
|
|
418
|
-
data: packet,
|
|
419
|
-
created: Date.now(),
|
|
420
|
-
});
|
|
421
|
-
// call the onError if there is a logcal one.
|
|
422
|
-
// if there is no local error return a promise reject.
|
|
541
|
+
this.state('error');
|
|
542
|
+
console.error(err)
|
|
423
543
|
if (this.onError) return this.onError(err, packet, reject);
|
|
424
544
|
return reject ? reject(err) : false;
|
|
425
545
|
}
|
|
426
546
|
|
|
427
|
-
|
|
547
|
+
/**************
|
|
548
|
+
func: start
|
|
549
|
+
params: none
|
|
550
|
+
describe:
|
|
551
|
+
The start function begins the process by setting the state to start setting
|
|
552
|
+
the active to the current datetime and then checking for a custom onStart
|
|
553
|
+
function or running the system enter function.
|
|
554
|
+
***************/
|
|
428
555
|
start() {
|
|
429
|
-
if (this.active) return;
|
|
430
|
-
this.
|
|
431
|
-
this.
|
|
432
|
-
return this.onStart ? this.onStart() : this.enter();
|
|
556
|
+
if (!this.active) return;
|
|
557
|
+
this.state('start');
|
|
558
|
+
return this.onStart && typeof this.onStart === 'function' ? this.onStart() : this.enter();
|
|
433
559
|
}
|
|
434
560
|
|
|
435
|
-
|
|
561
|
+
/**************
|
|
562
|
+
func: stop
|
|
563
|
+
params: none
|
|
564
|
+
describe:
|
|
565
|
+
The stop function will stop the Deva by setting the active status to false,
|
|
566
|
+
and the state to stop. From here it will check for a custom onStop function
|
|
567
|
+
for anything to run, or run the system exit function.
|
|
568
|
+
|
|
569
|
+
If the deva is offline it will return the offline message.
|
|
570
|
+
***************/
|
|
436
571
|
stop() {
|
|
437
572
|
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
573
|
+
this.state('stop');
|
|
438
574
|
this.active = false;
|
|
439
|
-
this.
|
|
440
|
-
return this.onStop ? this.onStop() : this.exit();
|
|
575
|
+
return this.onStop && typeof this.onStop === 'function' ? this.onStop() : this.exit();
|
|
441
576
|
}
|
|
442
577
|
|
|
443
|
-
|
|
578
|
+
/**************
|
|
579
|
+
func: enter
|
|
580
|
+
params: none
|
|
581
|
+
describe:
|
|
582
|
+
The ener function will check the actie status of the Deva and set it to
|
|
583
|
+
offline or enter.
|
|
584
|
+
|
|
585
|
+
If the Deva is offline it will return the offline message.
|
|
586
|
+
***************/
|
|
444
587
|
enter() {
|
|
445
588
|
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
446
|
-
this.
|
|
447
|
-
return this.onEnter ? this.onEnter() : this.done(this.state)
|
|
589
|
+
this.state('enter');
|
|
590
|
+
return this.onEnter && typeof this.onEnter === 'function' ? this.onEnter() : this.done(this.state)
|
|
448
591
|
}
|
|
449
592
|
|
|
450
|
-
|
|
593
|
+
/**************
|
|
594
|
+
func: exit
|
|
595
|
+
params: none
|
|
596
|
+
describe:
|
|
597
|
+
The exit state function is triggered when the Deva is exiting it's online
|
|
598
|
+
status and setting the state to exit for things like security check.
|
|
599
|
+
|
|
600
|
+
The return will check for a custom onExit function or run the system done
|
|
601
|
+
function.
|
|
602
|
+
|
|
603
|
+
If the deva is offline it will return the offline message.
|
|
604
|
+
***************/
|
|
451
605
|
exit() {
|
|
452
606
|
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
453
|
-
this.
|
|
454
|
-
return this.onExit ? this.onExit() : this.done(this.state)
|
|
607
|
+
this.state('exit');
|
|
608
|
+
return this.onExit && typeof this.onExit === 'function' ? this.onExit() : this.done(this.state)
|
|
455
609
|
}
|
|
456
610
|
|
|
457
|
-
|
|
611
|
+
/**************
|
|
612
|
+
func: done
|
|
613
|
+
params:
|
|
614
|
+
- msg: The done message
|
|
615
|
+
describe:
|
|
616
|
+
When the done function is triggered the system will also set the state
|
|
617
|
+
of hte Deva to done.
|
|
618
|
+
|
|
619
|
+
If the deva is offline it will return the offline message.
|
|
620
|
+
***************/
|
|
458
621
|
done(msg=false) {
|
|
459
622
|
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
460
|
-
this.
|
|
461
|
-
msg = msg ? msg : this.
|
|
462
|
-
return this.onDone ? this.onDone() : Promise.resolve({msg,agent:this.agent})
|
|
623
|
+
this.state('done');
|
|
624
|
+
msg = msg ? msg : this._state;
|
|
625
|
+
return this.onDone && typeof this.onDone === 'function' ? this.onDone() : Promise.resolve({msg,agent:this.agent})
|
|
463
626
|
}
|
|
464
627
|
|
|
465
|
-
|
|
466
|
-
status
|
|
628
|
+
/**************
|
|
629
|
+
func: status
|
|
630
|
+
params:
|
|
631
|
+
- addto: The addto is any additonal string to append to the end of hte call.
|
|
632
|
+
describe:
|
|
633
|
+
The status function provides an easy way to get the current status of a Deva
|
|
634
|
+
and append custom status messages that may pertain to any custom status call.
|
|
635
|
+
|
|
636
|
+
If the deva is offline it will return the offline message.
|
|
637
|
+
***************/
|
|
638
|
+
status(addto=false) {
|
|
467
639
|
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
468
640
|
const id = this.uid();
|
|
469
641
|
const dateFormat = new Intl.DateTimeFormat('en-US', { dateStyle: 'medium', timeStyle: 'medium' }).format(this.active);
|
|
470
642
|
let text = `${this.agent.name} is ONLINE since ${dateFormat}`;
|
|
471
|
-
if (
|
|
643
|
+
if (addto) text = text + `\n${addto}`;
|
|
472
644
|
return Promise.resolve({text});
|
|
473
645
|
}
|
|
474
646
|
|
|
475
|
-
|
|
647
|
+
/**************
|
|
648
|
+
func: prompt
|
|
649
|
+
params:
|
|
650
|
+
- text: The text string to send to the prompt.
|
|
651
|
+
describe:-
|
|
652
|
+
The prompt function is used to broadcasat a global prompt event with a string. Thsi is handy when passing events between a cli and user interface for example.
|
|
653
|
+
***************/
|
|
476
654
|
prompt(text) {
|
|
477
|
-
this.talk('prompt', {text, agent:this.agent});
|
|
655
|
+
return this.talk('prompt', {text, agent:this.agent});
|
|
478
656
|
}
|
|
479
657
|
|
|
480
|
-
|
|
481
|
-
hash
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
case 'add':
|
|
494
|
-
this.vars.hash = `${this.vars.hash}${params[1]}`;
|
|
495
|
-
break;
|
|
496
|
-
}
|
|
497
|
-
return resolve({
|
|
498
|
-
text:this.vars.hash,
|
|
499
|
-
html:`<div class="hash">${this.vars.hash}</div>`
|
|
500
|
-
});
|
|
501
|
-
});
|
|
658
|
+
/**************
|
|
659
|
+
func: hash
|
|
660
|
+
params:
|
|
661
|
+
- texts: The text string to create a hash value for.
|
|
662
|
+
- algo: The hashing algorithm to use for hashing. md5, sha256, or sha512
|
|
663
|
+
|
|
664
|
+
describe:
|
|
665
|
+
The hash algorithm will take a string of text and produce a hash.
|
|
666
|
+
***************/
|
|
667
|
+
hash(text, algo='md5') {
|
|
668
|
+
const the_hash = createHash(algo);
|
|
669
|
+
the_hash.update(text);
|
|
670
|
+
return the_hash.digest('hex');
|
|
502
671
|
}
|
|
503
|
-
|
|
504
|
-
|
|
672
|
+
|
|
673
|
+
/**************
|
|
674
|
+
func: startDevas
|
|
675
|
+
params: none
|
|
676
|
+
describe:
|
|
677
|
+
Start Devas will initialize the Deva agents inside this curent Deva.
|
|
678
|
+
***************/
|
|
505
679
|
startDevas() {
|
|
506
680
|
return new Promise((resolve, reject) => {
|
|
507
681
|
const devas = [];
|
|
@@ -513,6 +687,12 @@ class Deva {
|
|
|
513
687
|
}).catch(reject);
|
|
514
688
|
});
|
|
515
689
|
}
|
|
690
|
+
/**************
|
|
691
|
+
func: stpDevas
|
|
692
|
+
params: none
|
|
693
|
+
describe:
|
|
694
|
+
stopDevas will stop all the devas running in the current Deva.
|
|
695
|
+
***************/
|
|
516
696
|
stopDevas() {
|
|
517
697
|
return new Promise((resolve, reject) => {
|
|
518
698
|
const devas = [];
|