graphai 0.6.3 → 0.6.5
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 +247 -257
- 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 +3 -3
- package/lib/graphai.js +8 -5
- package/lib/node.d.ts +6 -4
- package/lib/node.js +30 -44
- package/lib/type.d.ts +12 -4
- package/lib/utils/prop_function.js +1 -1
- package/lib/utils/result.d.ts +1 -1
- package/lib/utils/result.js +7 -14
- package/lib/utils/utils.d.ts +1 -1
- package/lib/utils/utils.js +8 -1
- package/lib/validator.js +1 -1
- package/lib/validators/common.js +2 -0
- package/lib/validators/nodeValidator.js +3 -3
- package/package.json +1 -1
package/lib/bundle.esm.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
const sleep = async (milliseconds) => {
|
|
2
2
|
return await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
3
3
|
};
|
|
4
|
-
const parseNodeName = (inputNodeId) => {
|
|
4
|
+
const parseNodeName = (inputNodeId, isSelfNode = false) => {
|
|
5
|
+
if (isSelfNode) {
|
|
6
|
+
if (typeof inputNodeId === "string" && inputNodeId[0] === ".") {
|
|
7
|
+
const parts = inputNodeId.split(".");
|
|
8
|
+
return { nodeId: "self", propIds: parts.slice(1) };
|
|
9
|
+
}
|
|
10
|
+
return { value: inputNodeId };
|
|
11
|
+
}
|
|
5
12
|
if (typeof inputNodeId === "string") {
|
|
6
13
|
const regex = /^:(.*)$/;
|
|
7
14
|
const match = inputNodeId.match(regex);
|
|
@@ -209,6 +216,202 @@ class TransactionLog {
|
|
|
209
216
|
}
|
|
210
217
|
}
|
|
211
218
|
|
|
219
|
+
const propFunctionRegex = /^[a-zA-Z]+\([^)]*\)$/;
|
|
220
|
+
const propArrayFunction = (result, propId) => {
|
|
221
|
+
if (Array.isArray(result)) {
|
|
222
|
+
if (propId === "length()") {
|
|
223
|
+
return result.length;
|
|
224
|
+
}
|
|
225
|
+
if (propId === "flat()") {
|
|
226
|
+
return result.flat();
|
|
227
|
+
}
|
|
228
|
+
if (propId === "toJSON()") {
|
|
229
|
+
return JSON.stringify(result);
|
|
230
|
+
}
|
|
231
|
+
if (propId === "isEmpty()") {
|
|
232
|
+
return result.length === 0;
|
|
233
|
+
}
|
|
234
|
+
// array join
|
|
235
|
+
const matchJoin = propId.match(/^join\(([,-\s]?)\)$/);
|
|
236
|
+
if (matchJoin && Array.isArray(matchJoin)) {
|
|
237
|
+
return result.join(matchJoin[1] ?? "");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return undefined;
|
|
241
|
+
};
|
|
242
|
+
const propObjectFunction = (result, propId) => {
|
|
243
|
+
if (isObject(result)) {
|
|
244
|
+
if (propId === "keys()") {
|
|
245
|
+
return Object.keys(result);
|
|
246
|
+
}
|
|
247
|
+
if (propId === "values()") {
|
|
248
|
+
return Object.values(result);
|
|
249
|
+
}
|
|
250
|
+
if (propId === "toJSON()") {
|
|
251
|
+
return JSON.stringify(result);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return undefined;
|
|
255
|
+
};
|
|
256
|
+
const propStringFunction = (result, propId) => {
|
|
257
|
+
if (typeof result === "string") {
|
|
258
|
+
if (propId === "codeBlock()") {
|
|
259
|
+
const match = ("\n" + result).match(/\n```[a-zA-z]*([\s\S]*?)\n```/);
|
|
260
|
+
if (match) {
|
|
261
|
+
return match[1];
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (propId === "jsonParse()") {
|
|
265
|
+
return JSON.parse(result);
|
|
266
|
+
}
|
|
267
|
+
if (propId === "toNumber()") {
|
|
268
|
+
const ret = Number(result);
|
|
269
|
+
if (!isNaN(ret)) {
|
|
270
|
+
return ret;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (propId === "trim()") {
|
|
274
|
+
return result.trim();
|
|
275
|
+
}
|
|
276
|
+
if (propId === "toLowerCase()") {
|
|
277
|
+
return result.toLowerCase();
|
|
278
|
+
}
|
|
279
|
+
if (propId === "toUpperCase()") {
|
|
280
|
+
return result.toUpperCase();
|
|
281
|
+
}
|
|
282
|
+
// split()
|
|
283
|
+
}
|
|
284
|
+
return undefined;
|
|
285
|
+
};
|
|
286
|
+
const propNumberFunction = (result, propId) => {
|
|
287
|
+
if (result !== undefined && Number.isFinite(result)) {
|
|
288
|
+
if (propId === "toString()") {
|
|
289
|
+
return String(result);
|
|
290
|
+
}
|
|
291
|
+
const regex = /^add\((-?\d+)\)$/;
|
|
292
|
+
const match = propId.match(regex);
|
|
293
|
+
if (match) {
|
|
294
|
+
return Number(result) + Number(match[1]);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return undefined;
|
|
298
|
+
};
|
|
299
|
+
const propBooleanFunction = (result, propId) => {
|
|
300
|
+
if (typeof result === "boolean") {
|
|
301
|
+
if (propId === "not()") {
|
|
302
|
+
return !result;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return undefined;
|
|
306
|
+
};
|
|
307
|
+
const propFunctions = [propArrayFunction, propObjectFunction, propStringFunction, propNumberFunction, propBooleanFunction];
|
|
308
|
+
|
|
309
|
+
const getNestedData = (result, propId, propFunctions) => {
|
|
310
|
+
const match = propId.match(propFunctionRegex);
|
|
311
|
+
if (match) {
|
|
312
|
+
for (const propFunction of propFunctions) {
|
|
313
|
+
const ret = propFunction(result, propId);
|
|
314
|
+
if (!isNull(ret)) {
|
|
315
|
+
return ret;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// for array.
|
|
320
|
+
if (Array.isArray(result)) {
|
|
321
|
+
// $0, $1. array value.
|
|
322
|
+
const regex = /^\$(\d+)$/;
|
|
323
|
+
const match = propId.match(regex);
|
|
324
|
+
if (match) {
|
|
325
|
+
const index = parseInt(match[1], 10);
|
|
326
|
+
return result[index];
|
|
327
|
+
}
|
|
328
|
+
if (propId === "$last") {
|
|
329
|
+
return result[result.length - 1];
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
else if (isObject(result)) {
|
|
333
|
+
if (propId in result) {
|
|
334
|
+
return result[propId];
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return undefined;
|
|
338
|
+
};
|
|
339
|
+
const innerGetDataFromSource = (result, propIds, propFunctions) => {
|
|
340
|
+
if (!isNull(result) && propIds && propIds.length > 0) {
|
|
341
|
+
const propId = propIds[0];
|
|
342
|
+
const ret = getNestedData(result, propId, propFunctions);
|
|
343
|
+
if (ret === undefined) {
|
|
344
|
+
console.error(`prop: ${propIds.join(".")} is not hit`);
|
|
345
|
+
}
|
|
346
|
+
if (propIds.length > 1) {
|
|
347
|
+
return innerGetDataFromSource(ret, propIds.slice(1), propFunctions);
|
|
348
|
+
}
|
|
349
|
+
return ret;
|
|
350
|
+
}
|
|
351
|
+
return result;
|
|
352
|
+
};
|
|
353
|
+
const getDataFromSource = (result, source, propFunctions = []) => {
|
|
354
|
+
if (!source.nodeId) {
|
|
355
|
+
return source.value;
|
|
356
|
+
}
|
|
357
|
+
return innerGetDataFromSource(result, source.propIds, propFunctions);
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const resultsOfInner = (input, nodes, propFunctions, isSelfNode = false) => {
|
|
361
|
+
if (Array.isArray(input)) {
|
|
362
|
+
return input.map((inp) => resultsOfInner(inp, nodes, propFunctions, isSelfNode));
|
|
363
|
+
}
|
|
364
|
+
if (isNamedInputs(input)) {
|
|
365
|
+
return resultsOf(input, nodes, propFunctions, isSelfNode);
|
|
366
|
+
}
|
|
367
|
+
if (typeof input === "string") {
|
|
368
|
+
const templateMatch = [...input.matchAll(/\${(:[^}]+)}/g)].map((m) => m[1]);
|
|
369
|
+
if (templateMatch.length > 0) {
|
|
370
|
+
const results = resultsOfInner(templateMatch, nodes, propFunctions, isSelfNode);
|
|
371
|
+
return Array.from(templateMatch.keys()).reduce((tmp, key) => {
|
|
372
|
+
return tmp.replaceAll("${" + templateMatch[key] + "}", results[key]);
|
|
373
|
+
}, input);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return resultOf(parseNodeName(input, isSelfNode), nodes, propFunctions);
|
|
377
|
+
};
|
|
378
|
+
const resultsOf = (inputs, nodes, propFunctions, isSelfNode = false) => {
|
|
379
|
+
return Object.keys(inputs).reduce((tmp, key) => {
|
|
380
|
+
const input = inputs[key];
|
|
381
|
+
tmp[key] = isNamedInputs(input) ? resultsOf(input, nodes, propFunctions, isSelfNode) : resultsOfInner(input, nodes, propFunctions, isSelfNode);
|
|
382
|
+
return tmp;
|
|
383
|
+
}, {});
|
|
384
|
+
};
|
|
385
|
+
const resultOf = (source, nodes, propFunctions) => {
|
|
386
|
+
const { result } = source.nodeId ? nodes[source.nodeId] : { result: undefined };
|
|
387
|
+
return getDataFromSource(result, source, propFunctions);
|
|
388
|
+
};
|
|
389
|
+
// clean up object for anyInput
|
|
390
|
+
const cleanResultInner = (results) => {
|
|
391
|
+
if (Array.isArray(results)) {
|
|
392
|
+
return results.map((result) => cleanResultInner(result)).filter((result) => !isNull(result));
|
|
393
|
+
}
|
|
394
|
+
if (isObject(results)) {
|
|
395
|
+
return Object.keys(results).reduce((tmp, key) => {
|
|
396
|
+
const value = cleanResultInner(results[key]);
|
|
397
|
+
if (!isNull(value)) {
|
|
398
|
+
tmp[key] = value;
|
|
399
|
+
}
|
|
400
|
+
return tmp;
|
|
401
|
+
}, {});
|
|
402
|
+
}
|
|
403
|
+
return results;
|
|
404
|
+
};
|
|
405
|
+
const cleanResult = (results) => {
|
|
406
|
+
return Object.keys(results).reduce((tmp, key) => {
|
|
407
|
+
const value = cleanResultInner(results[key]);
|
|
408
|
+
if (!isNull(value)) {
|
|
409
|
+
tmp[key] = value;
|
|
410
|
+
}
|
|
411
|
+
return tmp;
|
|
412
|
+
}, {});
|
|
413
|
+
};
|
|
414
|
+
|
|
212
415
|
class Node {
|
|
213
416
|
constructor(nodeId, graph) {
|
|
214
417
|
this.waitlist = new Set(); // List of nodes which need data from this node.
|
|
@@ -234,7 +437,7 @@ class Node {
|
|
|
234
437
|
});
|
|
235
438
|
}
|
|
236
439
|
afterConsoleLog(result) {
|
|
237
|
-
if (this.console.after === true) {
|
|
440
|
+
if (this.console === true || this.console.after === true) {
|
|
238
441
|
console.log(typeof result === "string" ? result : JSON.stringify(result, null, 2));
|
|
239
442
|
}
|
|
240
443
|
else if (this.console.after) {
|
|
@@ -247,6 +450,7 @@ class ComputedNode extends Node {
|
|
|
247
450
|
super(nodeId, graph);
|
|
248
451
|
this.retryCount = 0;
|
|
249
452
|
this.dataSources = []; // no longer needed. This is for transaction log.
|
|
453
|
+
this.isSkip = false;
|
|
250
454
|
this.isStaticNode = false;
|
|
251
455
|
this.isComputedNode = true;
|
|
252
456
|
this.graphId = graphId;
|
|
@@ -260,7 +464,8 @@ class ComputedNode extends Node {
|
|
|
260
464
|
this.priority = data.priority ?? 0;
|
|
261
465
|
this.anyInput = data.anyInput ?? false;
|
|
262
466
|
this.inputs = data.inputs;
|
|
263
|
-
this.
|
|
467
|
+
this.output = data.output;
|
|
468
|
+
this.dataSources = [...(data.inputs ? inputs2dataSources(data.inputs).flat(10) : []), ...(data.params ? inputs2dataSources(data.params).flat(10) : [])];
|
|
264
469
|
if (data.inputs && Array.isArray(data.inputs)) {
|
|
265
470
|
throw new Error(`array inputs have been deprecated. nodeId: ${nodeId}: see https://github.com/receptron/graphai/blob/main/docs/NamedInputs.md`);
|
|
266
471
|
}
|
|
@@ -285,15 +490,10 @@ class ComputedNode extends Node {
|
|
|
285
490
|
if (data.unless) {
|
|
286
491
|
this.unlessSource = this.addPendingNode(data.unless);
|
|
287
492
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
tmp[key] = dataSource;
|
|
293
|
-
this.pendings.add(dataSource.nodeId);
|
|
294
|
-
}
|
|
295
|
-
return tmp;
|
|
296
|
-
}, {});
|
|
493
|
+
if (data.defaultValue) {
|
|
494
|
+
this.defaultValue = data.defaultValue;
|
|
495
|
+
}
|
|
496
|
+
this.isSkip = false;
|
|
297
497
|
this.log.initForComputedNode(this, graph);
|
|
298
498
|
}
|
|
299
499
|
getAgentId() {
|
|
@@ -309,8 +509,9 @@ class ComputedNode extends Node {
|
|
|
309
509
|
if (this.state !== NodeState.Waiting || this.pendings.size !== 0) {
|
|
310
510
|
return false;
|
|
311
511
|
}
|
|
312
|
-
|
|
313
|
-
(this.unlessSource && isLogicallyTrue(this.graph.resultOf(this.unlessSource))))
|
|
512
|
+
this.isSkip = !!((this.ifSource && !isLogicallyTrue(this.graph.resultOf(this.ifSource))) ||
|
|
513
|
+
(this.unlessSource && isLogicallyTrue(this.graph.resultOf(this.unlessSource))));
|
|
514
|
+
if (this.isSkip && this.defaultValue === undefined) {
|
|
314
515
|
this.state = NodeState.Skipped;
|
|
315
516
|
this.log.onSkipped(this, this.graph);
|
|
316
517
|
return false;
|
|
@@ -404,6 +605,10 @@ class ComputedNode extends Node {
|
|
|
404
605
|
// then it removes itself from the "running node" list of the graph.
|
|
405
606
|
// Notice that setting the result of this node may make other nodes ready to run.
|
|
406
607
|
async execute() {
|
|
608
|
+
if (this.isSkip) {
|
|
609
|
+
this.afterExecute(this.defaultValue, []);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
407
612
|
const previousResults = this.graph.resultsOf(this.inputs, this.anyInput);
|
|
408
613
|
const transactionId = Date.now();
|
|
409
614
|
this.prepareExecute(transactionId, Object.values(previousResults));
|
|
@@ -420,16 +625,7 @@ class ComputedNode extends Node {
|
|
|
420
625
|
// if this is a nested agent or not.
|
|
421
626
|
if (this.nestedGraph) {
|
|
422
627
|
this.graph.taskManager.prepareForNesting();
|
|
423
|
-
// context.taskManager = this.graph.taskManager;
|
|
424
628
|
context.onLogCallback = this.graph.onLogCallback;
|
|
425
|
-
/*
|
|
426
|
-
if ("nodes" in this.nestedGraph) {
|
|
427
|
-
context.graphData = this.nestedGraph;
|
|
428
|
-
} else {
|
|
429
|
-
context.graphData = this.graph.resultOf(this.nestedGraph) as GraphData; // HACK: compiler work-around
|
|
430
|
-
}
|
|
431
|
-
*/
|
|
432
|
-
// context.agents = this.graph.agentFunctionInfoDictionary;
|
|
433
629
|
context.forNestedGraph = {
|
|
434
630
|
graphData: "nodes" in this.nestedGraph ? this.nestedGraph : this.graph.resultOf(this.nestedGraph), // HACK: compiler work-around
|
|
435
631
|
agents: this.graph.agentFunctionInfoDictionary,
|
|
@@ -455,16 +651,23 @@ class ComputedNode extends Node {
|
|
|
455
651
|
console.log(`-- transactionId mismatch with ${this.nodeId} (probably timeout)`);
|
|
456
652
|
return;
|
|
457
653
|
}
|
|
458
|
-
|
|
459
|
-
this.result
|
|
460
|
-
this.log.onComplete(this, this.graph, localLog);
|
|
461
|
-
this.onSetResult();
|
|
462
|
-
this.graph.onExecutionComplete(this);
|
|
654
|
+
// after process
|
|
655
|
+
this.afterExecute(result, localLog);
|
|
463
656
|
}
|
|
464
657
|
catch (error) {
|
|
465
658
|
this.errorProcess(error, transactionId, previousResults);
|
|
466
659
|
}
|
|
467
660
|
}
|
|
661
|
+
afterExecute(result, localLog) {
|
|
662
|
+
this.state = NodeState.Completed;
|
|
663
|
+
this.result = this.getResult(result);
|
|
664
|
+
if (this.output) {
|
|
665
|
+
this.result = resultsOf(this.output, { self: this }, this.graph.propFunctions, true);
|
|
666
|
+
}
|
|
667
|
+
this.log.onComplete(this, this.graph, localLog);
|
|
668
|
+
this.onSetResult();
|
|
669
|
+
this.graph.onExecutionComplete(this);
|
|
670
|
+
}
|
|
468
671
|
// This private method (called only by execute()) prepares the ComputedNode object
|
|
469
672
|
// for execution, and create a new transaction to record it.
|
|
470
673
|
prepareExecute(transactionId, inputs) {
|
|
@@ -494,24 +697,9 @@ class ComputedNode extends Node {
|
|
|
494
697
|
this.retry(NodeState.Failed, Error("Unknown"));
|
|
495
698
|
}
|
|
496
699
|
}
|
|
497
|
-
getParams() {
|
|
498
|
-
return Object.keys(this.dynamicParams).reduce((tmp, key) => {
|
|
499
|
-
const result = this.graph.resultOf(this.dynamicParams[key]);
|
|
500
|
-
tmp[key] = result;
|
|
501
|
-
return tmp;
|
|
502
|
-
}, { ...this.params });
|
|
503
|
-
}
|
|
504
|
-
/*
|
|
505
|
-
private getInputs(previousResults: Record<string, ResultData | undefined>) {
|
|
506
|
-
if (Array.isArray(this.inputs)) {
|
|
507
|
-
return (this.inputs ?? []).map((key) => previousResults[String(key)]).filter((a) => !this.anyInput || a);
|
|
508
|
-
}
|
|
509
|
-
return [];
|
|
510
|
-
}
|
|
511
|
-
*/
|
|
512
700
|
getContext(previousResults, localLog) {
|
|
513
701
|
const context = {
|
|
514
|
-
params: this.
|
|
702
|
+
params: this.graph.resultsOf(this.params),
|
|
515
703
|
namedInputs: previousResults,
|
|
516
704
|
inputSchema: this.agentFunction ? undefined : this.graph.getAgentFunctionInfo(this.agentId)?.inputs,
|
|
517
705
|
debugInfo: this.getDebugInfo(),
|
|
@@ -545,7 +733,7 @@ class ComputedNode extends Node {
|
|
|
545
733
|
};
|
|
546
734
|
}
|
|
547
735
|
beforeConsoleLog(context) {
|
|
548
|
-
if (this.console.before === true) {
|
|
736
|
+
if (this.console === true || this.console.before === true) {
|
|
549
737
|
console.log(JSON.stringify(context.namedInputs, null, 2));
|
|
550
738
|
}
|
|
551
739
|
else if (this.console.before) {
|
|
@@ -574,212 +762,10 @@ class StaticNode extends Node {
|
|
|
574
762
|
}
|
|
575
763
|
}
|
|
576
764
|
|
|
577
|
-
const propFunctionRegex = /^[a-zA-Z]+\([^)]*\)$/;
|
|
578
|
-
const propArrayFunction = (result, propId) => {
|
|
579
|
-
if (Array.isArray(result)) {
|
|
580
|
-
if (propId === "length()") {
|
|
581
|
-
return result.length;
|
|
582
|
-
}
|
|
583
|
-
if (propId === "flat()") {
|
|
584
|
-
return result.flat();
|
|
585
|
-
}
|
|
586
|
-
if (propId === "toJSON()") {
|
|
587
|
-
return JSON.stringify(result);
|
|
588
|
-
}
|
|
589
|
-
if (propId === "isEmpty()") {
|
|
590
|
-
return result.length === 0;
|
|
591
|
-
}
|
|
592
|
-
// array join
|
|
593
|
-
const matchJoin = propId.match(/^join\(([,-]?)\)$/);
|
|
594
|
-
if (matchJoin && Array.isArray(matchJoin)) {
|
|
595
|
-
return result.join(matchJoin[1] ?? "");
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
return undefined;
|
|
599
|
-
};
|
|
600
|
-
const propObjectFunction = (result, propId) => {
|
|
601
|
-
if (isObject(result)) {
|
|
602
|
-
if (propId === "keys()") {
|
|
603
|
-
return Object.keys(result);
|
|
604
|
-
}
|
|
605
|
-
if (propId === "values()") {
|
|
606
|
-
return Object.values(result);
|
|
607
|
-
}
|
|
608
|
-
if (propId === "toJSON()") {
|
|
609
|
-
return JSON.stringify(result);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
return undefined;
|
|
613
|
-
};
|
|
614
|
-
const propStringFunction = (result, propId) => {
|
|
615
|
-
if (typeof result === "string") {
|
|
616
|
-
if (propId === "codeBlock()") {
|
|
617
|
-
const match = ("\n" + result).match(/\n```[a-zA-z]*([\s\S]*?)\n```/);
|
|
618
|
-
if (match) {
|
|
619
|
-
return match[1];
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
if (propId === "jsonParse()") {
|
|
623
|
-
return JSON.parse(result);
|
|
624
|
-
}
|
|
625
|
-
if (propId === "toNumber()") {
|
|
626
|
-
const ret = Number(result);
|
|
627
|
-
if (!isNaN(ret)) {
|
|
628
|
-
return ret;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
if (propId === "trim()") {
|
|
632
|
-
return result.trim();
|
|
633
|
-
}
|
|
634
|
-
if (propId === "toLowerCase()") {
|
|
635
|
-
return result.toLowerCase();
|
|
636
|
-
}
|
|
637
|
-
if (propId === "toUpperCase()") {
|
|
638
|
-
return result.toUpperCase();
|
|
639
|
-
}
|
|
640
|
-
// split()
|
|
641
|
-
}
|
|
642
|
-
return undefined;
|
|
643
|
-
};
|
|
644
|
-
const propNumberFunction = (result, propId) => {
|
|
645
|
-
if (result !== undefined && Number.isFinite(result)) {
|
|
646
|
-
if (propId === "toString()") {
|
|
647
|
-
return String(result);
|
|
648
|
-
}
|
|
649
|
-
const regex = /^add\((-?\d+)\)$/;
|
|
650
|
-
const match = propId.match(regex);
|
|
651
|
-
if (match) {
|
|
652
|
-
return Number(result) + Number(match[1]);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return undefined;
|
|
656
|
-
};
|
|
657
|
-
const propBooleanFunction = (result, propId) => {
|
|
658
|
-
if (typeof result === "boolean") {
|
|
659
|
-
if (propId === "not()") {
|
|
660
|
-
return !result;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return undefined;
|
|
664
|
-
};
|
|
665
|
-
const propFunctions = [propArrayFunction, propObjectFunction, propStringFunction, propNumberFunction, propBooleanFunction];
|
|
666
|
-
|
|
667
|
-
const getNestedData = (result, propId, propFunctions) => {
|
|
668
|
-
const match = propId.match(propFunctionRegex);
|
|
669
|
-
if (match) {
|
|
670
|
-
for (const propFunction of propFunctions) {
|
|
671
|
-
const ret = propFunction(result, propId);
|
|
672
|
-
if (!isNull(ret)) {
|
|
673
|
-
return ret;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
// for array.
|
|
678
|
-
if (Array.isArray(result)) {
|
|
679
|
-
// $0, $1. array value.
|
|
680
|
-
const regex = /^\$(\d+)$/;
|
|
681
|
-
const match = propId.match(regex);
|
|
682
|
-
if (match) {
|
|
683
|
-
const index = parseInt(match[1], 10);
|
|
684
|
-
return result[index];
|
|
685
|
-
}
|
|
686
|
-
if (propId === "$last") {
|
|
687
|
-
return result[result.length - 1];
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
else if (isObject(result)) {
|
|
691
|
-
if (propId in result) {
|
|
692
|
-
return result[propId];
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
return undefined;
|
|
696
|
-
};
|
|
697
|
-
const innerGetDataFromSource = (result, propIds, propFunctions) => {
|
|
698
|
-
if (!isNull(result) && propIds && propIds.length > 0) {
|
|
699
|
-
const propId = propIds[0];
|
|
700
|
-
const ret = getNestedData(result, propId, propFunctions);
|
|
701
|
-
if (ret === undefined) {
|
|
702
|
-
console.error(`prop: ${propIds.join(".")} is not hit`);
|
|
703
|
-
}
|
|
704
|
-
if (propIds.length > 1) {
|
|
705
|
-
return innerGetDataFromSource(ret, propIds.slice(1), propFunctions);
|
|
706
|
-
}
|
|
707
|
-
return ret;
|
|
708
|
-
}
|
|
709
|
-
return result;
|
|
710
|
-
};
|
|
711
|
-
const getDataFromSource = (result, source, propFunctions = []) => {
|
|
712
|
-
if (!source.nodeId) {
|
|
713
|
-
return source.value;
|
|
714
|
-
}
|
|
715
|
-
return innerGetDataFromSource(result, source.propIds, propFunctions);
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
const resultsOfInner = (input, nodes, propFunctions) => {
|
|
719
|
-
if (Array.isArray(input)) {
|
|
720
|
-
return input.map((inp) => resultsOfInner(inp, nodes, propFunctions));
|
|
721
|
-
}
|
|
722
|
-
if (isNamedInputs(input)) {
|
|
723
|
-
return resultsOf(input, nodes, propFunctions);
|
|
724
|
-
}
|
|
725
|
-
if (typeof input === "string") {
|
|
726
|
-
const templateMatch = [...input.matchAll(/\${(:[^}]+)}/g)].map((m) => m[1]);
|
|
727
|
-
if (templateMatch.length > 0) {
|
|
728
|
-
const results = resultsOfInner(templateMatch, nodes, propFunctions);
|
|
729
|
-
return Array.from(templateMatch.keys()).reduce((tmp, key) => {
|
|
730
|
-
return tmp.replaceAll("${" + templateMatch[key] + "}", results[key]);
|
|
731
|
-
}, input);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
return resultOf(parseNodeName(input), nodes, propFunctions);
|
|
735
|
-
};
|
|
736
|
-
const resultsOf = (inputs, nodes, propFunctions) => {
|
|
737
|
-
// for inputs. TODO remove if array input is not supported
|
|
738
|
-
if (Array.isArray(inputs)) {
|
|
739
|
-
return inputs.reduce((tmp, key) => {
|
|
740
|
-
tmp[key] = resultsOfInner(key, nodes, propFunctions);
|
|
741
|
-
return tmp;
|
|
742
|
-
}, {});
|
|
743
|
-
}
|
|
744
|
-
return Object.keys(inputs).reduce((tmp, key) => {
|
|
745
|
-
const input = inputs[key];
|
|
746
|
-
tmp[key] = isNamedInputs(input) ? resultsOf(input, nodes, propFunctions) : resultsOfInner(input, nodes, propFunctions);
|
|
747
|
-
return tmp;
|
|
748
|
-
}, {});
|
|
749
|
-
};
|
|
750
|
-
const resultOf = (source, nodes, propFunctions) => {
|
|
751
|
-
const { result } = source.nodeId ? nodes[source.nodeId] : { result: undefined };
|
|
752
|
-
return getDataFromSource(result, source, propFunctions);
|
|
753
|
-
};
|
|
754
|
-
// clean up object for anyInput
|
|
755
|
-
const cleanResultInner = (results) => {
|
|
756
|
-
if (Array.isArray(results)) {
|
|
757
|
-
return results.map((result) => cleanResultInner(result)).filter((result) => !isNull(result));
|
|
758
|
-
}
|
|
759
|
-
if (isObject(results)) {
|
|
760
|
-
return Object.keys(results).reduce((tmp, key) => {
|
|
761
|
-
const value = cleanResultInner(results[key]);
|
|
762
|
-
if (!isNull(value)) {
|
|
763
|
-
tmp[key] = value;
|
|
764
|
-
}
|
|
765
|
-
return tmp;
|
|
766
|
-
}, {});
|
|
767
|
-
}
|
|
768
|
-
return results;
|
|
769
|
-
};
|
|
770
|
-
const cleanResult = (results) => {
|
|
771
|
-
return Object.keys(results).reduce((tmp, key) => {
|
|
772
|
-
const value = cleanResultInner(results[key]);
|
|
773
|
-
if (!isNull(value)) {
|
|
774
|
-
tmp[key] = value;
|
|
775
|
-
}
|
|
776
|
-
return tmp;
|
|
777
|
-
}, {});
|
|
778
|
-
};
|
|
779
|
-
|
|
780
765
|
const graphDataAttributeKeys = ["nodes", "concurrency", "agentId", "loop", "verbose", "version"];
|
|
781
766
|
const computedNodeAttributeKeys = [
|
|
782
767
|
"inputs",
|
|
768
|
+
"output",
|
|
783
769
|
"anyInput",
|
|
784
770
|
"params",
|
|
785
771
|
"retry",
|
|
@@ -791,6 +777,7 @@ const computedNodeAttributeKeys = [
|
|
|
791
777
|
"priority",
|
|
792
778
|
"if",
|
|
793
779
|
"unless",
|
|
780
|
+
"defaultValue",
|
|
794
781
|
"filterParams",
|
|
795
782
|
"console",
|
|
796
783
|
"passThrough",
|
|
@@ -846,9 +833,9 @@ const nodeValidator = (nodeData) => {
|
|
|
846
833
|
if (nodeData.agent && nodeData.value) {
|
|
847
834
|
throw new ValidationError("Cannot set both agent and value");
|
|
848
835
|
}
|
|
849
|
-
if (!("agent" in nodeData) && !("value" in nodeData)) {
|
|
850
|
-
|
|
851
|
-
}
|
|
836
|
+
// if (!("agent" in nodeData) && !("value" in nodeData)) {
|
|
837
|
+
// throw new ValidationError("Either agent or value is required");
|
|
838
|
+
// }
|
|
852
839
|
return true;
|
|
853
840
|
};
|
|
854
841
|
|
|
@@ -967,7 +954,7 @@ const validateGraphData = (data, agentIds) => {
|
|
|
967
954
|
const graphAgentIds = new Set();
|
|
968
955
|
Object.keys(data.nodes).forEach((nodeId) => {
|
|
969
956
|
const node = data.nodes[nodeId];
|
|
970
|
-
const isStaticNode = "
|
|
957
|
+
const isStaticNode = !("agent" in node);
|
|
971
958
|
nodeValidator(node);
|
|
972
959
|
const agentId = isStaticNode ? "" : node.agent;
|
|
973
960
|
isStaticNode && staticNodeValidator(node) && staticNodeIds.push(nodeId);
|
|
@@ -1054,15 +1041,13 @@ class GraphAI {
|
|
|
1054
1041
|
createNodes(data) {
|
|
1055
1042
|
const nodes = Object.keys(data.nodes).reduce((_nodes, nodeId) => {
|
|
1056
1043
|
const nodeData = data.nodes[nodeId];
|
|
1057
|
-
if ("
|
|
1058
|
-
_nodes[nodeId] = new StaticNode(nodeId, nodeData, this);
|
|
1059
|
-
}
|
|
1060
|
-
else if ("agent" in nodeData) {
|
|
1044
|
+
if ("agent" in nodeData) {
|
|
1061
1045
|
_nodes[nodeId] = new ComputedNode(this.graphId, nodeId, nodeData, this);
|
|
1062
1046
|
}
|
|
1063
1047
|
else {
|
|
1064
|
-
|
|
1048
|
+
_nodes[nodeId] = new StaticNode(nodeId, nodeData, this);
|
|
1065
1049
|
}
|
|
1050
|
+
// throw new Error("Unknown node type (neither value nor agent): " + nodeId);
|
|
1066
1051
|
return _nodes;
|
|
1067
1052
|
}, {});
|
|
1068
1053
|
// Generate the waitlist for each node.
|
|
@@ -1231,6 +1216,11 @@ class GraphAI {
|
|
|
1231
1216
|
}
|
|
1232
1217
|
// Public API
|
|
1233
1218
|
async run(all = false) {
|
|
1219
|
+
if (Object.values(this.nodes)
|
|
1220
|
+
.filter((node) => node.isStaticNode)
|
|
1221
|
+
.some((node) => node.result === undefined && node.update === undefined)) {
|
|
1222
|
+
throw new Error("Static node must have value. Set value or injectValue or set update");
|
|
1223
|
+
}
|
|
1234
1224
|
if (this.isRunning()) {
|
|
1235
1225
|
throw new Error("This GraphUI instance is already running");
|
|
1236
1226
|
}
|