deepline 0.3.88 → 0.3.89
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/client.ts +534 -4
- package/dist/bundling-sources/sdk/src/config.ts +77 -0
- package/dist/bundling-sources/sdk/src/http.ts +76 -30
- package/dist/bundling-sources/sdk/src/index.ts +6 -0
- package/dist/bundling-sources/sdk/src/monitor-fleet-contract.ts +1 -1
- package/dist/bundling-sources/sdk/src/play.ts +15 -1
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +2 -2
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +83 -4
- package/dist/bundling-sources/shared_libs/integration-contracts/AGENTS.md +9 -0
- package/dist/bundling-sources/shared_libs/integration-contracts/README.md +3 -0
- package/dist/bundling-sources/shared_libs/integration-contracts/index.ts +2 -0
- package/dist/bundling-sources/shared_libs/monitors/analytics-install-guides.ts +77 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/charges.ts +125 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/policy-builders.ts +686 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/pricing.ts +54 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/public-pricing.ts +72 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/session.ts +45 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/state.ts +454 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/tamradar.ts +260 -0
- package/dist/bundling-sources/shared_libs/monitors/billing/types.ts +215 -0
- package/dist/bundling-sources/shared_libs/monitors/callback-security.ts +333 -0
- package/dist/bundling-sources/shared_libs/monitors/cursor-page.ts +42 -0
- package/dist/bundling-sources/shared_libs/monitors/deactivation-reasons.ts +16 -0
- package/dist/bundling-sources/shared_libs/monitors/framework-managed-payload-fields.ts +71 -0
- package/dist/bundling-sources/shared_libs/monitors/generated/provider-monitor-callback-admission-targets.ts +16 -0
- package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +267 -0
- package/dist/bundling-sources/shared_libs/monitors/inbound-publish-key.ts +39 -0
- package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +82 -0
- package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +473 -0
- package/dist/bundling-sources/shared_libs/monitors/org-monitor-limits.ts +1 -1
- package/dist/bundling-sources/shared_libs/monitors/package.json +29 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-callback-verification.ts +1125 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +263 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-capability.ts +964 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-consumer-health.ts +56 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-errors.ts +131 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-identity-claims.ts +535 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-legacy-aliases.ts +16 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-priority-execution.ts +56 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-public-aliases.ts +28 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-runtime-read-eligibility.ts +38 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-state.ts +122 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-status.ts +10 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-upstream-identity.ts +112 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-webhook-monitor-runtime.ts +300 -0
- package/dist/bundling-sources/shared_libs/monitors/quickstart-prompts.ts +22 -0
- package/dist/bundling-sources/shared_libs/monitors/snitcher-install-validation.ts +93 -0
- package/dist/bundling-sources/shared_libs/monitors/snitcher-ip2company.ts +332 -0
- package/dist/bundling-sources/shared_libs/monitors/snitcher-radar.ts +221 -0
- package/dist/bundling-sources/shared_libs/monitors/starter-templates.ts +105 -0
- package/dist/bundling-sources/shared_libs/monitors/tracking-provider-guidance.ts +73 -0
- package/dist/bundling-sources/shared_libs/monitors/tracking-provider-integrations.ts +81 -0
- package/dist/bundling-sources/shared_libs/monitors/tsconfig.json +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/activity-observation.ts +6 -11
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +90 -12
- package/dist/bundling-sources/shared_libs/play-runtime/async-play-invocation.ts +78 -0
- package/dist/bundling-sources/shared_libs/play-runtime/checkpoint-boundaries.ts +70 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +407 -53
- package/dist/bundling-sources/shared_libs/play-runtime/coordinator-headers.ts +1 -32
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +57 -0
- package/dist/bundling-sources/shared_libs/play-runtime/default-batch-strategies.ts +20 -1
- package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-protocol.ts +7 -1
- package/dist/bundling-sources/shared_libs/play-runtime/lane-retirement-gate.ts +189 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +28 -0
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +23 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +18 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-start-admission.ts +68 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +10 -8
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +20 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-env.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +24 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +30 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +6 -3
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +454 -17
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +19 -4
- package/dist/bundling-sources/shared_libs/plays/contracts.ts +6 -14
- package/dist/bundling-sources/shared_libs/plays/core.ts +11 -6
- package/dist/bundling-sources/shared_libs/plays/docflow-binding-owner.ts +16 -11
- package/dist/bundling-sources/shared_libs/plays/email-status.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/resolve-static-pipeline.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/slug.ts +115 -0
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +44 -14
- package/dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts +2 -2
- package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +877 -0
- package/dist/bundling-sources/shared_libs/product-notifications/configuration-draft.ts +456 -0
- package/dist/bundling-sources/shared_libs/product-notifications/configuration.ts +560 -0
- package/dist/bundling-sources/shared_libs/product-notifications/content.ts +28 -0
- package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +59 -0
- package/dist/bundling-sources/shared_libs/product-notifications/email.ts +246 -0
- package/dist/bundling-sources/shared_libs/product-notifications/evaluation.ts +280 -0
- package/dist/bundling-sources/shared_libs/product-notifications/events.ts +433 -0
- package/dist/bundling-sources/shared_libs/product-notifications/legacy-slack.ts +80 -0
- package/dist/bundling-sources/shared_libs/product-notifications/workspace.ts +38 -0
- package/dist/bundling-sources/shared_libs/runtime-env.ts +6 -0
- package/dist/bundling-sources/shared_libs/security/header-safe-env.ts +28 -0
- package/dist/bundling-sources/shared_libs/security/internal-actor.ts +50 -0
- package/dist/bundling-sources/shared_libs/security/secret-redaction.ts +267 -0
- package/dist/cli/index.js +1070 -193
- package/dist/cli/index.mjs +1057 -180
- package/dist/{compiler-manifest-Dbov16F7.d.mts → compiler-manifest-DsLbQaew.d.mts} +132 -8
- package/dist/{compiler-manifest-Dbov16F7.d.ts → compiler-manifest-DsLbQaew.d.ts} +132 -8
- package/dist/index.d.mts +834 -12
- package/dist/index.d.ts +834 -12
- package/dist/index.js +469 -40
- package/dist/index.mjs +469 -40
- package/dist/install-integrity.json +65 -4
- package/dist/plays/bundle-play-file.d.mts +8 -3
- package/dist/plays/bundle-play-file.d.ts +8 -3
- package/dist/plays/bundle-play-file.mjs +100 -20
- package/package.json +3 -1
- /package/dist/bundling-sources/shared_libs/{integrations/bettercontact-execution-policy.ts → integration-contracts/bettercontact/execution-policy.ts} +0 -0
- /package/dist/bundling-sources/shared_libs/{integrations/theirstack-execution-policy.ts → integration-contracts/theirstack/execution-policy.ts} +0 -0
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* HTTP headers attached to every server-to-coordinator request.
|
|
3
|
-
*
|
|
4
|
-
* The coordinator is a Cloudflare Worker (`deepline-play-coordinator-*`) that
|
|
5
|
-
* we publish through Cloudflare's Versions + Deployments primitives. Whenever
|
|
6
|
-
* a deployment is split across two versions (e.g. 10% canary), Cloudflare
|
|
7
|
-
* uses the `Cloudflare-Workers-Version-Key` header to pick a stable version
|
|
8
|
-
* per request. Sending the runId as the key keeps every request for one play
|
|
9
|
-
* run pinned to whichever version started the run, so a partial rollout
|
|
10
|
-
* cannot strand a Workflow's `/submit` and `/result` calls on different
|
|
11
|
-
* code versions.
|
|
12
|
-
*
|
|
13
|
-
* The header is harmless when there is only one active version (the default).
|
|
14
3
|
*/
|
|
15
|
-
|
|
16
|
-
export const COORDINATOR_VERSION_OVERRIDES_HEADER =
|
|
17
|
-
'Cloudflare-Workers-Version-Overrides';
|
|
4
|
+
|
|
18
5
|
/**
|
|
19
6
|
* Shared secret the coordinator uses to authenticate dispatcher (Vercel app)
|
|
20
7
|
* traffic. The coordinator also sanity-checks `x-deepline-run-scope` matches
|
|
@@ -88,8 +75,6 @@ export function coordinatorRequestHeaders(input: {
|
|
|
88
75
|
runId: string;
|
|
89
76
|
contentType?: string | null;
|
|
90
77
|
internalToken?: string | null;
|
|
91
|
-
runtimeDeployVersion?: string | null;
|
|
92
|
-
coordinatorWorkerName?: string | null;
|
|
93
78
|
/**
|
|
94
79
|
* When set, the coordinator validates this matches the runId in the URL.
|
|
95
80
|
* Pass the runId on `/cancel` / `/signal` calls so a leaked dispatcher
|
|
@@ -102,22 +87,6 @@ export function coordinatorRequestHeaders(input: {
|
|
|
102
87
|
headers['content-type'] = input.contentType;
|
|
103
88
|
}
|
|
104
89
|
const trimmed = input.runId.trim();
|
|
105
|
-
if (trimmed) {
|
|
106
|
-
headers[COORDINATOR_VERSION_KEY_HEADER] = trimmed;
|
|
107
|
-
}
|
|
108
|
-
const runtimeDeployVersion = input.runtimeDeployVersion?.trim();
|
|
109
|
-
const coordinatorWorkerName = input.coordinatorWorkerName?.trim();
|
|
110
|
-
if (
|
|
111
|
-
runtimeDeployVersion &&
|
|
112
|
-
coordinatorWorkerName &&
|
|
113
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
|
|
114
|
-
runtimeDeployVersion,
|
|
115
|
-
) &&
|
|
116
|
-
/^[A-Za-z0-9_-]+$/.test(coordinatorWorkerName)
|
|
117
|
-
) {
|
|
118
|
-
headers[COORDINATOR_VERSION_OVERRIDES_HEADER] =
|
|
119
|
-
`${coordinatorWorkerName}="${runtimeDeployVersion}"`;
|
|
120
|
-
}
|
|
121
90
|
const internalToken =
|
|
122
91
|
input.internalToken?.trim() || resolveInternalCoordinatorToken();
|
|
123
92
|
if (internalToken) {
|
|
@@ -10,8 +10,10 @@ import type { PlayRunContractSnapshot } from '../plays/contracts';
|
|
|
10
10
|
import type { PlayStructuredDefinition } from '../plays/definition';
|
|
11
11
|
import type { PlayStaticPipeline } from '../plays/static-pipeline';
|
|
12
12
|
import type {
|
|
13
|
+
AsyncPlayRunRef,
|
|
13
14
|
DurableCallStaleAfterSeconds,
|
|
14
15
|
PlayAuthoringCallOptions,
|
|
16
|
+
PlayAuthoringAsyncCallOptions,
|
|
15
17
|
PlayAuthoringCsvOptions,
|
|
16
18
|
PlayAuthoringFetchOptions,
|
|
17
19
|
PlayAuthoringRuntimeStepOptions,
|
|
@@ -331,6 +333,19 @@ export type PlayCallOptions = Omit<
|
|
|
331
333
|
timeoutMs?: number;
|
|
332
334
|
};
|
|
333
335
|
|
|
336
|
+
export type PlayAsyncCallOptions = PlayAuthoringAsyncCallOptions;
|
|
337
|
+
|
|
338
|
+
export type AsyncPlayLaunchRequest = Readonly<{
|
|
339
|
+
key: string;
|
|
340
|
+
invocationKey: string;
|
|
341
|
+
playRef: string;
|
|
342
|
+
input: Record<string, unknown>;
|
|
343
|
+
description: string;
|
|
344
|
+
schedulerSchema: string | null;
|
|
345
|
+
/** Governor ancestry at the authored call site, before entering the child. */
|
|
346
|
+
ancestryPlayIds: readonly string[];
|
|
347
|
+
}>;
|
|
348
|
+
|
|
334
349
|
export type RuntimeStepOptions = PlayAuthoringRuntimeStepOptions;
|
|
335
350
|
|
|
336
351
|
export type FetchOptions = PlayAuthoringFetchOptions;
|
|
@@ -345,6 +360,16 @@ export interface ResolvedPlayExecution {
|
|
|
345
360
|
definition?: PlayStructuredDefinition | null;
|
|
346
361
|
staticPipeline?: PlayStaticPipeline | null;
|
|
347
362
|
contractSnapshot?: PlayRunContractSnapshot | null;
|
|
363
|
+
launchMetadata?: {
|
|
364
|
+
revisionId?: string | null;
|
|
365
|
+
artifactStorageKey: string;
|
|
366
|
+
artifactHash: string;
|
|
367
|
+
graphHash: string;
|
|
368
|
+
definitionScope: 'org' | 'system';
|
|
369
|
+
authoringContract?:
|
|
370
|
+
| import('../plays/authoring-contract').AdmittedPlayAuthoringContract
|
|
371
|
+
| null;
|
|
372
|
+
} | null;
|
|
348
373
|
}
|
|
349
374
|
|
|
350
375
|
export interface BatchRequest {
|
|
@@ -548,6 +573,7 @@ export type IntegrationEventWaitRuntimeContext = {
|
|
|
548
573
|
workflowId?: string;
|
|
549
574
|
orgId?: string;
|
|
550
575
|
executorToken?: string;
|
|
576
|
+
slackHitlDefaultTimeoutMs?: number;
|
|
551
577
|
};
|
|
552
578
|
|
|
553
579
|
export type IntegrationEventWaitBoundary = {
|
|
@@ -560,6 +586,14 @@ export type IntegrationEventWaitBoundary = {
|
|
|
560
586
|
channel: string;
|
|
561
587
|
ts: string;
|
|
562
588
|
};
|
|
589
|
+
/**
|
|
590
|
+
* Optional control-plane timeout behavior. Missing preserves the legacy
|
|
591
|
+
* "return the timed_out result" replay behavior for older app deployments.
|
|
592
|
+
*/
|
|
593
|
+
timeoutPolicy?: {
|
|
594
|
+
suspendAfterTimeoutMs?: number;
|
|
595
|
+
finalizeOnTimeout?: boolean;
|
|
596
|
+
};
|
|
563
597
|
};
|
|
564
598
|
|
|
565
599
|
export type IntegrationEventWaitHandler = {
|
|
@@ -584,6 +618,11 @@ export type IntegrationEventWaitHandler = {
|
|
|
584
618
|
context: IntegrationEventWaitRuntimeContext;
|
|
585
619
|
boundary: IntegrationEventWaitBoundary;
|
|
586
620
|
}) => Promise<void>;
|
|
621
|
+
/**
|
|
622
|
+
* When set, timeout finalization is side-effect-only: the Play stays parked
|
|
623
|
+
* instead of consuming a `timed_out` result.
|
|
624
|
+
*/
|
|
625
|
+
suspendAfterTimeoutMs?: number;
|
|
587
626
|
};
|
|
588
627
|
|
|
589
628
|
export interface ContextOptions {
|
|
@@ -769,6 +808,8 @@ export interface ContextOptions {
|
|
|
769
808
|
}) => Promise<void>;
|
|
770
809
|
playId?: string;
|
|
771
810
|
runId?: string;
|
|
811
|
+
/** Shared governance/billing root. Differs from runId for async children. */
|
|
812
|
+
rootRunId?: string;
|
|
772
813
|
/** Physical executor run that owns leases for an inline child context. */
|
|
773
814
|
runtimeReceiptOwnerRunId?: string;
|
|
774
815
|
/** Logical invocation scope for receipts created inside an inline child. */
|
|
@@ -800,6 +841,10 @@ export interface ContextOptions {
|
|
|
800
841
|
*/
|
|
801
842
|
runtimeSheetBackedMapDatasets?: boolean;
|
|
802
843
|
resolvePlay?: (playRef: string) => Promise<ResolvedPlayExecution | null>;
|
|
844
|
+
/** Admit an independently scheduled scalar/HITL Play Run. */
|
|
845
|
+
launchPlayAsync?: (
|
|
846
|
+
request: AsyncPlayLaunchRequest,
|
|
847
|
+
) => Promise<AsyncPlayRunRef>;
|
|
803
848
|
getToolQueueHints?: (toolId: string) => Promise<readonly PlayQueueHint[]>;
|
|
804
849
|
getToolProvider?: (toolId: string) => Promise<string | null>;
|
|
805
850
|
getToolOperation?: (toolId: string) => Promise<string | null>;
|
|
@@ -1147,6 +1192,12 @@ export type PlayStep =
|
|
|
1147
1192
|
nestedSteps: PlayStep[];
|
|
1148
1193
|
description?: string;
|
|
1149
1194
|
}
|
|
1195
|
+
| {
|
|
1196
|
+
type: 'play_launch';
|
|
1197
|
+
playId: string;
|
|
1198
|
+
runId: string;
|
|
1199
|
+
description?: string;
|
|
1200
|
+
}
|
|
1150
1201
|
| {
|
|
1151
1202
|
type: 'run_javascript';
|
|
1152
1203
|
alias: string;
|
|
@@ -1187,6 +1238,12 @@ export type PlayDatasetSubstep =
|
|
|
1187
1238
|
nestedSteps: PlayStep[];
|
|
1188
1239
|
description?: string;
|
|
1189
1240
|
}
|
|
1241
|
+
| {
|
|
1242
|
+
type: 'play_launch';
|
|
1243
|
+
playId: string;
|
|
1244
|
+
runId: string;
|
|
1245
|
+
description?: string;
|
|
1246
|
+
}
|
|
1190
1247
|
| {
|
|
1191
1248
|
type: 'run_javascript';
|
|
1192
1249
|
alias: string;
|
|
@@ -10,6 +10,15 @@ type TestRateLimitPayload = {
|
|
|
10
10
|
lead_id?: string;
|
|
11
11
|
row_number?: number;
|
|
12
12
|
simulated_delay_ms?: number;
|
|
13
|
+
emit_security_gateway?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Synthetic-provider-only switch. The large-payload gauntlet uses the batch
|
|
16
|
+
* response as a transport fixture and does not inspect per-item execution
|
|
17
|
+
* counters, so it can avoid creating thousands of unrelated test-state rows.
|
|
18
|
+
*/
|
|
19
|
+
track_item_execution?: boolean;
|
|
20
|
+
simulated_cooldown_ms?: number;
|
|
21
|
+
cooldown_failures_before_success?: number;
|
|
13
22
|
};
|
|
14
23
|
|
|
15
24
|
type TestRateLimitBatchPayload = {
|
|
@@ -83,7 +92,17 @@ const testRateLimitBatchStrategy: BatchOperationStrategy<
|
|
|
83
92
|
maxBatchSize: 200,
|
|
84
93
|
bucketKeyPayloadFields: ['stage'],
|
|
85
94
|
canBatchWith(left, right) {
|
|
86
|
-
|
|
95
|
+
// One upstream native batch has one 429/Retry-After outcome. Cooldown
|
|
96
|
+
// fixtures therefore only share a physical request when they requested
|
|
97
|
+
// the exact same policy; a normal member must never inherit another
|
|
98
|
+
// member's synthetic provider failure.
|
|
99
|
+
return (
|
|
100
|
+
String(left.stage || '') === String(right.stage || '') &&
|
|
101
|
+
Number(left.simulated_cooldown_ms ?? 0) ===
|
|
102
|
+
Number(right.simulated_cooldown_ms ?? 0) &&
|
|
103
|
+
Number(left.cooldown_failures_before_success ?? 0) ===
|
|
104
|
+
Number(right.cooldown_failures_before_success ?? 0)
|
|
105
|
+
);
|
|
87
106
|
},
|
|
88
107
|
toBucketKey(payload) {
|
|
89
108
|
return `test_batch_rate_limit:${String(payload.stage || '')}`;
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
validateFixtureBehavior,
|
|
3
3
|
type FixtureBehavior,
|
|
4
4
|
} from './fixture-behavior';
|
|
5
|
+
import { normalizeRuntimeSchedulerSchema } from './runtime-scheduler-topology';
|
|
5
6
|
|
|
6
7
|
export const RUNTIME_EXECUTION_CAPABILITIES = [
|
|
7
8
|
'artifact.read',
|
|
@@ -46,6 +47,8 @@ export type RuntimeAuthorityDescriptor = {
|
|
|
46
47
|
synthetic?: boolean | null;
|
|
47
48
|
actorUserId?: string | null;
|
|
48
49
|
actorEmail?: string | null;
|
|
50
|
+
/** Durable scheduler topology, carried into each newly minted attempt token. */
|
|
51
|
+
schedulerSchema?: string | null;
|
|
49
52
|
/**
|
|
50
53
|
* Whether THIS run may capture the docflow provenance trace.
|
|
51
54
|
*
|
|
@@ -142,6 +145,9 @@ export function requireRuntimeAuthorityDescriptor(
|
|
|
142
145
|
synthetic: descriptor.synthetic === true,
|
|
143
146
|
actorUserId: descriptor.actorUserId ?? null,
|
|
144
147
|
actorEmail: descriptor.actorEmail ?? null,
|
|
148
|
+
schedulerSchema: normalizeRuntimeSchedulerSchema(
|
|
149
|
+
descriptor.schedulerSchema,
|
|
150
|
+
),
|
|
145
151
|
// `=== true`, not `?? false`: the normalizer is what a durable launch is
|
|
146
152
|
// read back through, so anything that is not an explicit yes — missing,
|
|
147
153
|
// null, a string that survived a JSON round trip — denies.
|
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
export const PLAY_RUNTIME_PROTOCOL = {
|
|
12
12
|
/** Launches written before this field existed. */
|
|
13
13
|
legacy: 0,
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Current scheduler/runner protocol. This number STAYS AT 1: the additive
|
|
16
|
+
* compatibility rule (`docs/runtime-compatibility-contract.md`) covers new
|
|
17
|
+
* fields and new named actions without a bump. A bump is a fence release —
|
|
18
|
+
* two PRs, expand worker support first, then enable — and needs a written
|
|
19
|
+
* reason the additive rule cannot serve.
|
|
20
|
+
*/
|
|
15
21
|
current: 1,
|
|
16
22
|
} as const;
|
|
17
23
|
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Absurd release-lane retirement gate, as dependency-free pure logic.
|
|
3
|
+
*
|
|
4
|
+
* This lives in its own module because three very different processes must
|
|
5
|
+
* reach exactly the same verdict and none of them may drag the others'
|
|
6
|
+
* dependencies in:
|
|
7
|
+
*
|
|
8
|
+
* - the Next.js app (`src/lib/plays/runtime-lanes.ts`, the admin and internal
|
|
9
|
+
* lane endpoints), which also talks to Convex;
|
|
10
|
+
* - `scripts/fly-absurd-lane.ts` retire, run by the release controller; and
|
|
11
|
+
* - `apps/absurd-release-scaler/index.ts`, which owns retirement of every lane
|
|
12
|
+
* the release controller handed over, and whose Fly image does not contain
|
|
13
|
+
* `packages/convex/`.
|
|
14
|
+
*
|
|
15
|
+
* The gate clears two ways:
|
|
16
|
+
*
|
|
17
|
+
* 1. **Empty.** No non-terminal task on the lane's queue and no non-terminal
|
|
18
|
+
* run row referencing its release id.
|
|
19
|
+
* 2. **Adopted parked (lane handoff).** The lane has been marked not claiming,
|
|
20
|
+
* nothing on it is claimable or running, and every remaining non-terminal
|
|
21
|
+
* run is parked in a durable wait the newest lane adopts.
|
|
22
|
+
*
|
|
23
|
+
* Anything else is blocked, and `blockedBy` names which of the two halves is
|
|
24
|
+
* responsible so an operator is not left guessing at a bare depth count.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The subset of a lane's depth the gate reads.
|
|
29
|
+
*
|
|
30
|
+
* Every field is optional because the gate is also evaluated against a lane
|
|
31
|
+
* view that crossed the wire from a control plane which may be older than its
|
|
32
|
+
* caller: the release-aware scaler is deployed from the same release as the
|
|
33
|
+
* app, but a scaler image can outlive the app deployment it polls. A fact that
|
|
34
|
+
* did not arrive is never guessed — see `adoption-facts-unavailable`.
|
|
35
|
+
*/
|
|
36
|
+
export type LaneRetirementGateFacts = {
|
|
37
|
+
/** Non-terminal tasks on `absurd.t_<queue>`. */
|
|
38
|
+
queuedTasks?: number;
|
|
39
|
+
claimableTasks?: number;
|
|
40
|
+
runningTasks?: number;
|
|
41
|
+
/** Non-terminal `runs` rows whose launch envelope pins this release id. */
|
|
42
|
+
nonTerminalRuns?: number;
|
|
43
|
+
/** Subset of `nonTerminalRuns` parked in a wait the newest lane adopts. */
|
|
44
|
+
adoptableParkedRuns?: number;
|
|
45
|
+
/** Whether this lane still claims work off its own queue. */
|
|
46
|
+
claiming?: boolean;
|
|
47
|
+
/** `queuedTasks === 0 && nonTerminalRuns === 0`. */
|
|
48
|
+
empty?: boolean;
|
|
49
|
+
/** `claimableTasks === 0 && runningTasks === 0 && nonTerminalRuns === adoptableParkedRuns`. */
|
|
50
|
+
emptyExceptAdoptableParked?: boolean;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type LaneRetirementGateBasis = 'empty' | 'adopted-parked' | 'blocked';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Why a blocked lane is blocked. This is the operator-facing half of the gate:
|
|
57
|
+
* each value maps to exactly one remediation.
|
|
58
|
+
*/
|
|
59
|
+
export type LaneRetirementBlockedReason =
|
|
60
|
+
/** Not blocked. */
|
|
61
|
+
| 'none'
|
|
62
|
+
/** Something on this lane is claimable or running right now. Wait. */
|
|
63
|
+
| 'executable-work'
|
|
64
|
+
/**
|
|
65
|
+
* The lane holds nothing but adoptable parked waits, and the ONLY thing
|
|
66
|
+
* keeping it alive is that its claiming switch was never flipped. The lane
|
|
67
|
+
* cannot flip it itself, so without an external write this lane is immortal.
|
|
68
|
+
*/
|
|
69
|
+
| 'still-claiming'
|
|
70
|
+
/**
|
|
71
|
+
* Non-terminal runs this lane can no longer execute and no other lane can
|
|
72
|
+
* adopt: a `detached_runner` park whose sandbox is gone, or a run row with no
|
|
73
|
+
* engine task at all. Nothing will ever wake these; they need an explicit,
|
|
74
|
+
* evidence-gated terminal transition.
|
|
75
|
+
*/
|
|
76
|
+
| 'unadoptable-non-terminal-runs'
|
|
77
|
+
/**
|
|
78
|
+
* The caller's lane view predates the adoption fields. The gate refuses to
|
|
79
|
+
* infer adoption from absent evidence and falls back to the strict `empty`
|
|
80
|
+
* half only.
|
|
81
|
+
*/
|
|
82
|
+
| 'adoption-facts-unavailable';
|
|
83
|
+
|
|
84
|
+
export type LaneRetirementGateResult = {
|
|
85
|
+
ok: boolean;
|
|
86
|
+
basis: LaneRetirementGateBasis;
|
|
87
|
+
blockedBy: LaneRetirementBlockedReason;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Evaluate the retirement gate.
|
|
92
|
+
*
|
|
93
|
+
* Deliberately conservative in one direction only: it never clears a lane on a
|
|
94
|
+
* fact it did not receive. It is safe for the caller to retire on `ok`, because
|
|
95
|
+
* retirement deletes Machines and flips the registry row; it does not drop the
|
|
96
|
+
* queue tables an adopting lane still claims from.
|
|
97
|
+
*/
|
|
98
|
+
export function laneRetirementGate(
|
|
99
|
+
depth: LaneRetirementGateFacts,
|
|
100
|
+
): LaneRetirementGateResult {
|
|
101
|
+
if (depth.empty === true) {
|
|
102
|
+
return { ok: true, basis: 'empty', blockedBy: 'none' };
|
|
103
|
+
}
|
|
104
|
+
if (
|
|
105
|
+
typeof depth.claiming !== 'boolean' ||
|
|
106
|
+
typeof depth.emptyExceptAdoptableParked !== 'boolean' ||
|
|
107
|
+
typeof depth.adoptableParkedRuns !== 'number'
|
|
108
|
+
) {
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
basis: 'blocked',
|
|
112
|
+
blockedBy: 'adoption-facts-unavailable',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (!depth.claiming && depth.emptyExceptAdoptableParked) {
|
|
116
|
+
return { ok: true, basis: 'adopted-parked', blockedBy: 'none' };
|
|
117
|
+
}
|
|
118
|
+
const executable =
|
|
119
|
+
(depth.claimableTasks ?? 0) > 0 || (depth.runningTasks ?? 0) > 0;
|
|
120
|
+
if (executable) {
|
|
121
|
+
return { ok: false, basis: 'blocked', blockedBy: 'executable-work' };
|
|
122
|
+
}
|
|
123
|
+
if (depth.claiming && depth.emptyExceptAdoptableParked) {
|
|
124
|
+
return { ok: false, basis: 'blocked', blockedBy: 'still-claiming' };
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
ok: false,
|
|
128
|
+
basis: 'blocked',
|
|
129
|
+
blockedBy: 'unadoptable-non-terminal-runs',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* The one operator-actionable sentence for a blocked lane.
|
|
135
|
+
*
|
|
136
|
+
* A depth count alone ("11 queued") has repeatedly sent operators looking for
|
|
137
|
+
* live work that is not there. Each reason below has exactly one next step.
|
|
138
|
+
*/
|
|
139
|
+
export function laneRetirementRemediation(
|
|
140
|
+
result: LaneRetirementGateResult,
|
|
141
|
+
): string {
|
|
142
|
+
switch (result.blockedBy) {
|
|
143
|
+
case 'none':
|
|
144
|
+
return result.basis === 'adopted-parked'
|
|
145
|
+
? 'Retirable: nothing here is claimable or running and every remaining run is a parked wait the newest lane adopts.'
|
|
146
|
+
: 'Retirable: this lane holds no non-terminal task and no non-terminal run.';
|
|
147
|
+
case 'executable-work':
|
|
148
|
+
return 'Wait. Work on this lane is claimable or running right now; the scaler keeps a version-matched machine for it.';
|
|
149
|
+
case 'still-claiming':
|
|
150
|
+
return 'Demote the lane. It holds only adoptable parked waits; the newest lane cannot adopt them until this lane stops claiming (lane handoff). The release-aware scaler converges this, or run `bun scripts/fly-absurd-lane.ts stop-claiming --release <id>`.';
|
|
151
|
+
case 'unadoptable-non-terminal-runs':
|
|
152
|
+
return 'Inspect the runs. This lane holds non-terminal runs it can no longer execute and no lane can adopt. Run `deepline-admin runtime stranded scan --release <id> --environment production --json`, then remediate the reviewed cohort with `runtime stranded plan` / `runtime stranded resolve --dry-run`.';
|
|
153
|
+
case 'adoption-facts-unavailable':
|
|
154
|
+
return 'The lane view did not carry the lane handoff adoption fields, so only the strict empty gate was evaluated. Re-read the lane against a control plane from this release.';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Should this lane's claiming switch be converged to `false`?
|
|
160
|
+
*
|
|
161
|
+
* The switch is written exactly once, by the release controller, as a
|
|
162
|
+
* `reclamation` effect whose failure is explicitly tolerated — a failed
|
|
163
|
+
* `stop-prior-lane-claiming` is logged and the release still SUCCEEDS. Absence
|
|
164
|
+
* of the control row reads as "claiming", so a lost write leaves a demoted lane
|
|
165
|
+
* claiming forever. With no machines the lane cannot make progress, and with
|
|
166
|
+
* `claiming` true the newest lane may not adopt it: a permanently unclaimable
|
|
167
|
+
* steady state.
|
|
168
|
+
*
|
|
169
|
+
* This predicate is intentionally narrow. It fires only for a lane whose gate
|
|
170
|
+
* is blocked by the lost write and nothing else, so it can never demote a lane
|
|
171
|
+
* that is still doing something, and it cannot fight `abort_retire` (which
|
|
172
|
+
* re-arms claiming for a lane that has real work, and therefore is not blocked
|
|
173
|
+
* by `still-claiming`).
|
|
174
|
+
*/
|
|
175
|
+
export function shouldConvergeLaneToNotClaiming(lane: {
|
|
176
|
+
active?: boolean;
|
|
177
|
+
status?: string;
|
|
178
|
+
queueDepth?: LaneRetirementGateFacts;
|
|
179
|
+
}): boolean {
|
|
180
|
+
if (lane.active !== false) return false;
|
|
181
|
+
if (lane.status !== 'draining' && lane.status !== 'retiring') return false;
|
|
182
|
+
const depth = lane.queueDepth;
|
|
183
|
+
if (!depth) return false;
|
|
184
|
+
if ((depth.claimableTasks ?? 0) > 0 || (depth.runningTasks ?? 0) > 0) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
if ((depth.adoptableParkedRuns ?? 0) <= 0) return false;
|
|
188
|
+
return laneRetirementGate(depth).blockedBy === 'still-claiming';
|
|
189
|
+
}
|
|
@@ -34,6 +34,9 @@ export type PlayRuntimeSemantics = Readonly<{
|
|
|
34
34
|
*/
|
|
35
35
|
receiptIdentityEdition: PlayAuthoringContractEdition | null;
|
|
36
36
|
}>;
|
|
37
|
+
slackHitl: Readonly<{
|
|
38
|
+
defaultTimeoutMs: number;
|
|
39
|
+
}>;
|
|
37
40
|
}>;
|
|
38
41
|
|
|
39
42
|
function definePlayRuntimeSemantics(
|
|
@@ -43,6 +46,7 @@ function definePlayRuntimeSemantics(
|
|
|
43
46
|
...semantics,
|
|
44
47
|
secrets: Object.freeze({ ...semantics.secrets }),
|
|
45
48
|
fetch: Object.freeze({ ...semantics.fetch }),
|
|
49
|
+
slackHitl: Object.freeze({ ...semantics.slackHitl }),
|
|
46
50
|
});
|
|
47
51
|
}
|
|
48
52
|
|
|
@@ -66,6 +70,14 @@ const PLAINTEXT_SECRET_SEMANTICS = {
|
|
|
66
70
|
secrets: { value: 'plaintext_promise' },
|
|
67
71
|
} as const;
|
|
68
72
|
|
|
73
|
+
const LEGACY_SLACK_HITL_SEMANTICS = {
|
|
74
|
+
defaultTimeoutMs: 24 * 60 * 60 * 1000,
|
|
75
|
+
} as const;
|
|
76
|
+
|
|
77
|
+
const WEEK_LONG_SLACK_HITL_SEMANTICS = {
|
|
78
|
+
defaultTimeoutMs: 7 * 24 * 60 * 60 * 1000,
|
|
79
|
+
} as const;
|
|
80
|
+
|
|
69
81
|
/**
|
|
70
82
|
* Exhaustive compatibility registry for worker-visible Play behavior.
|
|
71
83
|
*
|
|
@@ -77,22 +89,27 @@ const PLAY_RUNTIME_SEMANTICS_BY_EDITION = {
|
|
|
77
89
|
1: definePlayRuntimeSemantics({
|
|
78
90
|
authoringContractEdition: 1,
|
|
79
91
|
...LEGACY_SEMANTICS,
|
|
92
|
+
slackHitl: LEGACY_SLACK_HITL_SEMANTICS,
|
|
80
93
|
}),
|
|
81
94
|
2: definePlayRuntimeSemantics({
|
|
82
95
|
authoringContractEdition: 2,
|
|
83
96
|
...STRICT_SEMANTICS,
|
|
97
|
+
slackHitl: LEGACY_SLACK_HITL_SEMANTICS,
|
|
84
98
|
}),
|
|
85
99
|
3: definePlayRuntimeSemantics({
|
|
86
100
|
authoringContractEdition: 3,
|
|
87
101
|
...STRICT_SEMANTICS,
|
|
102
|
+
slackHitl: LEGACY_SLACK_HITL_SEMANTICS,
|
|
88
103
|
}),
|
|
89
104
|
4: definePlayRuntimeSemantics({
|
|
90
105
|
authoringContractEdition: 4,
|
|
91
106
|
...PLAINTEXT_SECRET_SEMANTICS,
|
|
107
|
+
slackHitl: LEGACY_SLACK_HITL_SEMANTICS,
|
|
92
108
|
}),
|
|
93
109
|
5: definePlayRuntimeSemantics({
|
|
94
110
|
authoringContractEdition: 5,
|
|
95
111
|
...PLAINTEXT_SECRET_SEMANTICS,
|
|
112
|
+
slackHitl: LEGACY_SLACK_HITL_SEMANTICS,
|
|
96
113
|
fetch: {
|
|
97
114
|
httpFailure: 'throw_typed_error',
|
|
98
115
|
persistHttpFailure: false,
|
|
@@ -102,6 +119,7 @@ const PLAY_RUNTIME_SEMANTICS_BY_EDITION = {
|
|
|
102
119
|
6: definePlayRuntimeSemantics({
|
|
103
120
|
authoringContractEdition: 6,
|
|
104
121
|
...PLAINTEXT_SECRET_SEMANTICS,
|
|
122
|
+
slackHitl: LEGACY_SLACK_HITL_SEMANTICS,
|
|
105
123
|
fetch: {
|
|
106
124
|
httpFailure: 'throw_typed_error',
|
|
107
125
|
persistHttpFailure: false,
|
|
@@ -110,6 +128,16 @@ const PLAY_RUNTIME_SEMANTICS_BY_EDITION = {
|
|
|
110
128
|
receiptIdentityEdition: 6,
|
|
111
129
|
},
|
|
112
130
|
}),
|
|
131
|
+
7: definePlayRuntimeSemantics({
|
|
132
|
+
authoringContractEdition: 7,
|
|
133
|
+
...PLAINTEXT_SECRET_SEMANTICS,
|
|
134
|
+
slackHitl: WEEK_LONG_SLACK_HITL_SEMANTICS,
|
|
135
|
+
fetch: {
|
|
136
|
+
httpFailure: 'throw_typed_error',
|
|
137
|
+
persistHttpFailure: false,
|
|
138
|
+
receiptIdentityEdition: 6,
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
113
141
|
} satisfies Record<PlayAuthoringContractEdition, PlayRuntimeSemantics>;
|
|
114
142
|
|
|
115
143
|
export function resolvePlayRuntimeSemantics(
|
|
@@ -152,6 +152,8 @@ export interface PlayRunnerContextConfig {
|
|
|
152
152
|
workflowId?: string;
|
|
153
153
|
playId?: string;
|
|
154
154
|
runId?: string;
|
|
155
|
+
/** Shared governance/billing root. Differs from runId for async children. */
|
|
156
|
+
rootRunId?: string;
|
|
155
157
|
runAttempt?: number | null;
|
|
156
158
|
playName?: string;
|
|
157
159
|
userEmail?: string;
|
|
@@ -170,6 +170,29 @@ export class ProviderExhaustedError extends Error {
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
/**
|
|
174
|
+
* `ProviderExhaustedError` is created inside the runtime, but a tool execution
|
|
175
|
+
* can cross the execution gateway before a step program sees it. The gateway
|
|
176
|
+
* deliberately serializes that error as the public, provider-owned
|
|
177
|
+
* `ToolExecutionError` shape. Treat those two representations as the same
|
|
178
|
+
* typed exhaustion outcome; do not fall back based on a message substring.
|
|
179
|
+
*/
|
|
180
|
+
export function isProviderExhaustedFailure(
|
|
181
|
+
error: unknown,
|
|
182
|
+
): error is
|
|
183
|
+
| ProviderExhaustedError
|
|
184
|
+
| (ToolExecutionError & {
|
|
185
|
+
readonly origin: 'provider';
|
|
186
|
+
readonly code: typeof PROVIDER_EXHAUSTED_CODE;
|
|
187
|
+
}) {
|
|
188
|
+
return (
|
|
189
|
+
error instanceof ProviderExhaustedError ||
|
|
190
|
+
(error instanceof ToolExecutionError &&
|
|
191
|
+
error.origin === 'provider' &&
|
|
192
|
+
error.code === PROVIDER_EXHAUSTED_CODE)
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
173
196
|
/**
|
|
174
197
|
* Derive the human provider name for a PROVIDER_EXHAUSTED error from a pacing
|
|
175
198
|
* bucketId. Bucket ids are `${orgId}:${provider}`; the provider itself is
|
|
@@ -130,7 +130,7 @@ export function isActivePlayRunStatus(status: unknown): boolean {
|
|
|
130
130
|
* The minimal persisted Play Run document shape required to project the live
|
|
131
131
|
* snapshot. This is a structural subset of the Convex `playRuns` doc and of
|
|
132
132
|
* the run-observer projection returned by
|
|
133
|
-
* `convex/runObservers.getPlayRunSnapshotForObserver`.
|
|
133
|
+
* `packages/convex/runObservers.getPlayRunSnapshotForObserver`.
|
|
134
134
|
*/
|
|
135
135
|
export type LedgerBackedRunLike = {
|
|
136
136
|
workflowId: string;
|
package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts
CHANGED
|
@@ -11,8 +11,15 @@ import {
|
|
|
11
11
|
} from '../../../plays/sandbox-runtime-limits';
|
|
12
12
|
import type { PlayRunnerRuntimeLifecycleEvent } from '../types';
|
|
13
13
|
import { DAYTONA_PLAY_RUNNER_LABEL_SOURCE } from './daytona-labels';
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
import type { DaytonaSandboxStartAdmission } from './daytona-start-admission';
|
|
15
|
+
|
|
16
|
+
// Match Daytona's supported default create window. Ten seconds is shorter
|
|
17
|
+
// than normal provider startup under burst load: the SDK abandons an otherwise
|
|
18
|
+
// healthy create, and the resulting provider-side transition cannot safely be
|
|
19
|
+
// deleted or hedged with a second sandbox. The runner deadline still bounds
|
|
20
|
+
// the full lifecycle, while ambiguous creates retain the fail-closed cleanup
|
|
21
|
+
// path below.
|
|
22
|
+
const DAYTONA_CREATE_TIMEOUT_SECONDS = 60;
|
|
16
23
|
const DAYTONA_CREATE_RETRY_DELAYS_MS = [0, 500, 1_500] as const;
|
|
17
24
|
const DAYTONA_TIMED_OUT_CREATE_RECONCILE_DELAYS_MS = [
|
|
18
25
|
0, 1_000, 3_000, 6_000, 12_000, 24_000, 36_000,
|
|
@@ -105,7 +112,7 @@ export function resolveDaytonaSandboxAcquisitionUnavailableReason(
|
|
|
105
112
|
}
|
|
106
113
|
|
|
107
114
|
function isDaytonaSandboxStartTimeout(error: string): boolean {
|
|
108
|
-
return /Failed to create and start sandbox within
|
|
115
|
+
return /Failed to create and start sandbox within \d+ seconds\. Operation timed out\./.test(
|
|
109
116
|
error,
|
|
110
117
|
);
|
|
111
118
|
}
|
|
@@ -575,6 +582,7 @@ async function acquireOneShotDaytonaSandbox(input: {
|
|
|
575
582
|
releaseSandboxCapacity?: (leaseId: string) => Promise<void>;
|
|
576
583
|
nextProviderAttempt: () => number;
|
|
577
584
|
startedAt: number;
|
|
585
|
+
startAdmission?: DaytonaSandboxStartAdmission;
|
|
578
586
|
}): Promise<AcquiredDaytonaSandbox> {
|
|
579
587
|
const limits = validatePlaySandboxRuntimeLimits(
|
|
580
588
|
input.context.sandboxRuntimeLimits ?? {
|
|
@@ -582,7 +590,11 @@ async function acquireOneShotDaytonaSandbox(input: {
|
|
|
582
590
|
},
|
|
583
591
|
);
|
|
584
592
|
input.emitStage('create:start');
|
|
585
|
-
const result =
|
|
593
|
+
const result = input.startAdmission
|
|
594
|
+
? await input.startAdmission.run(() =>
|
|
595
|
+
createRetriedOneShotDaytonaSandbox(input),
|
|
596
|
+
)
|
|
597
|
+
: await createRetriedOneShotDaytonaSandbox(input);
|
|
586
598
|
const granted = {
|
|
587
599
|
cpu: result.sandbox.cpu,
|
|
588
600
|
memoryGiB: result.sandbox.memory,
|
|
@@ -683,6 +695,7 @@ export function createOneShotDaytonaSandboxLifecycle(input: {
|
|
|
683
695
|
providerOperationToken: string | null;
|
|
684
696
|
}>;
|
|
685
697
|
releaseSandboxCapacity?: (leaseId: string) => Promise<void>;
|
|
698
|
+
startAdmission?: DaytonaSandboxStartAdmission;
|
|
686
699
|
startedAt?: number;
|
|
687
700
|
}): OneShotDaytonaSandboxLifecycle {
|
|
688
701
|
const orgId = validateDaytonaExecutionContext(input.context);
|
|
@@ -700,6 +713,7 @@ export function createOneShotDaytonaSandboxLifecycle(input: {
|
|
|
700
713
|
observeCreateCall: input.observeCreateCall,
|
|
701
714
|
reserveSandboxCapacity: input.reserveSandboxCapacity,
|
|
702
715
|
releaseSandboxCapacity: input.releaseSandboxCapacity,
|
|
716
|
+
startAdmission: input.startAdmission,
|
|
703
717
|
nextProviderAttempt: () => {
|
|
704
718
|
providerAttempt += 1;
|
|
705
719
|
return providerAttempt;
|