@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.js CHANGED
@@ -286,6 +286,19 @@ var ActionNode = class extends BaseNode {
286
286
  });
287
287
  const status = await this.executeTick(context);
288
288
  this._status = status;
289
+ if (status === "FAILURE" /* FAILURE */ && this._lastError) {
290
+ context.eventEmitter?.emit({
291
+ type: "error" /* ERROR */,
292
+ nodeId: this.id,
293
+ nodeName: this.name,
294
+ nodeType: this.type,
295
+ timestamp: Date.now(),
296
+ data: {
297
+ error: { message: this._lastError },
298
+ blackboard: context.blackboard?.toJSON?.() ?? {}
299
+ }
300
+ });
301
+ }
289
302
  context.eventEmitter?.emit({
290
303
  type: "tick_end" /* TICK_END */,
291
304
  nodeId: this.id,
@@ -352,6 +365,19 @@ var ConditionNode = class extends BaseNode {
352
365
  });
353
366
  const status = await this.executeTick(context);
354
367
  this._status = status;
368
+ if (status === "FAILURE" /* FAILURE */ && this._lastError) {
369
+ context.eventEmitter?.emit({
370
+ type: "error" /* ERROR */,
371
+ nodeId: this.id,
372
+ nodeName: this.name,
373
+ nodeType: this.type,
374
+ timestamp: Date.now(),
375
+ data: {
376
+ error: { message: this._lastError },
377
+ blackboard: context.blackboard?.toJSON?.() ?? {}
378
+ }
379
+ });
380
+ }
355
381
  context.eventEmitter?.emit({
356
382
  type: "tick_end" /* TICK_END */,
357
383
  nodeId: this.id,
@@ -830,9 +856,9 @@ var BehaviorTree = class _BehaviorTree {
830
856
  *
831
857
  * @example
832
858
  * ```typescript
833
- * import { BehaviorTree } from '@wayfarer-ai/btree';
834
- * import { Sequence } from '@wayfarer-ai/btree';
835
- * import { PrintAction } from '@wayfarer-ai/btree';
859
+ * import { BehaviorTree } from '@q1k-oss/behaviour-tree-workflows';
860
+ * import { Sequence } from '@q1k-oss/behaviour-tree-workflows';
861
+ * import { PrintAction } from '@q1k-oss/behaviour-tree-workflows';
836
862
  *
837
863
  * const root = new Sequence({ id: 'root' });
838
864
  * root.addChild(new PrintAction({ id: 'step1', message: 'Hello' }));
@@ -2192,6 +2218,52 @@ var SoftAssert = class extends DecoratorNode {
2192
2218
  }
2193
2219
  };
2194
2220
 
2221
+ // src/decorators/streaming-sink.ts
2222
+ var StreamingSink = class extends DecoratorNode {
2223
+ channelId;
2224
+ channelKey;
2225
+ constructor(config) {
2226
+ super(config);
2227
+ if (!config.channelId && !config.channelKey) {
2228
+ throw new ConfigurationError(
2229
+ "StreamingSink requires either channelId or channelKey"
2230
+ );
2231
+ }
2232
+ this.channelId = config.channelId;
2233
+ this.channelKey = config.channelKey;
2234
+ }
2235
+ async executeTick(context) {
2236
+ if (!this.child) {
2237
+ throw new ConfigurationError(
2238
+ `${this.name}: Decorator must have a child`
2239
+ );
2240
+ }
2241
+ let resolvedChannelId = this.channelId;
2242
+ if (this.channelKey) {
2243
+ const varCtx = {
2244
+ blackboard: context.blackboard,
2245
+ input: context.input,
2246
+ testData: context.testData
2247
+ };
2248
+ resolvedChannelId = resolveValue(this.channelKey, varCtx);
2249
+ }
2250
+ const previousValue = context.blackboard.get("__streamChannelId");
2251
+ context.blackboard.set("__streamChannelId", resolvedChannelId);
2252
+ this.log(`Set streaming channel: ${resolvedChannelId}`);
2253
+ try {
2254
+ const childStatus = await this.child.tick(context);
2255
+ this._status = childStatus;
2256
+ return childStatus;
2257
+ } finally {
2258
+ if (previousValue !== void 0) {
2259
+ context.blackboard.set("__streamChannelId", previousValue);
2260
+ } else {
2261
+ context.blackboard.delete("__streamChannelId");
2262
+ }
2263
+ }
2264
+ }
2265
+ };
2266
+
2195
2267
  // src/decorators/timeout.ts
2196
2268
  import { CancellationScope, isCancellation } from "@temporalio/workflow";
2197
2269
  var Timeout = class extends DecoratorNode {
@@ -2414,8 +2486,136 @@ var memorySequenceConfigurationSchema = nodeConfigurationSchema;
2414
2486
  // src/composites/recovery.schema.ts
2415
2487
  var recoveryConfigurationSchema = nodeConfigurationSchema;
2416
2488
 
2417
- // src/schemas/validation.ts
2489
+ // src/actions/llm-chat.schema.ts
2418
2490
  import { z as z3 } from "zod";
2491
+ var messageSchema = z3.object({
2492
+ role: z3.enum(["system", "user", "assistant"]),
2493
+ content: z3.string().min(1, "Message content cannot be empty")
2494
+ });
2495
+ var llmChatSchema = createNodeSchema("LLMChat", {
2496
+ provider: z3.enum(["anthropic", "openai", "google", "ollama"]),
2497
+ model: z3.string().min(1, "Model is required"),
2498
+ messages: z3.array(messageSchema).min(1, "At least one message is required"),
2499
+ systemPrompt: z3.string().optional(),
2500
+ temperature: z3.number().min(0).max(2).optional(),
2501
+ maxTokens: z3.number().int().positive().optional(),
2502
+ responseFormat: z3.enum(["text", "json"]).optional().default("text"),
2503
+ jsonSchema: z3.record(z3.string(), z3.unknown()).optional(),
2504
+ timeout: z3.number().int().positive().optional().default(6e4),
2505
+ baseUrl: z3.string().url().optional(),
2506
+ outputKey: z3.string().min(1, "outputKey is required")
2507
+ });
2508
+
2509
+ // src/actions/browser-agent.schema.ts
2510
+ import { z as z4 } from "zod";
2511
+ var browserAgentSchema = createNodeSchema("BrowserAgent", {
2512
+ goal: z4.string().min(1, "Goal is required"),
2513
+ startUrl: z4.string().optional(),
2514
+ contextKey: z4.string().optional(),
2515
+ persistContext: z4.boolean().optional().default(false),
2516
+ timeout: z4.number().int().positive().optional().default(6e4),
2517
+ maxSteps: z4.number().int().positive().optional().default(20),
2518
+ llmProvider: z4.enum(["anthropic", "openai", "google", "ollama"]).optional(),
2519
+ llmModel: z4.string().optional(),
2520
+ outputKey: z4.string().min(1, "outputKey is required")
2521
+ });
2522
+
2523
+ // src/actions/human-task.schema.ts
2524
+ import { z as z5 } from "zod";
2525
+ var a2uiComponentSchema = z5.object({
2526
+ id: z5.string().min(1, "Component ID cannot be empty"),
2527
+ component: z5.record(z5.string(), z5.unknown()),
2528
+ weight: z5.number().optional()
2529
+ });
2530
+ var humanTaskSchema = createNodeSchema("HumanTask", {
2531
+ title: z5.string().min(1, "Title is required"),
2532
+ description: z5.string().optional(),
2533
+ assignee: z5.string().optional(),
2534
+ assigneeRole: z5.string().optional(),
2535
+ a2ui: z5.object({
2536
+ components: z5.array(a2uiComponentSchema).min(1, "At least one A2UI component is required"),
2537
+ dataBindings: z5.record(z5.string(), z5.string()).optional()
2538
+ }),
2539
+ timeoutMs: z5.number().int().positive().optional().default(864e5),
2540
+ onTimeout: z5.enum(["expire", "approve", "reject"]).optional().default("expire"),
2541
+ outputKey: z5.string().optional()
2542
+ });
2543
+
2544
+ // src/utilities/set-variable.schema.ts
2545
+ import { z as z6 } from "zod";
2546
+ var setVariableSchema = createNodeSchema("SetVariable", {
2547
+ key: z6.string().min(1, "key is required"),
2548
+ value: z6.unknown()
2549
+ });
2550
+
2551
+ // src/actions/llm-tool-call.schema.ts
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())
2557
+ });
2558
+ 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")
2569
+ });
2570
+
2571
+ // src/actions/tool-executor.schema.ts
2572
+ import { z as z8 } from "zod";
2573
+ 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()
2577
+ });
2578
+
2579
+ // src/actions/wait-for-signal.schema.ts
2580
+ import { z as z9 } from "zod";
2581
+ 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")
2586
+ });
2587
+
2588
+ // 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())
2594
+ });
2595
+ var ruleSchema = z10.object({
2596
+ pattern: z10.string().min(1),
2597
+ toolSets: z10.array(z10.string().min(1)).min(1)
2598
+ });
2599
+ 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")
2605
+ });
2606
+
2607
+ // src/decorators/streaming-sink.schema.ts
2608
+ import { z as z11 } from "zod";
2609
+ var streamingSinkSchema = createNodeSchema("StreamingSink", {
2610
+ channelId: z11.string().optional(),
2611
+ channelKey: z11.string().optional()
2612
+ }).refine(
2613
+ (data) => data.channelId || data.channelKey,
2614
+ { message: "Either channelId or channelKey must be provided" }
2615
+ );
2616
+
2617
+ // src/schemas/validation.ts
2618
+ import { z as z12 } from "zod";
2419
2619
  function zodErrorToConfigurationError(error, nodeType, nodeId) {
2420
2620
  const nodeIdentifier = nodeId ? `${nodeType}:${nodeId}` : nodeType;
2421
2621
  const issues = error.issues.map((issue) => {
@@ -2431,7 +2631,7 @@ function validateConfiguration(schema, config, nodeType, nodeId) {
2431
2631
  try {
2432
2632
  return schema.parse(config);
2433
2633
  } catch (error) {
2434
- if (error instanceof z3.ZodError) {
2634
+ if (error instanceof z12.ZodError) {
2435
2635
  throw zodErrorToConfigurationError(error, nodeType, nodeId);
2436
2636
  }
2437
2637
  throw error;
@@ -2450,14 +2650,14 @@ function safeValidateConfiguration(schema, config, nodeType, nodeId) {
2450
2650
  }
2451
2651
 
2452
2652
  // src/schemas/tree-definition.schema.ts
2453
- import { z as z4 } from "zod";
2454
- var treeDefSchemaObject = z4.object({
2455
- type: z4.string().min(1, "Node type is required"),
2456
- id: z4.string().optional(),
2457
- name: z4.string().optional(),
2458
- props: z4.record(z4.string(), z4.unknown()).optional(),
2459
- children: z4.array(
2460
- z4.lazy(() => treeDefinitionSchema)
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)
2461
2661
  ).optional()
2462
2662
  });
2463
2663
  var treeDefinitionSchema = treeDefSchemaObject;
@@ -2536,6 +2736,15 @@ var SchemaRegistry = class {
2536
2736
  this.register("ReactiveSequence", reactiveSequenceConfigurationSchema);
2537
2737
  this.register("MemorySequence", memorySequenceConfigurationSchema);
2538
2738
  this.register("Recovery", recoveryConfigurationSchema);
2739
+ this.register("LLMChat", llmChatSchema);
2740
+ this.register("BrowserAgent", browserAgentSchema);
2741
+ this.register("HumanTask", humanTaskSchema);
2742
+ this.register("SetVariable", setVariableSchema);
2743
+ this.register("LLMToolCall", llmToolCallSchema);
2744
+ this.register("ToolExecutor", toolExecutorSchema);
2745
+ this.register("WaitForSignal", waitForSignalSchema);
2746
+ this.register("ToolRouter", toolRouterSchema);
2747
+ this.register("StreamingSink", streamingSinkSchema);
2539
2748
  }
2540
2749
  /**
2541
2750
  * Register a validation schema for a node type
@@ -3005,8 +3214,32 @@ var CheckCondition = class extends ConditionNode {
3005
3214
  this.operator = config.operator || "==";
3006
3215
  this.value = config.value;
3007
3216
  }
3217
+ /**
3218
+ * Resolve a potentially dotted key from the blackboard.
3219
+ * Tries exact key first (backward compatible), then dotted path traversal.
3220
+ */
3221
+ resolveBlackboardValue(context) {
3222
+ const exact = context.blackboard.get(this.key);
3223
+ if (exact !== void 0) {
3224
+ return exact;
3225
+ }
3226
+ if (this.key.includes(".")) {
3227
+ const segments = this.key.split(".");
3228
+ const rootKey = segments[0];
3229
+ let current = context.blackboard.get(rootKey);
3230
+ for (let i = 1; i < segments.length; i++) {
3231
+ if (current == null || typeof current !== "object") {
3232
+ return void 0;
3233
+ }
3234
+ const segment = segments[i];
3235
+ current = current[segment];
3236
+ }
3237
+ return current;
3238
+ }
3239
+ return void 0;
3240
+ }
3008
3241
  async executeTick(context) {
3009
- const actualValue = context.blackboard.get(this.key);
3242
+ const actualValue = this.resolveBlackboardValue(context);
3010
3243
  let result = false;
3011
3244
  switch (this.operator) {
3012
3245
  case "==":
@@ -3198,6 +3431,35 @@ var RegexExtract = class extends ActionNode {
3198
3431
  }
3199
3432
  };
3200
3433
 
3434
+ // src/utilities/set-variable.ts
3435
+ var SetVariable = class extends ActionNode {
3436
+ key;
3437
+ value;
3438
+ constructor(config) {
3439
+ super(config);
3440
+ this.key = config.key;
3441
+ this.value = config.value;
3442
+ }
3443
+ async executeTick(context) {
3444
+ try {
3445
+ const varCtx = {
3446
+ blackboard: context.blackboard,
3447
+ input: context.input,
3448
+ testData: context.testData
3449
+ };
3450
+ const resolvedKey = typeof this.key === "string" ? resolveValue(this.key, varCtx) : String(this.key);
3451
+ const resolvedValue = typeof this.value === "string" ? resolveValue(this.value, varCtx) : this.value;
3452
+ context.blackboard.set(resolvedKey, resolvedValue);
3453
+ this.log(`Set ${resolvedKey} = ${JSON.stringify(resolvedValue)}`);
3454
+ return "SUCCESS" /* SUCCESS */;
3455
+ } catch (error) {
3456
+ this._lastError = error instanceof Error ? error.message : String(error);
3457
+ this.log(`SetVariable failed: ${this._lastError}`);
3458
+ return "FAILURE" /* FAILURE */;
3459
+ }
3460
+ }
3461
+ };
3462
+
3201
3463
  // src/integrations/piece-executor.ts
3202
3464
  var PROVIDER_TO_PIECE = {
3203
3465
  // Google services
@@ -3889,6 +4151,788 @@ var CodeExecution = class extends ActionNode {
3889
4151
  }
3890
4152
  };
3891
4153
 
4154
+ // src/actions/llm-chat.ts
4155
+ var LLMChat = class extends ActionNode {
4156
+ provider;
4157
+ model;
4158
+ messages;
4159
+ systemPrompt;
4160
+ temperature;
4161
+ maxTokens;
4162
+ responseFormat;
4163
+ jsonSchema;
4164
+ timeout;
4165
+ baseUrl;
4166
+ outputKey;
4167
+ constructor(config) {
4168
+ super(config);
4169
+ if (!config.provider) {
4170
+ throw new ConfigurationError("LLMChat requires provider");
4171
+ }
4172
+ if (!config.model) {
4173
+ throw new ConfigurationError("LLMChat requires model");
4174
+ }
4175
+ if (!config.messages || config.messages.length === 0) {
4176
+ throw new ConfigurationError(
4177
+ "LLMChat requires at least one message"
4178
+ );
4179
+ }
4180
+ if (!config.outputKey) {
4181
+ throw new ConfigurationError("LLMChat requires outputKey");
4182
+ }
4183
+ this.provider = config.provider;
4184
+ this.model = config.model;
4185
+ this.messages = config.messages;
4186
+ this.systemPrompt = config.systemPrompt;
4187
+ this.temperature = config.temperature;
4188
+ this.maxTokens = config.maxTokens;
4189
+ this.responseFormat = config.responseFormat || "text";
4190
+ this.jsonSchema = config.jsonSchema;
4191
+ this.timeout = config.timeout;
4192
+ this.baseUrl = config.baseUrl;
4193
+ this.outputKey = config.outputKey;
4194
+ }
4195
+ async executeTick(context) {
4196
+ if (!context.activities?.llmChat) {
4197
+ this._lastError = "LLMChat requires activities.llmChat to be configured. This activity handles LLM API calls outside the workflow sandbox.";
4198
+ this.log(`Error: ${this._lastError}`);
4199
+ return "FAILURE" /* FAILURE */;
4200
+ }
4201
+ try {
4202
+ const varCtx = {
4203
+ blackboard: context.blackboard,
4204
+ input: context.input,
4205
+ testData: context.testData
4206
+ };
4207
+ const resolvedMessages = this.messages.map((msg) => ({
4208
+ role: msg.role,
4209
+ content: resolveValue(msg.content, varCtx)
4210
+ }));
4211
+ const resolvedSystemPrompt = this.systemPrompt ? resolveValue(this.systemPrompt, varCtx) : void 0;
4212
+ const resolvedModel = resolveValue(this.model, varCtx);
4213
+ const request = {
4214
+ provider: this.provider,
4215
+ model: resolvedModel,
4216
+ messages: resolvedMessages,
4217
+ systemPrompt: resolvedSystemPrompt,
4218
+ temperature: this.temperature,
4219
+ maxTokens: this.maxTokens,
4220
+ responseFormat: this.responseFormat,
4221
+ jsonSchema: this.jsonSchema,
4222
+ timeout: this.timeout,
4223
+ baseUrl: this.baseUrl
4224
+ };
4225
+ this.log(
4226
+ `LLM ${this.provider}/${resolvedModel} - ${resolvedMessages.length} messages`
4227
+ );
4228
+ const result = await context.activities.llmChat(request);
4229
+ context.blackboard.set(this.outputKey, result);
4230
+ if (result.finishReason === "error") {
4231
+ this._lastError = `LLM returned error: ${result.content}`;
4232
+ this.log(`Error: ${this._lastError}`);
4233
+ return "FAILURE" /* FAILURE */;
4234
+ }
4235
+ this.log(
4236
+ `LLM ${this.provider}/${resolvedModel} completed: ${result.usage.totalTokens} tokens, finish: ${result.finishReason}`
4237
+ );
4238
+ return "SUCCESS" /* SUCCESS */;
4239
+ } catch (error) {
4240
+ this._lastError = error instanceof Error ? error.message : String(error);
4241
+ this.log(`LLM chat failed: ${this._lastError}`);
4242
+ return "FAILURE" /* FAILURE */;
4243
+ }
4244
+ }
4245
+ };
4246
+
4247
+ // src/actions/browser-agent.ts
4248
+ var BrowserAgent = class extends ActionNode {
4249
+ goal;
4250
+ startUrl;
4251
+ contextKey;
4252
+ persistContext;
4253
+ timeout;
4254
+ maxSteps;
4255
+ llmProvider;
4256
+ llmModel;
4257
+ outputKey;
4258
+ constructor(config) {
4259
+ super(config);
4260
+ if (!config.goal) {
4261
+ throw new ConfigurationError("BrowserAgent requires goal");
4262
+ }
4263
+ if (!config.outputKey) {
4264
+ throw new ConfigurationError("BrowserAgent requires outputKey");
4265
+ }
4266
+ this.goal = config.goal;
4267
+ this.startUrl = config.startUrl;
4268
+ this.contextKey = config.contextKey;
4269
+ this.persistContext = config.persistContext ?? false;
4270
+ this.timeout = config.timeout;
4271
+ this.maxSteps = config.maxSteps;
4272
+ this.llmProvider = config.llmProvider;
4273
+ this.llmModel = config.llmModel;
4274
+ this.outputKey = config.outputKey;
4275
+ }
4276
+ async executeTick(context) {
4277
+ if (!context.activities?.browserAgent) {
4278
+ this._lastError = "BrowserAgent requires activities.browserAgent to be configured. This activity handles browser automation via Browserbase + Stagehand.";
4279
+ this.log(`Error: ${this._lastError}`);
4280
+ return "FAILURE" /* FAILURE */;
4281
+ }
4282
+ try {
4283
+ const varCtx = {
4284
+ blackboard: context.blackboard,
4285
+ input: context.input,
4286
+ testData: context.testData
4287
+ };
4288
+ const resolvedGoal = resolveValue(this.goal, varCtx);
4289
+ const resolvedStartUrl = this.startUrl ? resolveValue(this.startUrl, varCtx) : void 0;
4290
+ const contextId = this.contextKey ? context.blackboard.get(this.contextKey) : void 0;
4291
+ const request = {
4292
+ goal: resolvedGoal,
4293
+ startUrl: resolvedStartUrl,
4294
+ contextId,
4295
+ persistContext: this.persistContext,
4296
+ timeout: this.timeout,
4297
+ maxSteps: this.maxSteps,
4298
+ llmProvider: this.llmProvider,
4299
+ llmModel: this.llmModel
4300
+ };
4301
+ this.log(
4302
+ `Browser agent: ${resolvedGoal.substring(0, 50)}${resolvedGoal.length > 50 ? "..." : ""}`
4303
+ );
4304
+ const result = await context.activities.browserAgent(request);
4305
+ if (this.contextKey && result.contextId) {
4306
+ context.blackboard.set(this.contextKey, result.contextId);
4307
+ }
4308
+ context.blackboard.set(this.outputKey, result);
4309
+ if (!result.success) {
4310
+ this._lastError = `Browser agent failed to achieve goal: ${result.message}`;
4311
+ this.log(`Error: ${this._lastError}`);
4312
+ this.log(`Debug session: ${result.debugUrl}`);
4313
+ return "FAILURE" /* FAILURE */;
4314
+ }
4315
+ if (!result.completed) {
4316
+ this._lastError = `Browser agent hit step limit before completing: ${result.message}`;
4317
+ this.log(`Error: ${this._lastError}`);
4318
+ this.log(`Debug session: ${result.debugUrl}`);
4319
+ return "FAILURE" /* FAILURE */;
4320
+ }
4321
+ this.log(`Browser agent succeeded: ${result.message}`);
4322
+ this.log(`Debug session: ${result.debugUrl}`);
4323
+ return "SUCCESS" /* SUCCESS */;
4324
+ } catch (error) {
4325
+ this._lastError = error instanceof Error ? error.message : String(error);
4326
+ this.log(`Browser agent failed: ${this._lastError}`);
4327
+ return "FAILURE" /* FAILURE */;
4328
+ }
4329
+ }
4330
+ };
4331
+
4332
+ // src/actions/claude-agent.ts
4333
+ var ClaudeAgent = class extends ActionNode {
4334
+ prompt;
4335
+ model;
4336
+ systemPrompt;
4337
+ allowedTools;
4338
+ permissionMode;
4339
+ maxTurns;
4340
+ maxBudgetUsd;
4341
+ agentCwd;
4342
+ mcpServers;
4343
+ agents;
4344
+ outputKey;
4345
+ constructor(config) {
4346
+ super(config);
4347
+ if (!config.prompt) {
4348
+ throw new ConfigurationError("ClaudeAgent requires prompt");
4349
+ }
4350
+ if (!config.outputKey) {
4351
+ throw new ConfigurationError("ClaudeAgent requires outputKey");
4352
+ }
4353
+ this.prompt = config.prompt;
4354
+ this.model = config.model;
4355
+ this.systemPrompt = config.systemPrompt;
4356
+ this.allowedTools = config.allowedTools;
4357
+ this.permissionMode = config.permissionMode ?? "default";
4358
+ this.maxTurns = config.maxTurns ?? 50;
4359
+ this.maxBudgetUsd = config.maxBudgetUsd;
4360
+ this.agentCwd = config.cwd;
4361
+ this.mcpServers = config.mcpServers;
4362
+ this.agents = config.agents;
4363
+ this.outputKey = config.outputKey;
4364
+ }
4365
+ async executeTick(context) {
4366
+ if (!context.activities?.claudeAgent) {
4367
+ this._lastError = "ClaudeAgent requires activities.claudeAgent to be configured. This activity handles autonomous agent execution via the Claude Agent SDK.";
4368
+ this.log(`Error: ${this._lastError}`);
4369
+ return "FAILURE" /* FAILURE */;
4370
+ }
4371
+ try {
4372
+ const varCtx = {
4373
+ blackboard: context.blackboard,
4374
+ input: context.input,
4375
+ testData: context.testData
4376
+ };
4377
+ const resolvedPrompt = resolveValue(this.prompt, varCtx);
4378
+ const resolvedSystemPrompt = this.systemPrompt ? resolveValue(this.systemPrompt, varCtx) : void 0;
4379
+ const resolvedModel = this.model ? resolveValue(this.model, varCtx) : void 0;
4380
+ const resolvedCwd = this.agentCwd ? resolveValue(this.agentCwd, varCtx) : void 0;
4381
+ const request = {
4382
+ prompt: resolvedPrompt,
4383
+ model: resolvedModel,
4384
+ systemPrompt: resolvedSystemPrompt,
4385
+ allowedTools: this.allowedTools,
4386
+ permissionMode: this.permissionMode,
4387
+ maxTurns: this.maxTurns,
4388
+ maxBudgetUsd: this.maxBudgetUsd,
4389
+ cwd: resolvedCwd,
4390
+ mcpServers: this.mcpServers,
4391
+ agents: this.agents
4392
+ };
4393
+ this.log(
4394
+ `Claude agent: ${resolvedPrompt.substring(0, 80)}${resolvedPrompt.length > 80 ? "..." : ""}`
4395
+ );
4396
+ const result = await context.activities.claudeAgent(request);
4397
+ context.blackboard.set(this.outputKey, result);
4398
+ if (!result.success) {
4399
+ this._lastError = `Claude agent failed: ${result.errors?.join(", ") || "unknown error"}`;
4400
+ this.log(`Error: ${this._lastError}`);
4401
+ return "FAILURE" /* FAILURE */;
4402
+ }
4403
+ this.log(
4404
+ `Claude agent completed in ${result.numTurns} turns, $${result.totalCostUsd.toFixed(4)}, ${result.durationMs}ms`
4405
+ );
4406
+ return "SUCCESS" /* SUCCESS */;
4407
+ } catch (error) {
4408
+ this._lastError = error instanceof Error ? error.message : String(error);
4409
+ this.log(`Claude agent failed: ${this._lastError}`);
4410
+ return "FAILURE" /* FAILURE */;
4411
+ }
4412
+ }
4413
+ };
4414
+
4415
+ // src/actions/github-action.ts
4416
+ var VALID_OPERATIONS = [
4417
+ "createBranch",
4418
+ "createPullRequest",
4419
+ "getPullRequest",
4420
+ "mergePullRequest",
4421
+ "closePullRequest",
4422
+ "createReview",
4423
+ "listIssues",
4424
+ "addLabels",
4425
+ "createComment",
4426
+ "createRelease"
4427
+ ];
4428
+ var GitHubAction = class extends ActionNode {
4429
+ operation;
4430
+ repo;
4431
+ params;
4432
+ outputKey;
4433
+ constructor(config) {
4434
+ super(config);
4435
+ if (!config.operation) {
4436
+ throw new ConfigurationError("GitHubAction requires operation");
4437
+ }
4438
+ if (!VALID_OPERATIONS.includes(config.operation)) {
4439
+ throw new ConfigurationError(
4440
+ `GitHubAction: invalid operation "${config.operation}". Valid operations: ${VALID_OPERATIONS.join(", ")}`
4441
+ );
4442
+ }
4443
+ if (!config.repo) {
4444
+ throw new ConfigurationError("GitHubAction requires repo");
4445
+ }
4446
+ if (!config.outputKey) {
4447
+ throw new ConfigurationError("GitHubAction requires outputKey");
4448
+ }
4449
+ this.operation = config.operation;
4450
+ this.repo = config.repo;
4451
+ this.params = config.params ?? {};
4452
+ this.outputKey = config.outputKey;
4453
+ }
4454
+ async executeTick(context) {
4455
+ if (!context.activities?.githubAction) {
4456
+ this._lastError = "GitHubAction requires activities.githubAction to be configured. This activity handles GitHub API operations.";
4457
+ this.log(`Error: ${this._lastError}`);
4458
+ return "FAILURE" /* FAILURE */;
4459
+ }
4460
+ try {
4461
+ const varCtx = {
4462
+ blackboard: context.blackboard,
4463
+ input: context.input,
4464
+ testData: context.testData
4465
+ };
4466
+ const resolvedRepo = resolveValue(this.repo, varCtx);
4467
+ const resolvedParams = {};
4468
+ for (const [key, value] of Object.entries(this.params)) {
4469
+ if (typeof value === "string") {
4470
+ resolvedParams[key] = resolveValue(value, varCtx);
4471
+ } else {
4472
+ resolvedParams[key] = value;
4473
+ }
4474
+ }
4475
+ const request = {
4476
+ operation: this.operation,
4477
+ repo: resolvedRepo,
4478
+ params: resolvedParams
4479
+ };
4480
+ this.log(
4481
+ `GitHub ${this.operation}: ${resolvedRepo}`
4482
+ );
4483
+ const result = await context.activities.githubAction(request);
4484
+ context.blackboard.set(this.outputKey, result.data);
4485
+ if (!result.success) {
4486
+ this._lastError = `GitHub ${this.operation} failed`;
4487
+ this.log(`Error: ${this._lastError}`);
4488
+ return "FAILURE" /* FAILURE */;
4489
+ }
4490
+ this.log(`GitHub ${this.operation} completed successfully`);
4491
+ return "SUCCESS" /* SUCCESS */;
4492
+ } catch (error) {
4493
+ this._lastError = error instanceof Error ? error.message : String(error);
4494
+ this.log(`GitHub ${this.operation} failed: ${this._lastError}`);
4495
+ return "FAILURE" /* FAILURE */;
4496
+ }
4497
+ }
4498
+ };
4499
+
4500
+ // src/actions/human-task.ts
4501
+ var HumanTask = class extends ActionNode {
4502
+ title;
4503
+ description;
4504
+ assignee;
4505
+ assigneeRole;
4506
+ a2ui;
4507
+ timeoutMs;
4508
+ onTimeout;
4509
+ outputKey;
4510
+ constructor(config) {
4511
+ super(config);
4512
+ if (!config.title) {
4513
+ throw new ConfigurationError("HumanTask requires title");
4514
+ }
4515
+ if (!config.a2ui?.components || config.a2ui.components.length === 0) {
4516
+ throw new ConfigurationError(
4517
+ "HumanTask requires a2ui.components with at least one component"
4518
+ );
4519
+ }
4520
+ this.title = config.title;
4521
+ this.description = config.description;
4522
+ this.assignee = config.assignee;
4523
+ this.assigneeRole = config.assigneeRole;
4524
+ this.a2ui = config.a2ui;
4525
+ this.timeoutMs = config.timeoutMs ?? 864e5;
4526
+ this.onTimeout = config.onTimeout ?? "expire";
4527
+ this.outputKey = config.outputKey;
4528
+ }
4529
+ async executeTick(context) {
4530
+ if (!context.activities?.createHumanTask) {
4531
+ this._lastError = "HumanTask requires activities.createHumanTask to be configured. This activity creates a task record in the database.";
4532
+ this.log(`Error: ${this._lastError}`);
4533
+ return "FAILURE" /* FAILURE */;
4534
+ }
4535
+ if (!context.activities?.waitForHumanTask) {
4536
+ this._lastError = "HumanTask requires activities.waitForHumanTask to be configured. This activity waits for the user to complete the task.";
4537
+ this.log(`Error: ${this._lastError}`);
4538
+ return "FAILURE" /* FAILURE */;
4539
+ }
4540
+ try {
4541
+ const varCtx = {
4542
+ blackboard: context.blackboard,
4543
+ input: context.input,
4544
+ testData: context.testData
4545
+ };
4546
+ const a2uiDataModel = {};
4547
+ if (this.a2ui.dataBindings) {
4548
+ for (const [a2uiPath, expression] of Object.entries(
4549
+ this.a2ui.dataBindings
4550
+ )) {
4551
+ const resolved = resolveValue(expression, varCtx);
4552
+ setNestedPath(a2uiDataModel, a2uiPath, resolved);
4553
+ }
4554
+ }
4555
+ const resolvedTitle = resolveValue(this.title, varCtx);
4556
+ const resolvedDescription = this.description ? resolveValue(this.description, varCtx) : void 0;
4557
+ const resolvedAssignee = this.assignee ? resolveValue(this.assignee, varCtx) : void 0;
4558
+ const tenantId = context.blackboard.get("__tenantId") || "";
4559
+ const executionId = context.blackboard.get("__executionId") || context.workflowInfo?.workflowId || "";
4560
+ const request = {
4561
+ nodeId: this.id,
4562
+ tenantId,
4563
+ executionId,
4564
+ title: resolvedTitle,
4565
+ description: resolvedDescription,
4566
+ assigneeEmail: resolvedAssignee,
4567
+ assigneeRole: this.assigneeRole,
4568
+ a2uiComponents: this.a2ui.components,
4569
+ a2uiDataModel,
4570
+ timeoutMs: this.timeoutMs,
4571
+ onTimeout: this.onTimeout
4572
+ };
4573
+ this.log(
4574
+ `Creating human task: "${resolvedTitle}" (timeout: ${this.timeoutMs}ms)`
4575
+ );
4576
+ const createResult = await context.activities.createHumanTask(request);
4577
+ this.log(`Task created: ${createResult.taskId}`);
4578
+ this.log(
4579
+ `Waiting for human task ${createResult.taskId} on node ${this.id}`
4580
+ );
4581
+ const waitResult = await context.activities.waitForHumanTask({
4582
+ taskId: createResult.taskId,
4583
+ nodeId: this.id,
4584
+ timeoutMs: this.timeoutMs,
4585
+ onTimeout: this.onTimeout
4586
+ });
4587
+ const prefix = this.outputKey || this.id;
4588
+ context.blackboard.set(`${prefix}.taskId`, createResult.taskId);
4589
+ context.blackboard.set(`${prefix}.completed`, waitResult.completed);
4590
+ context.blackboard.set(`${prefix}.decision`, waitResult.decision);
4591
+ context.blackboard.set(
4592
+ `${prefix}.submittedData`,
4593
+ waitResult.submittedData
4594
+ );
4595
+ context.blackboard.set(`${prefix}.completedBy`, waitResult.completedBy);
4596
+ context.blackboard.set(`${prefix}.timedOut`, waitResult.timedOut);
4597
+ if (waitResult.timedOut) {
4598
+ this._lastError = `Task timed out after ${this.timeoutMs}ms`;
4599
+ this.log(`Task timed out, onTimeout=${this.onTimeout}`);
4600
+ return this.onTimeout === "approve" ? "SUCCESS" /* SUCCESS */ : "FAILURE" /* FAILURE */;
4601
+ }
4602
+ this.log(
4603
+ `Task completed: decision=${waitResult.decision}, completedBy=${waitResult.completedBy}`
4604
+ );
4605
+ return waitResult.completed ? "SUCCESS" /* SUCCESS */ : "FAILURE" /* FAILURE */;
4606
+ } catch (error) {
4607
+ this._lastError = error instanceof Error ? error.message : String(error);
4608
+ this.log(`HumanTask failed: ${this._lastError}`);
4609
+ return "FAILURE" /* FAILURE */;
4610
+ }
4611
+ }
4612
+ };
4613
+ function setNestedPath(obj, path2, value) {
4614
+ const parts = path2.split("/").filter(Boolean);
4615
+ let current = obj;
4616
+ for (let i = 0; i < parts.length - 1; i++) {
4617
+ const key = parts[i];
4618
+ if (!(key in current) || typeof current[key] !== "object") {
4619
+ current[key] = {};
4620
+ }
4621
+ current = current[key];
4622
+ }
4623
+ if (parts.length > 0) {
4624
+ const lastKey = parts[parts.length - 1];
4625
+ current[lastKey] = value;
4626
+ }
4627
+ }
4628
+
4629
+ // src/actions/llm-tool-call.ts
4630
+ var LLMToolCall = class extends ActionNode {
4631
+ provider;
4632
+ model;
4633
+ systemPrompt;
4634
+ messagesKey;
4635
+ userMessageKey;
4636
+ toolsKey;
4637
+ tools;
4638
+ temperature;
4639
+ maxTokens;
4640
+ outputKey;
4641
+ constructor(config) {
4642
+ super(config);
4643
+ if (!config.provider) {
4644
+ throw new ConfigurationError("LLMToolCall requires provider");
4645
+ }
4646
+ if (!config.model) {
4647
+ throw new ConfigurationError("LLMToolCall requires model");
4648
+ }
4649
+ if (!config.messagesKey) {
4650
+ throw new ConfigurationError("LLMToolCall requires messagesKey");
4651
+ }
4652
+ if (!config.outputKey) {
4653
+ throw new ConfigurationError("LLMToolCall requires outputKey");
4654
+ }
4655
+ this.provider = config.provider;
4656
+ this.model = config.model;
4657
+ this.systemPrompt = config.systemPrompt;
4658
+ this.messagesKey = config.messagesKey;
4659
+ this.userMessageKey = config.userMessageKey;
4660
+ this.toolsKey = config.toolsKey;
4661
+ this.tools = config.tools;
4662
+ this.temperature = config.temperature;
4663
+ this.maxTokens = config.maxTokens;
4664
+ this.outputKey = config.outputKey;
4665
+ }
4666
+ async executeTick(context) {
4667
+ if (!context.activities?.agentLoopTurn) {
4668
+ this._lastError = "LLMToolCall requires activities.agentLoopTurn to be configured.";
4669
+ this.log(`Error: ${this._lastError}`);
4670
+ return "FAILURE" /* FAILURE */;
4671
+ }
4672
+ try {
4673
+ const varCtx = {
4674
+ blackboard: context.blackboard,
4675
+ input: context.input,
4676
+ testData: context.testData
4677
+ };
4678
+ let messages = context.blackboard.get(this.messagesKey) || [];
4679
+ if (this.userMessageKey) {
4680
+ const userMsg = context.blackboard.get(this.userMessageKey);
4681
+ if (userMsg !== void 0 && userMsg !== null) {
4682
+ const content = typeof userMsg === "string" ? userMsg : String(userMsg);
4683
+ messages = [...messages, { role: "user", content }];
4684
+ context.blackboard.set(this.userMessageKey, null);
4685
+ }
4686
+ }
4687
+ const tools = this.toolsKey ? context.blackboard.get(this.toolsKey) || [] : this.tools || [];
4688
+ const resolvedModel = resolveValue(this.model, varCtx);
4689
+ const resolvedSystemPrompt = this.systemPrompt ? resolveValue(this.systemPrompt, varCtx) : void 0;
4690
+ const streamChannelId = context.blackboard.get("__streamChannelId");
4691
+ const request = {
4692
+ provider: this.provider,
4693
+ model: resolvedModel,
4694
+ systemPrompt: resolvedSystemPrompt,
4695
+ messages,
4696
+ tools: tools.length > 0 ? tools : void 0,
4697
+ temperature: this.temperature,
4698
+ maxTokens: this.maxTokens,
4699
+ streamChannelId: streamChannelId || void 0
4700
+ };
4701
+ this.log(
4702
+ `LLMToolCall ${this.provider}/${resolvedModel} - ${messages.length} messages, ${tools.length} tools`
4703
+ );
4704
+ const result = await context.activities.agentLoopTurn(request);
4705
+ if (result.toolCalls && result.toolCalls.length > 0) {
4706
+ const contentBlocks = [];
4707
+ if (result.content) {
4708
+ contentBlocks.push({ type: "text", text: result.content });
4709
+ }
4710
+ for (const tc of result.toolCalls) {
4711
+ contentBlocks.push({
4712
+ type: "tool_use",
4713
+ id: tc.id,
4714
+ name: tc.name,
4715
+ input: tc.input
4716
+ });
4717
+ }
4718
+ messages = [...messages, { role: "assistant", content: contentBlocks }];
4719
+ } else {
4720
+ messages = [...messages, { role: "assistant", content: result.content }];
4721
+ }
4722
+ context.blackboard.set(this.messagesKey, messages);
4723
+ context.blackboard.set(this.outputKey, {
4724
+ content: result.content,
4725
+ toolCalls: result.toolCalls,
4726
+ stopReason: result.stopReason,
4727
+ usage: result.usage
4728
+ });
4729
+ this.log(
4730
+ `LLMToolCall completed: stopReason=${result.stopReason}, tools=${result.toolCalls?.length || 0}, tokens=${result.usage.totalTokens}`
4731
+ );
4732
+ return "SUCCESS" /* SUCCESS */;
4733
+ } catch (error) {
4734
+ this._lastError = error instanceof Error ? error.message : String(error);
4735
+ this.log(`LLMToolCall failed: ${this._lastError}`);
4736
+ return "FAILURE" /* FAILURE */;
4737
+ }
4738
+ }
4739
+ };
4740
+
4741
+ // src/actions/tool-executor.ts
4742
+ var ToolExecutor = class extends ActionNode {
4743
+ responseKey;
4744
+ messagesKey;
4745
+ outputKey;
4746
+ constructor(config) {
4747
+ super(config);
4748
+ if (!config.responseKey) {
4749
+ throw new ConfigurationError("ToolExecutor requires responseKey");
4750
+ }
4751
+ if (!config.messagesKey) {
4752
+ throw new ConfigurationError("ToolExecutor requires messagesKey");
4753
+ }
4754
+ this.responseKey = config.responseKey;
4755
+ this.messagesKey = config.messagesKey;
4756
+ this.outputKey = config.outputKey;
4757
+ }
4758
+ async executeTick(context) {
4759
+ if (!context.activities?.executeAgentTool) {
4760
+ this._lastError = "ToolExecutor requires activities.executeAgentTool to be configured.";
4761
+ this.log(`Error: ${this._lastError}`);
4762
+ return "FAILURE" /* FAILURE */;
4763
+ }
4764
+ try {
4765
+ const response = context.blackboard.get(this.responseKey);
4766
+ const toolCalls = response?.toolCalls;
4767
+ if (!toolCalls || toolCalls.length === 0) {
4768
+ this.log("No tool calls to execute");
4769
+ return "SUCCESS" /* SUCCESS */;
4770
+ }
4771
+ const toolResults = [];
4772
+ for (const tc of toolCalls) {
4773
+ this.log(`Executing tool: ${tc.name} (${tc.id})`);
4774
+ const result = await context.activities.executeAgentTool({
4775
+ toolName: tc.name,
4776
+ toolInput: tc.input
4777
+ });
4778
+ toolResults.push({
4779
+ toolUseId: tc.id,
4780
+ toolName: tc.name,
4781
+ content: result.content,
4782
+ isError: result.isError
4783
+ });
4784
+ this.log(
4785
+ `Tool ${tc.name} ${result.isError ? "errored" : "completed"}: ${result.content.substring(0, 100)}`
4786
+ );
4787
+ }
4788
+ const resultBlocks = toolResults.map((tr) => ({
4789
+ type: "tool_result",
4790
+ tool_use_id: tr.toolUseId,
4791
+ content: tr.content,
4792
+ is_error: tr.isError
4793
+ }));
4794
+ const messages = context.blackboard.get(this.messagesKey) || [];
4795
+ const updatedMessages = [
4796
+ ...messages,
4797
+ { role: "user", content: resultBlocks }
4798
+ ];
4799
+ context.blackboard.set(this.messagesKey, updatedMessages);
4800
+ if (this.outputKey) {
4801
+ context.blackboard.set(this.outputKey, toolResults);
4802
+ }
4803
+ this.log(`Executed ${toolResults.length} tool(s), results appended to conversation`);
4804
+ return "SUCCESS" /* SUCCESS */;
4805
+ } catch (error) {
4806
+ this._lastError = error instanceof Error ? error.message : String(error);
4807
+ this.log(`ToolExecutor failed: ${this._lastError}`);
4808
+ return "FAILURE" /* FAILURE */;
4809
+ }
4810
+ }
4811
+ };
4812
+
4813
+ // src/actions/wait-for-signal.ts
4814
+ var WaitForSignal = class extends ActionNode {
4815
+ signalName;
4816
+ signalKey;
4817
+ timeoutMs;
4818
+ outputKey;
4819
+ constructor(config) {
4820
+ super(config);
4821
+ if (!config.signalName) {
4822
+ throw new ConfigurationError("WaitForSignal requires signalName");
4823
+ }
4824
+ if (!config.outputKey) {
4825
+ throw new ConfigurationError("WaitForSignal requires outputKey");
4826
+ }
4827
+ this.signalName = config.signalName;
4828
+ this.signalKey = config.signalKey;
4829
+ this.timeoutMs = config.timeoutMs ?? 864e5;
4830
+ this.outputKey = config.outputKey;
4831
+ }
4832
+ async executeTick(context) {
4833
+ if (!context.activities?.waitForSignal) {
4834
+ this._lastError = "WaitForSignal requires activities.waitForSignal to be configured. This is implemented as a Temporal condition in the workflow layer.";
4835
+ this.log(`Error: ${this._lastError}`);
4836
+ return "FAILURE" /* FAILURE */;
4837
+ }
4838
+ try {
4839
+ const varCtx = {
4840
+ blackboard: context.blackboard,
4841
+ input: context.input,
4842
+ testData: context.testData
4843
+ };
4844
+ const resolvedSignalKey = this.signalKey ? resolveValue(this.signalKey, varCtx) : void 0;
4845
+ this.log(
4846
+ `Waiting for signal "${this.signalName}"${resolvedSignalKey ? `:${resolvedSignalKey}` : ""} (timeout: ${this.timeoutMs}ms)`
4847
+ );
4848
+ const result = await context.activities.waitForSignal({
4849
+ signalName: this.signalName,
4850
+ signalKey: resolvedSignalKey,
4851
+ timeoutMs: this.timeoutMs
4852
+ });
4853
+ if (result.timedOut) {
4854
+ this._lastError = `Signal "${this.signalName}" timed out after ${this.timeoutMs}ms`;
4855
+ this.log(this._lastError);
4856
+ return "FAILURE" /* FAILURE */;
4857
+ }
4858
+ context.blackboard.set(this.outputKey, result.data);
4859
+ this.log(`Signal received, data stored at "${this.outputKey}"`);
4860
+ return "SUCCESS" /* SUCCESS */;
4861
+ } catch (error) {
4862
+ this._lastError = error instanceof Error ? error.message : String(error);
4863
+ this.log(`WaitForSignal failed: ${this._lastError}`);
4864
+ return "FAILURE" /* FAILURE */;
4865
+ }
4866
+ }
4867
+ };
4868
+
4869
+ // src/actions/tool-router.ts
4870
+ var ToolRouter = class extends ActionNode {
4871
+ intentKey;
4872
+ toolSets;
4873
+ defaultTools;
4874
+ rules;
4875
+ outputKey;
4876
+ constructor(config) {
4877
+ super(config);
4878
+ if (!config.intentKey) {
4879
+ throw new ConfigurationError("ToolRouter requires intentKey");
4880
+ }
4881
+ if (!config.toolSets || Object.keys(config.toolSets).length === 0) {
4882
+ throw new ConfigurationError("ToolRouter requires at least one toolSet");
4883
+ }
4884
+ if (!config.outputKey) {
4885
+ throw new ConfigurationError("ToolRouter requires outputKey");
4886
+ }
4887
+ this.intentKey = config.intentKey;
4888
+ this.toolSets = config.toolSets;
4889
+ this.defaultTools = config.defaultTools || [];
4890
+ this.rules = config.rules || [];
4891
+ this.outputKey = config.outputKey;
4892
+ }
4893
+ async executeTick(context) {
4894
+ try {
4895
+ const varCtx = {
4896
+ blackboard: context.blackboard,
4897
+ input: context.input,
4898
+ testData: context.testData
4899
+ };
4900
+ const intentRaw = context.blackboard.get(this.intentKey);
4901
+ const intent = typeof intentRaw === "string" ? intentRaw : "";
4902
+ const selectedSetNames = new Set(this.defaultTools);
4903
+ for (const rule of this.rules) {
4904
+ const regex = new RegExp(rule.pattern, "i");
4905
+ if (regex.test(intent)) {
4906
+ for (const setName of rule.toolSets) {
4907
+ selectedSetNames.add(setName);
4908
+ }
4909
+ }
4910
+ }
4911
+ const toolsByName = /* @__PURE__ */ new Map();
4912
+ for (const setName of selectedSetNames) {
4913
+ const tools = this.toolSets[setName];
4914
+ if (tools) {
4915
+ for (const tool of tools) {
4916
+ if (!toolsByName.has(tool.name)) {
4917
+ toolsByName.set(tool.name, tool);
4918
+ }
4919
+ }
4920
+ }
4921
+ }
4922
+ const selectedTools = Array.from(toolsByName.values());
4923
+ context.blackboard.set(this.outputKey, selectedTools);
4924
+ this.log(
4925
+ `Selected ${selectedTools.length} tools from sets [${Array.from(selectedSetNames).join(", ")}] for intent "${intent.substring(0, 50)}"`
4926
+ );
4927
+ return "SUCCESS" /* SUCCESS */;
4928
+ } catch (error) {
4929
+ this._lastError = error instanceof Error ? error.message : String(error);
4930
+ this.log(`ToolRouter failed: ${this._lastError}`);
4931
+ return "FAILURE" /* FAILURE */;
4932
+ }
4933
+ }
4934
+ };
4935
+
3892
4936
  // src/registry-utils.ts
3893
4937
  function registerStandardNodes(registry) {
3894
4938
  registry.register("Sequence", Sequence, { category: "composite" });
@@ -3942,12 +4986,23 @@ function registerStandardNodes(registry) {
3942
4986
  registry.register("WaitAction", WaitAction, { category: "action" });
3943
4987
  registry.register("LogMessage", LogMessage, { category: "action" });
3944
4988
  registry.register("RegexExtract", RegexExtract, { category: "action" });
4989
+ registry.register("SetVariable", SetVariable, { category: "action" });
3945
4990
  registry.register("IntegrationAction", IntegrationAction, { category: "action" });
3946
4991
  registry.register("PythonScript", PythonScript, { category: "action" });
3947
4992
  registry.register("ParseFile", ParseFile, { category: "action" });
3948
4993
  registry.register("GenerateFile", GenerateFile, { category: "action" });
3949
4994
  registry.register("HttpRequest", HttpRequest, { category: "action" });
3950
4995
  registry.register("CodeExecution", CodeExecution, { category: "action" });
4996
+ registry.register("LLMChat", LLMChat, { category: "action" });
4997
+ registry.register("BrowserAgent", BrowserAgent, { category: "action" });
4998
+ registry.register("ClaudeAgent", ClaudeAgent, { category: "action" });
4999
+ registry.register("GitHubAction", GitHubAction, { category: "action" });
5000
+ registry.register("HumanTask", HumanTask, { category: "action" });
5001
+ registry.register("LLMToolCall", LLMToolCall, { category: "action" });
5002
+ registry.register("ToolExecutor", ToolExecutor, { category: "action" });
5003
+ registry.register("WaitForSignal", WaitForSignal, { category: "action" });
5004
+ registry.register("ToolRouter", ToolRouter, { category: "action" });
5005
+ registry.register("StreamingSink", StreamingSink, { category: "decorator" });
3951
5006
  }
3952
5007
 
3953
5008
  // src/data-store/memory-store.ts
@@ -4784,7 +5839,9 @@ export {
4784
5839
  AlwaysCondition,
4785
5840
  BaseNode,
4786
5841
  BehaviorTree,
5842
+ BrowserAgent,
4787
5843
  CheckCondition,
5844
+ ClaudeAgent,
4788
5845
  CodeExecution,
4789
5846
  CompositeNode,
4790
5847
  ConditionNode,
@@ -4801,10 +5858,14 @@ export {
4801
5858
  ForceFailure,
4802
5859
  ForceSuccess,
4803
5860
  GenerateFile,
5861
+ GitHubAction,
4804
5862
  HttpRequest,
5863
+ HumanTask,
4805
5864
  IntegrationAction,
4806
5865
  Invert,
4807
5866
  KeepRunningUntilFailure,
5867
+ LLMChat,
5868
+ LLMToolCall,
4808
5869
  LogMessage,
4809
5870
  MemoryDataStore,
4810
5871
  MemorySequence,
@@ -4831,14 +5892,19 @@ export {
4831
5892
  SemanticValidationError,
4832
5893
  Sequence,
4833
5894
  SequenceWithMemory,
5895
+ SetVariable,
4834
5896
  SoftAssert,
5897
+ StreamingSink,
4835
5898
  StructureValidationError,
4836
5899
  SubTree,
4837
5900
  SuccessNode,
4838
5901
  Timeout,
5902
+ ToolExecutor,
5903
+ ToolRouter,
4839
5904
  ValidationError,
4840
5905
  ValidationErrors,
4841
5906
  WaitAction,
5907
+ WaitForSignal,
4842
5908
  While,
4843
5909
  YamlSyntaxError,
4844
5910
  clearPieceCache,