deepline 0.1.200 → 0.1.202

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 (33) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +49 -13
  2. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +25 -0
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +139 -124
  4. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  5. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +17 -2
  6. package/dist/bundling-sources/shared_libs/play-runtime/bounded-dispatch.ts +52 -0
  7. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +152 -23
  8. package/dist/bundling-sources/shared_libs/play-runtime/coordinator-headers.ts +10 -0
  9. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +11 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +121 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/governor/adaptive-admission.ts +6 -1
  12. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-budget-state-backend.ts +22 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +86 -19
  14. package/dist/bundling-sources/shared_libs/play-runtime/governor/block-reserving-budget-state-backend.ts +141 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/governor/budget-state-backend.ts +43 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +129 -41
  17. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +40 -2
  18. package/dist/bundling-sources/shared_libs/play-runtime/receipt-completion-sink.ts +92 -33
  19. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +13 -5
  20. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +43 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +122 -120
  22. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +10 -8
  23. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +140 -32
  24. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +327 -31
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +26 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +21 -0
  27. package/dist/bundling-sources/shared_libs/plays/dataset.ts +32 -10
  28. package/dist/cli/index.js +198 -76
  29. package/dist/cli/index.mjs +204 -82
  30. package/dist/index.js +3 -2
  31. package/dist/index.mjs +3 -2
  32. package/package.json +1 -1
  33. package/dist/bundling-sources/shared_libs/play-runtime/adaptive-tool-dispatcher.ts +0 -355
