deepline 0.3.23 → 0.3.25

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.
@@ -36,10 +36,50 @@ const MODAL_RUNNER_READY_TIMEOUT_MS =
36
36
  RUNTIME_RELIABILITY_POLICY.sandbox.runnerReadyTimeoutMs;
37
37
  const MODAL_SANDBOX_CREATE_TIMEOUT_MS =
38
38
  RUNTIME_RELIABILITY_POLICY.sandbox.modalSandboxCreateTimeoutMs;
39
+ const MODAL_PAYLOAD_UPLOAD_TIMEOUT_MS = 90_000;
40
+ const MODAL_TERMINATION_TIMEOUT_MS = 10_000;
39
41
  const MODAL_CAPACITY_RELEASE_RETRY_DELAYS_MS = [0, 100, 500, 2_000] as const;
40
42
  const MODAL_LATE_CREATE_PERSIST_RETRY_DELAYS_MS = [0, 100, 500, 2_000] as const;
41
43
  type ModalSandbox = Awaited<ReturnType<ModalClient['sandboxes']['create']>>;
42
44
 
45
+ class ModalPayloadUploadTimeoutError extends Error {
46
+ constructor(input: { sandboxId: string; path: string; bytes: number }) {
47
+ super(
48
+ `MODAL_PAYLOAD_UPLOAD_TIMEOUT: Modal payload upload did not complete within ${MODAL_PAYLOAD_UPLOAD_TIMEOUT_MS}ms (sandbox=${input.sandboxId}, path=${input.path}, bytes=${input.bytes}).`,
49
+ );
50
+ this.name = 'ModalPayloadUploadTimeoutError';
51
+ }
52
+ }
53
+
54
+ async function writeModalFileWithDeadline(input: {
55
+ sandbox: ModalSandbox;
56
+ content: Buffer;
57
+ path: string;
58
+ cancellation: Promise<never>;
59
+ }): Promise<void> {
60
+ let timer: ReturnType<typeof setTimeout> | undefined;
61
+ const deadline = new Promise<never>((_resolve, reject) => {
62
+ timer = setTimeout(() => {
63
+ reject(
64
+ new ModalPayloadUploadTimeoutError({
65
+ sandboxId: input.sandbox.sandboxId,
66
+ path: input.path,
67
+ bytes: input.content.byteLength,
68
+ }),
69
+ );
70
+ }, MODAL_PAYLOAD_UPLOAD_TIMEOUT_MS);
71
+ });
72
+ try {
73
+ await Promise.race([
74
+ input.sandbox.filesystem.writeBytes(input.content, input.path),
75
+ input.cancellation,
76
+ deadline,
77
+ ]);
78
+ } finally {
79
+ if (timer) clearTimeout(timer);
80
+ }
81
+ }
82
+
43
83
  /**
44
84
  * A create RPC that outlives its client deadline is fundamentally ambiguous:
45
85
  * Modal may still create the sandbox after the caller stops waiting. It is
@@ -185,10 +225,22 @@ async function confirmDetachedModalRunnerReady(input: {
185
225
  }
186
226
 
187
227
  async function terminateModalSandbox(sandbox: ModalSandbox): Promise<boolean> {
228
+ let timer: ReturnType<typeof setTimeout> | undefined;
188
229
  try {
189
230
  // The default terminate call only acknowledges the request. Capacity may
190
231
  // be released only after Modal confirms the sandbox itself has stopped.
191
- await sandbox.terminate({ wait: true });
232
+ await Promise.race([
233
+ sandbox.terminate({ wait: true }),
234
+ new Promise<never>((_resolve, reject) => {
235
+ timer = setTimeout(() => {
236
+ reject(
237
+ new Error(
238
+ `Modal sandbox termination did not settle within ${MODAL_TERMINATION_TIMEOUT_MS}ms.`,
239
+ ),
240
+ );
241
+ }, MODAL_TERMINATION_TIMEOUT_MS);
242
+ }),
243
+ ]);
192
244
  return true;
193
245
  } catch (error) {
194
246
  console.warn('[play-runner.modal.terminate_failed]', {
@@ -196,6 +248,8 @@ async function terminateModalSandbox(sandbox: ModalSandbox): Promise<boolean> {
196
248
  error: error instanceof Error ? error.message : String(error),
197
249
  });
198
250
  return false;
251
+ } finally {
252
+ if (timer) clearTimeout(timer);
199
253
  }
200
254
  }
201
255
 
@@ -529,7 +583,12 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
529
583
  sandbox: {
530
584
  id: sandbox.sandboxId,
531
585
  uploadFile: (content, path) =>
532
- sandbox.filesystem.writeBytes(content, path),
586
+ writeModalFileWithDeadline({
587
+ sandbox,
588
+ content,
589
+ path,
590
+ cancellation: cancellationPromise,
591
+ }),
533
592
  },
534
593
  bundlePromise: buildPlayRunnerBundle(),
535
594
  config,
@@ -1,6 +1,7 @@
1
1
  import type { PlayRunnerBackend } from './types';
2
2
  import { daytonaPlayRunnerBackend } from './backends/daytona';
3
3
  import {
4
+ daytonaModalCanaryPlayRunnerBackend,
4
5
  daytonaModalFallbackPlayRunnerBackend,
5
6
  daytonaOnlyPlayRunnerBackend,
6
7
  modalOnlyPlayRunnerBackend,
@@ -14,6 +15,8 @@ import {
14
15
  type PlayRuntimeBackendId,
15
16
  } from '@shared_libs/play-runtime/backend';
16
17
  import {
18
+ isRuntimeSandboxCanaryProduction,
19
+ RUNTIME_SANDBOX_PLACEMENT_POLICIES,
17
20
  runtimeSandboxPlacementPolicyForBackend,
18
21
  type RuntimeSandboxPlacementPolicyId,
19
22
  } from '@shared_libs/play-runtime/runtime-sandbox-placement-policy';
@@ -32,6 +35,13 @@ export function resolvePlayRunnerBackend(
32
35
  );
33
36
  const placementPolicy = runtimeSandboxPlacementPolicyForBackend(backend);
34
37
  if (placementPolicy) {
38
+ if (
39
+ placementPolicy.id ===
40
+ RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaModalCanaryV1 &&
41
+ !isRuntimeSandboxCanaryProduction({ nodeEnv: process.env.NODE_ENV })
42
+ ) {
43
+ return daytonaModalFallbackPlayRunnerBackend;
44
+ }
35
45
  return resolveRuntimeSandboxPlacementBackend(placementPolicy.id);
36
46
  }
37
47
  if (backend === PLAY_RUNTIME_BACKENDS.localProcess) {
@@ -42,6 +52,7 @@ export function resolvePlayRunnerBackend(
42
52
 
43
53
  export {
44
54
  daytonaPlayRunnerBackend,
55
+ daytonaModalCanaryPlayRunnerBackend,
45
56
  daytonaModalFallbackPlayRunnerBackend,
46
57
  daytonaOnlyPlayRunnerBackend,
47
58
  localProcessPlayRunnerBackend,
@@ -1,4 +1,6 @@
1
1
  import { PLAY_RUNTIME_BACKENDS, type PlayRuntimeBackendId } from './backend';
2
+ import { createHash } from 'node:crypto';
3
+ import { isIsolatedRuntimeSchedulerSchema } from './runtime-scheduler-topology';
2
4
 
3
5
  export const RUNTIME_SANDBOX_PROVIDERS = {
4
6
  daytona: 'daytona',
@@ -15,6 +17,7 @@ export type RuntimeSandboxProvider =
15
17
  export const RUNTIME_SANDBOX_PLACEMENT_POLICIES = {
16
18
  daytonaOnlyV1: 'daytona_only@1',
17
19
  daytonaThenModalV1: 'daytona_then_modal@1',
20
+ daytonaModalCanaryV1: 'daytona_modal_canary@1',
18
21
  modalOnlyV1: 'modal_only@1',
19
22
  } as const;
20
23
 
@@ -41,8 +44,59 @@ export type RuntimeSandboxPlacementPolicy = Readonly<{
41
44
  transitions: readonly RuntimeSandboxPlacementTransition[];
42
45
  requiredCredentialEnv: readonly string[];
43
46
  cleanupProviders: readonly RuntimeSandboxProvider[];
47
+ canary?: Readonly<{
48
+ provider: RuntimeSandboxProvider;
49
+ basisPoints: number;
50
+ selector: 'sha256_run_id_basis_points@1';
51
+ environment: 'production';
52
+ }>;
44
53
  }>;
45
54
 
55
+ const CANARY_BUCKET_COUNT = 10_000;
56
+
57
+ export type RuntimeSandboxCanarySelection = Readonly<{
58
+ canary: RuntimeSandboxProvider | null;
59
+ bucket: number | null;
60
+ basisPoints: number;
61
+ }>;
62
+
63
+ export function isRuntimeSandboxCanaryProduction(input: {
64
+ nodeEnv?: string | null;
65
+ runtimeSchedulerSchema?: string | null;
66
+ }): boolean {
67
+ return (
68
+ input.nodeEnv === 'production' &&
69
+ !isIsolatedRuntimeSchedulerSchema(input.runtimeSchedulerSchema)
70
+ );
71
+ }
72
+
73
+ /** Stable across scheduler attempts and worker processes for a durable run id. */
74
+ export function selectRuntimeSandboxCanary(input: {
75
+ policy: RuntimeSandboxPlacementPolicy;
76
+ runId?: string | null;
77
+ production: boolean;
78
+ }): RuntimeSandboxCanarySelection {
79
+ const canary = input.policy.canary;
80
+ const runId = input.runId?.trim();
81
+ if (!canary || !runId || !input.production) {
82
+ return {
83
+ canary: null,
84
+ bucket: null,
85
+ basisPoints: canary?.basisPoints ?? 0,
86
+ };
87
+ }
88
+ const bucket =
89
+ createHash('sha256')
90
+ .update(`runtime-sandbox-placement@1:${runId}`)
91
+ .digest()
92
+ .readUInt32BE(0) % CANARY_BUCKET_COUNT;
93
+ return {
94
+ canary: bucket < canary.basisPoints ? canary.provider : null,
95
+ bucket,
96
+ basisPoints: canary.basisPoints,
97
+ };
98
+ }
99
+
46
100
  const DAYTONA_THEN_MODAL_V1: RuntimeSandboxPlacementPolicy = {
47
101
  id: RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaThenModalV1,
48
102
  compatibilityRuntimeBackend: PLAY_RUNTIME_BACKENDS.daytona,
@@ -72,6 +126,23 @@ const DAYTONA_THEN_MODAL_V1: RuntimeSandboxPlacementPolicy = {
72
126
  ],
73
127
  };
