@q1k-oss/btree-workflows 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/README.md +13 -13
  2. package/dist/index.cjs +5011 -0
  3. package/dist/index.d.cts +3320 -0
  4. package/dist/index.d.ts +3320 -0
  5. package/dist/index.js +4879 -0
  6. package/package.json +33 -3
  7. package/.claude/settings.local.json +0 -31
  8. package/CLAUDE.md +0 -181
  9. package/behaviour-tree-workflows-landing/index.html +0 -16
  10. package/behaviour-tree-workflows-landing/package-lock.json +0 -2074
  11. package/behaviour-tree-workflows-landing/package.json +0 -31
  12. package/behaviour-tree-workflows-landing/public/favicon.svg +0 -17
  13. package/behaviour-tree-workflows-landing/src/App.css +0 -103
  14. package/behaviour-tree-workflows-landing/src/App.tsx +0 -176
  15. package/behaviour-tree-workflows-landing/src/components/BlackboardInspector.css +0 -89
  16. package/behaviour-tree-workflows-landing/src/components/BlackboardInspector.tsx +0 -64
  17. package/behaviour-tree-workflows-landing/src/components/ExampleSelector.css +0 -64
  18. package/behaviour-tree-workflows-landing/src/components/ExampleSelector.tsx +0 -34
  19. package/behaviour-tree-workflows-landing/src/components/ExecutionLog.css +0 -107
  20. package/behaviour-tree-workflows-landing/src/components/ExecutionLog.tsx +0 -85
  21. package/behaviour-tree-workflows-landing/src/components/Header.css +0 -50
  22. package/behaviour-tree-workflows-landing/src/components/Header.tsx +0 -26
  23. package/behaviour-tree-workflows-landing/src/components/StatusBadge.css +0 -45
  24. package/behaviour-tree-workflows-landing/src/components/StatusBadge.tsx +0 -15
  25. package/behaviour-tree-workflows-landing/src/components/Toolbar.css +0 -74
  26. package/behaviour-tree-workflows-landing/src/components/Toolbar.tsx +0 -53
  27. package/behaviour-tree-workflows-landing/src/components/TreeVisualizer.css +0 -67
  28. package/behaviour-tree-workflows-landing/src/components/TreeVisualizer.tsx +0 -192
  29. package/behaviour-tree-workflows-landing/src/components/YamlEditor.css +0 -18
  30. package/behaviour-tree-workflows-landing/src/components/YamlEditor.tsx +0 -96
  31. package/behaviour-tree-workflows-landing/src/lib/count-nodes.ts +0 -11
  32. package/behaviour-tree-workflows-landing/src/lib/execution-engine.ts +0 -96
  33. package/behaviour-tree-workflows-landing/src/lib/tree-layout.ts +0 -136
  34. package/behaviour-tree-workflows-landing/src/lib/yaml-examples.ts +0 -549
  35. package/behaviour-tree-workflows-landing/src/main.tsx +0 -9
  36. package/behaviour-tree-workflows-landing/src/stubs/activepieces.ts +0 -18
  37. package/behaviour-tree-workflows-landing/src/stubs/fs.ts +0 -24
  38. package/behaviour-tree-workflows-landing/src/stubs/path.ts +0 -16
  39. package/behaviour-tree-workflows-landing/src/stubs/temporal-activity.ts +0 -6
  40. package/behaviour-tree-workflows-landing/src/stubs/temporal-workflow.ts +0 -22
  41. package/behaviour-tree-workflows-landing/tsconfig.json +0 -25
  42. package/behaviour-tree-workflows-landing/vite.config.ts +0 -40
  43. package/demo-google-sheets.ts +0 -181
  44. package/demo-runtime-variables.ts +0 -174
  45. package/demo-template.ts +0 -208
  46. package/docs/ARCHITECTURE_SUMMARY.md +0 -613
  47. package/docs/NODE_REFERENCE.md +0 -504
  48. package/docs/README.md +0 -53
  49. package/docs/custom-nodes-architecture.md +0 -826
  50. package/docs/observability.md +0 -175
  51. package/docs/yaml-specification.md +0 -990
  52. package/examples/temporal/README.md +0 -117
  53. package/examples/temporal/activities.ts +0 -373
  54. package/examples/temporal/client.ts +0 -115
  55. package/examples/temporal/python-worker/activities.py +0 -339
  56. package/examples/temporal/python-worker/requirements.txt +0 -12
  57. package/examples/temporal/python-worker/worker.py +0 -106
  58. package/examples/temporal/worker.ts +0 -66
  59. package/examples/temporal/workflows.ts +0 -6
  60. package/examples/temporal/yaml-workflow-loader.ts +0 -105
  61. package/examples/yaml-test.ts +0 -97
  62. package/examples/yaml-workflows/01-simple-sequence.yaml +0 -25
  63. package/examples/yaml-workflows/02-parallel-timeout.yaml +0 -45
  64. package/examples/yaml-workflows/03-ecommerce-checkout.yaml +0 -94
  65. package/examples/yaml-workflows/04-ai-agent-workflow.yaml +0 -346
  66. package/examples/yaml-workflows/05-order-processing.yaml +0 -146
  67. package/examples/yaml-workflows/06-activity-test.yaml +0 -71
  68. package/examples/yaml-workflows/07-activity-simple-test.yaml +0 -43
  69. package/examples/yaml-workflows/08-file-processing.yaml +0 -141
  70. package/examples/yaml-workflows/09-http-request.yaml +0 -137
  71. package/examples/yaml-workflows/README.md +0 -211
  72. package/src/actions/code-execution.schema.ts +0 -27
  73. package/src/actions/code-execution.ts +0 -218
  74. package/src/actions/generate-file.test.ts +0 -516
  75. package/src/actions/generate-file.ts +0 -166
  76. package/src/actions/http-request.test.ts +0 -784
  77. package/src/actions/http-request.ts +0 -228
  78. package/src/actions/index.ts +0 -20
  79. package/src/actions/parse-file.test.ts +0 -448
  80. package/src/actions/parse-file.ts +0 -139
  81. package/src/actions/python-script.test.ts +0 -439
  82. package/src/actions/python-script.ts +0 -154
  83. package/src/base-node.test.ts +0 -511
  84. package/src/base-node.ts +0 -605
  85. package/src/behavior-tree.test.ts +0 -431
  86. package/src/behavior-tree.ts +0 -283
  87. package/src/blackboard.test.ts +0 -222
  88. package/src/blackboard.ts +0 -192
  89. package/src/composites/conditional.schema.ts +0 -19
  90. package/src/composites/conditional.test.ts +0 -309
  91. package/src/composites/conditional.ts +0 -129
  92. package/src/composites/for-each.schema.ts +0 -23
  93. package/src/composites/for-each.test.ts +0 -254
  94. package/src/composites/for-each.ts +0 -132
  95. package/src/composites/index.ts +0 -15
  96. package/src/composites/memory-sequence.schema.ts +0 -19
  97. package/src/composites/memory-sequence.test.ts +0 -223
  98. package/src/composites/memory-sequence.ts +0 -98
  99. package/src/composites/parallel.schema.ts +0 -28
  100. package/src/composites/parallel.test.ts +0 -502
  101. package/src/composites/parallel.ts +0 -157
  102. package/src/composites/reactive-sequence.schema.ts +0 -19
  103. package/src/composites/reactive-sequence.test.ts +0 -170
  104. package/src/composites/reactive-sequence.ts +0 -85
  105. package/src/composites/recovery.schema.ts +0 -19
  106. package/src/composites/recovery.test.ts +0 -366
  107. package/src/composites/recovery.ts +0 -90
  108. package/src/composites/selector.schema.ts +0 -19
  109. package/src/composites/selector.test.ts +0 -387
  110. package/src/composites/selector.ts +0 -85
  111. package/src/composites/sequence.schema.ts +0 -19
  112. package/src/composites/sequence.test.ts +0 -337
  113. package/src/composites/sequence.ts +0 -72
  114. package/src/composites/sub-tree.schema.ts +0 -21
  115. package/src/composites/sub-tree.test.ts +0 -893
  116. package/src/composites/sub-tree.ts +0 -177
  117. package/src/composites/while.schema.ts +0 -24
  118. package/src/composites/while.test.ts +0 -381
  119. package/src/composites/while.ts +0 -149
  120. package/src/data-store/index.ts +0 -10
  121. package/src/data-store/memory-store.ts +0 -161
  122. package/src/data-store/types.ts +0 -94
  123. package/src/debug/breakpoint.test.ts +0 -47
  124. package/src/debug/breakpoint.ts +0 -30
  125. package/src/debug/index.ts +0 -17
  126. package/src/debug/resume-point.test.ts +0 -49
  127. package/src/debug/resume-point.ts +0 -29
  128. package/src/decorators/delay.schema.ts +0 -21
  129. package/src/decorators/delay.test.ts +0 -261
  130. package/src/decorators/delay.ts +0 -140
  131. package/src/decorators/force-result.schema.ts +0 -32
  132. package/src/decorators/force-result.test.ts +0 -133
  133. package/src/decorators/force-result.ts +0 -63
  134. package/src/decorators/index.ts +0 -13
  135. package/src/decorators/invert.schema.ts +0 -19
  136. package/src/decorators/invert.test.ts +0 -135
  137. package/src/decorators/invert.ts +0 -42
  138. package/src/decorators/keep-running.schema.ts +0 -20
  139. package/src/decorators/keep-running.test.ts +0 -105
  140. package/src/decorators/keep-running.ts +0 -49
  141. package/src/decorators/precondition.schema.ts +0 -19
  142. package/src/decorators/precondition.test.ts +0 -351
  143. package/src/decorators/precondition.ts +0 -139
  144. package/src/decorators/repeat.schema.ts +0 -21
  145. package/src/decorators/repeat.test.ts +0 -187
  146. package/src/decorators/repeat.ts +0 -94
  147. package/src/decorators/run-once.schema.ts +0 -19
  148. package/src/decorators/run-once.test.ts +0 -140
  149. package/src/decorators/run-once.ts +0 -61
  150. package/src/decorators/soft-assert.schema.ts +0 -19
  151. package/src/decorators/soft-assert.test.ts +0 -107
  152. package/src/decorators/soft-assert.ts +0 -68
  153. package/src/decorators/timeout.schema.ts +0 -21
  154. package/src/decorators/timeout.test.ts +0 -274
  155. package/src/decorators/timeout.ts +0 -159
  156. package/src/errors.test.ts +0 -63
  157. package/src/errors.ts +0 -34
  158. package/src/events.test.ts +0 -347
  159. package/src/events.ts +0 -183
  160. package/src/index.ts +0 -80
  161. package/src/integrations/index.ts +0 -30
  162. package/src/integrations/integration-action.test.ts +0 -571
  163. package/src/integrations/integration-action.ts +0 -233
  164. package/src/integrations/piece-executor.ts +0 -320
  165. package/src/observability/execution-tracker.ts +0 -320
  166. package/src/observability/index.ts +0 -23
  167. package/src/observability/sinks.ts +0 -138
  168. package/src/observability/types.ts +0 -130
  169. package/src/registry-utils.ts +0 -147
  170. package/src/registry.test.ts +0 -466
  171. package/src/registry.ts +0 -334
  172. package/src/schemas/base.schema.ts +0 -104
  173. package/src/schemas/index.ts +0 -223
  174. package/src/schemas/integration.test.ts +0 -238
  175. package/src/schemas/tree-definition.schema.ts +0 -170
  176. package/src/schemas/validation.test.ts +0 -146
  177. package/src/schemas/validation.ts +0 -122
  178. package/src/scripting/index.ts +0 -22
  179. package/src/templates/template-loader.test.ts +0 -281
  180. package/src/templates/template-loader.ts +0 -152
  181. package/src/temporal-integration.test.ts +0 -213
  182. package/src/test-nodes.ts +0 -259
  183. package/src/types.ts +0 -503
  184. package/src/utilities/index.ts +0 -17
  185. package/src/utilities/log-message.test.ts +0 -275
  186. package/src/utilities/log-message.ts +0 -134
  187. package/src/utilities/regex-extract.test.ts +0 -138
  188. package/src/utilities/regex-extract.ts +0 -108
  189. package/src/utilities/variable-resolver.test.ts +0 -416
  190. package/src/utilities/variable-resolver.ts +0 -318
  191. package/src/utils/error-handler.test.ts +0 -117
  192. package/src/utils/error-handler.ts +0 -48
  193. package/src/utils/signal-check.test.ts +0 -234
  194. package/src/utils/signal-check.ts +0 -140
  195. package/src/yaml/errors.ts +0 -143
  196. package/src/yaml/index.ts +0 -30
  197. package/src/yaml/loader.ts +0 -39
  198. package/src/yaml/parser.ts +0 -286
  199. package/src/yaml/validation/semantic-validator.ts +0 -196
  200. package/templates/google-sheets/insert-row.yaml +0 -76
  201. package/templates/notification-sender.yaml +0 -33
  202. package/templates/order-validation.yaml +0 -44
  203. package/tsconfig.json +0 -24
  204. package/vitest.config.ts +0 -25
  205. package/workflows/order-processor.yaml +0 -59
  206. package/workflows/process-order-workflow.yaml +0 -142
