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.
- package/dist/bundling-sources/sdk/src/http.ts +3 -20
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/skills-version.ts +107 -0
- package/dist/bundling-sources/sdk/src/types.ts +18 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +83 -7
- package/dist/bundling-sources/shared_libs/play-runtime/db-session-plan.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/projection.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +8 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-modal-fallback.ts +101 -10
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +61 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/index.ts +11 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-placement-policy.ts +74 -1
- package/dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts +5 -0
- package/dist/cli/index.js +678 -857
- package/dist/cli/index.mjs +748 -927
- package/dist/index.d.mts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +78 -22
- package/dist/index.mjs +84 -28
- package/dist/install-integrity.json +1 -0
- package/package.json +1 -1
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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.
|