@q1k-oss/behaviour-tree-workflows 0.0.1
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/LICENSE +21 -0
- package/README.md +920 -0
- package/dist/index.cjs +5011 -0
- package/dist/index.d.cts +3320 -0
- package/dist/index.d.ts +3320 -0
- package/dist/index.js +4879 -0
- package/package.json +68 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3320 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Sinks } from '@temporalio/workflow';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Event system for observing behavior tree execution
|
|
6
|
+
* Enables external systems (debuggers, monitors, agents) to track execution in real-time
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Types of events emitted by nodes during execution
|
|
10
|
+
*/
|
|
11
|
+
declare enum NodeEventType {
|
|
12
|
+
TICK_START = "tick_start",
|
|
13
|
+
TICK_END = "tick_end",
|
|
14
|
+
STATUS_CHANGE = "status_change",
|
|
15
|
+
ERROR = "error",
|
|
16
|
+
HALT = "halt",
|
|
17
|
+
RESET = "reset",
|
|
18
|
+
LOG = "log"
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Data for LOG events emitted by LogMessage nodes
|
|
22
|
+
*/
|
|
23
|
+
interface LogEventData {
|
|
24
|
+
level: "info" | "warn" | "error" | "debug";
|
|
25
|
+
message: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Event emitted by a node during execution
|
|
29
|
+
*/
|
|
30
|
+
interface NodeEvent<TData> {
|
|
31
|
+
type: NodeEventType;
|
|
32
|
+
nodeId: string;
|
|
33
|
+
nodeName: string;
|
|
34
|
+
nodeType: string;
|
|
35
|
+
timestamp: number;
|
|
36
|
+
/** Tree path (e.g., "/0/1/2") - set by tree execution */
|
|
37
|
+
nodePath?: string;
|
|
38
|
+
data?: TData;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Callback function for node events
|
|
42
|
+
*/
|
|
43
|
+
type NodeEventCallback<TData> = (event: NodeEvent<TData>) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Event emitter for behavior tree nodes
|
|
46
|
+
* Supports subscribing to specific event types and emitting events
|
|
47
|
+
*/
|
|
48
|
+
declare class NodeEventEmitter {
|
|
49
|
+
private listeners;
|
|
50
|
+
private allListeners;
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe to a specific event type
|
|
53
|
+
* @param type - The event type to listen for
|
|
54
|
+
* @param callback - Function to call when event occurs
|
|
55
|
+
*/
|
|
56
|
+
on<TData>(type: NodeEventType, callback: NodeEventCallback<TData>): void;
|
|
57
|
+
/**
|
|
58
|
+
* Subscribe to all event types
|
|
59
|
+
* @param callback - Function to call for any event
|
|
60
|
+
*/
|
|
61
|
+
onAll<TData>(callback: NodeEventCallback<TData>): void;
|
|
62
|
+
/**
|
|
63
|
+
* Unsubscribe from a specific event type
|
|
64
|
+
* @param type - The event type to stop listening for
|
|
65
|
+
* @param callback - The callback to remove
|
|
66
|
+
*/
|
|
67
|
+
off<TData>(type: NodeEventType, callback: NodeEventCallback<TData>): void;
|
|
68
|
+
/**
|
|
69
|
+
* Unsubscribe from all events
|
|
70
|
+
* @param callback - The callback to remove
|
|
71
|
+
*/
|
|
72
|
+
offAll<TData>(callback: NodeEventCallback<TData>): void;
|
|
73
|
+
/**
|
|
74
|
+
* Emit an event to all registered listeners
|
|
75
|
+
* Errors in callbacks are caught and logged to prevent breaking execution
|
|
76
|
+
* @param event - The event to emit
|
|
77
|
+
*/
|
|
78
|
+
emit<TData>(event: NodeEvent<TData>): void;
|
|
79
|
+
/**
|
|
80
|
+
* Remove all listeners
|
|
81
|
+
*/
|
|
82
|
+
clear(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Get count of listeners for a specific type
|
|
85
|
+
* @param type - The event type to check
|
|
86
|
+
* @returns Number of listeners
|
|
87
|
+
*/
|
|
88
|
+
listenerCount(type: NodeEventType): number;
|
|
89
|
+
/**
|
|
90
|
+
* Get count of "all events" listeners
|
|
91
|
+
* @returns Number of listeners
|
|
92
|
+
*/
|
|
93
|
+
allListenerCount(): number;
|
|
94
|
+
/**
|
|
95
|
+
* Check if there are any listeners
|
|
96
|
+
* @returns True if any listeners are registered
|
|
97
|
+
*/
|
|
98
|
+
hasListeners(): boolean;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Core types for the Behavior Tree implementation
|
|
103
|
+
* Inspired by BehaviorTree.CPP
|
|
104
|
+
*/
|
|
105
|
+
/**
|
|
106
|
+
* Status of a node after tick execution
|
|
107
|
+
*/
|
|
108
|
+
declare enum NodeStatus {
|
|
109
|
+
SUCCESS = "SUCCESS",
|
|
110
|
+
FAILURE = "FAILURE",
|
|
111
|
+
RUNNING = "RUNNING",
|
|
112
|
+
IDLE = "IDLE"
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Base configuration for all nodes
|
|
116
|
+
*/
|
|
117
|
+
interface NodeConfiguration {
|
|
118
|
+
id: string;
|
|
119
|
+
name?: string;
|
|
120
|
+
[key: string]: unknown;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Context passed during tick execution
|
|
124
|
+
*/
|
|
125
|
+
interface TickContext {
|
|
126
|
+
blackboard: IScopedBlackboard;
|
|
127
|
+
treeRegistry: ITreeRegistry;
|
|
128
|
+
signal?: AbortSignal;
|
|
129
|
+
deltaTime?: number;
|
|
130
|
+
timestamp: number;
|
|
131
|
+
testData?: Map<string, unknown>;
|
|
132
|
+
/**
|
|
133
|
+
* Immutable workflow input parameters
|
|
134
|
+
* Accessible via ${input.key} syntax in variable resolution
|
|
135
|
+
* These are passed when the workflow starts and should not be modified
|
|
136
|
+
*/
|
|
137
|
+
input?: Readonly<Record<string, unknown>>;
|
|
138
|
+
sessionId?: string;
|
|
139
|
+
eventEmitter?: NodeEventEmitter;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Token provider function type for OAuth/API key authentication
|
|
143
|
+
*/
|
|
144
|
+
type TokenProvider = (context: TemporalContext, provider: string, connectionId?: string) => Promise<PieceAuth>;
|
|
145
|
+
/**
|
|
146
|
+
* Extended context for Temporal workflow execution
|
|
147
|
+
* Replaces EffectTickContext for Temporal-native execution
|
|
148
|
+
*/
|
|
149
|
+
interface TemporalContext extends TickContext {
|
|
150
|
+
workflowInfo?: {
|
|
151
|
+
workflowId: string;
|
|
152
|
+
runId: string;
|
|
153
|
+
namespace: string;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Activity functions for I/O operations
|
|
157
|
+
* When provided, I/O nodes use these instead of inline execution
|
|
158
|
+
* Controlplane creates these via proxyActivities() and passes to context
|
|
159
|
+
*/
|
|
160
|
+
activities?: BtreeActivities;
|
|
161
|
+
/**
|
|
162
|
+
* Token provider for IntegrationAction authentication
|
|
163
|
+
* Returns OAuth tokens or API keys for third-party services
|
|
164
|
+
*/
|
|
165
|
+
tokenProvider?: TokenProvider;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Activity capabilities that can be provided to btree
|
|
169
|
+
* Controlplane creates these via proxyActivities() and passes to context
|
|
170
|
+
*/
|
|
171
|
+
interface BtreeActivities {
|
|
172
|
+
/** Execute an Active Pieces action (Google Sheets, Slack, etc.) */
|
|
173
|
+
executePieceAction: (request: PieceActivityRequest) => Promise<unknown>;
|
|
174
|
+
/** Execute Python code via cross-language activity */
|
|
175
|
+
executePythonScript?: (request: PythonScriptRequest) => Promise<PythonScriptResult>;
|
|
176
|
+
/** Parse CSV/Excel file into structured data */
|
|
177
|
+
parseFile?: (request: ParseFileRequest) => Promise<ParseFileResult>;
|
|
178
|
+
/** Generate CSV/Excel file from data */
|
|
179
|
+
generateFile?: (request: GenerateFileRequest) => Promise<GenerateFileResult>;
|
|
180
|
+
/** Make HTTP request (for nodes that don't use Active Pieces) */
|
|
181
|
+
fetchUrl?: (request: HttpRequestActivity) => Promise<HttpResponseActivity>;
|
|
182
|
+
/** Execute code in sandbox (Microsandbox) - supports JavaScript and Python */
|
|
183
|
+
executeCode?: (request: CodeExecutionRequest) => Promise<CodeExecutionResult>;
|
|
184
|
+
/** Upload file to storage, returns DataRef */
|
|
185
|
+
uploadFile?: (request: UploadFileRequest) => Promise<UploadFileResult>;
|
|
186
|
+
/** Download file from storage */
|
|
187
|
+
downloadFile?: (request: DownloadFileRequest) => Promise<DownloadFileResult>;
|
|
188
|
+
/** Delete file from storage */
|
|
189
|
+
deleteFile?: (request: DeleteFileRequest) => Promise<DeleteFileResult>;
|
|
190
|
+
/** Check if file exists in storage */
|
|
191
|
+
fileExists?: (request: FileExistsRequest) => Promise<FileExistsResult>;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Authentication credentials for a piece
|
|
195
|
+
*/
|
|
196
|
+
type PieceAuth = {
|
|
197
|
+
access_token: string;
|
|
198
|
+
refresh_token?: string;
|
|
199
|
+
} | {
|
|
200
|
+
api_key: string;
|
|
201
|
+
} | Record<string, unknown>;
|
|
202
|
+
interface PieceActivityRequest {
|
|
203
|
+
provider: string;
|
|
204
|
+
action: string;
|
|
205
|
+
inputs: Record<string, unknown>;
|
|
206
|
+
auth: PieceAuth;
|
|
207
|
+
}
|
|
208
|
+
interface PythonScriptRequest {
|
|
209
|
+
/** Python code to execute */
|
|
210
|
+
code: string;
|
|
211
|
+
/** Blackboard snapshot (serializable) */
|
|
212
|
+
blackboard: Record<string, unknown>;
|
|
213
|
+
/** Workflow input (read-only) */
|
|
214
|
+
input?: Record<string, unknown>;
|
|
215
|
+
/** Allowed environment variables */
|
|
216
|
+
env?: Record<string, string>;
|
|
217
|
+
/** Execution timeout in ms */
|
|
218
|
+
timeout?: number;
|
|
219
|
+
}
|
|
220
|
+
interface PythonScriptResult {
|
|
221
|
+
/** Modified blackboard values */
|
|
222
|
+
blackboard: Record<string, unknown>;
|
|
223
|
+
/** Stdout from Python execution */
|
|
224
|
+
stdout?: string;
|
|
225
|
+
/** Stderr from Python execution */
|
|
226
|
+
stderr?: string;
|
|
227
|
+
}
|
|
228
|
+
interface ParseFileRequest {
|
|
229
|
+
/** File path or URL */
|
|
230
|
+
file: string;
|
|
231
|
+
/** File format (auto-detect if not specified) */
|
|
232
|
+
format?: "csv" | "xlsx" | "xls" | "auto";
|
|
233
|
+
/** Sheet name for Excel (default: first sheet) */
|
|
234
|
+
sheetName?: string;
|
|
235
|
+
/** Column mapping { "Original Name": "normalizedName" } */
|
|
236
|
+
columnMapping?: Record<string, string>;
|
|
237
|
+
/** Parse options */
|
|
238
|
+
options?: {
|
|
239
|
+
skipRows?: number;
|
|
240
|
+
trim?: boolean;
|
|
241
|
+
emptyAsNull?: boolean;
|
|
242
|
+
dateColumns?: string[];
|
|
243
|
+
dateFormat?: string;
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
interface ParseFileResult {
|
|
247
|
+
/** Parsed data rows */
|
|
248
|
+
data: Record<string, unknown>[];
|
|
249
|
+
/** Number of rows parsed */
|
|
250
|
+
rowCount: number;
|
|
251
|
+
/** Column names detected */
|
|
252
|
+
columns: string[];
|
|
253
|
+
}
|
|
254
|
+
interface GenerateFileRequest {
|
|
255
|
+
/** Output format */
|
|
256
|
+
format: "csv" | "xlsx" | "json";
|
|
257
|
+
/** Data to write */
|
|
258
|
+
data: Record<string, unknown>[];
|
|
259
|
+
/** Column definitions */
|
|
260
|
+
columns?: Array<{
|
|
261
|
+
header: string;
|
|
262
|
+
key: string;
|
|
263
|
+
width?: number;
|
|
264
|
+
}>;
|
|
265
|
+
/** Output filename */
|
|
266
|
+
filename: string;
|
|
267
|
+
/** Storage type */
|
|
268
|
+
storage: "temp" | "persistent";
|
|
269
|
+
}
|
|
270
|
+
interface GenerateFileResult {
|
|
271
|
+
/** Generated filename */
|
|
272
|
+
filename: string;
|
|
273
|
+
/** MIME type */
|
|
274
|
+
contentType: string;
|
|
275
|
+
/** File size in bytes */
|
|
276
|
+
size: number;
|
|
277
|
+
/** File path or storage key */
|
|
278
|
+
path: string;
|
|
279
|
+
/** Pre-signed download URL (if persistent) */
|
|
280
|
+
url?: string;
|
|
281
|
+
}
|
|
282
|
+
interface HttpRequestActivity {
|
|
283
|
+
url: string;
|
|
284
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
285
|
+
headers?: Record<string, string>;
|
|
286
|
+
body?: unknown;
|
|
287
|
+
timeout?: number;
|
|
288
|
+
}
|
|
289
|
+
interface HttpResponseActivity {
|
|
290
|
+
status: number;
|
|
291
|
+
headers: Record<string, string>;
|
|
292
|
+
data: unknown;
|
|
293
|
+
}
|
|
294
|
+
interface UploadFileRequest {
|
|
295
|
+
/** Base64-encoded file content */
|
|
296
|
+
fileBytes: string;
|
|
297
|
+
/** Target filename */
|
|
298
|
+
filename: string;
|
|
299
|
+
/** MIME type */
|
|
300
|
+
contentType?: string;
|
|
301
|
+
/** Workflow ID for organizing storage */
|
|
302
|
+
workflowId?: string;
|
|
303
|
+
}
|
|
304
|
+
interface UploadFileResult {
|
|
305
|
+
/** Reference to stored file */
|
|
306
|
+
dataRef: DataRef$1;
|
|
307
|
+
/** Uploaded filename */
|
|
308
|
+
filename: string;
|
|
309
|
+
/** File size in bytes */
|
|
310
|
+
sizeBytes: number;
|
|
311
|
+
}
|
|
312
|
+
interface DownloadFileRequest {
|
|
313
|
+
/** Reference to file in storage */
|
|
314
|
+
dataRef: DataRef$1;
|
|
315
|
+
}
|
|
316
|
+
interface DownloadFileResult {
|
|
317
|
+
/** Base64-encoded file content */
|
|
318
|
+
fileBytes: string;
|
|
319
|
+
/** File size in bytes */
|
|
320
|
+
sizeBytes: number;
|
|
321
|
+
}
|
|
322
|
+
interface DeleteFileRequest {
|
|
323
|
+
/** Reference to file in storage */
|
|
324
|
+
dataRef: DataRef$1;
|
|
325
|
+
}
|
|
326
|
+
interface DeleteFileResult {
|
|
327
|
+
/** Whether deletion was successful */
|
|
328
|
+
deleted: boolean;
|
|
329
|
+
/** Key of deleted file */
|
|
330
|
+
key: string;
|
|
331
|
+
}
|
|
332
|
+
interface FileExistsRequest {
|
|
333
|
+
/** Reference to file in storage */
|
|
334
|
+
dataRef: DataRef$1;
|
|
335
|
+
}
|
|
336
|
+
interface FileExistsResult {
|
|
337
|
+
/** Whether file exists */
|
|
338
|
+
exists: boolean;
|
|
339
|
+
/** Key checked */
|
|
340
|
+
key: string;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Reference to data stored in a DataStore
|
|
344
|
+
* Import from data-store module for full type, this is a lightweight re-export
|
|
345
|
+
*/
|
|
346
|
+
interface DataRef$1 {
|
|
347
|
+
store: "gcs" | "s3" | "redis" | "memory";
|
|
348
|
+
key: string;
|
|
349
|
+
sizeBytes?: number;
|
|
350
|
+
expiresAt?: number;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Request for code execution in a sandboxed environment
|
|
354
|
+
*/
|
|
355
|
+
interface CodeExecutionRequest {
|
|
356
|
+
/** Code to execute */
|
|
357
|
+
code: string;
|
|
358
|
+
/** Programming language */
|
|
359
|
+
language: "javascript" | "python";
|
|
360
|
+
/** References to large data stored in DataStore */
|
|
361
|
+
dataRefs?: Record<string, DataRef$1>;
|
|
362
|
+
/** Inline context data (small values) */
|
|
363
|
+
context?: Record<string, unknown>;
|
|
364
|
+
/** Workflow input data (read-only) */
|
|
365
|
+
input?: Record<string, unknown>;
|
|
366
|
+
/** Execution timeout in milliseconds */
|
|
367
|
+
timeout?: number;
|
|
368
|
+
/** Python packages to install before execution */
|
|
369
|
+
packages?: string[];
|
|
370
|
+
/** Associated workflow ID for data storage */
|
|
371
|
+
workflowId?: string;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Result from code execution
|
|
375
|
+
*/
|
|
376
|
+
interface CodeExecutionResult {
|
|
377
|
+
/** Small values returned inline */
|
|
378
|
+
values: Record<string, unknown>;
|
|
379
|
+
/** Large values stored in DataStore (returns refs) */
|
|
380
|
+
dataRefs: Record<string, DataRef$1>;
|
|
381
|
+
/** Console/stdout output from execution */
|
|
382
|
+
logs: string[];
|
|
383
|
+
/** Total execution time in milliseconds */
|
|
384
|
+
executionTimeMs: number;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Port definition for typed inputs/outputs
|
|
388
|
+
*/
|
|
389
|
+
interface PortDefinition {
|
|
390
|
+
name: string;
|
|
391
|
+
type: "input" | "output" | "inout";
|
|
392
|
+
description?: string;
|
|
393
|
+
defaultValue?: unknown;
|
|
394
|
+
required?: boolean;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Base interface for all tree nodes
|
|
398
|
+
*/
|
|
399
|
+
interface TreeNode {
|
|
400
|
+
readonly id: string;
|
|
401
|
+
readonly name: string;
|
|
402
|
+
readonly type: string;
|
|
403
|
+
tick(context: TemporalContext): Promise<NodeStatus>;
|
|
404
|
+
halt(): void;
|
|
405
|
+
reset(): void;
|
|
406
|
+
clone(): TreeNode;
|
|
407
|
+
providedPorts?(): PortDefinition[];
|
|
408
|
+
status(): NodeStatus;
|
|
409
|
+
lastError?: string;
|
|
410
|
+
parent?: TreeNode;
|
|
411
|
+
children?: TreeNode[];
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Constructor type for node factories
|
|
415
|
+
*/
|
|
416
|
+
type NodeConstructor<T extends TreeNode = TreeNode> = new (config: NodeConfiguration) => T;
|
|
417
|
+
/**
|
|
418
|
+
* Node metadata for registry
|
|
419
|
+
*/
|
|
420
|
+
interface NodeMetadata {
|
|
421
|
+
type: string;
|
|
422
|
+
category: "action" | "condition" | "decorator" | "composite" | "subtree";
|
|
423
|
+
description?: string;
|
|
424
|
+
ports?: PortDefinition[];
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Interface for tree registry (session-scoped)
|
|
428
|
+
* Used by nodes like StepGroup and LocateElement to lookup behavior trees
|
|
429
|
+
*/
|
|
430
|
+
interface ITreeRegistry {
|
|
431
|
+
hasTree(id: string): boolean;
|
|
432
|
+
cloneTree(id: string): {
|
|
433
|
+
getRoot(): TreeNode;
|
|
434
|
+
};
|
|
435
|
+
getAllTreeIds(): string[];
|
|
436
|
+
registerTree(id: string, tree: {
|
|
437
|
+
getRoot(): TreeNode;
|
|
438
|
+
clone(): {
|
|
439
|
+
getRoot(): TreeNode;
|
|
440
|
+
};
|
|
441
|
+
}, sourceFile: string): void;
|
|
442
|
+
getTree(id: string): {
|
|
443
|
+
getRoot(): TreeNode;
|
|
444
|
+
clone(): {
|
|
445
|
+
getRoot(): TreeNode;
|
|
446
|
+
};
|
|
447
|
+
} | undefined;
|
|
448
|
+
getTreeSourceFile(id: string): string | undefined;
|
|
449
|
+
getTreesForFile(filePath: string): Map<string, {
|
|
450
|
+
getRoot(): TreeNode;
|
|
451
|
+
clone(): {
|
|
452
|
+
getRoot(): TreeNode;
|
|
453
|
+
};
|
|
454
|
+
}>;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Interface for scoped blackboard
|
|
458
|
+
*/
|
|
459
|
+
interface IScopedBlackboard {
|
|
460
|
+
get(key: string): unknown;
|
|
461
|
+
set(key: string, value: unknown): void;
|
|
462
|
+
has(key: string): boolean;
|
|
463
|
+
delete(key: string): void;
|
|
464
|
+
clear(): void;
|
|
465
|
+
createScope(name: string): IScopedBlackboard;
|
|
466
|
+
getParentScope(): IScopedBlackboard | null;
|
|
467
|
+
getScopeName(): string;
|
|
468
|
+
getFullScopePath(): string;
|
|
469
|
+
getPort<T>(key: string, defaultValue?: T): T;
|
|
470
|
+
setPort<T>(key: string, value: T): void;
|
|
471
|
+
keys(): string[];
|
|
472
|
+
entries(): [string, unknown][];
|
|
473
|
+
toJSON(): Record<string, unknown>;
|
|
474
|
+
clone(): IScopedBlackboard;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Arguments passed to a BehaviorTree workflow
|
|
478
|
+
*/
|
|
479
|
+
interface WorkflowArgs {
|
|
480
|
+
/**
|
|
481
|
+
* Input data to initialize the blackboard
|
|
482
|
+
*/
|
|
483
|
+
input?: Record<string, unknown>;
|
|
484
|
+
/**
|
|
485
|
+
* Tree registry for looking up subtrees
|
|
486
|
+
*/
|
|
487
|
+
treeRegistry: ITreeRegistry;
|
|
488
|
+
/**
|
|
489
|
+
* Optional session ID
|
|
490
|
+
*/
|
|
491
|
+
sessionId?: string;
|
|
492
|
+
/**
|
|
493
|
+
* Activity functions for I/O operations (optional)
|
|
494
|
+
* When provided, nodes that support activities will use them instead of inline execution
|
|
495
|
+
* Controlplane creates these via proxyActivities() and passes them here
|
|
496
|
+
*/
|
|
497
|
+
activities?: BtreeActivities;
|
|
498
|
+
/**
|
|
499
|
+
* Token provider for IntegrationAction authentication (optional)
|
|
500
|
+
* Returns OAuth tokens or API keys for third-party services
|
|
501
|
+
*/
|
|
502
|
+
tokenProvider?: TokenProvider;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Result returned from a BehaviorTree workflow
|
|
506
|
+
*/
|
|
507
|
+
interface WorkflowResult {
|
|
508
|
+
/**
|
|
509
|
+
* Final status of the tree
|
|
510
|
+
*/
|
|
511
|
+
status: NodeStatus;
|
|
512
|
+
/**
|
|
513
|
+
* Final blackboard state
|
|
514
|
+
*/
|
|
515
|
+
output: Record<string, unknown>;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Abstract base class for all tree nodes
|
|
520
|
+
*/
|
|
521
|
+
declare abstract class BaseNode implements TreeNode {
|
|
522
|
+
readonly id: string;
|
|
523
|
+
readonly name: string;
|
|
524
|
+
readonly type: string;
|
|
525
|
+
protected _status: NodeStatus;
|
|
526
|
+
protected _lastError?: string;
|
|
527
|
+
protected config: NodeConfiguration;
|
|
528
|
+
protected _eventEmitter?: NodeEventEmitter;
|
|
529
|
+
parent?: TreeNode;
|
|
530
|
+
children?: TreeNode[];
|
|
531
|
+
constructor(config: NodeConfiguration);
|
|
532
|
+
/**
|
|
533
|
+
* Main tick method - subclasses override to implement execution logic
|
|
534
|
+
* Returns Promise for async/RUNNING semantics
|
|
535
|
+
* All errors are caught and converted to NodeStatus.FAILURE
|
|
536
|
+
*/
|
|
537
|
+
abstract tick(context: TemporalContext): Promise<NodeStatus>;
|
|
538
|
+
/**
|
|
539
|
+
* Clone this node (deep copy including children)
|
|
540
|
+
* Must be implemented by subclasses
|
|
541
|
+
*/
|
|
542
|
+
abstract clone(): TreeNode;
|
|
543
|
+
halt(): void;
|
|
544
|
+
reset(): void;
|
|
545
|
+
status(): NodeStatus;
|
|
546
|
+
get lastError(): string | undefined;
|
|
547
|
+
providedPorts(): PortDefinition[];
|
|
548
|
+
/**
|
|
549
|
+
* Hook for derived classes to implement custom halt logic
|
|
550
|
+
*/
|
|
551
|
+
protected onHalt(): void;
|
|
552
|
+
/**
|
|
553
|
+
* Hook for derived classes to implement custom reset logic
|
|
554
|
+
*/
|
|
555
|
+
protected onReset(): void;
|
|
556
|
+
/**
|
|
557
|
+
* Helper to get input value from blackboard
|
|
558
|
+
*/
|
|
559
|
+
protected getInput<T>(context: TemporalContext, key: string, defaultValue?: T): T;
|
|
560
|
+
/**
|
|
561
|
+
* Helper to set output value to blackboard
|
|
562
|
+
*/
|
|
563
|
+
protected setOutput<T>(context: TemporalContext, key: string, value: T): void;
|
|
564
|
+
/**
|
|
565
|
+
* Log helper for debugging
|
|
566
|
+
*/
|
|
567
|
+
protected log(message: string, ...args: unknown[]): void;
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Base class for action nodes
|
|
571
|
+
* Includes resumable execution support and Effect-based async/RUNNING semantics
|
|
572
|
+
*/
|
|
573
|
+
declare abstract class ActionNode extends BaseNode {
|
|
574
|
+
/**
|
|
575
|
+
* Clone this action node
|
|
576
|
+
* Leaf nodes have no children to clone
|
|
577
|
+
*/
|
|
578
|
+
clone(): TreeNode;
|
|
579
|
+
/**
|
|
580
|
+
* Tick with resumable execution support for leaf nodes
|
|
581
|
+
* Uses async/await for Promise-based async/RUNNING semantics
|
|
582
|
+
* All errors are caught and converted to NodeStatus.FAILURE
|
|
583
|
+
*/
|
|
584
|
+
tick(context: TemporalContext): Promise<NodeStatus>;
|
|
585
|
+
/**
|
|
586
|
+
* Abstract method for subclasses to implement their execution logic
|
|
587
|
+
* Returns Promise for async operations
|
|
588
|
+
*/
|
|
589
|
+
protected abstract executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Base class for condition nodes
|
|
593
|
+
* Includes resumable execution support and async/RUNNING semantics
|
|
594
|
+
*/
|
|
595
|
+
declare abstract class ConditionNode extends BaseNode {
|
|
596
|
+
/**
|
|
597
|
+
* Clone this condition node
|
|
598
|
+
* Leaf nodes have no children to clone
|
|
599
|
+
*/
|
|
600
|
+
clone(): TreeNode;
|
|
601
|
+
/**
|
|
602
|
+
* Tick with resumable execution support for leaf nodes
|
|
603
|
+
* Uses async/await for Promise-based async/RUNNING semantics
|
|
604
|
+
* All errors are caught and converted to NodeStatus.FAILURE
|
|
605
|
+
*/
|
|
606
|
+
tick(context: TemporalContext): Promise<NodeStatus>;
|
|
607
|
+
/**
|
|
608
|
+
* Abstract method for subclasses to implement their execution logic
|
|
609
|
+
* Returns Promise for async operations
|
|
610
|
+
*/
|
|
611
|
+
protected abstract executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Base class for decorator nodes (single child)
|
|
615
|
+
*/
|
|
616
|
+
declare abstract class DecoratorNode extends BaseNode {
|
|
617
|
+
protected child?: TreeNode;
|
|
618
|
+
/**
|
|
619
|
+
* Clone this decorator node including its child
|
|
620
|
+
*/
|
|
621
|
+
clone(): TreeNode;
|
|
622
|
+
/**
|
|
623
|
+
* Tick with resumable execution support - decorators can be resume points
|
|
624
|
+
* Uses async/await for Promise-based async/RUNNING semantics
|
|
625
|
+
* All errors are caught and converted to NodeStatus.FAILURE
|
|
626
|
+
*/
|
|
627
|
+
tick(context: TemporalContext): Promise<NodeStatus>;
|
|
628
|
+
/**
|
|
629
|
+
* Decorator nodes must implement their wrapping logic
|
|
630
|
+
* Returns Promise for async operations
|
|
631
|
+
*/
|
|
632
|
+
protected abstract executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
633
|
+
setChild(child: TreeNode): void;
|
|
634
|
+
halt(): void;
|
|
635
|
+
reset(): void;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Base class for composite nodes (multiple children)
|
|
639
|
+
*/
|
|
640
|
+
declare abstract class CompositeNode extends BaseNode {
|
|
641
|
+
protected _children: TreeNode[];
|
|
642
|
+
/**
|
|
643
|
+
* Clone this composite node including all children
|
|
644
|
+
*/
|
|
645
|
+
clone(): TreeNode;
|
|
646
|
+
/**
|
|
647
|
+
* Tick with resumable execution support - composites can be resume points
|
|
648
|
+
* Uses async/await for Promise-based async/RUNNING semantics
|
|
649
|
+
* All errors are caught and converted to NodeStatus.FAILURE
|
|
650
|
+
*/
|
|
651
|
+
tick(context: TemporalContext): Promise<NodeStatus>;
|
|
652
|
+
/**
|
|
653
|
+
* Composite nodes must implement their traversal logic
|
|
654
|
+
* Returns Promise for async operations
|
|
655
|
+
*/
|
|
656
|
+
protected abstract executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
657
|
+
addChild(child: TreeNode): void;
|
|
658
|
+
addChildren(children: TreeNode[]): void;
|
|
659
|
+
halt(): void;
|
|
660
|
+
reset(): void;
|
|
661
|
+
protected haltChildren(startIndex?: number): void;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* BehaviorTree - Wrapper for TreeNode with path-based indexing
|
|
666
|
+
* Enables partial tree updates without full reload
|
|
667
|
+
*/
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* BehaviorTree class that wraps a TreeNode root with path-based indexing
|
|
671
|
+
* Paths use child indices: /0/1/2 represents root → child[0] → child[1] → child[2]
|
|
672
|
+
*/
|
|
673
|
+
/**
|
|
674
|
+
* Result of parsing a path with tree ID prefix
|
|
675
|
+
*/
|
|
676
|
+
interface ParsedPath {
|
|
677
|
+
treeId: string;
|
|
678
|
+
nodePath: string;
|
|
679
|
+
}
|
|
680
|
+
declare class BehaviorTree {
|
|
681
|
+
private root;
|
|
682
|
+
private pathIndex;
|
|
683
|
+
private idIndex;
|
|
684
|
+
constructor(root: TreeNode);
|
|
685
|
+
/**
|
|
686
|
+
* Parse a path with tree ID prefix.
|
|
687
|
+
* Format: #TreeID/node/path
|
|
688
|
+
*
|
|
689
|
+
* @param fullPath Path string starting with # followed by tree ID
|
|
690
|
+
* @returns Object with treeId and nodePath
|
|
691
|
+
* @throws Error if path format is invalid
|
|
692
|
+
*
|
|
693
|
+
* Valid examples:
|
|
694
|
+
* - "#SimpleTest/0/1" -> { treeId: "SimpleTest", nodePath: "/0/1" }
|
|
695
|
+
* - "#MyTree/" -> { treeId: "MyTree", nodePath: "/" }
|
|
696
|
+
* - "#OnlyTree" -> { treeId: "OnlyTree", nodePath: "/" }
|
|
697
|
+
*
|
|
698
|
+
* Invalid examples:
|
|
699
|
+
* - "/0/1" - missing #TreeID prefix
|
|
700
|
+
* - "#/0/1" - empty tree ID
|
|
701
|
+
* - "#" - empty tree ID
|
|
702
|
+
*/
|
|
703
|
+
static parsePathWithTreeId(fullPath: string): ParsedPath;
|
|
704
|
+
/**
|
|
705
|
+
* Get the root node of the tree
|
|
706
|
+
*/
|
|
707
|
+
getRoot(): TreeNode;
|
|
708
|
+
/**
|
|
709
|
+
* Find a node by its path
|
|
710
|
+
* Path format: / for root, /0 for first child, /0/1 for second child of first child
|
|
711
|
+
*/
|
|
712
|
+
findNodeByPath(path: string): TreeNode | null;
|
|
713
|
+
/**
|
|
714
|
+
* Find a node by its ID (if it has one)
|
|
715
|
+
* Convenience method for nodes with explicit IDs
|
|
716
|
+
*/
|
|
717
|
+
findNodeById(nodeId: string): TreeNode | null;
|
|
718
|
+
/**
|
|
719
|
+
* Get the path for a given node
|
|
720
|
+
* Returns null if the node is not in the tree
|
|
721
|
+
*/
|
|
722
|
+
getNodePath(targetNode: TreeNode): string | null;
|
|
723
|
+
/**
|
|
724
|
+
* Get the path for a node by its ID
|
|
725
|
+
* More reliable than instance-based lookup
|
|
726
|
+
* Returns null if the node is not in the tree
|
|
727
|
+
*/
|
|
728
|
+
getNodePathById(nodeId: string): string | null;
|
|
729
|
+
/**
|
|
730
|
+
* Clone this BehaviorTree (deep clones the underlying TreeNode)
|
|
731
|
+
*/
|
|
732
|
+
clone(): BehaviorTree;
|
|
733
|
+
/**
|
|
734
|
+
* Convert this BehaviorTree to a Temporal workflow function
|
|
735
|
+
* Returns a workflow function that can be registered with Temporal
|
|
736
|
+
*
|
|
737
|
+
* @returns A Temporal workflow function that executes this behavior tree
|
|
738
|
+
*
|
|
739
|
+
* @example
|
|
740
|
+
* ```typescript
|
|
741
|
+
* import { BehaviorTree } from '@wayfarer-ai/btree';
|
|
742
|
+
* import { Sequence } from '@wayfarer-ai/btree';
|
|
743
|
+
* import { PrintAction } from '@wayfarer-ai/btree';
|
|
744
|
+
*
|
|
745
|
+
* const root = new Sequence({ id: 'root' });
|
|
746
|
+
* root.addChild(new PrintAction({ id: 'step1', message: 'Hello' }));
|
|
747
|
+
* root.addChild(new PrintAction({ id: 'step2', message: 'World' }));
|
|
748
|
+
*
|
|
749
|
+
* const tree = new BehaviorTree(root);
|
|
750
|
+
* const workflow = tree.toWorkflow();
|
|
751
|
+
*
|
|
752
|
+
* // Register with Temporal worker
|
|
753
|
+
* // Worker.create({ workflows: { myWorkflow: workflow }, ... })
|
|
754
|
+
* ```
|
|
755
|
+
*/
|
|
756
|
+
toWorkflow(): (args: WorkflowArgs) => Promise<WorkflowResult>;
|
|
757
|
+
/**
|
|
758
|
+
* Replace a node at the given path with a new node
|
|
759
|
+
* Updates parent-child relationships and rebuilds the index
|
|
760
|
+
*/
|
|
761
|
+
replaceNodeAtPath(path: string, newNode: TreeNode): void;
|
|
762
|
+
/**
|
|
763
|
+
* Build the node index with path-based and ID-based lookups
|
|
764
|
+
*/
|
|
765
|
+
private buildNodeIndex;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Scoped Blackboard implementation with inheritance
|
|
770
|
+
* Inspired by BehaviorTree.CPP's blackboard
|
|
771
|
+
*
|
|
772
|
+
* Simple mutable API with native deep cloning for snapshots
|
|
773
|
+
*/
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Implementation of a hierarchical blackboard with scoped inheritance
|
|
777
|
+
* Uses simple mutable operations with snapshot support via structuredClone
|
|
778
|
+
*/
|
|
779
|
+
declare class ScopedBlackboard implements IScopedBlackboard {
|
|
780
|
+
private data;
|
|
781
|
+
private parent;
|
|
782
|
+
private scopeName;
|
|
783
|
+
private childScopes;
|
|
784
|
+
constructor(scopeName?: string, parent?: ScopedBlackboard | null);
|
|
785
|
+
get(key: string): unknown;
|
|
786
|
+
set(key: string, value: unknown): void;
|
|
787
|
+
has(key: string): boolean;
|
|
788
|
+
delete(key: string): void;
|
|
789
|
+
clear(): void;
|
|
790
|
+
createScope(name: string): IScopedBlackboard;
|
|
791
|
+
getParentScope(): IScopedBlackboard | null;
|
|
792
|
+
getScopeName(): string;
|
|
793
|
+
getPort<T>(key: string, defaultValue?: T): T;
|
|
794
|
+
setPort<T>(key: string, value: T): void;
|
|
795
|
+
keys(): string[];
|
|
796
|
+
entries(): [string, unknown][];
|
|
797
|
+
toJSON(): Record<string, unknown>;
|
|
798
|
+
/**
|
|
799
|
+
* Create a deep clone of this blackboard for snapshots
|
|
800
|
+
* Uses structured cloning for deep copy
|
|
801
|
+
*/
|
|
802
|
+
clone(): IScopedBlackboard;
|
|
803
|
+
/**
|
|
804
|
+
* Get the full scope path (e.g., "root.child.grandchild")
|
|
805
|
+
*/
|
|
806
|
+
getFullScopePath(): string;
|
|
807
|
+
/**
|
|
808
|
+
* Debug utility to print the blackboard hierarchy
|
|
809
|
+
*/
|
|
810
|
+
debug(indent?: number): void;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* Conditional node - If-then-else logic for behavior trees
|
|
815
|
+
*/
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Conditional implements if-then-else logic.
|
|
819
|
+
* Structure:
|
|
820
|
+
* - First child = condition
|
|
821
|
+
* - Second child = then branch
|
|
822
|
+
* - Third child (optional) = else branch
|
|
823
|
+
*/
|
|
824
|
+
declare class Conditional extends CompositeNode {
|
|
825
|
+
private condition?;
|
|
826
|
+
private thenBranch?;
|
|
827
|
+
private elseBranch?;
|
|
828
|
+
private conditionEvaluated;
|
|
829
|
+
private selectedBranch?;
|
|
830
|
+
/**
|
|
831
|
+
* Override addChild to enforce conditional structure
|
|
832
|
+
*/
|
|
833
|
+
addChild(child: TreeNode): void;
|
|
834
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
835
|
+
protected onHalt(): void;
|
|
836
|
+
protected onReset(): void;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* ForEach node - Iterate over collection
|
|
841
|
+
*/
|
|
842
|
+
|
|
843
|
+
interface ForEachConfiguration extends NodeConfiguration {
|
|
844
|
+
collectionKey: string;
|
|
845
|
+
itemKey: string;
|
|
846
|
+
indexKey?: string;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* ForEach iterates over a collection from the blackboard.
|
|
850
|
+
* For each item, it sets the item (and optionally index) in the blackboard
|
|
851
|
+
* and executes the body (first child).
|
|
852
|
+
*/
|
|
853
|
+
declare class ForEach extends CompositeNode {
|
|
854
|
+
private collectionKey;
|
|
855
|
+
private itemKey;
|
|
856
|
+
private indexKey?;
|
|
857
|
+
private currentIndex;
|
|
858
|
+
constructor(config: ForEachConfiguration);
|
|
859
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
860
|
+
protected onReset(): void;
|
|
861
|
+
protected onHalt(): void;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Sequence composite node
|
|
866
|
+
* Executes children in order until one fails or all succeed
|
|
867
|
+
*/
|
|
868
|
+
|
|
869
|
+
declare class Sequence extends CompositeNode {
|
|
870
|
+
private currentChildIndex;
|
|
871
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
872
|
+
protected onHalt(): void;
|
|
873
|
+
protected onReset(): void;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* MemorySequence node - Remembers which children succeeded and skips them on retry
|
|
878
|
+
* Useful for long test sequences where early steps shouldn't re-run
|
|
879
|
+
*/
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* MemorySequence extends Sequence with memory of completed children.
|
|
883
|
+
* When a child fails, subsequent retries will skip already-successful children.
|
|
884
|
+
* This is particularly useful for expensive setup steps that shouldn't be re-executed.
|
|
885
|
+
*/
|
|
886
|
+
declare class MemorySequence extends Sequence {
|
|
887
|
+
private completedChildren;
|
|
888
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
889
|
+
protected onReset(): void;
|
|
890
|
+
protected onHalt(): void;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* SequenceWithMemory is an alias for MemorySequence (BehaviorTree.CPP compatibility)
|
|
894
|
+
*/
|
|
895
|
+
declare class SequenceWithMemory extends MemorySequence {
|
|
896
|
+
constructor(config: NodeConfiguration);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Parallel composite node
|
|
901
|
+
* Executes all children concurrently (truly concurrent, not sequential)
|
|
902
|
+
*/
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Execution strategy for parallel node
|
|
906
|
+
*/
|
|
907
|
+
type ParallelStrategy = "strict" | "any";
|
|
908
|
+
interface ParallelConfiguration extends NodeConfiguration {
|
|
909
|
+
/**
|
|
910
|
+
* Execution strategy
|
|
911
|
+
* - 'strict': All children must succeed (default)
|
|
912
|
+
* - 'any': At least one child must succeed
|
|
913
|
+
*/
|
|
914
|
+
strategy?: ParallelStrategy;
|
|
915
|
+
/**
|
|
916
|
+
* Optional: Number of children that must succeed (overrides strategy)
|
|
917
|
+
*/
|
|
918
|
+
successThreshold?: number;
|
|
919
|
+
/**
|
|
920
|
+
* Optional: Number of children that must fail before parallel fails
|
|
921
|
+
*/
|
|
922
|
+
failureThreshold?: number;
|
|
923
|
+
}
|
|
924
|
+
declare class Parallel extends CompositeNode {
|
|
925
|
+
private strategy;
|
|
926
|
+
private successThreshold?;
|
|
927
|
+
private failureThreshold?;
|
|
928
|
+
constructor(config: ParallelConfiguration);
|
|
929
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
930
|
+
protected onHalt(): void;
|
|
931
|
+
protected onReset(): void;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* ReactiveSequence node - Restarts from beginning each tick
|
|
936
|
+
* Responds to condition changes during execution
|
|
937
|
+
*/
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* ReactiveSequence restarts from the beginning on each tick.
|
|
941
|
+
* Unlike regular Sequence which remembers its position, ReactiveSequence
|
|
942
|
+
* re-evaluates all children from the start, making it responsive to
|
|
943
|
+
* conditions that might change between ticks.
|
|
944
|
+
*
|
|
945
|
+
* Use cases:
|
|
946
|
+
* - Real-time monitoring where conditions might change
|
|
947
|
+
* - Safety-critical checks that must be re-evaluated
|
|
948
|
+
* - Guard conditions that need constant verification
|
|
949
|
+
*/
|
|
950
|
+
declare class ReactiveSequence extends Sequence {
|
|
951
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
952
|
+
/**
|
|
953
|
+
* Override to prevent parent Sequence from resetting currentChildIndex
|
|
954
|
+
* (ReactiveSequence doesn't use currentChildIndex)
|
|
955
|
+
*/
|
|
956
|
+
protected onReset(): void;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* Recovery node - Try-catch-finally error handling
|
|
961
|
+
*/
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Recovery implements try-catch-finally error handling for behavior trees.
|
|
965
|
+
* Structure:
|
|
966
|
+
* - First child = try branch
|
|
967
|
+
* - Second child (optional) = catch branch
|
|
968
|
+
* - Third child (optional) = finally branch
|
|
969
|
+
*
|
|
970
|
+
* Behavior:
|
|
971
|
+
* - If try succeeds or returns RUNNING, use its result
|
|
972
|
+
* - If try returns FAILURE and catch exists, execute catch branch
|
|
973
|
+
* - Finally branch always executes (if present) after try/catch completes
|
|
974
|
+
* - Finally branch result does not affect the overall result
|
|
975
|
+
*
|
|
976
|
+
* Special error handling:
|
|
977
|
+
* - ConfigurationError and OperationCancelledError propagate immediately
|
|
978
|
+
* - When these special errors occur, finally branch does NOT execute
|
|
979
|
+
* - This differs from traditional finally semantics but is intentional:
|
|
980
|
+
* ConfigurationError means the test is broken, so execution stops immediately
|
|
981
|
+
*/
|
|
982
|
+
declare class Recovery extends CompositeNode {
|
|
983
|
+
private tryBranch?;
|
|
984
|
+
private catchBranch?;
|
|
985
|
+
private finallyBranch?;
|
|
986
|
+
addChild(child: TreeNode): void;
|
|
987
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* Selector (Fallback) composite node
|
|
992
|
+
* Executes children in order until one succeeds or all fail
|
|
993
|
+
*/
|
|
994
|
+
|
|
995
|
+
declare class Selector extends CompositeNode {
|
|
996
|
+
private currentChildIndex;
|
|
997
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
998
|
+
protected onHalt(): void;
|
|
999
|
+
protected onReset(): void;
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Fallback is an alias for Selector (BehaviorTree.CPP compatibility)
|
|
1003
|
+
*/
|
|
1004
|
+
declare class Fallback extends Selector {
|
|
1005
|
+
constructor(config: NodeConfiguration);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* SubTree node - References and executes a behavior tree from the session-scoped registry
|
|
1010
|
+
* Provides function-like reusability for step groups with scoped blackboard isolation
|
|
1011
|
+
*
|
|
1012
|
+
* Features:
|
|
1013
|
+
* - params: Pass values to subtree's blackboard (supports variable resolution)
|
|
1014
|
+
* - outputs: Export subtree values back to parent blackboard after execution
|
|
1015
|
+
*/
|
|
1016
|
+
|
|
1017
|
+
interface SubTreeConfiguration extends NodeConfiguration {
|
|
1018
|
+
/** BehaviorTree ID to look up from registry */
|
|
1019
|
+
treeId: string;
|
|
1020
|
+
/**
|
|
1021
|
+
* Parameters to pass to the subtree's blackboard
|
|
1022
|
+
* Supports variable resolution: ${input.key}, ${bb.key}, ${env.KEY}, ${param.key}
|
|
1023
|
+
*/
|
|
1024
|
+
params?: Record<string, unknown>;
|
|
1025
|
+
/**
|
|
1026
|
+
* Keys to export from subtree's blackboard back to parent after execution
|
|
1027
|
+
* These values are copied to the parent scope when subtree completes
|
|
1028
|
+
*/
|
|
1029
|
+
outputs?: string[];
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* SubTree - References and executes a behavior tree from the registry
|
|
1033
|
+
*
|
|
1034
|
+
* Execution flow:
|
|
1035
|
+
* 1. Clone behavior tree from registry (lazy, on first tick)
|
|
1036
|
+
* 2. Create scoped blackboard for isolation (subtree_${id})
|
|
1037
|
+
* 3. Resolve and copy params to subtree's blackboard
|
|
1038
|
+
* 4. Execute cloned tree with scoped context
|
|
1039
|
+
* 5. Copy output values back to parent blackboard
|
|
1040
|
+
* 6. Return the tree's execution status
|
|
1041
|
+
*
|
|
1042
|
+
* The scoped blackboard provides isolation while maintaining read access to parent scopes.
|
|
1043
|
+
*
|
|
1044
|
+
* @example
|
|
1045
|
+
* ```yaml
|
|
1046
|
+
* type: SubTree
|
|
1047
|
+
* id: process-order
|
|
1048
|
+
* props:
|
|
1049
|
+
* treeId: ProcessOrderFlow
|
|
1050
|
+
* params:
|
|
1051
|
+
* orderId: "${input.orderId}"
|
|
1052
|
+
* customer: "${bb.currentCustomer}"
|
|
1053
|
+
* outputs:
|
|
1054
|
+
* - orderResult
|
|
1055
|
+
* - processingTime
|
|
1056
|
+
* ```
|
|
1057
|
+
*/
|
|
1058
|
+
declare class SubTree extends ActionNode {
|
|
1059
|
+
private treeId;
|
|
1060
|
+
private params;
|
|
1061
|
+
private outputs;
|
|
1062
|
+
private clonedTree?;
|
|
1063
|
+
constructor(config: SubTreeConfiguration);
|
|
1064
|
+
protected executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1065
|
+
/**
|
|
1066
|
+
* Override clone to include cloned tree
|
|
1067
|
+
*/
|
|
1068
|
+
clone(): TreeNode;
|
|
1069
|
+
/**
|
|
1070
|
+
* Override halt to halt the referenced tree
|
|
1071
|
+
*/
|
|
1072
|
+
halt(): void;
|
|
1073
|
+
/**
|
|
1074
|
+
* Override reset to reset the referenced tree
|
|
1075
|
+
*/
|
|
1076
|
+
reset(): void;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* While node - Loop while condition is true
|
|
1081
|
+
*/
|
|
1082
|
+
|
|
1083
|
+
interface WhileConfiguration extends NodeConfiguration {
|
|
1084
|
+
maxIterations?: number;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* While loops while the condition returns SUCCESS.
|
|
1088
|
+
* Structure:
|
|
1089
|
+
* - First child = condition
|
|
1090
|
+
* - Second child = body
|
|
1091
|
+
*/
|
|
1092
|
+
declare class While extends CompositeNode {
|
|
1093
|
+
private maxIterations;
|
|
1094
|
+
private currentIteration;
|
|
1095
|
+
private condition?;
|
|
1096
|
+
private body?;
|
|
1097
|
+
private bodyStarted;
|
|
1098
|
+
constructor(config: WhileConfiguration);
|
|
1099
|
+
addChild(child: TreeNode): void;
|
|
1100
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1101
|
+
protected onReset(): void;
|
|
1102
|
+
protected onHalt(): void;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* Delay decorator node
|
|
1107
|
+
* Waits for a specified duration before executing the child
|
|
1108
|
+
*
|
|
1109
|
+
* In Temporal workflows: Uses sleep() for deterministic delays
|
|
1110
|
+
* In standalone mode: Uses Date.now() polling for multi-tick behavior
|
|
1111
|
+
*/
|
|
1112
|
+
|
|
1113
|
+
interface DelayConfiguration extends NodeConfiguration {
|
|
1114
|
+
/**
|
|
1115
|
+
* Delay duration in milliseconds
|
|
1116
|
+
*/
|
|
1117
|
+
delayMs: number;
|
|
1118
|
+
}
|
|
1119
|
+
declare class Delay extends DecoratorNode {
|
|
1120
|
+
private delayMs;
|
|
1121
|
+
private delayStartTime;
|
|
1122
|
+
private useTemporalAPI;
|
|
1123
|
+
constructor(config: DelayConfiguration);
|
|
1124
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1125
|
+
protected onHalt(): void;
|
|
1126
|
+
protected onReset(): void;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
* ForceSuccess and ForceFailure decorators
|
|
1131
|
+
* Always return specific result regardless of child
|
|
1132
|
+
*/
|
|
1133
|
+
|
|
1134
|
+
/**
|
|
1135
|
+
* ForceSuccess always returns SUCCESS regardless of child result.
|
|
1136
|
+
* Useful for ensuring a branch always succeeds.
|
|
1137
|
+
*/
|
|
1138
|
+
declare class ForceSuccess extends DecoratorNode {
|
|
1139
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* ForceFailure always returns FAILURE regardless of child result.
|
|
1143
|
+
* Useful for negation or testing.
|
|
1144
|
+
*/
|
|
1145
|
+
declare class ForceFailure extends DecoratorNode {
|
|
1146
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* Invert decorator node
|
|
1151
|
+
* Inverts the result of its child (SUCCESS becomes FAILURE and vice versa)
|
|
1152
|
+
*/
|
|
1153
|
+
|
|
1154
|
+
declare class Invert extends DecoratorNode {
|
|
1155
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
/**
|
|
1159
|
+
* KeepRunningUntilFailure decorator
|
|
1160
|
+
* Opposite of Retry - keeps running while child succeeds
|
|
1161
|
+
*/
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* KeepRunningUntilFailure keeps executing its child while it succeeds.
|
|
1165
|
+
* Returns SUCCESS when child fails (goal achieved).
|
|
1166
|
+
* Returns RUNNING while child succeeds (keep going).
|
|
1167
|
+
*/
|
|
1168
|
+
declare class KeepRunningUntilFailure extends DecoratorNode {
|
|
1169
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* Precondition decorator - Check/resolve preconditions before executing child
|
|
1174
|
+
*/
|
|
1175
|
+
|
|
1176
|
+
/**
|
|
1177
|
+
* Precondition checks preconditions before executing the main child.
|
|
1178
|
+
* If preconditions fail, attempts to resolve them using resolvers.
|
|
1179
|
+
* Useful for ensuring prerequisites are met before executing actions.
|
|
1180
|
+
*/
|
|
1181
|
+
declare class Precondition extends DecoratorNode {
|
|
1182
|
+
private preconditions;
|
|
1183
|
+
private preconditionsChecked;
|
|
1184
|
+
/**
|
|
1185
|
+
* Add a precondition to check before main execution
|
|
1186
|
+
*/
|
|
1187
|
+
addPrecondition(condition: TreeNode, resolver?: TreeNode, required?: boolean): void;
|
|
1188
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1189
|
+
protected onHalt(): void;
|
|
1190
|
+
protected onReset(): void;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* Repeat decorator - Execute child N times
|
|
1195
|
+
*/
|
|
1196
|
+
|
|
1197
|
+
interface RepeatConfiguration extends NodeConfiguration {
|
|
1198
|
+
numCycles: number;
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Repeat executes its child exactly N times.
|
|
1202
|
+
* Returns SUCCESS when all cycles complete successfully.
|
|
1203
|
+
* Returns FAILURE if any cycle fails.
|
|
1204
|
+
*/
|
|
1205
|
+
declare class Repeat extends DecoratorNode {
|
|
1206
|
+
private numCycles;
|
|
1207
|
+
private currentCycle;
|
|
1208
|
+
constructor(config: RepeatConfiguration);
|
|
1209
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1210
|
+
protected onReset(): void;
|
|
1211
|
+
protected onHalt(): void;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* RunOnce decorator - Execute child only once per session
|
|
1216
|
+
*/
|
|
1217
|
+
|
|
1218
|
+
/**
|
|
1219
|
+
* RunOnce executes its child only once and caches the result.
|
|
1220
|
+
* Subsequent ticks return the cached result without re-executing the child.
|
|
1221
|
+
* Useful for initialization or one-time setup operations.
|
|
1222
|
+
*/
|
|
1223
|
+
declare class RunOnce extends DecoratorNode {
|
|
1224
|
+
private hasRun;
|
|
1225
|
+
private cachedResult?;
|
|
1226
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1227
|
+
protected onReset(): void;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* SoftAssert decorator - Continue even if child fails
|
|
1232
|
+
*/
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* SoftAssert converts child FAILURE to SUCCESS, allowing execution to continue.
|
|
1236
|
+
* Logs all failures for later review but doesn't halt execution.
|
|
1237
|
+
* Useful for non-critical checks that shouldn't block the test.
|
|
1238
|
+
*/
|
|
1239
|
+
declare class SoftAssert extends DecoratorNode {
|
|
1240
|
+
private failures;
|
|
1241
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1242
|
+
/**
|
|
1243
|
+
* Get all recorded failures
|
|
1244
|
+
*/
|
|
1245
|
+
getFailures(): Array<{
|
|
1246
|
+
timestamp: number;
|
|
1247
|
+
message: string;
|
|
1248
|
+
}>;
|
|
1249
|
+
/**
|
|
1250
|
+
* Check if any assertions have failed
|
|
1251
|
+
*/
|
|
1252
|
+
hasFailures(): boolean;
|
|
1253
|
+
protected onReset(): void;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
* Timeout decorator node
|
|
1258
|
+
* Fails if the child doesn't complete within a specified time
|
|
1259
|
+
*
|
|
1260
|
+
* In Temporal workflows: Uses CancellationScope for deterministic timeouts
|
|
1261
|
+
* In standalone mode: Uses Date.now() polling for multi-tick behavior
|
|
1262
|
+
*/
|
|
1263
|
+
|
|
1264
|
+
interface TimeoutConfiguration extends NodeConfiguration {
|
|
1265
|
+
/**
|
|
1266
|
+
* Timeout duration in milliseconds
|
|
1267
|
+
*/
|
|
1268
|
+
timeoutMs: number;
|
|
1269
|
+
}
|
|
1270
|
+
declare class Timeout extends DecoratorNode {
|
|
1271
|
+
private timeoutMs;
|
|
1272
|
+
private startTime;
|
|
1273
|
+
private useTemporalAPI;
|
|
1274
|
+
constructor(config: TimeoutConfiguration);
|
|
1275
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1276
|
+
protected onHalt(): void;
|
|
1277
|
+
protected onReset(): void;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
/**
|
|
1281
|
+
* Registry for behavior tree nodes
|
|
1282
|
+
* Handles registration and creation of nodes by type
|
|
1283
|
+
*/
|
|
1284
|
+
|
|
1285
|
+
declare class Registry {
|
|
1286
|
+
private nodeTypes;
|
|
1287
|
+
private nodeMetadata;
|
|
1288
|
+
private behaviorTrees;
|
|
1289
|
+
constructor();
|
|
1290
|
+
/**
|
|
1291
|
+
* Register a node type with the registry
|
|
1292
|
+
*/
|
|
1293
|
+
register<T extends TreeNode>(type: string, ctor: NodeConstructor<T>, metadata?: Partial<NodeMetadata>): void;
|
|
1294
|
+
/**
|
|
1295
|
+
* Create a node instance by type
|
|
1296
|
+
* Validates configuration against schema before creating node
|
|
1297
|
+
*/
|
|
1298
|
+
create(type: string, config: NodeConfiguration): TreeNode;
|
|
1299
|
+
/**
|
|
1300
|
+
* Check if a node type is registered
|
|
1301
|
+
*/
|
|
1302
|
+
has(type: string): boolean;
|
|
1303
|
+
/**
|
|
1304
|
+
* Get metadata for a node type
|
|
1305
|
+
*/
|
|
1306
|
+
getMetadata(type: string): NodeMetadata | undefined;
|
|
1307
|
+
/**
|
|
1308
|
+
* Get all registered node types
|
|
1309
|
+
*/
|
|
1310
|
+
getRegisteredTypes(): string[];
|
|
1311
|
+
/**
|
|
1312
|
+
* Get registered types by category
|
|
1313
|
+
*/
|
|
1314
|
+
getTypesByCategory(category: NodeMetadata["category"]): string[];
|
|
1315
|
+
/**
|
|
1316
|
+
* Clear all registrations (node types, metadata, and behavior trees)
|
|
1317
|
+
*/
|
|
1318
|
+
clear(): void;
|
|
1319
|
+
/**
|
|
1320
|
+
* Register a behavior tree instance with source file metadata.
|
|
1321
|
+
* Used for reusable trees like elements, step groups, and test cases.
|
|
1322
|
+
*
|
|
1323
|
+
* @param id Unique identifier for the tree
|
|
1324
|
+
* @param tree BehaviorTree instance to register
|
|
1325
|
+
* @param sourceFile Path to the source .sigma file
|
|
1326
|
+
* @throws Error if a tree with the same ID is already registered
|
|
1327
|
+
*/
|
|
1328
|
+
registerTree(id: string, tree: BehaviorTree, sourceFile: string): void;
|
|
1329
|
+
/**
|
|
1330
|
+
* Unregister a behavior tree by ID.
|
|
1331
|
+
* Useful for cleanup in long-running processes or tests.
|
|
1332
|
+
*
|
|
1333
|
+
* @param id Tree ID to unregister
|
|
1334
|
+
* @returns true if tree was found and removed, false otherwise
|
|
1335
|
+
*/
|
|
1336
|
+
unregisterTree(id: string): boolean;
|
|
1337
|
+
/**
|
|
1338
|
+
* Replace an existing behavior tree registration.
|
|
1339
|
+
* If the tree doesn't exist, it will be registered as new.
|
|
1340
|
+
*
|
|
1341
|
+
* @param id Tree ID to replace
|
|
1342
|
+
* @param tree New BehaviorTree instance
|
|
1343
|
+
* @param sourceFile Path to the source .sigma file
|
|
1344
|
+
*/
|
|
1345
|
+
replaceTree(id: string, tree: BehaviorTree, sourceFile: string): void;
|
|
1346
|
+
/**
|
|
1347
|
+
* Get a behavior tree instance by ID
|
|
1348
|
+
*/
|
|
1349
|
+
getTree(id: string): BehaviorTree | undefined;
|
|
1350
|
+
/**
|
|
1351
|
+
* Get the source file path for a behavior tree
|
|
1352
|
+
*/
|
|
1353
|
+
getTreeSourceFile(id: string): string | undefined;
|
|
1354
|
+
/**
|
|
1355
|
+
* Get all trees that belong to a specific source file
|
|
1356
|
+
*/
|
|
1357
|
+
getTreesForFile(filePath: string): Map<string, BehaviorTree>;
|
|
1358
|
+
/**
|
|
1359
|
+
* Check if a behavior tree is registered
|
|
1360
|
+
*/
|
|
1361
|
+
hasTree(id: string): boolean;
|
|
1362
|
+
/**
|
|
1363
|
+
* Clone a registered behavior tree for instantiation
|
|
1364
|
+
* Returns the cloned BehaviorTree (caller should use getRoot() for TreeNode)
|
|
1365
|
+
*/
|
|
1366
|
+
cloneTree(id: string): BehaviorTree;
|
|
1367
|
+
/**
|
|
1368
|
+
* Get all registered behavior tree IDs
|
|
1369
|
+
*/
|
|
1370
|
+
getAllTreeIds(): string[];
|
|
1371
|
+
/**
|
|
1372
|
+
* Clear all registered behavior trees
|
|
1373
|
+
*/
|
|
1374
|
+
clearTrees(): void;
|
|
1375
|
+
/**
|
|
1376
|
+
* Create a tree from a JSON definition
|
|
1377
|
+
* Validates tree structure before creating nodes
|
|
1378
|
+
*/
|
|
1379
|
+
createTree(definition: unknown): TreeNode;
|
|
1380
|
+
/**
|
|
1381
|
+
* Safe tree creation that returns success/error result
|
|
1382
|
+
* Useful for user-facing tools that need graceful error handling
|
|
1383
|
+
*
|
|
1384
|
+
* @param definition - Tree definition to create
|
|
1385
|
+
* @returns Success result with tree or failure result with error
|
|
1386
|
+
*
|
|
1387
|
+
* @example
|
|
1388
|
+
* ```typescript
|
|
1389
|
+
* const result = registry.safeCreateTree({
|
|
1390
|
+
* type: 'Sequence',
|
|
1391
|
+
* id: 'root',
|
|
1392
|
+
* children: [...]
|
|
1393
|
+
* });
|
|
1394
|
+
*
|
|
1395
|
+
* if (result.success) {
|
|
1396
|
+
* console.log('Tree created:', result.tree);
|
|
1397
|
+
* } else {
|
|
1398
|
+
* console.error('Failed:', result.error.message);
|
|
1399
|
+
* }
|
|
1400
|
+
* ```
|
|
1401
|
+
*/
|
|
1402
|
+
safeCreateTree(definition: unknown): {
|
|
1403
|
+
success: true;
|
|
1404
|
+
tree: TreeNode;
|
|
1405
|
+
} | {
|
|
1406
|
+
success: false;
|
|
1407
|
+
error: Error;
|
|
1408
|
+
};
|
|
1409
|
+
private log;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
/**
|
|
1413
|
+
* Registry utilities for registering standard nodes
|
|
1414
|
+
*/
|
|
1415
|
+
|
|
1416
|
+
/**
|
|
1417
|
+
* Register all standard built-in nodes to a registry
|
|
1418
|
+
* This includes composites, decorators, actions, conditions, and utilities
|
|
1419
|
+
*
|
|
1420
|
+
* @param registry - Registry to register nodes to
|
|
1421
|
+
*
|
|
1422
|
+
* @example
|
|
1423
|
+
* ```typescript
|
|
1424
|
+
* import { Registry, registerStandardNodes } from '@wayfarer-ai/btree';
|
|
1425
|
+
*
|
|
1426
|
+
* const registry = new Registry();
|
|
1427
|
+
* registerStandardNodes(registry);
|
|
1428
|
+
*
|
|
1429
|
+
* // Now register your custom nodes
|
|
1430
|
+
* registry.register('MyCustomAction', MyCustomAction, { category: 'action' });
|
|
1431
|
+
* ```
|
|
1432
|
+
*/
|
|
1433
|
+
declare function registerStandardNodes(registry: Registry): void;
|
|
1434
|
+
|
|
1435
|
+
/**
|
|
1436
|
+
* Simple test nodes for demonstrating behavior tree functionality
|
|
1437
|
+
*/
|
|
1438
|
+
|
|
1439
|
+
/**
|
|
1440
|
+
* Simple action that prints a message and succeeds
|
|
1441
|
+
*/
|
|
1442
|
+
declare class PrintAction extends ActionNode {
|
|
1443
|
+
private message;
|
|
1444
|
+
constructor(config: NodeConfiguration & {
|
|
1445
|
+
message?: string;
|
|
1446
|
+
});
|
|
1447
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* Action that waits for a specified duration
|
|
1451
|
+
*/
|
|
1452
|
+
declare class WaitAction extends ActionNode {
|
|
1453
|
+
private waitMs;
|
|
1454
|
+
private startTime;
|
|
1455
|
+
constructor(config: NodeConfiguration & {
|
|
1456
|
+
waitMs?: number;
|
|
1457
|
+
});
|
|
1458
|
+
executeTick(_context: TemporalContext): Promise<NodeStatus>;
|
|
1459
|
+
protected onReset(): void;
|
|
1460
|
+
protected onHalt(): void;
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* Action that increments a counter in the blackboard
|
|
1464
|
+
*/
|
|
1465
|
+
declare class CounterAction extends ActionNode {
|
|
1466
|
+
private counterKey;
|
|
1467
|
+
private increment;
|
|
1468
|
+
constructor(config: NodeConfiguration & {
|
|
1469
|
+
counterKey?: string;
|
|
1470
|
+
increment?: number;
|
|
1471
|
+
});
|
|
1472
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Action that can be configured to return any status
|
|
1476
|
+
*/
|
|
1477
|
+
declare class MockAction extends ActionNode {
|
|
1478
|
+
private returnStatus;
|
|
1479
|
+
private ticksBeforeComplete;
|
|
1480
|
+
private currentTicks;
|
|
1481
|
+
constructor(config: NodeConfiguration & {
|
|
1482
|
+
returnStatus?: NodeStatus;
|
|
1483
|
+
ticksBeforeComplete?: number;
|
|
1484
|
+
});
|
|
1485
|
+
executeTick(_context: TemporalContext): Promise<NodeStatus>;
|
|
1486
|
+
protected onReset(): void;
|
|
1487
|
+
protected onHalt(): void;
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Condition that checks if a blackboard value meets a criteria
|
|
1491
|
+
*/
|
|
1492
|
+
declare class CheckCondition extends ConditionNode {
|
|
1493
|
+
private key;
|
|
1494
|
+
private operator;
|
|
1495
|
+
private value;
|
|
1496
|
+
constructor(config: NodeConfiguration & {
|
|
1497
|
+
key: string;
|
|
1498
|
+
operator?: string;
|
|
1499
|
+
value: unknown;
|
|
1500
|
+
});
|
|
1501
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1502
|
+
}
|
|
1503
|
+
/**
|
|
1504
|
+
* Simple condition that always returns the configured status
|
|
1505
|
+
*/
|
|
1506
|
+
declare class AlwaysCondition extends ConditionNode {
|
|
1507
|
+
private returnStatus;
|
|
1508
|
+
constructor(config: NodeConfiguration & {
|
|
1509
|
+
returnStatus?: NodeStatus;
|
|
1510
|
+
});
|
|
1511
|
+
executeTick(_context: TemporalContext): Promise<NodeStatus>;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Simple test node that always succeeds
|
|
1515
|
+
*/
|
|
1516
|
+
declare class SuccessNode extends ActionNode {
|
|
1517
|
+
executeTick(_context: TemporalContext): Promise<NodeStatus>;
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* Simple test node that always fails
|
|
1521
|
+
*/
|
|
1522
|
+
declare class FailureNode extends ActionNode {
|
|
1523
|
+
executeTick(_context: TemporalContext): Promise<NodeStatus>;
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Simple test node that stays running
|
|
1527
|
+
*/
|
|
1528
|
+
declare class RunningNode extends ActionNode {
|
|
1529
|
+
executeTick(_context: TemporalContext): Promise<NodeStatus>;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
/**
|
|
1533
|
+
* DataStore Interface
|
|
1534
|
+
*
|
|
1535
|
+
* Provides an abstraction for storing and retrieving large data payloads
|
|
1536
|
+
* outside the workflow execution context. This keeps the Temporal workflow
|
|
1537
|
+
* history lean while allowing workflows to process large datasets.
|
|
1538
|
+
*
|
|
1539
|
+
* Implementations:
|
|
1540
|
+
* - MemoryDataStore: In-memory storage for tests
|
|
1541
|
+
* - GCSDataStore: Google Cloud Storage for production (in controlplane)
|
|
1542
|
+
* - RedisDataStore: Redis storage for caching (future)
|
|
1543
|
+
*/
|
|
1544
|
+
/**
|
|
1545
|
+
* Reference to data stored in a DataStore
|
|
1546
|
+
* This lightweight reference can be passed through workflows/activities
|
|
1547
|
+
*/
|
|
1548
|
+
interface DataRef {
|
|
1549
|
+
/** Storage backend identifier */
|
|
1550
|
+
store: "gcs" | "s3" | "redis" | "memory";
|
|
1551
|
+
/** Unique key for retrieving the data */
|
|
1552
|
+
key: string;
|
|
1553
|
+
/** Size of stored data in bytes (for monitoring/optimization) */
|
|
1554
|
+
sizeBytes?: number;
|
|
1555
|
+
/** Unix timestamp when data expires (optional TTL) */
|
|
1556
|
+
expiresAt?: number;
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* Options for storing data
|
|
1560
|
+
*/
|
|
1561
|
+
interface PutOptions {
|
|
1562
|
+
/** Time-to-live in seconds (data auto-deleted after expiry) */
|
|
1563
|
+
ttlSeconds?: number;
|
|
1564
|
+
/** Content type hint for serialization */
|
|
1565
|
+
contentType?: "json" | "csv" | "binary";
|
|
1566
|
+
/** Associated workflow ID for grouping/cleanup */
|
|
1567
|
+
workflowId?: string;
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* DataStore interface for storing and retrieving large payloads
|
|
1571
|
+
*/
|
|
1572
|
+
interface DataStore {
|
|
1573
|
+
/**
|
|
1574
|
+
* Store data and return a reference
|
|
1575
|
+
* @param key - Unique identifier for the data
|
|
1576
|
+
* @param data - Data to store (will be JSON serialized)
|
|
1577
|
+
* @param options - Storage options (TTL, content type, etc.)
|
|
1578
|
+
* @returns Reference to the stored data
|
|
1579
|
+
*/
|
|
1580
|
+
put(key: string, data: unknown, options?: PutOptions): Promise<DataRef>;
|
|
1581
|
+
/**
|
|
1582
|
+
* Retrieve data by reference
|
|
1583
|
+
* @param ref - Reference returned from put()
|
|
1584
|
+
* @returns The stored data (JSON deserialized)
|
|
1585
|
+
* @throws Error if data not found or expired
|
|
1586
|
+
*/
|
|
1587
|
+
get(ref: DataRef): Promise<unknown>;
|
|
1588
|
+
/**
|
|
1589
|
+
* Delete data by reference
|
|
1590
|
+
* @param ref - Reference to delete
|
|
1591
|
+
*/
|
|
1592
|
+
delete(ref: DataRef): Promise<void>;
|
|
1593
|
+
/**
|
|
1594
|
+
* Check if data exists
|
|
1595
|
+
* @param ref - Reference to check
|
|
1596
|
+
* @returns true if data exists and hasn't expired
|
|
1597
|
+
*/
|
|
1598
|
+
exists(ref: DataRef): Promise<boolean>;
|
|
1599
|
+
}
|
|
1600
|
+
/**
|
|
1601
|
+
* Type guard to check if a value is a DataRef
|
|
1602
|
+
* @param value - Value to check
|
|
1603
|
+
* @returns true if value is a DataRef
|
|
1604
|
+
*/
|
|
1605
|
+
declare function isDataRef(value: unknown): value is DataRef;
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* In-Memory DataStore Implementation
|
|
1609
|
+
*
|
|
1610
|
+
* Simple in-memory storage for testing and development.
|
|
1611
|
+
* Data is lost when the process terminates.
|
|
1612
|
+
*
|
|
1613
|
+
* Features:
|
|
1614
|
+
* - TTL support with automatic cleanup
|
|
1615
|
+
* - Size tracking
|
|
1616
|
+
* - Thread-safe for single Node.js process
|
|
1617
|
+
*/
|
|
1618
|
+
|
|
1619
|
+
/**
|
|
1620
|
+
* In-memory DataStore implementation
|
|
1621
|
+
* Suitable for tests and local development
|
|
1622
|
+
*/
|
|
1623
|
+
declare class MemoryDataStore implements DataStore {
|
|
1624
|
+
private storage;
|
|
1625
|
+
private cleanupInterval;
|
|
1626
|
+
constructor(options?: {
|
|
1627
|
+
cleanupIntervalMs?: number;
|
|
1628
|
+
});
|
|
1629
|
+
put(key: string, data: unknown, options?: PutOptions): Promise<DataRef>;
|
|
1630
|
+
get(ref: DataRef): Promise<unknown>;
|
|
1631
|
+
delete(ref: DataRef): Promise<void>;
|
|
1632
|
+
exists(ref: DataRef): Promise<boolean>;
|
|
1633
|
+
/**
|
|
1634
|
+
* Clear all stored data
|
|
1635
|
+
* Useful for test cleanup
|
|
1636
|
+
*/
|
|
1637
|
+
clear(): void;
|
|
1638
|
+
/**
|
|
1639
|
+
* Get the number of stored entries
|
|
1640
|
+
*/
|
|
1641
|
+
size(): number;
|
|
1642
|
+
/**
|
|
1643
|
+
* Get total bytes stored
|
|
1644
|
+
*/
|
|
1645
|
+
totalBytes(): number;
|
|
1646
|
+
/**
|
|
1647
|
+
* Stop the cleanup interval
|
|
1648
|
+
* Call this when done with the store to prevent memory leaks in tests
|
|
1649
|
+
*/
|
|
1650
|
+
dispose(): void;
|
|
1651
|
+
/**
|
|
1652
|
+
* Remove expired entries
|
|
1653
|
+
*/
|
|
1654
|
+
private cleanup;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
/**
|
|
1658
|
+
* LogMessage Node - Log messages for debugging and test visibility
|
|
1659
|
+
*
|
|
1660
|
+
* Utility node that logs messages to console with optional variable resolution.
|
|
1661
|
+
* Useful for debugging test flows and tracking execution progress.
|
|
1662
|
+
*
|
|
1663
|
+
* Supports variable resolution:
|
|
1664
|
+
* - ${key} - Shorthand for blackboard (backward compatible)
|
|
1665
|
+
* - ${input.key} - Workflow input parameters
|
|
1666
|
+
* - ${bb.key} - Blackboard values
|
|
1667
|
+
* - ${env.KEY} - Environment variables
|
|
1668
|
+
* - ${param.key} - Test data parameters
|
|
1669
|
+
*
|
|
1670
|
+
* Use Cases:
|
|
1671
|
+
* - Log intermediate values during test execution
|
|
1672
|
+
* - Debug blackboard state at specific points
|
|
1673
|
+
* - Add visibility to test steps
|
|
1674
|
+
* - Track execution flow
|
|
1675
|
+
*
|
|
1676
|
+
* Examples:
|
|
1677
|
+
* - Log static message: <LogMessage message="Starting form submission" />
|
|
1678
|
+
* - Log blackboard value: <LogMessage message="Current URL: ${currentUrl}" />
|
|
1679
|
+
* - Log input value: <LogMessage message="Order ID: ${input.orderId}" />
|
|
1680
|
+
* - Log with level: <LogMessage message="Error occurred" level="error" />
|
|
1681
|
+
*/
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* Configuration for LogMessage node
|
|
1685
|
+
*/
|
|
1686
|
+
interface LogMessageConfig extends NodeConfiguration {
|
|
1687
|
+
message: string;
|
|
1688
|
+
level?: "info" | "warn" | "error" | "debug";
|
|
1689
|
+
}
|
|
1690
|
+
/**
|
|
1691
|
+
* LogMessage Node - Logs messages with optional variable resolution
|
|
1692
|
+
*/
|
|
1693
|
+
declare class LogMessage extends ActionNode {
|
|
1694
|
+
private message;
|
|
1695
|
+
private level;
|
|
1696
|
+
constructor(config: LogMessageConfig);
|
|
1697
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1698
|
+
/**
|
|
1699
|
+
* Resolve variable references in message string
|
|
1700
|
+
* Supports ${key}, ${input.key}, ${bb.key}, ${env.KEY}, ${param.key}
|
|
1701
|
+
*/
|
|
1702
|
+
private resolveMessage;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
/**
|
|
1706
|
+
* RegexExtract Node - Extract text using regular expressions
|
|
1707
|
+
*
|
|
1708
|
+
* Data manipulation utility node that operates on blackboard values.
|
|
1709
|
+
* Extracts matches from a text string using a regex pattern.
|
|
1710
|
+
*
|
|
1711
|
+
* Use Cases:
|
|
1712
|
+
* - Extract email addresses from text
|
|
1713
|
+
* - Extract numbers/IDs from strings
|
|
1714
|
+
* - Parse structured data from unstructured text
|
|
1715
|
+
* - Extract URLs from content
|
|
1716
|
+
*/
|
|
1717
|
+
|
|
1718
|
+
/**
|
|
1719
|
+
* Configuration for RegexExtract node
|
|
1720
|
+
*/
|
|
1721
|
+
interface RegexExtractConfig extends NodeConfiguration {
|
|
1722
|
+
input: string;
|
|
1723
|
+
pattern: string;
|
|
1724
|
+
outputKey: string;
|
|
1725
|
+
flags?: string;
|
|
1726
|
+
matchIndex?: number;
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* RegexExtract Node - Extracts text using regular expressions
|
|
1730
|
+
*/
|
|
1731
|
+
declare class RegexExtract extends ActionNode {
|
|
1732
|
+
private input;
|
|
1733
|
+
private pattern;
|
|
1734
|
+
private outputKey;
|
|
1735
|
+
private flags;
|
|
1736
|
+
private matchIndex?;
|
|
1737
|
+
constructor(config: RegexExtractConfig);
|
|
1738
|
+
executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
/**
|
|
1742
|
+
* Unified Variable Resolver
|
|
1743
|
+
*
|
|
1744
|
+
* Resolves variable references in strings and objects with support for multiple namespaces:
|
|
1745
|
+
* - ${input.key} - Workflow input parameters (immutable)
|
|
1746
|
+
* - ${bb.key} - Blackboard values (mutable runtime state)
|
|
1747
|
+
* - ${env.KEY} - Environment variables
|
|
1748
|
+
* - ${param.key} - Test data parameters
|
|
1749
|
+
* - ${key} - Shorthand for ${bb.key} (backward compatibility)
|
|
1750
|
+
*
|
|
1751
|
+
* Features:
|
|
1752
|
+
* - Nested property access: ${bb.user.profile.name}
|
|
1753
|
+
* - Type preservation for full matches: "${bb.user}" returns the user object
|
|
1754
|
+
* - String interpolation for partial matches: "Hello ${bb.name}!" returns string
|
|
1755
|
+
*/
|
|
1756
|
+
|
|
1757
|
+
/**
|
|
1758
|
+
* Context for variable resolution
|
|
1759
|
+
*/
|
|
1760
|
+
interface VariableContext {
|
|
1761
|
+
/** Blackboard for runtime state */
|
|
1762
|
+
blackboard: IScopedBlackboard;
|
|
1763
|
+
/** Immutable workflow input parameters */
|
|
1764
|
+
input?: Readonly<Record<string, unknown>>;
|
|
1765
|
+
/** Test data parameters (from CSV, data tables, etc.) */
|
|
1766
|
+
testData?: Map<string, unknown>;
|
|
1767
|
+
}
|
|
1768
|
+
/**
|
|
1769
|
+
* Options for variable resolution
|
|
1770
|
+
*/
|
|
1771
|
+
interface ResolveOptions {
|
|
1772
|
+
/** Whether to keep undefined placeholders in output (default: true) */
|
|
1773
|
+
preserveUndefined?: boolean;
|
|
1774
|
+
/** Custom environment source (default: process.env) */
|
|
1775
|
+
envSource?: Record<string, string | undefined>;
|
|
1776
|
+
}
|
|
1777
|
+
declare function resolveString(str: string, ctx: VariableContext, opts?: ResolveOptions): unknown;
|
|
1778
|
+
/**
|
|
1779
|
+
* Resolve variables in any value (string, object, array, or primitive)
|
|
1780
|
+
*
|
|
1781
|
+
* @param value - Value to resolve
|
|
1782
|
+
* @param ctx - Variable context
|
|
1783
|
+
* @param opts - Resolution options
|
|
1784
|
+
* @returns Resolved value with all variable references replaced
|
|
1785
|
+
*/
|
|
1786
|
+
declare function resolveValue(value: unknown, ctx: VariableContext, opts?: ResolveOptions): unknown;
|
|
1787
|
+
/**
|
|
1788
|
+
* Check if a string contains any variable references
|
|
1789
|
+
*
|
|
1790
|
+
* @param str - String to check
|
|
1791
|
+
* @returns True if string contains ${...} patterns
|
|
1792
|
+
*/
|
|
1793
|
+
declare function hasVariables(str: string): boolean;
|
|
1794
|
+
/**
|
|
1795
|
+
* Extract all variable references from a string
|
|
1796
|
+
*
|
|
1797
|
+
* @param str - String to analyze
|
|
1798
|
+
* @returns Array of {namespace, key} objects
|
|
1799
|
+
*/
|
|
1800
|
+
declare function extractVariables(str: string): Array<{
|
|
1801
|
+
namespace: string;
|
|
1802
|
+
key: string;
|
|
1803
|
+
}>;
|
|
1804
|
+
|
|
1805
|
+
/**
|
|
1806
|
+
* ResumePoint - Marker node for resume location
|
|
1807
|
+
* Always returns SUCCESS, used purely as a findable marker for LLM-based resume
|
|
1808
|
+
*/
|
|
1809
|
+
|
|
1810
|
+
interface ResumePointConfig {
|
|
1811
|
+
id: string;
|
|
1812
|
+
}
|
|
1813
|
+
/**
|
|
1814
|
+
* ResumePoint is a marker node that LLM agents can insert to indicate
|
|
1815
|
+
* where execution should resume from. It always returns SUCCESS.
|
|
1816
|
+
*/
|
|
1817
|
+
declare class ResumePoint extends ActionNode {
|
|
1818
|
+
readonly resumePointId: string;
|
|
1819
|
+
constructor(config: ResumePointConfig);
|
|
1820
|
+
executeTick(_context: TemporalContext): Promise<NodeStatus>;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
/**
|
|
1824
|
+
* Custom error types for behavior tree execution
|
|
1825
|
+
*/
|
|
1826
|
+
/**
|
|
1827
|
+
* Error for test configuration/authoring issues.
|
|
1828
|
+
* These errors are NOT caught by Selector/Sequence - they propagate up
|
|
1829
|
+
* to signal that the test case itself is broken.
|
|
1830
|
+
*
|
|
1831
|
+
* Examples:
|
|
1832
|
+
* - Element reference not found in blackboard
|
|
1833
|
+
* - Missing required adapter
|
|
1834
|
+
* - Invalid tree structure (decorator without child)
|
|
1835
|
+
* - Invalid attribute values (negative timeout)
|
|
1836
|
+
*
|
|
1837
|
+
* These differ from operational failures (element not visible, timeout exceeded)
|
|
1838
|
+
* which should return NodeStatus.FAILURE and can be handled by Selector.
|
|
1839
|
+
*/
|
|
1840
|
+
declare class ConfigurationError extends Error {
|
|
1841
|
+
readonly hint?: string | undefined;
|
|
1842
|
+
readonly isConfigurationError = true;
|
|
1843
|
+
constructor(message: string, hint?: string | undefined);
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
/**
|
|
1847
|
+
* Tree definition schemas
|
|
1848
|
+
* Validates the structure of tree definitions before node creation
|
|
1849
|
+
*/
|
|
1850
|
+
|
|
1851
|
+
/**
|
|
1852
|
+
* Tree definition type
|
|
1853
|
+
* Matches the format expected by Registry.createTree()
|
|
1854
|
+
*/
|
|
1855
|
+
interface TreeDefinition {
|
|
1856
|
+
type: string;
|
|
1857
|
+
id?: string;
|
|
1858
|
+
name?: string;
|
|
1859
|
+
props?: Record<string, unknown>;
|
|
1860
|
+
children?: TreeDefinition[];
|
|
1861
|
+
}
|
|
1862
|
+
declare const treeDefinitionSchema: z.ZodType<TreeDefinition>;
|
|
1863
|
+
/**
|
|
1864
|
+
* Validate tree definition structure (without type-specific validation)
|
|
1865
|
+
* Type-specific validation happens in Registry.create()
|
|
1866
|
+
*
|
|
1867
|
+
* @param definition - Tree definition to validate
|
|
1868
|
+
* @returns Validated tree definition
|
|
1869
|
+
* @throws ZodError if structure is invalid
|
|
1870
|
+
*
|
|
1871
|
+
* @example
|
|
1872
|
+
* ```typescript
|
|
1873
|
+
* const definition = validateTreeDefinition({
|
|
1874
|
+
* type: 'Sequence',
|
|
1875
|
+
* id: 'root',
|
|
1876
|
+
* children: [
|
|
1877
|
+
* { type: 'PrintAction', id: 'action1' }
|
|
1878
|
+
* ]
|
|
1879
|
+
* });
|
|
1880
|
+
* ```
|
|
1881
|
+
*/
|
|
1882
|
+
declare function validateTreeDefinition(definition: unknown): TreeDefinition;
|
|
1883
|
+
/**
|
|
1884
|
+
* Validate decorator has exactly one child
|
|
1885
|
+
*
|
|
1886
|
+
* @param nodeType - Type of the decorator node
|
|
1887
|
+
* @param children - Children array to validate
|
|
1888
|
+
* @throws Error if child count is not exactly 1
|
|
1889
|
+
*/
|
|
1890
|
+
declare function validateDecoratorChildren(nodeType: string, children?: TreeDefinition[]): void;
|
|
1891
|
+
/**
|
|
1892
|
+
* Validate composite has at least minimum children
|
|
1893
|
+
*
|
|
1894
|
+
* @param nodeType - Type of the composite node
|
|
1895
|
+
* @param children - Children array to validate
|
|
1896
|
+
* @param minChildren - Minimum required children (default: 0)
|
|
1897
|
+
* @throws Error if child count is less than minimum
|
|
1898
|
+
*/
|
|
1899
|
+
declare function validateCompositeChildren(nodeType: string, children?: TreeDefinition[], minChildren?: number): void;
|
|
1900
|
+
/**
|
|
1901
|
+
* Validate specific child count for composites with fixed requirements
|
|
1902
|
+
*
|
|
1903
|
+
* @param nodeType - Type of the composite node
|
|
1904
|
+
* @param children - Children array to validate
|
|
1905
|
+
* @param expectedCount - Exact number of expected children
|
|
1906
|
+
* @throws Error if child count doesn't match expected
|
|
1907
|
+
*
|
|
1908
|
+
* @example
|
|
1909
|
+
* ```typescript
|
|
1910
|
+
* // While node requires exactly 2 children (condition, body)
|
|
1911
|
+
* validateChildCount('While', children, 2);
|
|
1912
|
+
* ```
|
|
1913
|
+
*/
|
|
1914
|
+
declare function validateChildCount(nodeType: string, children?: TreeDefinition[], expectedCount?: number): void;
|
|
1915
|
+
/**
|
|
1916
|
+
* Validate child count range for composites with flexible requirements
|
|
1917
|
+
*
|
|
1918
|
+
* @param nodeType - Type of the composite node
|
|
1919
|
+
* @param children - Children array to validate
|
|
1920
|
+
* @param minChildren - Minimum required children
|
|
1921
|
+
* @param maxChildren - Maximum allowed children
|
|
1922
|
+
* @throws Error if child count is outside range
|
|
1923
|
+
*
|
|
1924
|
+
* @example
|
|
1925
|
+
* ```typescript
|
|
1926
|
+
* // Conditional node requires 2-3 children (condition, then, optional else)
|
|
1927
|
+
* validateChildCountRange('Conditional', children, 2, 3);
|
|
1928
|
+
* ```
|
|
1929
|
+
*/
|
|
1930
|
+
declare function validateChildCountRange(nodeType: string, children?: TreeDefinition[], minChildren?: number, maxChildren?: number): void;
|
|
1931
|
+
|
|
1932
|
+
/**
|
|
1933
|
+
* YAML parser and validation error types
|
|
1934
|
+
*/
|
|
1935
|
+
/**
|
|
1936
|
+
* Base class for all YAML validation errors
|
|
1937
|
+
*/
|
|
1938
|
+
declare class ValidationError extends Error {
|
|
1939
|
+
path?: string | undefined;
|
|
1940
|
+
suggestion?: string | undefined;
|
|
1941
|
+
constructor(message: string, path?: string | undefined, suggestion?: string | undefined);
|
|
1942
|
+
/**
|
|
1943
|
+
* Format error message with path and suggestion
|
|
1944
|
+
*/
|
|
1945
|
+
format(): string;
|
|
1946
|
+
}
|
|
1947
|
+
/**
|
|
1948
|
+
* YAML syntax error (Stage 1)
|
|
1949
|
+
* Thrown when YAML is malformed
|
|
1950
|
+
*/
|
|
1951
|
+
declare class YamlSyntaxError extends ValidationError {
|
|
1952
|
+
line?: number | undefined;
|
|
1953
|
+
column?: number | undefined;
|
|
1954
|
+
constructor(message: string, line?: number | undefined, column?: number | undefined, suggestion?: string);
|
|
1955
|
+
format(): string;
|
|
1956
|
+
}
|
|
1957
|
+
/**
|
|
1958
|
+
* Tree structure validation error (Stage 2)
|
|
1959
|
+
* Thrown when tree definition structure is invalid
|
|
1960
|
+
*/
|
|
1961
|
+
declare class StructureValidationError extends ValidationError {
|
|
1962
|
+
constructor(message: string, path?: string, suggestion?: string);
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Node configuration validation error (Stage 3)
|
|
1966
|
+
* Thrown when node-specific configuration is invalid
|
|
1967
|
+
*/
|
|
1968
|
+
declare class ConfigValidationError extends ValidationError {
|
|
1969
|
+
nodeType: string;
|
|
1970
|
+
constructor(message: string, nodeType: string, path?: string, suggestion?: string);
|
|
1971
|
+
format(): string;
|
|
1972
|
+
}
|
|
1973
|
+
/**
|
|
1974
|
+
* Semantic validation error (Stage 4)
|
|
1975
|
+
* Thrown when semantic rules are violated (duplicate IDs, circular refs, etc.)
|
|
1976
|
+
*/
|
|
1977
|
+
declare class SemanticValidationError extends ValidationError {
|
|
1978
|
+
constructor(message: string, path?: string, suggestion?: string);
|
|
1979
|
+
}
|
|
1980
|
+
/**
|
|
1981
|
+
* Collect multiple validation errors
|
|
1982
|
+
*/
|
|
1983
|
+
declare class ValidationErrors extends Error {
|
|
1984
|
+
errors: ValidationError[];
|
|
1985
|
+
constructor(errors: ValidationError[]);
|
|
1986
|
+
/**
|
|
1987
|
+
* Format all errors as a single message
|
|
1988
|
+
*/
|
|
1989
|
+
format(): string;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
/**
|
|
1993
|
+
* YAML parser for behavior tree definitions
|
|
1994
|
+
* Implements 4-stage validation pipeline
|
|
1995
|
+
*/
|
|
1996
|
+
|
|
1997
|
+
/**
|
|
1998
|
+
* Options for YAML loading and validation
|
|
1999
|
+
*/
|
|
2000
|
+
interface LoadOptions {
|
|
2001
|
+
/**
|
|
2002
|
+
* Enable validation (default: true)
|
|
2003
|
+
*/
|
|
2004
|
+
validate?: boolean;
|
|
2005
|
+
/**
|
|
2006
|
+
* Fail on first error or collect all errors (default: true - fail fast)
|
|
2007
|
+
*/
|
|
2008
|
+
failFast?: boolean;
|
|
2009
|
+
/**
|
|
2010
|
+
* Auto-generate IDs for nodes without IDs (default: true)
|
|
2011
|
+
*/
|
|
2012
|
+
autoGenerateIds?: boolean;
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* Validation options for validateYaml()
|
|
2016
|
+
*/
|
|
2017
|
+
interface ValidationOptions {
|
|
2018
|
+
/**
|
|
2019
|
+
* Collect all errors instead of failing fast (default: false)
|
|
2020
|
+
*/
|
|
2021
|
+
collectAllErrors?: boolean;
|
|
2022
|
+
/**
|
|
2023
|
+
* Check semantic rules like references and circular deps (default: true)
|
|
2024
|
+
*/
|
|
2025
|
+
checkReferences?: boolean;
|
|
2026
|
+
}
|
|
2027
|
+
/**
|
|
2028
|
+
* Validation result
|
|
2029
|
+
*/
|
|
2030
|
+
interface ValidationResult {
|
|
2031
|
+
valid: boolean;
|
|
2032
|
+
errors: ValidationError[];
|
|
2033
|
+
warnings?: string[];
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Parse YAML string to TreeDefinition
|
|
2037
|
+
* Stage 1: YAML Syntax Validation
|
|
2038
|
+
*
|
|
2039
|
+
* @param yamlString - YAML content to parse
|
|
2040
|
+
* @returns Parsed tree definition object
|
|
2041
|
+
* @throws YamlSyntaxError if YAML is malformed
|
|
2042
|
+
*/
|
|
2043
|
+
declare function parseYaml(yamlString: string): TreeDefinition;
|
|
2044
|
+
/**
|
|
2045
|
+
* Load and create tree from YAML string
|
|
2046
|
+
*
|
|
2047
|
+
* @param yamlString - YAML content defining the tree
|
|
2048
|
+
* @param registry - Registry with registered node types
|
|
2049
|
+
* @param options - Loading options
|
|
2050
|
+
* @returns Created tree node
|
|
2051
|
+
* @throws ValidationError if validation fails
|
|
2052
|
+
*
|
|
2053
|
+
* @example
|
|
2054
|
+
* ```typescript
|
|
2055
|
+
* const yaml = `
|
|
2056
|
+
* type: Sequence
|
|
2057
|
+
* id: my-seq
|
|
2058
|
+
* children:
|
|
2059
|
+
* - type: PrintAction
|
|
2060
|
+
* id: action1
|
|
2061
|
+
* `;
|
|
2062
|
+
*
|
|
2063
|
+
* const tree = loadTreeFromYaml(yaml, registry);
|
|
2064
|
+
* ```
|
|
2065
|
+
*/
|
|
2066
|
+
declare function loadTreeFromYaml(yamlString: string, registry: Registry, options?: LoadOptions): TreeNode;
|
|
2067
|
+
/**
|
|
2068
|
+
* Validate YAML without creating tree
|
|
2069
|
+
* Useful for editors and validators
|
|
2070
|
+
*
|
|
2071
|
+
* @param yamlString - YAML content to validate
|
|
2072
|
+
* @param registry - Registry with registered node types
|
|
2073
|
+
* @param options - Validation options
|
|
2074
|
+
* @returns Validation result with errors
|
|
2075
|
+
*
|
|
2076
|
+
* @example
|
|
2077
|
+
* ```typescript
|
|
2078
|
+
* const result = validateYaml(yaml, registry);
|
|
2079
|
+
* if (!result.valid) {
|
|
2080
|
+
* console.error('Validation errors:', result.errors);
|
|
2081
|
+
* }
|
|
2082
|
+
* ```
|
|
2083
|
+
*/
|
|
2084
|
+
declare function validateYaml(yamlString: string, registry: Registry, options?: ValidationOptions): ValidationResult;
|
|
2085
|
+
/**
|
|
2086
|
+
* Convert TreeDefinition to YAML string
|
|
2087
|
+
*
|
|
2088
|
+
* @param definition - Tree definition to convert
|
|
2089
|
+
* @returns YAML string representation
|
|
2090
|
+
*
|
|
2091
|
+
* @example
|
|
2092
|
+
* ```typescript
|
|
2093
|
+
* const definition = { type: 'Sequence', id: 'root', children: [] };
|
|
2094
|
+
* const yamlString = toYaml(definition);
|
|
2095
|
+
* ```
|
|
2096
|
+
*/
|
|
2097
|
+
declare function toYaml(definition: TreeDefinition): string;
|
|
2098
|
+
|
|
2099
|
+
/**
|
|
2100
|
+
* File system integration for YAML loading
|
|
2101
|
+
*/
|
|
2102
|
+
|
|
2103
|
+
/**
|
|
2104
|
+
* Load and create tree from YAML file
|
|
2105
|
+
*
|
|
2106
|
+
* @param filePath - Path to YAML file
|
|
2107
|
+
* @param registry - Registry with registered node types
|
|
2108
|
+
* @param options - Loading options
|
|
2109
|
+
* @returns Created tree node
|
|
2110
|
+
* @throws ValidationError if validation fails
|
|
2111
|
+
* @throws Error if file cannot be read
|
|
2112
|
+
*
|
|
2113
|
+
* @example
|
|
2114
|
+
* ```typescript
|
|
2115
|
+
* const tree = await loadTreeFromFile('./workflows/checkout.yaml', registry);
|
|
2116
|
+
* ```
|
|
2117
|
+
*/
|
|
2118
|
+
declare function loadTreeFromFile(filePath: string, registry: Registry, options?: LoadOptions): Promise<TreeNode>;
|
|
2119
|
+
|
|
2120
|
+
/**
|
|
2121
|
+
* Semantic validation (Stage 4)
|
|
2122
|
+
* Validates semantic rules like ID uniqueness, circular references, etc.
|
|
2123
|
+
*/
|
|
2124
|
+
|
|
2125
|
+
/**
|
|
2126
|
+
* Semantic validator for tree definitions
|
|
2127
|
+
* Validates cross-node rules that can't be expressed in schemas
|
|
2128
|
+
*/
|
|
2129
|
+
declare class SemanticValidator {
|
|
2130
|
+
/**
|
|
2131
|
+
* Validate semantic rules for a tree definition
|
|
2132
|
+
*
|
|
2133
|
+
* @param definition - Tree definition to validate
|
|
2134
|
+
* @param registry - Registry to check node types and tree references
|
|
2135
|
+
* @returns Array of validation errors (empty if valid)
|
|
2136
|
+
*/
|
|
2137
|
+
validate(definition: TreeDefinition, registry: Registry): SemanticValidationError[];
|
|
2138
|
+
/**
|
|
2139
|
+
* Recursively validate a node and its children
|
|
2140
|
+
*/
|
|
2141
|
+
private validateNode;
|
|
2142
|
+
}
|
|
2143
|
+
/**
|
|
2144
|
+
* Singleton semantic validator instance
|
|
2145
|
+
*/
|
|
2146
|
+
declare const semanticValidator: SemanticValidator;
|
|
2147
|
+
|
|
2148
|
+
/**
|
|
2149
|
+
* Base Zod schemas for node configurations
|
|
2150
|
+
* Foundation for all node-specific validation schemas
|
|
2151
|
+
*/
|
|
2152
|
+
|
|
2153
|
+
/**
|
|
2154
|
+
* Base schema for all node configurations
|
|
2155
|
+
* Matches NodeConfiguration interface from types.ts
|
|
2156
|
+
*/
|
|
2157
|
+
declare const nodeConfigurationSchema: z.ZodObject<{
|
|
2158
|
+
id: z.ZodString;
|
|
2159
|
+
name: z.ZodOptional<z.ZodString>;
|
|
2160
|
+
}, z.core.$loose>;
|
|
2161
|
+
/**
|
|
2162
|
+
* Branded type for validated configurations
|
|
2163
|
+
* Ensures runtime type matches compile-time type
|
|
2164
|
+
*/
|
|
2165
|
+
type ValidatedNodeConfiguration = z.infer<typeof nodeConfigurationSchema>;
|
|
2166
|
+
/**
|
|
2167
|
+
* Helper to create node-specific configuration schemas
|
|
2168
|
+
* Extends base schema with node-specific fields
|
|
2169
|
+
*
|
|
2170
|
+
* @param nodeType - Name of the node type for error messages
|
|
2171
|
+
* @param fields - Node-specific field definitions
|
|
2172
|
+
* @returns Extended Zod schema
|
|
2173
|
+
*
|
|
2174
|
+
* @example
|
|
2175
|
+
* ```typescript
|
|
2176
|
+
* const timeoutSchema = createNodeSchema('Timeout', {
|
|
2177
|
+
* timeoutMs: validations.positiveNumber('timeoutMs'),
|
|
2178
|
+
* });
|
|
2179
|
+
* ```
|
|
2180
|
+
*/
|
|
2181
|
+
declare function createNodeSchema<T extends z.ZodRawShape>(nodeType: string, fields: T): z.ZodObject<(("id" | "name") & keyof T extends never ? {
|
|
2182
|
+
id: z.ZodString;
|
|
2183
|
+
name: z.ZodOptional<z.ZodString>;
|
|
2184
|
+
} & T : ({
|
|
2185
|
+
id: z.ZodString;
|
|
2186
|
+
name: z.ZodOptional<z.ZodString>;
|
|
2187
|
+
} extends infer T_2 extends z.core.util.SomeObject ? { [K in keyof T_2 as K extends keyof T ? never : K]: T_2[K]; } : never) & { [K_1 in keyof T]: T[K_1]; }) extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never, z.core.$loose>;
|
|
2188
|
+
/**
|
|
2189
|
+
* Common validation helpers
|
|
2190
|
+
* Reusable validators for standard patterns
|
|
2191
|
+
*/
|
|
2192
|
+
declare const validations: {
|
|
2193
|
+
/**
|
|
2194
|
+
* Positive number validator (> 0)
|
|
2195
|
+
*/
|
|
2196
|
+
positiveNumber: (fieldName: string) => z.ZodNumber;
|
|
2197
|
+
/**
|
|
2198
|
+
* Non-negative number validator (>= 0)
|
|
2199
|
+
*/
|
|
2200
|
+
nonNegativeNumber: (fieldName: string) => z.ZodNumber;
|
|
2201
|
+
/**
|
|
2202
|
+
* Positive integer validator (> 0, whole number)
|
|
2203
|
+
*/
|
|
2204
|
+
positiveInteger: (fieldName: string) => z.ZodNumber;
|
|
2205
|
+
/**
|
|
2206
|
+
* Non-negative integer validator (>= 0, whole number)
|
|
2207
|
+
*/
|
|
2208
|
+
nonNegativeInteger: (fieldName: string) => z.ZodNumber;
|
|
2209
|
+
/**
|
|
2210
|
+
* Blackboard key validator (non-empty string)
|
|
2211
|
+
*/
|
|
2212
|
+
blackboardKey: z.ZodString;
|
|
2213
|
+
/**
|
|
2214
|
+
* Tree ID validator (non-empty string for SubTree references)
|
|
2215
|
+
*/
|
|
2216
|
+
treeId: z.ZodString;
|
|
2217
|
+
/**
|
|
2218
|
+
* Duration in milliseconds validator (non-negative)
|
|
2219
|
+
*/
|
|
2220
|
+
durationMs: (fieldName?: string) => z.ZodNumber;
|
|
2221
|
+
};
|
|
2222
|
+
/**
|
|
2223
|
+
* Infer TypeScript type from schema
|
|
2224
|
+
* Helper for type-safe configuration interfaces
|
|
2225
|
+
*/
|
|
2226
|
+
type InferSchema<T extends z.ZodSchema> = z.infer<T>;
|
|
2227
|
+
|
|
2228
|
+
/**
|
|
2229
|
+
* Validation utilities and error conversion
|
|
2230
|
+
* Converts Zod validation errors to ConfigurationError
|
|
2231
|
+
*/
|
|
2232
|
+
|
|
2233
|
+
/**
|
|
2234
|
+
* Convert Zod validation errors to ConfigurationError
|
|
2235
|
+
* Preserves detailed error context and provides helpful hints
|
|
2236
|
+
*
|
|
2237
|
+
* @param error - Zod validation error
|
|
2238
|
+
* @param nodeType - Type of node being validated
|
|
2239
|
+
* @param nodeId - Optional node ID for context
|
|
2240
|
+
* @returns ConfigurationError with formatted message
|
|
2241
|
+
*/
|
|
2242
|
+
declare function zodErrorToConfigurationError(error: z.ZodError<unknown>, nodeType: string, nodeId?: string): ConfigurationError;
|
|
2243
|
+
/**
|
|
2244
|
+
* Validate and parse configuration with ConfigurationError conversion
|
|
2245
|
+
* Throws ConfigurationError if validation fails
|
|
2246
|
+
*
|
|
2247
|
+
* @param schema - Zod schema to validate against
|
|
2248
|
+
* @param config - Configuration object to validate
|
|
2249
|
+
* @param nodeType - Type of node being validated
|
|
2250
|
+
* @param nodeId - Optional node ID for error context
|
|
2251
|
+
* @returns Validated and parsed configuration
|
|
2252
|
+
* @throws ConfigurationError if validation fails
|
|
2253
|
+
*
|
|
2254
|
+
* @example
|
|
2255
|
+
* ```typescript
|
|
2256
|
+
* const validatedConfig = validateConfiguration(
|
|
2257
|
+
* timeoutSchema,
|
|
2258
|
+
* { id: 'test', timeoutMs: 1000 },
|
|
2259
|
+
* 'Timeout',
|
|
2260
|
+
* 'test'
|
|
2261
|
+
* );
|
|
2262
|
+
* ```
|
|
2263
|
+
*/
|
|
2264
|
+
declare function validateConfiguration<T = unknown>(schema: z.ZodSchema<T>, config: unknown, nodeType: string, nodeId?: string): T;
|
|
2265
|
+
/**
|
|
2266
|
+
* Safe validation that returns result instead of throwing
|
|
2267
|
+
* Useful for user-facing tools that need graceful error handling
|
|
2268
|
+
*
|
|
2269
|
+
* @param schema - Zod schema to validate against
|
|
2270
|
+
* @param config - Configuration object to validate
|
|
2271
|
+
* @param nodeType - Type of node being validated (for error messages)
|
|
2272
|
+
* @param nodeId - Optional node ID for error context
|
|
2273
|
+
* @returns Success result with data or failure result with error
|
|
2274
|
+
*
|
|
2275
|
+
* @example
|
|
2276
|
+
* ```typescript
|
|
2277
|
+
* const result = safeValidateConfiguration(
|
|
2278
|
+
* timeoutSchema,
|
|
2279
|
+
* { id: 'test', timeoutMs: -100 },
|
|
2280
|
+
* 'Timeout'
|
|
2281
|
+
* );
|
|
2282
|
+
*
|
|
2283
|
+
* if (result.success) {
|
|
2284
|
+
* console.log(result.data);
|
|
2285
|
+
* } else {
|
|
2286
|
+
* console.error(result.error.message);
|
|
2287
|
+
* }
|
|
2288
|
+
* ```
|
|
2289
|
+
*/
|
|
2290
|
+
declare function safeValidateConfiguration<T>(schema: z.ZodSchema<T>, config: unknown, nodeType: string, nodeId?: string): {
|
|
2291
|
+
success: true;
|
|
2292
|
+
data: T;
|
|
2293
|
+
} | {
|
|
2294
|
+
success: false;
|
|
2295
|
+
error: ConfigurationError;
|
|
2296
|
+
};
|
|
2297
|
+
|
|
2298
|
+
/**
|
|
2299
|
+
* Schema registry and validation exports
|
|
2300
|
+
* Central registry mapping node types to their validation schemas
|
|
2301
|
+
*/
|
|
2302
|
+
|
|
2303
|
+
/**
|
|
2304
|
+
* Central registry mapping node types to their validation schemas
|
|
2305
|
+
*
|
|
2306
|
+
* Responsibilities:
|
|
2307
|
+
* - Register Zod schemas for each node type
|
|
2308
|
+
* - Provide schema lookup by node type
|
|
2309
|
+
* - Validate configurations against registered schemas
|
|
2310
|
+
* - Fallback to base schema for unregistered types
|
|
2311
|
+
*
|
|
2312
|
+
* Usage:
|
|
2313
|
+
* ```typescript
|
|
2314
|
+
* // Register a schema
|
|
2315
|
+
* schemaRegistry.register('Timeout', timeoutConfigurationSchema);
|
|
2316
|
+
*
|
|
2317
|
+
* // Get a schema
|
|
2318
|
+
* const schema = schemaRegistry.getSchema('Timeout');
|
|
2319
|
+
*
|
|
2320
|
+
* // Validate configuration
|
|
2321
|
+
* const config = schemaRegistry.validate('Timeout', { id: 'test', timeoutMs: 1000 });
|
|
2322
|
+
* ```
|
|
2323
|
+
*/
|
|
2324
|
+
declare class SchemaRegistry {
|
|
2325
|
+
private schemas;
|
|
2326
|
+
constructor();
|
|
2327
|
+
/**
|
|
2328
|
+
* Register all node schemas
|
|
2329
|
+
* Called automatically on construction
|
|
2330
|
+
*/
|
|
2331
|
+
private registerAllSchemas;
|
|
2332
|
+
/**
|
|
2333
|
+
* Register a validation schema for a node type
|
|
2334
|
+
*
|
|
2335
|
+
* @param nodeType - Name of the node type (e.g., 'Timeout', 'Sequence')
|
|
2336
|
+
* @param schema - Zod schema for validating this node type's configuration
|
|
2337
|
+
* @throws Error if node type is already registered
|
|
2338
|
+
*
|
|
2339
|
+
* @example
|
|
2340
|
+
* ```typescript
|
|
2341
|
+
* schemaRegistry.register('Timeout', timeoutConfigurationSchema);
|
|
2342
|
+
* ```
|
|
2343
|
+
*/
|
|
2344
|
+
register(nodeType: string, schema: z.ZodSchema): void;
|
|
2345
|
+
/**
|
|
2346
|
+
* Get schema for a node type
|
|
2347
|
+
* Returns base schema if no specific schema registered
|
|
2348
|
+
*
|
|
2349
|
+
* @param nodeType - Name of the node type
|
|
2350
|
+
* @returns Zod schema for the node type (or base schema if not found)
|
|
2351
|
+
*
|
|
2352
|
+
* @example
|
|
2353
|
+
* ```typescript
|
|
2354
|
+
* const schema = schemaRegistry.getSchema('Timeout');
|
|
2355
|
+
* const validated = schema.parse({ id: 'test', timeoutMs: 1000 });
|
|
2356
|
+
* ```
|
|
2357
|
+
*/
|
|
2358
|
+
getSchema(nodeType: string): z.ZodSchema;
|
|
2359
|
+
/**
|
|
2360
|
+
* Check if a schema is registered for a node type
|
|
2361
|
+
*
|
|
2362
|
+
* @param nodeType - Name of the node type
|
|
2363
|
+
* @returns True if schema is registered, false otherwise
|
|
2364
|
+
*/
|
|
2365
|
+
hasSchema(nodeType: string): boolean;
|
|
2366
|
+
/**
|
|
2367
|
+
* Get all registered node types
|
|
2368
|
+
*
|
|
2369
|
+
* @returns Array of registered node type names
|
|
2370
|
+
*/
|
|
2371
|
+
getRegisteredTypes(): string[];
|
|
2372
|
+
/**
|
|
2373
|
+
* Validate configuration for a specific node type
|
|
2374
|
+
* Throws ZodError if validation fails
|
|
2375
|
+
*
|
|
2376
|
+
* @param nodeType - Name of the node type
|
|
2377
|
+
* @param config - Configuration object to validate
|
|
2378
|
+
* @returns Validated and parsed configuration
|
|
2379
|
+
* @throws ZodError if validation fails
|
|
2380
|
+
*
|
|
2381
|
+
* @example
|
|
2382
|
+
* ```typescript
|
|
2383
|
+
* const config = schemaRegistry.validate('Timeout', {
|
|
2384
|
+
* id: 'test',
|
|
2385
|
+
* timeoutMs: 1000
|
|
2386
|
+
* });
|
|
2387
|
+
* ```
|
|
2388
|
+
*/
|
|
2389
|
+
validate<T>(nodeType: string, config: unknown): T;
|
|
2390
|
+
/**
|
|
2391
|
+
* Safe validation that returns success/error result
|
|
2392
|
+
* Does not throw errors
|
|
2393
|
+
*
|
|
2394
|
+
* @param nodeType - Name of the node type
|
|
2395
|
+
* @param config - Configuration object to validate
|
|
2396
|
+
* @returns Result with success/error
|
|
2397
|
+
*
|
|
2398
|
+
* @example
|
|
2399
|
+
* ```typescript
|
|
2400
|
+
* const result = schemaRegistry.safeParse('Timeout', { id: 'test', timeoutMs: -100 });
|
|
2401
|
+
* if (result.success) {
|
|
2402
|
+
* console.log(result.data);
|
|
2403
|
+
* } else {
|
|
2404
|
+
* console.error(result.error);
|
|
2405
|
+
* }
|
|
2406
|
+
* ```
|
|
2407
|
+
*/
|
|
2408
|
+
safeParse(nodeType: string, config: unknown): {
|
|
2409
|
+
success: true;
|
|
2410
|
+
data: unknown;
|
|
2411
|
+
} | {
|
|
2412
|
+
success: false;
|
|
2413
|
+
error: z.ZodError<unknown>;
|
|
2414
|
+
};
|
|
2415
|
+
/**
|
|
2416
|
+
* Clear all registered schemas
|
|
2417
|
+
* Useful for testing
|
|
2418
|
+
*/
|
|
2419
|
+
clear(): void;
|
|
2420
|
+
}
|
|
2421
|
+
/**
|
|
2422
|
+
* Global singleton schema registry instance
|
|
2423
|
+
* Used by Registry class for validation
|
|
2424
|
+
*/
|
|
2425
|
+
declare const schemaRegistry: SchemaRegistry;
|
|
2426
|
+
|
|
2427
|
+
/**
|
|
2428
|
+
* Template Loader
|
|
2429
|
+
* Load YAML template files from a directory and register them in the btree Registry.
|
|
2430
|
+
* Templates can then be referenced by SubTree nodes using their template ID.
|
|
2431
|
+
*/
|
|
2432
|
+
|
|
2433
|
+
/**
|
|
2434
|
+
* Options for loading templates from a directory
|
|
2435
|
+
*/
|
|
2436
|
+
interface TemplateLoaderOptions {
|
|
2437
|
+
/** Path to the templates directory */
|
|
2438
|
+
templatesDir: string;
|
|
2439
|
+
/** Optional prefix to add to all template IDs (e.g., "tpl:") */
|
|
2440
|
+
idPrefix?: string;
|
|
2441
|
+
}
|
|
2442
|
+
/**
|
|
2443
|
+
* Load all template YAML files from a directory and register them in the registry.
|
|
2444
|
+
*
|
|
2445
|
+
* Each YAML file becomes a registered BehaviorTree that can be referenced
|
|
2446
|
+
* by SubTree nodes using the filename (without extension) as the tree ID.
|
|
2447
|
+
*
|
|
2448
|
+
* @param registry - The Registry instance to register templates in
|
|
2449
|
+
* @param options - Configuration options
|
|
2450
|
+
* @returns Array of template IDs that were loaded
|
|
2451
|
+
*
|
|
2452
|
+
* @example
|
|
2453
|
+
* ```typescript
|
|
2454
|
+
* const registry = new Registry();
|
|
2455
|
+
* registerStandardNodes(registry);
|
|
2456
|
+
*
|
|
2457
|
+
* const loadedIds = await loadTemplatesFromDirectory(registry, {
|
|
2458
|
+
* templatesDir: './templates',
|
|
2459
|
+
* idPrefix: 'tpl:'
|
|
2460
|
+
* });
|
|
2461
|
+
*
|
|
2462
|
+
* // Templates can now be used via SubTree:
|
|
2463
|
+
* // type: SubTree
|
|
2464
|
+
* // props:
|
|
2465
|
+
* // treeId: "tpl:order-validation"
|
|
2466
|
+
* ```
|
|
2467
|
+
*/
|
|
2468
|
+
declare function loadTemplatesFromDirectory(registry: Registry, options: TemplateLoaderOptions): Promise<string[]>;
|
|
2469
|
+
/**
|
|
2470
|
+
* Load a single template file and register it in the registry.
|
|
2471
|
+
*
|
|
2472
|
+
* @param registry - The Registry instance to register the template in
|
|
2473
|
+
* @param filePath - Path to the YAML template file
|
|
2474
|
+
* @param templateId - Optional custom ID for the template (defaults to filename)
|
|
2475
|
+
* @returns The template ID that was registered
|
|
2476
|
+
*
|
|
2477
|
+
* @example
|
|
2478
|
+
* ```typescript
|
|
2479
|
+
* const id = loadTemplate(registry, './templates/order-validation.yaml');
|
|
2480
|
+
* // Template is now available as "order-validation"
|
|
2481
|
+
*
|
|
2482
|
+
* const customId = loadTemplate(registry, './special.yaml', 'my-custom-id');
|
|
2483
|
+
* // Template is now available as "my-custom-id"
|
|
2484
|
+
* ```
|
|
2485
|
+
*/
|
|
2486
|
+
declare function loadTemplate(registry: Registry, filePath: string, templateId?: string): string;
|
|
2487
|
+
/**
|
|
2488
|
+
* Check if a template exists in the registry
|
|
2489
|
+
*/
|
|
2490
|
+
declare function hasTemplate(registry: Registry, templateId: string): boolean;
|
|
2491
|
+
/**
|
|
2492
|
+
* Get all registered template IDs
|
|
2493
|
+
*/
|
|
2494
|
+
declare function getTemplateIds(registry: Registry): string[];
|
|
2495
|
+
|
|
2496
|
+
/**
|
|
2497
|
+
* Integration Action Node
|
|
2498
|
+
* Execute third-party service actions via Active Pieces packages
|
|
2499
|
+
*
|
|
2500
|
+
* Features:
|
|
2501
|
+
* - Variable resolution: ${input.key}, ${bb.key}, ${env.KEY}, ${param.key}
|
|
2502
|
+
* - Pluggable token provider for OAuth/API key authentication
|
|
2503
|
+
* - Dynamic Active Pieces action execution
|
|
2504
|
+
* - Result storage in blackboard
|
|
2505
|
+
*/
|
|
2506
|
+
|
|
2507
|
+
/**
|
|
2508
|
+
* Configuration for IntegrationAction node
|
|
2509
|
+
*/
|
|
2510
|
+
interface IntegrationActionConfig extends NodeConfiguration {
|
|
2511
|
+
/** Provider name: 'google-sheets', 'slack', 'openai', etc. */
|
|
2512
|
+
provider: string;
|
|
2513
|
+
/** Action name from Active Pieces: 'append_row', 'send_message', etc. */
|
|
2514
|
+
action: string;
|
|
2515
|
+
/** Action inputs (supports ${input.key}, ${bb.key}, ${env.KEY}, ${param.key}) */
|
|
2516
|
+
inputs?: Record<string, unknown>;
|
|
2517
|
+
/** Connection ID to use (optional, defaults to user's primary connection) */
|
|
2518
|
+
connectionId?: string;
|
|
2519
|
+
/** Whether to store the result in blackboard (default: true) */
|
|
2520
|
+
storeResult?: boolean;
|
|
2521
|
+
/** Custom blackboard key for result (default: ${nodeId}.result) */
|
|
2522
|
+
resultKey?: string;
|
|
2523
|
+
}
|
|
2524
|
+
/**
|
|
2525
|
+
* Extended context with token provider
|
|
2526
|
+
*/
|
|
2527
|
+
interface IntegrationContext extends TemporalContext {
|
|
2528
|
+
/** Token provider function for fetching OAuth tokens */
|
|
2529
|
+
tokenProvider?: TokenProvider;
|
|
2530
|
+
/** Tenant ID for multi-tenant token lookup */
|
|
2531
|
+
tenantId?: string;
|
|
2532
|
+
/** User ID for user-scoped token lookup */
|
|
2533
|
+
userId?: string;
|
|
2534
|
+
}
|
|
2535
|
+
/**
|
|
2536
|
+
* Integration Action Node
|
|
2537
|
+
*
|
|
2538
|
+
* Executes actions on third-party services using Active Pieces packages.
|
|
2539
|
+
* Requires a token provider to be set in context for authentication.
|
|
2540
|
+
*
|
|
2541
|
+
* Supports variable resolution:
|
|
2542
|
+
* - ${input.key} - Workflow input parameters
|
|
2543
|
+
* - ${bb.key} - Blackboard values
|
|
2544
|
+
* - ${env.KEY} - Environment variables
|
|
2545
|
+
* - ${param.key} - Test data parameters
|
|
2546
|
+
*
|
|
2547
|
+
* @example
|
|
2548
|
+
* ```yaml
|
|
2549
|
+
* type: IntegrationAction
|
|
2550
|
+
* id: add-to-sheet
|
|
2551
|
+
* props:
|
|
2552
|
+
* provider: google-sheets
|
|
2553
|
+
* action: append_row
|
|
2554
|
+
* inputs:
|
|
2555
|
+
* spreadsheetId: "${input.spreadsheetId}"
|
|
2556
|
+
* sheetName: "Orders"
|
|
2557
|
+
* values:
|
|
2558
|
+
* - "${input.orderId}"
|
|
2559
|
+
* - "${bb.customerName}"
|
|
2560
|
+
* - "${bb.total}"
|
|
2561
|
+
* ```
|
|
2562
|
+
*/
|
|
2563
|
+
declare class IntegrationAction extends ActionNode {
|
|
2564
|
+
private provider;
|
|
2565
|
+
private action;
|
|
2566
|
+
private inputs;
|
|
2567
|
+
private connectionId?;
|
|
2568
|
+
private storeResult;
|
|
2569
|
+
private resultKey;
|
|
2570
|
+
constructor(config: IntegrationActionConfig);
|
|
2571
|
+
protected executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
2572
|
+
/**
|
|
2573
|
+
* Dual-mode execution:
|
|
2574
|
+
* - Activity mode: Use context.activities (deterministic for Temporal)
|
|
2575
|
+
* - Standalone mode: Inline executePieceAction (for testing)
|
|
2576
|
+
*/
|
|
2577
|
+
private executeAction;
|
|
2578
|
+
/**
|
|
2579
|
+
* Resolve variable references in inputs
|
|
2580
|
+
* Supports ${input.key}, ${bb.key}, ${env.KEY}, ${param.key}
|
|
2581
|
+
*/
|
|
2582
|
+
private resolveInputs;
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* Default token provider that reads from environment variables
|
|
2586
|
+
* Useful for testing and simple deployments
|
|
2587
|
+
*
|
|
2588
|
+
* Looks for:
|
|
2589
|
+
* - {PROVIDER}_ACCESS_TOKEN (e.g., GOOGLE_ACCESS_TOKEN)
|
|
2590
|
+
* - {PROVIDER}_API_KEY (e.g., OPENAI_API_KEY)
|
|
2591
|
+
*/
|
|
2592
|
+
declare const envTokenProvider: TokenProvider;
|
|
2593
|
+
|
|
2594
|
+
/**
|
|
2595
|
+
* Piece Executor
|
|
2596
|
+
* Dynamically executes Active Pieces actions
|
|
2597
|
+
*
|
|
2598
|
+
* Active Pieces is an open-source automation platform with 440+ connectors.
|
|
2599
|
+
* This module wraps their npm packages for use in btree workflows.
|
|
2600
|
+
*
|
|
2601
|
+
* @see https://activepieces.com/docs
|
|
2602
|
+
*/
|
|
2603
|
+
|
|
2604
|
+
/**
|
|
2605
|
+
* Execute an Active Pieces action
|
|
2606
|
+
*
|
|
2607
|
+
* @param request - Action request with provider, action, inputs, and auth
|
|
2608
|
+
* @returns The result from the Active Pieces action
|
|
2609
|
+
*
|
|
2610
|
+
* @example
|
|
2611
|
+
* ```typescript
|
|
2612
|
+
* const result = await executePieceAction({
|
|
2613
|
+
* provider: 'google-sheets',
|
|
2614
|
+
* action: 'append_row',
|
|
2615
|
+
* inputs: {
|
|
2616
|
+
* spreadsheetId: 'xxx',
|
|
2617
|
+
* sheetName: 'Sheet1',
|
|
2618
|
+
* values: ['A', 'B', 'C']
|
|
2619
|
+
* },
|
|
2620
|
+
* auth: { access_token: 'ya29.xxx' }
|
|
2621
|
+
* });
|
|
2622
|
+
* ```
|
|
2623
|
+
*/
|
|
2624
|
+
declare function executePieceAction(request: PieceActivityRequest): Promise<unknown>;
|
|
2625
|
+
/**
|
|
2626
|
+
* List available actions for a provider
|
|
2627
|
+
* Useful for UI builders and documentation
|
|
2628
|
+
*/
|
|
2629
|
+
declare function listPieceActions(provider: string): Promise<{
|
|
2630
|
+
name: string;
|
|
2631
|
+
displayName?: string;
|
|
2632
|
+
description?: string;
|
|
2633
|
+
}[]>;
|
|
2634
|
+
/**
|
|
2635
|
+
* Check if a piece is installed
|
|
2636
|
+
*/
|
|
2637
|
+
declare function isPieceInstalled(provider: string): Promise<boolean>;
|
|
2638
|
+
/**
|
|
2639
|
+
* Clear the piece cache (useful for testing)
|
|
2640
|
+
*/
|
|
2641
|
+
declare function clearPieceCache(): void;
|
|
2642
|
+
|
|
2643
|
+
/**
|
|
2644
|
+
* PythonScript Node
|
|
2645
|
+
*
|
|
2646
|
+
* Executes Python code via a cross-language Temporal activity.
|
|
2647
|
+
* This node requires the `executePythonScript` activity to be configured
|
|
2648
|
+
* in the context - it does not support standalone/inline execution because
|
|
2649
|
+
* Python execution requires a separate Python worker process.
|
|
2650
|
+
*
|
|
2651
|
+
* Features:
|
|
2652
|
+
* - Access to blackboard state via `bb` dict in Python
|
|
2653
|
+
* - Access to workflow input via `input` dict in Python
|
|
2654
|
+
* - Modifications to `bb` dict are merged back to blackboard
|
|
2655
|
+
* - Configurable timeout and environment variables
|
|
2656
|
+
*/
|
|
2657
|
+
|
|
2658
|
+
/**
|
|
2659
|
+
* Configuration for PythonScript node
|
|
2660
|
+
*/
|
|
2661
|
+
interface PythonScriptConfig extends NodeConfiguration {
|
|
2662
|
+
/** Python code to execute */
|
|
2663
|
+
code: string;
|
|
2664
|
+
/** Required packages (for documentation/validation) */
|
|
2665
|
+
packages?: string[];
|
|
2666
|
+
/** Execution timeout in ms (default: 60000) */
|
|
2667
|
+
timeout?: number;
|
|
2668
|
+
/** Allowed environment variables to pass to Python */
|
|
2669
|
+
allowedEnvVars?: string[];
|
|
2670
|
+
}
|
|
2671
|
+
/**
|
|
2672
|
+
* PythonScript Node
|
|
2673
|
+
*
|
|
2674
|
+
* Executes Python code via a cross-language Temporal activity.
|
|
2675
|
+
* The Python code has access to:
|
|
2676
|
+
* - `bb`: dict - Blackboard state (read/write)
|
|
2677
|
+
* - `input`: dict - Workflow input (read-only)
|
|
2678
|
+
*
|
|
2679
|
+
* @example YAML
|
|
2680
|
+
* ```yaml
|
|
2681
|
+
* type: PythonScript
|
|
2682
|
+
* id: transform-data
|
|
2683
|
+
* props:
|
|
2684
|
+
* code: |
|
|
2685
|
+
* import pandas as pd
|
|
2686
|
+
* df = pd.DataFrame(bb['orders'])
|
|
2687
|
+
* bb['total'] = df['amount'].sum()
|
|
2688
|
+
* bb['count'] = len(df)
|
|
2689
|
+
* packages:
|
|
2690
|
+
* - pandas
|
|
2691
|
+
* timeout: 30000
|
|
2692
|
+
* ```
|
|
2693
|
+
*/
|
|
2694
|
+
declare class PythonScript extends ActionNode {
|
|
2695
|
+
private code;
|
|
2696
|
+
private packages;
|
|
2697
|
+
private timeout;
|
|
2698
|
+
private allowedEnvVars;
|
|
2699
|
+
constructor(config: PythonScriptConfig);
|
|
2700
|
+
protected executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
2701
|
+
/**
|
|
2702
|
+
* Resolve variable references in the Python code
|
|
2703
|
+
* Allows dynamic code templates like:
|
|
2704
|
+
* code: "bb['output_key'] = '${input.prefix}_result'"
|
|
2705
|
+
*/
|
|
2706
|
+
private resolveCode;
|
|
2707
|
+
/**
|
|
2708
|
+
* Get allowed environment variables to pass to Python
|
|
2709
|
+
*/
|
|
2710
|
+
private getAllowedEnv;
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
/**
|
|
2714
|
+
* ParseFile Node
|
|
2715
|
+
*
|
|
2716
|
+
* Parses CSV/Excel files into structured data via a Temporal activity.
|
|
2717
|
+
* This node requires the `parseFile` activity to be configured in the context -
|
|
2718
|
+
* it does not support standalone/inline execution because file I/O requires
|
|
2719
|
+
* capabilities outside the workflow sandbox.
|
|
2720
|
+
*
|
|
2721
|
+
* Features:
|
|
2722
|
+
* - CSV and Excel (xlsx, xls) file format support
|
|
2723
|
+
* - Column mapping/renaming
|
|
2724
|
+
* - Parse options (skip rows, trim, date parsing)
|
|
2725
|
+
* - Result stored in blackboard
|
|
2726
|
+
*/
|
|
2727
|
+
|
|
2728
|
+
/**
|
|
2729
|
+
* Configuration for ParseFile node
|
|
2730
|
+
*/
|
|
2731
|
+
interface ParseFileConfig extends NodeConfiguration {
|
|
2732
|
+
/** Path to file (supports ${input.file}, ${bb.filePath}) */
|
|
2733
|
+
file: string;
|
|
2734
|
+
/** File format */
|
|
2735
|
+
format?: "csv" | "xlsx" | "xls" | "auto";
|
|
2736
|
+
/** Sheet name for Excel (default: first sheet) */
|
|
2737
|
+
sheetName?: string;
|
|
2738
|
+
/** Column mapping { "Original Name": "normalizedName" } */
|
|
2739
|
+
columnMapping?: Record<string, string>;
|
|
2740
|
+
/** Output key on blackboard */
|
|
2741
|
+
outputKey: string;
|
|
2742
|
+
/** Parse options */
|
|
2743
|
+
options?: ParseFileRequest["options"];
|
|
2744
|
+
}
|
|
2745
|
+
/**
|
|
2746
|
+
* ParseFile Node
|
|
2747
|
+
*
|
|
2748
|
+
* Parses CSV/Excel files into structured data and stores the result in blackboard.
|
|
2749
|
+
* Requires the `parseFile` activity to be configured.
|
|
2750
|
+
*
|
|
2751
|
+
* @example YAML
|
|
2752
|
+
* ```yaml
|
|
2753
|
+
* type: ParseFile
|
|
2754
|
+
* id: parse-orders
|
|
2755
|
+
* props:
|
|
2756
|
+
* file: "${input.orderFile}"
|
|
2757
|
+
* format: csv
|
|
2758
|
+
* columnMapping:
|
|
2759
|
+
* "Order ID": "orderId"
|
|
2760
|
+
* "Customer Name": "customerName"
|
|
2761
|
+
* "Amount": "amount"
|
|
2762
|
+
* outputKey: "orders"
|
|
2763
|
+
* options:
|
|
2764
|
+
* skipRows: 1
|
|
2765
|
+
* trim: true
|
|
2766
|
+
* ```
|
|
2767
|
+
*/
|
|
2768
|
+
declare class ParseFile extends ActionNode {
|
|
2769
|
+
private file;
|
|
2770
|
+
private format;
|
|
2771
|
+
private sheetName?;
|
|
2772
|
+
private columnMapping?;
|
|
2773
|
+
private outputKey;
|
|
2774
|
+
private options?;
|
|
2775
|
+
constructor(config: ParseFileConfig);
|
|
2776
|
+
protected executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
/**
|
|
2780
|
+
* GenerateFile Node
|
|
2781
|
+
*
|
|
2782
|
+
* Generates CSV/Excel/JSON files from data via a Temporal activity.
|
|
2783
|
+
* This node requires the `generateFile` activity to be configured in the context -
|
|
2784
|
+
* it does not support standalone/inline execution because file I/O requires
|
|
2785
|
+
* capabilities outside the workflow sandbox.
|
|
2786
|
+
*
|
|
2787
|
+
* Features:
|
|
2788
|
+
* - CSV, Excel (xlsx), and JSON output formats
|
|
2789
|
+
* - Column definitions with header names and widths
|
|
2790
|
+
* - Temporary or persistent storage
|
|
2791
|
+
* - Result metadata stored in blackboard (filename, path, URL)
|
|
2792
|
+
*/
|
|
2793
|
+
|
|
2794
|
+
/**
|
|
2795
|
+
* Configuration for GenerateFile node
|
|
2796
|
+
*/
|
|
2797
|
+
interface GenerateFileConfig extends NodeConfiguration {
|
|
2798
|
+
/** Output format */
|
|
2799
|
+
format: "csv" | "xlsx" | "json";
|
|
2800
|
+
/** Data source (blackboard key) */
|
|
2801
|
+
dataKey: string;
|
|
2802
|
+
/** Column definitions */
|
|
2803
|
+
columns?: Array<{
|
|
2804
|
+
header: string;
|
|
2805
|
+
key: string;
|
|
2806
|
+
width?: number;
|
|
2807
|
+
}>;
|
|
2808
|
+
/** Output filename template (supports ${input.x}, ${bb.x}) */
|
|
2809
|
+
filename: string;
|
|
2810
|
+
/** Storage type */
|
|
2811
|
+
storage: "temp" | "persistent";
|
|
2812
|
+
/** Output key for file metadata (path, url, size) */
|
|
2813
|
+
outputKey: string;
|
|
2814
|
+
}
|
|
2815
|
+
/**
|
|
2816
|
+
* GenerateFile Node
|
|
2817
|
+
*
|
|
2818
|
+
* Generates a file from data in the blackboard and stores file metadata.
|
|
2819
|
+
* Requires the `generateFile` activity to be configured.
|
|
2820
|
+
*
|
|
2821
|
+
* @example YAML
|
|
2822
|
+
* ```yaml
|
|
2823
|
+
* type: GenerateFile
|
|
2824
|
+
* id: export-report
|
|
2825
|
+
* props:
|
|
2826
|
+
* format: csv
|
|
2827
|
+
* dataKey: "processedOrders"
|
|
2828
|
+
* columns:
|
|
2829
|
+
* - header: "Order ID"
|
|
2830
|
+
* key: "orderId"
|
|
2831
|
+
* - header: "Customer"
|
|
2832
|
+
* key: "customerName"
|
|
2833
|
+
* - header: "Total"
|
|
2834
|
+
* key: "amount"
|
|
2835
|
+
* width: 15
|
|
2836
|
+
* filename: "orders-${bb.timestamp}.csv"
|
|
2837
|
+
* storage: persistent
|
|
2838
|
+
* outputKey: "exportedFile"
|
|
2839
|
+
* ```
|
|
2840
|
+
*/
|
|
2841
|
+
declare class GenerateFile extends ActionNode {
|
|
2842
|
+
private format;
|
|
2843
|
+
private dataKey;
|
|
2844
|
+
private columns?;
|
|
2845
|
+
private filename;
|
|
2846
|
+
private storage;
|
|
2847
|
+
private outputKey;
|
|
2848
|
+
constructor(config: GenerateFileConfig);
|
|
2849
|
+
protected executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
/**
|
|
2853
|
+
* HttpRequest Node
|
|
2854
|
+
*
|
|
2855
|
+
* Makes HTTP requests via a Temporal activity.
|
|
2856
|
+
* This node requires the `fetchUrl` activity to be configured in the context -
|
|
2857
|
+
* it does not support standalone/inline execution because HTTP I/O requires
|
|
2858
|
+
* capabilities outside the workflow sandbox.
|
|
2859
|
+
*
|
|
2860
|
+
* Features:
|
|
2861
|
+
* - Support for GET, POST, PUT, DELETE, PATCH methods
|
|
2862
|
+
* - Variable resolution in URL, headers, and body
|
|
2863
|
+
* - Configurable response parsing (JSON/text/binary)
|
|
2864
|
+
* - Retry with exponential backoff support
|
|
2865
|
+
* - Timeout configuration
|
|
2866
|
+
* - Result stored in blackboard
|
|
2867
|
+
*/
|
|
2868
|
+
|
|
2869
|
+
/**
|
|
2870
|
+
* Configuration for HttpRequest node
|
|
2871
|
+
*/
|
|
2872
|
+
interface HttpRequestConfig extends NodeConfiguration {
|
|
2873
|
+
/** URL to request (supports ${input.x}, ${bb.x}) */
|
|
2874
|
+
url: string;
|
|
2875
|
+
/** HTTP method (default: GET) */
|
|
2876
|
+
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
2877
|
+
/** Request headers (supports variable resolution) */
|
|
2878
|
+
headers?: Record<string, string>;
|
|
2879
|
+
/** Request body (supports variable resolution) */
|
|
2880
|
+
body?: unknown;
|
|
2881
|
+
/** Expected response type for parsing */
|
|
2882
|
+
responseType?: "json" | "text" | "binary";
|
|
2883
|
+
/** Request timeout in milliseconds */
|
|
2884
|
+
timeout?: number;
|
|
2885
|
+
/** Retry configuration */
|
|
2886
|
+
retry?: {
|
|
2887
|
+
maxAttempts: number;
|
|
2888
|
+
backoffMs: number;
|
|
2889
|
+
};
|
|
2890
|
+
/** Output key on blackboard for response */
|
|
2891
|
+
outputKey: string;
|
|
2892
|
+
}
|
|
2893
|
+
/**
|
|
2894
|
+
* HttpRequest Node
|
|
2895
|
+
*
|
|
2896
|
+
* Makes HTTP requests via a Temporal activity and stores the response in blackboard.
|
|
2897
|
+
* Requires the `fetchUrl` activity to be configured.
|
|
2898
|
+
*
|
|
2899
|
+
* @example YAML
|
|
2900
|
+
* ```yaml
|
|
2901
|
+
* type: HttpRequest
|
|
2902
|
+
* id: fetch-user
|
|
2903
|
+
* props:
|
|
2904
|
+
* url: "https://api.example.com/users/${input.userId}"
|
|
2905
|
+
* method: GET
|
|
2906
|
+
* headers:
|
|
2907
|
+
* Authorization: "Bearer ${bb.accessToken}"
|
|
2908
|
+
* timeout: 5000
|
|
2909
|
+
* responseType: json
|
|
2910
|
+
* outputKey: "userData"
|
|
2911
|
+
* ```
|
|
2912
|
+
*
|
|
2913
|
+
* @example YAML with POST
|
|
2914
|
+
* ```yaml
|
|
2915
|
+
* type: HttpRequest
|
|
2916
|
+
* id: create-order
|
|
2917
|
+
* props:
|
|
2918
|
+
* url: "https://api.example.com/orders"
|
|
2919
|
+
* method: POST
|
|
2920
|
+
* headers:
|
|
2921
|
+
* Content-Type: "application/json"
|
|
2922
|
+
* Authorization: "Bearer ${bb.token}"
|
|
2923
|
+
* body:
|
|
2924
|
+
* customerId: "${input.customerId}"
|
|
2925
|
+
* items: "${bb.cartItems}"
|
|
2926
|
+
* timeout: 10000
|
|
2927
|
+
* retry:
|
|
2928
|
+
* maxAttempts: 3
|
|
2929
|
+
* backoffMs: 1000
|
|
2930
|
+
* outputKey: "orderResponse"
|
|
2931
|
+
* ```
|
|
2932
|
+
*/
|
|
2933
|
+
declare class HttpRequest extends ActionNode {
|
|
2934
|
+
private url;
|
|
2935
|
+
private method;
|
|
2936
|
+
private headers?;
|
|
2937
|
+
private body?;
|
|
2938
|
+
private responseType;
|
|
2939
|
+
private timeout?;
|
|
2940
|
+
private retry?;
|
|
2941
|
+
private outputKey;
|
|
2942
|
+
constructor(config: HttpRequestConfig);
|
|
2943
|
+
protected executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
2944
|
+
/**
|
|
2945
|
+
* Sleep for the specified duration
|
|
2946
|
+
*/
|
|
2947
|
+
private sleep;
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
/**
|
|
2951
|
+
* CodeExecution Node
|
|
2952
|
+
*
|
|
2953
|
+
* Executes JavaScript or Python code in a secure sandboxed environment
|
|
2954
|
+
* via Microsandbox (libkrun microVM). This node replaces the inline Script
|
|
2955
|
+
* node for production use where untrusted/AI-generated code needs isolation.
|
|
2956
|
+
*
|
|
2957
|
+
* Features:
|
|
2958
|
+
* - Support for JavaScript and Python
|
|
2959
|
+
* - Full VM isolation (no network, no filesystem, no cloud credentials)
|
|
2960
|
+
* - DataStore integration for large payloads
|
|
2961
|
+
* - getBB/setBB helpers for blackboard access
|
|
2962
|
+
* - getInput helper for workflow input access
|
|
2963
|
+
* - Configurable timeout
|
|
2964
|
+
* - Python package installation support
|
|
2965
|
+
*
|
|
2966
|
+
* Security:
|
|
2967
|
+
* - Code runs in Microsandbox microVM
|
|
2968
|
+
* - No cloud credentials exposed to sandbox
|
|
2969
|
+
* - Activity fetches data from DataStore, not the sandbox
|
|
2970
|
+
* - Only JSON data crosses the sandbox boundary
|
|
2971
|
+
*/
|
|
2972
|
+
|
|
2973
|
+
/**
|
|
2974
|
+
* Configuration for CodeExecution node
|
|
2975
|
+
*/
|
|
2976
|
+
interface CodeExecutionConfig extends NodeConfiguration {
|
|
2977
|
+
/** Code to execute */
|
|
2978
|
+
code: string;
|
|
2979
|
+
/** Programming language: 'javascript' or 'python' */
|
|
2980
|
+
language: "javascript" | "python";
|
|
2981
|
+
/** Execution timeout in milliseconds (default: 30000) */
|
|
2982
|
+
timeout?: number;
|
|
2983
|
+
/** Python packages to install before execution */
|
|
2984
|
+
packages?: string[];
|
|
2985
|
+
}
|
|
2986
|
+
/**
|
|
2987
|
+
* CodeExecution Node
|
|
2988
|
+
*
|
|
2989
|
+
* Executes code in a sandboxed environment via Temporal activity.
|
|
2990
|
+
* Requires the `executeCode` activity to be configured.
|
|
2991
|
+
*
|
|
2992
|
+
* @example YAML (JavaScript)
|
|
2993
|
+
* ```yaml
|
|
2994
|
+
* type: CodeExecution
|
|
2995
|
+
* id: transform-data
|
|
2996
|
+
* props:
|
|
2997
|
+
* language: javascript
|
|
2998
|
+
* code: |
|
|
2999
|
+
* const users = getBB('apiUsers');
|
|
3000
|
+
* const processed = users.map(u => ({
|
|
3001
|
+
* id: u.id,
|
|
3002
|
+
* name: u.name.toUpperCase()
|
|
3003
|
+
* }));
|
|
3004
|
+
* setBB('processedUsers', processed);
|
|
3005
|
+
* timeout: 30000
|
|
3006
|
+
* ```
|
|
3007
|
+
*
|
|
3008
|
+
* @example YAML (Python)
|
|
3009
|
+
* ```yaml
|
|
3010
|
+
* type: CodeExecution
|
|
3011
|
+
* id: analyze-data
|
|
3012
|
+
* props:
|
|
3013
|
+
* language: python
|
|
3014
|
+
* packages:
|
|
3015
|
+
* - pandas
|
|
3016
|
+
* code: |
|
|
3017
|
+
* import pandas as pd
|
|
3018
|
+
*
|
|
3019
|
+
* users = getBB('apiUsers')
|
|
3020
|
+
* df = pd.DataFrame(users)
|
|
3021
|
+
*
|
|
3022
|
+
* setBB('userCount', len(df))
|
|
3023
|
+
* setBB('domains', df['email'].str.split('@').str[1].unique().tolist())
|
|
3024
|
+
* timeout: 60000
|
|
3025
|
+
* ```
|
|
3026
|
+
*
|
|
3027
|
+
* Available functions in sandbox:
|
|
3028
|
+
* - getBB(key): Get value from blackboard
|
|
3029
|
+
* - setBB(key, value): Set value on blackboard
|
|
3030
|
+
* - getInput(key): Get value from workflow input (read-only)
|
|
3031
|
+
*/
|
|
3032
|
+
declare class CodeExecution extends ActionNode {
|
|
3033
|
+
private code;
|
|
3034
|
+
private language;
|
|
3035
|
+
private timeout;
|
|
3036
|
+
private packages;
|
|
3037
|
+
constructor(config: CodeExecutionConfig);
|
|
3038
|
+
protected executeTick(context: TemporalContext): Promise<NodeStatus>;
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
/**
|
|
3042
|
+
* Observability types for workflow execution tracking
|
|
3043
|
+
* Used by ExecutionTracker and Analyzer Agent
|
|
3044
|
+
*/
|
|
3045
|
+
/**
|
|
3046
|
+
* Overall execution progress summary
|
|
3047
|
+
*/
|
|
3048
|
+
interface ExecutionProgress {
|
|
3049
|
+
/** Total number of nodes in the tree */
|
|
3050
|
+
totalNodes: number;
|
|
3051
|
+
/** Number of nodes that completed successfully */
|
|
3052
|
+
completedNodes: number;
|
|
3053
|
+
/** Number of nodes that failed */
|
|
3054
|
+
failedNodes: number;
|
|
3055
|
+
/** Currently executing node ID (null if not running) */
|
|
3056
|
+
currentNodeId: string | null;
|
|
3057
|
+
/** Type of currently executing node */
|
|
3058
|
+
currentNodeType: string | null;
|
|
3059
|
+
/** Ordered list of node IDs that have been executed */
|
|
3060
|
+
pathTaken: string[];
|
|
3061
|
+
/** Timestamp when execution started */
|
|
3062
|
+
startedAt: number;
|
|
3063
|
+
/** Timestamp of last activity */
|
|
3064
|
+
lastActivityAt: number;
|
|
3065
|
+
/** Overall status */
|
|
3066
|
+
status: "running" | "completed" | "failed";
|
|
3067
|
+
}
|
|
3068
|
+
/**
|
|
3069
|
+
* State of a single node during execution
|
|
3070
|
+
*/
|
|
3071
|
+
interface NodeState {
|
|
3072
|
+
/** Node ID */
|
|
3073
|
+
id: string;
|
|
3074
|
+
/** Node type (e.g., "Sequence", "CodeExecution") */
|
|
3075
|
+
type: string;
|
|
3076
|
+
/** Node name */
|
|
3077
|
+
name: string;
|
|
3078
|
+
/** Tree path (e.g., "/0/1/2") */
|
|
3079
|
+
path: string;
|
|
3080
|
+
/** Current status */
|
|
3081
|
+
status: "idle" | "running" | "success" | "failure";
|
|
3082
|
+
/** Last error message if failed */
|
|
3083
|
+
lastError?: string;
|
|
3084
|
+
/** Number of times this node has been ticked */
|
|
3085
|
+
tickCount: number;
|
|
3086
|
+
/** Timestamp of last tick */
|
|
3087
|
+
lastTickAt?: number;
|
|
3088
|
+
/** Duration of last tick in ms */
|
|
3089
|
+
durationMs?: number;
|
|
3090
|
+
}
|
|
3091
|
+
/**
|
|
3092
|
+
* Structured error with rich context for debugging
|
|
3093
|
+
*/
|
|
3094
|
+
interface StructuredError {
|
|
3095
|
+
/** Node ID where error occurred */
|
|
3096
|
+
nodeId: string;
|
|
3097
|
+
/** Node type */
|
|
3098
|
+
nodeType: string;
|
|
3099
|
+
/** Node name */
|
|
3100
|
+
nodeName: string;
|
|
3101
|
+
/** Tree path (e.g., "/0/1/2") */
|
|
3102
|
+
nodePath: string;
|
|
3103
|
+
/** Error message */
|
|
3104
|
+
message: string;
|
|
3105
|
+
/** Error stack trace (if available) */
|
|
3106
|
+
stack?: string;
|
|
3107
|
+
/** Timestamp when error occurred */
|
|
3108
|
+
timestamp: number;
|
|
3109
|
+
/** Blackboard snapshot at time of error */
|
|
3110
|
+
blackboardSnapshot: Record<string, unknown>;
|
|
3111
|
+
/** Input that was passed to the node */
|
|
3112
|
+
nodeInput?: unknown;
|
|
3113
|
+
/** Whether this error is potentially recoverable with retry */
|
|
3114
|
+
recoverable: boolean;
|
|
3115
|
+
/** Suggested fix based on error analysis */
|
|
3116
|
+
suggestedFix?: string;
|
|
3117
|
+
}
|
|
3118
|
+
/**
|
|
3119
|
+
* Entry in the execution timeline
|
|
3120
|
+
*/
|
|
3121
|
+
interface TimelineEntry {
|
|
3122
|
+
/** Node ID */
|
|
3123
|
+
nodeId: string;
|
|
3124
|
+
/** Node type */
|
|
3125
|
+
nodeType: string;
|
|
3126
|
+
/** Node name */
|
|
3127
|
+
nodeName: string;
|
|
3128
|
+
/** Tree path */
|
|
3129
|
+
nodePath: string;
|
|
3130
|
+
/** Event type */
|
|
3131
|
+
event: "start" | "end" | "error";
|
|
3132
|
+
/** Timestamp */
|
|
3133
|
+
timestamp: number;
|
|
3134
|
+
/** Final status (for end events) */
|
|
3135
|
+
status?: string;
|
|
3136
|
+
/** Duration in ms (for end events) */
|
|
3137
|
+
durationMs?: number;
|
|
3138
|
+
/** Error details (for error events) */
|
|
3139
|
+
error?: {
|
|
3140
|
+
message: string;
|
|
3141
|
+
stack?: string;
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
/**
|
|
3145
|
+
* Extended NodeEvent with path and blackboard context
|
|
3146
|
+
* Used internally by ExecutionTracker
|
|
3147
|
+
*/
|
|
3148
|
+
interface ObservableNodeEvent {
|
|
3149
|
+
type: string;
|
|
3150
|
+
nodeId: string;
|
|
3151
|
+
nodeName: string;
|
|
3152
|
+
nodeType: string;
|
|
3153
|
+
nodePath?: string;
|
|
3154
|
+
timestamp: number;
|
|
3155
|
+
data?: {
|
|
3156
|
+
status?: string;
|
|
3157
|
+
durationMs?: number;
|
|
3158
|
+
error?: {
|
|
3159
|
+
message: string;
|
|
3160
|
+
stack?: string;
|
|
3161
|
+
input?: unknown;
|
|
3162
|
+
};
|
|
3163
|
+
blackboard?: Record<string, unknown>;
|
|
3164
|
+
};
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
/**
|
|
3168
|
+
* ExecutionTracker - Aggregates node events into queryable state
|
|
3169
|
+
* Used by workflow query handlers to expose real-time execution progress
|
|
3170
|
+
*/
|
|
3171
|
+
|
|
3172
|
+
/**
|
|
3173
|
+
* Tracks execution state by subscribing to node events
|
|
3174
|
+
* Provides query methods for progress, node states, errors, and timeline
|
|
3175
|
+
*/
|
|
3176
|
+
declare class ExecutionTracker {
|
|
3177
|
+
private nodeStates;
|
|
3178
|
+
private timeline;
|
|
3179
|
+
private errors;
|
|
3180
|
+
private pathTaken;
|
|
3181
|
+
private startedAt;
|
|
3182
|
+
private currentNodeId;
|
|
3183
|
+
private totalNodes;
|
|
3184
|
+
private finished;
|
|
3185
|
+
constructor(totalNodes: number);
|
|
3186
|
+
/**
|
|
3187
|
+
* Process a node event and update internal state
|
|
3188
|
+
* Called by NodeEventEmitter subscription
|
|
3189
|
+
*/
|
|
3190
|
+
onNodeEvent(event: ObservableNodeEvent): void;
|
|
3191
|
+
private handleTickStart;
|
|
3192
|
+
private handleTickEnd;
|
|
3193
|
+
private handleError;
|
|
3194
|
+
/**
|
|
3195
|
+
* Mark execution as finished
|
|
3196
|
+
*/
|
|
3197
|
+
markFinished(): void;
|
|
3198
|
+
/**
|
|
3199
|
+
* Get overall execution progress
|
|
3200
|
+
*/
|
|
3201
|
+
getProgress(): ExecutionProgress;
|
|
3202
|
+
/**
|
|
3203
|
+
* Get all node states
|
|
3204
|
+
*/
|
|
3205
|
+
getNodeStates(): Map<string, NodeState>;
|
|
3206
|
+
/**
|
|
3207
|
+
* Get node states as a plain object (for JSON serialization)
|
|
3208
|
+
*/
|
|
3209
|
+
getNodeStatesObject(): Record<string, NodeState>;
|
|
3210
|
+
/**
|
|
3211
|
+
* Get all errors that occurred during execution
|
|
3212
|
+
*/
|
|
3213
|
+
getErrors(): StructuredError[];
|
|
3214
|
+
/**
|
|
3215
|
+
* Get the full execution timeline
|
|
3216
|
+
*/
|
|
3217
|
+
getTimeline(): TimelineEntry[];
|
|
3218
|
+
/**
|
|
3219
|
+
* Get state for a specific node
|
|
3220
|
+
*/
|
|
3221
|
+
getNodeState(nodeId: string): NodeState | undefined;
|
|
3222
|
+
private getOrCreateState;
|
|
3223
|
+
/**
|
|
3224
|
+
* Check if an error type is potentially recoverable with retry
|
|
3225
|
+
*/
|
|
3226
|
+
private isRecoverable;
|
|
3227
|
+
/**
|
|
3228
|
+
* Suggest a fix based on error patterns
|
|
3229
|
+
*/
|
|
3230
|
+
private suggestFix;
|
|
3231
|
+
}
|
|
3232
|
+
|
|
3233
|
+
/**
|
|
3234
|
+
* Workflow Sink types for exporting events from Temporal workflows
|
|
3235
|
+
* Sinks allow workflows to export data without affecting determinism
|
|
3236
|
+
*/
|
|
3237
|
+
|
|
3238
|
+
/**
|
|
3239
|
+
* Observability sinks for workflow event export
|
|
3240
|
+
*
|
|
3241
|
+
* Usage in workflow:
|
|
3242
|
+
* ```typescript
|
|
3243
|
+
* import { proxySinks } from '@temporalio/workflow';
|
|
3244
|
+
* import type { ObservabilitySinks } from '@wayfarer-ai/btree-workflows';
|
|
3245
|
+
*
|
|
3246
|
+
* const { events } = proxySinks<ObservabilitySinks>();
|
|
3247
|
+
* events.push(nodeEvent); // Fire-and-forget
|
|
3248
|
+
* ```
|
|
3249
|
+
*
|
|
3250
|
+
* The sink handler runs in the worker (outside the deterministic sandbox)
|
|
3251
|
+
* and can safely perform I/O like database writes or triggering agents.
|
|
3252
|
+
*/
|
|
3253
|
+
interface ObservabilitySinks extends Sinks {
|
|
3254
|
+
events: {
|
|
3255
|
+
/**
|
|
3256
|
+
* Push a node event to external observers
|
|
3257
|
+
* This is fire-and-forget - workflow execution continues immediately
|
|
3258
|
+
*/
|
|
3259
|
+
push(event: ObservableNodeEvent): void;
|
|
3260
|
+
};
|
|
3261
|
+
}
|
|
3262
|
+
/**
|
|
3263
|
+
* Configuration for creating sink handlers
|
|
3264
|
+
*/
|
|
3265
|
+
interface SinkHandlerConfig {
|
|
3266
|
+
/**
|
|
3267
|
+
* Called when a node event is received
|
|
3268
|
+
* Can be async - workflow doesn't wait for completion
|
|
3269
|
+
*/
|
|
3270
|
+
onEvent?: (workflowId: string, runId: string, event: ObservableNodeEvent) => void | Promise<void>;
|
|
3271
|
+
/**
|
|
3272
|
+
* Called specifically for ERROR events
|
|
3273
|
+
* Use this to trigger analyzer agent or alerting
|
|
3274
|
+
*/
|
|
3275
|
+
onError?: (workflowId: string, runId: string, event: ObservableNodeEvent) => void | Promise<void>;
|
|
3276
|
+
/**
|
|
3277
|
+
* Whether to log events to console (default: false)
|
|
3278
|
+
*/
|
|
3279
|
+
logEvents?: boolean;
|
|
3280
|
+
}
|
|
3281
|
+
/**
|
|
3282
|
+
* Sink function signature for InjectedSinks
|
|
3283
|
+
*/
|
|
3284
|
+
interface SinkFunction<T extends (...args: any[]) => any> {
|
|
3285
|
+
fn(info: {
|
|
3286
|
+
workflowId: string;
|
|
3287
|
+
runId: string;
|
|
3288
|
+
}, ...args: Parameters<T>): ReturnType<T>;
|
|
3289
|
+
callDuringReplay: boolean;
|
|
3290
|
+
}
|
|
3291
|
+
/**
|
|
3292
|
+
* Type for InjectedSinks<ObservabilitySinks>
|
|
3293
|
+
*/
|
|
3294
|
+
type InjectedObservabilitySinks = {
|
|
3295
|
+
events: {
|
|
3296
|
+
push: SinkFunction<(event: ObservableNodeEvent) => void>;
|
|
3297
|
+
};
|
|
3298
|
+
};
|
|
3299
|
+
/**
|
|
3300
|
+
* Create sink handler functions for InjectedSinks
|
|
3301
|
+
*
|
|
3302
|
+
* Usage in worker:
|
|
3303
|
+
* ```typescript
|
|
3304
|
+
* import { createObservabilitySinkHandler } from '@wayfarer-ai/btree-workflows';
|
|
3305
|
+
*
|
|
3306
|
+
* const sinks = createObservabilitySinkHandler({
|
|
3307
|
+
* onEvent: (workflowId, runId, event) => {
|
|
3308
|
+
* // Store event to database
|
|
3309
|
+
* },
|
|
3310
|
+
* onError: (workflowId, runId, event) => {
|
|
3311
|
+
* // Trigger analyzer agent
|
|
3312
|
+
* },
|
|
3313
|
+
* });
|
|
3314
|
+
*
|
|
3315
|
+
* const worker = await Worker.create({ sinks, ... });
|
|
3316
|
+
* ```
|
|
3317
|
+
*/
|
|
3318
|
+
declare function createObservabilitySinkHandler(config?: SinkHandlerConfig): InjectedObservabilitySinks;
|
|
3319
|
+
|
|
3320
|
+
export { ActionNode, AlwaysCondition, BaseNode, BehaviorTree, type BtreeActivities, CheckCondition, CodeExecution, type CodeExecutionConfig, type CodeExecutionRequest, type CodeExecutionResult, CompositeNode, ConditionNode, Conditional, ConfigValidationError, ConfigurationError, CounterAction, type DataRef$1 as DataRef, type DataStore, DecoratorNode, Delay, type DeleteFileRequest, type DeleteFileResult, type DownloadFileRequest, type DownloadFileResult, type ExecutionProgress, ExecutionTracker, FailureNode, Fallback, type FileExistsRequest, type FileExistsResult, ForEach, ForceFailure, ForceSuccess, GenerateFile, type GenerateFileConfig, type GenerateFileRequest, type GenerateFileResult, HttpRequest, type HttpRequestActivity, type HttpRequestConfig, type HttpResponseActivity, type IScopedBlackboard, type ITreeRegistry, type InferSchema, type InjectedObservabilitySinks, IntegrationAction, type IntegrationActionConfig, type IntegrationContext, Invert, KeepRunningUntilFailure, type LoadOptions, type LogEventData, LogMessage, type LogMessageConfig, MemoryDataStore, MemorySequence, MockAction, type NodeConfiguration, type NodeConstructor, type NodeEvent, type NodeEventCallback, NodeEventEmitter, NodeEventType, type NodeMetadata, type NodeState, NodeStatus, type ObservabilitySinks, type ObservableNodeEvent, Parallel, type ParallelStrategy, ParseFile, type ParseFileConfig, type ParseFileRequest, type ParseFileResult, type ParsedPath, type PieceActivityRequest as PieceActionRequest, type PieceActivityRequest, type PieceAuth, type PortDefinition, Precondition, PrintAction, type PutOptions, PythonScript, type PythonScriptConfig, type PythonScriptRequest, type PythonScriptResult, ReactiveSequence, Recovery, RegexExtract, type RegexExtractConfig, Registry, Repeat, type ResolveOptions, ResumePoint, type ResumePointConfig, RunOnce, RunningNode, SchemaRegistry, ScopedBlackboard, Selector, SemanticValidationError, Sequence, SequenceWithMemory, type SinkHandlerConfig, SoftAssert, StructureValidationError, type StructuredError, SubTree, SuccessNode, type TemplateLoaderOptions, type TemporalContext, type TickContext, type TimelineEntry, Timeout, type TokenProvider, type TreeDefinition, type TreeNode, type UploadFileRequest, type UploadFileResult, type ValidatedNodeConfiguration, ValidationError, ValidationErrors, type ValidationOptions, type ValidationResult, type VariableContext, WaitAction, While, type WorkflowArgs, type WorkflowResult, YamlSyntaxError, clearPieceCache, createNodeSchema, createObservabilitySinkHandler, envTokenProvider, executePieceAction, extractVariables, getTemplateIds, hasTemplate, hasVariables, isDataRef, isPieceInstalled, listPieceActions, loadTemplate, loadTemplatesFromDirectory, loadTreeFromFile, loadTreeFromYaml, nodeConfigurationSchema, parseYaml, registerStandardNodes, resolveString, resolveValue, safeValidateConfiguration, schemaRegistry, semanticValidator, toYaml, treeDefinitionSchema, validateChildCount, validateChildCountRange, validateCompositeChildren, validateConfiguration, validateDecoratorChildren, validateTreeDefinition, validateYaml, validations, zodErrorToConfigurationError };
|