@mondaydotcomorg/atp-compiler 0.17.14

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 (285) hide show
  1. package/README.md +382 -0
  2. package/__tests__/integration/all-array-methods-native.test.ts +321 -0
  3. package/__tests__/integration/all-callback-types.test.ts +406 -0
  4. package/__tests__/integration/comprehensive-edge-cases.test.ts +701 -0
  5. package/__tests__/integration/native-behavior-verification.test.ts +340 -0
  6. package/__tests__/integration/semantic-correctness.test.ts +354 -0
  7. package/__tests__/integration/threshold-tests.test.ts +529 -0
  8. package/__tests__/unit/batch-optimizer.test.ts +253 -0
  9. package/__tests__/unit/checkpoint-manager.test.ts +145 -0
  10. package/__tests__/unit/detector.test.ts +346 -0
  11. package/dist/atp-compiler/src/index.d.ts +6 -0
  12. package/dist/atp-compiler/src/index.d.ts.map +1 -0
  13. package/dist/atp-compiler/src/index.js +6 -0
  14. package/dist/atp-compiler/src/index.js.map +1 -0
  15. package/dist/atp-compiler/src/runtime/batch-parallel.d.ts +3 -0
  16. package/dist/atp-compiler/src/runtime/batch-parallel.d.ts.map +1 -0
  17. package/dist/atp-compiler/src/runtime/batch-parallel.js +13 -0
  18. package/dist/atp-compiler/src/runtime/batch-parallel.js.map +1 -0
  19. package/dist/atp-compiler/src/runtime/checkpoint-manager.d.ts +19 -0
  20. package/dist/atp-compiler/src/runtime/checkpoint-manager.d.ts.map +1 -0
  21. package/dist/atp-compiler/src/runtime/checkpoint-manager.js +81 -0
  22. package/dist/atp-compiler/src/runtime/checkpoint-manager.js.map +1 -0
  23. package/dist/atp-compiler/src/runtime/context.d.ts +8 -0
  24. package/dist/atp-compiler/src/runtime/context.d.ts.map +1 -0
  25. package/dist/atp-compiler/src/runtime/context.js +25 -0
  26. package/dist/atp-compiler/src/runtime/context.js.map +1 -0
  27. package/dist/atp-compiler/src/runtime/errors.d.ts +38 -0
  28. package/dist/atp-compiler/src/runtime/errors.d.ts.map +1 -0
  29. package/dist/atp-compiler/src/runtime/errors.js +61 -0
  30. package/dist/atp-compiler/src/runtime/errors.js.map +1 -0
  31. package/dist/atp-compiler/src/runtime/index.d.ts +16 -0
  32. package/dist/atp-compiler/src/runtime/index.d.ts.map +1 -0
  33. package/dist/atp-compiler/src/runtime/index.js +20 -0
  34. package/dist/atp-compiler/src/runtime/index.js.map +1 -0
  35. package/dist/atp-compiler/src/runtime/resumable-arrays.d.ts +9 -0
  36. package/dist/atp-compiler/src/runtime/resumable-arrays.d.ts.map +1 -0
  37. package/dist/atp-compiler/src/runtime/resumable-arrays.js +179 -0
  38. package/dist/atp-compiler/src/runtime/resumable-arrays.js.map +1 -0
  39. package/dist/atp-compiler/src/runtime/resumable-loops.d.ts +4 -0
  40. package/dist/atp-compiler/src/runtime/resumable-loops.d.ts.map +1 -0
  41. package/dist/atp-compiler/src/runtime/resumable-loops.js +61 -0
  42. package/dist/atp-compiler/src/runtime/resumable-loops.js.map +1 -0
  43. package/dist/atp-compiler/src/runtime/resumable-parallel.d.ts +3 -0
  44. package/dist/atp-compiler/src/runtime/resumable-parallel.d.ts.map +1 -0
  45. package/dist/atp-compiler/src/runtime/resumable-parallel.js +44 -0
  46. package/dist/atp-compiler/src/runtime/resumable-parallel.js.map +1 -0
  47. package/dist/atp-compiler/src/transformer/array-transformer-batch.d.ts +13 -0
  48. package/dist/atp-compiler/src/transformer/array-transformer-batch.d.ts.map +1 -0
  49. package/dist/atp-compiler/src/transformer/array-transformer-batch.js +55 -0
  50. package/dist/atp-compiler/src/transformer/array-transformer-batch.js.map +1 -0
  51. package/dist/atp-compiler/src/transformer/array-transformer-sequential.d.ts +6 -0
  52. package/dist/atp-compiler/src/transformer/array-transformer-sequential.d.ts.map +1 -0
  53. package/dist/atp-compiler/src/transformer/array-transformer-sequential.js +23 -0
  54. package/dist/atp-compiler/src/transformer/array-transformer-sequential.js.map +1 -0
  55. package/dist/atp-compiler/src/transformer/array-transformer-utils.d.ts +18 -0
  56. package/dist/atp-compiler/src/transformer/array-transformer-utils.d.ts.map +1 -0
  57. package/dist/atp-compiler/src/transformer/array-transformer-utils.js +69 -0
  58. package/dist/atp-compiler/src/transformer/array-transformer-utils.js.map +1 -0
  59. package/dist/atp-compiler/src/transformer/array-transformer-wrappers.d.ts +26 -0
  60. package/dist/atp-compiler/src/transformer/array-transformer-wrappers.d.ts.map +1 -0
  61. package/dist/atp-compiler/src/transformer/array-transformer-wrappers.js +88 -0
  62. package/dist/atp-compiler/src/transformer/array-transformer-wrappers.js.map +1 -0
  63. package/dist/atp-compiler/src/transformer/array-transformer.d.ts +12 -0
  64. package/dist/atp-compiler/src/transformer/array-transformer.d.ts.map +1 -0
  65. package/dist/atp-compiler/src/transformer/array-transformer.js +47 -0
  66. package/dist/atp-compiler/src/transformer/array-transformer.js.map +1 -0
  67. package/dist/atp-compiler/src/transformer/batch-detector.d.ts +16 -0
  68. package/dist/atp-compiler/src/transformer/batch-detector.d.ts.map +1 -0
  69. package/dist/atp-compiler/src/transformer/batch-detector.js +131 -0
  70. package/dist/atp-compiler/src/transformer/batch-detector.js.map +1 -0
  71. package/dist/atp-compiler/src/transformer/batch-optimizer.d.ts +27 -0
  72. package/dist/atp-compiler/src/transformer/batch-optimizer.d.ts.map +1 -0
  73. package/dist/atp-compiler/src/transformer/batch-optimizer.js +244 -0
  74. package/dist/atp-compiler/src/transformer/batch-optimizer.js.map +1 -0
  75. package/dist/atp-compiler/src/transformer/detector.d.ts +9 -0
  76. package/dist/atp-compiler/src/transformer/detector.d.ts.map +1 -0
  77. package/dist/atp-compiler/src/transformer/detector.js +141 -0
  78. package/dist/atp-compiler/src/transformer/detector.js.map +1 -0
  79. package/dist/atp-compiler/src/transformer/index.d.ts +22 -0
  80. package/dist/atp-compiler/src/transformer/index.d.ts.map +1 -0
  81. package/dist/atp-compiler/src/transformer/index.js +132 -0
  82. package/dist/atp-compiler/src/transformer/index.js.map +1 -0
  83. package/dist/atp-compiler/src/transformer/loop-transformer.d.ts +25 -0
  84. package/dist/atp-compiler/src/transformer/loop-transformer.d.ts.map +1 -0
  85. package/dist/atp-compiler/src/transformer/loop-transformer.js +193 -0
  86. package/dist/atp-compiler/src/transformer/loop-transformer.js.map +1 -0
  87. package/dist/atp-compiler/src/transformer/promise-transformer.d.ts +17 -0
  88. package/dist/atp-compiler/src/transformer/promise-transformer.d.ts.map +1 -0
  89. package/dist/atp-compiler/src/transformer/promise-transformer.js +132 -0
  90. package/dist/atp-compiler/src/transformer/promise-transformer.js.map +1 -0
  91. package/dist/atp-compiler/src/transformer/utils.d.ts +15 -0
  92. package/dist/atp-compiler/src/transformer/utils.d.ts.map +1 -0
  93. package/dist/atp-compiler/src/transformer/utils.js +118 -0
  94. package/dist/atp-compiler/src/transformer/utils.js.map +1 -0
  95. package/dist/atp-compiler/src/types.d.ts +57 -0
  96. package/dist/atp-compiler/src/types.d.ts.map +1 -0
  97. package/dist/atp-compiler/src/types.js +23 -0
  98. package/dist/atp-compiler/src/types.js.map +1 -0
  99. package/dist/protocol/src/auth.d.ts +173 -0
  100. package/dist/protocol/src/auth.d.ts.map +1 -0
  101. package/dist/protocol/src/auth.js +202 -0
  102. package/dist/protocol/src/auth.js.map +1 -0
  103. package/dist/protocol/src/index.d.ts +7 -0
  104. package/dist/protocol/src/index.d.ts.map +1 -0
  105. package/dist/protocol/src/index.js +7 -0
  106. package/dist/protocol/src/index.js.map +1 -0
  107. package/dist/protocol/src/oauth.d.ts +63 -0
  108. package/dist/protocol/src/oauth.d.ts.map +1 -0
  109. package/dist/protocol/src/oauth.js +5 -0
  110. package/dist/protocol/src/oauth.js.map +1 -0
  111. package/dist/protocol/src/providers.d.ts +167 -0
  112. package/dist/protocol/src/providers.d.ts.map +1 -0
  113. package/dist/protocol/src/providers.js +33 -0
  114. package/dist/protocol/src/providers.js.map +1 -0
  115. package/dist/protocol/src/schemas.d.ts +6 -0
  116. package/dist/protocol/src/schemas.d.ts.map +1 -0
  117. package/dist/protocol/src/schemas.js +51 -0
  118. package/dist/protocol/src/schemas.js.map +1 -0
  119. package/dist/protocol/src/types.d.ts +489 -0
  120. package/dist/protocol/src/types.d.ts.map +1 -0
  121. package/dist/protocol/src/types.js +88 -0
  122. package/dist/protocol/src/types.js.map +1 -0
  123. package/dist/protocol/src/validation.d.ts +76 -0
  124. package/dist/protocol/src/validation.d.ts.map +1 -0
  125. package/dist/protocol/src/validation.js +129 -0
  126. package/dist/protocol/src/validation.js.map +1 -0
  127. package/dist/provenance/src/ast/instrumentor.d.ts +37 -0
  128. package/dist/provenance/src/ast/instrumentor.d.ts.map +1 -0
  129. package/dist/provenance/src/ast/instrumentor.js +299 -0
  130. package/dist/provenance/src/ast/instrumentor.js.map +1 -0
  131. package/dist/provenance/src/index.d.ts +7 -0
  132. package/dist/provenance/src/index.d.ts.map +1 -0
  133. package/dist/provenance/src/index.js +7 -0
  134. package/dist/provenance/src/index.js.map +1 -0
  135. package/dist/provenance/src/policies/engine.d.ts +71 -0
  136. package/dist/provenance/src/policies/engine.d.ts.map +1 -0
  137. package/dist/provenance/src/policies/engine.js +433 -0
  138. package/dist/provenance/src/policies/engine.js.map +1 -0
  139. package/dist/provenance/src/registry.d.ts +94 -0
  140. package/dist/provenance/src/registry.d.ts.map +1 -0
  141. package/dist/provenance/src/registry.js +445 -0
  142. package/dist/provenance/src/registry.js.map +1 -0
  143. package/dist/provenance/src/tokens.d.ts +49 -0
  144. package/dist/provenance/src/tokens.d.ts.map +1 -0
  145. package/dist/provenance/src/tokens.js +239 -0
  146. package/dist/provenance/src/tokens.js.map +1 -0
  147. package/dist/provenance/src/types.d.ts +150 -0
  148. package/dist/provenance/src/types.d.ts.map +1 -0
  149. package/dist/provenance/src/types.js +47 -0
  150. package/dist/provenance/src/types.js.map +1 -0
  151. package/dist/runtime/src/approval/handler.d.ts +12 -0
  152. package/dist/runtime/src/approval/handler.d.ts.map +1 -0
  153. package/dist/runtime/src/approval/handler.js +17 -0
  154. package/dist/runtime/src/approval/handler.js.map +1 -0
  155. package/dist/runtime/src/approval/index.d.ts +17 -0
  156. package/dist/runtime/src/approval/index.d.ts.map +1 -0
  157. package/dist/runtime/src/approval/index.js +94 -0
  158. package/dist/runtime/src/approval/index.js.map +1 -0
  159. package/dist/runtime/src/approval/types.d.ts +21 -0
  160. package/dist/runtime/src/approval/types.d.ts.map +1 -0
  161. package/dist/runtime/src/approval/types.js +5 -0
  162. package/dist/runtime/src/approval/types.js.map +1 -0
  163. package/dist/runtime/src/cache/backends.d.ts +39 -0
  164. package/dist/runtime/src/cache/backends.d.ts.map +1 -0
  165. package/dist/runtime/src/cache/backends.js +167 -0
  166. package/dist/runtime/src/cache/backends.js.map +1 -0
  167. package/dist/runtime/src/cache/index.d.ts +32 -0
  168. package/dist/runtime/src/cache/index.d.ts.map +1 -0
  169. package/dist/runtime/src/cache/index.js +103 -0
  170. package/dist/runtime/src/cache/index.js.map +1 -0
  171. package/dist/runtime/src/cache/types.d.ts +20 -0
  172. package/dist/runtime/src/cache/types.d.ts.map +1 -0
  173. package/dist/runtime/src/cache/types.js +2 -0
  174. package/dist/runtime/src/cache/types.js.map +1 -0
  175. package/dist/runtime/src/embedding/index.d.ts +39 -0
  176. package/dist/runtime/src/embedding/index.d.ts.map +1 -0
  177. package/dist/runtime/src/embedding/index.js +162 -0
  178. package/dist/runtime/src/embedding/index.js.map +1 -0
  179. package/dist/runtime/src/embedding/types.d.ts +28 -0
  180. package/dist/runtime/src/embedding/types.d.ts.map +1 -0
  181. package/dist/runtime/src/embedding/types.js +5 -0
  182. package/dist/runtime/src/embedding/types.js.map +1 -0
  183. package/dist/runtime/src/embedding/utils.d.ts +11 -0
  184. package/dist/runtime/src/embedding/utils.d.ts.map +1 -0
  185. package/dist/runtime/src/embedding/utils.js +30 -0
  186. package/dist/runtime/src/embedding/utils.js.map +1 -0
  187. package/dist/runtime/src/embedding/vector-store.d.ts +64 -0
  188. package/dist/runtime/src/embedding/vector-store.d.ts.map +1 -0
  189. package/dist/runtime/src/embedding/vector-store.js +142 -0
  190. package/dist/runtime/src/embedding/vector-store.js.map +1 -0
  191. package/dist/runtime/src/index.d.ts +18 -0
  192. package/dist/runtime/src/index.d.ts.map +1 -0
  193. package/dist/runtime/src/index.js +17 -0
  194. package/dist/runtime/src/index.js.map +1 -0
  195. package/dist/runtime/src/llm/callback.d.ts +13 -0
  196. package/dist/runtime/src/llm/callback.d.ts.map +1 -0
  197. package/dist/runtime/src/llm/callback.js +19 -0
  198. package/dist/runtime/src/llm/callback.js.map +1 -0
  199. package/dist/runtime/src/llm/index.d.ts +29 -0
  200. package/dist/runtime/src/llm/index.d.ts.map +1 -0
  201. package/dist/runtime/src/llm/index.js +118 -0
  202. package/dist/runtime/src/llm/index.js.map +1 -0
  203. package/dist/runtime/src/llm/replay.d.ts +47 -0
  204. package/dist/runtime/src/llm/replay.d.ts.map +1 -0
  205. package/dist/runtime/src/llm/replay.js +114 -0
  206. package/dist/runtime/src/llm/replay.js.map +1 -0
  207. package/dist/runtime/src/llm/types.d.ts +24 -0
  208. package/dist/runtime/src/llm/types.d.ts.map +1 -0
  209. package/dist/runtime/src/llm/types.js +2 -0
  210. package/dist/runtime/src/llm/types.js.map +1 -0
  211. package/dist/runtime/src/log/index.d.ts +12 -0
  212. package/dist/runtime/src/log/index.d.ts.map +1 -0
  213. package/dist/runtime/src/log/index.js +166 -0
  214. package/dist/runtime/src/log/index.js.map +1 -0
  215. package/dist/runtime/src/log/types.d.ts +19 -0
  216. package/dist/runtime/src/log/types.d.ts.map +1 -0
  217. package/dist/runtime/src/log/types.js +5 -0
  218. package/dist/runtime/src/log/types.js.map +1 -0
  219. package/dist/runtime/src/metadata/decorators.d.ts +27 -0
  220. package/dist/runtime/src/metadata/decorators.d.ts.map +1 -0
  221. package/dist/runtime/src/metadata/decorators.js +38 -0
  222. package/dist/runtime/src/metadata/decorators.js.map +1 -0
  223. package/dist/runtime/src/metadata/generated.d.ts +18 -0
  224. package/dist/runtime/src/metadata/generated.d.ts.map +1 -0
  225. package/dist/runtime/src/metadata/generated.js +290 -0
  226. package/dist/runtime/src/metadata/generated.js.map +1 -0
  227. package/dist/runtime/src/metadata/index.d.ts +11 -0
  228. package/dist/runtime/src/metadata/index.d.ts.map +1 -0
  229. package/dist/runtime/src/metadata/index.js +45 -0
  230. package/dist/runtime/src/metadata/index.js.map +1 -0
  231. package/dist/runtime/src/metadata/types.d.ts +22 -0
  232. package/dist/runtime/src/metadata/types.d.ts.map +1 -0
  233. package/dist/runtime/src/metadata/types.js +6 -0
  234. package/dist/runtime/src/metadata/types.js.map +1 -0
  235. package/dist/runtime/src/pause/index.d.ts +11 -0
  236. package/dist/runtime/src/pause/index.d.ts.map +1 -0
  237. package/dist/runtime/src/pause/index.js +15 -0
  238. package/dist/runtime/src/pause/index.js.map +1 -0
  239. package/dist/runtime/src/pause/types.d.ts +46 -0
  240. package/dist/runtime/src/pause/types.d.ts.map +1 -0
  241. package/dist/runtime/src/pause/types.js +57 -0
  242. package/dist/runtime/src/pause/types.js.map +1 -0
  243. package/dist/runtime/src/progress/index.d.ts +19 -0
  244. package/dist/runtime/src/progress/index.d.ts.map +1 -0
  245. package/dist/runtime/src/progress/index.js +61 -0
  246. package/dist/runtime/src/progress/index.js.map +1 -0
  247. package/dist/runtime/src/progress/types.d.ts +7 -0
  248. package/dist/runtime/src/progress/types.d.ts.map +1 -0
  249. package/dist/runtime/src/progress/types.js +2 -0
  250. package/dist/runtime/src/progress/types.js.map +1 -0
  251. package/dist/runtime/src/registry.d.ts +16 -0
  252. package/dist/runtime/src/registry.d.ts.map +1 -0
  253. package/dist/runtime/src/registry.js +16 -0
  254. package/dist/runtime/src/registry.js.map +1 -0
  255. package/dist/runtime/src/utils.d.ts +11 -0
  256. package/dist/runtime/src/utils.d.ts.map +1 -0
  257. package/dist/runtime/src/utils.js +31 -0
  258. package/dist/runtime/src/utils.js.map +1 -0
  259. package/dist/tsconfig.tsbuildinfo +1 -0
  260. package/jest.config.js +29 -0
  261. package/package.json +56 -0
  262. package/project.json +31 -0
  263. package/src/index.ts +6 -0
  264. package/src/runtime/batch-parallel.ts +22 -0
  265. package/src/runtime/checkpoint-manager.ts +105 -0
  266. package/src/runtime/context.ts +33 -0
  267. package/src/runtime/errors.ts +79 -0
  268. package/src/runtime/index.ts +35 -0
  269. package/src/runtime/resumable-arrays.ts +253 -0
  270. package/src/runtime/resumable-loops.ts +93 -0
  271. package/src/runtime/resumable-parallel.ts +57 -0
  272. package/src/transformer/array-transformer-batch.ts +86 -0
  273. package/src/transformer/array-transformer-sequential.ts +38 -0
  274. package/src/transformer/array-transformer-utils.ts +80 -0
  275. package/src/transformer/array-transformer-wrappers.ts +165 -0
  276. package/src/transformer/array-transformer.ts +76 -0
  277. package/src/transformer/batch-detector.ts +166 -0
  278. package/src/transformer/batch-optimizer.ts +320 -0
  279. package/src/transformer/detector.ts +171 -0
  280. package/src/transformer/index.ts +155 -0
  281. package/src/transformer/loop-transformer.ts +285 -0
  282. package/src/transformer/promise-transformer.ts +194 -0
  283. package/src/transformer/utils.ts +147 -0
  284. package/src/types.ts +101 -0
  285. package/tsconfig.json +12 -0
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Tests for Batch Optimizer
3
+ *
4
+ * Verifies that simple callbacks are correctly identified as batchable
5
+ * and complex callbacks fall back to sequential execution
6
+ */
7
+
8
+ import { describe, test, expect } from '@jest/globals';
9
+ import * as parser from '@babel/parser';
10
+ import * as t from '@babel/types';
11
+ import { BatchOptimizer } from '../../src/transformer/batch-optimizer';
12
+
13
+ describe('BatchOptimizer', () => {
14
+ const optimizer = new BatchOptimizer();
15
+
16
+ describe('canBatchArrayMethod', () => {
17
+ test('✅ Simple forEach with single LLM call - CAN BATCH', () => {
18
+ const code = `async (item) => { await atp.llm.call({ prompt: item }); }`;
19
+ const ast = parser.parseExpression(code);
20
+ const callback = ast as t.Function;
21
+
22
+ const result = optimizer.canBatchArrayMethod(callback);
23
+
24
+ expect(result.canBatch).toBe(true);
25
+ expect(result.llmCallPattern).toBe('single');
26
+ });
27
+
28
+ test('✅ Simple map with single LLM call - CAN BATCH', () => {
29
+ const code = `async (item) => await atp.llm.call({ prompt: item })`;
30
+ const ast = parser.parseExpression(code);
31
+ const callback = ast as t.Function;
32
+
33
+ const result = optimizer.canBatchArrayMethod(callback);
34
+
35
+ expect(result.canBatch).toBe(true);
36
+ expect(result.llmCallPattern).toBe('single');
37
+ });
38
+
39
+ test('✅ Arrow function with expression body - CAN BATCH', () => {
40
+ const code = `async (x) => await atp.llm.call({ prompt: x })`;
41
+ const ast = parser.parseExpression(code);
42
+ const callback = ast as t.Function;
43
+
44
+ const result = optimizer.canBatchArrayMethod(callback);
45
+
46
+ expect(result.canBatch).toBe(true);
47
+ });
48
+
49
+ test('✅ forEach with conditional - CAN BATCH (smart decision later)', () => {
50
+ const code = `async (item) => {
51
+ if (item.priority > 5) {
52
+ await atp.llm.call({ prompt: item });
53
+ }
54
+ }`;
55
+ const ast = parser.parseExpression(code);
56
+ const callback = ast as t.Function;
57
+
58
+ const result = optimizer.canBatchArrayMethod(callback);
59
+
60
+ expect(result.canBatch).toBe(true);
61
+ expect(result.hasConditionals).toBe(true);
62
+ expect(result.llmCallPattern).toBe('conditional');
63
+ });
64
+
65
+ test('❌ forEach with loop inside - CANNOT BATCH', () => {
66
+ const code = `async (item) => {
67
+ for (const x of item.parts) {
68
+ await atp.llm.call({ prompt: x });
69
+ }
70
+ }`;
71
+ const ast = parser.parseExpression(code);
72
+ const callback = ast as t.Function;
73
+
74
+ const result = optimizer.canBatchArrayMethod(callback);
75
+
76
+ expect(result.canBatch).toBe(false);
77
+ expect(result.reason).toBe('Contains loops');
78
+ });
79
+
80
+ test('❌ forEach with try-catch - CANNOT BATCH', () => {
81
+ const code = `async (item) => {
82
+ try {
83
+ await atp.llm.call({ prompt: item });
84
+ } catch (e) {
85
+ console.error(e);
86
+ }
87
+ }`;
88
+ const ast = parser.parseExpression(code);
89
+ const callback = ast as t.Function;
90
+
91
+ const result = optimizer.canBatchArrayMethod(callback);
92
+
93
+ expect(result.canBatch).toBe(false);
94
+ expect(result.reason).toBe('Contains try-catch');
95
+ });
96
+
97
+ test('❌ forEach with sequential dependencies - CANNOT BATCH', () => {
98
+ const code = `async (item) => {
99
+ const first = await atp.llm.call({ prompt: item });
100
+ const second = await atp.llm.call({ prompt: first });
101
+ return second;
102
+ }`;
103
+ const ast = parser.parseExpression(code);
104
+ const callback = ast as t.Function;
105
+
106
+ const result = optimizer.canBatchArrayMethod(callback);
107
+
108
+ expect(result.canBatch).toBe(false);
109
+ expect(result.reason).toBe('Multiple pausable calls');
110
+ });
111
+
112
+ test('❌ Non-async callback - CANNOT BATCH', () => {
113
+ const code = `(item) => { console.log(item); }`;
114
+ const ast = parser.parseExpression(code);
115
+ const callback = ast as t.Function;
116
+
117
+ const result = optimizer.canBatchArrayMethod(callback);
118
+
119
+ expect(result.canBatch).toBe(false);
120
+ expect(result.reason).toBe('Not async');
121
+ });
122
+
123
+ test('❌ No pausable calls - CANNOT BATCH', () => {
124
+ const code = `async (item) => { await fetch(item); }`;
125
+ const ast = parser.parseExpression(code);
126
+ const callback = ast as t.Function;
127
+
128
+ const result = optimizer.canBatchArrayMethod(callback);
129
+
130
+ expect(result.canBatch).toBe(false);
131
+ expect(result.reason).toBe('No pausable calls');
132
+ });
133
+
134
+ test('❌ Multiple independent LLM calls - CANNOT BATCH (too complex)', () => {
135
+ const code = `async (item) => {
136
+ await atp.llm.call({ prompt: 'A' + item });
137
+ await atp.llm.call({ prompt: 'B' + item });
138
+ }`;
139
+ const ast = parser.parseExpression(code);
140
+ const callback = ast as t.Function;
141
+
142
+ const result = optimizer.canBatchArrayMethod(callback);
143
+
144
+ expect(result.canBatch).toBe(false);
145
+ expect(result.reason).toBe('Multiple pausable calls');
146
+ });
147
+ });
148
+
149
+ describe('canBatchForOfLoop', () => {
150
+ test('✅ Simple for...of with single LLM call - CAN BATCH', () => {
151
+ const code = `for (const item of items) { await atp.llm.call({ prompt: item }); }`;
152
+ const ast = parser.parse(code, { sourceType: 'module' });
153
+ const loop = ast.program.body[0] as t.ForOfStatement;
154
+
155
+ const result = optimizer.canBatchForOfLoop(loop);
156
+
157
+ expect(result.canBatch).toBe(true);
158
+ expect(result.llmCallPattern).toBe('single');
159
+ });
160
+
161
+ test('❌ for...of with break - CANNOT BATCH', () => {
162
+ const code = `for (const item of items) {
163
+ await atp.llm.call({ prompt: item });
164
+ if (item === 'stop') break;
165
+ }`;
166
+ const ast = parser.parse(code, { sourceType: 'module' });
167
+ const loop = ast.program.body[0] as t.ForOfStatement;
168
+
169
+ const result = optimizer.canBatchForOfLoop(loop);
170
+
171
+ expect(result.canBatch).toBe(false);
172
+ expect(result.reason).toBe('Contains break/continue');
173
+ });
174
+
175
+ test('❌ for...of with continue - CANNOT BATCH', () => {
176
+ const code = `for (const item of items) {
177
+ if (!item.valid) continue;
178
+ await atp.llm.call({ prompt: item });
179
+ }`;
180
+ const ast = parser.parse(code, { sourceType: 'module' });
181
+ const loop = ast.program.body[0] as t.ForOfStatement;
182
+
183
+ const result = optimizer.canBatchForOfLoop(loop);
184
+
185
+ expect(result.canBatch).toBe(false);
186
+ expect(result.reason).toBe('Contains break/continue');
187
+ });
188
+
189
+ test('✅ for...of with conditional - CAN BATCH (smart decision later)', () => {
190
+ const code = `for (const item of items) {
191
+ if (item.priority > 5) {
192
+ await atp.llm.call({ prompt: item });
193
+ }
194
+ }`;
195
+ const ast = parser.parse(code, { sourceType: 'module' });
196
+ const loop = ast.program.body[0] as t.ForOfStatement;
197
+
198
+ const result = optimizer.canBatchForOfLoop(loop);
199
+
200
+ expect(result.canBatch).toBe(true);
201
+ expect(result.hasConditionals).toBe(true);
202
+ });
203
+
204
+ test('❌ for...of with nested loop - CANNOT BATCH', () => {
205
+ const code = `for (const outer of items) {
206
+ for (const inner of outer.items) {
207
+ await atp.llm.call({ prompt: inner });
208
+ }
209
+ }`;
210
+ const ast = parser.parse(code, { sourceType: 'module' });
211
+ const loop = ast.program.body[0] as t.ForOfStatement;
212
+
213
+ const result = optimizer.canBatchForOfLoop(loop);
214
+
215
+ expect(result.canBatch).toBe(false);
216
+ expect(result.reason).toBe('Contains nested loops');
217
+ });
218
+ });
219
+
220
+ describe('Performance Impact Examples', () => {
221
+ test('Example: 100 items with simple LLM call - WILL BE BATCHED', () => {
222
+ const code = `async (item) => await atp.llm.call({ prompt: item })`;
223
+ const ast = parser.parseExpression(code);
224
+ const callback = ast as t.Function;
225
+
226
+ const result = optimizer.canBatchArrayMethod(callback);
227
+
228
+ expect(result.canBatch).toBe(true);
229
+ // This means 100 items = 1 batch call (~2s) instead of 100 sequential (~200s)
230
+ // 100x speedup!
231
+ });
232
+
233
+ test('Example: forEach with complex logic - WILL BE SEQUENTIAL', () => {
234
+ const code = `async (item) => {
235
+ if (item.needsReview) {
236
+ const review = await atp.llm.call({ prompt: 'Review: ' + item });
237
+ if (review.approved) {
238
+ await atp.llm.call({ prompt: 'Finalize: ' + item });
239
+ }
240
+ }
241
+ }`;
242
+ const ast = parser.parseExpression(code);
243
+ const callback = ast as t.Function;
244
+
245
+ const result = optimizer.canBatchArrayMethod(callback);
246
+
247
+ expect(result.canBatch).toBe(false);
248
+ // Complex logic requires sequential execution with checkpoints
249
+ });
250
+ });
251
+ });
252
+
253
+ console.log('\n✅ Batch Optimizer tests complete!\n');
@@ -0,0 +1,145 @@
1
+ import { CheckpointManager } from '../../src/runtime/checkpoint-manager';
2
+ import type { CacheProvider } from '@mondaydotcomorg/atp-protocol';
3
+ import type { LoopCheckpoint } from '../../src/types';
4
+
5
+ describe('CheckpointManager', () => {
6
+ let mockCache: jest.Mocked<CacheProvider>;
7
+ let manager: CheckpointManager;
8
+
9
+ beforeEach(() => {
10
+ mockCache = {
11
+ get: jest.fn(),
12
+ set: jest.fn(),
13
+ delete: jest.fn(),
14
+ } as any;
15
+
16
+ manager = new CheckpointManager('exec-123', mockCache, 'test-checkpoint');
17
+ });
18
+
19
+ describe('save', () => {
20
+ it('should save checkpoint to cache', async () => {
21
+ const checkpoint: LoopCheckpoint = {
22
+ loopId: 'loop-1',
23
+ currentIndex: 5,
24
+ timestamp: Date.now(),
25
+ };
26
+
27
+ await manager.save(checkpoint);
28
+
29
+ expect(mockCache.set).toHaveBeenCalledWith(
30
+ 'test-checkpoint:exec-123:loop-1',
31
+ checkpoint,
32
+ 3600
33
+ );
34
+ });
35
+
36
+ it('should save checkpoint with results', async () => {
37
+ const checkpoint: LoopCheckpoint = {
38
+ loopId: 'loop-1',
39
+ currentIndex: 3,
40
+ results: ['a', 'b', 'c'],
41
+ timestamp: Date.now(),
42
+ };
43
+
44
+ await manager.save(checkpoint);
45
+
46
+ expect(mockCache.set).toHaveBeenCalledWith(
47
+ 'test-checkpoint:exec-123:loop-1',
48
+ checkpoint,
49
+ 3600
50
+ );
51
+ });
52
+
53
+ it('should throw CheckpointError if size exceeds limit', async () => {
54
+ const largeArray = Array(100000).fill('x'.repeat(1000));
55
+ const checkpoint: LoopCheckpoint = {
56
+ loopId: 'loop-1',
57
+ currentIndex: 1,
58
+ results: largeArray,
59
+ timestamp: Date.now(),
60
+ };
61
+
62
+ await expect(manager.save(checkpoint)).rejects.toThrow('Checkpoint size');
63
+ });
64
+
65
+ it('should throw CheckpointError on cache failure', async () => {
66
+ mockCache.set.mockRejectedValue(new Error('Cache error'));
67
+
68
+ const checkpoint: LoopCheckpoint = {
69
+ loopId: 'loop-1',
70
+ currentIndex: 1,
71
+ timestamp: Date.now(),
72
+ };
73
+
74
+ await expect(manager.save(checkpoint)).rejects.toThrow('Checkpoint save failed');
75
+ });
76
+ });
77
+
78
+ describe('load', () => {
79
+ it('should load checkpoint from cache', async () => {
80
+ const checkpoint: LoopCheckpoint = {
81
+ loopId: 'loop-1',
82
+ currentIndex: 5,
83
+ timestamp: Date.now(),
84
+ };
85
+
86
+ mockCache.get.mockResolvedValue(checkpoint);
87
+
88
+ const result = await manager.load('loop-1');
89
+
90
+ expect(result).toEqual(checkpoint);
91
+ expect(mockCache.get).toHaveBeenCalledWith('test-checkpoint:exec-123:loop-1');
92
+ });
93
+
94
+ it('should return null if checkpoint not found', async () => {
95
+ mockCache.get.mockResolvedValue(null);
96
+
97
+ const result = await manager.load('loop-1');
98
+
99
+ expect(result).toBeNull();
100
+ });
101
+
102
+ it('should convert completed array to Set', async () => {
103
+ const checkpoint = {
104
+ loopId: 'loop-1',
105
+ currentIndex: 5,
106
+ completed: [0, 1, 2],
107
+ timestamp: Date.now(),
108
+ };
109
+
110
+ mockCache.get.mockResolvedValue(checkpoint);
111
+
112
+ const result = await manager.load('loop-1');
113
+
114
+ expect(result).not.toBeNull();
115
+ expect(result!.completed).toBeInstanceOf(Set);
116
+ expect(result!.completed).toEqual(new Set([0, 1, 2]));
117
+ });
118
+
119
+ it('should throw CheckpointError on cache failure', async () => {
120
+ mockCache.get.mockRejectedValue(new Error('Cache error'));
121
+
122
+ await expect(manager.load('loop-1')).rejects.toThrow('Checkpoint load failed');
123
+ });
124
+ });
125
+
126
+ describe('clear', () => {
127
+ it('should clear checkpoint from cache', async () => {
128
+ await manager.clear('loop-1');
129
+
130
+ expect(mockCache.delete).toHaveBeenCalledWith('test-checkpoint:exec-123:loop-1');
131
+ });
132
+
133
+ it('should throw CheckpointError on cache failure', async () => {
134
+ mockCache.delete.mockRejectedValue(new Error('Cache error'));
135
+
136
+ await expect(manager.clear('loop-1')).rejects.toThrow('Checkpoint clear failed');
137
+ });
138
+ });
139
+
140
+ describe('getExecutionId', () => {
141
+ it('should return execution ID', () => {
142
+ expect(manager.getExecutionId()).toBe('exec-123');
143
+ });
144
+ });
145
+ });