@@ -60,16 +60,18 @@ function nodeMaterializePayloadCommand(input: {
60
60
  function remoteRuntimeContextForDaytona(
61
61
  context: DaytonaExecutionContext,
62
62
  ): DaytonaRemoteRuntimeContext {
63
- if ((context.preloadedDbSessions?.length ?? 0) > 0) {
64
- return {
65
- ...context,
66
- dbSessionStrategy: 'preloaded',
67
- preloadedDbSessions: context.preloadedDbSessions,
68
- };
63
+ const gatewayBaseUrl = context.receiptGatewayBaseUrl?.trim();
64
+ if (!gatewayBaseUrl) {
65
+ throw new Error(
66
+ 'Daytona execution requires DEEPLINE_RUNTIME_RECEIPT_GATEWAY_URL. Refusing to put app credentials or database sessions in the customer-code sandbox.',
67
+ );
69
68
  }
70
69
  return {
71
70
  ...context,
72
- dbSessionStrategy: 'sandbox_public_key',
71
+ baseUrl: gatewayBaseUrl,
72
+ receiptGatewayBaseUrl: gatewayBaseUrl,
73
+ vercelProtectionBypassToken: null,
74
+ dbSessionStrategy: 'gateway_only',
73
75
  preloadedDbSessions: undefined,
74
76
  };
75
77
  }
@@ -215,7 +217,7 @@ export async function stageDaytonaRunnerPayload(input: {
215
217
  configPath,
216
218
  artifactCodePath,
217
219
  })} && DEEPLINE_PLAY_RUNNER_PROGRESS_EVENT_PATH=${shellQuote(progressEventPath)} DEEPLINE_PLAY_RUNNER_STDOUT_EVENT_MODE=compact node ${shellQuote(runnerPath)} ${shellQuote(configPath)}`;
218
- const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(exitCodePath)} ${shellQuote(progressEventPath)}; ( ${runnerCommand} ) > ${shellQuote(outputPath)} 2>&1; code=$?; printf '%s' "$code" > ${shellQuote(exitCodePath)}; printf 'deepline runner output captured: %s\\n' ${shellQuote(outputPath)}; exit "$code"`;
220
+ const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(exitCodePath)} ${shellQuote(progressEventPath)} ${shellQuote(`${progressEventPath}.*`)}; ( ${runnerCommand} ) > ${shellQuote(outputPath)} 2>&1; code=$?; printf '%s' "$code" > ${shellQuote(exitCodePath)}; printf 'deepline runner output captured: %s\\n' ${shellQuote(outputPath)}; exit "$code"`;
219
221
 
220
222
  return {
221
223
  workDir: input.workDir,
@@ -46,6 +46,71 @@ const DAYTONA_RUNTIME_DB_CONNECT_MAX_ATTEMPTS = 2;
46
46
  const DAYTONA_INFRASTRUCTURE_MAX_ATTEMPTS = 2;
47
47
  const DAYTONA_UPLOAD_MAX_ATTEMPTS = 2;
48
48
  const DAYTONA_UPLOAD_ATTEMPT_DEADLINE_MS = 90_000;
49
+ /**
50
+ * Client-side wall-clock grace for `sandbox.process.executeCommand`. The
51
+ * `timeout` argument we pass is a SERVER-side directive; the Daytona SDK's
52
+ * underlying HTTP call has no client deadline, so a wedged socket (observed:
53
+ * `AggregateError [ETIMEDOUT]`) leaves the await hanging forever and holds the
54
+ * worker slot. We race the call against this deadline = server timeout + grace,
55
+ * so a genuine server-side runtime-limit hit still returns first, but a wedged
56
+ * client transport fails the attempt loudly and lets the engine retry ladder
57
+ * take over instead of livelocking the slot.
58
+ */
59
+ const DAYTONA_EXECUTE_CLIENT_GRACE_MS = 60_000;
60
+ const DAYTONA_EXECUTE_CLIENT_DEADLINE_MS =
61
+ DAYTONA_EXECUTE_TIMEOUT_SECONDS * 1_000 + DAYTONA_EXECUTE_CLIENT_GRACE_MS;
62
+ /**
63
+ * Bound for individual sandbox/runtime API calls that have no natural timeout
64
+ * (e.g. recording the acquired runtime resource). A wedged one of these must
65
+ * fail the attempt, not hold the slot.
66
+ */
67
+ const DAYTONA_API_CALL_DEADLINE_MS = 60_000;
68
+
69
+ export class DaytonaOperationDeadlineError extends Error {
70
+ readonly operation: string;
71
+ readonly deadlineMs: number;
72
+
73
+ constructor(input: { operation: string; deadlineMs: number }) {
74
+ super(
75
+ `Daytona operation "${input.operation}" exceeded client deadline of ${input.deadlineMs}ms and was abandoned to free the worker slot.`,
76
+ );
77
+ this.name = 'DaytonaOperationDeadlineError';
78
+ this.operation = input.operation;
79
+ this.deadlineMs = input.deadlineMs;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Race `promise` against a wall-clock deadline. On breach, reject loudly with a
85
+ * `DaytonaOperationDeadlineError` (the caller's retry/failure classification
86
+ * decides what happens next). The timer is always cleared so a fast-resolving
87
+ * promise never leaves a dangling handle.
88
+ */
89
+ export async function withDaytonaOperationDeadline<T>(input: {
90
+ operation: string;
91
+ deadlineMs: number;
92
+ promise: Promise<T>;
93
+ }): Promise<T> {
94
+ let deadlineTimer: ReturnType<typeof setTimeout> | null = null;
95
+ const deadlinePromise = new Promise<never>((_resolve, reject) => {
96
+ deadlineTimer = setTimeout(() => {
97
+ reject(
98
+ new DaytonaOperationDeadlineError({
99
+ operation: input.operation,
100
+ deadlineMs: input.deadlineMs,
101
+ }),
102
+ );
103
+ }, input.deadlineMs);
104
+ deadlineTimer.unref?.();
105
+ });
106
+ try {
107
+ return await Promise.race([input.promise, deadlinePromise]);
108
+ } finally {
109
+ if (deadlineTimer) {
110
+ clearTimeout(deadlineTimer);
111
+ }
112
+ }
113
+ }
49
114
  const RUNTIME_POSTGRES_CONNECT_RETRY_PATTERN =
50
115
  /\bRuntime Postgres\b.*\b(connection timed out|connect timeout|ETIMEDOUT|ECONNRESET|ECONNREFUSED|Connection terminated|Connection ended unexpectedly)\b/i;
51
116
  const DAYTONA_INFRASTRUCTURE_RETRY_PATTERN =
@@ -223,10 +288,11 @@ function createDaytonaProgressSidecarPoller(input: {
223
288
  context: DaytonaExecutionContext;
224
289
  startedAt: number;
225
290
  processedEventKeys: Set<string>;
226
- }): { start(): void; stop(): Promise<void> } {
291
+ }): { start(): void; stop(flush?: boolean): Promise<void> } {
227
292
  let timer: ReturnType<typeof setTimeout> | null = null;
228
293
  let stopped = false;
229
294
  let inFlight: Promise<void> = Promise.resolve();
295
+ let segment = 0;
230
296
  let offsetBytes = 0;
231
297
  let pendingLine = '';
232
298
  let warned = false;
@@ -259,20 +325,39 @@ function createDaytonaProgressSidecarPoller(input: {
259
325
 
260
326
  const poll = async (flushPartial = false): Promise<void> => {
261
327
  try {
262
- const file = await input.sandbox.fs.downloadFile(
328
+ const manifest = await input.sandbox.fs.downloadFile(
263
329
  input.progressEventPath,
264
330
  5,
265
331
  );
266
- const buffer = Buffer.isBuffer(file) ? file : Buffer.from(file);
267
- if (buffer.length < offsetBytes) {
332
+ const parsedLatestSegment = Number.parseInt(
333
+ Buffer.isBuffer(manifest)
334
+ ? manifest.toString('utf-8').trim()
335
+ : String(manifest).trim(),
336
+ 10,
337
+ );
338
+ const latestSegment = Number.isFinite(parsedLatestSegment)
339
+ ? Math.max(segment, parsedLatestSegment)
340
+ : segment;
341
+ while (segment <= latestSegment) {
342
+ const segmentPath = `${input.progressEventPath}.${String(
343
+ segment,
344
+ ).padStart(6, '0')}`;
345
+ const file = await input.sandbox.fs.downloadFile(segmentPath, 5);
346
+ const buffer = Buffer.isBuffer(file) ? file : Buffer.from(file);
347
+ if (buffer.length < offsetBytes) {
348
+ offsetBytes = 0;
349
+ pendingLine = '';
350
+ }
351
+ if (buffer.length > offsetBytes) {
352
+ const chunk = buffer.subarray(offsetBytes).toString('utf-8');
353
+ offsetBytes = buffer.length;
354
+ processText(chunk, flushPartial && segment === latestSegment);
355
+ }
356
+ if (segment >= latestSegment) break;
357
+ segment += 1;
268
358
  offsetBytes = 0;
269
- pendingLine = '';
270
359
  }
271
- if (buffer.length > offsetBytes) {
272
- const chunk = buffer.subarray(offsetBytes).toString('utf-8');
273
- offsetBytes = buffer.length;
274
- processText(chunk, flushPartial);
275
- } else if (flushPartial && pendingLine.trim()) {
360
+ if (flushPartial && pendingLine.trim()) {
276
361
  processText('\n', true);
277
362
  }
278
363
  } catch (error) {
@@ -304,14 +389,14 @@ function createDaytonaProgressSidecarPoller(input: {
304
389
  start() {
305
390
  inFlight = inFlight.then(() => poll()).finally(schedule);
306
391
  },
307
- async stop() {
392
+ async stop(flush = true) {
308
393
  stopped = true;
309
394
  if (timer) {
310
395
  clearTimeout(timer);
311
396
  timer = null;
312
397
  }
313
398
  await inFlight.catch(() => {});
314
- await poll(true);
399
+ if (flush) await poll(true);
315
400
  },
316
401
  };
317
402
  }
@@ -422,6 +507,12 @@ function isRetryableDaytonaInfrastructureFailure(error: unknown): boolean {
422
507
  if (error instanceof DaytonaCommandTransportError) {
423
508
  return false;
424
509
  }
510
+ // A client-side deadline breach is a wedged transport (hung socket / SDK call
511
+ // with no client timeout). Retry once on a fresh sandbox before spending an
512
+ // engine attempt, same as the other transport-level infrastructure failures.
513
+ if (error instanceof DaytonaOperationDeadlineError) {
514
+ return true;
515
+ }
425
516
  const message = error instanceof Error ? error.message : String(error);
426
517
  if (!message || /cancelled|aborted/i.test(message)) {
427
518
  return false;
@@ -566,15 +657,24 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
566
657
  acquiredSandbox.billingStartedAt - startedAt;
567
658
  const sandbox = acquiredSandbox.sandbox;
568
659
  sandboxForAttempt = sandbox;
569
- await callbacks?.onRuntimeResourceAcquired?.({
570
- kind: 'daytona_sandbox',
571
- sandboxId: sandbox.id,
572
- billingStartedAt: acquiredSandbox.billingStartedAt,
573
- cpu: typeof sandbox.cpu === 'number' ? sandbox.cpu : null,
574
- memoryGiB:
575
- typeof sandbox.memory === 'number' ? sandbox.memory : null,
576
- diskGiB: typeof sandbox.disk === 'number' ? sandbox.disk : null,
577
- });
660
+ const resourceAcquiredNotice = callbacks?.onRuntimeResourceAcquired?.(
661
+ {
662
+ kind: 'daytona_sandbox',
663
+ sandboxId: sandbox.id,
664
+ billingStartedAt: acquiredSandbox.billingStartedAt,
665
+ cpu: typeof sandbox.cpu === 'number' ? sandbox.cpu : null,
666
+ memoryGiB:
667
+ typeof sandbox.memory === 'number' ? sandbox.memory : null,
668
+ diskGiB: typeof sandbox.disk === 'number' ? sandbox.disk : null,
669
+ },
670
+ );
671
+ if (resourceAcquiredNotice) {
672
+ await withDaytonaOperationDeadline({
673
+ operation: 'onRuntimeResourceAcquired',
674
+ deadlineMs: DAYTONA_API_CALL_DEADLINE_MS,
675
+ promise: resourceAcquiredNotice,
676
+ });
677
+ }
578
678
  throwIfCancellationRequested();
579
679
 
580
680
  const { workdir: workDir } = loadDaytonaRunnerPathsConfig();
@@ -676,16 +776,19 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
676
776
  try {
677
777
  progressSidecar.start();
678
778
  execution = await Promise.race([
679
- sandbox.process.executeCommand(
680
- stagedPayload.command,
681
- stagedPayload.workDir,
682
- undefined,
683
- DAYTONA_EXECUTE_TIMEOUT_SECONDS,
684
- ),
779
+ withDaytonaOperationDeadline({
780
+ operation: 'sandbox.process.executeCommand',
781
+ deadlineMs: DAYTONA_EXECUTE_CLIENT_DEADLINE_MS,
782
+ promise: sandbox.process.executeCommand(
783
+ stagedPayload.command,
784
+ stagedPayload.workDir,
785
+ undefined,
786
+ DAYTONA_EXECUTE_TIMEOUT_SECONDS,
787
+ ),
788
+ }),
685
789
  cancellationPromise,
686
790
  ]);
687
791
  } catch (error) {
688
- await progressSidecar.stop();
689
792
  if (
690
793
  cancellationRequested ||
691
794
  callbacks?.cancellationSignal?.aborted
@@ -729,7 +832,10 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
729
832
  });
730
833
  execution = recovered.execution;
731
834
  } finally {
732
- await progressSidecar.stop();
835
+ await progressSidecar.stop(
836
+ !cancellationRequested &&
837
+ callbacks?.cancellationSignal?.aborted !== true,
838
+ );
733
839
  }
734
840
  const runnerOutput = await resolveDaytonaCommandOutput({
735
841
  sandbox,
@@ -818,9 +924,11 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
818
924
  error:
819
925
  typeof execution.exitCode === 'number' &&
820
926
  execution.exitCode !== 0
821
- ? `Daytona play runner exited with code ${execution.exitCode}.${
822
- outputTail ? ` Output tail: ${outputTail}` : ''
823
- }`
927
+ ? `Daytona play runner exited with code ${execution.exitCode}${
928
+ execution.exitCode === 137
929
+ ? ' (sandbox OOM or forced SIGKILL)'
930
+ : ''
931
+ }.${outputTail ? ` Output tail: ${outputTail}` : ''}`
824
932
  : 'Daytona play runner produced no result.',
825
933
  runtimeTiming,
826
934
  }),