@q1k-oss/btree-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/.claude/settings.local.json +31 -0
- package/CLAUDE.md +181 -0
- package/LICENSE +21 -0
- package/README.md +920 -0
- package/behaviour-tree-workflows-landing/index.html +16 -0
- package/behaviour-tree-workflows-landing/package-lock.json +2074 -0
- package/behaviour-tree-workflows-landing/package.json +31 -0
- package/behaviour-tree-workflows-landing/public/favicon.svg +17 -0
- package/behaviour-tree-workflows-landing/src/App.css +103 -0
- package/behaviour-tree-workflows-landing/src/App.tsx +176 -0
- package/behaviour-tree-workflows-landing/src/components/BlackboardInspector.css +89 -0
- package/behaviour-tree-workflows-landing/src/components/BlackboardInspector.tsx +64 -0
- package/behaviour-tree-workflows-landing/src/components/ExampleSelector.css +64 -0
- package/behaviour-tree-workflows-landing/src/components/ExampleSelector.tsx +34 -0
- package/behaviour-tree-workflows-landing/src/components/ExecutionLog.css +107 -0
- package/behaviour-tree-workflows-landing/src/components/ExecutionLog.tsx +85 -0
- package/behaviour-tree-workflows-landing/src/components/Header.css +50 -0
- package/behaviour-tree-workflows-landing/src/components/Header.tsx +26 -0
- package/behaviour-tree-workflows-landing/src/components/StatusBadge.css +45 -0
- package/behaviour-tree-workflows-landing/src/components/StatusBadge.tsx +15 -0
- package/behaviour-tree-workflows-landing/src/components/Toolbar.css +74 -0
- package/behaviour-tree-workflows-landing/src/components/Toolbar.tsx +53 -0
- package/behaviour-tree-workflows-landing/src/components/TreeVisualizer.css +67 -0
- package/behaviour-tree-workflows-landing/src/components/TreeVisualizer.tsx +192 -0
- package/behaviour-tree-workflows-landing/src/components/YamlEditor.css +18 -0
- package/behaviour-tree-workflows-landing/src/components/YamlEditor.tsx +96 -0
- package/behaviour-tree-workflows-landing/src/lib/count-nodes.ts +11 -0
- package/behaviour-tree-workflows-landing/src/lib/execution-engine.ts +96 -0
- package/behaviour-tree-workflows-landing/src/lib/tree-layout.ts +136 -0
- package/behaviour-tree-workflows-landing/src/lib/yaml-examples.ts +549 -0
- package/behaviour-tree-workflows-landing/src/main.tsx +9 -0
- package/behaviour-tree-workflows-landing/src/stubs/activepieces.ts +18 -0
- package/behaviour-tree-workflows-landing/src/stubs/fs.ts +24 -0
- package/behaviour-tree-workflows-landing/src/stubs/path.ts +16 -0
- package/behaviour-tree-workflows-landing/src/stubs/temporal-activity.ts +6 -0
- package/behaviour-tree-workflows-landing/src/stubs/temporal-workflow.ts +22 -0
- package/behaviour-tree-workflows-landing/tsconfig.json +25 -0
- package/behaviour-tree-workflows-landing/vite.config.ts +40 -0
- package/demo-google-sheets.ts +181 -0
- package/demo-runtime-variables.ts +174 -0
- package/demo-template.ts +208 -0
- package/docs/ARCHITECTURE_SUMMARY.md +613 -0
- package/docs/NODE_REFERENCE.md +504 -0
- package/docs/README.md +53 -0
- package/docs/custom-nodes-architecture.md +826 -0
- package/docs/observability.md +175 -0
- package/docs/yaml-specification.md +990 -0
- package/examples/temporal/README.md +117 -0
- package/examples/temporal/activities.ts +373 -0
- package/examples/temporal/client.ts +115 -0
- package/examples/temporal/python-worker/activities.py +339 -0
- package/examples/temporal/python-worker/requirements.txt +12 -0
- package/examples/temporal/python-worker/worker.py +106 -0
- package/examples/temporal/worker.ts +66 -0
- package/examples/temporal/workflows.ts +6 -0
- package/examples/temporal/yaml-workflow-loader.ts +105 -0
- package/examples/yaml-test.ts +97 -0
- package/examples/yaml-workflows/01-simple-sequence.yaml +25 -0
- package/examples/yaml-workflows/02-parallel-timeout.yaml +45 -0
- package/examples/yaml-workflows/03-ecommerce-checkout.yaml +94 -0
- package/examples/yaml-workflows/04-ai-agent-workflow.yaml +346 -0
- package/examples/yaml-workflows/05-order-processing.yaml +146 -0
- package/examples/yaml-workflows/06-activity-test.yaml +71 -0
- package/examples/yaml-workflows/07-activity-simple-test.yaml +43 -0
- package/examples/yaml-workflows/08-file-processing.yaml +141 -0
- package/examples/yaml-workflows/09-http-request.yaml +137 -0
- package/examples/yaml-workflows/README.md +211 -0
- package/package.json +38 -0
- package/src/actions/code-execution.schema.ts +27 -0
- package/src/actions/code-execution.ts +218 -0
- package/src/actions/generate-file.test.ts +516 -0
- package/src/actions/generate-file.ts +166 -0
- package/src/actions/http-request.test.ts +784 -0
- package/src/actions/http-request.ts +228 -0
- package/src/actions/index.ts +20 -0
- package/src/actions/parse-file.test.ts +448 -0
- package/src/actions/parse-file.ts +139 -0
- package/src/actions/python-script.test.ts +439 -0
- package/src/actions/python-script.ts +154 -0
- package/src/base-node.test.ts +511 -0
- package/src/base-node.ts +605 -0
- package/src/behavior-tree.test.ts +431 -0
- package/src/behavior-tree.ts +283 -0
- package/src/blackboard.test.ts +222 -0
- package/src/blackboard.ts +192 -0
- package/src/composites/conditional.schema.ts +19 -0
- package/src/composites/conditional.test.ts +309 -0
- package/src/composites/conditional.ts +129 -0
- package/src/composites/for-each.schema.ts +23 -0
- package/src/composites/for-each.test.ts +254 -0
- package/src/composites/for-each.ts +132 -0
- package/src/composites/index.ts +15 -0
- package/src/composites/memory-sequence.schema.ts +19 -0
- package/src/composites/memory-sequence.test.ts +223 -0
- package/src/composites/memory-sequence.ts +98 -0
- package/src/composites/parallel.schema.ts +28 -0
- package/src/composites/parallel.test.ts +502 -0
- package/src/composites/parallel.ts +157 -0
- package/src/composites/reactive-sequence.schema.ts +19 -0
- package/src/composites/reactive-sequence.test.ts +170 -0
- package/src/composites/reactive-sequence.ts +85 -0
- package/src/composites/recovery.schema.ts +19 -0
- package/src/composites/recovery.test.ts +366 -0
- package/src/composites/recovery.ts +90 -0
- package/src/composites/selector.schema.ts +19 -0
- package/src/composites/selector.test.ts +387 -0
- package/src/composites/selector.ts +85 -0
- package/src/composites/sequence.schema.ts +19 -0
- package/src/composites/sequence.test.ts +337 -0
- package/src/composites/sequence.ts +72 -0
- package/src/composites/sub-tree.schema.ts +21 -0
- package/src/composites/sub-tree.test.ts +893 -0
- package/src/composites/sub-tree.ts +177 -0
- package/src/composites/while.schema.ts +24 -0
- package/src/composites/while.test.ts +381 -0
- package/src/composites/while.ts +149 -0
- package/src/data-store/index.ts +10 -0
- package/src/data-store/memory-store.ts +161 -0
- package/src/data-store/types.ts +94 -0
- package/src/debug/breakpoint.test.ts +47 -0
- package/src/debug/breakpoint.ts +30 -0
- package/src/debug/index.ts +17 -0
- package/src/debug/resume-point.test.ts +49 -0
- package/src/debug/resume-point.ts +29 -0
- package/src/decorators/delay.schema.ts +21 -0
- package/src/decorators/delay.test.ts +261 -0
- package/src/decorators/delay.ts +140 -0
- package/src/decorators/force-result.schema.ts +32 -0
- package/src/decorators/force-result.test.ts +133 -0
- package/src/decorators/force-result.ts +63 -0
- package/src/decorators/index.ts +13 -0
- package/src/decorators/invert.schema.ts +19 -0
- package/src/decorators/invert.test.ts +135 -0
- package/src/decorators/invert.ts +42 -0
- package/src/decorators/keep-running.schema.ts +20 -0
- package/src/decorators/keep-running.test.ts +105 -0
- package/src/decorators/keep-running.ts +49 -0
- package/src/decorators/precondition.schema.ts +19 -0
- package/src/decorators/precondition.test.ts +351 -0
- package/src/decorators/precondition.ts +139 -0
- package/src/decorators/repeat.schema.ts +21 -0
- package/src/decorators/repeat.test.ts +187 -0
- package/src/decorators/repeat.ts +94 -0
- package/src/decorators/run-once.schema.ts +19 -0
- package/src/decorators/run-once.test.ts +140 -0
- package/src/decorators/run-once.ts +61 -0
- package/src/decorators/soft-assert.schema.ts +19 -0
- package/src/decorators/soft-assert.test.ts +107 -0
- package/src/decorators/soft-assert.ts +68 -0
- package/src/decorators/timeout.schema.ts +21 -0
- package/src/decorators/timeout.test.ts +274 -0
- package/src/decorators/timeout.ts +159 -0
- package/src/errors.test.ts +63 -0
- package/src/errors.ts +34 -0
- package/src/events.test.ts +347 -0
- package/src/events.ts +183 -0
- package/src/index.ts +80 -0
- package/src/integrations/index.ts +30 -0
- package/src/integrations/integration-action.test.ts +571 -0
- package/src/integrations/integration-action.ts +233 -0
- package/src/integrations/piece-executor.ts +320 -0
- package/src/observability/execution-tracker.ts +320 -0
- package/src/observability/index.ts +23 -0
- package/src/observability/sinks.ts +138 -0
- package/src/observability/types.ts +130 -0
- package/src/registry-utils.ts +147 -0
- package/src/registry.test.ts +466 -0
- package/src/registry.ts +334 -0
- package/src/schemas/base.schema.ts +104 -0
- package/src/schemas/index.ts +223 -0
- package/src/schemas/integration.test.ts +238 -0
- package/src/schemas/tree-definition.schema.ts +170 -0
- package/src/schemas/validation.test.ts +146 -0
- package/src/schemas/validation.ts +122 -0
- package/src/scripting/index.ts +22 -0
- package/src/templates/template-loader.test.ts +281 -0
- package/src/templates/template-loader.ts +152 -0
- package/src/temporal-integration.test.ts +213 -0
- package/src/test-nodes.ts +259 -0
- package/src/types.ts +503 -0
- package/src/utilities/index.ts +17 -0
- package/src/utilities/log-message.test.ts +275 -0
- package/src/utilities/log-message.ts +134 -0
- package/src/utilities/regex-extract.test.ts +138 -0
- package/src/utilities/regex-extract.ts +108 -0
- package/src/utilities/variable-resolver.test.ts +416 -0
- package/src/utilities/variable-resolver.ts +318 -0
- package/src/utils/error-handler.test.ts +117 -0
- package/src/utils/error-handler.ts +48 -0
- package/src/utils/signal-check.test.ts +234 -0
- package/src/utils/signal-check.ts +140 -0
- package/src/yaml/errors.ts +143 -0
- package/src/yaml/index.ts +30 -0
- package/src/yaml/loader.ts +39 -0
- package/src/yaml/parser.ts +286 -0
- package/src/yaml/validation/semantic-validator.ts +196 -0
- package/templates/google-sheets/insert-row.yaml +76 -0
- package/templates/notification-sender.yaml +33 -0
- package/templates/order-validation.yaml +44 -0
- package/tsconfig.json +24 -0
- package/vitest.config.ts +25 -0
- package/workflows/order-processor.yaml +59 -0
- package/workflows/process-order-workflow.yaml +142 -0
|
@@ -0,0 +1,990 @@
|
|
|
1
|
+
# YAML Workflow Specification
|
|
2
|
+
|
|
3
|
+
This document provides a comprehensive reference for defining behavior tree workflows using YAML in btree.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Overview](#overview)
|
|
8
|
+
2. [Basic Structure](#basic-structure)
|
|
9
|
+
3. [Node Types](#node-types)
|
|
10
|
+
4. [Validation Pipeline](#validation-pipeline)
|
|
11
|
+
5. [Composite Nodes](#composite-nodes)
|
|
12
|
+
6. [Decorator Nodes](#decorator-nodes)
|
|
13
|
+
7. [Action and Condition Nodes](#action-and-condition-nodes)
|
|
14
|
+
8. [Error Handling](#error-handling)
|
|
15
|
+
9. [Migration Guide](#migration-guide)
|
|
16
|
+
|
|
17
|
+
## Overview
|
|
18
|
+
|
|
19
|
+
The YAML workflow format allows you to define behavior trees declaratively, with comprehensive validation ensuring correctness before execution. All workflows undergo a 4-stage validation pipeline:
|
|
20
|
+
|
|
21
|
+
1. **YAML Syntax** - Validates YAML well-formedness
|
|
22
|
+
2. **Tree Structure** - Ensures required fields and correct data types
|
|
23
|
+
3. **Node Configuration** - Validates node-specific properties
|
|
24
|
+
4. **Semantic Rules** - Checks ID uniqueness, child counts, and references
|
|
25
|
+
|
|
26
|
+
## Basic Structure
|
|
27
|
+
|
|
28
|
+
Every workflow starts with a root node definition:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
type: NodeType # Required: The node type (e.g., Sequence, Timeout)
|
|
32
|
+
id: unique-id # Optional: Unique identifier for this node
|
|
33
|
+
name: Display Name # Optional: Human-readable name
|
|
34
|
+
props: # Optional: Node-specific configuration
|
|
35
|
+
key: value
|
|
36
|
+
children: # Optional: Child nodes (for composites/decorators)
|
|
37
|
+
- type: ChildType
|
|
38
|
+
id: child-id
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Minimal Example
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
type: PrintAction
|
|
45
|
+
id: hello-world
|
|
46
|
+
props:
|
|
47
|
+
message: "Hello, World!"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Complete Example
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
type: Sequence
|
|
54
|
+
id: user-onboarding
|
|
55
|
+
name: User Onboarding Flow
|
|
56
|
+
|
|
57
|
+
children:
|
|
58
|
+
- type: PrintAction
|
|
59
|
+
id: welcome-message
|
|
60
|
+
props:
|
|
61
|
+
message: "Welcome to our platform!"
|
|
62
|
+
|
|
63
|
+
- type: Timeout
|
|
64
|
+
id: profile-setup-timeout
|
|
65
|
+
props:
|
|
66
|
+
timeoutMs: 30000
|
|
67
|
+
children:
|
|
68
|
+
- type: Sequence
|
|
69
|
+
id: profile-setup
|
|
70
|
+
children:
|
|
71
|
+
- type: PrintAction
|
|
72
|
+
id: request-info
|
|
73
|
+
props:
|
|
74
|
+
message: "Please complete your profile..."
|
|
75
|
+
|
|
76
|
+
- type: Delay
|
|
77
|
+
id: wait-for-input
|
|
78
|
+
props:
|
|
79
|
+
delayMs: 1000
|
|
80
|
+
children:
|
|
81
|
+
- type: PrintAction
|
|
82
|
+
id: processing
|
|
83
|
+
props:
|
|
84
|
+
message: "Processing..."
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Node Types
|
|
88
|
+
|
|
89
|
+
### Composites
|
|
90
|
+
|
|
91
|
+
Composites execute multiple children according to specific logic:
|
|
92
|
+
|
|
93
|
+
| Node Type | Children | Description |
|
|
94
|
+
|-----------|----------|-------------|
|
|
95
|
+
| `Sequence` | 1+ | Execute children in order until one fails |
|
|
96
|
+
| `Selector` | 1+ | Execute children in order until one succeeds |
|
|
97
|
+
| `Parallel` | 1+ | Execute all children concurrently |
|
|
98
|
+
| `ReactiveSequence` | 1+ | Like Sequence but re-ticks previous children |
|
|
99
|
+
| `MemorySequence` | 1+ | Like Sequence but remembers position |
|
|
100
|
+
| `ForEach` | 1+ | Iterate over collection, executing child for each item |
|
|
101
|
+
| `While` | 2 | Loop while condition succeeds, execute body |
|
|
102
|
+
| `Conditional` | 2-3 | If-then-else logic |
|
|
103
|
+
| `Recovery` | 1+ | Try children in order until one succeeds or all fail |
|
|
104
|
+
| `SubTree` | 0 | Reference another tree by ID |
|
|
105
|
+
|
|
106
|
+
### Decorators
|
|
107
|
+
|
|
108
|
+
Decorators wrap a single child and modify its behavior:
|
|
109
|
+
|
|
110
|
+
| Node Type | Children | Description |
|
|
111
|
+
|-----------|----------|-------------|
|
|
112
|
+
| `Timeout` | 1 | Fail if child exceeds time limit |
|
|
113
|
+
| `Delay` | 1 | Wait before executing child |
|
|
114
|
+
| `Repeat` | 1 | Execute child N times |
|
|
115
|
+
| `Invert` | 1 | Flip success/failure |
|
|
116
|
+
| `ForceSuccess` | 1 | Always return success |
|
|
117
|
+
| `ForceFailure` | 1 | Always return failure |
|
|
118
|
+
| `RunOnce` | 1 | Execute child only once |
|
|
119
|
+
| `KeepRunningUntilFailure` | 1 | Keep returning RUNNING until child fails |
|
|
120
|
+
| `Precondition` | 1 | Check condition before executing child |
|
|
121
|
+
| `SoftAssert` | 1 | Like Precondition but less strict |
|
|
122
|
+
|
|
123
|
+
### Actions and Conditions
|
|
124
|
+
|
|
125
|
+
Custom application-specific nodes defined in your registry.
|
|
126
|
+
|
|
127
|
+
## Validation Pipeline
|
|
128
|
+
|
|
129
|
+
### Stage 1: YAML Syntax Validation
|
|
130
|
+
|
|
131
|
+
Validates that the YAML is well-formed:
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
# Invalid: Missing colon
|
|
135
|
+
type Sequence
|
|
136
|
+
|
|
137
|
+
# Invalid: Incorrect indentation
|
|
138
|
+
type: Sequence
|
|
139
|
+
id: wrong-indent
|
|
140
|
+
|
|
141
|
+
# Valid
|
|
142
|
+
type: Sequence
|
|
143
|
+
id: correct
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Errors:**
|
|
147
|
+
- `YamlSyntaxError` - Malformed YAML, incorrect indentation, invalid characters
|
|
148
|
+
|
|
149
|
+
### Stage 2: Tree Structure Validation
|
|
150
|
+
|
|
151
|
+
Validates required fields and data types:
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
# Invalid: Missing type field
|
|
155
|
+
id: my-node
|
|
156
|
+
children: []
|
|
157
|
+
|
|
158
|
+
# Invalid: children must be an array
|
|
159
|
+
type: Sequence
|
|
160
|
+
children: "not-an-array"
|
|
161
|
+
|
|
162
|
+
# Valid
|
|
163
|
+
type: Sequence
|
|
164
|
+
id: my-sequence
|
|
165
|
+
children:
|
|
166
|
+
- type: PrintAction
|
|
167
|
+
id: action1
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Errors:**
|
|
171
|
+
- `StructureValidationError` - Missing `type` field, incorrect data types, invalid structure
|
|
172
|
+
|
|
173
|
+
### Stage 3: Node Configuration Validation
|
|
174
|
+
|
|
175
|
+
Validates node-specific properties using Zod schemas:
|
|
176
|
+
|
|
177
|
+
```yaml
|
|
178
|
+
# Invalid: Negative timeout
|
|
179
|
+
type: Timeout
|
|
180
|
+
props:
|
|
181
|
+
timeoutMs: -100
|
|
182
|
+
|
|
183
|
+
# Invalid: Missing required property
|
|
184
|
+
type: ForEach
|
|
185
|
+
props:
|
|
186
|
+
itemKey: item
|
|
187
|
+
# Missing collectionKey
|
|
188
|
+
|
|
189
|
+
# Valid
|
|
190
|
+
type: Timeout
|
|
191
|
+
props:
|
|
192
|
+
timeoutMs: 5000
|
|
193
|
+
children:
|
|
194
|
+
- type: PrintAction
|
|
195
|
+
id: action
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Errors:**
|
|
199
|
+
- `ConfigValidationError` - Invalid property values, missing required properties, type mismatches
|
|
200
|
+
|
|
201
|
+
### Stage 4: Semantic Validation
|
|
202
|
+
|
|
203
|
+
Validates semantic rules and relationships:
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
# Invalid: Duplicate IDs
|
|
207
|
+
type: Sequence
|
|
208
|
+
children:
|
|
209
|
+
- type: PrintAction
|
|
210
|
+
id: duplicate
|
|
211
|
+
- type: PrintAction
|
|
212
|
+
id: duplicate # Error: ID already used
|
|
213
|
+
|
|
214
|
+
# Invalid: Decorator must have exactly 1 child
|
|
215
|
+
type: Timeout
|
|
216
|
+
props:
|
|
217
|
+
timeoutMs: 1000
|
|
218
|
+
children:
|
|
219
|
+
- type: PrintAction
|
|
220
|
+
id: action1
|
|
221
|
+
- type: PrintAction
|
|
222
|
+
id: action2 # Error: Timeout requires exactly 1 child
|
|
223
|
+
|
|
224
|
+
# Invalid: Circular SubTree reference
|
|
225
|
+
type: SubTree
|
|
226
|
+
props:
|
|
227
|
+
treeId: my-tree # Error: Cannot reference self or create cycle
|
|
228
|
+
|
|
229
|
+
# Valid
|
|
230
|
+
type: Sequence
|
|
231
|
+
children:
|
|
232
|
+
- type: PrintAction
|
|
233
|
+
id: unique-id-1
|
|
234
|
+
- type: PrintAction
|
|
235
|
+
id: unique-id-2
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Errors:**
|
|
239
|
+
- `SemanticValidationError` - Duplicate IDs, wrong child count, circular references, unregistered node types
|
|
240
|
+
|
|
241
|
+
## Composite Nodes
|
|
242
|
+
|
|
243
|
+
### Sequence
|
|
244
|
+
|
|
245
|
+
Execute children in order until one fails or all succeed.
|
|
246
|
+
|
|
247
|
+
```yaml
|
|
248
|
+
type: Sequence
|
|
249
|
+
id: checkout-flow
|
|
250
|
+
children:
|
|
251
|
+
- type: ValidateCart
|
|
252
|
+
id: validate
|
|
253
|
+
- type: ProcessPayment
|
|
254
|
+
id: payment
|
|
255
|
+
- type: SendConfirmation
|
|
256
|
+
id: confirmation
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Configuration:** Base properties only
|
|
260
|
+
|
|
261
|
+
### Selector
|
|
262
|
+
|
|
263
|
+
Execute children in order until one succeeds or all fail.
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
type: Selector
|
|
267
|
+
id: payment-methods
|
|
268
|
+
children:
|
|
269
|
+
- type: TryCreditCard
|
|
270
|
+
id: credit-card
|
|
271
|
+
- type: TryPayPal
|
|
272
|
+
id: paypal
|
|
273
|
+
- type: TryBankTransfer
|
|
274
|
+
id: bank
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Configuration:** Base properties only
|
|
278
|
+
|
|
279
|
+
### Parallel
|
|
280
|
+
|
|
281
|
+
Execute all children concurrently.
|
|
282
|
+
|
|
283
|
+
```yaml
|
|
284
|
+
type: Parallel
|
|
285
|
+
id: parallel-tasks
|
|
286
|
+
props:
|
|
287
|
+
strategy: "strict" # "strict" | "any"
|
|
288
|
+
successThreshold: 2 # Optional: Number of successes needed
|
|
289
|
+
failureThreshold: 1 # Optional: Number of failures to abort
|
|
290
|
+
children:
|
|
291
|
+
- type: FetchUserData
|
|
292
|
+
id: fetch-user
|
|
293
|
+
- type: FetchProductData
|
|
294
|
+
id: fetch-product
|
|
295
|
+
- type: FetchInventory
|
|
296
|
+
id: fetch-inventory
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Properties:**
|
|
300
|
+
- `strategy` (optional):
|
|
301
|
+
- `"strict"` - All children must succeed (default)
|
|
302
|
+
- `"any"` - At least one child must succeed
|
|
303
|
+
- `successThreshold` (optional): Number of children that must succeed
|
|
304
|
+
- `failureThreshold` (optional): Number of children that can fail before aborting
|
|
305
|
+
|
|
306
|
+
### ForEach
|
|
307
|
+
|
|
308
|
+
Iterate over a collection, executing child for each item.
|
|
309
|
+
|
|
310
|
+
```yaml
|
|
311
|
+
type: ForEach
|
|
312
|
+
id: process-orders
|
|
313
|
+
props:
|
|
314
|
+
collectionKey: "orders" # Required: Blackboard key with array
|
|
315
|
+
itemKey: "currentOrder" # Required: Blackboard key for current item
|
|
316
|
+
indexKey: "orderIndex" # Optional: Blackboard key for index
|
|
317
|
+
children:
|
|
318
|
+
- type: ProcessOrder
|
|
319
|
+
id: process-order
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Properties:**
|
|
323
|
+
- `collectionKey` (required): Blackboard key containing the array to iterate
|
|
324
|
+
- `itemKey` (required): Blackboard key where current item is stored
|
|
325
|
+
- `indexKey` (optional): Blackboard key where current index is stored
|
|
326
|
+
|
|
327
|
+
### While
|
|
328
|
+
|
|
329
|
+
Loop while condition succeeds, executing body.
|
|
330
|
+
|
|
331
|
+
```yaml
|
|
332
|
+
type: While
|
|
333
|
+
id: retry-loop
|
|
334
|
+
props:
|
|
335
|
+
maxIterations: 1000 # Optional: Default 1000, prevents infinite loops
|
|
336
|
+
children:
|
|
337
|
+
- type: HasMoreItems # Condition (child 0)
|
|
338
|
+
id: has-more
|
|
339
|
+
- type: ProcessItem # Body (child 1)
|
|
340
|
+
id: process
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Properties:**
|
|
344
|
+
- `maxIterations` (optional): Maximum loop iterations (default: 1000)
|
|
345
|
+
|
|
346
|
+
**Requirements:**
|
|
347
|
+
- Must have exactly 2 children
|
|
348
|
+
- First child is the condition
|
|
349
|
+
- Second child is the body
|
|
350
|
+
|
|
351
|
+
### Conditional
|
|
352
|
+
|
|
353
|
+
If-then-else logic.
|
|
354
|
+
|
|
355
|
+
```yaml
|
|
356
|
+
type: Conditional
|
|
357
|
+
id: user-check
|
|
358
|
+
children:
|
|
359
|
+
- type: IsUserLoggedIn # Condition (child 0)
|
|
360
|
+
id: check-login
|
|
361
|
+
- type: ShowDashboard # Then branch (child 1)
|
|
362
|
+
id: show-dashboard
|
|
363
|
+
- type: ShowLoginPage # Else branch (child 2, optional)
|
|
364
|
+
id: show-login
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Configuration:** Base properties only
|
|
368
|
+
|
|
369
|
+
**Requirements:**
|
|
370
|
+
- Must have 2-3 children
|
|
371
|
+
- First child is the condition
|
|
372
|
+
- Second child is the "then" branch
|
|
373
|
+
- Third child (optional) is the "else" branch
|
|
374
|
+
|
|
375
|
+
### ReactiveSequence
|
|
376
|
+
|
|
377
|
+
Like Sequence but re-ticks previous children on each tick.
|
|
378
|
+
|
|
379
|
+
```yaml
|
|
380
|
+
type: ReactiveSequence
|
|
381
|
+
id: reactive-flow
|
|
382
|
+
children:
|
|
383
|
+
- type: CheckSensor
|
|
384
|
+
id: sensor-check
|
|
385
|
+
- type: ProcessData
|
|
386
|
+
id: process
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Configuration:** Base properties only
|
|
390
|
+
|
|
391
|
+
### MemorySequence
|
|
392
|
+
|
|
393
|
+
Like Sequence but remembers last executing child.
|
|
394
|
+
|
|
395
|
+
```yaml
|
|
396
|
+
type: MemorySequence
|
|
397
|
+
id: memory-flow
|
|
398
|
+
children:
|
|
399
|
+
- type: Step1
|
|
400
|
+
id: step-1
|
|
401
|
+
- type: Step2
|
|
402
|
+
id: step-2
|
|
403
|
+
- type: Step3
|
|
404
|
+
id: step-3
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Configuration:** Base properties only
|
|
408
|
+
|
|
409
|
+
### Recovery
|
|
410
|
+
|
|
411
|
+
Try children in order until one succeeds or all fail (like Selector but for error recovery).
|
|
412
|
+
|
|
413
|
+
```yaml
|
|
414
|
+
type: Recovery
|
|
415
|
+
id: error-recovery
|
|
416
|
+
children:
|
|
417
|
+
- type: TryPrimaryService
|
|
418
|
+
id: primary
|
|
419
|
+
- type: TryBackupService
|
|
420
|
+
id: backup
|
|
421
|
+
- type: UseCache
|
|
422
|
+
id: cache
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Configuration:** Base properties only
|
|
426
|
+
|
|
427
|
+
### SubTree
|
|
428
|
+
|
|
429
|
+
Reference another tree by ID.
|
|
430
|
+
|
|
431
|
+
```yaml
|
|
432
|
+
type: SubTree
|
|
433
|
+
id: reusable-subtree
|
|
434
|
+
props:
|
|
435
|
+
treeId: "common-validation" # Required: ID of tree to reference
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**Properties:**
|
|
439
|
+
- `treeId` (required): ID of the tree to execute
|
|
440
|
+
|
|
441
|
+
**Note:** Circular references are detected and prevented.
|
|
442
|
+
|
|
443
|
+
## Decorator Nodes
|
|
444
|
+
|
|
445
|
+
All decorators must have exactly 1 child.
|
|
446
|
+
|
|
447
|
+
### Timeout
|
|
448
|
+
|
|
449
|
+
Fail if child exceeds time limit.
|
|
450
|
+
|
|
451
|
+
```yaml
|
|
452
|
+
type: Timeout
|
|
453
|
+
id: api-timeout
|
|
454
|
+
props:
|
|
455
|
+
timeoutMs: 5000 # Required: Timeout in milliseconds (> 0)
|
|
456
|
+
children:
|
|
457
|
+
- type: CallExternalAPI
|
|
458
|
+
id: api-call
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
**Properties:**
|
|
462
|
+
- `timeoutMs` (required): Timeout duration in milliseconds (must be > 0)
|
|
463
|
+
|
|
464
|
+
### Delay
|
|
465
|
+
|
|
466
|
+
Wait before executing child.
|
|
467
|
+
|
|
468
|
+
```yaml
|
|
469
|
+
type: Delay
|
|
470
|
+
id: wait-before-retry
|
|
471
|
+
props:
|
|
472
|
+
delayMs: 1000 # Required: Delay in milliseconds (>= 0)
|
|
473
|
+
children:
|
|
474
|
+
- type: RetryOperation
|
|
475
|
+
id: retry
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
**Properties:**
|
|
479
|
+
- `delayMs` (required): Delay duration in milliseconds (must be >= 0)
|
|
480
|
+
|
|
481
|
+
### Repeat
|
|
482
|
+
|
|
483
|
+
Execute child N times.
|
|
484
|
+
|
|
485
|
+
```yaml
|
|
486
|
+
type: Repeat
|
|
487
|
+
id: retry-three-times
|
|
488
|
+
props:
|
|
489
|
+
numCycles: 3 # Required: Number of times to repeat (> 0, integer)
|
|
490
|
+
children:
|
|
491
|
+
- type: AttemptConnection
|
|
492
|
+
id: connect
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
**Properties:**
|
|
496
|
+
- `numCycles` (required): Number of repetitions (must be > 0 and an integer)
|
|
497
|
+
|
|
498
|
+
### Invert
|
|
499
|
+
|
|
500
|
+
Flip success/failure status of child.
|
|
501
|
+
|
|
502
|
+
```yaml
|
|
503
|
+
type: Invert
|
|
504
|
+
id: invert-result
|
|
505
|
+
children:
|
|
506
|
+
- type: CheckCondition
|
|
507
|
+
id: condition
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Configuration:** Base properties only
|
|
511
|
+
|
|
512
|
+
### ForceSuccess
|
|
513
|
+
|
|
514
|
+
Always return success regardless of child result.
|
|
515
|
+
|
|
516
|
+
```yaml
|
|
517
|
+
type: ForceSuccess
|
|
518
|
+
id: optional-step
|
|
519
|
+
children:
|
|
520
|
+
- type: OptionalOperation
|
|
521
|
+
id: operation
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
**Configuration:** Base properties only
|
|
525
|
+
|
|
526
|
+
### ForceFailure
|
|
527
|
+
|
|
528
|
+
Always return failure regardless of child result.
|
|
529
|
+
|
|
530
|
+
```yaml
|
|
531
|
+
type: ForceFailure
|
|
532
|
+
id: force-fail
|
|
533
|
+
children:
|
|
534
|
+
- type: SomeOperation
|
|
535
|
+
id: operation
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
**Configuration:** Base properties only
|
|
539
|
+
|
|
540
|
+
### RunOnce
|
|
541
|
+
|
|
542
|
+
Execute child only once, then always return success.
|
|
543
|
+
|
|
544
|
+
```yaml
|
|
545
|
+
type: RunOnce
|
|
546
|
+
id: initialize-once
|
|
547
|
+
children:
|
|
548
|
+
- type: InitializeSystem
|
|
549
|
+
id: init
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
**Configuration:** Base properties only
|
|
553
|
+
|
|
554
|
+
### KeepRunningUntilFailure
|
|
555
|
+
|
|
556
|
+
Keep returning RUNNING until child fails.
|
|
557
|
+
|
|
558
|
+
```yaml
|
|
559
|
+
type: KeepRunningUntilFailure
|
|
560
|
+
id: keep-running
|
|
561
|
+
children:
|
|
562
|
+
- type: MonitorProcess
|
|
563
|
+
id: monitor
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Configuration:** Base properties only
|
|
567
|
+
|
|
568
|
+
### Precondition
|
|
569
|
+
|
|
570
|
+
Check condition before executing child. Fail if condition fails.
|
|
571
|
+
|
|
572
|
+
```yaml
|
|
573
|
+
type: Precondition
|
|
574
|
+
id: check-prerequisites
|
|
575
|
+
children:
|
|
576
|
+
- type: CheckUserPermissions
|
|
577
|
+
id: check-perms
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Configuration:** Base properties only
|
|
581
|
+
|
|
582
|
+
### SoftAssert
|
|
583
|
+
|
|
584
|
+
Like Precondition but less strict.
|
|
585
|
+
|
|
586
|
+
```yaml
|
|
587
|
+
type: SoftAssert
|
|
588
|
+
id: soft-check
|
|
589
|
+
children:
|
|
590
|
+
- type: OptionalCheck
|
|
591
|
+
id: check
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
**Configuration:** Base properties only
|
|
595
|
+
|
|
596
|
+
## Action and Condition Nodes
|
|
597
|
+
|
|
598
|
+
Action and condition nodes are application-specific and must be registered in your Registry before loading YAML workflows.
|
|
599
|
+
|
|
600
|
+
```yaml
|
|
601
|
+
# Custom action node
|
|
602
|
+
type: SendEmail
|
|
603
|
+
id: send-notification
|
|
604
|
+
props:
|
|
605
|
+
recipient: "user@example.com"
|
|
606
|
+
subject: "Welcome!"
|
|
607
|
+
template: "welcome-email"
|
|
608
|
+
|
|
609
|
+
# Custom condition node
|
|
610
|
+
type: IsUserPremium
|
|
611
|
+
id: check-premium
|
|
612
|
+
props:
|
|
613
|
+
userId: "{{userId}}"
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
**Requirements:**
|
|
617
|
+
- Node type must be registered in Registry
|
|
618
|
+
- Properties validated against node's schema (if defined)
|
|
619
|
+
- Can use blackboard variable interpolation (e.g., `"{{variableName}}"`)
|
|
620
|
+
|
|
621
|
+
## Error Handling
|
|
622
|
+
|
|
623
|
+
### Error Types
|
|
624
|
+
|
|
625
|
+
| Error Type | Stage | Description |
|
|
626
|
+
|------------|-------|-------------|
|
|
627
|
+
| `YamlSyntaxError` | 1 | YAML parsing failed |
|
|
628
|
+
| `StructureValidationError` | 2 | Invalid tree structure |
|
|
629
|
+
| `ConfigValidationError` | 3 | Invalid node configuration |
|
|
630
|
+
| `SemanticValidationError` | 4 | Semantic rule violation |
|
|
631
|
+
|
|
632
|
+
### Error Format
|
|
633
|
+
|
|
634
|
+
All validation errors include:
|
|
635
|
+
- **Message**: Description of the error
|
|
636
|
+
- **Path**: Location in the tree (e.g., `root.children[2].props.timeoutMs`)
|
|
637
|
+
- **Suggestion**: How to fix the error
|
|
638
|
+
|
|
639
|
+
Example error:
|
|
640
|
+
|
|
641
|
+
```
|
|
642
|
+
SemanticValidationError: Duplicate node ID 'process-payment'
|
|
643
|
+
Path: root.children[3].id
|
|
644
|
+
Previous occurrence: root.children[1].id
|
|
645
|
+
Suggestion: Use unique IDs for each node in the tree
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### Common Errors
|
|
649
|
+
|
|
650
|
+
#### Duplicate IDs
|
|
651
|
+
|
|
652
|
+
```yaml
|
|
653
|
+
# Error: Duplicate IDs
|
|
654
|
+
type: Sequence
|
|
655
|
+
children:
|
|
656
|
+
- type: PrintAction
|
|
657
|
+
id: my-action
|
|
658
|
+
- type: PrintAction
|
|
659
|
+
id: my-action # Error!
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
**Fix:** Use unique IDs for each node.
|
|
663
|
+
|
|
664
|
+
#### Wrong Child Count
|
|
665
|
+
|
|
666
|
+
```yaml
|
|
667
|
+
# Error: Decorator with multiple children
|
|
668
|
+
type: Timeout
|
|
669
|
+
props:
|
|
670
|
+
timeoutMs: 1000
|
|
671
|
+
children:
|
|
672
|
+
- type: Action1
|
|
673
|
+
id: a1
|
|
674
|
+
- type: Action2
|
|
675
|
+
id: a2 # Error: Timeout requires exactly 1 child
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
**Fix:** Decorators must have exactly 1 child. Wrap multiple children in a Sequence.
|
|
679
|
+
|
|
680
|
+
```yaml
|
|
681
|
+
# Fixed
|
|
682
|
+
type: Timeout
|
|
683
|
+
props:
|
|
684
|
+
timeoutMs: 1000
|
|
685
|
+
children:
|
|
686
|
+
- type: Sequence
|
|
687
|
+
id: actions
|
|
688
|
+
children:
|
|
689
|
+
- type: Action1
|
|
690
|
+
id: a1
|
|
691
|
+
- type: Action2
|
|
692
|
+
id: a2
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
#### Invalid Property Values
|
|
696
|
+
|
|
697
|
+
```yaml
|
|
698
|
+
# Error: Negative timeout
|
|
699
|
+
type: Timeout
|
|
700
|
+
props:
|
|
701
|
+
timeoutMs: -100 # Error: Must be > 0
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
**Fix:** Use valid values per node schema.
|
|
705
|
+
|
|
706
|
+
```yaml
|
|
707
|
+
# Fixed
|
|
708
|
+
type: Timeout
|
|
709
|
+
props:
|
|
710
|
+
timeoutMs: 5000
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
#### Missing Required Properties
|
|
714
|
+
|
|
715
|
+
```yaml
|
|
716
|
+
# Error: Missing required property
|
|
717
|
+
type: ForEach
|
|
718
|
+
props:
|
|
719
|
+
itemKey: "item"
|
|
720
|
+
# Missing collectionKey!
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
**Fix:** Include all required properties.
|
|
724
|
+
|
|
725
|
+
```yaml
|
|
726
|
+
# Fixed
|
|
727
|
+
type: ForEach
|
|
728
|
+
props:
|
|
729
|
+
collectionKey: "items"
|
|
730
|
+
itemKey: "item"
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
## Migration Guide
|
|
734
|
+
|
|
735
|
+
### From Programmatic API to YAML
|
|
736
|
+
|
|
737
|
+
**Before (TypeScript):**
|
|
738
|
+
|
|
739
|
+
```typescript
|
|
740
|
+
const tree = new Sequence({ id: "checkout" }, [
|
|
741
|
+
new Timeout({ id: "payment-timeout", timeoutMs: 30000 }, [
|
|
742
|
+
new ProcessPayment({ id: "payment" })
|
|
743
|
+
]),
|
|
744
|
+
new SendConfirmation({ id: "confirmation" })
|
|
745
|
+
]);
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
**After (YAML):**
|
|
749
|
+
|
|
750
|
+
```yaml
|
|
751
|
+
type: Sequence
|
|
752
|
+
id: checkout
|
|
753
|
+
children:
|
|
754
|
+
- type: Timeout
|
|
755
|
+
id: payment-timeout
|
|
756
|
+
props:
|
|
757
|
+
timeoutMs: 30000
|
|
758
|
+
children:
|
|
759
|
+
- type: ProcessPayment
|
|
760
|
+
id: payment
|
|
761
|
+
|
|
762
|
+
- type: SendConfirmation
|
|
763
|
+
id: confirmation
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
### Loading YAML Workflows
|
|
767
|
+
|
|
768
|
+
```typescript
|
|
769
|
+
import {
|
|
770
|
+
Registry,
|
|
771
|
+
registerStandardNodes,
|
|
772
|
+
loadTreeFromYaml,
|
|
773
|
+
loadTreeFromFile
|
|
774
|
+
} from '@wayfarer-ai/btree';
|
|
775
|
+
|
|
776
|
+
// Setup registry with all 32 built-in nodes
|
|
777
|
+
const registry = new Registry();
|
|
778
|
+
registerStandardNodes(registry); // One line instead of 32!
|
|
779
|
+
|
|
780
|
+
// Register your custom nodes
|
|
781
|
+
registry.register('ProcessPayment', ProcessPayment, { category: 'action' });
|
|
782
|
+
registry.register('SendConfirmation', SendConfirmation, { category: 'action' });
|
|
783
|
+
|
|
784
|
+
// Load from string
|
|
785
|
+
const yamlString = `
|
|
786
|
+
type: Sequence
|
|
787
|
+
id: checkout
|
|
788
|
+
children:
|
|
789
|
+
- type: ProcessPayment
|
|
790
|
+
id: payment
|
|
791
|
+
`;
|
|
792
|
+
|
|
793
|
+
const tree = loadTreeFromYaml(yamlString, registry);
|
|
794
|
+
|
|
795
|
+
// Load from file
|
|
796
|
+
const tree = await loadTreeFromFile('./workflows/checkout.yaml', registry);
|
|
797
|
+
|
|
798
|
+
// Execute
|
|
799
|
+
const result = await tree.execute();
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
**Built-in nodes** automatically registered by `registerStandardNodes()`:
|
|
803
|
+
- **10 Composites**: Sequence, Selector, Parallel, ForEach, While, Conditional, ReactiveSequence, MemorySequence, Recovery, SubTree
|
|
804
|
+
- **10 Decorators**: Timeout, Delay, Repeat, Invert, ForceSuccess, ForceFailure, RunOnce, KeepRunningUntilFailure, Precondition, SoftAssert
|
|
805
|
+
- **9 Actions/Conditions**: PrintAction, MockAction, CounterAction, CheckCondition, AlwaysCondition, WaitAction, Script, LogMessage, RegexExtract
|
|
806
|
+
- **3 Test Nodes**: SuccessNode, FailureNode, RunningNode
|
|
807
|
+
|
|
808
|
+
### Validation Without Execution
|
|
809
|
+
|
|
810
|
+
```typescript
|
|
811
|
+
import { validateYaml } from 'btree';
|
|
812
|
+
|
|
813
|
+
const result = validateYaml(yamlString, registry);
|
|
814
|
+
|
|
815
|
+
if (!result.valid) {
|
|
816
|
+
console.error('Validation errors:');
|
|
817
|
+
result.errors.forEach(error => {
|
|
818
|
+
console.error(error.format());
|
|
819
|
+
});
|
|
820
|
+
} else {
|
|
821
|
+
console.log('Workflow is valid!');
|
|
822
|
+
}
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
### Loading Options
|
|
826
|
+
|
|
827
|
+
```typescript
|
|
828
|
+
import { loadTreeFromYaml } from 'btree';
|
|
829
|
+
|
|
830
|
+
const tree = loadTreeFromYaml(yamlString, registry, {
|
|
831
|
+
validate: true, // Enable validation (default: true)
|
|
832
|
+
failFast: false, // Collect all errors (default: true)
|
|
833
|
+
autoGenerateIds: true // Auto-generate missing IDs (default: true)
|
|
834
|
+
});
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### Validation Options
|
|
838
|
+
|
|
839
|
+
```typescript
|
|
840
|
+
import { validateYaml } from 'btree';
|
|
841
|
+
|
|
842
|
+
const result = validateYaml(yamlString, registry, {
|
|
843
|
+
collectAllErrors: true, // Collect all errors (default: false)
|
|
844
|
+
checkReferences: true // Check semantic rules (default: true)
|
|
845
|
+
});
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
## Best Practices
|
|
849
|
+
|
|
850
|
+
### 1. Always Provide IDs
|
|
851
|
+
|
|
852
|
+
While IDs can be auto-generated, explicit IDs make debugging easier:
|
|
853
|
+
|
|
854
|
+
```yaml
|
|
855
|
+
# Good
|
|
856
|
+
type: Sequence
|
|
857
|
+
id: user-registration
|
|
858
|
+
children:
|
|
859
|
+
- type: ValidateEmail
|
|
860
|
+
id: validate-email
|
|
861
|
+
- type: CreateAccount
|
|
862
|
+
id: create-account
|
|
863
|
+
|
|
864
|
+
# Avoid (auto-generated IDs are hard to track)
|
|
865
|
+
type: Sequence
|
|
866
|
+
children:
|
|
867
|
+
- type: ValidateEmail
|
|
868
|
+
- type: CreateAccount
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
### 2. Use Descriptive Names
|
|
872
|
+
|
|
873
|
+
Add names for better readability:
|
|
874
|
+
|
|
875
|
+
```yaml
|
|
876
|
+
type: Sequence
|
|
877
|
+
id: checkout-flow
|
|
878
|
+
name: E-commerce Checkout Flow
|
|
879
|
+
children:
|
|
880
|
+
- type: ValidateCart
|
|
881
|
+
id: validate-cart
|
|
882
|
+
name: Validate Shopping Cart
|
|
883
|
+
|
|
884
|
+
- type: ProcessPayment
|
|
885
|
+
id: process-payment
|
|
886
|
+
name: Process Customer Payment
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
### 3. Validate Before Deployment
|
|
890
|
+
|
|
891
|
+
Always validate workflows before deploying to production:
|
|
892
|
+
|
|
893
|
+
```typescript
|
|
894
|
+
const result = validateYaml(workflowYaml, registry);
|
|
895
|
+
if (!result.valid) {
|
|
896
|
+
throw new Error('Invalid workflow');
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
### 4. Use SubTrees for Reusability
|
|
901
|
+
|
|
902
|
+
Extract common patterns into reusable subtrees:
|
|
903
|
+
|
|
904
|
+
```yaml
|
|
905
|
+
# common-validation.yaml
|
|
906
|
+
type: Sequence
|
|
907
|
+
id: common-validation
|
|
908
|
+
children:
|
|
909
|
+
- type: CheckAuth
|
|
910
|
+
id: check-auth
|
|
911
|
+
- type: ValidateInput
|
|
912
|
+
id: validate-input
|
|
913
|
+
|
|
914
|
+
# main-workflow.yaml
|
|
915
|
+
type: Sequence
|
|
916
|
+
id: api-endpoint
|
|
917
|
+
children:
|
|
918
|
+
- type: SubTree
|
|
919
|
+
id: validation
|
|
920
|
+
props:
|
|
921
|
+
treeId: "common-validation"
|
|
922
|
+
|
|
923
|
+
- type: ProcessRequest
|
|
924
|
+
id: process
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
### 5. Handle Timeouts Explicitly
|
|
928
|
+
|
|
929
|
+
Always set realistic timeouts for external operations:
|
|
930
|
+
|
|
931
|
+
```yaml
|
|
932
|
+
type: Timeout
|
|
933
|
+
id: api-timeout
|
|
934
|
+
props:
|
|
935
|
+
timeoutMs: 5000 # 5 seconds for API call
|
|
936
|
+
children:
|
|
937
|
+
- type: CallExternalAPI
|
|
938
|
+
id: api-call
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
### 6. Use Recovery for Fallbacks
|
|
942
|
+
|
|
943
|
+
Implement graceful degradation with Recovery nodes:
|
|
944
|
+
|
|
945
|
+
```yaml
|
|
946
|
+
type: Recovery
|
|
947
|
+
id: data-source
|
|
948
|
+
children:
|
|
949
|
+
- type: FetchFromDatabase
|
|
950
|
+
id: db-fetch
|
|
951
|
+
|
|
952
|
+
- type: FetchFromCache
|
|
953
|
+
id: cache-fetch
|
|
954
|
+
|
|
955
|
+
- type: UseDefaultData
|
|
956
|
+
id: default-data
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
## Examples
|
|
960
|
+
|
|
961
|
+
See the `examples/yaml-workflows/` directory for complete examples:
|
|
962
|
+
|
|
963
|
+
**Working Examples** (tested with Temporal):
|
|
964
|
+
- `01-simple-sequence.yaml` - Basic sequential workflow with 3 print actions
|
|
965
|
+
- `02-parallel-timeout.yaml` - Parallel task execution with timeout protection
|
|
966
|
+
- `05-order-processing.yaml` - Complex e-commerce order processing (20+ nodes, 5 levels deep)
|
|
967
|
+
|
|
968
|
+
**Reference Examples** (showcase advanced patterns):
|
|
969
|
+
- `03-ecommerce-checkout.yaml` - Multi-phase checkout with conditional logic
|
|
970
|
+
- `04-ai-agent-workflow.yaml` - AI agent with decision trees and iterative processing
|
|
971
|
+
|
|
972
|
+
To run the working examples:
|
|
973
|
+
```bash
|
|
974
|
+
# Terminal 1: Start Temporal server
|
|
975
|
+
temporal server start-dev
|
|
976
|
+
|
|
977
|
+
# Terminal 2: Start worker
|
|
978
|
+
cd examples/temporal
|
|
979
|
+
npx tsx worker.ts
|
|
980
|
+
|
|
981
|
+
# Terminal 3: Execute workflows
|
|
982
|
+
npx tsx client.ts
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
## Further Reading
|
|
986
|
+
|
|
987
|
+
- [Core Concepts](./workflow-engine/01-core-concepts.md) - Behavior tree fundamentals
|
|
988
|
+
- [Node Reference](./workflow-engine/02-node-reference.md) - Complete node documentation
|
|
989
|
+
- [Schema Documentation](../src/schemas/README.md) - Zod schema reference
|
|
990
|
+
- [Registry Guide](./workflow-engine/03-registry.md) - Node registration and tree creation
|