graphai 1.0.12 → 1.0.14
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/lib/bundle.cjs.js +1 -1
- package/lib/bundle.cjs.js.map +1 -1
- package/lib/bundle.esm.js +145 -132
- package/lib/bundle.esm.js.map +1 -1
- package/lib/bundle.umd.js +1 -1
- package/lib/bundle.umd.js.map +1 -1
- package/lib/graphai.d.ts +2 -1
- package/lib/graphai.js +13 -7
- package/lib/type.d.ts +1 -0
- package/lib/utils/nodeUtils.js +1 -0
- package/lib/utils/result.js +2 -1
- package/lib/utils/utils.d.ts +2 -1
- package/lib/utils/utils.js +13 -7
- package/package.json +2 -2
package/lib/bundle.esm.js
CHANGED
|
@@ -61,10 +61,127 @@ const GraphAILogger = {
|
|
|
61
61
|
error,
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
+
const propFunctionRegex = /^[a-zA-Z]+\([^)]*\)$/;
|
|
65
|
+
const propArrayFunction = (result, propId) => {
|
|
66
|
+
if (Array.isArray(result)) {
|
|
67
|
+
if (propId === "length()") {
|
|
68
|
+
return result.length;
|
|
69
|
+
}
|
|
70
|
+
if (propId === "flat()") {
|
|
71
|
+
return result.flat();
|
|
72
|
+
}
|
|
73
|
+
if (propId === "toJSON()") {
|
|
74
|
+
return JSON.stringify(result, null, 2);
|
|
75
|
+
}
|
|
76
|
+
if (propId === "isEmpty()") {
|
|
77
|
+
return result.length === 0;
|
|
78
|
+
}
|
|
79
|
+
// array join
|
|
80
|
+
const matchJoin = propId.match(/^join\(([,-\s]?)\)$/);
|
|
81
|
+
if (matchJoin && Array.isArray(matchJoin)) {
|
|
82
|
+
return result.join(matchJoin[1] ?? "");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
};
|
|
87
|
+
const propObjectFunction = (result, propId) => {
|
|
88
|
+
if (isObject(result)) {
|
|
89
|
+
if (propId === "keys()") {
|
|
90
|
+
return Object.keys(result);
|
|
91
|
+
}
|
|
92
|
+
if (propId === "values()") {
|
|
93
|
+
return Object.values(result);
|
|
94
|
+
}
|
|
95
|
+
if (propId === "toJSON()") {
|
|
96
|
+
return JSON.stringify(result, null, 2);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
};
|
|
101
|
+
const propStringFunction = (result, propId) => {
|
|
102
|
+
if (typeof result === "string") {
|
|
103
|
+
if (propId === "codeBlock()") {
|
|
104
|
+
const match = ("\n" + result).match(/\n```[a-zA-z]*([\s\S]*?)\n```/);
|
|
105
|
+
if (match) {
|
|
106
|
+
return match[1];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (propId === "jsonParse()") {
|
|
110
|
+
return JSON.parse(result);
|
|
111
|
+
}
|
|
112
|
+
if (propId === "toNumber()") {
|
|
113
|
+
const ret = Number(result);
|
|
114
|
+
if (!isNaN(ret)) {
|
|
115
|
+
return ret;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (propId === "trim()") {
|
|
119
|
+
return result.trim();
|
|
120
|
+
}
|
|
121
|
+
if (propId === "toLowerCase()") {
|
|
122
|
+
return result.toLowerCase();
|
|
123
|
+
}
|
|
124
|
+
if (propId === "toUpperCase()") {
|
|
125
|
+
return result.toUpperCase();
|
|
126
|
+
}
|
|
127
|
+
const sliceMatch = propId.match(/^slice\((-?\d+)(?:,\s*(-?\d+))?\)/);
|
|
128
|
+
if (sliceMatch) {
|
|
129
|
+
if (sliceMatch[2] !== undefined) {
|
|
130
|
+
return result.slice(Number(sliceMatch[1]), Number(sliceMatch[2]));
|
|
131
|
+
}
|
|
132
|
+
if (sliceMatch[1] !== undefined) {
|
|
133
|
+
return result.slice(Number(sliceMatch[1]));
|
|
134
|
+
}
|
|
135
|
+
GraphAILogger.warn("slice is not valid format: " + sliceMatch);
|
|
136
|
+
}
|
|
137
|
+
const splitMatch = propId.match(/^split\(([-_:;.,\s\n]+)\)$/);
|
|
138
|
+
if (splitMatch) {
|
|
139
|
+
return result.split(splitMatch[1]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
};
|
|
144
|
+
const propNumberFunction = (result, propId) => {
|
|
145
|
+
if (result !== undefined && Number.isFinite(result)) {
|
|
146
|
+
if (propId === "toString()") {
|
|
147
|
+
return String(result);
|
|
148
|
+
}
|
|
149
|
+
const regex = /^add\((-?\d+)\)$/;
|
|
150
|
+
const match = propId.match(regex);
|
|
151
|
+
if (match) {
|
|
152
|
+
return Number(result) + Number(match[1]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return undefined;
|
|
156
|
+
};
|
|
157
|
+
const propBooleanFunction = (result, propId) => {
|
|
158
|
+
if (typeof result === "boolean") {
|
|
159
|
+
if (propId === "not()") {
|
|
160
|
+
return !result;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
};
|
|
165
|
+
const propFunctions = [propArrayFunction, propObjectFunction, propStringFunction, propNumberFunction, propBooleanFunction];
|
|
166
|
+
const utilsFunctions = (input, nodes) => {
|
|
167
|
+
if (input === "@now" || input === "@now_ms") {
|
|
168
|
+
return Date.now();
|
|
169
|
+
}
|
|
170
|
+
if (input === "@now_s") {
|
|
171
|
+
return Math.floor(Date.now() / 1000);
|
|
172
|
+
}
|
|
173
|
+
if (input === "@loop") {
|
|
174
|
+
return nodes[loopCounterKey].result;
|
|
175
|
+
}
|
|
176
|
+
// If a placeholder does not match any key, replace it with an empty string.
|
|
177
|
+
GraphAILogger.warn("not match template utility function: ${" + input + "}");
|
|
178
|
+
return "";
|
|
179
|
+
};
|
|
180
|
+
|
|
64
181
|
const sleep = async (milliseconds) => {
|
|
65
182
|
return await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
66
183
|
};
|
|
67
|
-
const parseNodeName = (inputNodeId, isSelfNode = false) => {
|
|
184
|
+
const parseNodeName = (inputNodeId, isSelfNode = false, nodes) => {
|
|
68
185
|
if (isSelfNode) {
|
|
69
186
|
if (typeof inputNodeId === "string" && inputNodeId[0] === ".") {
|
|
70
187
|
const parts = inputNodeId.split(".");
|
|
@@ -75,14 +192,19 @@ const parseNodeName = (inputNodeId, isSelfNode = false) => {
|
|
|
75
192
|
if (typeof inputNodeId === "string") {
|
|
76
193
|
const regex = /^:(.*)$/;
|
|
77
194
|
const match = inputNodeId.match(regex);
|
|
78
|
-
if (
|
|
79
|
-
|
|
195
|
+
if (match) {
|
|
196
|
+
const parts = match[1].split(/(?<!\()\.(?!\))/);
|
|
197
|
+
if (parts.length == 1) {
|
|
198
|
+
return { nodeId: parts[0] };
|
|
199
|
+
}
|
|
200
|
+
return { nodeId: parts[0], propIds: parts.slice(1) };
|
|
80
201
|
}
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
202
|
+
const regexUtil = /^@(.*)$/;
|
|
203
|
+
const matchUtil = inputNodeId.match(regexUtil);
|
|
204
|
+
// Only when just called from resultsOfInner
|
|
205
|
+
if (nodes && matchUtil) {
|
|
206
|
+
return { value: utilsFunctions(inputNodeId, nodes) };
|
|
84
207
|
}
|
|
85
|
-
return { nodeId: parts[0], propIds: parts.slice(1) };
|
|
86
208
|
}
|
|
87
209
|
return { value: inputNodeId }; // non-string literal
|
|
88
210
|
};
|
|
@@ -207,6 +329,7 @@ const inputs2dataSources = (inputs) => {
|
|
|
207
329
|
}
|
|
208
330
|
return parseNodeName(inputs);
|
|
209
331
|
};
|
|
332
|
+
// TODO: Maybe it's a remnant of old array inputs. Check and delete.
|
|
210
333
|
const dataSourceNodeIds = (sources) => {
|
|
211
334
|
if (!Array.isArray(sources)) {
|
|
212
335
|
throw new Error("sources must be array!! maybe inputs is invalid");
|
|
@@ -278,123 +401,6 @@ class TransactionLog {
|
|
|
278
401
|
}
|
|
279
402
|
}
|
|
280
403
|
|
|
281
|
-
const propFunctionRegex = /^[a-zA-Z]+\([^)]*\)$/;
|
|
282
|
-
const propArrayFunction = (result, propId) => {
|
|
283
|
-
if (Array.isArray(result)) {
|
|
284
|
-
if (propId === "length()") {
|
|
285
|
-
return result.length;
|
|
286
|
-
}
|
|
287
|
-
if (propId === "flat()") {
|
|
288
|
-
return result.flat();
|
|
289
|
-
}
|
|
290
|
-
if (propId === "toJSON()") {
|
|
291
|
-
return JSON.stringify(result, null, 2);
|
|
292
|
-
}
|
|
293
|
-
if (propId === "isEmpty()") {
|
|
294
|
-
return result.length === 0;
|
|
295
|
-
}
|
|
296
|
-
// array join
|
|
297
|
-
const matchJoin = propId.match(/^join\(([,-\s]?)\)$/);
|
|
298
|
-
if (matchJoin && Array.isArray(matchJoin)) {
|
|
299
|
-
return result.join(matchJoin[1] ?? "");
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
return undefined;
|
|
303
|
-
};
|
|
304
|
-
const propObjectFunction = (result, propId) => {
|
|
305
|
-
if (isObject(result)) {
|
|
306
|
-
if (propId === "keys()") {
|
|
307
|
-
return Object.keys(result);
|
|
308
|
-
}
|
|
309
|
-
if (propId === "values()") {
|
|
310
|
-
return Object.values(result);
|
|
311
|
-
}
|
|
312
|
-
if (propId === "toJSON()") {
|
|
313
|
-
return JSON.stringify(result, null, 2);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return undefined;
|
|
317
|
-
};
|
|
318
|
-
const propStringFunction = (result, propId) => {
|
|
319
|
-
if (typeof result === "string") {
|
|
320
|
-
if (propId === "codeBlock()") {
|
|
321
|
-
const match = ("\n" + result).match(/\n```[a-zA-z]*([\s\S]*?)\n```/);
|
|
322
|
-
if (match) {
|
|
323
|
-
return match[1];
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
if (propId === "jsonParse()") {
|
|
327
|
-
return JSON.parse(result);
|
|
328
|
-
}
|
|
329
|
-
if (propId === "toNumber()") {
|
|
330
|
-
const ret = Number(result);
|
|
331
|
-
if (!isNaN(ret)) {
|
|
332
|
-
return ret;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
if (propId === "trim()") {
|
|
336
|
-
return result.trim();
|
|
337
|
-
}
|
|
338
|
-
if (propId === "toLowerCase()") {
|
|
339
|
-
return result.toLowerCase();
|
|
340
|
-
}
|
|
341
|
-
if (propId === "toUpperCase()") {
|
|
342
|
-
return result.toUpperCase();
|
|
343
|
-
}
|
|
344
|
-
const sliceMatch = propId.match(/^slice\((-?\d+)(?:,\s*(-?\d+))?\)/);
|
|
345
|
-
if (sliceMatch) {
|
|
346
|
-
if (sliceMatch[2] !== undefined) {
|
|
347
|
-
return result.slice(Number(sliceMatch[1]), Number(sliceMatch[2]));
|
|
348
|
-
}
|
|
349
|
-
if (sliceMatch[1] !== undefined) {
|
|
350
|
-
return result.slice(Number(sliceMatch[1]));
|
|
351
|
-
}
|
|
352
|
-
GraphAILogger.warn("slice is not valid format: " + sliceMatch);
|
|
353
|
-
}
|
|
354
|
-
const splitMatch = propId.match(/^split\(([-_:;.,\s\n]+)\)$/);
|
|
355
|
-
if (splitMatch) {
|
|
356
|
-
return result.split(splitMatch[1]);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
return undefined;
|
|
360
|
-
};
|
|
361
|
-
const propNumberFunction = (result, propId) => {
|
|
362
|
-
if (result !== undefined && Number.isFinite(result)) {
|
|
363
|
-
if (propId === "toString()") {
|
|
364
|
-
return String(result);
|
|
365
|
-
}
|
|
366
|
-
const regex = /^add\((-?\d+)\)$/;
|
|
367
|
-
const match = propId.match(regex);
|
|
368
|
-
if (match) {
|
|
369
|
-
return Number(result) + Number(match[1]);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
return undefined;
|
|
373
|
-
};
|
|
374
|
-
const propBooleanFunction = (result, propId) => {
|
|
375
|
-
if (typeof result === "boolean") {
|
|
376
|
-
if (propId === "not()") {
|
|
377
|
-
return !result;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
return undefined;
|
|
381
|
-
};
|
|
382
|
-
const propFunctions = [propArrayFunction, propObjectFunction, propStringFunction, propNumberFunction, propBooleanFunction];
|
|
383
|
-
const utilsFunctions = (input, nodes) => {
|
|
384
|
-
if (input === "@now" || input === "@now_ms") {
|
|
385
|
-
return Date.now();
|
|
386
|
-
}
|
|
387
|
-
if (input === "@now_s") {
|
|
388
|
-
return Math.floor(Date.now() / 1000);
|
|
389
|
-
}
|
|
390
|
-
if (input === "@loop") {
|
|
391
|
-
return nodes[loopCounterKey].result;
|
|
392
|
-
}
|
|
393
|
-
// If a placeholder does not match any key, replace it with an empty string.
|
|
394
|
-
GraphAILogger.warn("not match template utility function: ${" + input + "}");
|
|
395
|
-
return "";
|
|
396
|
-
};
|
|
397
|
-
|
|
398
404
|
const getNestedData = (result, propId, propFunctions) => {
|
|
399
405
|
const match = propId.match(propFunctionRegex);
|
|
400
406
|
if (match) {
|
|
@@ -476,7 +482,8 @@ const resultsOfInner = (input, nodes, propFunctions, isSelfNode = false) => {
|
|
|
476
482
|
return replaceTemplatePlaceholders(input, templateMatch, nodes, propFunctions, isSelfNode);
|
|
477
483
|
}
|
|
478
484
|
}
|
|
479
|
-
|
|
485
|
+
// :node.prod
|
|
486
|
+
return resultOf(parseNodeName(input, isSelfNode, nodes), nodes, propFunctions);
|
|
480
487
|
};
|
|
481
488
|
const resultsOf = (inputs, nodes, propFunctions, isSelfNode = false) => {
|
|
482
489
|
return Object.keys(inputs).reduce((tmp, key) => {
|
|
@@ -1296,6 +1303,7 @@ class GraphAI {
|
|
|
1296
1303
|
bypassAgentIds: [],
|
|
1297
1304
|
config: {},
|
|
1298
1305
|
graphLoader: undefined,
|
|
1306
|
+
forceLoop: false,
|
|
1299
1307
|
}) {
|
|
1300
1308
|
this.logs = [];
|
|
1301
1309
|
this.config = {};
|
|
@@ -1318,6 +1326,7 @@ class GraphAI {
|
|
|
1318
1326
|
this.bypassAgentIds = options.bypassAgentIds ?? [];
|
|
1319
1327
|
this.config = options.config;
|
|
1320
1328
|
this.graphLoader = options.graphLoader;
|
|
1329
|
+
this.forceLoop = options.forceLoop ?? false;
|
|
1321
1330
|
this.loop = graphData.loop;
|
|
1322
1331
|
this.verbose = graphData.verbose === true;
|
|
1323
1332
|
this.onComplete = (__isAbort) => {
|
|
@@ -1358,9 +1367,9 @@ class GraphAI {
|
|
|
1358
1367
|
.join("\n");
|
|
1359
1368
|
}
|
|
1360
1369
|
// Public API
|
|
1361
|
-
results(all) {
|
|
1370
|
+
results(all, internalUse = false) {
|
|
1362
1371
|
return Object.keys(this.nodes)
|
|
1363
|
-
.filter((nodeId) => (all && nodeId !== loopCounterKey) || this.nodes[nodeId].isResult)
|
|
1372
|
+
.filter((nodeId) => (all && (internalUse || nodeId !== loopCounterKey)) || this.nodes[nodeId].isResult)
|
|
1364
1373
|
.reduce((results, nodeId) => {
|
|
1365
1374
|
const node = this.nodes[nodeId];
|
|
1366
1375
|
if (node.result !== undefined) {
|
|
@@ -1426,9 +1435,9 @@ class GraphAI {
|
|
|
1426
1435
|
return new Promise((resolve, reject) => {
|
|
1427
1436
|
this.onComplete = (isAbort = false) => {
|
|
1428
1437
|
const errors = this.errors();
|
|
1429
|
-
const
|
|
1430
|
-
if (
|
|
1431
|
-
reject(errors[
|
|
1438
|
+
const errorNodeIds = Object.keys(errors);
|
|
1439
|
+
if (errorNodeIds.length > 0 || isAbort) {
|
|
1440
|
+
reject(errors[errorNodeIds[0]]);
|
|
1432
1441
|
}
|
|
1433
1442
|
else {
|
|
1434
1443
|
resolve(this.results(all));
|
|
@@ -1469,18 +1478,22 @@ class GraphAI {
|
|
|
1469
1478
|
// Check if there is any running computed nodes.
|
|
1470
1479
|
// In case of no running computed note, start the another iteration if ncessary (loop)
|
|
1471
1480
|
processLoopIfNecessary() {
|
|
1481
|
+
//
|
|
1482
|
+
if (!this.forceLoop && Object.keys(this.errors()).length > 0) {
|
|
1483
|
+
return false;
|
|
1484
|
+
}
|
|
1472
1485
|
this.repeatCount++;
|
|
1473
1486
|
const loop = this.loop;
|
|
1474
1487
|
if (!loop) {
|
|
1475
1488
|
return false;
|
|
1476
1489
|
}
|
|
1477
1490
|
// We need to update static nodes, before checking the condition
|
|
1478
|
-
const previousResults = this.results(true); // results from previous loop
|
|
1491
|
+
const previousResults = this.results(true, true); // results from previous loop
|
|
1479
1492
|
this.updateStaticNodes(previousResults);
|
|
1480
1493
|
if (loop.count === undefined || this.repeatCount < loop.count) {
|
|
1481
1494
|
if (loop.while) {
|
|
1482
1495
|
const source = parseNodeName(loop.while);
|
|
1483
|
-
const value = this.getValueFromResults(source, this.results(true));
|
|
1496
|
+
const value = this.getValueFromResults(source, this.results(true, true));
|
|
1484
1497
|
// NOTE: We treat an empty array as false.
|
|
1485
1498
|
if (!isLogicallyTrue(value)) {
|
|
1486
1499
|
return false; // while condition is not met
|