graphai 0.6.4 → 0.6.6

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.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,11 +437,16 @@ 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) {
241
- console.log(this.console.after);
444
+ if (isObject(this.console.after)) {
445
+ console.log(JSON.stringify(resultsOf(this.console.after, { self: this }, this.graph.propFunctions, true), null, 2));
446
+ }
447
+ else {
448
+ console.log(this.console.after);
449
+ }
242
450
  }
243
451
  }
244
452
  }
@@ -261,6 +469,7 @@ class ComputedNode extends Node {
261
469
  this.priority = data.priority ?? 0;
262
470
  this.anyInput = data.anyInput ?? false;
263
471
  this.inputs = data.inputs;
472
+ this.output = data.output;
264
473
  this.dataSources = [...(data.inputs ? inputs2dataSources(data.inputs).flat(10) : []), ...(data.params ? inputs2dataSources(data.params).flat(10) : [])];
265
474
  if (data.inputs && Array.isArray(data.inputs)) {
266
475
  throw new Error(`array inputs have been deprecated. nodeId: ${nodeId}: see https://github.com/receptron/graphai/blob/main/docs/NamedInputs.md`);
@@ -457,6 +666,9 @@ class ComputedNode extends Node {
457
666
  afterExecute(result, localLog) {
458
667
  this.state = NodeState.Completed;
459
668
  this.result = this.getResult(result);
669
+ if (this.output) {
670
+ this.result = resultsOf(this.output, { self: this }, this.graph.propFunctions, true);
671
+ }
460
672
  this.log.onComplete(this, this.graph, localLog);
461
673
  this.onSetResult();
462
674
  this.graph.onExecutionComplete(this);
@@ -526,7 +738,7 @@ class ComputedNode extends Node {
526
738
  };
527
739
  }
528
740
  beforeConsoleLog(context) {
529
- if (this.console.before === true) {
741
+ if (this.console === true || this.console.before === true) {
530
742
  console.log(JSON.stringify(context.namedInputs, null, 2));
531
743
  }
532
744
  else if (this.console.before) {
@@ -555,212 +767,10 @@ class StaticNode extends Node {
555
767
  }
556
768
  }
557
769
 
558
- const propFunctionRegex = /^[a-zA-Z]+\([^)]*\)$/;
559
- const propArrayFunction = (result, propId) => {
560
- if (Array.isArray(result)) {
561
- if (propId === "length()") {
562
- return result.length;
563
- }
564
- if (propId === "flat()") {
565
- return result.flat();
566
- }
567
- if (propId === "toJSON()") {
568
- return JSON.stringify(result);
569
- }
570
- if (propId === "isEmpty()") {
571
- return result.length === 0;
572
- }
573
- // array join
574
- const matchJoin = propId.match(/^join\(([,-\s]?)\)$/);
575
- if (matchJoin && Array.isArray(matchJoin)) {
576
- return result.join(matchJoin[1] ?? "");
577
- }
578
- }
579
- return undefined;
580
- };
581
- const propObjectFunction = (result, propId) => {
582
- if (isObject(result)) {
583
- if (propId === "keys()") {
584
- return Object.keys(result);
585
- }
586
- if (propId === "values()") {
587
- return Object.values(result);
588
- }
589
- if (propId === "toJSON()") {
590
- return JSON.stringify(result);
591
- }
592
- }
593
- return undefined;
594
- };
595
- const propStringFunction = (result, propId) => {
596
- if (typeof result === "string") {
597
- if (propId === "codeBlock()") {
598
- const match = ("\n" + result).match(/\n```[a-zA-z]*([\s\S]*?)\n```/);
599
- if (match) {
600
- return match[1];
601
- }
602
- }
603
- if (propId === "jsonParse()") {
604
- return JSON.parse(result);
605
- }
606
- if (propId === "toNumber()") {
607
- const ret = Number(result);
608
- if (!isNaN(ret)) {
609
- return ret;
610
- }
611
- }
612
- if (propId === "trim()") {
613
- return result.trim();
614
- }
615
- if (propId === "toLowerCase()") {
616
- return result.toLowerCase();
617
- }
618
- if (propId === "toUpperCase()") {
619
- return result.toUpperCase();
620
- }
621
- // split()
622
- }
623
- return undefined;
624
- };
625
- const propNumberFunction = (result, propId) => {
626
- if (result !== undefined && Number.isFinite(result)) {
627
- if (propId === "toString()") {
628
- return String(result);
629
- }
630
- const regex = /^add\((-?\d+)\)$/;
631
- const match = propId.match(regex);
632
- if (match) {
633
- return Number(result) + Number(match[1]);
634
- }
635
- }
636
- return undefined;
637
- };
638
- const propBooleanFunction = (result, propId) => {
639
- if (typeof result === "boolean") {
640
- if (propId === "not()") {
641
- return !result;
642
- }
643
- }
644
- return undefined;
645
- };
646
- const propFunctions = [propArrayFunction, propObjectFunction, propStringFunction, propNumberFunction, propBooleanFunction];
647
-
648
- const getNestedData = (result, propId, propFunctions) => {
649
- const match = propId.match(propFunctionRegex);
650
- if (match) {
651
- for (const propFunction of propFunctions) {
652
- const ret = propFunction(result, propId);
653
- if (!isNull(ret)) {
654
- return ret;
655
- }
656
- }
657
- }
658
- // for array.
659
- if (Array.isArray(result)) {
660
- // $0, $1. array value.
661
- const regex = /^\$(\d+)$/;
662
- const match = propId.match(regex);
663
- if (match) {
664
- const index = parseInt(match[1], 10);
665
- return result[index];
666
- }
667
- if (propId === "$last") {
668
- return result[result.length - 1];
669
- }
670
- }
671
- else if (isObject(result)) {
672
- if (propId in result) {
673
- return result[propId];
674
- }
675
- }
676
- return undefined;
677
- };
678
- const innerGetDataFromSource = (result, propIds, propFunctions) => {
679
- if (!isNull(result) && propIds && propIds.length > 0) {
680
- const propId = propIds[0];
681
- const ret = getNestedData(result, propId, propFunctions);
682
- if (ret === undefined) {
683
- console.error(`prop: ${propIds.join(".")} is not hit`);
684
- }
685
- if (propIds.length > 1) {
686
- return innerGetDataFromSource(ret, propIds.slice(1), propFunctions);
687
- }
688
- return ret;
689
- }
690
- return result;
691
- };
692
- const getDataFromSource = (result, source, propFunctions = []) => {
693
- if (!source.nodeId) {
694
- return source.value;
695
- }
696
- return innerGetDataFromSource(result, source.propIds, propFunctions);
697
- };
698
-
699
- const resultsOfInner = (input, nodes, propFunctions) => {
700
- if (Array.isArray(input)) {
701
- return input.map((inp) => resultsOfInner(inp, nodes, propFunctions));
702
- }
703
- if (isNamedInputs(input)) {
704
- return resultsOf(input, nodes, propFunctions);
705
- }
706
- if (typeof input === "string") {
707
- const templateMatch = [...input.matchAll(/\${(:[^}]+)}/g)].map((m) => m[1]);
708
- if (templateMatch.length > 0) {
709
- const results = resultsOfInner(templateMatch, nodes, propFunctions);
710
- return Array.from(templateMatch.keys()).reduce((tmp, key) => {
711
- return tmp.replaceAll("${" + templateMatch[key] + "}", results[key]);
712
- }, input);
713
- }
714
- }
715
- return resultOf(parseNodeName(input), nodes, propFunctions);
716
- };
717
- const resultsOf = (inputs, nodes, propFunctions) => {
718
- // for inputs. TODO remove if array input is not supported
719
- if (Array.isArray(inputs)) {
720
- return inputs.reduce((tmp, key) => {
721
- tmp[key] = resultsOfInner(key, nodes, propFunctions);
722
- return tmp;
723
- }, {});
724
- }
725
- return Object.keys(inputs).reduce((tmp, key) => {
726
- const input = inputs[key];
727
- tmp[key] = isNamedInputs(input) ? resultsOf(input, nodes, propFunctions) : resultsOfInner(input, nodes, propFunctions);
728
- return tmp;
729
- }, {});
730
- };
731
- const resultOf = (source, nodes, propFunctions) => {
732
- const { result } = source.nodeId ? nodes[source.nodeId] : { result: undefined };
733
- return getDataFromSource(result, source, propFunctions);
734
- };
735
- // clean up object for anyInput
736
- const cleanResultInner = (results) => {
737
- if (Array.isArray(results)) {
738
- return results.map((result) => cleanResultInner(result)).filter((result) => !isNull(result));
739
- }
740
- if (isObject(results)) {
741
- return Object.keys(results).reduce((tmp, key) => {
742
- const value = cleanResultInner(results[key]);
743
- if (!isNull(value)) {
744
- tmp[key] = value;
745
- }
746
- return tmp;
747
- }, {});
748
- }
749
- return results;
750
- };
751
- const cleanResult = (results) => {
752
- return Object.keys(results).reduce((tmp, key) => {
753
- const value = cleanResultInner(results[key]);
754
- if (!isNull(value)) {
755
- tmp[key] = value;
756
- }
757
- return tmp;
758
- }, {});
759
- };
760
-
761
770
  const graphDataAttributeKeys = ["nodes", "concurrency", "agentId", "loop", "verbose", "version"];
762
771
  const computedNodeAttributeKeys = [
763
772
  "inputs",
773
+ "output",
764
774
  "anyInput",
765
775
  "params",
766
776
  "retry",
@@ -1042,7 +1052,6 @@ class GraphAI {
1042
1052
  else {
1043
1053
  _nodes[nodeId] = new StaticNode(nodeId, nodeData, this);
1044
1054
  }
1045
- // throw new Error("Unknown node type (neither value nor agent): " + nodeId);
1046
1055
  return _nodes;
1047
1056
  }, {});
1048
1057
  // Generate the waitlist for each node.
@@ -1217,7 +1226,7 @@ class GraphAI {
1217
1226
  throw new Error("Static node must have value. Set value or injectValue or set update");
1218
1227
  }
1219
1228
  if (this.isRunning()) {
1220
- throw new Error("This GraphUI instance is already running");
1229
+ throw new Error("This GraphAI instance is already running");
1221
1230
  }
1222
1231
  this.pushReadyNodesIntoQueue();
1223
1232
  if (!this.isRunning()) {
@@ -1270,14 +1279,23 @@ class GraphAI {
1270
1279
  return false; // while condition is not met
1271
1280
  }
1272
1281
  }
1273
- this.nodes = this.createNodes(this.data);
1274
- this.initializeStaticNodes();
1282
+ this.initializeGraphAI();
1275
1283
  this.updateStaticNodes(previousResults, true);
1276
1284
  this.pushReadyNodesIntoQueue();
1277
1285
  return true; // Indicating that we are going to continue.
1278
1286
  }
1279
1287
  return false;
1280
1288
  }
1289
+ initializeGraphAI() {
1290
+ if (this.isRunning()) {
1291
+ throw new Error("This GraphAI instance is running");
1292
+ }
1293
+ this.nodes = this.createNodes(this.data);
1294
+ this.initializeStaticNodes();
1295
+ }
1296
+ setPreviousResults(previousResults) {
1297
+ this.updateStaticNodes(previousResults);
1298
+ }
1281
1299
  setLoopLog(log) {
1282
1300
  log.isLoop = !!this.loop;
1283
1301
  log.repeatCount = this.repeatCount;