@@ -1,387 +0,0 @@
1
- import { beforeEach, describe, expect, it } from "vitest";
2
- import { ActionNode } from "../base-node.js";
3
- import { ScopedBlackboard } from "../blackboard.js";
4
- import { ConfigurationError } from "../errors.js";
5
- import { MockAction } from "../test-nodes.js";
6
- import { type TemporalContext, NodeStatus } from "../types.js";
7
- import { checkSignal } from "../utils/signal-check.js";
8
- import { Fallback, Selector } from "./selector.js";
9
-
10
- describe("Selector", () => {
11
- let context: TemporalContext;
12
- let selector: Selector;
13
-
14
- beforeEach(() => {
15
- context = {
16
- blackboard: new ScopedBlackboard(),
17
- timestamp: Date.now(),
18
- deltaTime: 0,
19
- };
20
- selector = new Selector({ id: "test-selector" });
21
- });
22
-
23
- it("should return FAILURE when empty", async () => {
24
- const status = await selector.tick(context);
25
- expect(status).toBe(NodeStatus.FAILURE);
26
- });
27
-
28
- it("should return SUCCESS on first successful child", async () => {
29
- const executionOrder: string[] = [];
30
-
31
- const child1 = new MockAction({
32
- id: "child1",
33
- returnStatus: NodeStatus.FAILURE,
34
- });
35
- const child2 = new MockAction({
36
- id: "child2",
37
- returnStatus: NodeStatus.SUCCESS,
38
- });
39
- const child3 = new MockAction({
40
- id: "child3",
41
- returnStatus: NodeStatus.SUCCESS,
42
- });
43
-
44
- // Track execution order
45
- const originalTick1 = child1.tick.bind(child1);
46
- const originalTick2 = child2.tick.bind(child2);
47
- const originalTick3 = child3.tick.bind(child3);
48
-
49
- child1.tick = (ctx) => {
50
- executionOrder.push("child1");
51
- return originalTick1(ctx);
52
- };
53
- child2.tick = (ctx) => {
54
- executionOrder.push("child2");
55
- return originalTick2(ctx);
56
- };
57
- child3.tick = (ctx) => {
58
- executionOrder.push("child3");
59
- return originalTick3(ctx);
60
- };
61
-
62
- selector.addChildren([child1, child2, child3]);
63
-
64
- const status = await selector.tick(context);
65
-
66
- expect(status).toBe(NodeStatus.SUCCESS);
67
- expect(executionOrder).toEqual(["child1", "child2"]); // child3 should not execute
68
- expect(selector.status()).toBe(NodeStatus.SUCCESS);
69
- });
70
-
71
- it("should return FAILURE when all children fail", async () => {
72
- const child1 = new MockAction({
73
- id: "child1",
74
- returnStatus: NodeStatus.FAILURE,
75
- });
76
- const child2 = new MockAction({
77
- id: "child2",
78
- returnStatus: NodeStatus.FAILURE,
79
- });
80
- const child3 = new MockAction({
81
- id: "child3",
82
- returnStatus: NodeStatus.FAILURE,
83
- });
84
-
85
- selector.addChildren([child1, child2, child3]);
86
-
87
- const status = await selector.tick(context);
88
-
89
- expect(status).toBe(NodeStatus.FAILURE);
90
- expect(selector.status()).toBe(NodeStatus.FAILURE);
91
- });
92
-
93
- it("should handle RUNNING status correctly", async () => {
94
- const child1 = new MockAction({
95
- id: "child1",
96
- returnStatus: NodeStatus.FAILURE,
97
- });
98
- let child2 = new MockAction({
99
- id: "child2",
100
- returnStatus: NodeStatus.RUNNING,
101
- ticksBeforeComplete: 2,
102
- });
103
- const child3 = new MockAction({
104
- id: "child3",
105
- returnStatus: NodeStatus.SUCCESS,
106
- });
107
-
108
- selector.addChildren([child1, child2, child3]);
109
-
110
- // First tick - child2 returns RUNNING
111
- let status = await selector.tick(context);
112
- expect(status).toBe(NodeStatus.RUNNING);
113
- expect(child1.status()).toBe(NodeStatus.FAILURE);
114
- expect(child2.status()).toBe(NodeStatus.RUNNING);
115
-
116
- // Second tick - child2 still RUNNING
117
- status = await selector.tick(context);
118
- expect(status).toBe(NodeStatus.RUNNING);
119
-
120
- // Replace child2 to simulate completion
121
- child2 = new MockAction({
122
- id: "child2",
123
- returnStatus: NodeStatus.SUCCESS,
124
- });
125
- selector._children[1] = child2;
126
-
127
- status = await selector.tick(context);
128
- expect(status).toBe(NodeStatus.SUCCESS);
129
- expect(child3.status()).toBe(NodeStatus.IDLE); // Should not have been executed
130
- });
131
-
132
- it("should continue after RUNNING child fails", async () => {
133
- let tickCount = 0;
134
- const child1 = new MockAction({
135
- id: "child1",
136
- returnStatus: NodeStatus.FAILURE,
137
- });
138
-
139
- // Custom child that returns RUNNING first, then FAILURE
140
- const child2 = new MockAction({ id: "child2" });
141
- child2.tick = async (_ctx) => {
142
- tickCount++;
143
- if (tickCount === 1) {
144
- (child2 as unknown)._status = NodeStatus.RUNNING;
145
- return NodeStatus.RUNNING;
146
- }
147
- (child2 as unknown)._status = NodeStatus.FAILURE;
148
- return NodeStatus.FAILURE;
149
- };
150
-
151
- const child3 = new MockAction({
152
- id: "child3",
153
- returnStatus: NodeStatus.SUCCESS,
154
- });
155
-
156
- selector.addChildren([child1, child2, child3]);
157
-
158
- // First tick - child2 returns RUNNING
159
- let status = await selector.tick(context);
160
- expect(status).toBe(NodeStatus.RUNNING);
161
-
162
- // Second tick - child2 fails, moves to child3
163
- status = await selector.tick(context);
164
- expect(status).toBe(NodeStatus.SUCCESS);
165
- expect(child3.status()).toBe(NodeStatus.SUCCESS);
166
- });
167
-
168
- it("should reset child index on completion", async () => {
169
- const child1 = new MockAction({
170
- id: "child1",
171
- returnStatus: NodeStatus.SUCCESS,
172
- });
173
- const child2 = new MockAction({
174
- id: "child2",
175
- returnStatus: NodeStatus.SUCCESS,
176
- });
177
-
178
- selector.addChildren([child1, child2]);
179
-
180
- // First execution
181
- await selector.tick(context);
182
- expect((selector as unknown).currentChildIndex).toBe(0);
183
-
184
- // Reset children status for second execution
185
- child1.reset();
186
-
187
- // Second execution should start from beginning
188
- await selector.tick(context);
189
- expect(child1.status()).toBe(NodeStatus.SUCCESS);
190
- });
191
-
192
- it("should halt running children when halted", async () => {
193
- const child1 = new MockAction({
194
- id: "child1",
195
- returnStatus: NodeStatus.FAILURE,
196
- });
197
- const child2 = new MockAction({
198
- id: "child2",
199
- returnStatus: NodeStatus.RUNNING,
200
- });
201
-
202
- selector.addChildren([child1, child2]);
203
-
204
- // Start execution
205
- await selector.tick(context);
206
- expect(selector.status()).toBe(NodeStatus.RUNNING);
207
-
208
- // Halt the selector
209
- selector.halt();
210
-
211
- expect(selector.status()).toBe(NodeStatus.IDLE);
212
- expect((selector as unknown).currentChildIndex).toBe(0);
213
- });
214
-
215
- it("should throw error if child is undefined", () => {
216
- expect(() => selector.addChild(undefined as unknown)).toThrow(
217
- "Cannot add undefined child to composite node",
218
- );
219
- });
220
-
221
- describe("Signal-based cancellation", () => {
222
- it("should stop executing children when signal is aborted", async () => {
223
- const executionOrder: string[] = [];
224
- const controller = new AbortController();
225
-
226
- context.signal = controller.signal;
227
-
228
- const child1 = new MockAction({
229
- id: "child1",
230
- returnStatus: NodeStatus.FAILURE,
231
- });
232
- const child2 = new MockAction({
233
- id: "child2",
234
- returnStatus: NodeStatus.SUCCESS,
235
- });
236
- const child3 = new MockAction({
237
- id: "child3",
238
- returnStatus: NodeStatus.SUCCESS,
239
- });
240
-
241
- const originalTick1 = child1.tick.bind(child1);
242
- const originalTick2 = child2.tick.bind(child2);
243
- const originalTick3 = child3.tick.bind(child3);
244
-
245
- child1.tick = (ctx: TemporalContext) => {
246
- executionOrder.push("child1");
247
- return originalTick1(ctx);
248
- };
249
- child2.tick = (ctx: TemporalContext) => {
250
- executionOrder.push("child2");
251
- return originalTick2(ctx);
252
- };
253
- child3.tick = (ctx: TemporalContext) => {
254
- executionOrder.push("child3");
255
- return originalTick3(ctx);
256
- };
257
-
258
- selector.addChildren([child1, child2, child3]);
259
-
260
- // Abort signal before ticking
261
- controller.abort();
262
-
263
- try {
264
- await selector.tick(context);
265
- expect.fail("Should have thrown an error");
266
- } catch (error) {
267
- expect(error).toBeInstanceOf(Error);
268
- expect((error as Error).name).toBe("OperationCancelledError");
269
- }
270
-
271
- expect(executionOrder.length).toBe(0);
272
- });
273
-
274
- it("should respect abort signal in child iteration loop", async () => {
275
- const controller = new AbortController();
276
- const childrenExecuted: string[] = [];
277
-
278
- context.signal = controller.signal;
279
-
280
- const children = Array.from({ length: 5 }, (_, i) => {
281
- const child = new MockAction({
282
- id: `child${i}`,
283
- returnStatus: NodeStatus.FAILURE,
284
- });
285
- child.tick = async (ctx: TemporalContext) => {
286
- await checkSignal(ctx.signal);
287
- childrenExecuted.push(`child${i}`);
288
- return NodeStatus.FAILURE;
289
- };
290
- return child;
291
- });
292
-
293
- selector.addChildren(children);
294
-
295
- // Abort after 2 children
296
- let execCount = 0;
297
- children.forEach((child) => {
298
- const orig = child.tick;
299
- child.tick = async (ctx: TemporalContext) => {
300
- execCount++;
301
- if (execCount === 2) {
302
- controller.abort();
303
- }
304
- return await orig(ctx);
305
- };
306
- });
307
-
308
- try {
309
- await selector.tick(context);
310
- expect.fail("Should have thrown an error");
311
- } catch (error) {
312
- expect(error).toBeInstanceOf(Error);
313
- expect((error as Error).name).toBe("OperationCancelledError");
314
- }
315
-
316
- expect(childrenExecuted.length).toBeLessThanOrEqual(2);
317
- });
318
- });
319
-
320
- describe("ConfigurationError handling", () => {
321
- it(
322
- "should NOT catch ConfigurationError from child - it propagates up",
323
- async () => {
324
- class MisconfiguredNode extends ActionNode {
325
- executeTick(_context: TemporalContext) {
326
- throw new ConfigurationError("Element not found in blackboard");
327
- }
328
- }
329
-
330
- const misconfiguredChild = new MisconfiguredNode({ id: "broken" });
331
- const validChild = new MockAction({
332
- id: "valid",
333
- returnStatus: NodeStatus.SUCCESS,
334
- });
335
-
336
- selector.addChildren([misconfiguredChild, validChild]);
337
-
338
- // ConfigurationError should propagate as error
339
- // Selector should NOT try the next child
340
- try {
341
- await selector.tick(context);
342
- expect.fail("Should have thrown ConfigurationError");
343
- } catch (error) {
344
- expect(error).toBeInstanceOf(ConfigurationError);
345
- expect((error as ConfigurationError).message).toContain(
346
- "Element not found in blackboard",
347
- );
348
- }
349
-
350
- // Verify second child was NOT executed
351
- expect(validChild.status()).toBe(NodeStatus.IDLE);
352
- },
353
- );
354
- });
355
- });
356
-
357
- describe("Fallback", () => {
358
- it("should be an alias for Selector", () => {
359
- const fallback = new Fallback({ id: "test-fallback" });
360
- expect(fallback).toBeInstanceOf(Selector);
361
- expect(fallback.type).toBe("Fallback");
362
- });
363
-
364
- it("should behave like Selector", async () => {
365
- const context: TemporalContext = {
366
- blackboard: new ScopedBlackboard(),
367
- timestamp: Date.now(),
368
- deltaTime: 0,
369
- };
370
-
371
- const fallback = new Fallback({ id: "test-fallback" });
372
-
373
- const child1 = new MockAction({
374
- id: "child1",
375
- returnStatus: NodeStatus.FAILURE,
376
- });
377
- const child2 = new MockAction({
378
- id: "child2",
379
- returnStatus: NodeStatus.SUCCESS,
380
- });
381
-
382
- fallback.addChildren([child1, child2]);
383
-
384
- const status = await fallback.tick(context);
385
- expect(status).toBe(NodeStatus.SUCCESS);
386
- });
387
- });
@@ -1,85 +0,0 @@
1
- /**
2
- * Selector (Fallback) composite node
3
- * Executes children in order until one succeeds or all fail
4
- */
5
-
6
- import { CompositeNode } from "../base-node.js";
7
- import {
8
- type TemporalContext,
9
- type NodeConfiguration,
10
- NodeStatus,
11
- } from "../types.js";
12
- import { checkSignal } from "../utils/signal-check.js";
13
-
14
- export class Selector extends CompositeNode {
15
- private currentChildIndex: number = 0;
16
-
17
- async executeTick(context: TemporalContext): Promise<NodeStatus> {
18
- this.log("Ticking with", this._children.length, "children");
19
-
20
- if (this._children.length === 0) {
21
- return NodeStatus.FAILURE;
22
- }
23
-
24
- // Continue from where we left off if RUNNING
25
- while (this.currentChildIndex < this._children.length) {
26
- // Check for cancellation before ticking each child
27
- checkSignal(context.signal);
28
-
29
- const child = this._children[this.currentChildIndex];
30
- if (!child) {
31
- throw new Error(
32
- `Child at index ${this.currentChildIndex} is undefined`,
33
- );
34
- }
35
-
36
- this.log(`Ticking child ${this.currentChildIndex}: ${child.name}`);
37
- const childStatus = await child.tick(context);
38
-
39
- switch (childStatus) {
40
- case NodeStatus.SUCCESS:
41
- this.log(`Child ${child.name} succeeded - selector succeeds`);
42
- this._status = NodeStatus.SUCCESS;
43
- this.currentChildIndex = 0;
44
- return NodeStatus.SUCCESS;
45
-
46
- case NodeStatus.FAILURE:
47
- this.log(`Child ${child.name} failed`);
48
- this.currentChildIndex++;
49
- break;
50
-
51
- case NodeStatus.RUNNING:
52
- this.log(`Child ${child.name} is running`);
53
- this._status = NodeStatus.RUNNING;
54
- return NodeStatus.RUNNING;
55
-
56
- default:
57
- throw new Error(`Unexpected status from child: ${childStatus}`);
58
- }
59
- }
60
-
61
- // All children failed
62
- this.log("All children failed");
63
- this._status = NodeStatus.FAILURE;
64
- this.currentChildIndex = 0;
65
- return NodeStatus.FAILURE;
66
- }
67
-
68
- protected onHalt(): void {
69
- this.haltChildren(this.currentChildIndex);
70
- this.currentChildIndex = 0;
71
- }
72
-
73
- protected onReset(): void {
74
- this.currentChildIndex = 0;
75
- }
76
- }
77
-
78
- /**
79
- * Fallback is an alias for Selector (BehaviorTree.CPP compatibility)
80
- */
81
- export class Fallback extends Selector {
82
- constructor(config: NodeConfiguration) {
83
- super({ ...config, type: "Fallback" });
84
- }
85
- }
@@ -1,19 +0,0 @@
1
- /**
2
- * Sequence composite configuration schema
3
- */
4
-
5
- import { z } from "zod";
6
- import { nodeConfigurationSchema } from "../schemas/base.schema.js";
7
-
8
- /**
9
- * Schema for Sequence composite configuration
10
- * Uses base schema only (no additional properties)
11
- */
12
- export const sequenceConfigurationSchema = nodeConfigurationSchema;
13
-
14
- /**
15
- * Validated Sequence configuration type
16
- */
17
- export type ValidatedSequenceConfiguration = z.infer<
18
- typeof sequenceConfigurationSchema
19
- >;