@mondaydotcomorg/atp-compiler 0.20.0 → 0.21.0
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/__tests__/checkpoint-transformer.test.ts +295 -0
- package/__tests__/integration/checkpoint-integration.test.ts +638 -0
- package/dist/checkpoint/checkpoint-runtime.d.ts +110 -0
- package/dist/checkpoint/checkpoint-runtime.d.ts.map +1 -0
- package/dist/checkpoint/checkpoint-runtime.js +161 -0
- package/dist/checkpoint/checkpoint-runtime.js.map +1 -0
- package/dist/checkpoint/checkpoint-strategy.d.ts +39 -0
- package/dist/checkpoint/checkpoint-strategy.d.ts.map +1 -0
- package/dist/checkpoint/checkpoint-strategy.js +100 -0
- package/dist/checkpoint/checkpoint-strategy.js.map +1 -0
- package/dist/checkpoint/checkpoint-types.d.ts +205 -0
- package/dist/checkpoint/checkpoint-types.d.ts.map +1 -0
- package/dist/checkpoint/checkpoint-types.js +43 -0
- package/dist/checkpoint/checkpoint-types.js.map +1 -0
- package/dist/checkpoint/constants.d.ts +9 -0
- package/dist/checkpoint/constants.d.ts.map +1 -0
- package/dist/checkpoint/constants.js +13 -0
- package/dist/checkpoint/constants.js.map +1 -0
- package/dist/checkpoint/index.d.ts +11 -0
- package/dist/checkpoint/index.d.ts.map +1 -0
- package/dist/checkpoint/index.js +11 -0
- package/dist/checkpoint/index.js.map +1 -0
- package/dist/checkpoint/operation-checkpoint-manager.d.ts +199 -0
- package/dist/checkpoint/operation-checkpoint-manager.d.ts.map +1 -0
- package/dist/checkpoint/operation-checkpoint-manager.js +519 -0
- package/dist/checkpoint/operation-checkpoint-manager.js.map +1 -0
- package/dist/index.cjs +19878 -2731
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19854 -2731
- package/dist/index.js.map +1 -1
- package/dist/plugin-system/pluggable-compiler.d.ts.map +1 -1
- package/dist/plugin-system/pluggable-compiler.js +2 -0
- package/dist/plugin-system/pluggable-compiler.js.map +1 -1
- package/dist/transformer/checkpoint-transformer.d.ts +190 -0
- package/dist/transformer/checkpoint-transformer.d.ts.map +1 -0
- package/dist/transformer/checkpoint-transformer.js +707 -0
- package/dist/transformer/checkpoint-transformer.js.map +1 -0
- package/dist/transformer/index.d.ts +2 -0
- package/dist/transformer/index.d.ts.map +1 -1
- package/dist/transformer/index.js +56 -2
- package/dist/transformer/index.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +5 -5
- package/src/checkpoint/checkpoint-runtime.ts +295 -0
- package/src/checkpoint/checkpoint-strategy.ts +125 -0
- package/src/checkpoint/checkpoint-types.ts +237 -0
- package/src/checkpoint/constants.ts +17 -0
- package/src/checkpoint/index.ts +11 -0
- package/src/checkpoint/operation-checkpoint-manager.ts +674 -0
- package/src/index.ts +21 -0
- package/src/plugin-system/pluggable-compiler.ts +2 -0
- package/src/transformer/checkpoint-transformer.ts +929 -0
- package/src/transformer/index.ts +63 -3
- package/src/types.ts +7 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for OperationCheckpointTransformer
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach } from '@jest/globals';
|
|
6
|
+
import { parse } from '@babel/parser';
|
|
7
|
+
import _traverse from '@babel/traverse';
|
|
8
|
+
const traverse = (_traverse as any).default || _traverse;
|
|
9
|
+
import _generate from '@babel/generator';
|
|
10
|
+
const generate = (_generate as any).default || _generate;
|
|
11
|
+
import {
|
|
12
|
+
OperationCheckpointTransformer,
|
|
13
|
+
CHECKPOINTABLE_PATTERNS,
|
|
14
|
+
isCheckpointableCall,
|
|
15
|
+
getOperationType,
|
|
16
|
+
} from '../src/transformer/checkpoint-transformer.js';
|
|
17
|
+
import { OperationType } from '../src/checkpoint/checkpoint-types.js';
|
|
18
|
+
|
|
19
|
+
function parseAndTransform(code: string, transformer: OperationCheckpointTransformer): string {
|
|
20
|
+
const ast = parse(code, {
|
|
21
|
+
sourceType: 'module',
|
|
22
|
+
plugins: ['typescript'],
|
|
23
|
+
allowAwaitOutsideFunction: true,
|
|
24
|
+
allowReturnOutsideFunction: true,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
traverse(ast, {
|
|
28
|
+
AwaitExpression: (path: any) => {
|
|
29
|
+
transformer.transformAwaitExpression(path);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return generate(ast).code;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('OperationCheckpointTransformer', () => {
|
|
37
|
+
let transformer: OperationCheckpointTransformer;
|
|
38
|
+
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
transformer = new OperationCheckpointTransformer();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('transformAwaitExpression', () => {
|
|
44
|
+
it('should transform atp.api calls', () => {
|
|
45
|
+
const code = `const user = await atp.api.github.getUser({ id: 123 });`;
|
|
46
|
+
const result = parseAndTransform(code, transformer);
|
|
47
|
+
|
|
48
|
+
expect(result).toContain('__checkpoint.buffer');
|
|
49
|
+
expect(result).toContain('async () =>');
|
|
50
|
+
expect(result).toContain('atp.api.github.getUser');
|
|
51
|
+
expect(transformer.getTransformCount()).toBe(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should transform atp.llm calls', () => {
|
|
55
|
+
const code = `const response = await atp.llm.call({ prompt: "hello" });`;
|
|
56
|
+
const result = parseAndTransform(code, transformer);
|
|
57
|
+
|
|
58
|
+
expect(result).toContain('__checkpoint.buffer');
|
|
59
|
+
expect(result).toContain('atp.llm.call');
|
|
60
|
+
expect(transformer.getTransformCount()).toBe(1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should transform atp.embedding calls', () => {
|
|
64
|
+
const code = `const embedding = await atp.embedding.embed("text");`;
|
|
65
|
+
const result = parseAndTransform(code, transformer);
|
|
66
|
+
|
|
67
|
+
expect(result).toContain('__checkpoint.buffer');
|
|
68
|
+
expect(result).toContain('atp.embedding.embed');
|
|
69
|
+
expect(transformer.getTransformCount()).toBe(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should transform atp.client calls', () => {
|
|
73
|
+
const code = `const result = await atp.client.myTool({ data: "test" });`;
|
|
74
|
+
const result = parseAndTransform(code, transformer);
|
|
75
|
+
|
|
76
|
+
expect(result).toContain('__checkpoint.buffer');
|
|
77
|
+
expect(result).toContain('atp.client.myTool');
|
|
78
|
+
expect(transformer.getTransformCount()).toBe(1);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should NOT transform non-atp calls', () => {
|
|
82
|
+
const code = `const data = await fetch("https://api.example.com");`;
|
|
83
|
+
const result = parseAndTransform(code, transformer);
|
|
84
|
+
|
|
85
|
+
expect(result).not.toContain('__checkpoint.buffer');
|
|
86
|
+
expect(transformer.getTransformCount()).toBe(0);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should NOT transform atp.cache calls (not checkpointable)', () => {
|
|
90
|
+
const code = `const cached = await atp.cache.get("key");`;
|
|
91
|
+
const result = parseAndTransform(code, transformer);
|
|
92
|
+
|
|
93
|
+
expect(result).not.toContain('__checkpoint.buffer');
|
|
94
|
+
expect(transformer.getTransformCount()).toBe(0);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should transform multiple operations', () => {
|
|
98
|
+
const code = `
|
|
99
|
+
const user = await atp.api.users.get({ id: 1 });
|
|
100
|
+
const repos = await atp.api.github.listRepos({ user: user.id });
|
|
101
|
+
const summary = await atp.llm.call({ prompt: "summarize" });
|
|
102
|
+
`;
|
|
103
|
+
const result = parseAndTransform(code, transformer);
|
|
104
|
+
|
|
105
|
+
expect(result).toContain('__checkpoint.buffer');
|
|
106
|
+
expect(transformer.getTransformCount()).toBe(3);
|
|
107
|
+
expect(transformer.getCheckpointIds()).toHaveLength(3);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should generate deterministic checkpoint IDs based on location', () => {
|
|
111
|
+
const code = `const user = await atp.api.users.get({ id: 1 });`;
|
|
112
|
+
parseAndTransform(code, transformer);
|
|
113
|
+
|
|
114
|
+
const ids = transformer.getCheckpointIds();
|
|
115
|
+
expect(ids).toHaveLength(1);
|
|
116
|
+
// ID should contain line and column info
|
|
117
|
+
expect(ids[0]).toMatch(/op_L\d+_C\d+/);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should include metadata in transformed code', () => {
|
|
121
|
+
const code = `const user = await atp.api.github.getUser({ id: 123 });`;
|
|
122
|
+
const result = parseAndTransform(code, transformer);
|
|
123
|
+
|
|
124
|
+
// Check that metadata is present
|
|
125
|
+
expect(result).toContain('type:');
|
|
126
|
+
expect(result).toContain('"api"');
|
|
127
|
+
expect(result).toContain('namespace:');
|
|
128
|
+
expect(result).toContain('"atp"');
|
|
129
|
+
expect(result).toContain('group:');
|
|
130
|
+
expect(result).toContain('"api.github"');
|
|
131
|
+
expect(result).toContain('method:');
|
|
132
|
+
expect(result).toContain('"getUser"');
|
|
133
|
+
expect(result).toContain('params:');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should handle nested member expressions', () => {
|
|
137
|
+
const code = `const data = await atp.api.v2.users.admin.get({ id: 1 });`;
|
|
138
|
+
const result = parseAndTransform(code, transformer);
|
|
139
|
+
|
|
140
|
+
expect(result).toContain('__checkpoint.buffer');
|
|
141
|
+
expect(result).toContain('"api.v2.users.admin"'); // group
|
|
142
|
+
expect(result).toContain('"get"'); // method
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should handle calls without arguments', () => {
|
|
146
|
+
const code = `const list = await atp.api.users.list();`;
|
|
147
|
+
const result = parseAndTransform(code, transformer);
|
|
148
|
+
|
|
149
|
+
expect(result).toContain('__checkpoint.buffer');
|
|
150
|
+
expect(result).toContain('params: {}');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should handle non-object arguments', () => {
|
|
154
|
+
const code = `const user = await atp.api.users.get(userId);`;
|
|
155
|
+
const result = parseAndTransform(code, transformer);
|
|
156
|
+
|
|
157
|
+
expect(result).toContain('__checkpoint.buffer');
|
|
158
|
+
expect(result).toContain('params:');
|
|
159
|
+
expect(result).toContain('arg:'); // wrapped in arg property
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('isCheckpointable', () => {
|
|
164
|
+
it('should return true for checkpointable patterns', () => {
|
|
165
|
+
const ast = parse(`await atp.api.test();`, {
|
|
166
|
+
sourceType: 'module',
|
|
167
|
+
allowAwaitOutsideFunction: true,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
let awaitNode: any = null;
|
|
171
|
+
traverse(ast, {
|
|
172
|
+
AwaitExpression: (path: any) => {
|
|
173
|
+
awaitNode = path.node;
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
expect(transformer.isCheckpointable(awaitNode)).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should return false for non-checkpointable patterns', () => {
|
|
181
|
+
const ast = parse(`await someOtherCall();`, {
|
|
182
|
+
sourceType: 'module',
|
|
183
|
+
allowAwaitOutsideFunction: true,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
let awaitNode: any = null;
|
|
187
|
+
traverse(ast, {
|
|
188
|
+
AwaitExpression: (path: any) => {
|
|
189
|
+
awaitNode = path.node;
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(transformer.isCheckpointable(awaitNode)).toBe(false);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe('reset', () => {
|
|
198
|
+
it('should reset transformer state', () => {
|
|
199
|
+
const code = `const user = await atp.api.users.get({ id: 1 });`;
|
|
200
|
+
parseAndTransform(code, transformer);
|
|
201
|
+
|
|
202
|
+
expect(transformer.getTransformCount()).toBe(1);
|
|
203
|
+
expect(transformer.getCheckpointIds()).toHaveLength(1);
|
|
204
|
+
|
|
205
|
+
transformer.reset();
|
|
206
|
+
|
|
207
|
+
expect(transformer.getTransformCount()).toBe(0);
|
|
208
|
+
expect(transformer.getCheckpointIds()).toHaveLength(0);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('getResult', () => {
|
|
213
|
+
it('should return transformation result', () => {
|
|
214
|
+
const code = `
|
|
215
|
+
const a = await atp.api.test1();
|
|
216
|
+
const b = await atp.api.test2();
|
|
217
|
+
`;
|
|
218
|
+
parseAndTransform(code, transformer);
|
|
219
|
+
|
|
220
|
+
const result = transformer.getResult();
|
|
221
|
+
|
|
222
|
+
expect(result.transformCount).toBe(2);
|
|
223
|
+
expect(result.checkpointIds).toHaveLength(2);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe('Utility functions', () => {
|
|
229
|
+
describe('isCheckpointableCall', () => {
|
|
230
|
+
it('should return true for atp.api paths', () => {
|
|
231
|
+
expect(isCheckpointableCall('atp.api.users.get')).toBe(true);
|
|
232
|
+
expect(isCheckpointableCall('atp.api.github.repos.list')).toBe(true);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should return true for atp.llm paths', () => {
|
|
236
|
+
expect(isCheckpointableCall('atp.llm.call')).toBe(true);
|
|
237
|
+
expect(isCheckpointableCall('atp.llm.extract')).toBe(true);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should return true for atp.embedding paths', () => {
|
|
241
|
+
expect(isCheckpointableCall('atp.embedding.embed')).toBe(true);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should return true for atp.client paths', () => {
|
|
245
|
+
expect(isCheckpointableCall('atp.client.myTool')).toBe(true);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should return false for non-checkpointable paths', () => {
|
|
249
|
+
expect(isCheckpointableCall('atp.cache.get')).toBe(false);
|
|
250
|
+
expect(isCheckpointableCall('atp.log.info')).toBe(false);
|
|
251
|
+
expect(isCheckpointableCall('fetch')).toBe(false);
|
|
252
|
+
expect(isCheckpointableCall('console.log')).toBe(false);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should return false for partial matches', () => {
|
|
256
|
+
// Should not match just "atp.api" without a method
|
|
257
|
+
expect(isCheckpointableCall('atp.api')).toBe(false);
|
|
258
|
+
expect(isCheckpointableCall('atp')).toBe(false);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe('getOperationType', () => {
|
|
263
|
+
it('should return correct operation type for each pattern', () => {
|
|
264
|
+
expect(getOperationType('atp.api.users.get')).toBe('api');
|
|
265
|
+
expect(getOperationType('atp.llm.call')).toBe('llm');
|
|
266
|
+
expect(getOperationType('atp.embedding.embed')).toBe('embedding');
|
|
267
|
+
expect(getOperationType('atp.client.myTool')).toBe('client_tool');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should return null for non-checkpointable paths', () => {
|
|
271
|
+
expect(getOperationType('atp.cache.get')).toBeNull();
|
|
272
|
+
expect(getOperationType('fetch')).toBeNull();
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe('CHECKPOINTABLE_PATTERNS', () => {
|
|
278
|
+
it('should include expected patterns', () => {
|
|
279
|
+
const namespaces = CHECKPOINTABLE_PATTERNS.map((p) => p.namespacePrefix);
|
|
280
|
+
|
|
281
|
+
expect(namespaces).toContain('atp.api');
|
|
282
|
+
expect(namespaces).toContain('atp.llm');
|
|
283
|
+
expect(namespaces).toContain('atp.embedding');
|
|
284
|
+
expect(namespaces).toContain('atp.client');
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should map to correct operation types', () => {
|
|
288
|
+
const apiPattern = CHECKPOINTABLE_PATTERNS.find((p) => p.namespacePrefix === 'atp.api');
|
|
289
|
+
const llmPattern = CHECKPOINTABLE_PATTERNS.find((p) => p.namespacePrefix === 'atp.llm');
|
|
290
|
+
|
|
291
|
+
expect(apiPattern?.operationType).toBe('api');
|
|
292
|
+
expect(llmPattern?.operationType).toBe('llm');
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|