deepline 0.1.281 → 0.1.283
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/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +4 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +25 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +61 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-cache-policy.ts +14 -0
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -155,7 +155,7 @@ export const SDK_RELEASE = {
|
|
|
155
155
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
156
156
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
157
157
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
158
|
-
version: '0.1.
|
|
158
|
+
version: '0.1.283',
|
|
159
159
|
contracts: {
|
|
160
160
|
api: {
|
|
161
161
|
name: 'sdk-http-api',
|
|
@@ -142,6 +142,7 @@ import {
|
|
|
142
142
|
isQueryResultDatasetReadRequest,
|
|
143
143
|
isQueryResultDatasetTool,
|
|
144
144
|
} from './query-result-dataset';
|
|
145
|
+
import { isAlwaysFreshIntegrationTool } from './tool-cache-policy';
|
|
145
146
|
import { isRowIsolationExemptError } from './row-isolation';
|
|
146
147
|
import {
|
|
147
148
|
createRuntimePersistenceLatch,
|
|
@@ -6355,7 +6356,9 @@ export class PlayContextImpl {
|
|
|
6355
6356
|
const eventWaitHandler =
|
|
6356
6357
|
(await this.#options.getIntegrationEventWaitHandler?.(toolId)) ?? null;
|
|
6357
6358
|
const cacheableToolResult =
|
|
6358
|
-
!eventWaitHandler &&
|
|
6359
|
+
!eventWaitHandler &&
|
|
6360
|
+
!isQueryResultDatasetReadRequest(toolId, input) &&
|
|
6361
|
+
!isAlwaysFreshIntegrationTool(toolId);
|
|
6359
6362
|
let durableCacheKey = await this.durableToolCallCacheKey({
|
|
6360
6363
|
toolId,
|
|
6361
6364
|
requestInput: input,
|
|
@@ -10,6 +10,9 @@ const RUNTIME_LIMIT_EXCEEDED_RE = /\bRUNTIME_LIMIT_EXCEEDED\b/i;
|
|
|
10
10
|
const RUNTIME_SANDBOX_INSPECTION_UNAVAILABLE_RE =
|
|
11
11
|
/\bRUNTIME_SANDBOX_INSPECTION_UNAVAILABLE\b/i;
|
|
12
12
|
const RUNTIME_SANDBOX_LOST_RE = /\bRUNTIME_SANDBOX_LOST\b/i;
|
|
13
|
+
const RUNTIME_SANDBOX_OOM_RE =
|
|
14
|
+
/\bRUNTIME_SANDBOX_OOM\b|(?:javascript heap out of memory|fatal error:.*(?:heap|allocation).*memory)/i;
|
|
15
|
+
const RUNTIME_SANDBOX_KILLED_RE = /\bRUNTIME_SANDBOX_KILLED\b/i;
|
|
13
16
|
const OUTPUT_TOO_LARGE_RE = /\b(?:OUTPUT_TOO_LARGE|OutputTooLarge)\b/;
|
|
14
17
|
|
|
15
18
|
export const PLATFORM_DEPLOY_INTERRUPTED_MESSAGE =
|
|
@@ -23,6 +26,10 @@ export const INTERNAL_RUNTIME_STORAGE_ERROR_MESSAGE =
|
|
|
23
26
|
'Internal play runtime storage failed. Please retry the run; if this keeps happening, contact Deepline support with the run ID.';
|
|
24
27
|
export const RUNTIME_SANDBOX_LOST_MESSAGE =
|
|
25
28
|
'The execution sandbox became unreachable before returning a terminal result. Re-run the same command; if this keeps happening, contact Deepline support with the run ID.';
|
|
29
|
+
export const RUNTIME_SANDBOX_OOM_MESSAGE =
|
|
30
|
+
'The execution sandbox ran out of memory. Completed work is durably recorded. Retry the same command safely; Deepline reuses completed steps and does not repeat their provider calls. If it happens again, reduce the batch size or row payload.';
|
|
31
|
+
export const RUNTIME_SANDBOX_KILLED_MESSAGE =
|
|
32
|
+
'The execution sandbox was killed before it could return a result, and the kill reason is unavailable. Completed work is durably recorded. Retry the same command safely; Deepline reuses completed steps and does not repeat their provider calls.';
|
|
26
33
|
export const RUNTIME_LIMIT_EXCEEDED_MESSAGE =
|
|
27
34
|
'The play reached its 30 minute runtime limit and was stopped. Completed row state was preserved; run a smaller batch or continue from the persisted rows.';
|
|
28
35
|
export const RUNTIME_SANDBOX_INSPECTION_UNAVAILABLE_MESSAGE =
|
|
@@ -268,6 +275,24 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
|
268
275
|
cause,
|
|
269
276
|
};
|
|
270
277
|
}
|
|
278
|
+
if (RUNTIME_SANDBOX_OOM_RE.test(rawCause)) {
|
|
279
|
+
return {
|
|
280
|
+
code: 'RUNTIME_SANDBOX_OOM',
|
|
281
|
+
phase: 'infrastructure',
|
|
282
|
+
message: RUNTIME_SANDBOX_OOM_MESSAGE,
|
|
283
|
+
retryable: true,
|
|
284
|
+
cause,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
if (RUNTIME_SANDBOX_KILLED_RE.test(rawCause)) {
|
|
288
|
+
return {
|
|
289
|
+
code: 'RUNTIME_SANDBOX_KILLED',
|
|
290
|
+
phase: 'infrastructure',
|
|
291
|
+
message: RUNTIME_SANDBOX_KILLED_MESSAGE,
|
|
292
|
+
retryable: true,
|
|
293
|
+
cause,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
271
296
|
if (RUNTIME_SANDBOX_LOST_RE.test(rawCause)) {
|
|
272
297
|
const stack = error instanceof Error ? boundedFailureStack(error) : null;
|
|
273
298
|
const causes = error instanceof Error ? failureCauseTexts(error) : [];
|
|
@@ -18,6 +18,10 @@ import {
|
|
|
18
18
|
RUNNER_POST_TERMINAL_DIAGNOSTIC_MAX_BYTES,
|
|
19
19
|
RUNNER_TERMINAL_PUSH_MAX_BODY_BYTES,
|
|
20
20
|
} from '@shared_libs/play-runtime/output-size-limits';
|
|
21
|
+
import {
|
|
22
|
+
RUNTIME_SANDBOX_KILLED_MESSAGE,
|
|
23
|
+
RUNTIME_SANDBOX_OOM_MESSAGE,
|
|
24
|
+
} from '@shared_libs/play-runtime/run-failure';
|
|
21
25
|
import { compactPlayArtifactForRuntimeTransport } from '@shared_libs/plays/artifact-transport';
|
|
22
26
|
import type {
|
|
23
27
|
DaytonaExecutionContext,
|
|
@@ -122,6 +126,8 @@ const configPath = process.argv[2];
|
|
|
122
126
|
const exitCodeRaw = Number.parseInt(process.argv[3] ?? '', 10);
|
|
123
127
|
const outputPath = process.argv[4];
|
|
124
128
|
const runtimeLimitMarkerPath = process.argv[5] || '';
|
|
129
|
+
const oomKillBaselinePath = process.argv[6] || '';
|
|
130
|
+
const memoryEventsPath = process.argv[7] || '/sys/fs/cgroup/memory.events';
|
|
125
131
|
const exitCode = Number.isFinite(exitCodeRaw) ? exitCodeRaw : null;
|
|
126
132
|
const MAX_OUTPUT_BYTES = ${DAYTONA_CRASH_PUSHER_OUTPUT_TAIL_MAX_BYTES};
|
|
127
133
|
const MAX_POST_TERMINAL_DIAGNOSTIC_BYTES = ${RUNNER_POST_TERMINAL_DIAGNOSTIC_MAX_BYTES};
|
|
@@ -176,6 +182,31 @@ function readResultFromOutput() {
|
|
|
176
182
|
return null;
|
|
177
183
|
}
|
|
178
184
|
|
|
185
|
+
function outputHasExplicitOomSignature() {
|
|
186
|
+
try {
|
|
187
|
+
const stat = fs.statSync(outputPath);
|
|
188
|
+
const start = Math.max(0, stat.size - MAX_OUTPUT_BYTES);
|
|
189
|
+
const fd = fs.openSync(outputPath, 'r');
|
|
190
|
+
const buffer = Buffer.alloc(stat.size - start);
|
|
191
|
+
fs.readSync(fd, buffer, 0, buffer.length, start);
|
|
192
|
+
fs.closeSync(fd);
|
|
193
|
+
return /javascript heap out of memory|fatal error:.*(?:heap|allocation).*memory/i.test(buffer.toString('utf-8'));
|
|
194
|
+
} catch {}
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function cgroupOomKillObserved() {
|
|
199
|
+
try {
|
|
200
|
+
if (!oomKillBaselinePath) return false;
|
|
201
|
+
const baseline = Number.parseInt(fs.readFileSync(oomKillBaselinePath, 'utf8').trim(), 10);
|
|
202
|
+
const events = fs.readFileSync(memoryEventsPath, 'utf8');
|
|
203
|
+
const match = events.match(/^oom_kill\\s+(\\d+)$/m);
|
|
204
|
+
const current = match ? Number.parseInt(match[1], 10) : Number.NaN;
|
|
205
|
+
return Number.isFinite(baseline) && Number.isFinite(current) && current > baseline;
|
|
206
|
+
} catch {}
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
|
|
179
210
|
function terminalResultForTransport(result) {
|
|
180
211
|
if (
|
|
181
212
|
result &&
|
|
@@ -225,12 +256,21 @@ async function main() {
|
|
|
225
256
|
const runtimeLimitExceeded = Boolean(
|
|
226
257
|
runtimeLimitMarkerPath && fs.existsSync(runtimeLimitMarkerPath),
|
|
227
258
|
);
|
|
259
|
+
// 137 is SIGKILL, not proof of an OOM. A watchdog, platform eviction, or
|
|
260
|
+
// operator action can produce the same status. Only label this an OOM when
|
|
261
|
+
// the captured runtime output carries an explicit V8 allocation signature.
|
|
262
|
+
const sandboxKilled = exitCode === 137;
|
|
263
|
+
const sandboxOom =
|
|
264
|
+
sandboxKilled && (outputHasExplicitOomSignature() || cgroupOomKillObserved());
|
|
228
265
|
const synthesizedError = runtimeLimitExceeded
|
|
229
266
|
? 'RUNTIME_LIMIT_EXCEEDED: The play reached its 30 minute runtime limit and was stopped.'
|
|
267
|
+
: sandboxOom
|
|
268
|
+
? 'RUNTIME_SANDBOX_OOM: ' + ${JSON.stringify(RUNTIME_SANDBOX_OOM_MESSAGE)}
|
|
269
|
+
: sandboxKilled
|
|
270
|
+
? 'RUNTIME_SANDBOX_KILLED: ' + ${JSON.stringify(RUNTIME_SANDBOX_KILLED_MESSAGE)}
|
|
230
271
|
:
|
|
231
272
|
'Daytona play runner exited with code ' +
|
|
232
273
|
(exitCode === null ? 'unknown' : exitCode) +
|
|
233
|
-
(exitCode === 137 ? ' (sandbox OOM or forced SIGKILL)' : '') +
|
|
234
274
|
' without pushing a terminal (crash containment epilogue).';
|
|
235
275
|
const result = terminalResultForTransport(parsedResult || {
|
|
236
276
|
status: 'failed',
|
|
@@ -244,6 +284,24 @@ async function main() {
|
|
|
244
284
|
cause: synthesizedError,
|
|
245
285
|
}]
|
|
246
286
|
: undefined,
|
|
287
|
+
...(sandboxOom
|
|
288
|
+
? { errors: [{
|
|
289
|
+
code: 'RUNTIME_SANDBOX_OOM',
|
|
290
|
+
phase: 'infrastructure',
|
|
291
|
+
message: ${JSON.stringify(RUNTIME_SANDBOX_OOM_MESSAGE)},
|
|
292
|
+
retryable: true,
|
|
293
|
+
cause: synthesizedError,
|
|
294
|
+
}] }
|
|
295
|
+
: {}),
|
|
296
|
+
...(sandboxKilled && !sandboxOom
|
|
297
|
+
? { errors: [{
|
|
298
|
+
code: 'RUNTIME_SANDBOX_KILLED',
|
|
299
|
+
phase: 'infrastructure',
|
|
300
|
+
message: ${JSON.stringify(RUNTIME_SANDBOX_KILLED_MESSAGE)},
|
|
301
|
+
retryable: true,
|
|
302
|
+
cause: synthesizedError,
|
|
303
|
+
}] }
|
|
304
|
+
: {}),
|
|
247
305
|
logs: [],
|
|
248
306
|
stats: {},
|
|
249
307
|
steps: [],
|
|
@@ -454,6 +512,7 @@ export async function stageDaytonaRunnerPayload(input: {
|
|
|
454
512
|
const outputPath = `${workDir}/deepline-play-output-${randomUUID()}.log`;
|
|
455
513
|
const crashPusherLogPath = `${workDir}/deepline-play-crash-terminal-${randomUUID()}.log`;
|
|
456
514
|
const exitCodePath = `${workDir}/deepline-play-exit-${randomUUID()}.txt`;
|
|
515
|
+
const oomKillBaselinePath = `${workDir}/deepline-play-oom-kill-${randomUUID()}.txt`;
|
|
457
516
|
const runtimeStartedPath = `${workDir}/deepline-play-runtime-started-${randomUUID()}.json`;
|
|
458
517
|
const runtimeCompletedPath = `${workDir}/deepline-play-runtime-completed-${randomUUID()}.json`;
|
|
459
518
|
const runtimeLimitMarkerPath = `${workDir}/deepline-play-runtime-limit-${randomUUID()}.txt`;
|
|
@@ -491,7 +550,7 @@ export async function stageDaytonaRunnerPayload(input: {
|
|
|
491
550
|
// Its own retry diagnostics are kept in a separate log: appending them to
|
|
492
551
|
// `outputPath` after a near-gateway-sized result could hide that result from
|
|
493
552
|
// a later bounded-tail recovery read.
|
|
494
|
-
const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(crashPusherLogPath)} ${shellQuote(exitCodePath)} ${shellQuote(runtimeStartedPath)} ${shellQuote(runtimeCompletedPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(progressEventPath)} ${shellQuote(`${progressEventPath}.*`)}; ( ${runnerCommand} ) > ${shellQuote(outputPath)} 2>&1; code=$?; printf '%s' "$code" > ${shellQuote(exitCodePath)}; node ${shellQuote(crashPusherPath)} ${shellQuote(configPath)} "$code" ${shellQuote(outputPath)} ${shellQuote(runtimeLimitMarkerPath)} > ${shellQuote(crashPusherLogPath)} 2>&1 || true; printf 'deepline runner output captured: %s\\n' ${shellQuote(outputPath)}; exit "$code"`;
|
|
553
|
+
const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(crashPusherLogPath)} ${shellQuote(exitCodePath)} ${shellQuote(oomKillBaselinePath)} ${shellQuote(runtimeStartedPath)} ${shellQuote(runtimeCompletedPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(progressEventPath)} ${shellQuote(`${progressEventPath}.*`)}; ( awk '$1 == "oom_kill" { print $2 }' /sys/fs/cgroup/memory.events 2>/dev/null || true ) > ${shellQuote(oomKillBaselinePath)}; ( ${runnerCommand} ) > ${shellQuote(outputPath)} 2>&1; code=$?; printf '%s' "$code" > ${shellQuote(exitCodePath)}; node ${shellQuote(crashPusherPath)} ${shellQuote(configPath)} "$code" ${shellQuote(outputPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(oomKillBaselinePath)} /sys/fs/cgroup/memory.events > ${shellQuote(crashPusherLogPath)} 2>&1 || true; printf 'deepline runner output captured: %s\\n' ${shellQuote(outputPath)}; exit "$code"`;
|
|
495
554
|
|
|
496
555
|
return {
|
|
497
556
|
workDir: input.workDir,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const ALWAYS_FRESH_INTEGRATION_TOOL_IDS = new Set([
|
|
2
|
+
'google_workspace_request',
|
|
3
|
+
'google_workspace_export_dataset',
|
|
4
|
+
// Unique public operation alias for google_workspace_export_dataset.
|
|
5
|
+
'export_dataset',
|
|
6
|
+
]);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* These tools read or mutate reviewer-owned live state. Reusing a checkpoint or
|
|
10
|
+
* durable receipt would hide edits or skip the export's conflict checks.
|
|
11
|
+
*/
|
|
12
|
+
export function isAlwaysFreshIntegrationTool(toolId: string): boolean {
|
|
13
|
+
return ALWAYS_FRESH_INTEGRATION_TOOL_IDS.has(toolId.trim());
|
|
14
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -718,7 +718,7 @@ var SDK_RELEASE = {
|
|
|
718
718
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
719
719
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
720
720
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
721
|
-
version: "0.1.
|
|
721
|
+
version: "0.1.283",
|
|
722
722
|
contracts: {
|
|
723
723
|
api: {
|
|
724
724
|
name: "sdk-http-api",
|
package/dist/cli/index.mjs
CHANGED
|
@@ -703,7 +703,7 @@ var SDK_RELEASE = {
|
|
|
703
703
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
704
704
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
705
705
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
706
|
-
version: "0.1.
|
|
706
|
+
version: "0.1.283",
|
|
707
707
|
contracts: {
|
|
708
708
|
api: {
|
|
709
709
|
name: "sdk-http-api",
|
package/dist/index.js
CHANGED
|
@@ -438,7 +438,7 @@ var SDK_RELEASE = {
|
|
|
438
438
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
439
439
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
440
440
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
441
|
-
version: "0.1.
|
|
441
|
+
version: "0.1.283",
|
|
442
442
|
contracts: {
|
|
443
443
|
api: {
|
|
444
444
|
name: "sdk-http-api",
|
package/dist/index.mjs
CHANGED
|
@@ -367,7 +367,7 @@ var SDK_RELEASE = {
|
|
|
367
367
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
368
368
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
369
369
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
370
|
-
version: "0.1.
|
|
370
|
+
version: "0.1.283",
|
|
371
371
|
contracts: {
|
|
372
372
|
api: {
|
|
373
373
|
name: "sdk-http-api",
|