@q1k-oss/behaviour-tree-workflows 0.0.1 → 0.0.2
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 +587 -13
- package/dist/index.d.cts +790 -10
- package/dist/index.d.ts +790 -10
- package/dist/index.js +582 -13
- package/package.json +1 -1
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 '@
|
|
834
|
-
* import { Sequence } from '@
|
|
835
|
-
* import { PrintAction } from '@
|
|
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' }));
|
|
@@ -2414,8 +2440,63 @@ var memorySequenceConfigurationSchema = nodeConfigurationSchema;
|
|
|
2414
2440
|
// src/composites/recovery.schema.ts
|
|
2415
2441
|
var recoveryConfigurationSchema = nodeConfigurationSchema;
|
|
2416
2442
|
|
|
2417
|
-
// src/
|
|
2443
|
+
// src/actions/llm-chat.schema.ts
|
|
2418
2444
|
import { z as z3 } from "zod";
|
|
2445
|
+
var messageSchema = z3.object({
|
|
2446
|
+
role: z3.enum(["system", "user", "assistant"]),
|
|
2447
|
+
content: z3.string().min(1, "Message content cannot be empty")
|
|
2448
|
+
});
|
|
2449
|
+
var llmChatSchema = createNodeSchema("LLMChat", {
|
|
2450
|
+
provider: z3.enum(["anthropic", "openai", "google", "ollama"]),
|
|
2451
|
+
model: z3.string().min(1, "Model is required"),
|
|
2452
|
+
messages: z3.array(messageSchema).min(1, "At least one message is required"),
|
|
2453
|
+
systemPrompt: z3.string().optional(),
|
|
2454
|
+
temperature: z3.number().min(0).max(2).optional(),
|
|
2455
|
+
maxTokens: z3.number().int().positive().optional(),
|
|
2456
|
+
responseFormat: z3.enum(["text", "json"]).optional().default("text"),
|
|
2457
|
+
jsonSchema: z3.record(z3.string(), z3.unknown()).optional(),
|
|
2458
|
+
timeout: z3.number().int().positive().optional().default(6e4),
|
|
2459
|
+
baseUrl: z3.string().url().optional(),
|
|
2460
|
+
outputKey: z3.string().min(1, "outputKey is required")
|
|
2461
|
+
});
|
|
2462
|
+
|
|
2463
|
+
// src/actions/browser-agent.schema.ts
|
|
2464
|
+
import { z as z4 } from "zod";
|
|
2465
|
+
var browserAgentSchema = createNodeSchema("BrowserAgent", {
|
|
2466
|
+
goal: z4.string().min(1, "Goal is required"),
|
|
2467
|
+
startUrl: z4.string().optional(),
|
|
2468
|
+
contextKey: z4.string().optional(),
|
|
2469
|
+
persistContext: z4.boolean().optional().default(false),
|
|
2470
|
+
timeout: z4.number().int().positive().optional().default(6e4),
|
|
2471
|
+
maxSteps: z4.number().int().positive().optional().default(20),
|
|
2472
|
+
llmProvider: z4.enum(["anthropic", "openai", "google", "ollama"]).optional(),
|
|
2473
|
+
llmModel: z4.string().optional(),
|
|
2474
|
+
outputKey: z4.string().min(1, "outputKey is required")
|
|
2475
|
+
});
|
|
2476
|
+
|
|
2477
|
+
// src/actions/human-task.schema.ts
|
|
2478
|
+
import { z as z5 } from "zod";
|
|
2479
|
+
var a2uiComponentSchema = z5.object({
|
|
2480
|
+
id: z5.string().min(1, "Component ID cannot be empty"),
|
|
2481
|
+
component: z5.record(z5.string(), z5.unknown()),
|
|
2482
|
+
weight: z5.number().optional()
|
|
2483
|
+
});
|
|
2484
|
+
var humanTaskSchema = createNodeSchema("HumanTask", {
|
|
2485
|
+
title: z5.string().min(1, "Title is required"),
|
|
2486
|
+
description: z5.string().optional(),
|
|
2487
|
+
assignee: z5.string().optional(),
|
|
2488
|
+
assigneeRole: z5.string().optional(),
|
|
2489
|
+
a2ui: z5.object({
|
|
2490
|
+
components: z5.array(a2uiComponentSchema).min(1, "At least one A2UI component is required"),
|
|
2491
|
+
dataBindings: z5.record(z5.string(), z5.string()).optional()
|
|
2492
|
+
}),
|
|
2493
|
+
timeoutMs: z5.number().int().positive().optional().default(864e5),
|
|
2494
|
+
onTimeout: z5.enum(["expire", "approve", "reject"]).optional().default("expire"),
|
|
2495
|
+
outputKey: z5.string().optional()
|
|
2496
|
+
});
|
|
2497
|
+
|
|
2498
|
+
// src/schemas/validation.ts
|
|
2499
|
+
import { z as z6 } from "zod";
|
|
2419
2500
|
function zodErrorToConfigurationError(error, nodeType, nodeId) {
|
|
2420
2501
|
const nodeIdentifier = nodeId ? `${nodeType}:${nodeId}` : nodeType;
|
|
2421
2502
|
const issues = error.issues.map((issue) => {
|
|
@@ -2431,7 +2512,7 @@ function validateConfiguration(schema, config, nodeType, nodeId) {
|
|
|
2431
2512
|
try {
|
|
2432
2513
|
return schema.parse(config);
|
|
2433
2514
|
} catch (error) {
|
|
2434
|
-
if (error instanceof
|
|
2515
|
+
if (error instanceof z6.ZodError) {
|
|
2435
2516
|
throw zodErrorToConfigurationError(error, nodeType, nodeId);
|
|
2436
2517
|
}
|
|
2437
2518
|
throw error;
|
|
@@ -2450,14 +2531,14 @@ function safeValidateConfiguration(schema, config, nodeType, nodeId) {
|
|
|
2450
2531
|
}
|
|
2451
2532
|
|
|
2452
2533
|
// src/schemas/tree-definition.schema.ts
|
|
2453
|
-
import { z as
|
|
2454
|
-
var treeDefSchemaObject =
|
|
2455
|
-
type:
|
|
2456
|
-
id:
|
|
2457
|
-
name:
|
|
2458
|
-
props:
|
|
2459
|
-
children:
|
|
2460
|
-
|
|
2534
|
+
import { z as z7 } from "zod";
|
|
2535
|
+
var treeDefSchemaObject = z7.object({
|
|
2536
|
+
type: z7.string().min(1, "Node type is required"),
|
|
2537
|
+
id: z7.string().optional(),
|
|
2538
|
+
name: z7.string().optional(),
|
|
2539
|
+
props: z7.record(z7.string(), z7.unknown()).optional(),
|
|
2540
|
+
children: z7.array(
|
|
2541
|
+
z7.lazy(() => treeDefinitionSchema)
|
|
2461
2542
|
).optional()
|
|
2462
2543
|
});
|
|
2463
2544
|
var treeDefinitionSchema = treeDefSchemaObject;
|
|
@@ -2536,6 +2617,9 @@ var SchemaRegistry = class {
|
|
|
2536
2617
|
this.register("ReactiveSequence", reactiveSequenceConfigurationSchema);
|
|
2537
2618
|
this.register("MemorySequence", memorySequenceConfigurationSchema);
|
|
2538
2619
|
this.register("Recovery", recoveryConfigurationSchema);
|
|
2620
|
+
this.register("LLMChat", llmChatSchema);
|
|
2621
|
+
this.register("BrowserAgent", browserAgentSchema);
|
|
2622
|
+
this.register("HumanTask", humanTaskSchema);
|
|
2539
2623
|
}
|
|
2540
2624
|
/**
|
|
2541
2625
|
* Register a validation schema for a node type
|
|
@@ -3889,6 +3973,481 @@ var CodeExecution = class extends ActionNode {
|
|
|
3889
3973
|
}
|
|
3890
3974
|
};
|
|
3891
3975
|
|
|
3976
|
+
// src/actions/llm-chat.ts
|
|
3977
|
+
var LLMChat = class extends ActionNode {
|
|
3978
|
+
provider;
|
|
3979
|
+
model;
|
|
3980
|
+
messages;
|
|
3981
|
+
systemPrompt;
|
|
3982
|
+
temperature;
|
|
3983
|
+
maxTokens;
|
|
3984
|
+
responseFormat;
|
|
3985
|
+
jsonSchema;
|
|
3986
|
+
timeout;
|
|
3987
|
+
baseUrl;
|
|
3988
|
+
outputKey;
|
|
3989
|
+
constructor(config) {
|
|
3990
|
+
super(config);
|
|
3991
|
+
if (!config.provider) {
|
|
3992
|
+
throw new ConfigurationError("LLMChat requires provider");
|
|
3993
|
+
}
|
|
3994
|
+
if (!config.model) {
|
|
3995
|
+
throw new ConfigurationError("LLMChat requires model");
|
|
3996
|
+
}
|
|
3997
|
+
if (!config.messages || config.messages.length === 0) {
|
|
3998
|
+
throw new ConfigurationError(
|
|
3999
|
+
"LLMChat requires at least one message"
|
|
4000
|
+
);
|
|
4001
|
+
}
|
|
4002
|
+
if (!config.outputKey) {
|
|
4003
|
+
throw new ConfigurationError("LLMChat requires outputKey");
|
|
4004
|
+
}
|
|
4005
|
+
this.provider = config.provider;
|
|
4006
|
+
this.model = config.model;
|
|
4007
|
+
this.messages = config.messages;
|
|
4008
|
+
this.systemPrompt = config.systemPrompt;
|
|
4009
|
+
this.temperature = config.temperature;
|
|
4010
|
+
this.maxTokens = config.maxTokens;
|
|
4011
|
+
this.responseFormat = config.responseFormat || "text";
|
|
4012
|
+
this.jsonSchema = config.jsonSchema;
|
|
4013
|
+
this.timeout = config.timeout;
|
|
4014
|
+
this.baseUrl = config.baseUrl;
|
|
4015
|
+
this.outputKey = config.outputKey;
|
|
4016
|
+
}
|
|
4017
|
+
async executeTick(context) {
|
|
4018
|
+
if (!context.activities?.llmChat) {
|
|
4019
|
+
this._lastError = "LLMChat requires activities.llmChat to be configured. This activity handles LLM API calls outside the workflow sandbox.";
|
|
4020
|
+
this.log(`Error: ${this._lastError}`);
|
|
4021
|
+
return "FAILURE" /* FAILURE */;
|
|
4022
|
+
}
|
|
4023
|
+
try {
|
|
4024
|
+
const varCtx = {
|
|
4025
|
+
blackboard: context.blackboard,
|
|
4026
|
+
input: context.input,
|
|
4027
|
+
testData: context.testData
|
|
4028
|
+
};
|
|
4029
|
+
const resolvedMessages = this.messages.map((msg) => ({
|
|
4030
|
+
role: msg.role,
|
|
4031
|
+
content: resolveValue(msg.content, varCtx)
|
|
4032
|
+
}));
|
|
4033
|
+
const resolvedSystemPrompt = this.systemPrompt ? resolveValue(this.systemPrompt, varCtx) : void 0;
|
|
4034
|
+
const resolvedModel = resolveValue(this.model, varCtx);
|
|
4035
|
+
const request = {
|
|
4036
|
+
provider: this.provider,
|
|
4037
|
+
model: resolvedModel,
|
|
4038
|
+
messages: resolvedMessages,
|
|
4039
|
+
systemPrompt: resolvedSystemPrompt,
|
|
4040
|
+
temperature: this.temperature,
|
|
4041
|
+
maxTokens: this.maxTokens,
|
|
4042
|
+
responseFormat: this.responseFormat,
|
|
4043
|
+
jsonSchema: this.jsonSchema,
|
|
4044
|
+
timeout: this.timeout,
|
|
4045
|
+
baseUrl: this.baseUrl
|
|
4046
|
+
};
|
|
4047
|
+
this.log(
|
|
4048
|
+
`LLM ${this.provider}/${resolvedModel} - ${resolvedMessages.length} messages`
|
|
4049
|
+
);
|
|
4050
|
+
const result = await context.activities.llmChat(request);
|
|
4051
|
+
context.blackboard.set(this.outputKey, result);
|
|
4052
|
+
if (result.finishReason === "error") {
|
|
4053
|
+
this._lastError = `LLM returned error: ${result.content}`;
|
|
4054
|
+
this.log(`Error: ${this._lastError}`);
|
|
4055
|
+
return "FAILURE" /* FAILURE */;
|
|
4056
|
+
}
|
|
4057
|
+
this.log(
|
|
4058
|
+
`LLM ${this.provider}/${resolvedModel} completed: ${result.usage.totalTokens} tokens, finish: ${result.finishReason}`
|
|
4059
|
+
);
|
|
4060
|
+
return "SUCCESS" /* SUCCESS */;
|
|
4061
|
+
} catch (error) {
|
|
4062
|
+
this._lastError = error instanceof Error ? error.message : String(error);
|
|
4063
|
+
this.log(`LLM chat failed: ${this._lastError}`);
|
|
4064
|
+
return "FAILURE" /* FAILURE */;
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
4067
|
+
};
|
|
4068
|
+
|
|
4069
|
+
// src/actions/browser-agent.ts
|
|
4070
|
+
var BrowserAgent = class extends ActionNode {
|
|
4071
|
+
goal;
|
|
4072
|
+
startUrl;
|
|
4073
|
+
contextKey;
|
|
4074
|
+
persistContext;
|
|
4075
|
+
timeout;
|
|
4076
|
+
maxSteps;
|
|
4077
|
+
llmProvider;
|
|
4078
|
+
llmModel;
|
|
4079
|
+
outputKey;
|
|
4080
|
+
constructor(config) {
|
|
4081
|
+
super(config);
|
|
4082
|
+
if (!config.goal) {
|
|
4083
|
+
throw new ConfigurationError("BrowserAgent requires goal");
|
|
4084
|
+
}
|
|
4085
|
+
if (!config.outputKey) {
|
|
4086
|
+
throw new ConfigurationError("BrowserAgent requires outputKey");
|
|
4087
|
+
}
|
|
4088
|
+
this.goal = config.goal;
|
|
4089
|
+
this.startUrl = config.startUrl;
|
|
4090
|
+
this.contextKey = config.contextKey;
|
|
4091
|
+
this.persistContext = config.persistContext ?? false;
|
|
4092
|
+
this.timeout = config.timeout;
|
|
4093
|
+
this.maxSteps = config.maxSteps;
|
|
4094
|
+
this.llmProvider = config.llmProvider;
|
|
4095
|
+
this.llmModel = config.llmModel;
|
|
4096
|
+
this.outputKey = config.outputKey;
|
|
4097
|
+
}
|
|
4098
|
+
async executeTick(context) {
|
|
4099
|
+
if (!context.activities?.browserAgent) {
|
|
4100
|
+
this._lastError = "BrowserAgent requires activities.browserAgent to be configured. This activity handles browser automation via Browserbase + Stagehand.";
|
|
4101
|
+
this.log(`Error: ${this._lastError}`);
|
|
4102
|
+
return "FAILURE" /* FAILURE */;
|
|
4103
|
+
}
|
|
4104
|
+
try {
|
|
4105
|
+
const varCtx = {
|
|
4106
|
+
blackboard: context.blackboard,
|
|
4107
|
+
input: context.input,
|
|
4108
|
+
testData: context.testData
|
|
4109
|
+
};
|
|
4110
|
+
const resolvedGoal = resolveValue(this.goal, varCtx);
|
|
4111
|
+
const resolvedStartUrl = this.startUrl ? resolveValue(this.startUrl, varCtx) : void 0;
|
|
4112
|
+
const contextId = this.contextKey ? context.blackboard.get(this.contextKey) : void 0;
|
|
4113
|
+
const request = {
|
|
4114
|
+
goal: resolvedGoal,
|
|
4115
|
+
startUrl: resolvedStartUrl,
|
|
4116
|
+
contextId,
|
|
4117
|
+
persistContext: this.persistContext,
|
|
4118
|
+
timeout: this.timeout,
|
|
4119
|
+
maxSteps: this.maxSteps,
|
|
4120
|
+
llmProvider: this.llmProvider,
|
|
4121
|
+
llmModel: this.llmModel
|
|
4122
|
+
};
|
|
4123
|
+
this.log(
|
|
4124
|
+
`Browser agent: ${resolvedGoal.substring(0, 50)}${resolvedGoal.length > 50 ? "..." : ""}`
|
|
4125
|
+
);
|
|
4126
|
+
const result = await context.activities.browserAgent(request);
|
|
4127
|
+
if (this.contextKey && result.contextId) {
|
|
4128
|
+
context.blackboard.set(this.contextKey, result.contextId);
|
|
4129
|
+
}
|
|
4130
|
+
context.blackboard.set(this.outputKey, result);
|
|
4131
|
+
if (!result.success) {
|
|
4132
|
+
this._lastError = `Browser agent failed to achieve goal: ${result.message}`;
|
|
4133
|
+
this.log(`Error: ${this._lastError}`);
|
|
4134
|
+
this.log(`Debug session: ${result.debugUrl}`);
|
|
4135
|
+
return "FAILURE" /* FAILURE */;
|
|
4136
|
+
}
|
|
4137
|
+
if (!result.completed) {
|
|
4138
|
+
this._lastError = `Browser agent hit step limit before completing: ${result.message}`;
|
|
4139
|
+
this.log(`Error: ${this._lastError}`);
|
|
4140
|
+
this.log(`Debug session: ${result.debugUrl}`);
|
|
4141
|
+
return "FAILURE" /* FAILURE */;
|
|
4142
|
+
}
|
|
4143
|
+
this.log(`Browser agent succeeded: ${result.message}`);
|
|
4144
|
+
this.log(`Debug session: ${result.debugUrl}`);
|
|
4145
|
+
return "SUCCESS" /* SUCCESS */;
|
|
4146
|
+
} catch (error) {
|
|
4147
|
+
this._lastError = error instanceof Error ? error.message : String(error);
|
|
4148
|
+
this.log(`Browser agent failed: ${this._lastError}`);
|
|
4149
|
+
return "FAILURE" /* FAILURE */;
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
};
|
|
4153
|
+
|
|
4154
|
+
// src/actions/claude-agent.ts
|
|
4155
|
+
var ClaudeAgent = class extends ActionNode {
|
|
4156
|
+
prompt;
|
|
4157
|
+
model;
|
|
4158
|
+
systemPrompt;
|
|
4159
|
+
allowedTools;
|
|
4160
|
+
permissionMode;
|
|
4161
|
+
maxTurns;
|
|
4162
|
+
maxBudgetUsd;
|
|
4163
|
+
agentCwd;
|
|
4164
|
+
mcpServers;
|
|
4165
|
+
agents;
|
|
4166
|
+
outputKey;
|
|
4167
|
+
constructor(config) {
|
|
4168
|
+
super(config);
|
|
4169
|
+
if (!config.prompt) {
|
|
4170
|
+
throw new ConfigurationError("ClaudeAgent requires prompt");
|
|
4171
|
+
}
|
|
4172
|
+
if (!config.outputKey) {
|
|
4173
|
+
throw new ConfigurationError("ClaudeAgent requires outputKey");
|
|
4174
|
+
}
|
|
4175
|
+
this.prompt = config.prompt;
|
|
4176
|
+
this.model = config.model;
|
|
4177
|
+
this.systemPrompt = config.systemPrompt;
|
|
4178
|
+
this.allowedTools = config.allowedTools;
|
|
4179
|
+
this.permissionMode = config.permissionMode ?? "default";
|
|
4180
|
+
this.maxTurns = config.maxTurns ?? 50;
|
|
4181
|
+
this.maxBudgetUsd = config.maxBudgetUsd;
|
|
4182
|
+
this.agentCwd = config.cwd;
|
|
4183
|
+
this.mcpServers = config.mcpServers;
|
|
4184
|
+
this.agents = config.agents;
|
|
4185
|
+
this.outputKey = config.outputKey;
|
|
4186
|
+
}
|
|
4187
|
+
async executeTick(context) {
|
|
4188
|
+
if (!context.activities?.claudeAgent) {
|
|
4189
|
+
this._lastError = "ClaudeAgent requires activities.claudeAgent to be configured. This activity handles autonomous agent execution via the Claude Agent SDK.";
|
|
4190
|
+
this.log(`Error: ${this._lastError}`);
|
|
4191
|
+
return "FAILURE" /* FAILURE */;
|
|
4192
|
+
}
|
|
4193
|
+
try {
|
|
4194
|
+
const varCtx = {
|
|
4195
|
+
blackboard: context.blackboard,
|
|
4196
|
+
input: context.input,
|
|
4197
|
+
testData: context.testData
|
|
4198
|
+
};
|
|
4199
|
+
const resolvedPrompt = resolveValue(this.prompt, varCtx);
|
|
4200
|
+
const resolvedSystemPrompt = this.systemPrompt ? resolveValue(this.systemPrompt, varCtx) : void 0;
|
|
4201
|
+
const resolvedModel = this.model ? resolveValue(this.model, varCtx) : void 0;
|
|
4202
|
+
const resolvedCwd = this.agentCwd ? resolveValue(this.agentCwd, varCtx) : void 0;
|
|
4203
|
+
const request = {
|
|
4204
|
+
prompt: resolvedPrompt,
|
|
4205
|
+
model: resolvedModel,
|
|
4206
|
+
systemPrompt: resolvedSystemPrompt,
|
|
4207
|
+
allowedTools: this.allowedTools,
|
|
4208
|
+
permissionMode: this.permissionMode,
|
|
4209
|
+
maxTurns: this.maxTurns,
|
|
4210
|
+
maxBudgetUsd: this.maxBudgetUsd,
|
|
4211
|
+
cwd: resolvedCwd,
|
|
4212
|
+
mcpServers: this.mcpServers,
|
|
4213
|
+
agents: this.agents
|
|
4214
|
+
};
|
|
4215
|
+
this.log(
|
|
4216
|
+
`Claude agent: ${resolvedPrompt.substring(0, 80)}${resolvedPrompt.length > 80 ? "..." : ""}`
|
|
4217
|
+
);
|
|
4218
|
+
const result = await context.activities.claudeAgent(request);
|
|
4219
|
+
context.blackboard.set(this.outputKey, result);
|
|
4220
|
+
if (!result.success) {
|
|
4221
|
+
this._lastError = `Claude agent failed: ${result.errors?.join(", ") || "unknown error"}`;
|
|
4222
|
+
this.log(`Error: ${this._lastError}`);
|
|
4223
|
+
return "FAILURE" /* FAILURE */;
|
|
4224
|
+
}
|
|
4225
|
+
this.log(
|
|
4226
|
+
`Claude agent completed in ${result.numTurns} turns, $${result.totalCostUsd.toFixed(4)}, ${result.durationMs}ms`
|
|
4227
|
+
);
|
|
4228
|
+
return "SUCCESS" /* SUCCESS */;
|
|
4229
|
+
} catch (error) {
|
|
4230
|
+
this._lastError = error instanceof Error ? error.message : String(error);
|
|
4231
|
+
this.log(`Claude agent failed: ${this._lastError}`);
|
|
4232
|
+
return "FAILURE" /* FAILURE */;
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
};
|
|
4236
|
+
|
|
4237
|
+
// src/actions/github-action.ts
|
|
4238
|
+
var VALID_OPERATIONS = [
|
|
4239
|
+
"createBranch",
|
|
4240
|
+
"createPullRequest",
|
|
4241
|
+
"getPullRequest",
|
|
4242
|
+
"mergePullRequest",
|
|
4243
|
+
"closePullRequest",
|
|
4244
|
+
"createReview",
|
|
4245
|
+
"listIssues",
|
|
4246
|
+
"addLabels",
|
|
4247
|
+
"createComment",
|
|
4248
|
+
"createRelease"
|
|
4249
|
+
];
|
|
4250
|
+
var GitHubAction = class extends ActionNode {
|
|
4251
|
+
operation;
|
|
4252
|
+
repo;
|
|
4253
|
+
params;
|
|
4254
|
+
outputKey;
|
|
4255
|
+
constructor(config) {
|
|
4256
|
+
super(config);
|
|
4257
|
+
if (!config.operation) {
|
|
4258
|
+
throw new ConfigurationError("GitHubAction requires operation");
|
|
4259
|
+
}
|
|
4260
|
+
if (!VALID_OPERATIONS.includes(config.operation)) {
|
|
4261
|
+
throw new ConfigurationError(
|
|
4262
|
+
`GitHubAction: invalid operation "${config.operation}". Valid operations: ${VALID_OPERATIONS.join(", ")}`
|
|
4263
|
+
);
|
|
4264
|
+
}
|
|
4265
|
+
if (!config.repo) {
|
|
4266
|
+
throw new ConfigurationError("GitHubAction requires repo");
|
|
4267
|
+
}
|
|
4268
|
+
if (!config.outputKey) {
|
|
4269
|
+
throw new ConfigurationError("GitHubAction requires outputKey");
|
|
4270
|
+
}
|
|
4271
|
+
this.operation = config.operation;
|
|
4272
|
+
this.repo = config.repo;
|
|
4273
|
+
this.params = config.params ?? {};
|
|
4274
|
+
this.outputKey = config.outputKey;
|
|
4275
|
+
}
|
|
4276
|
+
async executeTick(context) {
|
|
4277
|
+
if (!context.activities?.githubAction) {
|
|
4278
|
+
this._lastError = "GitHubAction requires activities.githubAction to be configured. This activity handles GitHub API operations.";
|
|
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 resolvedRepo = resolveValue(this.repo, varCtx);
|
|
4289
|
+
const resolvedParams = {};
|
|
4290
|
+
for (const [key, value] of Object.entries(this.params)) {
|
|
4291
|
+
if (typeof value === "string") {
|
|
4292
|
+
resolvedParams[key] = resolveValue(value, varCtx);
|
|
4293
|
+
} else {
|
|
4294
|
+
resolvedParams[key] = value;
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
const request = {
|
|
4298
|
+
operation: this.operation,
|
|
4299
|
+
repo: resolvedRepo,
|
|
4300
|
+
params: resolvedParams
|
|
4301
|
+
};
|
|
4302
|
+
this.log(
|
|
4303
|
+
`GitHub ${this.operation}: ${resolvedRepo}`
|
|
4304
|
+
);
|
|
4305
|
+
const result = await context.activities.githubAction(request);
|
|
4306
|
+
context.blackboard.set(this.outputKey, result.data);
|
|
4307
|
+
if (!result.success) {
|
|
4308
|
+
this._lastError = `GitHub ${this.operation} failed`;
|
|
4309
|
+
this.log(`Error: ${this._lastError}`);
|
|
4310
|
+
return "FAILURE" /* FAILURE */;
|
|
4311
|
+
}
|
|
4312
|
+
this.log(`GitHub ${this.operation} completed successfully`);
|
|
4313
|
+
return "SUCCESS" /* SUCCESS */;
|
|
4314
|
+
} catch (error) {
|
|
4315
|
+
this._lastError = error instanceof Error ? error.message : String(error);
|
|
4316
|
+
this.log(`GitHub ${this.operation} failed: ${this._lastError}`);
|
|
4317
|
+
return "FAILURE" /* FAILURE */;
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
};
|
|
4321
|
+
|
|
4322
|
+
// src/actions/human-task.ts
|
|
4323
|
+
var HumanTask = class extends ActionNode {
|
|
4324
|
+
title;
|
|
4325
|
+
description;
|
|
4326
|
+
assignee;
|
|
4327
|
+
assigneeRole;
|
|
4328
|
+
a2ui;
|
|
4329
|
+
timeoutMs;
|
|
4330
|
+
onTimeout;
|
|
4331
|
+
outputKey;
|
|
4332
|
+
constructor(config) {
|
|
4333
|
+
super(config);
|
|
4334
|
+
if (!config.title) {
|
|
4335
|
+
throw new ConfigurationError("HumanTask requires title");
|
|
4336
|
+
}
|
|
4337
|
+
if (!config.a2ui?.components || config.a2ui.components.length === 0) {
|
|
4338
|
+
throw new ConfigurationError(
|
|
4339
|
+
"HumanTask requires a2ui.components with at least one component"
|
|
4340
|
+
);
|
|
4341
|
+
}
|
|
4342
|
+
this.title = config.title;
|
|
4343
|
+
this.description = config.description;
|
|
4344
|
+
this.assignee = config.assignee;
|
|
4345
|
+
this.assigneeRole = config.assigneeRole;
|
|
4346
|
+
this.a2ui = config.a2ui;
|
|
4347
|
+
this.timeoutMs = config.timeoutMs ?? 864e5;
|
|
4348
|
+
this.onTimeout = config.onTimeout ?? "expire";
|
|
4349
|
+
this.outputKey = config.outputKey;
|
|
4350
|
+
}
|
|
4351
|
+
async executeTick(context) {
|
|
4352
|
+
if (!context.activities?.createHumanTask) {
|
|
4353
|
+
this._lastError = "HumanTask requires activities.createHumanTask to be configured. This activity creates a task record in the database.";
|
|
4354
|
+
this.log(`Error: ${this._lastError}`);
|
|
4355
|
+
return "FAILURE" /* FAILURE */;
|
|
4356
|
+
}
|
|
4357
|
+
if (!context.activities?.waitForHumanTask) {
|
|
4358
|
+
this._lastError = "HumanTask requires activities.waitForHumanTask to be configured. This activity waits for the user to complete the task.";
|
|
4359
|
+
this.log(`Error: ${this._lastError}`);
|
|
4360
|
+
return "FAILURE" /* FAILURE */;
|
|
4361
|
+
}
|
|
4362
|
+
try {
|
|
4363
|
+
const varCtx = {
|
|
4364
|
+
blackboard: context.blackboard,
|
|
4365
|
+
input: context.input,
|
|
4366
|
+
testData: context.testData
|
|
4367
|
+
};
|
|
4368
|
+
const a2uiDataModel = {};
|
|
4369
|
+
if (this.a2ui.dataBindings) {
|
|
4370
|
+
for (const [a2uiPath, expression] of Object.entries(
|
|
4371
|
+
this.a2ui.dataBindings
|
|
4372
|
+
)) {
|
|
4373
|
+
const resolved = resolveValue(expression, varCtx);
|
|
4374
|
+
setNestedPath(a2uiDataModel, a2uiPath, resolved);
|
|
4375
|
+
}
|
|
4376
|
+
}
|
|
4377
|
+
const resolvedTitle = resolveValue(this.title, varCtx);
|
|
4378
|
+
const resolvedDescription = this.description ? resolveValue(this.description, varCtx) : void 0;
|
|
4379
|
+
const resolvedAssignee = this.assignee ? resolveValue(this.assignee, varCtx) : void 0;
|
|
4380
|
+
const tenantId = context.blackboard.get("__tenantId") || "";
|
|
4381
|
+
const executionId = context.blackboard.get("__executionId") || context.workflowInfo?.workflowId || "";
|
|
4382
|
+
const request = {
|
|
4383
|
+
nodeId: this.id,
|
|
4384
|
+
tenantId,
|
|
4385
|
+
executionId,
|
|
4386
|
+
title: resolvedTitle,
|
|
4387
|
+
description: resolvedDescription,
|
|
4388
|
+
assigneeEmail: resolvedAssignee,
|
|
4389
|
+
assigneeRole: this.assigneeRole,
|
|
4390
|
+
a2uiComponents: this.a2ui.components,
|
|
4391
|
+
a2uiDataModel,
|
|
4392
|
+
timeoutMs: this.timeoutMs,
|
|
4393
|
+
onTimeout: this.onTimeout
|
|
4394
|
+
};
|
|
4395
|
+
this.log(
|
|
4396
|
+
`Creating human task: "${resolvedTitle}" (timeout: ${this.timeoutMs}ms)`
|
|
4397
|
+
);
|
|
4398
|
+
const createResult = await context.activities.createHumanTask(request);
|
|
4399
|
+
this.log(`Task created: ${createResult.taskId}`);
|
|
4400
|
+
this.log(
|
|
4401
|
+
`Waiting for human task ${createResult.taskId} on node ${this.id}`
|
|
4402
|
+
);
|
|
4403
|
+
const waitResult = await context.activities.waitForHumanTask({
|
|
4404
|
+
taskId: createResult.taskId,
|
|
4405
|
+
nodeId: this.id,
|
|
4406
|
+
timeoutMs: this.timeoutMs,
|
|
4407
|
+
onTimeout: this.onTimeout
|
|
4408
|
+
});
|
|
4409
|
+
const prefix = this.outputKey || this.id;
|
|
4410
|
+
context.blackboard.set(`${prefix}.taskId`, createResult.taskId);
|
|
4411
|
+
context.blackboard.set(`${prefix}.completed`, waitResult.completed);
|
|
4412
|
+
context.blackboard.set(`${prefix}.decision`, waitResult.decision);
|
|
4413
|
+
context.blackboard.set(
|
|
4414
|
+
`${prefix}.submittedData`,
|
|
4415
|
+
waitResult.submittedData
|
|
4416
|
+
);
|
|
4417
|
+
context.blackboard.set(`${prefix}.completedBy`, waitResult.completedBy);
|
|
4418
|
+
context.blackboard.set(`${prefix}.timedOut`, waitResult.timedOut);
|
|
4419
|
+
if (waitResult.timedOut) {
|
|
4420
|
+
this._lastError = `Task timed out after ${this.timeoutMs}ms`;
|
|
4421
|
+
this.log(`Task timed out, onTimeout=${this.onTimeout}`);
|
|
4422
|
+
return this.onTimeout === "approve" ? "SUCCESS" /* SUCCESS */ : "FAILURE" /* FAILURE */;
|
|
4423
|
+
}
|
|
4424
|
+
this.log(
|
|
4425
|
+
`Task completed: decision=${waitResult.decision}, completedBy=${waitResult.completedBy}`
|
|
4426
|
+
);
|
|
4427
|
+
return waitResult.completed ? "SUCCESS" /* SUCCESS */ : "FAILURE" /* FAILURE */;
|
|
4428
|
+
} catch (error) {
|
|
4429
|
+
this._lastError = error instanceof Error ? error.message : String(error);
|
|
4430
|
+
this.log(`HumanTask failed: ${this._lastError}`);
|
|
4431
|
+
return "FAILURE" /* FAILURE */;
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
};
|
|
4435
|
+
function setNestedPath(obj, path2, value) {
|
|
4436
|
+
const parts = path2.split("/").filter(Boolean);
|
|
4437
|
+
let current = obj;
|
|
4438
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
4439
|
+
const key = parts[i];
|
|
4440
|
+
if (!(key in current) || typeof current[key] !== "object") {
|
|
4441
|
+
current[key] = {};
|
|
4442
|
+
}
|
|
4443
|
+
current = current[key];
|
|
4444
|
+
}
|
|
4445
|
+
if (parts.length > 0) {
|
|
4446
|
+
const lastKey = parts[parts.length - 1];
|
|
4447
|
+
current[lastKey] = value;
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
|
|
3892
4451
|
// src/registry-utils.ts
|
|
3893
4452
|
function registerStandardNodes(registry) {
|
|
3894
4453
|
registry.register("Sequence", Sequence, { category: "composite" });
|
|
@@ -3948,6 +4507,11 @@ function registerStandardNodes(registry) {
|
|
|
3948
4507
|
registry.register("GenerateFile", GenerateFile, { category: "action" });
|
|
3949
4508
|
registry.register("HttpRequest", HttpRequest, { category: "action" });
|
|
3950
4509
|
registry.register("CodeExecution", CodeExecution, { category: "action" });
|
|
4510
|
+
registry.register("LLMChat", LLMChat, { category: "action" });
|
|
4511
|
+
registry.register("BrowserAgent", BrowserAgent, { category: "action" });
|
|
4512
|
+
registry.register("ClaudeAgent", ClaudeAgent, { category: "action" });
|
|
4513
|
+
registry.register("GitHubAction", GitHubAction, { category: "action" });
|
|
4514
|
+
registry.register("HumanTask", HumanTask, { category: "action" });
|
|
3951
4515
|
}
|
|
3952
4516
|
|
|
3953
4517
|
// src/data-store/memory-store.ts
|
|
@@ -4784,7 +5348,9 @@ export {
|
|
|
4784
5348
|
AlwaysCondition,
|
|
4785
5349
|
BaseNode,
|
|
4786
5350
|
BehaviorTree,
|
|
5351
|
+
BrowserAgent,
|
|
4787
5352
|
CheckCondition,
|
|
5353
|
+
ClaudeAgent,
|
|
4788
5354
|
CodeExecution,
|
|
4789
5355
|
CompositeNode,
|
|
4790
5356
|
ConditionNode,
|
|
@@ -4801,10 +5367,13 @@ export {
|
|
|
4801
5367
|
ForceFailure,
|
|
4802
5368
|
ForceSuccess,
|
|
4803
5369
|
GenerateFile,
|
|
5370
|
+
GitHubAction,
|
|
4804
5371
|
HttpRequest,
|
|
5372
|
+
HumanTask,
|
|
4805
5373
|
IntegrationAction,
|
|
4806
5374
|
Invert,
|
|
4807
5375
|
KeepRunningUntilFailure,
|
|
5376
|
+
LLMChat,
|
|
4808
5377
|
LogMessage,
|
|
4809
5378
|
MemoryDataStore,
|
|
4810
5379
|
MemorySequence,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@q1k-oss/behaviour-tree-workflows",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Behavior tree library for TypeScript — 30+ production-ready nodes, YAML workflows, Temporal integration, and built-in observability",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|