@mondaydotcomorg/atp-server 0.21.6 → 0.23.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/dist/executor/compiler-config.d.ts +2 -1
- package/dist/executor/compiler-config.d.ts.map +1 -1
- package/dist/executor/compiler-config.js +18 -4
- package/dist/executor/compiler-config.js.map +1 -1
- package/dist/executor/execution-error-handler.d.ts +1 -1
- package/dist/executor/execution-error-handler.d.ts.map +1 -1
- package/dist/executor/execution-error-handler.js +32 -2
- package/dist/executor/execution-error-handler.js.map +1 -1
- package/dist/executor/executor.d.ts.map +1 -1
- package/dist/executor/executor.js +87 -19
- package/dist/executor/executor.js.map +1 -1
- package/dist/executor/sandbox-injector.d.ts +1 -0
- package/dist/executor/sandbox-injector.d.ts.map +1 -1
- package/dist/executor/sandbox-injector.js +60 -9
- package/dist/executor/sandbox-injector.js.map +1 -1
- package/dist/index.cjs +169 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +171 -27
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/executor/compiler-config.ts +35 -7
- package/src/executor/execution-error-handler.ts +38 -5
- package/src/executor/executor.ts +127 -32
- package/src/executor/sandbox-injector.ts +75 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mondaydotcomorg/atp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Server implementation for Agent Tool Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"@babel/parser": "^7.26.0",
|
|
50
50
|
"@babel/traverse": "^7.26.0",
|
|
51
51
|
"@babel/types": "^7.26.0",
|
|
52
|
-
"@mondaydotcomorg/atp-compiler": "0.
|
|
53
|
-
"@mondaydotcomorg/atp-protocol": "0.
|
|
54
|
-
"@mondaydotcomorg/atp-provenance": "0.
|
|
55
|
-
"@mondaydotcomorg/atp-providers": "0.
|
|
56
|
-
"@mondaydotcomorg/atp-runtime": "0.
|
|
52
|
+
"@mondaydotcomorg/atp-compiler": "0.21.0",
|
|
53
|
+
"@mondaydotcomorg/atp-protocol": "0.21.0",
|
|
54
|
+
"@mondaydotcomorg/atp-provenance": "0.21.0",
|
|
55
|
+
"@mondaydotcomorg/atp-providers": "0.21.0",
|
|
56
|
+
"@mondaydotcomorg/atp-runtime": "0.21.0",
|
|
57
57
|
"@opentelemetry/api": "^1.9.0",
|
|
58
58
|
"@opentelemetry/auto-instrumentations-node": "^0.66.0",
|
|
59
59
|
"@opentelemetry/core": "^2.2.0",
|
|
@@ -18,10 +18,15 @@ import {
|
|
|
18
18
|
resumablePromiseAll,
|
|
19
19
|
resumablePromiseAllSettled,
|
|
20
20
|
batchParallel,
|
|
21
|
+
initializeCheckpointRuntime,
|
|
22
|
+
initializeCheckpointRuntimeWithProvenance,
|
|
23
|
+
cleanupCheckpointRuntime,
|
|
24
|
+
getCheckpointRuntime,
|
|
25
|
+
getCheckpointDataForError,
|
|
21
26
|
type TransformResult,
|
|
22
27
|
type DetectionResult,
|
|
23
28
|
type ICompiler,
|
|
24
|
-
type
|
|
29
|
+
type CheckpointProvenanceMetadata,
|
|
25
30
|
} from '@mondaydotcomorg/atp-compiler';
|
|
26
31
|
import { ATP_COMPILER_ENABLED, ATP_BATCH_SIZE_THRESHOLD } from './constants.js';
|
|
27
32
|
|
|
@@ -31,8 +36,11 @@ import { ATP_COMPILER_ENABLED, ATP_BATCH_SIZE_THRESHOLD } from './constants.js';
|
|
|
31
36
|
class ATPCompilerAdapter implements ICompiler {
|
|
32
37
|
private compiler: ATPCompiler;
|
|
33
38
|
|
|
34
|
-
constructor(config: { enableBatchParallel: boolean; batchSizeThreshold: number }) {
|
|
35
|
-
this.compiler = new ATPCompiler(
|
|
39
|
+
constructor(config: { enableBatchParallel: boolean; batchSizeThreshold: number; enableOperationCheckpoints?: boolean }) {
|
|
40
|
+
this.compiler = new ATPCompiler({
|
|
41
|
+
...config,
|
|
42
|
+
enableOperationCheckpoints: config.enableOperationCheckpoints ?? true,
|
|
43
|
+
});
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
detect(code: string): DetectionResult {
|
|
@@ -58,8 +66,11 @@ class ATPCompilerAdapter implements ICompiler {
|
|
|
58
66
|
class PluggableCompilerAdapter implements ICompiler {
|
|
59
67
|
private compiler: ReturnType<typeof createDefaultCompiler>;
|
|
60
68
|
|
|
61
|
-
constructor(config: { enableBatchParallel: boolean; batchSizeThreshold: number }) {
|
|
62
|
-
this.compiler = createDefaultCompiler(
|
|
69
|
+
constructor(config: { enableBatchParallel: boolean; batchSizeThreshold: number; enableOperationCheckpoints?: boolean }) {
|
|
70
|
+
this.compiler = createDefaultCompiler({
|
|
71
|
+
...config,
|
|
72
|
+
enableOperationCheckpoints: config.enableOperationCheckpoints ?? true,
|
|
73
|
+
});
|
|
63
74
|
}
|
|
64
75
|
|
|
65
76
|
async detect(code: string): Promise<DetectionResult> {
|
|
@@ -84,7 +95,7 @@ class PluggableCompilerAdapter implements ICompiler {
|
|
|
84
95
|
* This is where you can easily add new compiler types
|
|
85
96
|
*/
|
|
86
97
|
class CompilerFactory {
|
|
87
|
-
static create(config: { enableBatchParallel: boolean; batchSizeThreshold: number }): ICompiler {
|
|
98
|
+
static create(config: { enableBatchParallel: boolean; batchSizeThreshold: number; enableOperationCheckpoints?: boolean }): ICompiler {
|
|
88
99
|
const compilerType = process.env.ATP_USE_PLUGGABLE_COMPILER === 'true' ? 'pluggable' : 'atp';
|
|
89
100
|
|
|
90
101
|
switch (compilerType) {
|
|
@@ -173,6 +184,16 @@ export function getCompilerRuntime() {
|
|
|
173
184
|
};
|
|
174
185
|
}
|
|
175
186
|
|
|
187
|
+
// Re-export checkpoint functions for executor use
|
|
188
|
+
export {
|
|
189
|
+
initializeCheckpointRuntime,
|
|
190
|
+
initializeCheckpointRuntimeWithProvenance,
|
|
191
|
+
cleanupCheckpointRuntime,
|
|
192
|
+
getCheckpointRuntime,
|
|
193
|
+
getCheckpointDataForError,
|
|
194
|
+
type CheckpointProvenanceMetadata,
|
|
195
|
+
};
|
|
196
|
+
|
|
176
197
|
export async function transformCodeWithCompiler(
|
|
177
198
|
code: string,
|
|
178
199
|
executionId: string,
|
|
@@ -202,13 +223,19 @@ export async function transformCodeWithCompiler(
|
|
|
202
223
|
// Detect patterns (abstracted sync/async handling)
|
|
203
224
|
const detection = await compiler.detect(code);
|
|
204
225
|
|
|
226
|
+
// With enableOperationCheckpoints, we always need to transform to wrap API calls
|
|
227
|
+
const enableCheckpoints = process.env.ATP_DISABLE_CHECKPOINTS !== 'true';
|
|
228
|
+
const needsTransform = detection.needsTransform || enableCheckpoints;
|
|
229
|
+
|
|
205
230
|
executionLogger.info('ATP Compiler detection result', {
|
|
206
231
|
needsTransform: detection.needsTransform,
|
|
207
232
|
patterns: detection.patterns,
|
|
208
233
|
batchable: detection.batchableParallel,
|
|
234
|
+
checkpointsEnabled: enableCheckpoints,
|
|
235
|
+
willTransform: needsTransform,
|
|
209
236
|
});
|
|
210
237
|
|
|
211
|
-
if (
|
|
238
|
+
if (needsTransform) {
|
|
212
239
|
const codeHash = getCodeHash(code);
|
|
213
240
|
const cached = transformCache.get(codeHash);
|
|
214
241
|
if (cached) {
|
|
@@ -244,6 +271,7 @@ export async function transformCodeWithCompiler(
|
|
|
244
271
|
loopCount: transformed.metadata.loopCount,
|
|
245
272
|
arrayMethodCount: transformed.metadata.arrayMethodCount,
|
|
246
273
|
parallelCallCount: transformed.metadata.parallelCallCount,
|
|
274
|
+
checkpointCount: transformed.metadata.checkpointCount,
|
|
247
275
|
batchSizeThreshold: ATP_BATCH_SIZE_THRESHOLD,
|
|
248
276
|
};
|
|
249
277
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ivm from 'isolated-vm';
|
|
2
2
|
import { ExecutionStatus } from '@mondaydotcomorg/atp-protocol';
|
|
3
|
-
import type { ExecutionResult } from '@mondaydotcomorg/atp-protocol';
|
|
3
|
+
import type { ExecutionResult, ExecutionCheckpointData } from '@mondaydotcomorg/atp-protocol';
|
|
4
4
|
import type { Logger } from '@mondaydotcomorg/atp-runtime';
|
|
5
5
|
import {
|
|
6
6
|
isPauseError,
|
|
@@ -10,17 +10,20 @@ import {
|
|
|
10
10
|
getAPICallResults,
|
|
11
11
|
clearAPICallResults,
|
|
12
12
|
setCurrentExecutionId,
|
|
13
|
-
clearCurrentExecutionId,
|
|
14
13
|
type PauseExecutionError,
|
|
15
14
|
} from '@mondaydotcomorg/atp-runtime';
|
|
16
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
isBatchPauseError,
|
|
17
|
+
getCheckpointDataForError,
|
|
18
|
+
type BatchPauseExecutionError,
|
|
19
|
+
} from '@mondaydotcomorg/atp-compiler';
|
|
17
20
|
import { randomUUID } from 'node:crypto';
|
|
18
21
|
import type { CallbackRecord } from '../execution-state/index.js';
|
|
19
22
|
import type { RuntimeContext } from './types.js';
|
|
20
23
|
import { categorizeError } from './error-handler.js';
|
|
21
24
|
import { PAUSE_EXECUTION_MARKER } from './constants.js';
|
|
22
25
|
|
|
23
|
-
export function handleExecutionError(
|
|
26
|
+
export async function handleExecutionError(
|
|
24
27
|
error: unknown,
|
|
25
28
|
pauseError: unknown,
|
|
26
29
|
context: RuntimeContext,
|
|
@@ -30,7 +33,7 @@ export function handleExecutionError(
|
|
|
30
33
|
executionLogger: Logger,
|
|
31
34
|
isolate: ivm.Isolate,
|
|
32
35
|
transformedCode?: string
|
|
33
|
-
): ExecutionResult {
|
|
36
|
+
): Promise<ExecutionResult> {
|
|
34
37
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
35
38
|
|
|
36
39
|
if (errMsg.includes(PAUSE_EXECUTION_MARKER) && pauseError) {
|
|
@@ -192,6 +195,35 @@ export function handleExecutionError(
|
|
|
192
195
|
const memoryAfter = process.memoryUsage().heapUsed;
|
|
193
196
|
const memoryUsed = Math.max(0, memoryAfter - memoryBefore);
|
|
194
197
|
|
|
198
|
+
// Collect checkpoint data if available
|
|
199
|
+
// This also flushes buffered checkpoints to cache for recovery
|
|
200
|
+
let checkpointData: ExecutionCheckpointData | undefined;
|
|
201
|
+
try {
|
|
202
|
+
const rawCheckpointData = await getCheckpointDataForError();
|
|
203
|
+
if (rawCheckpointData && rawCheckpointData.checkpoints.length > 0) {
|
|
204
|
+
checkpointData = {
|
|
205
|
+
checkpoints: rawCheckpointData.checkpoints.map((cp) => ({
|
|
206
|
+
id: cp.id,
|
|
207
|
+
type: cp.type,
|
|
208
|
+
operation: cp.operation,
|
|
209
|
+
description: cp.description,
|
|
210
|
+
timestamp: cp.timestamp,
|
|
211
|
+
})),
|
|
212
|
+
restoreInstructions: rawCheckpointData.restoreInstructions,
|
|
213
|
+
stats: rawCheckpointData.stats,
|
|
214
|
+
};
|
|
215
|
+
executionLogger.info('Checkpoint data included in error response', {
|
|
216
|
+
checkpointCount: checkpointData.checkpoints.length,
|
|
217
|
+
fullSnapshots: checkpointData.stats.fullSnapshots,
|
|
218
|
+
references: checkpointData.stats.references,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
} catch (checkpointError) {
|
|
222
|
+
executionLogger.debug('No checkpoint data available', {
|
|
223
|
+
reason: checkpointError instanceof Error ? checkpointError.message : String(checkpointError),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
195
227
|
try {
|
|
196
228
|
isolate.dispose();
|
|
197
229
|
} catch (e) {}
|
|
@@ -208,6 +240,7 @@ export function handleExecutionError(
|
|
|
208
240
|
stack: err.stack,
|
|
209
241
|
retryable: errorInfo.retryable,
|
|
210
242
|
suggestion: errorInfo.suggestion,
|
|
243
|
+
checkpointData,
|
|
211
244
|
},
|
|
212
245
|
stats: {
|
|
213
246
|
duration: Date.now() - context.startTime,
|
package/src/executor/executor.ts
CHANGED
|
@@ -28,24 +28,38 @@ import type { ExecutorConfig, RuntimeContext } from './types.js';
|
|
|
28
28
|
import { SandboxBuilder } from './sandbox-builder.js';
|
|
29
29
|
import { CodeInstrumentor, StateManager } from '../instrumentation/index.js';
|
|
30
30
|
import { ATP_COMPILER_ENABLED } from './constants.js';
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
getCompilerRuntime,
|
|
33
|
+
transformCodeWithCompiler,
|
|
34
|
+
initializeCheckpointRuntime,
|
|
35
|
+
initializeCheckpointRuntimeWithProvenance,
|
|
36
|
+
cleanupCheckpointRuntime,
|
|
37
|
+
getCheckpointRuntime,
|
|
38
|
+
type CheckpointProvenanceMetadata,
|
|
39
|
+
} from './compiler-config.js';
|
|
32
40
|
import { setupResumeExecution } from './resume-handler.js';
|
|
33
41
|
import {
|
|
34
42
|
injectSandbox,
|
|
35
43
|
injectTimerPolyfills,
|
|
36
44
|
setupAPINamespace,
|
|
37
45
|
setupRuntimeNamespace,
|
|
46
|
+
setupCheckpointNamespace,
|
|
38
47
|
} from './sandbox-injector.js';
|
|
39
48
|
import { handleExecutionError } from './execution-error-handler.js';
|
|
40
49
|
import {
|
|
50
|
+
attachProvenanceMetaForCheckpoint,
|
|
41
51
|
captureProvenanceSnapshot,
|
|
42
52
|
cleanupProvenanceForExecution,
|
|
43
53
|
clearProvenanceExecutionId,
|
|
54
|
+
createProvenanceProxy,
|
|
44
55
|
createTrackingRuntime,
|
|
56
|
+
getProvenance,
|
|
57
|
+
getAllProvenance,
|
|
45
58
|
instrumentCode as astInstrumentCode,
|
|
46
59
|
registerProvenanceMetadata,
|
|
47
60
|
SecurityPolicyEngine,
|
|
48
61
|
setProvenanceExecutionId,
|
|
62
|
+
type ProvenanceMetadata,
|
|
49
63
|
} from '@mondaydotcomorg/atp-provenance';
|
|
50
64
|
import {
|
|
51
65
|
createASTProvenanceChecker,
|
|
@@ -297,11 +311,72 @@ export class SandboxExecutor {
|
|
|
297
311
|
};
|
|
298
312
|
}
|
|
299
313
|
|
|
300
|
-
|
|
301
|
-
|
|
314
|
+
if (ATP_COMPILER_ENABLED) {
|
|
315
|
+
sandbox.__runtime = getCompilerRuntime();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Initialize checkpoint runtime if cache provider is available
|
|
319
|
+
if (this.config.cacheProvider) {
|
|
320
|
+
if (provenanceMode !== ProvenanceMode.NONE) {
|
|
321
|
+
// Provenance-aware checkpoint initialization
|
|
322
|
+
initializeCheckpointRuntimeWithProvenance({
|
|
323
|
+
executionId,
|
|
324
|
+
cache: this.config.cacheProvider,
|
|
325
|
+
config: { enabled: true },
|
|
326
|
+
provenanceMetaAttacher: attachProvenanceMetaForCheckpoint,
|
|
327
|
+
provenanceExtractor: (value: unknown) => {
|
|
328
|
+
// Just return ProvenanceMetadata as-is - types are now compatible
|
|
329
|
+
return getProvenance(value);
|
|
330
|
+
},
|
|
331
|
+
provenanceAttacher: (
|
|
332
|
+
value: unknown,
|
|
333
|
+
metadata,
|
|
334
|
+
primitives?
|
|
335
|
+
): unknown => {
|
|
336
|
+
// Skip null values (primitive registration calls)
|
|
337
|
+
if (value === null) {
|
|
338
|
+
// Re-register primitive taints if present
|
|
339
|
+
if (primitives) {
|
|
340
|
+
for (const [key, primMeta] of primitives) {
|
|
341
|
+
registerProvenanceMetadata(key, primMeta, executionId);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Re-attach provenance to restored value using the metadata as-is
|
|
348
|
+
const restored = createProvenanceProxy(
|
|
349
|
+
value,
|
|
350
|
+
metadata.source,
|
|
351
|
+
metadata.readers,
|
|
352
|
+
metadata.dependencies
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
// Re-register primitive taints if present
|
|
356
|
+
if (primitives) {
|
|
357
|
+
for (const [key, primMeta] of primitives) {
|
|
358
|
+
registerProvenanceMetadata(key, primMeta, executionId);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return restored;
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
executionLogger.debug('Checkpoint runtime initialized with provenance integration', {
|
|
366
|
+
provenanceMode,
|
|
367
|
+
});
|
|
368
|
+
} else {
|
|
369
|
+
// Standard checkpoint initialization (no provenance)
|
|
370
|
+
initializeCheckpointRuntime({
|
|
371
|
+
executionId,
|
|
372
|
+
cache: this.config.cacheProvider,
|
|
373
|
+
config: { enabled: true },
|
|
374
|
+
});
|
|
302
375
|
}
|
|
376
|
+
sandbox.__checkpoint = getCheckpointRuntime();
|
|
377
|
+
}
|
|
303
378
|
|
|
304
|
-
|
|
379
|
+
let hintMetadata: Map<string, any> | undefined;
|
|
305
380
|
if (provenanceMode === ProvenanceMode.AST) {
|
|
306
381
|
hintMetadata = getHintMap(executionId);
|
|
307
382
|
|
|
@@ -336,11 +411,16 @@ export class SandboxExecutor {
|
|
|
336
411
|
|
|
337
412
|
await setupAPINamespace(ivmContext, sandbox, provenanceMode);
|
|
338
413
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
414
|
+
if (ATP_COMPILER_ENABLED) {
|
|
415
|
+
await setupRuntimeNamespace(ivmContext, sandbox);
|
|
416
|
+
}
|
|
342
417
|
|
|
343
|
-
|
|
418
|
+
// Setup checkpoint namespace if available
|
|
419
|
+
if (this.config.cacheProvider) {
|
|
420
|
+
await setupCheckpointNamespace(ivmContext, sandbox);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
let useCompiler = false;
|
|
344
424
|
let astInstrumented = false;
|
|
345
425
|
|
|
346
426
|
const isResume = resumeData !== undefined;
|
|
@@ -366,13 +446,44 @@ export class SandboxExecutor {
|
|
|
366
446
|
codePreview: code.substring(0, 100),
|
|
367
447
|
});
|
|
368
448
|
|
|
369
|
-
|
|
449
|
+
// STEP 1: Checkpoint transformation FIRST (before AST instrumentation)
|
|
450
|
+
// This ensures checkpoints are tracked even in AST provenance mode
|
|
451
|
+
if (
|
|
452
|
+
ATP_COMPILER_ENABLED &&
|
|
453
|
+
this.config.cacheProvider &&
|
|
454
|
+
!alreadyTransformed
|
|
455
|
+
) {
|
|
456
|
+
const compilerResult = await transformCodeWithCompiler(
|
|
457
|
+
code,
|
|
458
|
+
executionId,
|
|
459
|
+
this.config.cacheProvider,
|
|
460
|
+
executionLogger,
|
|
461
|
+
this.compiler
|
|
462
|
+
);
|
|
463
|
+
codeToExecute = compilerResult.code;
|
|
464
|
+
useCompiler = compilerResult.useCompiler;
|
|
465
|
+
executionLogger.debug('Checkpoint transformation applied', {
|
|
466
|
+
useCompiler,
|
|
467
|
+
originalLength: code.length,
|
|
468
|
+
transformedLength: codeToExecute.length,
|
|
469
|
+
});
|
|
470
|
+
} else if (alreadyTransformed) {
|
|
471
|
+
codeToExecute = code;
|
|
472
|
+
useCompiler = true;
|
|
473
|
+
executionLogger.debug('Using already-transformed code on resume');
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// STEP 2: AST instrumentation AFTER checkpoint transformation
|
|
477
|
+
// This ensures provenance tracking works with checkpoint-wrapped code
|
|
478
|
+
if (provenanceMode === ProvenanceMode.AST && !alreadyTransformed) {
|
|
370
479
|
try {
|
|
371
|
-
|
|
480
|
+
// Instrument the (potentially checkpoint-transformed) code
|
|
481
|
+
const instrumentResult = astInstrumentCode(codeToExecute);
|
|
372
482
|
codeToExecute = instrumentResult.code;
|
|
373
483
|
astInstrumented = true;
|
|
374
484
|
executionLogger.info('Code instrumented for provenance tracking (AST mode)', {
|
|
375
485
|
trackingCalls: instrumentResult.metadata.trackingCalls,
|
|
486
|
+
checkpointsPreserved: useCompiler,
|
|
376
487
|
instrumentedCodeStart: codeToExecute.substring(0, 150),
|
|
377
488
|
instrumentedCodeEnd: codeToExecute.substring(codeToExecute.length - 150),
|
|
378
489
|
});
|
|
@@ -402,27 +513,6 @@ export class SandboxExecutor {
|
|
|
402
513
|
}
|
|
403
514
|
}
|
|
404
515
|
|
|
405
|
-
if (
|
|
406
|
-
ATP_COMPILER_ENABLED &&
|
|
407
|
-
this.config.cacheProvider &&
|
|
408
|
-
!astInstrumented &&
|
|
409
|
-
!alreadyTransformed
|
|
410
|
-
) {
|
|
411
|
-
const compilerResult = await transformCodeWithCompiler(
|
|
412
|
-
code,
|
|
413
|
-
executionId,
|
|
414
|
-
this.config.cacheProvider,
|
|
415
|
-
executionLogger,
|
|
416
|
-
this.compiler
|
|
417
|
-
);
|
|
418
|
-
codeToExecute = compilerResult.code;
|
|
419
|
-
useCompiler = compilerResult.useCompiler;
|
|
420
|
-
} else if (alreadyTransformed) {
|
|
421
|
-
codeToExecute = code;
|
|
422
|
-
useCompiler = true;
|
|
423
|
-
executionLogger.debug('Using already-transformed code on resume');
|
|
424
|
-
}
|
|
425
|
-
|
|
426
516
|
if (!useCompiler && !astInstrumented && stateManager) {
|
|
427
517
|
try {
|
|
428
518
|
const instrumentor = new CodeInstrumentor();
|
|
@@ -580,7 +670,7 @@ export class SandboxExecutor {
|
|
|
580
670
|
}
|
|
581
671
|
}
|
|
582
672
|
|
|
583
|
-
return handleExecutionError(
|
|
673
|
+
return await handleExecutionError(
|
|
584
674
|
error,
|
|
585
675
|
pauseError,
|
|
586
676
|
context,
|
|
@@ -643,6 +733,11 @@ export class SandboxExecutor {
|
|
|
643
733
|
|
|
644
734
|
clearVectorStoreExecutionId();
|
|
645
735
|
|
|
736
|
+
// Cleanup checkpoint runtime
|
|
737
|
+
try {
|
|
738
|
+
cleanupCheckpointRuntime();
|
|
739
|
+
} catch (e) {}
|
|
740
|
+
|
|
646
741
|
if (executionId) {
|
|
647
742
|
try {
|
|
648
743
|
cleanupExecutionState(executionId);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ivm from 'isolated-vm';
|
|
2
2
|
import type { Logger } from '@mondaydotcomorg/atp-runtime';
|
|
3
3
|
import { isPauseError, runInExecutionContext } from '@mondaydotcomorg/atp-runtime';
|
|
4
|
-
import { isBatchPauseError } from '@mondaydotcomorg/atp-compiler';
|
|
4
|
+
import { isBatchPauseError, CHECKPOINT_RUNTIME_NAMESPACE } from '@mondaydotcomorg/atp-compiler';
|
|
5
5
|
import { PAUSE_EXECUTION_MARKER } from './constants.js';
|
|
6
6
|
import { isInIsolateFunction, getInIsolateImplementation } from './in-isolate-runtime.js';
|
|
7
7
|
|
|
@@ -117,14 +117,16 @@ export async function injectSandbox(
|
|
|
117
117
|
// In AST mode, tag result with provenance ID before copying so tag survives
|
|
118
118
|
if (isASTMode && result && typeof result === 'object') {
|
|
119
119
|
try {
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
// Only add __prov_id__ if not already present (avoids overwriting UUID from createProvenanceProxy)
|
|
121
|
+
if (!Object.prototype.hasOwnProperty.call(result, '__prov_id__')) {
|
|
122
|
+
const provId = `tracked_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
123
|
+
Object.defineProperty(result, '__prov_id__', {
|
|
124
|
+
value: provId,
|
|
125
|
+
writable: false,
|
|
126
|
+
enumerable: true,
|
|
127
|
+
configurable: true,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
128
130
|
} catch (e) {
|
|
129
131
|
// If can't define property, that's ok
|
|
130
132
|
}
|
|
@@ -176,6 +178,41 @@ export async function injectSandbox(
|
|
|
176
178
|
continue;
|
|
177
179
|
}
|
|
178
180
|
|
|
181
|
+
// Handle checkpoint namespace
|
|
182
|
+
if (namespace === '__checkpoint' && typeof value === 'object' && value !== null) {
|
|
183
|
+
for (const [key, fn] of Object.entries(value)) {
|
|
184
|
+
if (typeof fn === 'function') {
|
|
185
|
+
await jail.set(
|
|
186
|
+
`__checkpoint_${key}_impl`,
|
|
187
|
+
new ivm.Reference(async (...args: unknown[]) => {
|
|
188
|
+
try {
|
|
189
|
+
const execute = async () => {
|
|
190
|
+
const result = await fn(...args);
|
|
191
|
+
return new ivm.ExternalCopy(result).copyInto();
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
if (executionId) {
|
|
195
|
+
return await runInExecutionContext(executionId, execute);
|
|
196
|
+
} else {
|
|
197
|
+
return await execute();
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
const err = error as Error;
|
|
201
|
+
if (isPauseError(error) || err.message === PAUSE_EXECUTION_MARKER) {
|
|
202
|
+
if (isPauseError(error)) {
|
|
203
|
+
onPauseError(error);
|
|
204
|
+
}
|
|
205
|
+
throw new Error(PAUSE_EXECUTION_MARKER);
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
179
216
|
if (namespace === '__runtime' && typeof value === 'object' && value !== null) {
|
|
180
217
|
for (const [key, fn] of Object.entries(value)) {
|
|
181
218
|
if (typeof fn === 'function') {
|
|
@@ -352,3 +389,32 @@ ${newAccessPath} = async function(...args) {
|
|
|
352
389
|
setupNestedAPI(apiObject, '', 'globalThis.api');
|
|
353
390
|
await ivmContext.eval(apiSetup);
|
|
354
391
|
}
|
|
392
|
+
|
|
393
|
+
export async function setupCheckpointNamespace(
|
|
394
|
+
ivmContext: ivm.Context,
|
|
395
|
+
sandbox: Record<string, unknown>
|
|
396
|
+
): Promise<void> {
|
|
397
|
+
const checkpointObject = sandbox.__checkpoint as Record<string, unknown>;
|
|
398
|
+
if (!checkpointObject || typeof checkpointObject !== 'object') {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const checkpointKeys = Object.keys(checkpointObject).filter(
|
|
403
|
+
(k) => typeof checkpointObject[k] === 'function'
|
|
404
|
+
);
|
|
405
|
+
if (checkpointKeys.length === 0) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Setup __checkpoint namespace for internal use by transformed code
|
|
410
|
+
let checkpointSetup = `globalThis.${CHECKPOINT_RUNTIME_NAMESPACE} = {\n`;
|
|
411
|
+
checkpointSetup += checkpointKeys
|
|
412
|
+
.map(
|
|
413
|
+
(key) =>
|
|
414
|
+
`\t${key}: async (...args) => {\n\t\treturn await ${CHECKPOINT_RUNTIME_NAMESPACE}_${key}_impl.apply(undefined, args, { arguments: { copy: true }, result: { promise: true } });\n\t}`
|
|
415
|
+
)
|
|
416
|
+
.join(',\n');
|
|
417
|
+
checkpointSetup += '\n};';
|
|
418
|
+
|
|
419
|
+
await ivmContext.eval(checkpointSetup);
|
|
420
|
+
}
|