74
128
 
129
+ /**
130
+ * Staged Daytona-compatible policy. Workers learn this policy before launch
131
+ * writers start persisting it, so an app-first deploy cannot strand runs on an
132
+ * unsupported policy id. One percent of production runs enter the same Modal
133
+ * Adapter used by DAYTONA_THEN_MODAL_V1 after a capacity failure.
134
+ */
135
+ const DAYTONA_MODAL_CANARY_V1: RuntimeSandboxPlacementPolicy = {
136
+ ...DAYTONA_THEN_MODAL_V1,
137
+ id: RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaModalCanaryV1,
138
+ canary: {
139
+ provider: RUNTIME_SANDBOX_PROVIDERS.modal,
140
+ basisPoints: 100,
141
+ selector: 'sha256_run_id_basis_points@1',
142
+ environment: 'production',
143
+ },
144
+ };
145
+
75
146
  /**
76
147
  * Frozen compatibility policy for launches written before placement policy ids
77
148
  * existed. It is retained until every pre-policy release lane has drained.
@@ -100,6 +171,8 @@ export const RUNTIME_SANDBOX_PLACEMENT_POLICY_CATALOG: Readonly<
100
171
  [RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaOnlyV1]: DAYTONA_ONLY_V1,
101
172
  [RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaThenModalV1]:
102
173
  DAYTONA_THEN_MODAL_V1,
174
+ [RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaModalCanaryV1]:
175
+ DAYTONA_MODAL_CANARY_V1,
103
176
  [RUNTIME_SANDBOX_PLACEMENT_POLICIES.modalOnlyV1]: MODAL_ONLY_V1,
104
177
  };
105
178
 
@@ -129,7 +202,7 @@ export function runtimeSandboxPlacementPolicyForBackend(
129
202
  backend: PlayRuntimeBackendId,
130
203
  ): RuntimeSandboxPlacementPolicy | null {
131
204
  if (backend === PLAY_RUNTIME_BACKENDS.daytona) {
132
- return DAYTONA_THEN_MODAL_V1;
205
+ return DAYTONA_MODAL_CANARY_V1;
133
206
  }
134
207
  if (backend === PLAY_RUNTIME_BACKENDS.modal) {
135
208
  return MODAL_ONLY_V1;
@@ -42,6 +42,11 @@ export const TOOL_CATEGORY_DESCRIPTIONS: Readonly<Record<string, string>> = {
42
42
  free: 'Free tools that do not spend Deepline credits.',
43
43
  };
44
44
 
45
+ /** Stable UI/CLI enumeration of the well-known canonical category slugs. */
46
+ export const WELL_KNOWN_TOOL_CATEGORIES = Object.freeze(
47
+ Object.keys(TOOL_CATEGORY_DESCRIPTIONS),
48
+ );
49
+
45
50
  /**
46
51
  * One-line definition for a tool category slug, or null when none is declared.
47
52
  * Never fabricates a definition for unknown slugs.