graphai 0.6.4 → 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.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) {
@@ -261,6 +464,7 @@ class ComputedNode extends Node {
261
464
  this.priority = data.priority ?? 0;
262
465
  this.anyInput = data.anyInput ?? false;
263
466
  this.inputs = data.inputs;
467
+ this.output = data.output;
264
468
  this.dataSources = [...(data.inputs ? inputs2dataSources(data.inputs).flat(10) : []), ...(data.params ? inputs2dataSources(data.params).flat(10) : [])];
265
469
  if (data.inputs && Array.isArray(data.inputs)) {
266
470
  throw new Error(`array inputs have been deprecated. nodeId: ${nodeId}: see https://github.com/receptron/graphai/blob/main/docs/NamedInputs.md`);
@@ -457,6 +661,9 @@ class ComputedNode extends Node {
457
661
  afterExecute(result, localLog) {
458
662
  this.state = NodeState.Completed;
459
663
  this.result = this.getResult(result);
664
+ if (this.output) {
665
+ this.result = resultsOf(this.output, { self: this }, this.graph.propFunctions, true);
666
+ }
460
667
  this.log.onComplete(this, this.graph, localLog);
461
668
  this.onSetResult();
462
669
  this.graph.onExecutionComplete(this);
@@ -526,7 +733,7 @@ class ComputedNode extends Node {
526
733
  };
527
734
  }
528
735
  beforeConsoleLog(context) {
529
- if (this.console.before === true) {
736
+ if (this.console === true || this.console.before === true) {
530
737
  console.log(JSON.stringify(context.namedInputs, null, 2));
531
738
  }
532
739
  else if (this.console.before) {
@@ -555,212 +762,10 @@ class StaticNode extends Node {
555
762
  }
556
763
  }
557
764
 
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
765
  const graphDataAttributeKeys = ["nodes", "concurrency", "agentId", "loop", "verbose", "version"];
762
766
  const computedNodeAttributeKeys = [
763
767
  "inputs",
768
+ "output",
764
769
  "anyInput",
765
770
  "params",
766
771
  "retry",