@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.js CHANGED
@@ -2548,74 +2548,153 @@ var setVariableSchema = createNodeSchema("SetVariable", {
2548
2548
  value: z6.unknown()
2549
2549
  });
2550
2550
 
2551
- // src/actions/llm-tool-call.schema.ts
2551
+ // src/utilities/math-op.schema.ts
2552
2552
  import { z as z7 } from "zod";
2553
- var toolDefinitionSchema = z7.object({
2554
- name: z7.string().min(1),
2555
- description: z7.string().min(1),
2556
- inputSchema: z7.record(z7.string(), z7.unknown())
2553
+ var mathOpSchema = createNodeSchema("MathOp", {
2554
+ expression: z7.string().min(1, "expression is required"),
2555
+ outputKey: z7.string().min(1, "outputKey is required"),
2556
+ round: z7.enum(["none", "round", "floor", "ceil"]).optional(),
2557
+ precision: z7.number().int().nonnegative().optional()
2558
+ });
2559
+
2560
+ // src/utilities/array-filter.schema.ts
2561
+ import { z as z8 } from "zod";
2562
+ var filterConditionSchema = z8.object({
2563
+ field: z8.string().min(1),
2564
+ operator: z8.enum([
2565
+ "eq",
2566
+ "ne",
2567
+ "gt",
2568
+ "lt",
2569
+ "gte",
2570
+ "lte",
2571
+ "in",
2572
+ "nin",
2573
+ "exists",
2574
+ "regex",
2575
+ "between",
2576
+ "contains"
2577
+ ]),
2578
+ value: z8.unknown().optional(),
2579
+ range: z8.tuple([z8.unknown(), z8.unknown()]).optional()
2580
+ });
2581
+ var arrayFilterSchema = createNodeSchema("ArrayFilter", {
2582
+ input: z8.string().min(1, "input is required"),
2583
+ outputKey: z8.string().min(1, "outputKey is required"),
2584
+ conditions: z8.array(filterConditionSchema).min(1, "at least one condition is required"),
2585
+ logic: z8.enum(["and", "or"]).optional()
2586
+ });
2587
+
2588
+ // src/utilities/aggregate.schema.ts
2589
+ import { z as z9 } from "zod";
2590
+ var aggregateOperationSchema = z9.object({
2591
+ type: z9.enum(["count", "sum", "avg", "min", "max"]),
2592
+ field: z9.string().optional(),
2593
+ as: z9.string().optional()
2594
+ });
2595
+ var aggregateSchema = createNodeSchema("Aggregate", {
2596
+ input: z9.string().min(1, "input is required"),
2597
+ outputKey: z9.string().min(1, "outputKey is required"),
2598
+ operations: z9.array(aggregateOperationSchema).min(1, "at least one operation is required"),
2599
+ groupBy: z9.string().optional()
2600
+ });
2601
+
2602
+ // src/utilities/threshold-check.schema.ts
2603
+ import { z as z10 } from "zod";
2604
+ var thresholdLevelSchema = z10.object({
2605
+ operator: z10.enum(["lte", "lt", "gte", "gt", "eq", "ne", "between"]),
2606
+ value: z10.unknown().optional(),
2607
+ range: z10.tuple([z10.unknown(), z10.unknown()]).optional(),
2608
+ label: z10.string().min(1, "label is required")
2609
+ });
2610
+ var thresholdCheckSchema = createNodeSchema("ThresholdCheck", {
2611
+ value: z10.unknown(),
2612
+ thresholds: z10.array(thresholdLevelSchema).min(1, "at least one threshold is required"),
2613
+ outputKey: z10.string().optional(),
2614
+ failOn: z10.array(z10.string()).optional()
2615
+ });
2616
+
2617
+ // src/utilities/data-transform.schema.ts
2618
+ import { z as z11 } from "zod";
2619
+ var transformMappingSchema = z11.object({
2620
+ target: z11.string().min(1, "target is required"),
2621
+ value: z11.unknown(),
2622
+ coerce: z11.enum(["string", "number", "boolean"]).optional()
2623
+ });
2624
+ var dataTransformSchema = createNodeSchema("DataTransform", {
2625
+ outputKey: z11.string().min(1, "outputKey is required"),
2626
+ mappings: z11.array(transformMappingSchema).min(1, "at least one mapping is required"),
2627
+ wrapInArray: z11.boolean().optional()
2628
+ });
2629
+
2630
+ // src/actions/llm-tool-call.schema.ts
2631
+ import { z as z12 } from "zod";
2632
+ var toolDefinitionSchema = z12.object({
2633
+ name: z12.string().min(1),
2634
+ description: z12.string().min(1),
2635
+ inputSchema: z12.record(z12.string(), z12.unknown())
2557
2636
  });
2558
2637
  var llmToolCallSchema = createNodeSchema("LLMToolCall", {
2559
- provider: z7.enum(["anthropic", "openai", "google", "ollama"]),
2560
- model: z7.string().min(1, "Model is required"),
2561
- systemPrompt: z7.string().optional(),
2562
- messagesKey: z7.string().min(1, "messagesKey is required"),
2563
- userMessageKey: z7.string().optional(),
2564
- toolsKey: z7.string().optional(),
2565
- tools: z7.array(toolDefinitionSchema).optional(),
2566
- temperature: z7.number().min(0).max(2).optional(),
2567
- maxTokens: z7.number().int().positive().optional(),
2568
- outputKey: z7.string().min(1, "outputKey is required")
2638
+ provider: z12.enum(["anthropic", "openai", "google", "ollama"]),
2639
+ model: z12.string().min(1, "Model is required"),
2640
+ systemPrompt: z12.string().optional(),
2641
+ messagesKey: z12.string().min(1, "messagesKey is required"),
2642
+ userMessageKey: z12.string().optional(),
2643
+ toolsKey: z12.string().optional(),
2644
+ tools: z12.array(toolDefinitionSchema).optional(),
2645
+ temperature: z12.number().min(0).max(2).optional(),
2646
+ maxTokens: z12.number().int().positive().optional(),
2647
+ outputKey: z12.string().min(1, "outputKey is required")
2569
2648
  });
2570
2649
 
2571
2650
  // src/actions/tool-executor.schema.ts
2572
- import { z as z8 } from "zod";
2651
+ import { z as z13 } from "zod";
2573
2652
  var toolExecutorSchema = createNodeSchema("ToolExecutor", {
2574
- responseKey: z8.string().min(1, "responseKey is required"),
2575
- messagesKey: z8.string().min(1, "messagesKey is required"),
2576
- outputKey: z8.string().optional()
2653
+ responseKey: z13.string().min(1, "responseKey is required"),
2654
+ messagesKey: z13.string().min(1, "messagesKey is required"),
2655
+ outputKey: z13.string().optional()
2577
2656
  });
2578
2657
 
2579
2658
  // src/actions/wait-for-signal.schema.ts
2580
- import { z as z9 } from "zod";
2659
+ import { z as z14 } from "zod";
2581
2660
  var waitForSignalSchema = createNodeSchema("WaitForSignal", {
2582
- signalName: z9.string().min(1, "signalName is required"),
2583
- signalKey: z9.string().optional(),
2584
- timeoutMs: z9.number().int().positive().optional().default(864e5),
2585
- outputKey: z9.string().min(1, "outputKey is required")
2661
+ signalName: z14.string().min(1, "signalName is required"),
2662
+ signalKey: z14.string().optional(),
2663
+ timeoutMs: z14.number().int().positive().optional().default(864e5),
2664
+ outputKey: z14.string().min(1, "outputKey is required")
2586
2665
  });
2587
2666
 
2588
2667
  // src/actions/tool-router.schema.ts
2589
- import { z as z10 } from "zod";
2590
- var toolDefinitionSchema2 = z10.object({
2591
- name: z10.string().min(1),
2592
- description: z10.string().min(1),
2593
- inputSchema: z10.record(z10.string(), z10.unknown())
2668
+ import { z as z15 } from "zod";
2669
+ var toolDefinitionSchema2 = z15.object({
2670
+ name: z15.string().min(1),
2671
+ description: z15.string().min(1),
2672
+ inputSchema: z15.record(z15.string(), z15.unknown())
2594
2673
  });
2595
- var ruleSchema = z10.object({
2596
- pattern: z10.string().min(1),
2597
- toolSets: z10.array(z10.string().min(1)).min(1)
2674
+ var ruleSchema = z15.object({
2675
+ pattern: z15.string().min(1),
2676
+ toolSets: z15.array(z15.string().min(1)).min(1)
2598
2677
  });
2599
2678
  var toolRouterSchema = createNodeSchema("ToolRouter", {
2600
- intentKey: z10.string().min(1, "intentKey is required"),
2601
- toolSets: z10.record(z10.string(), z10.array(toolDefinitionSchema2)),
2602
- defaultTools: z10.array(z10.string()).optional(),
2603
- rules: z10.array(ruleSchema).optional(),
2604
- outputKey: z10.string().min(1, "outputKey is required")
2679
+ intentKey: z15.string().min(1, "intentKey is required"),
2680
+ toolSets: z15.record(z15.string(), z15.array(toolDefinitionSchema2)),
2681
+ defaultTools: z15.array(z15.string()).optional(),
2682
+ rules: z15.array(ruleSchema).optional(),
2683
+ outputKey: z15.string().min(1, "outputKey is required")
2605
2684
  });
2606
2685
 
2607
2686
  // src/decorators/streaming-sink.schema.ts
2608
- import { z as z11 } from "zod";
2687
+ import { z as z16 } from "zod";
2609
2688
  var streamingSinkSchema = createNodeSchema("StreamingSink", {
2610
- channelId: z11.string().optional(),
2611
- channelKey: z11.string().optional()
2689
+ channelId: z16.string().optional(),
2690
+ channelKey: z16.string().optional()
2612
2691
  }).refine(
2613
2692
  (data) => data.channelId || data.channelKey,
2614
2693
  { message: "Either channelId or channelKey must be provided" }
2615
2694
  );
2616
2695
 
2617
2696
  // src/schemas/validation.ts
2618
- import { z as z12 } from "zod";
2697
+ import { z as z17 } from "zod";
2619
2698
  function zodErrorToConfigurationError(error, nodeType, nodeId) {
2620
2699
  const nodeIdentifier = nodeId ? `${nodeType}:${nodeId}` : nodeType;
2621
2700
  const issues = error.issues.map((issue) => {
@@ -2631,7 +2710,7 @@ function validateConfiguration(schema, config, nodeType, nodeId) {
2631
2710
  try {
2632
2711
  return schema.parse(config);
2633
2712
  } catch (error) {
2634
- if (error instanceof z12.ZodError) {
2713
+ if (error instanceof z17.ZodError) {
2635
2714
  throw zodErrorToConfigurationError(error, nodeType, nodeId);
2636
2715
  }
2637
2716
  throw error;
@@ -2650,14 +2729,14 @@ function safeValidateConfiguration(schema, config, nodeType, nodeId) {
2650
2729
  }
2651
2730
 
2652
2731
  // src/schemas/tree-definition.schema.ts
2653
- import { z as z13 } from "zod";
2654
- var treeDefSchemaObject = z13.object({
2655
- type: z13.string().min(1, "Node type is required"),
2656
- id: z13.string().optional(),
2657
- name: z13.string().optional(),
2658
- props: z13.record(z13.string(), z13.unknown()).optional(),
2659
- children: z13.array(
2660
- z13.lazy(() => treeDefinitionSchema)
2732
+ import { z as z18 } from "zod";
2733
+ var treeDefSchemaObject = z18.object({
2734
+ type: z18.string().min(1, "Node type is required"),
2735
+ id: z18.string().optional(),
2736
+ name: z18.string().optional(),
2737
+ props: z18.record(z18.string(), z18.unknown()).optional(),
2738
+ children: z18.array(
2739
+ z18.lazy(() => treeDefinitionSchema)
2661
2740
  ).optional()
2662
2741
  });
2663
2742
  var treeDefinitionSchema = treeDefSchemaObject;
@@ -2740,6 +2819,11 @@ var SchemaRegistry = class {
2740
2819
  this.register("BrowserAgent", browserAgentSchema);
2741
2820
  this.register("HumanTask", humanTaskSchema);
2742
2821
  this.register("SetVariable", setVariableSchema);
2822
+ this.register("MathOp", mathOpSchema);
2823
+ this.register("ArrayFilter", arrayFilterSchema);
2824
+ this.register("Aggregate", aggregateSchema);
2825
+ this.register("ThresholdCheck", thresholdCheckSchema);
2826
+ this.register("DataTransform", dataTransformSchema);
2743
2827
  this.register("LLMToolCall", llmToolCallSchema);
2744
2828
  this.register("ToolExecutor", toolExecutorSchema);
2745
2829
  this.register("WaitForSignal", waitForSignalSchema);
@@ -3460,6 +3544,547 @@ var SetVariable = class extends ActionNode {
3460
3544
  }
3461
3545
  };
3462
3546
 
3547
+ // src/utilities/math-op.ts
3548
+ function tokenize(expr) {
3549
+ const tokens = [];
3550
+ let i = 0;
3551
+ while (i < expr.length) {
3552
+ const ch = expr[i];
3553
+ if (ch === " " || ch === " ") {
3554
+ i++;
3555
+ continue;
3556
+ }
3557
+ if (ch === "(" || ch === ")") {
3558
+ tokens.push({ type: ch === "(" ? "lparen" : "rparen", value: ch });
3559
+ i++;
3560
+ continue;
3561
+ }
3562
+ if (ch === "+" || ch === "-" || ch === "*" || ch === "/" || ch === "%") {
3563
+ const prev = tokens.length > 0 ? tokens[tokens.length - 1] : void 0;
3564
+ const isUnary = ch === "-" && (tokens.length === 0 || prev?.type === "op" || prev?.type === "lparen");
3565
+ if (isUnary) {
3566
+ let numStr = "-";
3567
+ i++;
3568
+ while (i < expr.length && isDigitOrDot(expr[i])) {
3569
+ numStr += expr[i];
3570
+ i++;
3571
+ }
3572
+ if (numStr === "-") {
3573
+ tokens.push({ type: "number", value: -1 });
3574
+ tokens.push({ type: "op", value: "*" });
3575
+ } else {
3576
+ const num = parseFloat(numStr);
3577
+ if (isNaN(num)) throw new Error(`Invalid number: ${numStr}`);
3578
+ tokens.push({ type: "number", value: num });
3579
+ }
3580
+ continue;
3581
+ }
3582
+ tokens.push({ type: "op", value: ch });
3583
+ i++;
3584
+ continue;
3585
+ }
3586
+ if (isDigitOrDot(ch)) {
3587
+ let numStr = "";
3588
+ while (i < expr.length && isDigitOrDot(expr[i])) {
3589
+ numStr += expr[i];
3590
+ i++;
3591
+ }
3592
+ const num = parseFloat(numStr);
3593
+ if (isNaN(num)) throw new Error(`Invalid number: ${numStr}`);
3594
+ tokens.push({ type: "number", value: num });
3595
+ continue;
3596
+ }
3597
+ throw new Error(`Unexpected character: '${ch}' at position ${i}`);
3598
+ }
3599
+ return tokens;
3600
+ }
3601
+ function isDigitOrDot(ch) {
3602
+ return ch >= "0" && ch <= "9" || ch === ".";
3603
+ }
3604
+ function evaluate(tokens) {
3605
+ let pos = 0;
3606
+ function current() {
3607
+ return tokens[pos];
3608
+ }
3609
+ function parseExpr() {
3610
+ let left = parseTerm();
3611
+ let tok = current();
3612
+ while (tok && tok.type === "op" && (tok.value === "+" || tok.value === "-")) {
3613
+ const op = tok.value;
3614
+ pos++;
3615
+ const right = parseTerm();
3616
+ left = op === "+" ? left + right : left - right;
3617
+ tok = current();
3618
+ }
3619
+ return left;
3620
+ }
3621
+ function parseTerm() {
3622
+ let left = parseFactor();
3623
+ let tok = current();
3624
+ while (tok && tok.type === "op" && (tok.value === "*" || tok.value === "/" || tok.value === "%")) {
3625
+ const op = tok.value;
3626
+ pos++;
3627
+ const right = parseFactor();
3628
+ if ((op === "/" || op === "%") && right === 0) {
3629
+ throw new Error("Division by zero");
3630
+ }
3631
+ if (op === "*") left = left * right;
3632
+ else if (op === "/") left = left / right;
3633
+ else left = left % right;
3634
+ tok = current();
3635
+ }
3636
+ return left;
3637
+ }
3638
+ function parseFactor() {
3639
+ const tok = current();
3640
+ if (!tok) {
3641
+ throw new Error("Unexpected end of expression");
3642
+ }
3643
+ if (tok.type === "number") {
3644
+ pos++;
3645
+ return tok.value;
3646
+ }
3647
+ if (tok.type === "lparen") {
3648
+ pos++;
3649
+ const val = parseExpr();
3650
+ const closing = current();
3651
+ if (!closing || closing.type !== "rparen") {
3652
+ throw new Error("Missing closing parenthesis");
3653
+ }
3654
+ pos++;
3655
+ return val;
3656
+ }
3657
+ throw new Error(`Unexpected token: ${JSON.stringify(tok)}`);
3658
+ }
3659
+ const result = parseExpr();
3660
+ const remaining = current();
3661
+ if (remaining) {
3662
+ throw new Error(`Unexpected token after expression: ${JSON.stringify(remaining)}`);
3663
+ }
3664
+ return result;
3665
+ }
3666
+ function safeEvaluate(expression) {
3667
+ const tokens = tokenize(expression);
3668
+ if (tokens.length === 0) {
3669
+ throw new Error("Empty expression");
3670
+ }
3671
+ return evaluate(tokens);
3672
+ }
3673
+ function applyRounding(value, round, precision) {
3674
+ if (round === "none") return value;
3675
+ const factor = Math.pow(10, precision);
3676
+ const scaled = value * factor;
3677
+ switch (round) {
3678
+ case "round":
3679
+ return Math.round(scaled) / factor;
3680
+ case "floor":
3681
+ return Math.floor(scaled) / factor;
3682
+ case "ceil":
3683
+ return Math.ceil(scaled) / factor;
3684
+ default:
3685
+ return value;
3686
+ }
3687
+ }
3688
+ var MathOp = class extends ActionNode {
3689
+ expression;
3690
+ outputKey;
3691
+ round;
3692
+ precision;
3693
+ constructor(config) {
3694
+ super(config);
3695
+ this.expression = config.expression;
3696
+ this.outputKey = config.outputKey;
3697
+ this.round = config.round ?? "none";
3698
+ this.precision = config.precision ?? 0;
3699
+ }
3700
+ async executeTick(context) {
3701
+ try {
3702
+ const varCtx = {
3703
+ blackboard: context.blackboard,
3704
+ input: context.input,
3705
+ testData: context.testData
3706
+ };
3707
+ const resolved = resolveString(this.expression, varCtx);
3708
+ let result;
3709
+ if (typeof resolved === "number") {
3710
+ result = resolved;
3711
+ } else if (typeof resolved === "string") {
3712
+ result = safeEvaluate(resolved);
3713
+ } else {
3714
+ throw new Error(`Expression resolved to non-numeric type: ${typeof resolved}`);
3715
+ }
3716
+ if (!isFinite(result)) {
3717
+ throw new Error(`Expression result is not finite: ${result}`);
3718
+ }
3719
+ result = applyRounding(result, this.round, this.precision);
3720
+ context.blackboard.set(this.outputKey, result);
3721
+ this.log(`${this.expression} = ${result}`);
3722
+ return "SUCCESS" /* SUCCESS */;
3723
+ } catch (error) {
3724
+ this._lastError = error instanceof Error ? error.message : String(error);
3725
+ this.log(`MathOp failed: ${this._lastError}`);
3726
+ return "FAILURE" /* FAILURE */;
3727
+ }
3728
+ }
3729
+ };
3730
+
3731
+ // src/utilities/array-filter.ts
3732
+ function getFieldValue(item, path2) {
3733
+ if (item === null || item === void 0) return void 0;
3734
+ const parts = path2.split(".");
3735
+ let current = item;
3736
+ for (const part of parts) {
3737
+ if (current === null || current === void 0) return void 0;
3738
+ if (typeof current !== "object") return void 0;
3739
+ current = current[part];
3740
+ }
3741
+ return current;
3742
+ }
3743
+ function evaluateCondition(item, condition, resolvedValue, resolvedRange) {
3744
+ const fieldVal = getFieldValue(item, condition.field);
3745
+ switch (condition.operator) {
3746
+ case "eq":
3747
+ return fieldVal === resolvedValue;
3748
+ case "ne":
3749
+ return fieldVal !== resolvedValue;
3750
+ case "gt":
3751
+ return fieldVal > resolvedValue;
3752
+ case "lt":
3753
+ return fieldVal < resolvedValue;
3754
+ case "gte":
3755
+ return fieldVal >= resolvedValue;
3756
+ case "lte":
3757
+ return fieldVal <= resolvedValue;
3758
+ case "in":
3759
+ if (!Array.isArray(resolvedValue)) return false;
3760
+ return resolvedValue.includes(fieldVal);
3761
+ case "nin":
3762
+ if (!Array.isArray(resolvedValue)) return true;
3763
+ return !resolvedValue.includes(fieldVal);
3764
+ case "exists":
3765
+ const shouldExist = resolvedValue !== false;
3766
+ const exists = fieldVal !== null && fieldVal !== void 0;
3767
+ return shouldExist ? exists : !exists;
3768
+ case "regex": {
3769
+ if (typeof fieldVal !== "string" || typeof resolvedValue !== "string") return false;
3770
+ try {
3771
+ return new RegExp(resolvedValue).test(fieldVal);
3772
+ } catch {
3773
+ return false;
3774
+ }
3775
+ }
3776
+ case "between": {
3777
+ if (!resolvedRange) return false;
3778
+ const [min, max] = resolvedRange;
3779
+ return fieldVal >= min && fieldVal <= max;
3780
+ }
3781
+ case "contains": {
3782
+ if (typeof fieldVal === "string" && typeof resolvedValue === "string") {
3783
+ return fieldVal.includes(resolvedValue);
3784
+ }
3785
+ if (Array.isArray(fieldVal)) {
3786
+ return fieldVal.includes(resolvedValue);
3787
+ }
3788
+ return false;
3789
+ }
3790
+ default:
3791
+ return false;
3792
+ }
3793
+ }
3794
+ var ArrayFilter = class extends ActionNode {
3795
+ input;
3796
+ outputKey;
3797
+ conditions;
3798
+ logic;
3799
+ constructor(config) {
3800
+ super(config);
3801
+ this.input = config.input;
3802
+ this.outputKey = config.outputKey;
3803
+ this.conditions = config.conditions;
3804
+ this.logic = config.logic ?? "and";
3805
+ }
3806
+ async executeTick(context) {
3807
+ try {
3808
+ const varCtx = {
3809
+ blackboard: context.blackboard,
3810
+ input: context.input,
3811
+ testData: context.testData
3812
+ };
3813
+ const inputResolved = typeof this.input === "string" ? resolveValue(this.input, varCtx) : this.input;
3814
+ if (!Array.isArray(inputResolved)) {
3815
+ throw new Error(
3816
+ `Input is not an array: got ${inputResolved === null ? "null" : typeof inputResolved}`
3817
+ );
3818
+ }
3819
+ const resolvedConditions = this.conditions.map((c) => ({
3820
+ condition: c,
3821
+ value: c.value !== void 0 ? resolveValue(c.value, varCtx) : void 0,
3822
+ range: c.range ? [resolveValue(c.range[0], varCtx), resolveValue(c.range[1], varCtx)] : void 0
3823
+ }));
3824
+ const result = inputResolved.filter((item) => {
3825
+ const results = resolvedConditions.map(
3826
+ ({ condition, value, range }) => evaluateCondition(item, condition, value, range)
3827
+ );
3828
+ return this.logic === "and" ? results.every(Boolean) : results.some(Boolean);
3829
+ });
3830
+ context.blackboard.set(this.outputKey, result);
3831
+ this.log(`Filtered ${inputResolved.length} \u2192 ${result.length} items`);
3832
+ return "SUCCESS" /* SUCCESS */;
3833
+ } catch (error) {
3834
+ this._lastError = error instanceof Error ? error.message : String(error);
3835
+ this.log(`ArrayFilter failed: ${this._lastError}`);
3836
+ return "FAILURE" /* FAILURE */;
3837
+ }
3838
+ }
3839
+ };
3840
+
3841
+ // src/utilities/aggregate.ts
3842
+ function getFieldValue2(item, path2) {
3843
+ if (item === null || item === void 0) return void 0;
3844
+ const parts = path2.split(".");
3845
+ let current = item;
3846
+ for (const part of parts) {
3847
+ if (current === null || current === void 0) return void 0;
3848
+ if (typeof current !== "object") return void 0;
3849
+ current = current[part];
3850
+ }
3851
+ return current;
3852
+ }
3853
+ function computeAggregations(items, operations) {
3854
+ const result = {};
3855
+ for (const op of operations) {
3856
+ const key = op.as ?? (op.field ? `${op.type}_${op.field}` : op.type);
3857
+ if (op.type === "count") {
3858
+ result[key] = items.length;
3859
+ continue;
3860
+ }
3861
+ if (!op.field) {
3862
+ result[key] = null;
3863
+ continue;
3864
+ }
3865
+ const values = [];
3866
+ for (const item of items) {
3867
+ const raw = getFieldValue2(item, op.field);
3868
+ const num = typeof raw === "number" ? raw : parseFloat(String(raw));
3869
+ if (!isNaN(num)) values.push(num);
3870
+ }
3871
+ switch (op.type) {
3872
+ case "sum":
3873
+ result[key] = values.reduce((a, b) => a + b, 0);
3874
+ break;
3875
+ case "avg":
3876
+ result[key] = values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0;
3877
+ break;
3878
+ case "min":
3879
+ result[key] = values.length > 0 ? Math.min(...values) : null;
3880
+ break;
3881
+ case "max":
3882
+ result[key] = values.length > 0 ? Math.max(...values) : null;
3883
+ break;
3884
+ }
3885
+ }
3886
+ return result;
3887
+ }
3888
+ var Aggregate = class extends ActionNode {
3889
+ input;
3890
+ outputKey;
3891
+ operations;
3892
+ groupBy;
3893
+ constructor(config) {
3894
+ super(config);
3895
+ this.input = config.input;
3896
+ this.outputKey = config.outputKey;
3897
+ this.operations = config.operations;
3898
+ this.groupBy = config.groupBy;
3899
+ }
3900
+ async executeTick(context) {
3901
+ try {
3902
+ const varCtx = {
3903
+ blackboard: context.blackboard,
3904
+ input: context.input,
3905
+ testData: context.testData
3906
+ };
3907
+ const inputResolved = typeof this.input === "string" ? resolveValue(this.input, varCtx) : this.input;
3908
+ if (!Array.isArray(inputResolved)) {
3909
+ throw new Error(
3910
+ `Input is not an array: got ${inputResolved === null ? "null" : typeof inputResolved}`
3911
+ );
3912
+ }
3913
+ if (!this.groupBy) {
3914
+ const result = computeAggregations(inputResolved, this.operations);
3915
+ context.blackboard.set(this.outputKey, result);
3916
+ this.log(`Aggregated ${inputResolved.length} items \u2192 ${JSON.stringify(result)}`);
3917
+ } else {
3918
+ const groups = {};
3919
+ for (const item of inputResolved) {
3920
+ const groupVal = getFieldValue2(item, this.groupBy);
3921
+ const groupKey = groupVal === null || groupVal === void 0 ? "__null__" : String(groupVal);
3922
+ if (!groups[groupKey]) groups[groupKey] = [];
3923
+ groups[groupKey].push(item);
3924
+ }
3925
+ const result = {};
3926
+ for (const [groupKey, groupItems] of Object.entries(groups)) {
3927
+ result[groupKey] = computeAggregations(groupItems, this.operations);
3928
+ }
3929
+ context.blackboard.set(this.outputKey, result);
3930
+ this.log(
3931
+ `Aggregated ${inputResolved.length} items into ${Object.keys(groups).length} groups`
3932
+ );
3933
+ }
3934
+ return "SUCCESS" /* SUCCESS */;
3935
+ } catch (error) {
3936
+ this._lastError = error instanceof Error ? error.message : String(error);
3937
+ this.log(`Aggregate failed: ${this._lastError}`);
3938
+ return "FAILURE" /* FAILURE */;
3939
+ }
3940
+ }
3941
+ };
3942
+
3943
+ // src/utilities/threshold-check.ts
3944
+ function evaluateThreshold(val, threshold, resolvedValue, resolvedRange) {
3945
+ switch (threshold.operator) {
3946
+ case "lte":
3947
+ return val <= resolvedValue;
3948
+ case "lt":
3949
+ return val < resolvedValue;
3950
+ case "gte":
3951
+ return val >= resolvedValue;
3952
+ case "gt":
3953
+ return val > resolvedValue;
3954
+ case "eq":
3955
+ return val === resolvedValue;
3956
+ case "ne":
3957
+ return val !== resolvedValue;
3958
+ case "between": {
3959
+ if (!resolvedRange) return false;
3960
+ return val >= resolvedRange[0] && val <= resolvedRange[1];
3961
+ }
3962
+ default:
3963
+ return false;
3964
+ }
3965
+ }
3966
+ var ThresholdCheck = class extends ActionNode {
3967
+ valueRef;
3968
+ thresholds;
3969
+ outputKey;
3970
+ failOn;
3971
+ constructor(config) {
3972
+ super(config);
3973
+ this.valueRef = config.value;
3974
+ this.thresholds = config.thresholds;
3975
+ this.outputKey = config.outputKey;
3976
+ this.failOn = config.failOn ?? [];
3977
+ }
3978
+ async executeTick(context) {
3979
+ try {
3980
+ const varCtx = {
3981
+ blackboard: context.blackboard,
3982
+ input: context.input,
3983
+ testData: context.testData
3984
+ };
3985
+ const resolved = typeof this.valueRef === "string" ? resolveValue(this.valueRef, varCtx) : this.valueRef;
3986
+ const numValue = typeof resolved === "number" ? resolved : parseFloat(String(resolved));
3987
+ if (isNaN(numValue)) {
3988
+ throw new Error(`Value is not numeric: ${JSON.stringify(resolved)}`);
3989
+ }
3990
+ let matchedLabel = "normal";
3991
+ for (const threshold of this.thresholds) {
3992
+ const thresholdValue = threshold.value !== void 0 ? resolveValue(threshold.value, varCtx) : void 0;
3993
+ const thresholdRange = threshold.range ? [resolveValue(threshold.range[0], varCtx), resolveValue(threshold.range[1], varCtx)] : void 0;
3994
+ if (evaluateThreshold(numValue, threshold, thresholdValue, thresholdRange)) {
3995
+ matchedLabel = threshold.label;
3996
+ break;
3997
+ }
3998
+ }
3999
+ if (this.outputKey) {
4000
+ context.blackboard.set(this.outputKey, matchedLabel);
4001
+ }
4002
+ this.log(`Value ${numValue} \u2192 ${matchedLabel}`);
4003
+ if (this.failOn.includes(matchedLabel)) {
4004
+ this._lastError = `Threshold breach: ${matchedLabel} (value: ${numValue})`;
4005
+ return "FAILURE" /* FAILURE */;
4006
+ }
4007
+ return "SUCCESS" /* SUCCESS */;
4008
+ } catch (error) {
4009
+ this._lastError = error instanceof Error ? error.message : String(error);
4010
+ this.log(`ThresholdCheck failed: ${this._lastError}`);
4011
+ return "FAILURE" /* FAILURE */;
4012
+ }
4013
+ }
4014
+ };
4015
+
4016
+ // src/utilities/data-transform.ts
4017
+ function setNestedValue(obj, path2, value) {
4018
+ const parts = path2.split(".");
4019
+ let current = obj;
4020
+ for (let i = 0; i < parts.length - 1; i++) {
4021
+ const part = parts[i];
4022
+ if (current[part] === void 0 || current[part] === null || typeof current[part] !== "object") {
4023
+ current[part] = {};
4024
+ }
4025
+ current = current[part];
4026
+ }
4027
+ const lastPart = parts[parts.length - 1];
4028
+ if (lastPart !== void 0) {
4029
+ current[lastPart] = value;
4030
+ }
4031
+ }
4032
+ function coerceValue(value, coerce) {
4033
+ switch (coerce) {
4034
+ case "string":
4035
+ return value === null || value === void 0 ? "" : String(value);
4036
+ case "number": {
4037
+ if (typeof value === "number") return value;
4038
+ const num = parseFloat(String(value));
4039
+ if (isNaN(num)) throw new Error(`Cannot coerce "${value}" to number`);
4040
+ return num;
4041
+ }
4042
+ case "boolean":
4043
+ if (typeof value === "boolean") return value;
4044
+ if (value === "true" || value === 1) return true;
4045
+ if (value === "false" || value === 0 || value === "" || value === null || value === void 0) return false;
4046
+ return Boolean(value);
4047
+ default:
4048
+ return value;
4049
+ }
4050
+ }
4051
+ var DataTransform = class extends ActionNode {
4052
+ outputKey;
4053
+ mappings;
4054
+ wrapInArray;
4055
+ constructor(config) {
4056
+ super(config);
4057
+ this.outputKey = config.outputKey;
4058
+ this.mappings = config.mappings;
4059
+ this.wrapInArray = config.wrapInArray ?? false;
4060
+ }
4061
+ async executeTick(context) {
4062
+ try {
4063
+ const varCtx = {
4064
+ blackboard: context.blackboard,
4065
+ input: context.input,
4066
+ testData: context.testData
4067
+ };
4068
+ const result = {};
4069
+ for (const mapping of this.mappings) {
4070
+ let resolved = resolveValue(mapping.value, varCtx);
4071
+ if (mapping.coerce) {
4072
+ resolved = coerceValue(resolved, mapping.coerce);
4073
+ }
4074
+ setNestedValue(result, mapping.target, resolved);
4075
+ }
4076
+ const output = this.wrapInArray ? [result] : result;
4077
+ context.blackboard.set(this.outputKey, output);
4078
+ this.log(`Built object with ${this.mappings.length} fields \u2192 ${this.outputKey}`);
4079
+ return "SUCCESS" /* SUCCESS */;
4080
+ } catch (error) {
4081
+ this._lastError = error instanceof Error ? error.message : String(error);
4082
+ this.log(`DataTransform failed: ${this._lastError}`);
4083
+ return "FAILURE" /* FAILURE */;
4084
+ }
4085
+ }
4086
+ };
4087
+
3463
4088
  // src/integrations/piece-executor.ts
3464
4089
  var PROVIDER_TO_PIECE = {
3465
4090
  // Google services
@@ -4988,6 +5613,11 @@ function registerStandardNodes(registry) {
4988
5613
  registry.register("LogMessage", LogMessage, { category: "action" });
4989
5614
  registry.register("RegexExtract", RegexExtract, { category: "action" });
4990
5615
  registry.register("SetVariable", SetVariable, { category: "action" });
5616
+ registry.register("MathOp", MathOp, { category: "action" });
5617
+ registry.register("ArrayFilter", ArrayFilter, { category: "action" });
5618
+ registry.register("Aggregate", Aggregate, { category: "action" });
5619
+ registry.register("ThresholdCheck", ThresholdCheck, { category: "action" });
5620
+ registry.register("DataTransform", DataTransform, { category: "action" });
4991
5621
  registry.register("IntegrationAction", IntegrationAction, { category: "action" });
4992
5622
  registry.register("PythonScript", PythonScript, { category: "action" });
4993
5623
  registry.register("ParseFile", ParseFile, { category: "action" });
@@ -5837,7 +6467,9 @@ function createObservabilitySinkHandler(config = {}) {
5837
6467
  }
5838
6468
  export {
5839
6469
  ActionNode,
6470
+ Aggregate,
5840
6471
  AlwaysCondition,
6472
+ ArrayFilter,
5841
6473
  BaseNode,
5842
6474
  BehaviorTree,
5843
6475
  BrowserAgent,
@@ -5850,6 +6482,7 @@ export {
5850
6482
  ConfigValidationError,
5851
6483
  ConfigurationError,
5852
6484
  CounterAction,
6485
+ DataTransform,
5853
6486
  DecoratorNode,
5854
6487
  Delay,
5855
6488
  ExecutionTracker,
@@ -5868,6 +6501,7 @@ export {
5868
6501
  LLMChat,
5869
6502
  LLMToolCall,
5870
6503
  LogMessage,
6504
+ MathOp,
5871
6505
  MemoryDataStore,
5872
6506
  MemorySequence,
5873
6507
  MockAction,
@@ -5899,6 +6533,7 @@ export {
5899
6533
  StructureValidationError,
5900
6534
  SubTree,
5901
6535
  SuccessNode,
6536
+ ThresholdCheck,
5902
6537
  Timeout,
5903
6538
  ToolExecutor,
5904
6539
  ToolRouter,
@@ -5929,6 +6564,7 @@ export {
5929
6564
  registerStandardNodes,
5930
6565
  resolveString,
5931
6566
  resolveValue,
6567
+ safeEvaluate,
5932
6568
  safeValidateConfiguration,
5933
6569
  schemaRegistry,
5934
6570
  semanticValidator,