@q1k-oss/behaviour-tree-workflows 0.0.1 → 0.0.3

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
@@ -34,7 +34,9 @@ __export(index_exports, {
34
34
  AlwaysCondition: () => AlwaysCondition,
35
35
  BaseNode: () => BaseNode,
36
36
  BehaviorTree: () => BehaviorTree,
37
+ BrowserAgent: () => BrowserAgent,
37
38
  CheckCondition: () => CheckCondition,
39
+ ClaudeAgent: () => ClaudeAgent,
38
40
  CodeExecution: () => CodeExecution,
39
41
  CompositeNode: () => CompositeNode,
40
42
  ConditionNode: () => ConditionNode,
@@ -51,10 +53,14 @@ __export(index_exports, {
51
53
  ForceFailure: () => ForceFailure,
52
54
  ForceSuccess: () => ForceSuccess,
53
55
  GenerateFile: () => GenerateFile,
56
+ GitHubAction: () => GitHubAction,
54
57
  HttpRequest: () => HttpRequest,
58
+ HumanTask: () => HumanTask,
55
59
  IntegrationAction: () => IntegrationAction,
56
60
  Invert: () => Invert,
57
61
  KeepRunningUntilFailure: () => KeepRunningUntilFailure,
62
+ LLMChat: () => LLMChat,
63
+ LLMToolCall: () => LLMToolCall,
58
64
  LogMessage: () => LogMessage,
59
65
  MemoryDataStore: () => MemoryDataStore,
60
66
  MemorySequence: () => MemorySequence,
@@ -81,14 +87,19 @@ __export(index_exports, {
81
87
  SemanticValidationError: () => SemanticValidationError,
82
88
  Sequence: () => Sequence,
83
89
  SequenceWithMemory: () => SequenceWithMemory,
90
+ SetVariable: () => SetVariable,
84
91
  SoftAssert: () => SoftAssert,
92
+ StreamingSink: () => StreamingSink,
85
93
  StructureValidationError: () => StructureValidationError,
86
94
  SubTree: () => SubTree,
87
95
  SuccessNode: () => SuccessNode,
88
96
  Timeout: () => Timeout,
97
+ ToolExecutor: () => ToolExecutor,
98
+ ToolRouter: () => ToolRouter,
89
99
  ValidationError: () => ValidationError,
90
100
  ValidationErrors: () => ValidationErrors,
91
101
  WaitAction: () => WaitAction,
102
+ WaitForSignal: () => WaitForSignal,
92
103
  While: () => While,
93
104
  YamlSyntaxError: () => YamlSyntaxError,
94
105
  clearPieceCache: () => clearPieceCache,
@@ -417,6 +428,19 @@ var ActionNode = class extends BaseNode {
417
428
  });
418
429
  const status = await this.executeTick(context);
419
430
  this._status = status;
431
+ if (status === "FAILURE" /* FAILURE */ && this._lastError) {
432
+ context.eventEmitter?.emit({
433
+ type: "error" /* ERROR */,
434
+ nodeId: this.id,
435
+ nodeName: this.name,
436
+ nodeType: this.type,
437
+ timestamp: Date.now(),
438
+ data: {
439
+ error: { message: this._lastError },
440
+ blackboard: context.blackboard?.toJSON?.() ?? {}
441
+ }
442
+ });
443
+ }
420
444
  context.eventEmitter?.emit({
421
445
  type: "tick_end" /* TICK_END */,
422
446
  nodeId: this.id,
@@ -483,6 +507,19 @@ var ConditionNode = class extends BaseNode {
483
507
  });
484
508
  const status = await this.executeTick(context);
485
509
  this._status = status;
510
+ if (status === "FAILURE" /* FAILURE */ && this._lastError) {
511
+ context.eventEmitter?.emit({
512
+ type: "error" /* ERROR */,
513
+ nodeId: this.id,
514
+ nodeName: this.name,
515
+ nodeType: this.type,
516
+ timestamp: Date.now(),
517
+ data: {
518
+ error: { message: this._lastError },
519
+ blackboard: context.blackboard?.toJSON?.() ?? {}
520
+ }
521
+ });
522
+ }
486
523
  context.eventEmitter?.emit({
487
524
  type: "tick_end" /* TICK_END */,
488
525
  nodeId: this.id,
@@ -961,9 +998,9 @@ var BehaviorTree = class _BehaviorTree {
961
998
  *
962
999
  * @example
963
1000
  * ```typescript
964
- * import { BehaviorTree } from '@wayfarer-ai/btree';
965
- * import { Sequence } from '@wayfarer-ai/btree';
966
- * import { PrintAction } from '@wayfarer-ai/btree';
1001
+ * import { BehaviorTree } from '@q1k-oss/behaviour-tree-workflows';
1002
+ * import { Sequence } from '@q1k-oss/behaviour-tree-workflows';
1003
+ * import { PrintAction } from '@q1k-oss/behaviour-tree-workflows';
967
1004
  *
968
1005
  * const root = new Sequence({ id: 'root' });
969
1006
  * root.addChild(new PrintAction({ id: 'step1', message: 'Hello' }));
@@ -2323,6 +2360,52 @@ var SoftAssert = class extends DecoratorNode {
2323
2360
  }
2324
2361
  };
2325
2362
 
2363
+ // src/decorators/streaming-sink.ts
2364
+ var StreamingSink = class extends DecoratorNode {
2365
+ channelId;
2366
+ channelKey;
2367
+ constructor(config) {
2368
+ super(config);
2369
+ if (!config.channelId && !config.channelKey) {
2370
+ throw new ConfigurationError(
2371
+ "StreamingSink requires either channelId or channelKey"
2372
+ );
2373
+ }
2374
+ this.channelId = config.channelId;
2375
+ this.channelKey = config.channelKey;
2376
+ }
2377
+ async executeTick(context) {
2378
+ if (!this.child) {
2379
+ throw new ConfigurationError(
2380
+ `${this.name}: Decorator must have a child`
2381
+ );
2382
+ }
2383
+ let resolvedChannelId = this.channelId;
2384
+ if (this.channelKey) {
2385
+ const varCtx = {
2386
+ blackboard: context.blackboard,
2387
+ input: context.input,
2388
+ testData: context.testData
2389
+ };
2390
+ resolvedChannelId = resolveValue(this.channelKey, varCtx);
2391
+ }
2392
+ const previousValue = context.blackboard.get("__streamChannelId");
2393
+ context.blackboard.set("__streamChannelId", resolvedChannelId);
2394
+ this.log(`Set streaming channel: ${resolvedChannelId}`);
2395
+ try {
2396
+ const childStatus = await this.child.tick(context);
2397
+ this._status = childStatus;
2398
+ return childStatus;
2399
+ } finally {
2400
+ if (previousValue !== void 0) {
2401
+ context.blackboard.set("__streamChannelId", previousValue);
2402
+ } else {
2403
+ context.blackboard.delete("__streamChannelId");
2404
+ }
2405
+ }
2406
+ }
2407
+ };
2408
+
2326
2409
  // src/decorators/timeout.ts
2327
2410
  var import_workflow2 = require("@temporalio/workflow");
2328
2411
  var Timeout = class extends DecoratorNode {
@@ -2545,8 +2628,136 @@ var memorySequenceConfigurationSchema = nodeConfigurationSchema;
2545
2628
  // src/composites/recovery.schema.ts
2546
2629
  var recoveryConfigurationSchema = nodeConfigurationSchema;
2547
2630
 
2548
- // src/schemas/validation.ts
2631
+ // src/actions/llm-chat.schema.ts
2549
2632
  var import_zod3 = require("zod");
2633
+ var messageSchema = import_zod3.z.object({
2634
+ role: import_zod3.z.enum(["system", "user", "assistant"]),
2635
+ content: import_zod3.z.string().min(1, "Message content cannot be empty")
2636
+ });
2637
+ var llmChatSchema = createNodeSchema("LLMChat", {
2638
+ provider: import_zod3.z.enum(["anthropic", "openai", "google", "ollama"]),
2639
+ model: import_zod3.z.string().min(1, "Model is required"),
2640
+ messages: import_zod3.z.array(messageSchema).min(1, "At least one message is required"),
2641
+ systemPrompt: import_zod3.z.string().optional(),
2642
+ temperature: import_zod3.z.number().min(0).max(2).optional(),
2643
+ maxTokens: import_zod3.z.number().int().positive().optional(),
2644
+ responseFormat: import_zod3.z.enum(["text", "json"]).optional().default("text"),
2645
+ jsonSchema: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional(),
2646
+ timeout: import_zod3.z.number().int().positive().optional().default(6e4),
2647
+ baseUrl: import_zod3.z.string().url().optional(),
2648
+ outputKey: import_zod3.z.string().min(1, "outputKey is required")
2649
+ });
2650
+
2651
+ // src/actions/browser-agent.schema.ts
2652
+ var import_zod4 = require("zod");
2653
+ var browserAgentSchema = createNodeSchema("BrowserAgent", {
2654
+ goal: import_zod4.z.string().min(1, "Goal is required"),
2655
+ startUrl: import_zod4.z.string().optional(),
2656
+ contextKey: import_zod4.z.string().optional(),
2657
+ persistContext: import_zod4.z.boolean().optional().default(false),
2658
+ timeout: import_zod4.z.number().int().positive().optional().default(6e4),
2659
+ maxSteps: import_zod4.z.number().int().positive().optional().default(20),
2660
+ llmProvider: import_zod4.z.enum(["anthropic", "openai", "google", "ollama"]).optional(),
2661
+ llmModel: import_zod4.z.string().optional(),
2662
+ outputKey: import_zod4.z.string().min(1, "outputKey is required")
2663
+ });
2664
+
2665
+ // src/actions/human-task.schema.ts
2666
+ var import_zod5 = require("zod");
2667
+ var a2uiComponentSchema = import_zod5.z.object({
2668
+ id: import_zod5.z.string().min(1, "Component ID cannot be empty"),
2669
+ component: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.unknown()),
2670
+ weight: import_zod5.z.number().optional()
2671
+ });
2672
+ var humanTaskSchema = createNodeSchema("HumanTask", {
2673
+ title: import_zod5.z.string().min(1, "Title is required"),
2674
+ description: import_zod5.z.string().optional(),
2675
+ assignee: import_zod5.z.string().optional(),
2676
+ assigneeRole: import_zod5.z.string().optional(),
2677
+ a2ui: import_zod5.z.object({
2678
+ components: import_zod5.z.array(a2uiComponentSchema).min(1, "At least one A2UI component is required"),
2679
+ dataBindings: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.string()).optional()
2680
+ }),
2681
+ timeoutMs: import_zod5.z.number().int().positive().optional().default(864e5),
2682
+ onTimeout: import_zod5.z.enum(["expire", "approve", "reject"]).optional().default("expire"),
2683
+ outputKey: import_zod5.z.string().optional()
2684
+ });
2685
+
2686
+ // src/utilities/set-variable.schema.ts
2687
+ var import_zod6 = require("zod");
2688
+ var setVariableSchema = createNodeSchema("SetVariable", {
2689
+ key: import_zod6.z.string().min(1, "key is required"),
2690
+ value: import_zod6.z.unknown()
2691
+ });
2692
+
2693
+ // src/actions/llm-tool-call.schema.ts
2694
+ 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())
2699
+ });
2700
+ 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")
2711
+ });
2712
+
2713
+ // src/actions/tool-executor.schema.ts
2714
+ var import_zod8 = require("zod");
2715
+ 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()
2719
+ });
2720
+
2721
+ // src/actions/wait-for-signal.schema.ts
2722
+ var import_zod9 = require("zod");
2723
+ 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")
2728
+ });
2729
+
2730
+ // 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())
2736
+ });
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)
2740
+ });
2741
+ 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")
2747
+ });
2748
+
2749
+ // src/decorators/streaming-sink.schema.ts
2750
+ var import_zod11 = require("zod");
2751
+ var streamingSinkSchema = createNodeSchema("StreamingSink", {
2752
+ channelId: import_zod11.z.string().optional(),
2753
+ channelKey: import_zod11.z.string().optional()
2754
+ }).refine(
2755
+ (data) => data.channelId || data.channelKey,
2756
+ { message: "Either channelId or channelKey must be provided" }
2757
+ );
2758
+
2759
+ // src/schemas/validation.ts
2760
+ var import_zod12 = require("zod");
2550
2761
  function zodErrorToConfigurationError(error, nodeType, nodeId) {
2551
2762
  const nodeIdentifier = nodeId ? `${nodeType}:${nodeId}` : nodeType;
2552
2763
  const issues = error.issues.map((issue) => {
@@ -2562,7 +2773,7 @@ function validateConfiguration(schema, config, nodeType, nodeId) {
2562
2773
  try {
2563
2774
  return schema.parse(config);
2564
2775
  } catch (error) {
2565
- if (error instanceof import_zod3.z.ZodError) {
2776
+ if (error instanceof import_zod12.z.ZodError) {
2566
2777
  throw zodErrorToConfigurationError(error, nodeType, nodeId);
2567
2778
  }
2568
2779
  throw error;
@@ -2581,14 +2792,14 @@ function safeValidateConfiguration(schema, config, nodeType, nodeId) {
2581
2792
  }
2582
2793
 
2583
2794
  // src/schemas/tree-definition.schema.ts
2584
- var import_zod4 = require("zod");
2585
- var treeDefSchemaObject = import_zod4.z.object({
2586
- type: import_zod4.z.string().min(1, "Node type is required"),
2587
- id: import_zod4.z.string().optional(),
2588
- name: import_zod4.z.string().optional(),
2589
- props: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()).optional(),
2590
- children: import_zod4.z.array(
2591
- import_zod4.z.lazy(() => treeDefinitionSchema)
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)
2592
2803
  ).optional()
2593
2804
  });
2594
2805
  var treeDefinitionSchema = treeDefSchemaObject;
@@ -2667,6 +2878,15 @@ var SchemaRegistry = class {
2667
2878
  this.register("ReactiveSequence", reactiveSequenceConfigurationSchema);
2668
2879
  this.register("MemorySequence", memorySequenceConfigurationSchema);
2669
2880
  this.register("Recovery", recoveryConfigurationSchema);
2881
+ this.register("LLMChat", llmChatSchema);
2882
+ this.register("BrowserAgent", browserAgentSchema);
2883
+ this.register("HumanTask", humanTaskSchema);
2884
+ this.register("SetVariable", setVariableSchema);
2885
+ this.register("LLMToolCall", llmToolCallSchema);
2886
+ this.register("ToolExecutor", toolExecutorSchema);
2887
+ this.register("WaitForSignal", waitForSignalSchema);
2888
+ this.register("ToolRouter", toolRouterSchema);
2889
+ this.register("StreamingSink", streamingSinkSchema);
2670
2890
  }
2671
2891
  /**
2672
2892
  * Register a validation schema for a node type
@@ -3136,8 +3356,32 @@ var CheckCondition = class extends ConditionNode {
3136
3356
  this.operator = config.operator || "==";
3137
3357
  this.value = config.value;
3138
3358
  }
3359
+ /**
3360
+ * Resolve a potentially dotted key from the blackboard.
3361
+ * Tries exact key first (backward compatible), then dotted path traversal.
3362
+ */
3363
+ resolveBlackboardValue(context) {
3364
+ const exact = context.blackboard.get(this.key);
3365
+ if (exact !== void 0) {
3366
+ return exact;
3367
+ }
3368
+ if (this.key.includes(".")) {
3369
+ const segments = this.key.split(".");
3370
+ const rootKey = segments[0];
3371
+ let current = context.blackboard.get(rootKey);
3372
+ for (let i = 1; i < segments.length; i++) {
3373
+ if (current == null || typeof current !== "object") {
3374
+ return void 0;
3375
+ }
3376
+ const segment = segments[i];
3377
+ current = current[segment];
3378
+ }
3379
+ return current;
3380
+ }
3381
+ return void 0;
3382
+ }
3139
3383
  async executeTick(context) {
3140
- const actualValue = context.blackboard.get(this.key);
3384
+ const actualValue = this.resolveBlackboardValue(context);
3141
3385
  let result = false;
3142
3386
  switch (this.operator) {
3143
3387
  case "==":
@@ -3329,6 +3573,35 @@ var RegexExtract = class extends ActionNode {
3329
3573
  }
3330
3574
  };
3331
3575
 
3576
+ // src/utilities/set-variable.ts
3577
+ var SetVariable = class extends ActionNode {
3578
+ key;
3579
+ value;
3580
+ constructor(config) {
3581
+ super(config);
3582
+ this.key = config.key;
3583
+ this.value = config.value;
3584
+ }
3585
+ async executeTick(context) {
3586
+ try {
3587
+ const varCtx = {
3588
+ blackboard: context.blackboard,
3589
+ input: context.input,
3590
+ testData: context.testData
3591
+ };
3592
+ const resolvedKey = typeof this.key === "string" ? resolveValue(this.key, varCtx) : String(this.key);
3593
+ const resolvedValue = typeof this.value === "string" ? resolveValue(this.value, varCtx) : this.value;
3594
+ context.blackboard.set(resolvedKey, resolvedValue);
3595
+ this.log(`Set ${resolvedKey} = ${JSON.stringify(resolvedValue)}`);
3596
+ return "SUCCESS" /* SUCCESS */;
3597
+ } catch (error) {
3598
+ this._lastError = error instanceof Error ? error.message : String(error);
3599
+ this.log(`SetVariable failed: ${this._lastError}`);
3600
+ return "FAILURE" /* FAILURE */;
3601
+ }
3602
+ }
3603
+ };
3604
+
3332
3605
  // src/integrations/piece-executor.ts
3333
3606
  var PROVIDER_TO_PIECE = {
3334
3607
  // Google services
@@ -4020,6 +4293,788 @@ var CodeExecution = class extends ActionNode {
4020
4293
  }
4021
4294
  };
4022
4295
 
4296
+ // src/actions/llm-chat.ts
4297
+ var LLMChat = class extends ActionNode {
4298
+ provider;
4299
+ model;
4300
+ messages;
4301
+ systemPrompt;
4302
+ temperature;
4303
+ maxTokens;
4304
+ responseFormat;
4305
+ jsonSchema;
4306
+ timeout;
4307
+ baseUrl;
4308
+ outputKey;
4309
+ constructor(config) {
4310
+ super(config);
4311
+ if (!config.provider) {
4312
+ throw new ConfigurationError("LLMChat requires provider");
4313
+ }
4314
+ if (!config.model) {
4315
+ throw new ConfigurationError("LLMChat requires model");
4316
+ }
4317
+ if (!config.messages || config.messages.length === 0) {
4318
+ throw new ConfigurationError(
4319
+ "LLMChat requires at least one message"
4320
+ );
4321
+ }
4322
+ if (!config.outputKey) {
4323
+ throw new ConfigurationError("LLMChat requires outputKey");
4324
+ }
4325
+ this.provider = config.provider;
4326
+ this.model = config.model;
4327
+ this.messages = config.messages;
4328
+ this.systemPrompt = config.systemPrompt;
4329
+ this.temperature = config.temperature;
4330
+ this.maxTokens = config.maxTokens;
4331
+ this.responseFormat = config.responseFormat || "text";
4332
+ this.jsonSchema = config.jsonSchema;
4333
+ this.timeout = config.timeout;
4334
+ this.baseUrl = config.baseUrl;
4335
+ this.outputKey = config.outputKey;
4336
+ }
4337
+ async executeTick(context) {
4338
+ if (!context.activities?.llmChat) {
4339
+ this._lastError = "LLMChat requires activities.llmChat to be configured. This activity handles LLM API calls outside the workflow sandbox.";
4340
+ this.log(`Error: ${this._lastError}`);
4341
+ return "FAILURE" /* FAILURE */;
4342
+ }
4343
+ try {
4344
+ const varCtx = {
4345
+ blackboard: context.blackboard,
4346
+ input: context.input,
4347
+ testData: context.testData
4348
+ };
4349
+ const resolvedMessages = this.messages.map((msg) => ({
4350
+ role: msg.role,
4351
+ content: resolveValue(msg.content, varCtx)
4352
+ }));
4353
+ const resolvedSystemPrompt = this.systemPrompt ? resolveValue(this.systemPrompt, varCtx) : void 0;
4354
+ const resolvedModel = resolveValue(this.model, varCtx);
4355
+ const request = {
4356
+ provider: this.provider,
4357
+ model: resolvedModel,
4358
+ messages: resolvedMessages,
4359
+ systemPrompt: resolvedSystemPrompt,
4360
+ temperature: this.temperature,
4361
+ maxTokens: this.maxTokens,
4362
+ responseFormat: this.responseFormat,
4363
+ jsonSchema: this.jsonSchema,
4364
+ timeout: this.timeout,
4365
+ baseUrl: this.baseUrl
4366
+ };
4367
+ this.log(
4368
+ `LLM ${this.provider}/${resolvedModel} - ${resolvedMessages.length} messages`
4369
+ );
4370
+ const result = await context.activities.llmChat(request);
4371
+ context.blackboard.set(this.outputKey, result);
4372
+ if (result.finishReason === "error") {
4373
+ this._lastError = `LLM returned error: ${result.content}`;
4374
+ this.log(`Error: ${this._lastError}`);
4375
+ return "FAILURE" /* FAILURE */;
4376
+ }
4377
+ this.log(
4378
+ `LLM ${this.provider}/${resolvedModel} completed: ${result.usage.totalTokens} tokens, finish: ${result.finishReason}`
4379
+ );
4380
+ return "SUCCESS" /* SUCCESS */;
4381
+ } catch (error) {
4382
+ this._lastError = error instanceof Error ? error.message : String(error);
4383
+ this.log(`LLM chat failed: ${this._lastError}`);
4384
+ return "FAILURE" /* FAILURE */;
4385
+ }
4386
+ }
4387
+ };
4388
+
4389
+ // src/actions/browser-agent.ts
4390
+ var BrowserAgent = class extends ActionNode {
4391
+ goal;
4392
+ startUrl;
4393
+ contextKey;
4394
+ persistContext;
4395
+ timeout;
4396
+ maxSteps;
4397
+ llmProvider;
4398
+ llmModel;
4399
+ outputKey;
4400
+ constructor(config) {
4401
+ super(config);
4402
+ if (!config.goal) {
4403
+ throw new ConfigurationError("BrowserAgent requires goal");
4404
+ }
4405
+ if (!config.outputKey) {
4406
+ throw new ConfigurationError("BrowserAgent requires outputKey");
4407
+ }
4408
+ this.goal = config.goal;
4409
+ this.startUrl = config.startUrl;
4410
+ this.contextKey = config.contextKey;
4411
+ this.persistContext = config.persistContext ?? false;
4412
+ this.timeout = config.timeout;
4413
+ this.maxSteps = config.maxSteps;
4414
+ this.llmProvider = config.llmProvider;
4415
+ this.llmModel = config.llmModel;
4416
+ this.outputKey = config.outputKey;
4417
+ }
4418
+ async executeTick(context) {
4419
+ if (!context.activities?.browserAgent) {
4420
+ this._lastError = "BrowserAgent requires activities.browserAgent to be configured. This activity handles browser automation via Browserbase + Stagehand.";
4421
+ this.log(`Error: ${this._lastError}`);
4422
+ return "FAILURE" /* FAILURE */;
4423
+ }
4424
+ try {
4425
+ const varCtx = {
4426
+ blackboard: context.blackboard,
4427
+ input: context.input,
4428
+ testData: context.testData
4429
+ };
4430
+ const resolvedGoal = resolveValue(this.goal, varCtx);
4431
+ const resolvedStartUrl = this.startUrl ? resolveValue(this.startUrl, varCtx) : void 0;
4432
+ const contextId = this.contextKey ? context.blackboard.get(this.contextKey) : void 0;
4433
+ const request = {
4434
+ goal: resolvedGoal,
4435
+ startUrl: resolvedStartUrl,
4436
+ contextId,
4437
+ persistContext: this.persistContext,
4438
+ timeout: this.timeout,
4439
+ maxSteps: this.maxSteps,
4440
+ llmProvider: this.llmProvider,
4441
+ llmModel: this.llmModel
4442
+ };
4443
+ this.log(
4444
+ `Browser agent: ${resolvedGoal.substring(0, 50)}${resolvedGoal.length > 50 ? "..." : ""}`
4445
+ );
4446
+ const result = await context.activities.browserAgent(request);
4447
+ if (this.contextKey && result.contextId) {
4448
+ context.blackboard.set(this.contextKey, result.contextId);
4449
+ }
4450
+ context.blackboard.set(this.outputKey, result);
4451
+ if (!result.success) {
4452
+ this._lastError = `Browser agent failed to achieve goal: ${result.message}`;
4453
+ this.log(`Error: ${this._lastError}`);
4454
+ this.log(`Debug session: ${result.debugUrl}`);
4455
+ return "FAILURE" /* FAILURE */;
4456
+ }
4457
+ if (!result.completed) {
4458
+ this._lastError = `Browser agent hit step limit before completing: ${result.message}`;
4459
+ this.log(`Error: ${this._lastError}`);
4460
+ this.log(`Debug session: ${result.debugUrl}`);
4461
+ return "FAILURE" /* FAILURE */;
4462
+ }
4463
+ this.log(`Browser agent succeeded: ${result.message}`);
4464
+ this.log(`Debug session: ${result.debugUrl}`);
4465
+ return "SUCCESS" /* SUCCESS */;
4466
+ } catch (error) {
4467
+ this._lastError = error instanceof Error ? error.message : String(error);
4468
+ this.log(`Browser agent failed: ${this._lastError}`);
4469
+ return "FAILURE" /* FAILURE */;
4470
+ }
4471
+ }
4472
+ };
4473
+
4474
+ // src/actions/claude-agent.ts
4475
+ var ClaudeAgent = class extends ActionNode {
4476
+ prompt;
4477
+ model;
4478
+ systemPrompt;
4479
+ allowedTools;
4480
+ permissionMode;
4481
+ maxTurns;
4482
+ maxBudgetUsd;
4483
+ agentCwd;
4484
+ mcpServers;
4485
+ agents;
4486
+ outputKey;
4487
+ constructor(config) {
4488
+ super(config);
4489
+ if (!config.prompt) {
4490
+ throw new ConfigurationError("ClaudeAgent requires prompt");
4491
+ }
4492
+ if (!config.outputKey) {
4493
+ throw new ConfigurationError("ClaudeAgent requires outputKey");
4494
+ }
4495
+ this.prompt = config.prompt;
4496
+ this.model = config.model;
4497
+ this.systemPrompt = config.systemPrompt;
4498
+ this.allowedTools = config.allowedTools;
4499
+ this.permissionMode = config.permissionMode ?? "default";
4500
+ this.maxTurns = config.maxTurns ?? 50;
4501
+ this.maxBudgetUsd = config.maxBudgetUsd;
4502
+ this.agentCwd = config.cwd;
4503
+ this.mcpServers = config.mcpServers;
4504
+ this.agents = config.agents;
4505
+ this.outputKey = config.outputKey;
4506
+ }
4507
+ async executeTick(context) {
4508
+ if (!context.activities?.claudeAgent) {
4509
+ this._lastError = "ClaudeAgent requires activities.claudeAgent to be configured. This activity handles autonomous agent execution via the Claude Agent SDK.";
4510
+ this.log(`Error: ${this._lastError}`);
4511
+ return "FAILURE" /* FAILURE */;
4512
+ }
4513
+ try {
4514
+ const varCtx = {
4515
+ blackboard: context.blackboard,
4516
+ input: context.input,
4517
+ testData: context.testData
4518
+ };
4519
+ const resolvedPrompt = resolveValue(this.prompt, varCtx);
4520
+ const resolvedSystemPrompt = this.systemPrompt ? resolveValue(this.systemPrompt, varCtx) : void 0;
4521
+ const resolvedModel = this.model ? resolveValue(this.model, varCtx) : void 0;
4522
+ const resolvedCwd = this.agentCwd ? resolveValue(this.agentCwd, varCtx) : void 0;
4523
+ const request = {
4524
+ prompt: resolvedPrompt,
4525
+ model: resolvedModel,
4526
+ systemPrompt: resolvedSystemPrompt,
4527
+ allowedTools: this.allowedTools,
4528
+ permissionMode: this.permissionMode,
4529
+ maxTurns: this.maxTurns,
4530
+ maxBudgetUsd: this.maxBudgetUsd,
4531
+ cwd: resolvedCwd,
4532
+ mcpServers: this.mcpServers,
4533
+ agents: this.agents
4534
+ };
4535
+ this.log(
4536
+ `Claude agent: ${resolvedPrompt.substring(0, 80)}${resolvedPrompt.length > 80 ? "..." : ""}`
4537
+ );
4538
+ const result = await context.activities.claudeAgent(request);
4539
+ context.blackboard.set(this.outputKey, result);
4540
+ if (!result.success) {
4541
+ this._lastError = `Claude agent failed: ${result.errors?.join(", ") || "unknown error"}`;
4542
+ this.log(`Error: ${this._lastError}`);
4543
+ return "FAILURE" /* FAILURE */;
4544
+ }
4545
+ this.log(
4546
+ `Claude agent completed in ${result.numTurns} turns, $${result.totalCostUsd.toFixed(4)}, ${result.durationMs}ms`
4547
+ );
4548
+ return "SUCCESS" /* SUCCESS */;
4549
+ } catch (error) {
4550
+ this._lastError = error instanceof Error ? error.message : String(error);
4551
+ this.log(`Claude agent failed: ${this._lastError}`);
4552
+ return "FAILURE" /* FAILURE */;
4553
+ }
4554
+ }
4555
+ };
4556
+
4557
+ // src/actions/github-action.ts
4558
+ var VALID_OPERATIONS = [
4559
+ "createBranch",
4560
+ "createPullRequest",
4561
+ "getPullRequest",
4562
+ "mergePullRequest",
4563
+ "closePullRequest",
4564
+ "createReview",
4565
+ "listIssues",
4566
+ "addLabels",
4567
+ "createComment",
4568
+ "createRelease"
4569
+ ];
4570
+ var GitHubAction = class extends ActionNode {
4571
+ operation;
4572
+ repo;
4573
+ params;
4574
+ outputKey;
4575
+ constructor(config) {
4576
+ super(config);
4577
+ if (!config.operation) {
4578
+ throw new ConfigurationError("GitHubAction requires operation");
4579
+ }
4580
+ if (!VALID_OPERATIONS.includes(config.operation)) {
4581
+ throw new ConfigurationError(
4582
+ `GitHubAction: invalid operation "${config.operation}". Valid operations: ${VALID_OPERATIONS.join(", ")}`
4583
+ );
4584
+ }
4585
+ if (!config.repo) {
4586
+ throw new ConfigurationError("GitHubAction requires repo");
4587
+ }
4588
+ if (!config.outputKey) {
4589
+ throw new ConfigurationError("GitHubAction requires outputKey");
4590
+ }
4591
+ this.operation = config.operation;
4592
+ this.repo = config.repo;
4593
+ this.params = config.params ?? {};
4594
+ this.outputKey = config.outputKey;
4595
+ }
4596
+ async executeTick(context) {
4597
+ if (!context.activities?.githubAction) {
4598
+ this._lastError = "GitHubAction requires activities.githubAction to be configured. This activity handles GitHub API operations.";
4599
+ this.log(`Error: ${this._lastError}`);
4600
+ return "FAILURE" /* FAILURE */;
4601
+ }
4602
+ try {
4603
+ const varCtx = {
4604
+ blackboard: context.blackboard,
4605
+ input: context.input,
4606
+ testData: context.testData
4607
+ };
4608
+ const resolvedRepo = resolveValue(this.repo, varCtx);
4609
+ const resolvedParams = {};
4610
+ for (const [key, value] of Object.entries(this.params)) {
4611
+ if (typeof value === "string") {
4612
+ resolvedParams[key] = resolveValue(value, varCtx);
4613
+ } else {
4614
+ resolvedParams[key] = value;
4615
+ }
4616
+ }
4617
+ const request = {
4618
+ operation: this.operation,
4619
+ repo: resolvedRepo,
4620
+ params: resolvedParams
4621
+ };
4622
+ this.log(
4623
+ `GitHub ${this.operation}: ${resolvedRepo}`
4624
+ );
4625
+ const result = await context.activities.githubAction(request);
4626
+ context.blackboard.set(this.outputKey, result.data);
4627
+ if (!result.success) {
4628
+ this._lastError = `GitHub ${this.operation} failed`;
4629
+ this.log(`Error: ${this._lastError}`);
4630
+ return "FAILURE" /* FAILURE */;
4631
+ }
4632
+ this.log(`GitHub ${this.operation} completed successfully`);
4633
+ return "SUCCESS" /* SUCCESS */;
4634
+ } catch (error) {
4635
+ this._lastError = error instanceof Error ? error.message : String(error);
4636
+ this.log(`GitHub ${this.operation} failed: ${this._lastError}`);
4637
+ return "FAILURE" /* FAILURE */;
4638
+ }
4639
+ }
4640
+ };
4641
+
4642
+ // src/actions/human-task.ts
4643
+ var HumanTask = class extends ActionNode {
4644
+ title;
4645
+ description;
4646
+ assignee;
4647
+ assigneeRole;
4648
+ a2ui;
4649
+ timeoutMs;
4650
+ onTimeout;
4651
+ outputKey;
4652
+ constructor(config) {
4653
+ super(config);
4654
+ if (!config.title) {
4655
+ throw new ConfigurationError("HumanTask requires title");
4656
+ }
4657
+ if (!config.a2ui?.components || config.a2ui.components.length === 0) {
4658
+ throw new ConfigurationError(
4659
+ "HumanTask requires a2ui.components with at least one component"
4660
+ );
4661
+ }
4662
+ this.title = config.title;
4663
+ this.description = config.description;
4664
+ this.assignee = config.assignee;
4665
+ this.assigneeRole = config.assigneeRole;
4666
+ this.a2ui = config.a2ui;
4667
+ this.timeoutMs = config.timeoutMs ?? 864e5;
4668
+ this.onTimeout = config.onTimeout ?? "expire";
4669
+ this.outputKey = config.outputKey;
4670
+ }
4671
+ async executeTick(context) {
4672
+ if (!context.activities?.createHumanTask) {
4673
+ this._lastError = "HumanTask requires activities.createHumanTask to be configured. This activity creates a task record in the database.";
4674
+ this.log(`Error: ${this._lastError}`);
4675
+ return "FAILURE" /* FAILURE */;
4676
+ }
4677
+ if (!context.activities?.waitForHumanTask) {
4678
+ this._lastError = "HumanTask requires activities.waitForHumanTask to be configured. This activity waits for the user to complete the task.";
4679
+ this.log(`Error: ${this._lastError}`);
4680
+ return "FAILURE" /* FAILURE */;
4681
+ }
4682
+ try {
4683
+ const varCtx = {
4684
+ blackboard: context.blackboard,
4685
+ input: context.input,
4686
+ testData: context.testData
4687
+ };
4688
+ const a2uiDataModel = {};
4689
+ if (this.a2ui.dataBindings) {
4690
+ for (const [a2uiPath, expression] of Object.entries(
4691
+ this.a2ui.dataBindings
4692
+ )) {
4693
+ const resolved = resolveValue(expression, varCtx);
4694
+ setNestedPath(a2uiDataModel, a2uiPath, resolved);
4695
+ }
4696
+ }
4697
+ const resolvedTitle = resolveValue(this.title, varCtx);
4698
+ const resolvedDescription = this.description ? resolveValue(this.description, varCtx) : void 0;
4699
+ const resolvedAssignee = this.assignee ? resolveValue(this.assignee, varCtx) : void 0;
4700
+ const tenantId = context.blackboard.get("__tenantId") || "";
4701
+ const executionId = context.blackboard.get("__executionId") || context.workflowInfo?.workflowId || "";
4702
+ const request = {
4703
+ nodeId: this.id,
4704
+ tenantId,
4705
+ executionId,
4706
+ title: resolvedTitle,
4707
+ description: resolvedDescription,
4708
+ assigneeEmail: resolvedAssignee,
4709
+ assigneeRole: this.assigneeRole,
4710
+ a2uiComponents: this.a2ui.components,
4711
+ a2uiDataModel,
4712
+ timeoutMs: this.timeoutMs,
4713
+ onTimeout: this.onTimeout
4714
+ };
4715
+ this.log(
4716
+ `Creating human task: "${resolvedTitle}" (timeout: ${this.timeoutMs}ms)`
4717
+ );
4718
+ const createResult = await context.activities.createHumanTask(request);
4719
+ this.log(`Task created: ${createResult.taskId}`);
4720
+ this.log(
4721
+ `Waiting for human task ${createResult.taskId} on node ${this.id}`
4722
+ );
4723
+ const waitResult = await context.activities.waitForHumanTask({
4724
+ taskId: createResult.taskId,
4725
+ nodeId: this.id,
4726
+ timeoutMs: this.timeoutMs,
4727
+ onTimeout: this.onTimeout
4728
+ });
4729
+ const prefix = this.outputKey || this.id;
4730
+ context.blackboard.set(`${prefix}.taskId`, createResult.taskId);
4731
+ context.blackboard.set(`${prefix}.completed`, waitResult.completed);
4732
+ context.blackboard.set(`${prefix}.decision`, waitResult.decision);
4733
+ context.blackboard.set(
4734
+ `${prefix}.submittedData`,
4735
+ waitResult.submittedData
4736
+ );
4737
+ context.blackboard.set(`${prefix}.completedBy`, waitResult.completedBy);
4738
+ context.blackboard.set(`${prefix}.timedOut`, waitResult.timedOut);
4739
+ if (waitResult.timedOut) {
4740
+ this._lastError = `Task timed out after ${this.timeoutMs}ms`;
4741
+ this.log(`Task timed out, onTimeout=${this.onTimeout}`);
4742
+ return this.onTimeout === "approve" ? "SUCCESS" /* SUCCESS */ : "FAILURE" /* FAILURE */;
4743
+ }
4744
+ this.log(
4745
+ `Task completed: decision=${waitResult.decision}, completedBy=${waitResult.completedBy}`
4746
+ );
4747
+ return waitResult.completed ? "SUCCESS" /* SUCCESS */ : "FAILURE" /* FAILURE */;
4748
+ } catch (error) {
4749
+ this._lastError = error instanceof Error ? error.message : String(error);
4750
+ this.log(`HumanTask failed: ${this._lastError}`);
4751
+ return "FAILURE" /* FAILURE */;
4752
+ }
4753
+ }
4754
+ };
4755
+ function setNestedPath(obj, path2, value) {
4756
+ const parts = path2.split("/").filter(Boolean);
4757
+ let current = obj;
4758
+ for (let i = 0; i < parts.length - 1; i++) {
4759
+ const key = parts[i];
4760
+ if (!(key in current) || typeof current[key] !== "object") {
4761
+ current[key] = {};
4762
+ }
4763
+ current = current[key];
4764
+ }
4765
+ if (parts.length > 0) {
4766
+ const lastKey = parts[parts.length - 1];
4767
+ current[lastKey] = value;
4768
+ }
4769
+ }
4770
+
4771
+ // src/actions/llm-tool-call.ts
4772
+ var LLMToolCall = class extends ActionNode {
4773
+ provider;
4774
+ model;
4775
+ systemPrompt;
4776
+ messagesKey;
4777
+ userMessageKey;
4778
+ toolsKey;
4779
+ tools;
4780
+ temperature;
4781
+ maxTokens;
4782
+ outputKey;
4783
+ constructor(config) {
4784
+ super(config);
4785
+ if (!config.provider) {
4786
+ throw new ConfigurationError("LLMToolCall requires provider");
4787
+ }
4788
+ if (!config.model) {
4789
+ throw new ConfigurationError("LLMToolCall requires model");
4790
+ }
4791
+ if (!config.messagesKey) {
4792
+ throw new ConfigurationError("LLMToolCall requires messagesKey");
4793
+ }
4794
+ if (!config.outputKey) {
4795
+ throw new ConfigurationError("LLMToolCall requires outputKey");
4796
+ }
4797
+ this.provider = config.provider;
4798
+ this.model = config.model;
4799
+ this.systemPrompt = config.systemPrompt;
4800
+ this.messagesKey = config.messagesKey;
4801
+ this.userMessageKey = config.userMessageKey;
4802
+ this.toolsKey = config.toolsKey;
4803
+ this.tools = config.tools;
4804
+ this.temperature = config.temperature;
4805
+ this.maxTokens = config.maxTokens;
4806
+ this.outputKey = config.outputKey;
4807
+ }
4808
+ async executeTick(context) {
4809
+ if (!context.activities?.agentLoopTurn) {
4810
+ this._lastError = "LLMToolCall requires activities.agentLoopTurn to be configured.";
4811
+ this.log(`Error: ${this._lastError}`);
4812
+ return "FAILURE" /* FAILURE */;
4813
+ }
4814
+ try {
4815
+ const varCtx = {
4816
+ blackboard: context.blackboard,
4817
+ input: context.input,
4818
+ testData: context.testData
4819
+ };
4820
+ let messages = context.blackboard.get(this.messagesKey) || [];
4821
+ if (this.userMessageKey) {
4822
+ const userMsg = context.blackboard.get(this.userMessageKey);
4823
+ if (userMsg !== void 0 && userMsg !== null) {
4824
+ const content = typeof userMsg === "string" ? userMsg : String(userMsg);
4825
+ messages = [...messages, { role: "user", content }];
4826
+ context.blackboard.set(this.userMessageKey, null);
4827
+ }
4828
+ }
4829
+ const tools = this.toolsKey ? context.blackboard.get(this.toolsKey) || [] : this.tools || [];
4830
+ const resolvedModel = resolveValue(this.model, varCtx);
4831
+ const resolvedSystemPrompt = this.systemPrompt ? resolveValue(this.systemPrompt, varCtx) : void 0;
4832
+ const streamChannelId = context.blackboard.get("__streamChannelId");
4833
+ const request = {
4834
+ provider: this.provider,
4835
+ model: resolvedModel,
4836
+ systemPrompt: resolvedSystemPrompt,
4837
+ messages,
4838
+ tools: tools.length > 0 ? tools : void 0,
4839
+ temperature: this.temperature,
4840
+ maxTokens: this.maxTokens,
4841
+ streamChannelId: streamChannelId || void 0
4842
+ };
4843
+ this.log(
4844
+ `LLMToolCall ${this.provider}/${resolvedModel} - ${messages.length} messages, ${tools.length} tools`
4845
+ );
4846
+ const result = await context.activities.agentLoopTurn(request);
4847
+ if (result.toolCalls && result.toolCalls.length > 0) {
4848
+ const contentBlocks = [];
4849
+ if (result.content) {
4850
+ contentBlocks.push({ type: "text", text: result.content });
4851
+ }
4852
+ for (const tc of result.toolCalls) {
4853
+ contentBlocks.push({
4854
+ type: "tool_use",
4855
+ id: tc.id,
4856
+ name: tc.name,
4857
+ input: tc.input
4858
+ });
4859
+ }
4860
+ messages = [...messages, { role: "assistant", content: contentBlocks }];
4861
+ } else {
4862
+ messages = [...messages, { role: "assistant", content: result.content }];
4863
+ }
4864
+ context.blackboard.set(this.messagesKey, messages);
4865
+ context.blackboard.set(this.outputKey, {
4866
+ content: result.content,
4867
+ toolCalls: result.toolCalls,
4868
+ stopReason: result.stopReason,
4869
+ usage: result.usage
4870
+ });
4871
+ this.log(
4872
+ `LLMToolCall completed: stopReason=${result.stopReason}, tools=${result.toolCalls?.length || 0}, tokens=${result.usage.totalTokens}`
4873
+ );
4874
+ return "SUCCESS" /* SUCCESS */;
4875
+ } catch (error) {
4876
+ this._lastError = error instanceof Error ? error.message : String(error);
4877
+ this.log(`LLMToolCall failed: ${this._lastError}`);
4878
+ return "FAILURE" /* FAILURE */;
4879
+ }
4880
+ }
4881
+ };
4882
+
4883
+ // src/actions/tool-executor.ts
4884
+ var ToolExecutor = class extends ActionNode {
4885
+ responseKey;
4886
+ messagesKey;
4887
+ outputKey;
4888
+ constructor(config) {
4889
+ super(config);
4890
+ if (!config.responseKey) {
4891
+ throw new ConfigurationError("ToolExecutor requires responseKey");
4892
+ }
4893
+ if (!config.messagesKey) {
4894
+ throw new ConfigurationError("ToolExecutor requires messagesKey");
4895
+ }
4896
+ this.responseKey = config.responseKey;
4897
+ this.messagesKey = config.messagesKey;
4898
+ this.outputKey = config.outputKey;
4899
+ }
4900
+ async executeTick(context) {
4901
+ if (!context.activities?.executeAgentTool) {
4902
+ this._lastError = "ToolExecutor requires activities.executeAgentTool to be configured.";
4903
+ this.log(`Error: ${this._lastError}`);
4904
+ return "FAILURE" /* FAILURE */;
4905
+ }
4906
+ try {
4907
+ const response = context.blackboard.get(this.responseKey);
4908
+ const toolCalls = response?.toolCalls;
4909
+ if (!toolCalls || toolCalls.length === 0) {
4910
+ this.log("No tool calls to execute");
4911
+ return "SUCCESS" /* SUCCESS */;
4912
+ }
4913
+ const toolResults = [];
4914
+ for (const tc of toolCalls) {
4915
+ this.log(`Executing tool: ${tc.name} (${tc.id})`);
4916
+ const result = await context.activities.executeAgentTool({
4917
+ toolName: tc.name,
4918
+ toolInput: tc.input
4919
+ });
4920
+ toolResults.push({
4921
+ toolUseId: tc.id,
4922
+ toolName: tc.name,
4923
+ content: result.content,
4924
+ isError: result.isError
4925
+ });
4926
+ this.log(
4927
+ `Tool ${tc.name} ${result.isError ? "errored" : "completed"}: ${result.content.substring(0, 100)}`
4928
+ );
4929
+ }
4930
+ const resultBlocks = toolResults.map((tr) => ({
4931
+ type: "tool_result",
4932
+ tool_use_id: tr.toolUseId,
4933
+ content: tr.content,
4934
+ is_error: tr.isError
4935
+ }));
4936
+ const messages = context.blackboard.get(this.messagesKey) || [];
4937
+ const updatedMessages = [
4938
+ ...messages,
4939
+ { role: "user", content: resultBlocks }
4940
+ ];
4941
+ context.blackboard.set(this.messagesKey, updatedMessages);
4942
+ if (this.outputKey) {
4943
+ context.blackboard.set(this.outputKey, toolResults);
4944
+ }
4945
+ this.log(`Executed ${toolResults.length} tool(s), results appended to conversation`);
4946
+ return "SUCCESS" /* SUCCESS */;
4947
+ } catch (error) {
4948
+ this._lastError = error instanceof Error ? error.message : String(error);
4949
+ this.log(`ToolExecutor failed: ${this._lastError}`);
4950
+ return "FAILURE" /* FAILURE */;
4951
+ }
4952
+ }
4953
+ };
4954
+
4955
+ // src/actions/wait-for-signal.ts
4956
+ var WaitForSignal = class extends ActionNode {
4957
+ signalName;
4958
+ signalKey;
4959
+ timeoutMs;
4960
+ outputKey;
4961
+ constructor(config) {
4962
+ super(config);
4963
+ if (!config.signalName) {
4964
+ throw new ConfigurationError("WaitForSignal requires signalName");
4965
+ }
4966
+ if (!config.outputKey) {
4967
+ throw new ConfigurationError("WaitForSignal requires outputKey");
4968
+ }
4969
+ this.signalName = config.signalName;
4970
+ this.signalKey = config.signalKey;
4971
+ this.timeoutMs = config.timeoutMs ?? 864e5;
4972
+ this.outputKey = config.outputKey;
4973
+ }
4974
+ async executeTick(context) {
4975
+ if (!context.activities?.waitForSignal) {
4976
+ this._lastError = "WaitForSignal requires activities.waitForSignal to be configured. This is implemented as a Temporal condition in the workflow layer.";
4977
+ this.log(`Error: ${this._lastError}`);
4978
+ return "FAILURE" /* FAILURE */;
4979
+ }
4980
+ try {
4981
+ const varCtx = {
4982
+ blackboard: context.blackboard,
4983
+ input: context.input,
4984
+ testData: context.testData
4985
+ };
4986
+ const resolvedSignalKey = this.signalKey ? resolveValue(this.signalKey, varCtx) : void 0;
4987
+ this.log(
4988
+ `Waiting for signal "${this.signalName}"${resolvedSignalKey ? `:${resolvedSignalKey}` : ""} (timeout: ${this.timeoutMs}ms)`
4989
+ );
4990
+ const result = await context.activities.waitForSignal({
4991
+ signalName: this.signalName,
4992
+ signalKey: resolvedSignalKey,
4993
+ timeoutMs: this.timeoutMs
4994
+ });
4995
+ if (result.timedOut) {
4996
+ this._lastError = `Signal "${this.signalName}" timed out after ${this.timeoutMs}ms`;
4997
+ this.log(this._lastError);
4998
+ return "FAILURE" /* FAILURE */;
4999
+ }
5000
+ context.blackboard.set(this.outputKey, result.data);
5001
+ this.log(`Signal received, data stored at "${this.outputKey}"`);
5002
+ return "SUCCESS" /* SUCCESS */;
5003
+ } catch (error) {
5004
+ this._lastError = error instanceof Error ? error.message : String(error);
5005
+ this.log(`WaitForSignal failed: ${this._lastError}`);
5006
+ return "FAILURE" /* FAILURE */;
5007
+ }
5008
+ }
5009
+ };
5010
+
5011
+ // src/actions/tool-router.ts
5012
+ var ToolRouter = class extends ActionNode {
5013
+ intentKey;
5014
+ toolSets;
5015
+ defaultTools;
5016
+ rules;
5017
+ outputKey;
5018
+ constructor(config) {
5019
+ super(config);
5020
+ if (!config.intentKey) {
5021
+ throw new ConfigurationError("ToolRouter requires intentKey");
5022
+ }
5023
+ if (!config.toolSets || Object.keys(config.toolSets).length === 0) {
5024
+ throw new ConfigurationError("ToolRouter requires at least one toolSet");
5025
+ }
5026
+ if (!config.outputKey) {
5027
+ throw new ConfigurationError("ToolRouter requires outputKey");
5028
+ }
5029
+ this.intentKey = config.intentKey;
5030
+ this.toolSets = config.toolSets;
5031
+ this.defaultTools = config.defaultTools || [];
5032
+ this.rules = config.rules || [];
5033
+ this.outputKey = config.outputKey;
5034
+ }
5035
+ async executeTick(context) {
5036
+ try {
5037
+ const varCtx = {
5038
+ blackboard: context.blackboard,
5039
+ input: context.input,
5040
+ testData: context.testData
5041
+ };
5042
+ const intentRaw = context.blackboard.get(this.intentKey);
5043
+ const intent = typeof intentRaw === "string" ? intentRaw : "";
5044
+ const selectedSetNames = new Set(this.defaultTools);
5045
+ for (const rule of this.rules) {
5046
+ const regex = new RegExp(rule.pattern, "i");
5047
+ if (regex.test(intent)) {
5048
+ for (const setName of rule.toolSets) {
5049
+ selectedSetNames.add(setName);
5050
+ }
5051
+ }
5052
+ }
5053
+ const toolsByName = /* @__PURE__ */ new Map();
5054
+ for (const setName of selectedSetNames) {
5055
+ const tools = this.toolSets[setName];
5056
+ if (tools) {
5057
+ for (const tool of tools) {
5058
+ if (!toolsByName.has(tool.name)) {
5059
+ toolsByName.set(tool.name, tool);
5060
+ }
5061
+ }
5062
+ }
5063
+ }
5064
+ const selectedTools = Array.from(toolsByName.values());
5065
+ context.blackboard.set(this.outputKey, selectedTools);
5066
+ this.log(
5067
+ `Selected ${selectedTools.length} tools from sets [${Array.from(selectedSetNames).join(", ")}] for intent "${intent.substring(0, 50)}"`
5068
+ );
5069
+ return "SUCCESS" /* SUCCESS */;
5070
+ } catch (error) {
5071
+ this._lastError = error instanceof Error ? error.message : String(error);
5072
+ this.log(`ToolRouter failed: ${this._lastError}`);
5073
+ return "FAILURE" /* FAILURE */;
5074
+ }
5075
+ }
5076
+ };
5077
+
4023
5078
  // src/registry-utils.ts
4024
5079
  function registerStandardNodes(registry) {
4025
5080
  registry.register("Sequence", Sequence, { category: "composite" });
@@ -4073,12 +5128,23 @@ function registerStandardNodes(registry) {
4073
5128
  registry.register("WaitAction", WaitAction, { category: "action" });
4074
5129
  registry.register("LogMessage", LogMessage, { category: "action" });
4075
5130
  registry.register("RegexExtract", RegexExtract, { category: "action" });
5131
+ registry.register("SetVariable", SetVariable, { category: "action" });
4076
5132
  registry.register("IntegrationAction", IntegrationAction, { category: "action" });
4077
5133
  registry.register("PythonScript", PythonScript, { category: "action" });
4078
5134
  registry.register("ParseFile", ParseFile, { category: "action" });
4079
5135
  registry.register("GenerateFile", GenerateFile, { category: "action" });
4080
5136
  registry.register("HttpRequest", HttpRequest, { category: "action" });
4081
5137
  registry.register("CodeExecution", CodeExecution, { category: "action" });
5138
+ registry.register("LLMChat", LLMChat, { category: "action" });
5139
+ registry.register("BrowserAgent", BrowserAgent, { category: "action" });
5140
+ registry.register("ClaudeAgent", ClaudeAgent, { category: "action" });
5141
+ registry.register("GitHubAction", GitHubAction, { category: "action" });
5142
+ registry.register("HumanTask", HumanTask, { category: "action" });
5143
+ registry.register("LLMToolCall", LLMToolCall, { category: "action" });
5144
+ registry.register("ToolExecutor", ToolExecutor, { category: "action" });
5145
+ registry.register("WaitForSignal", WaitForSignal, { category: "action" });
5146
+ registry.register("ToolRouter", ToolRouter, { category: "action" });
5147
+ registry.register("StreamingSink", StreamingSink, { category: "decorator" });
4082
5148
  }
4083
5149
 
4084
5150
  // src/data-store/memory-store.ts
@@ -4916,7 +5982,9 @@ function createObservabilitySinkHandler(config = {}) {
4916
5982
  AlwaysCondition,
4917
5983
  BaseNode,
4918
5984
  BehaviorTree,
5985
+ BrowserAgent,
4919
5986
  CheckCondition,
5987
+ ClaudeAgent,
4920
5988
  CodeExecution,
4921
5989
  CompositeNode,
4922
5990
  ConditionNode,
@@ -4933,10 +6001,14 @@ function createObservabilitySinkHandler(config = {}) {
4933
6001
  ForceFailure,
4934
6002
  ForceSuccess,
4935
6003
  GenerateFile,
6004
+ GitHubAction,
4936
6005
  HttpRequest,
6006
+ HumanTask,
4937
6007
  IntegrationAction,
4938
6008
  Invert,
4939
6009
  KeepRunningUntilFailure,
6010
+ LLMChat,
6011
+ LLMToolCall,
4940
6012
  LogMessage,
4941
6013
  MemoryDataStore,
4942
6014
  MemorySequence,
@@ -4963,14 +6035,19 @@ function createObservabilitySinkHandler(config = {}) {
4963
6035
  SemanticValidationError,
4964
6036
  Sequence,
4965
6037
  SequenceWithMemory,
6038
+ SetVariable,
4966
6039
  SoftAssert,
6040
+ StreamingSink,
4967
6041
  StructureValidationError,
4968
6042
  SubTree,
4969
6043
  SuccessNode,
4970
6044
  Timeout,
6045
+ ToolExecutor,
6046
+ ToolRouter,
4971
6047
  ValidationError,
4972
6048
  ValidationErrors,
4973
6049
  WaitAction,
6050
+ WaitForSignal,
4974
6051
  While,
4975
6052
  YamlSyntaxError,
4976
6053
  clearPieceCache,