@q1k-oss/behaviour-tree-workflows 0.0.4 → 0.0.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/dist/index.cjs CHANGED
@@ -31,7 +31,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ActionNode: () => ActionNode,
34
+ Aggregate: () => Aggregate,
34
35
  AlwaysCondition: () => AlwaysCondition,
36
+ ArrayFilter: () => ArrayFilter,
35
37
  BaseNode: () => BaseNode,
36
38
  BehaviorTree: () => BehaviorTree,
37
39
  BrowserAgent: () => BrowserAgent,
@@ -44,6 +46,7 @@ __export(index_exports, {
44
46
  ConfigValidationError: () => ConfigValidationError,
45
47
  ConfigurationError: () => ConfigurationError,
46
48
  CounterAction: () => CounterAction,
49
+ DataTransform: () => DataTransform,
47
50
  DecoratorNode: () => DecoratorNode,
48
51
  Delay: () => Delay,
49
52
  ExecutionTracker: () => ExecutionTracker,
@@ -62,6 +65,7 @@ __export(index_exports, {
62
65
  LLMChat: () => LLMChat,
63
66
  LLMToolCall: () => LLMToolCall,
64
67
  LogMessage: () => LogMessage,
68
+ MathOp: () => MathOp,
65
69
  MemoryDataStore: () => MemoryDataStore,
66
70
  MemorySequence: () => MemorySequence,
67
71
  MockAction: () => MockAction,
@@ -93,6 +97,7 @@ __export(index_exports, {
93
97
  StructureValidationError: () => StructureValidationError,
94
98
  SubTree: () => SubTree,
95
99
  SuccessNode: () => SuccessNode,
100
+ ThresholdCheck: () => ThresholdCheck,
96
101
  Timeout: () => Timeout,
97
102
  ToolExecutor: () => ToolExecutor,
98
103
  ToolRouter: () => ToolRouter,
@@ -123,6 +128,7 @@ __export(index_exports, {
123
128
  registerStandardNodes: () => registerStandardNodes,
124
129
  resolveString: () => resolveString,
125
130
  resolveValue: () => resolveValue,
131
+ safeEvaluate: () => safeEvaluate,
126
132
  safeValidateConfiguration: () => safeValidateConfiguration,
127
133
  schemaRegistry: () => schemaRegistry,
128
134
  semanticValidator: () => semanticValidator,
@@ -2690,74 +2696,153 @@ var setVariableSchema = createNodeSchema("SetVariable", {
2690
2696
  value: import_zod6.z.unknown()
2691
2697
  });
2692
2698
 
2693
- // src/actions/llm-tool-call.schema.ts
2699
+ // src/utilities/math-op.schema.ts
2694
2700
  var import_zod7 = require("zod");
2695
- var toolDefinitionSchema = import_zod7.z.object({
2696
- name: import_zod7.z.string().min(1),
2697
- description: import_zod7.z.string().min(1),
2698
- inputSchema: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.unknown())
2701
+ var mathOpSchema = createNodeSchema("MathOp", {
2702
+ expression: import_zod7.z.string().min(1, "expression is required"),
2703
+ outputKey: import_zod7.z.string().min(1, "outputKey is required"),
2704
+ round: import_zod7.z.enum(["none", "round", "floor", "ceil"]).optional(),
2705
+ precision: import_zod7.z.number().int().nonnegative().optional()
2706
+ });
2707
+
2708
+ // src/utilities/array-filter.schema.ts
2709
+ var import_zod8 = require("zod");
2710
+ var filterConditionSchema = import_zod8.z.object({
2711
+ field: import_zod8.z.string().min(1),
2712
+ operator: import_zod8.z.enum([
2713
+ "eq",
2714
+ "ne",
2715
+ "gt",
2716
+ "lt",
2717
+ "gte",
2718
+ "lte",
2719
+ "in",
2720
+ "nin",
2721
+ "exists",
2722
+ "regex",
2723
+ "between",
2724
+ "contains"
2725
+ ]),
2726
+ value: import_zod8.z.unknown().optional(),
2727
+ range: import_zod8.z.tuple([import_zod8.z.unknown(), import_zod8.z.unknown()]).optional()
2728
+ });
2729
+ var arrayFilterSchema = createNodeSchema("ArrayFilter", {
2730
+ input: import_zod8.z.string().min(1, "input is required"),
2731
+ outputKey: import_zod8.z.string().min(1, "outputKey is required"),
2732
+ conditions: import_zod8.z.array(filterConditionSchema).min(1, "at least one condition is required"),
2733
+ logic: import_zod8.z.enum(["and", "or"]).optional()
2734
+ });
2735
+
2736
+ // src/utilities/aggregate.schema.ts
2737
+ var import_zod9 = require("zod");
2738
+ var aggregateOperationSchema = import_zod9.z.object({
2739
+ type: import_zod9.z.enum(["count", "sum", "avg", "min", "max"]),
2740
+ field: import_zod9.z.string().optional(),
2741
+ as: import_zod9.z.string().optional()
2742
+ });
2743
+ var aggregateSchema = createNodeSchema("Aggregate", {
2744
+ input: import_zod9.z.string().min(1, "input is required"),
2745
+ outputKey: import_zod9.z.string().min(1, "outputKey is required"),
2746
+ operations: import_zod9.z.array(aggregateOperationSchema).min(1, "at least one operation is required"),
2747
+ groupBy: import_zod9.z.string().optional()
2748
+ });
2749
+
2750
+ // src/utilities/threshold-check.schema.ts
2751
+ var import_zod10 = require("zod");
2752
+ var thresholdLevelSchema = import_zod10.z.object({
2753
+ operator: import_zod10.z.enum(["lte", "lt", "gte", "gt", "eq", "ne", "between"]),
2754
+ value: import_zod10.z.unknown().optional(),
2755
+ range: import_zod10.z.tuple([import_zod10.z.unknown(), import_zod10.z.unknown()]).optional(),
2756
+ label: import_zod10.z.string().min(1, "label is required")
2757
+ });
2758
+ var thresholdCheckSchema = createNodeSchema("ThresholdCheck", {
2759
+ value: import_zod10.z.unknown(),
2760
+ thresholds: import_zod10.z.array(thresholdLevelSchema).min(1, "at least one threshold is required"),
2761
+ outputKey: import_zod10.z.string().optional(),
2762
+ failOn: import_zod10.z.array(import_zod10.z.string()).optional()
2763
+ });
2764
+
2765
+ // src/utilities/data-transform.schema.ts
2766
+ var import_zod11 = require("zod");
2767
+ var transformMappingSchema = import_zod11.z.object({
2768
+ target: import_zod11.z.string().min(1, "target is required"),
2769
+ value: import_zod11.z.unknown(),
2770
+ coerce: import_zod11.z.enum(["string", "number", "boolean"]).optional()
2771
+ });
2772
+ var dataTransformSchema = createNodeSchema("DataTransform", {
2773
+ outputKey: import_zod11.z.string().min(1, "outputKey is required"),
2774
+ mappings: import_zod11.z.array(transformMappingSchema).min(1, "at least one mapping is required"),
2775
+ wrapInArray: import_zod11.z.boolean().optional()
2776
+ });
2777
+
2778
+ // src/actions/llm-tool-call.schema.ts
2779
+ var import_zod12 = require("zod");
2780
+ var toolDefinitionSchema = import_zod12.z.object({
2781
+ name: import_zod12.z.string().min(1),
2782
+ description: import_zod12.z.string().min(1),
2783
+ inputSchema: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown())
2699
2784
  });
2700
2785
  var llmToolCallSchema = createNodeSchema("LLMToolCall", {
2701
- provider: import_zod7.z.enum(["anthropic", "openai", "google", "ollama"]),
2702
- model: import_zod7.z.string().min(1, "Model is required"),
2703
- systemPrompt: import_zod7.z.string().optional(),
2704
- messagesKey: import_zod7.z.string().min(1, "messagesKey is required"),
2705
- userMessageKey: import_zod7.z.string().optional(),
2706
- toolsKey: import_zod7.z.string().optional(),
2707
- tools: import_zod7.z.array(toolDefinitionSchema).optional(),
2708
- temperature: import_zod7.z.number().min(0).max(2).optional(),
2709
- maxTokens: import_zod7.z.number().int().positive().optional(),
2710
- outputKey: import_zod7.z.string().min(1, "outputKey is required")
2786
+ provider: import_zod12.z.enum(["anthropic", "openai", "google", "ollama"]),
2787
+ model: import_zod12.z.string().min(1, "Model is required"),
2788
+ systemPrompt: import_zod12.z.string().optional(),
2789
+ messagesKey: import_zod12.z.string().min(1, "messagesKey is required"),
2790
+ userMessageKey: import_zod12.z.string().optional(),
2791
+ toolsKey: import_zod12.z.string().optional(),
2792
+ tools: import_zod12.z.array(toolDefinitionSchema).optional(),
2793
+ temperature: import_zod12.z.number().min(0).max(2).optional(),
2794
+ maxTokens: import_zod12.z.number().int().positive().optional(),
2795
+ outputKey: import_zod12.z.string().min(1, "outputKey is required")
2711
2796
  });
2712
2797
 
2713
2798
  // src/actions/tool-executor.schema.ts
2714
- var import_zod8 = require("zod");
2799
+ var import_zod13 = require("zod");
2715
2800
  var toolExecutorSchema = createNodeSchema("ToolExecutor", {
2716
- responseKey: import_zod8.z.string().min(1, "responseKey is required"),
2717
- messagesKey: import_zod8.z.string().min(1, "messagesKey is required"),
2718
- outputKey: import_zod8.z.string().optional()
2801
+ responseKey: import_zod13.z.string().min(1, "responseKey is required"),
2802
+ messagesKey: import_zod13.z.string().min(1, "messagesKey is required"),
2803
+ outputKey: import_zod13.z.string().optional()
2719
2804
  });
2720
2805
 
2721
2806
  // src/actions/wait-for-signal.schema.ts
2722
- var import_zod9 = require("zod");
2807
+ var import_zod14 = require("zod");
2723
2808
  var waitForSignalSchema = createNodeSchema("WaitForSignal", {
2724
- signalName: import_zod9.z.string().min(1, "signalName is required"),
2725
- signalKey: import_zod9.z.string().optional(),
2726
- timeoutMs: import_zod9.z.number().int().positive().optional().default(864e5),
2727
- outputKey: import_zod9.z.string().min(1, "outputKey is required")
2809
+ signalName: import_zod14.z.string().min(1, "signalName is required"),
2810
+ signalKey: import_zod14.z.string().optional(),
2811
+ timeoutMs: import_zod14.z.number().int().positive().optional().default(864e5),
2812
+ outputKey: import_zod14.z.string().min(1, "outputKey is required")
2728
2813
  });
2729
2814
 
2730
2815
  // src/actions/tool-router.schema.ts
2731
- var import_zod10 = require("zod");
2732
- var toolDefinitionSchema2 = import_zod10.z.object({
2733
- name: import_zod10.z.string().min(1),
2734
- description: import_zod10.z.string().min(1),
2735
- inputSchema: import_zod10.z.record(import_zod10.z.string(), import_zod10.z.unknown())
2816
+ var import_zod15 = require("zod");
2817
+ var toolDefinitionSchema2 = import_zod15.z.object({
2818
+ name: import_zod15.z.string().min(1),
2819
+ description: import_zod15.z.string().min(1),
2820
+ inputSchema: import_zod15.z.record(import_zod15.z.string(), import_zod15.z.unknown())
2736
2821
  });
2737
- var ruleSchema = import_zod10.z.object({
2738
- pattern: import_zod10.z.string().min(1),
2739
- toolSets: import_zod10.z.array(import_zod10.z.string().min(1)).min(1)
2822
+ var ruleSchema = import_zod15.z.object({
2823
+ pattern: import_zod15.z.string().min(1),
2824
+ toolSets: import_zod15.z.array(import_zod15.z.string().min(1)).min(1)
2740
2825
  });
2741
2826
  var toolRouterSchema = createNodeSchema("ToolRouter", {
2742
- intentKey: import_zod10.z.string().min(1, "intentKey is required"),
2743
- toolSets: import_zod10.z.record(import_zod10.z.string(), import_zod10.z.array(toolDefinitionSchema2)),
2744
- defaultTools: import_zod10.z.array(import_zod10.z.string()).optional(),
2745
- rules: import_zod10.z.array(ruleSchema).optional(),
2746
- outputKey: import_zod10.z.string().min(1, "outputKey is required")
2827
+ intentKey: import_zod15.z.string().min(1, "intentKey is required"),
2828
+ toolSets: import_zod15.z.record(import_zod15.z.string(), import_zod15.z.array(toolDefinitionSchema2)),
2829
+ defaultTools: import_zod15.z.array(import_zod15.z.string()).optional(),
2830
+ rules: import_zod15.z.array(ruleSchema).optional(),
2831
+ outputKey: import_zod15.z.string().min(1, "outputKey is required")
2747
2832
  });
2748
2833
 
2749
2834
  // src/decorators/streaming-sink.schema.ts
2750
- var import_zod11 = require("zod");
2835
+ var import_zod16 = require("zod");
2751
2836
  var streamingSinkSchema = createNodeSchema("StreamingSink", {
2752
- channelId: import_zod11.z.string().optional(),
2753
- channelKey: import_zod11.z.string().optional()
2837
+ channelId: import_zod16.z.string().optional(),
2838
+ channelKey: import_zod16.z.string().optional()
2754
2839
  }).refine(
2755
2840
  (data) => data.channelId || data.channelKey,
2756
2841
  { message: "Either channelId or channelKey must be provided" }
2757
2842
  );
2758
2843
 
2759
2844
  // src/schemas/validation.ts
2760
- var import_zod12 = require("zod");
2845
+ var import_zod17 = require("zod");
2761
2846
  function zodErrorToConfigurationError(error, nodeType, nodeId) {
2762
2847
  const nodeIdentifier = nodeId ? `${nodeType}:${nodeId}` : nodeType;
2763
2848
  const issues = error.issues.map((issue) => {
@@ -2773,7 +2858,7 @@ function validateConfiguration(schema, config, nodeType, nodeId) {
2773
2858
  try {
2774
2859
  return schema.parse(config);
2775
2860
  } catch (error) {
2776
- if (error instanceof import_zod12.z.ZodError) {
2861
+ if (error instanceof import_zod17.z.ZodError) {
2777
2862
  throw zodErrorToConfigurationError(error, nodeType, nodeId);
2778
2863
  }
2779
2864
  throw error;
@@ -2792,14 +2877,14 @@ function safeValidateConfiguration(schema, config, nodeType, nodeId) {
2792
2877
  }
2793
2878
 
2794
2879
  // src/schemas/tree-definition.schema.ts
2795
- var import_zod13 = require("zod");
2796
- var treeDefSchemaObject = import_zod13.z.object({
2797
- type: import_zod13.z.string().min(1, "Node type is required"),
2798
- id: import_zod13.z.string().optional(),
2799
- name: import_zod13.z.string().optional(),
2800
- props: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.unknown()).optional(),
2801
- children: import_zod13.z.array(
2802
- import_zod13.z.lazy(() => treeDefinitionSchema)
2880
+ var import_zod18 = require("zod");
2881
+ var treeDefSchemaObject = import_zod18.z.object({
2882
+ type: import_zod18.z.string().min(1, "Node type is required"),
2883
+ id: import_zod18.z.string().optional(),
2884
+ name: import_zod18.z.string().optional(),
2885
+ props: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional(),
2886
+ children: import_zod18.z.array(
2887
+ import_zod18.z.lazy(() => treeDefinitionSchema)
2803
2888
  ).optional()
2804
2889
  });
2805
2890
  var treeDefinitionSchema = treeDefSchemaObject;
@@ -2882,6 +2967,11 @@ var SchemaRegistry = class {
2882
2967
  this.register("BrowserAgent", browserAgentSchema);
2883
2968
  this.register("HumanTask", humanTaskSchema);
2884
2969
  this.register("SetVariable", setVariableSchema);
2970
+ this.register("MathOp", mathOpSchema);
2971
+ this.register("ArrayFilter", arrayFilterSchema);
2972
+ this.register("Aggregate", aggregateSchema);
2973
+ this.register("ThresholdCheck", thresholdCheckSchema);
2974
+ this.register("DataTransform", dataTransformSchema);
2885
2975
  this.register("LLMToolCall", llmToolCallSchema);
2886
2976
  this.register("ToolExecutor", toolExecutorSchema);
2887
2977
  this.register("WaitForSignal", waitForSignalSchema);
@@ -3602,6 +3692,547 @@ var SetVariable = class extends ActionNode {
3602
3692
  }
3603
3693
  };
3604
3694
 
3695
+ // src/utilities/math-op.ts
3696
+ function tokenize(expr) {
3697
+ const tokens = [];
3698
+ let i = 0;
3699
+ while (i < expr.length) {
3700
+ const ch = expr[i];
3701
+ if (ch === " " || ch === " ") {
3702
+ i++;
3703
+ continue;
3704
+ }
3705
+ if (ch === "(" || ch === ")") {
3706
+ tokens.push({ type: ch === "(" ? "lparen" : "rparen", value: ch });
3707
+ i++;
3708
+ continue;
3709
+ }
3710
+ if (ch === "+" || ch === "-" || ch === "*" || ch === "/" || ch === "%") {
3711
+ const prev = tokens.length > 0 ? tokens[tokens.length - 1] : void 0;
3712
+ const isUnary = ch === "-" && (tokens.length === 0 || prev?.type === "op" || prev?.type === "lparen");
3713
+ if (isUnary) {
3714
+ let numStr = "-";
3715
+ i++;
3716
+ while (i < expr.length && isDigitOrDot(expr[i])) {
3717
+ numStr += expr[i];
3718
+ i++;
3719
+ }
3720
+ if (numStr === "-") {
3721
+ tokens.push({ type: "number", value: -1 });
3722
+ tokens.push({ type: "op", value: "*" });
3723
+ } else {
3724
+ const num = parseFloat(numStr);
3725
+ if (isNaN(num)) throw new Error(`Invalid number: ${numStr}`);
3726
+ tokens.push({ type: "number", value: num });
3727
+ }
3728
+ continue;
3729
+ }
3730
+ tokens.push({ type: "op", value: ch });
3731
+ i++;
3732
+ continue;
3733
+ }
3734
+ if (isDigitOrDot(ch)) {
3735
+ let numStr = "";
3736
+ while (i < expr.length && isDigitOrDot(expr[i])) {
3737
+ numStr += expr[i];
3738
+ i++;
3739
+ }
3740
+ const num = parseFloat(numStr);
3741
+ if (isNaN(num)) throw new Error(`Invalid number: ${numStr}`);
3742
+ tokens.push({ type: "number", value: num });
3743
+ continue;
3744
+ }
3745
+ throw new Error(`Unexpected character: '${ch}' at position ${i}`);
3746
+ }
3747
+ return tokens;
3748
+ }
3749
+ function isDigitOrDot(ch) {
3750
+ return ch >= "0" && ch <= "9" || ch === ".";
3751
+ }
3752
+ function evaluate(tokens) {
3753
+ let pos = 0;
3754
+ function current() {
3755
+ return tokens[pos];
3756
+ }
3757
+ function parseExpr() {
3758
+ let left = parseTerm();
3759
+ let tok = current();
3760
+ while (tok && tok.type === "op" && (tok.value === "+" || tok.value === "-")) {
3761
+ const op = tok.value;
3762
+ pos++;
3763
+ const right = parseTerm();
3764
+ left = op === "+" ? left + right : left - right;
3765
+ tok = current();
3766
+ }
3767
+ return left;
3768
+ }
3769
+ function parseTerm() {
3770
+ let left = parseFactor();
3771
+ let tok = current();
3772
+ while (tok && tok.type === "op" && (tok.value === "*" || tok.value === "/" || tok.value === "%")) {
3773
+ const op = tok.value;
3774
+ pos++;
3775
+ const right = parseFactor();
3776
+ if ((op === "/" || op === "%") && right === 0) {
3777
+ throw new Error("Division by zero");
3778
+ }
3779
+ if (op === "*") left = left * right;
3780
+ else if (op === "/") left = left / right;
3781
+ else left = left % right;
3782
+ tok = current();
3783
+ }
3784
+ return left;
3785
+ }
3786
+ function parseFactor() {
3787
+ const tok = current();
3788
+ if (!tok) {
3789
+ throw new Error("Unexpected end of expression");
3790
+ }
3791
+ if (tok.type === "number") {
3792
+ pos++;
3793
+ return tok.value;
3794
+ }
3795
+ if (tok.type === "lparen") {
3796
+ pos++;
3797
+ const val = parseExpr();
3798
+ const closing = current();
3799
+ if (!closing || closing.type !== "rparen") {
3800
+ throw new Error("Missing closing parenthesis");
3801
+ }
3802
+ pos++;
3803
+ return val;
3804
+ }
3805
+ throw new Error(`Unexpected token: ${JSON.stringify(tok)}`);
3806
+ }
3807
+ const result = parseExpr();
3808
+ const remaining = current();
3809
+ if (remaining) {
3810
+ throw new Error(`Unexpected token after expression: ${JSON.stringify(remaining)}`);
3811
+ }
3812
+ return result;
3813
+ }
3814
+ function safeEvaluate(expression) {
3815
+ const tokens = tokenize(expression);
3816
+ if (tokens.length === 0) {
3817
+ throw new Error("Empty expression");
3818
+ }
3819
+ return evaluate(tokens);
3820
+ }
3821
+ function applyRounding(value, round, precision) {
3822
+ if (round === "none") return value;
3823
+ const factor = Math.pow(10, precision);
3824
+ const scaled = value * factor;
3825
+ switch (round) {
3826
+ case "round":
3827
+ return Math.round(scaled) / factor;
3828
+ case "floor":
3829
+ return Math.floor(scaled) / factor;
3830
+ case "ceil":
3831
+ return Math.ceil(scaled) / factor;
3832
+ default:
3833
+ return value;
3834
+ }
3835
+ }
3836
+ var MathOp = class extends ActionNode {
3837
+ expression;
3838
+ outputKey;
3839
+ round;
3840
+ precision;
3841
+ constructor(config) {
3842
+ super(config);
3843
+ this.expression = config.expression;
3844
+ this.outputKey = config.outputKey;
3845
+ this.round = config.round ?? "none";
3846
+ this.precision = config.precision ?? 0;
3847
+ }
3848
+ async executeTick(context) {
3849
+ try {
3850
+ const varCtx = {
3851
+ blackboard: context.blackboard,
3852
+ input: context.input,
3853
+ testData: context.testData
3854
+ };
3855
+ const resolved = resolveString(this.expression, varCtx);
3856
+ let result;
3857
+ if (typeof resolved === "number") {
3858
+ result = resolved;
3859
+ } else if (typeof resolved === "string") {
3860
+ result = safeEvaluate(resolved);
3861
+ } else {
3862
+ throw new Error(`Expression resolved to non-numeric type: ${typeof resolved}`);
3863
+ }
3864
+ if (!isFinite(result)) {
3865
+ throw new Error(`Expression result is not finite: ${result}`);
3866
+ }
3867
+ result = applyRounding(result, this.round, this.precision);
3868
+ context.blackboard.set(this.outputKey, result);
3869
+ this.log(`${this.expression} = ${result}`);
3870
+ return "SUCCESS" /* SUCCESS */;
3871
+ } catch (error) {
3872
+ this._lastError = error instanceof Error ? error.message : String(error);
3873
+ this.log(`MathOp failed: ${this._lastError}`);
3874
+ return "FAILURE" /* FAILURE */;
3875
+ }
3876
+ }
3877
+ };
3878
+
3879
+ // src/utilities/array-filter.ts
3880
+ function getFieldValue(item, path2) {
3881
+ if (item === null || item === void 0) return void 0;
3882
+ const parts = path2.split(".");
3883
+ let current = item;
3884
+ for (const part of parts) {
3885
+ if (current === null || current === void 0) return void 0;
3886
+ if (typeof current !== "object") return void 0;
3887
+ current = current[part];
3888
+ }
3889
+ return current;
3890
+ }
3891
+ function evaluateCondition(item, condition, resolvedValue, resolvedRange) {
3892
+ const fieldVal = getFieldValue(item, condition.field);
3893
+ switch (condition.operator) {
3894
+ case "eq":
3895
+ return fieldVal === resolvedValue;
3896
+ case "ne":
3897
+ return fieldVal !== resolvedValue;
3898
+ case "gt":
3899
+ return fieldVal > resolvedValue;
3900
+ case "lt":
3901
+ return fieldVal < resolvedValue;
3902
+ case "gte":
3903
+ return fieldVal >= resolvedValue;
3904
+ case "lte":
3905
+ return fieldVal <= resolvedValue;
3906
+ case "in":
3907
+ if (!Array.isArray(resolvedValue)) return false;
3908
+ return resolvedValue.includes(fieldVal);
3909
+ case "nin":
3910
+ if (!Array.isArray(resolvedValue)) return true;
3911
+ return !resolvedValue.includes(fieldVal);
3912
+ case "exists":
3913
+ const shouldExist = resolvedValue !== false;
3914
+ const exists = fieldVal !== null && fieldVal !== void 0;
3915
+ return shouldExist ? exists : !exists;
3916
+ case "regex": {
3917
+ if (typeof fieldVal !== "string" || typeof resolvedValue !== "string") return false;
3918
+ try {
3919
+ return new RegExp(resolvedValue).test(fieldVal);
3920
+ } catch {
3921
+ return false;
3922
+ }
3923
+ }
3924
+ case "between": {
3925
+ if (!resolvedRange) return false;
3926
+ const [min, max] = resolvedRange;
3927
+ return fieldVal >= min && fieldVal <= max;
3928
+ }
3929
+ case "contains": {
3930
+ if (typeof fieldVal === "string" && typeof resolvedValue === "string") {
3931
+ return fieldVal.includes(resolvedValue);
3932
+ }
3933
+ if (Array.isArray(fieldVal)) {
3934
+ return fieldVal.includes(resolvedValue);
3935
+ }
3936
+ return false;
3937
+ }
3938
+ default:
3939
+ return false;
3940
+ }
3941
+ }
3942
+ var ArrayFilter = class extends ActionNode {
3943
+ input;
3944
+ outputKey;
3945
+ conditions;
3946
+ logic;
3947
+ constructor(config) {
3948
+ super(config);
3949
+ this.input = config.input;
3950
+ this.outputKey = config.outputKey;
3951
+ this.conditions = config.conditions;
3952
+ this.logic = config.logic ?? "and";
3953
+ }
3954
+ async executeTick(context) {
3955
+ try {
3956
+ const varCtx = {
3957
+ blackboard: context.blackboard,
3958
+ input: context.input,
3959
+ testData: context.testData
3960
+ };
3961
+ const inputResolved = typeof this.input === "string" ? resolveValue(this.input, varCtx) : this.input;
3962
+ if (!Array.isArray(inputResolved)) {
3963
+ throw new Error(
3964
+ `Input is not an array: got ${inputResolved === null ? "null" : typeof inputResolved}`
3965
+ );
3966
+ }
3967
+ const resolvedConditions = this.conditions.map((c) => ({
3968
+ condition: c,
3969
+ value: c.value !== void 0 ? resolveValue(c.value, varCtx) : void 0,
3970
+ range: c.range ? [resolveValue(c.range[0], varCtx), resolveValue(c.range[1], varCtx)] : void 0
3971
+ }));
3972
+ const result = inputResolved.filter((item) => {
3973
+ const results = resolvedConditions.map(
3974
+ ({ condition, value, range }) => evaluateCondition(item, condition, value, range)
3975
+ );
3976
+ return this.logic === "and" ? results.every(Boolean) : results.some(Boolean);
3977
+ });
3978
+ context.blackboard.set(this.outputKey, result);
3979
+ this.log(`Filtered ${inputResolved.length} \u2192 ${result.length} items`);
3980
+ return "SUCCESS" /* SUCCESS */;
3981
+ } catch (error) {
3982
+ this._lastError = error instanceof Error ? error.message : String(error);
3983
+ this.log(`ArrayFilter failed: ${this._lastError}`);
3984
+ return "FAILURE" /* FAILURE */;
3985
+ }
3986
+ }
3987
+ };
3988
+
3989
+ // src/utilities/aggregate.ts
3990
+ function getFieldValue2(item, path2) {
3991
+ if (item === null || item === void 0) return void 0;
3992
+ const parts = path2.split(".");
3993
+ let current = item;
3994
+ for (const part of parts) {
3995
+ if (current === null || current === void 0) return void 0;
3996
+ if (typeof current !== "object") return void 0;
3997
+ current = current[part];
3998
+ }
3999
+ return current;
4000
+ }
4001
+ function computeAggregations(items, operations) {
4002
+ const result = {};
4003
+ for (const op of operations) {
4004
+ const key = op.as ?? (op.field ? `${op.type}_${op.field}` : op.type);
4005
+ if (op.type === "count") {
4006
+ result[key] = items.length;
4007
+ continue;
4008
+ }
4009
+ if (!op.field) {
4010
+ result[key] = null;
4011
+ continue;
4012
+ }
4013
+ const values = [];
4014
+ for (const item of items) {
4015
+ const raw = getFieldValue2(item, op.field);
4016
+ const num = typeof raw === "number" ? raw : parseFloat(String(raw));
4017
+ if (!isNaN(num)) values.push(num);
4018
+ }
4019
+ switch (op.type) {
4020
+ case "sum":
4021
+ result[key] = values.reduce((a, b) => a + b, 0);
4022
+ break;
4023
+ case "avg":
4024
+ result[key] = values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;
4025
+ break;
4026
+ case "min":
4027
+ result[key] = values.length > 0 ? Math.min(...values) : null;
4028
+ break;
4029
+ case "max":
4030
+ result[key] = values.length > 0 ? Math.max(...values) : null;
4031
+ break;
4032
+ }
4033
+ }
4034
+ return result;
4035
+ }
4036
+ var Aggregate = class extends ActionNode {
4037
+ input;
4038
+ outputKey;
4039
+ operations;
4040
+ groupBy;
4041
+ constructor(config) {
4042
+ super(config);
4043
+ this.input = config.input;
4044
+ this.outputKey = config.outputKey;
4045
+ this.operations = config.operations;
4046
+ this.groupBy = config.groupBy;
4047
+ }
4048
+ async executeTick(context) {
4049
+ try {
4050
+ const varCtx = {
4051
+ blackboard: context.blackboard,
4052
+ input: context.input,
4053
+ testData: context.testData
4054
+ };
4055
+ const inputResolved = typeof this.input === "string" ? resolveValue(this.input, varCtx) : this.input;
4056
+ if (!Array.isArray(inputResolved)) {
4057
+ throw new Error(
4058
+ `Input is not an array: got ${inputResolved === null ? "null" : typeof inputResolved}`
4059
+ );
4060
+ }
4061
+ if (!this.groupBy) {
4062
+ const result = computeAggregations(inputResolved, this.operations);
4063
+ context.blackboard.set(this.outputKey, result);
4064
+ this.log(`Aggregated ${inputResolved.length} items \u2192 ${JSON.stringify(result)}`);
4065
+ } else {
4066
+ const groups = {};
4067
+ for (const item of inputResolved) {
4068
+ const groupVal = getFieldValue2(item, this.groupBy);
4069
+ const groupKey = groupVal === null || groupVal === void 0 ? "__null__" : String(groupVal);
4070
+ if (!groups[groupKey]) groups[groupKey] = [];
4071
+ groups[groupKey].push(item);
4072
+ }
4073
+ const result = {};
4074
+ for (const [groupKey, groupItems] of Object.entries(groups)) {
4075
+ result[groupKey] = computeAggregations(groupItems, this.operations);
4076
+ }
4077
+ context.blackboard.set(this.outputKey, result);
4078
+ this.log(
4079
+ `Aggregated ${inputResolved.length} items into ${Object.keys(groups).length} groups`
4080
+ );
4081
+ }
4082
+ return "SUCCESS" /* SUCCESS */;
4083
+ } catch (error) {
4084
+ this._lastError = error instanceof Error ? error.message : String(error);
4085
+ this.log(`Aggregate failed: ${this._lastError}`);
4086
+ return "FAILURE" /* FAILURE */;
4087
+ }
4088
+ }
4089
+ };
4090
+
4091
+ // src/utilities/threshold-check.ts
4092
+ function evaluateThreshold(val, threshold, resolvedValue, resolvedRange) {
4093
+ switch (threshold.operator) {
4094
+ case "lte":
4095
+ return val <= resolvedValue;
4096
+ case "lt":
4097
+ return val < resolvedValue;
4098
+ case "gte":
4099
+ return val >= resolvedValue;
4100
+ case "gt":
4101
+ return val > resolvedValue;
4102
+ case "eq":
4103
+ return val === resolvedValue;
4104
+ case "ne":
4105
+ return val !== resolvedValue;
4106
+ case "between": {
4107
+ if (!resolvedRange) return false;
4108
+ return val >= resolvedRange[0] && val <= resolvedRange[1];
4109
+ }
4110
+ default:
4111
+ return false;
4112
+ }
4113
+ }
4114
+ var ThresholdCheck = class extends ActionNode {
4115
+ valueRef;
4116
+ thresholds;
4117
+ outputKey;
4118
+ failOn;
4119
+ constructor(config) {
4120
+ super(config);
4121
+ this.valueRef = config.value;
4122
+ this.thresholds = config.thresholds;
4123
+ this.outputKey = config.outputKey;
4124
+ this.failOn = config.failOn ?? [];
4125
+ }
4126
+ async executeTick(context) {
4127
+ try {
4128
+ const varCtx = {
4129
+ blackboard: context.blackboard,
4130
+ input: context.input,
4131
+ testData: context.testData
4132
+ };
4133
+ const resolved = typeof this.valueRef === "string" ? resolveValue(this.valueRef, varCtx) : this.valueRef;
4134
+ const numValue = typeof resolved === "number" ? resolved : parseFloat(String(resolved));
4135
+ if (isNaN(numValue)) {
4136
+ throw new Error(`Value is not numeric: ${JSON.stringify(resolved)}`);
4137
+ }
4138
+ let matchedLabel = "normal";
4139
+ for (const threshold of this.thresholds) {
4140
+ const thresholdValue = threshold.value !== void 0 ? resolveValue(threshold.value, varCtx) : void 0;
4141
+ const thresholdRange = threshold.range ? [resolveValue(threshold.range[0], varCtx), resolveValue(threshold.range[1], varCtx)] : void 0;
4142
+ if (evaluateThreshold(numValue, threshold, thresholdValue, thresholdRange)) {
4143
+ matchedLabel = threshold.label;
4144
+ break;
4145
+ }
4146
+ }
4147
+ if (this.outputKey) {
4148
+ context.blackboard.set(this.outputKey, matchedLabel);
4149
+ }
4150
+ this.log(`Value ${numValue} \u2192 ${matchedLabel}`);
4151
+ if (this.failOn.includes(matchedLabel)) {
4152
+ this._lastError = `Threshold breach: ${matchedLabel} (value: ${numValue})`;
4153
+ return "FAILURE" /* FAILURE */;
4154
+ }
4155
+ return "SUCCESS" /* SUCCESS */;
4156
+ } catch (error) {
4157
+ this._lastError = error instanceof Error ? error.message : String(error);
4158
+ this.log(`ThresholdCheck failed: ${this._lastError}`);
4159
+ return "FAILURE" /* FAILURE */;
4160
+ }
4161
+ }
4162
+ };
4163
+
4164
+ // src/utilities/data-transform.ts
4165
+ function setNestedValue(obj, path2, value) {
4166
+ const parts = path2.split(".");
4167
+ let current = obj;
4168
+ for (let i = 0; i < parts.length - 1; i++) {
4169
+ const part = parts[i];
4170
+ if (current[part] === void 0 || current[part] === null || typeof current[part] !== "object") {
4171
+ current[part] = {};
4172
+ }
4173
+ current = current[part];
4174
+ }
4175
+ const lastPart = parts[parts.length - 1];
4176
+ if (lastPart !== void 0) {
4177
+ current[lastPart] = value;
4178
+ }
4179
+ }
4180
+ function coerceValue(value, coerce) {
4181
+ switch (coerce) {
4182
+ case "string":
4183
+ return value === null || value === void 0 ? "" : String(value);
4184
+ case "number": {
4185
+ if (typeof value === "number") return value;
4186
+ const num = parseFloat(String(value));
4187
+ if (isNaN(num)) throw new Error(`Cannot coerce "${value}" to number`);
4188
+ return num;
4189
+ }
4190
+ case "boolean":
4191
+ if (typeof value === "boolean") return value;
4192
+ if (value === "true" || value === 1) return true;
4193
+ if (value === "false" || value === 0 || value === "" || value === null || value === void 0) return false;
4194
+ return Boolean(value);
4195
+ default:
4196
+ return value;
4197
+ }
4198
+ }
4199
+ var DataTransform = class extends ActionNode {
4200
+ outputKey;
4201
+ mappings;
4202
+ wrapInArray;
4203
+ constructor(config) {
4204
+ super(config);
4205
+ this.outputKey = config.outputKey;
4206
+ this.mappings = config.mappings;
4207
+ this.wrapInArray = config.wrapInArray ?? false;
4208
+ }
4209
+ async executeTick(context) {
4210
+ try {
4211
+ const varCtx = {
4212
+ blackboard: context.blackboard,
4213
+ input: context.input,
4214
+ testData: context.testData
4215
+ };
4216
+ const result = {};
4217
+ for (const mapping of this.mappings) {
4218
+ let resolved = resolveValue(mapping.value, varCtx);
4219
+ if (mapping.coerce) {
4220
+ resolved = coerceValue(resolved, mapping.coerce);
4221
+ }
4222
+ setNestedValue(result, mapping.target, resolved);
4223
+ }
4224
+ const output = this.wrapInArray ? [result] : result;
4225
+ context.blackboard.set(this.outputKey, output);
4226
+ this.log(`Built object with ${this.mappings.length} fields \u2192 ${this.outputKey}`);
4227
+ return "SUCCESS" /* SUCCESS */;
4228
+ } catch (error) {
4229
+ this._lastError = error instanceof Error ? error.message : String(error);
4230
+ this.log(`DataTransform failed: ${this._lastError}`);
4231
+ return "FAILURE" /* FAILURE */;
4232
+ }
4233
+ }
4234
+ };
4235
+
3605
4236
  // src/integrations/piece-executor.ts
3606
4237
  var PROVIDER_TO_PIECE = {
3607
4238
  // Google services
@@ -5130,6 +5761,11 @@ function registerStandardNodes(registry) {
5130
5761
  registry.register("LogMessage", LogMessage, { category: "action" });
5131
5762
  registry.register("RegexExtract", RegexExtract, { category: "action" });
5132
5763
  registry.register("SetVariable", SetVariable, { category: "action" });
5764
+ registry.register("MathOp", MathOp, { category: "action" });
5765
+ registry.register("ArrayFilter", ArrayFilter, { category: "action" });
5766
+ registry.register("Aggregate", Aggregate, { category: "action" });
5767
+ registry.register("ThresholdCheck", ThresholdCheck, { category: "action" });
5768
+ registry.register("DataTransform", DataTransform, { category: "action" });
5133
5769
  registry.register("IntegrationAction", IntegrationAction, { category: "action" });
5134
5770
  registry.register("PythonScript", PythonScript, { category: "action" });
5135
5771
  registry.register("ParseFile", ParseFile, { category: "action" });
@@ -5980,7 +6616,9 @@ function createObservabilitySinkHandler(config = {}) {
5980
6616
  // Annotate the CommonJS export names for ESM import in node:
5981
6617
  0 && (module.exports = {
5982
6618
  ActionNode,
6619
+ Aggregate,
5983
6620
  AlwaysCondition,
6621
+ ArrayFilter,
5984
6622
  BaseNode,
5985
6623
  BehaviorTree,
5986
6624
  BrowserAgent,
@@ -5993,6 +6631,7 @@ function createObservabilitySinkHandler(config = {}) {
5993
6631
  ConfigValidationError,
5994
6632
  ConfigurationError,
5995
6633
  CounterAction,
6634
+ DataTransform,
5996
6635
  DecoratorNode,
5997
6636
  Delay,
5998
6637
  ExecutionTracker,
@@ -6011,6 +6650,7 @@ function createObservabilitySinkHandler(config = {}) {
6011
6650
  LLMChat,
6012
6651
  LLMToolCall,
6013
6652
  LogMessage,
6653
+ MathOp,
6014
6654
  MemoryDataStore,
6015
6655
  MemorySequence,
6016
6656
  MockAction,
@@ -6042,6 +6682,7 @@ function createObservabilitySinkHandler(config = {}) {
6042
6682
  StructureValidationError,
6043
6683
  SubTree,
6044
6684
  SuccessNode,
6685
+ ThresholdCheck,
6045
6686
  Timeout,
6046
6687
  ToolExecutor,
6047
6688
  ToolRouter,
@@ -6072,6 +6713,7 @@ function createObservabilitySinkHandler(config = {}) {
6072
6713
  registerStandardNodes,
6073
6714
  resolveString,
6074
6715
  resolveValue,
6716
+ safeEvaluate,
6075
6717
  safeValidateConfiguration,
6076
6718
  schemaRegistry,
6077
6719
  semanticValidator,