import { PLAY_RUNTIME_BACKENDS, type PlayRuntimeBackendId } from './backend'; export const RUNTIME_SANDBOX_PROVIDERS = { daytona: 'daytona', modal: 'modal', } as const; export type RuntimeSandboxProvider = (typeof RUNTIME_SANDBOX_PROVIDERS)[keyof typeof RUNTIME_SANDBOX_PROVIDERS]; /** * Stable durable ids. Changing provider order or transition rules creates a * new version instead of changing the meaning of an already-queued launch. */ export const RUNTIME_SANDBOX_PLACEMENT_POLICIES = { daytonaOnlyV1: 'daytona_only@1', daytonaThenModalV1: 'daytona_then_modal@1', modalOnlyV1: 'modal_only@1', } as const; export type RuntimeSandboxPlacementPolicyId = (typeof RUNTIME_SANDBOX_PLACEMENT_POLICIES)[keyof typeof RUNTIME_SANDBOX_PLACEMENT_POLICIES]; export type RuntimeSandboxPlacementFailureReason = | 'provider_capacity_exhausted' | 'provider_start_timeout_before_execution'; export type RuntimeSandboxPlacementTransition = Readonly<{ from: RuntimeSandboxProvider; to: RuntimeSandboxProvider; stage: 'acquisition'; reasons: readonly RuntimeSandboxPlacementFailureReason[]; }>; export type RuntimeSandboxPlacementPolicy = Readonly<{ id: RuntimeSandboxPlacementPolicyId; compatibilityRuntimeBackend: | typeof PLAY_RUNTIME_BACKENDS.daytona | typeof PLAY_RUNTIME_BACKENDS.modal; providers: readonly [RuntimeSandboxProvider, ...RuntimeSandboxProvider[]]; transitions: readonly RuntimeSandboxPlacementTransition[]; requiredCredentialEnv: readonly string[]; cleanupProviders: readonly RuntimeSandboxProvider[]; }>; const DAYTONA_THEN_MODAL_V1: RuntimeSandboxPlacementPolicy = { id: RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaThenModalV1, compatibilityRuntimeBackend: PLAY_RUNTIME_BACKENDS.daytona, providers: [ RUNTIME_SANDBOX_PROVIDERS.daytona, RUNTIME_SANDBOX_PROVIDERS.modal, ], transitions: [ { from: RUNTIME_SANDBOX_PROVIDERS.daytona, to: RUNTIME_SANDBOX_PROVIDERS.modal, stage: 'acquisition', reasons: [ 'provider_capacity_exhausted', 'provider_start_timeout_before_execution', ], }, ], requiredCredentialEnv: [ 'DAYTONA_API_KEY', 'MODAL_TOKEN_ID', 'MODAL_TOKEN_SECRET', ], cleanupProviders: [ RUNTIME_SANDBOX_PROVIDERS.daytona, RUNTIME_SANDBOX_PROVIDERS.modal, ], }; /** * Frozen compatibility policy for launches written before placement policy ids * existed. It is retained until every pre-policy release lane has drained. */ const DAYTONA_ONLY_V1: RuntimeSandboxPlacementPolicy = { id: RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaOnlyV1, compatibilityRuntimeBackend: PLAY_RUNTIME_BACKENDS.daytona, providers: [RUNTIME_SANDBOX_PROVIDERS.daytona], transitions: [], requiredCredentialEnv: ['DAYTONA_API_KEY'], cleanupProviders: [RUNTIME_SANDBOX_PROVIDERS.daytona], }; const MODAL_ONLY_V1: RuntimeSandboxPlacementPolicy = { id: RUNTIME_SANDBOX_PLACEMENT_POLICIES.modalOnlyV1, compatibilityRuntimeBackend: PLAY_RUNTIME_BACKENDS.modal, providers: [RUNTIME_SANDBOX_PROVIDERS.modal], transitions: [], requiredCredentialEnv: ['MODAL_TOKEN_ID', 'MODAL_TOKEN_SECRET'], cleanupProviders: [RUNTIME_SANDBOX_PROVIDERS.modal], }; export const RUNTIME_SANDBOX_PLACEMENT_POLICY_CATALOG: Readonly< Record > = { [RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaOnlyV1]: DAYTONA_ONLY_V1, [RUNTIME_SANDBOX_PLACEMENT_POLICIES.daytonaThenModalV1]: DAYTONA_THEN_MODAL_V1, [RUNTIME_SANDBOX_PLACEMENT_POLICIES.modalOnlyV1]: MODAL_ONLY_V1, }; export function resolveRuntimeSandboxPlacementPolicy( id: RuntimeSandboxPlacementPolicyId | string, ): RuntimeSandboxPlacementPolicy { const normalized = id.trim(); const policy = RUNTIME_SANDBOX_PLACEMENT_POLICY_CATALOG[ normalized as RuntimeSandboxPlacementPolicyId ]; if (!policy) { throw new Error( `Unsupported runtime sandbox placement policy "${normalized}". Expected one of: ${Object.keys( RUNTIME_SANDBOX_PLACEMENT_POLICY_CATALOG, ).join(', ')}.`, ); } return policy; } /** * Compatibility Adapter for the public runtimeBackend selector. The returned * policy id, not this selector, is the durable execution contract. */ export function runtimeSandboxPlacementPolicyForBackend( backend: PlayRuntimeBackendId, ): RuntimeSandboxPlacementPolicy | null { if (backend === PLAY_RUNTIME_BACKENDS.daytona) { return DAYTONA_THEN_MODAL_V1; } if (backend === PLAY_RUNTIME_BACKENDS.modal) { return MODAL_ONLY_V1; } return null; } export function runtimeSandboxPlacementPoliciesForBackend( backend: PlayRuntimeBackendId, ): readonly RuntimeSandboxPlacementPolicy[] { if (backend === PLAY_RUNTIME_BACKENDS.localProcess) return []; return Object.values(RUNTIME_SANDBOX_PLACEMENT_POLICY_CATALOG).filter( (policy) => policy.compatibilityRuntimeBackend === backend, ); } /** * Old queued launches have no policy id. Derive their historical meaning from * runtimeBackend only when the durable field is absent. Unknown stored ids fail * loudly rather than silently changing execution semantics. */ export function resolveLaunchRuntimeSandboxPlacementPolicy(input: { runtimeSandboxPlacementPolicyId?: string | null; runtimeBackend: PlayRuntimeBackendId; }): RuntimeSandboxPlacementPolicy | null { const storedId = input.runtimeSandboxPlacementPolicyId?.trim(); if (storedId) { const policy = resolveRuntimeSandboxPlacementPolicy(storedId); if (policy.compatibilityRuntimeBackend !== input.runtimeBackend) { throw new Error( `Runtime sandbox placement policy ${policy.id} is incompatible with runtime backend ${input.runtimeBackend}.`, ); } return policy; } if (input.runtimeBackend === PLAY_RUNTIME_BACKENDS.daytona) { return DAYTONA_ONLY_V1; } return runtimeSandboxPlacementPolicyForBackend(input.runtimeBackend); } export function canTransitionRuntimeSandboxPlacement(input: { policy: RuntimeSandboxPlacementPolicy; from: RuntimeSandboxProvider; to: RuntimeSandboxProvider; stage: 'acquisition'; reason: RuntimeSandboxPlacementFailureReason; }): boolean { return input.policy.transitions.some( (transition) => transition.from === input.from && transition.to === input.to && transition.stage === input.stage && transition.reasons.includes(input.reason), ); }