deepline 0.3.472 → 0.3.474
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-core.ts +4 -1
- package/dist/bundling-sources/sdk/src/play.ts +7 -2
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/integration-contracts/billing-entitlements.ts +3 -1
- package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +18 -0
- package/dist/bundling-sources/shared_libs/observability/scheduled-work-control.ts +17 -0
- package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +55 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +101 -2
- package/dist/bundling-sources/shared_libs/play-runtime/modal-runtime-config.ts +62 -20
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-launch-transport.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +24 -8
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +19 -7
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +196 -10
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +40 -17
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +4 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal-resource-usage.ts +222 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +46 -14
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-incident-drills.ts +9 -5
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-compute-usage.ts +8 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +5 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +14 -5
- package/dist/bundling-sources/shared_libs/play-runtime/worker-api-types.ts +36 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +18 -8
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/sandbox-runtime-limits.ts +64 -16
- package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +1 -1
- package/dist/bundling-sources/shared_libs/product-notifications/billing-sales.ts +14 -1
- package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +40 -0
- package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +23 -1
- package/dist/bundling-sources/shared_libs/product-notifications/events.ts +18 -0
- package/dist/bundling-sources/shared_libs/product-notifications/slack-delivery.ts +2 -1
- package/dist/cli/auth-O6KAH543.js +41 -0
- package/dist/cli/{auth-35DAEPHC.mjs → auth-QMANU5PV.mjs} +5 -5
- package/dist/cli/{billing-5ED5X2IO.js → billing-WZ5POBZX.js} +85 -83
- package/dist/cli/{billing-CXVBJEC4.mjs → billing-YJAP4VZN.mjs} +12 -10
- package/dist/cli/{chunk-CFDQZQE2.mjs → chunk-26CZVDQN.mjs} +2 -2
- package/dist/cli/{chunk-UXFUD2MB.mjs → chunk-35SZHTRW.mjs} +5 -5
- package/dist/cli/{chunk-R73LE2IM.mjs → chunk-3MZPWIOE.mjs} +1 -1
- package/dist/cli/{chunk-HBVT4FW5.js → chunk-3NRZFMX4.js} +6 -6
- package/dist/cli/{chunk-SBPI7AEB.js → chunk-3ODBCZLL.js} +272 -258
- package/dist/cli/{chunk-ODAARZSK.js → chunk-475V572K.js} +36 -36
- package/dist/cli/{chunk-L3AXQXNT.js → chunk-4C34LGI4.js} +13 -13
- package/dist/cli/{chunk-V6OMS7E2.js → chunk-4IOY2SCQ.js} +10 -2
- package/dist/cli/{chunk-6ZTSHKJF.js → chunk-5QS4T4KR.js} +10 -3
- package/dist/cli/{chunk-R6L6JRDR.mjs → chunk-7IYOWIEJ.mjs} +2 -2
- package/dist/cli/{chunk-RDOPZK7A.js → chunk-AIPTW3EK.js} +18 -4
- package/dist/cli/{chunk-T5GRG37B.js → chunk-AK7UKQ5R.js} +5 -5
- package/dist/cli/{chunk-2G4R4APL.js → chunk-AWJKYS25.js} +2 -2
- package/dist/cli/{chunk-IPJ27SD2.mjs → chunk-BB4RZMWA.mjs} +5 -5
- package/dist/cli/{chunk-GJPRBELO.js → chunk-CXBEZAPU.js} +16 -16
- package/dist/cli/{chunk-Z52WEIBR.js → chunk-DKR7QPEO.js} +11 -7
- package/dist/cli/{chunk-YK64LQPQ.mjs → chunk-DQZBERDL.mjs} +1 -1
- package/dist/cli/{chunk-YUNPYX5T.mjs → chunk-DUGZKPRK.mjs} +10 -3
- package/dist/cli/{chunk-2S36YV2K.mjs → chunk-EIKONWW7.mjs} +1 -1
- package/dist/cli/{chunk-VDHDTXCK.js → chunk-EK2TAZJZ.js} +2 -2
- package/dist/cli/{chunk-2DND7LLL.js → chunk-G3UHAYRX.js} +8 -8
- package/dist/cli/{chunk-UPXGN62E.js → chunk-IK3VOGDR.js} +21 -21
- package/dist/cli/{chunk-UKKCS6Z4.js → chunk-JCNJQH6X.js} +1 -1
- package/dist/cli/{chunk-ZZQIS3TH.mjs → chunk-JEYX3345.mjs} +3 -3
- package/dist/cli/{chunk-QSCLOPWR.mjs → chunk-JJVYUKLY.mjs} +16 -2
- package/dist/cli/{chunk-XSSIBO74.js → chunk-JSXMJSBE.js} +8 -8
- package/dist/cli/{chunk-4NFBYW7X.mjs → chunk-KKWQ24VM.mjs} +2 -2
- package/dist/cli/{chunk-3L76SFGN.js → chunk-LHOEWAVD.js} +53 -53
- package/dist/cli/{chunk-NZBZFEVA.mjs → chunk-MKSB2FTU.mjs} +4 -4
- package/dist/cli/{chunk-MRZ7AO72.mjs → chunk-MNK4ZK2C.mjs} +26 -12
- package/dist/cli/{chunk-6PKONIIP.mjs → chunk-MXUJVCKV.mjs} +5 -5
- package/dist/cli/{chunk-7KAS4QOW.js → chunk-N62MS3XJ.js} +6 -6
- package/dist/cli/{chunk-SYWOSAW7.js → chunk-ORQYKA4I.js} +4 -4
- package/dist/cli/{chunk-X3RAGNNZ.mjs → chunk-OWUZKXE7.mjs} +1 -1
- package/dist/cli/{chunk-LQUOZGM6.js → chunk-PGKELBIY.js} +51 -51
- package/dist/cli/{chunk-52VOORHM.mjs → chunk-RGIQ5ZJX.mjs} +2 -2
- package/dist/cli/{chunk-M475BQ77.js → chunk-RLQIGBFK.js} +3 -3
- package/dist/cli/{chunk-5FHU67AT.js → chunk-RXITRC37.js} +3 -3
- package/dist/cli/{chunk-XSX6TJUA.mjs → chunk-SD7QWZTV.mjs} +10 -2
- package/dist/cli/{chunk-H7YFUC3J.js → chunk-STLJYWUC.js} +7 -7
- package/dist/cli/{chunk-T5H7ETIM.mjs → chunk-THDXVSNL.mjs} +4 -4
- package/dist/cli/{chunk-JRZW4LWK.mjs → chunk-UGYLGT7B.mjs} +1 -1
- package/dist/cli/{chunk-YNW47NOJ.mjs → chunk-UKX4FESF.mjs} +2 -2
- package/dist/cli/{chunk-RZHUHL53.mjs → chunk-V4ILQ2DS.mjs} +11 -7
- package/dist/cli/{chunk-QLVYYDUI.js → chunk-XNP7XTBN.js} +26 -26
- package/dist/cli/{chunk-SKVMC6K6.js → chunk-XP7FAYLN.js} +5 -5
- package/dist/cli/{chunk-RMQB72WW.js → chunk-YFDTF2XC.js} +9 -9
- package/dist/cli/{chunk-KQJHIVCE.mjs → chunk-YK64UZXN.mjs} +1 -1
- package/dist/cli/{chunk-IIQ6O5F3.js → chunk-YKNULB7V.js} +5 -5
- package/dist/cli/{chunk-YMB2CD55.mjs → chunk-YVJ6IWVD.mjs} +1 -1
- package/dist/cli/{chunk-TMMODGPV.mjs → chunk-YX762HFK.mjs} +2 -2
- package/dist/cli/{chunk-OMPW5ELS.mjs → chunk-Z27NSLPC.mjs} +1 -1
- package/dist/cli/{chunk-FHIO7WI2.mjs → chunk-ZGC2SUAA.mjs} +2 -2
- package/dist/cli/{chunk-C5PY2PP6.mjs → chunk-ZRWQKTSX.mjs} +3 -3
- package/dist/cli/command-docs.js +2 -2
- package/dist/cli/command-docs.mjs +1 -1
- package/dist/cli/{csv-SQJQM3B2.js → csv-ENKCFCSM.js} +13 -13
- package/dist/cli/{csv-OSDYY3QW.mjs → csv-QCLQOIEA.mjs} +4 -4
- package/dist/cli/{db-ATDYXAD5.js → db-5TLBZDT3.js} +27 -27
- package/dist/cli/{db-2M6BU6G5.mjs → db-P25LGP33.mjs} +6 -6
- package/dist/cli/describe-44L7OBGM.js +48 -0
- package/dist/cli/{describe-WIAJCWF3.mjs → describe-W2H5DHR6.mjs} +19 -19
- package/dist/cli/describe-core.d.mts +3 -3
- package/dist/cli/describe-core.d.ts +3 -3
- package/dist/cli/describe-core.js +3 -3
- package/dist/cli/describe-core.mjs +2 -2
- package/dist/cli/{executions-2J6CCJL2.mjs → executions-VYZCYUBR.mjs} +6 -6
- package/dist/cli/{executions-Y32LMYH6.js → executions-YHFAWJOJ.js} +8 -8
- package/dist/cli/{feedback-L4AVIMGI.mjs → feedback-K2FWYYLZ.mjs} +4 -4
- package/dist/cli/{feedback-RXQLS6QU.js → feedback-RJF3QSBB.js} +8 -8
- package/dist/cli/git-F3EI5DY5.js +25 -0
- package/dist/cli/{git-V3K77AWH.mjs → git-S3APUPLL.mjs} +5 -5
- package/dist/cli/index.js +139 -139
- package/dist/cli/index.mjs +41 -41
- package/dist/cli/{legacy-noops-B2KJT4CZ.js → legacy-noops-3SWNRE7Z.js} +8 -8
- package/dist/cli/{legacy-noops-LOGMYOY5.mjs → legacy-noops-ICYZACTW.mjs} +5 -5
- package/dist/cli/{monitors-5ETSB7S7.mjs → monitors-DEZCEQLB.mjs} +7 -7
- package/dist/cli/{monitors-A5WYUCGD.js → monitors-VRIWTRPG.js} +91 -91
- package/dist/cli/{org-BJOAUSXL.mjs → org-IQW5ZIAO.mjs} +6 -6
- package/dist/cli/{org-7EZDWYKK.js → org-NX752DTE.js} +72 -72
- package/dist/cli/{pages-3BYGBTVK.mjs → pages-5WQRVVKX.mjs} +6 -6
- package/dist/cli/{pages-45VNTEQU.js → pages-YIBWYGVS.js} +17 -17
- package/dist/cli/{play-5KER3JFU.js → play-3EXNH3HD.js} +662 -601
- package/dist/cli/{play-R7JQV533.mjs → play-WOMJXS4O.mjs} +110 -49
- package/dist/cli/{providers-OHMZ6QIF.js → providers-C2WYSR2Y.js} +9 -9
- package/dist/cli/{providers-RMFCE6MM.mjs → providers-XDVPYRTS.mjs} +6 -6
- package/dist/cli/{quickstart-GNRE4SAT.js → quickstart-7RABZF66.js} +6 -6
- package/dist/cli/{quickstart-IHR4VC5K.mjs → quickstart-YMSIL2TK.mjs} +4 -4
- package/dist/cli/{run-77QIMUUV.js → run-5QVVWFGL.js} +39 -39
- package/dist/cli/{run-Y4MIRFJY.mjs → run-A4JD6TAR.mjs} +24 -24
- package/dist/cli/{search-24YKTHMK.mjs → search-2TOSF2G3.mjs} +7 -7
- package/dist/cli/search-772R7YHI.js +32 -0
- package/dist/cli/{secrets-KHX62AWC.mjs → secrets-BUN4ORE7.mjs} +6 -6
- package/dist/cli/{secrets-SSEBT3IS.js → secrets-Q7UVOSNM.js} +15 -15
- package/dist/cli/{sessions-H7T25HGE.mjs → sessions-IAOORI6X.mjs} +5 -5
- package/dist/cli/{sessions-E6KNWYEH.js → sessions-NXQOQ4HX.js} +6 -6
- package/dist/cli/{settings-XSJG6M32.mjs → settings-BMI373AI.mjs} +11 -11
- package/dist/cli/{settings-GXUYF5G7.js → settings-WD4KSY5S.js} +78 -78
- package/dist/cli/{setup-JP5YPIA4.js → setup-3IA7BVPE.js} +44 -44
- package/dist/cli/{setup-GD7IOD4U.mjs → setup-55VIWAWR.mjs} +9 -9
- package/dist/cli/{skills-HLHE3ENN.mjs → skills-GKITMBTM.mjs} +7 -7
- package/dist/cli/skills-PUUTFMP3.js +31 -0
- package/dist/cli/tools-3WX7TUUG.js +55 -0
- package/dist/cli/{tools-Q4XIQX7W.mjs → tools-XHCFC7GP.mjs} +17 -17
- package/dist/cli/update-PC3CLODV.js +33 -0
- package/dist/cli/{update-3KRMR2QJ.mjs → update-SWB24YKE.mjs} +9 -9
- package/dist/cli/{workflow-NMUESL3O.js → workflow-5QPMFI3Z.js} +17 -17
- package/dist/cli/{workflow-NOZ7WFEY.mjs → workflow-XO4CKUA7.mjs} +7 -7
- package/dist/{client-C9bJ0QXu.d.mts → client-Bgl0_zXi.d.mts} +1 -1
- package/dist/{client-CuNH54w3.d.ts → client-_ah6IuhK.d.ts} +1 -1
- package/dist/{client-core-CSiXbe2n.d.mts → client-core-Bfsedm0_.d.mts} +44 -3
- package/dist/{client-core-C8Q6DKga.d.ts → client-core-C-ZF5vh9.d.ts} +44 -3
- package/dist/{compiler-manifest-Zwm9yqOA.d.ts → compiler-manifest-CCOqDGjU.d.mts} +12 -10
- package/dist/{compiler-manifest-Zwm9yqOA.d.mts → compiler-manifest-CCOqDGjU.d.ts} +12 -10
- package/dist/{errors-nEsqNLL8.d.mts → errors-BLccD7tG.d.mts} +1 -1
- package/dist/{errors-CsYwlpn4.d.ts → errors-Cy3kPnsi.d.ts} +1 -1
- package/dist/{index-CXF2jtza.d.mts → index-4-j44HuT.d.mts} +1 -1
- package/dist/{index-9pUZqkPH.d.ts → index-D5e4h1-H.d.ts} +1 -1
- package/dist/index.d.mts +14 -9
- package/dist/index.d.ts +14 -9
- package/dist/index.js +9 -9
- package/dist/index.mjs +6 -6
- package/dist/install-integrity.json +115 -114
- package/dist/plays/bundle-play-file.d.mts +3 -3
- package/dist/plays/bundle-play-file.d.ts +3 -3
- package/dist/plays/bundle-play-file.mjs +1 -1
- package/dist/plays/play-description.d.mts +2 -2
- package/dist/plays/play-description.d.ts +2 -2
- package/dist/plays/run-request.d.mts +2 -2
- package/dist/plays/run-request.d.ts +2 -2
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +2 -2
- package/dist/release.mjs +1 -1
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +5 -5
- package/dist/server.mjs +3 -3
- package/package.json +1 -1
- package/dist/cli/auth-Q5TM66UI.js +0 -41
- package/dist/cli/describe-37QXXDCF.js +0 -48
- package/dist/cli/git-JGUR335T.js +0 -25
- package/dist/cli/search-S3VO2UKV.js +0 -32
- package/dist/cli/skills-C4KTW3US.js +0 -31
- package/dist/cli/tools-KS7JMRK6.js +0 -55
- package/dist/cli/update-GYTQYK2W.js +0 -33
|
@@ -18,10 +18,11 @@ import {
|
|
|
18
18
|
PLAY_RUNNER_TERMINAL_GRACE_SECONDS,
|
|
19
19
|
} from '../../runtime-constants';
|
|
20
20
|
import {
|
|
21
|
-
|
|
22
|
-
MODAL_SANDBOX_MEMORY_MIB,
|
|
21
|
+
modalSandboxResourcesForPlay,
|
|
23
22
|
loadModalClientConfig,
|
|
24
23
|
loadModalRequiredConfig,
|
|
24
|
+
resolveModalSandboxMemoryPolicy,
|
|
25
|
+
isModalPreviewEvaluation,
|
|
25
26
|
withModalCallSignal,
|
|
26
27
|
} from '../../modal-runtime-config';
|
|
27
28
|
import type { PlaySandboxRuntimeLimits } from '../../../plays/sandbox-runtime-limits';
|
|
@@ -371,10 +372,33 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
371
372
|
runtimeSchedulerSchema: config.context.runtimeSchedulerSchema,
|
|
372
373
|
limits: config.context.sandboxRuntimeLimits,
|
|
373
374
|
});
|
|
375
|
+
const resources = modalSandboxResourcesForPlay(modalConfig.limits);
|
|
376
|
+
const memoryPolicy = resolveModalSandboxMemoryPolicy({
|
|
377
|
+
limits: modalConfig.limits,
|
|
378
|
+
runtimeSchedulerSchema: config.context.runtimeSchedulerSchema,
|
|
379
|
+
});
|
|
374
380
|
const app = await modalConfig.client.apps.fromName(modalConfig.appName, {
|
|
375
381
|
createIfMissing: true,
|
|
376
382
|
});
|
|
377
|
-
const
|
|
383
|
+
const baseImage = modalConfig.client.images.fromRegistry(
|
|
384
|
+
modalConfig.image,
|
|
385
|
+
);
|
|
386
|
+
// Modal caches this immutable layer by its build commands. Build before
|
|
387
|
+
// sandbox admission so a cold Python image owns no sandbox-capacity lease
|
|
388
|
+
// or ambiguous SandboxCreate intent. Production keeps its existing image.
|
|
389
|
+
const image = isModalPreviewEvaluation({
|
|
390
|
+
runtimeSchedulerSchema: config.context.runtimeSchedulerSchema,
|
|
391
|
+
})
|
|
392
|
+
? await withModalCallSignal(
|
|
393
|
+
AbortSignal.timeout(MODAL_SANDBOX_CREATE_TIMEOUT_MS),
|
|
394
|
+
() =>
|
|
395
|
+
baseImage
|
|
396
|
+
.dockerfileCommands([
|
|
397
|
+
'RUN apt-get update && apt-get install -y --no-install-recommends python3 python-is-python3 && rm -rf /var/lib/apt/lists/*',
|
|
398
|
+
])
|
|
399
|
+
.build(app),
|
|
400
|
+
)
|
|
401
|
+
: baseImage;
|
|
378
402
|
const capacityReservation =
|
|
379
403
|
await callbacks?.reserveSandboxCapacity?.('modal');
|
|
380
404
|
const createTags = {
|
|
@@ -428,10 +452,10 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
428
452
|
createSent = true;
|
|
429
453
|
sandbox = await awaitModalSandboxCreate({
|
|
430
454
|
create: modalConfig.client.sandboxes.create(app, image, {
|
|
431
|
-
cpu:
|
|
432
|
-
cpuLimit:
|
|
433
|
-
memoryMiB:
|
|
434
|
-
memoryLimitMiB:
|
|
455
|
+
cpu: resources.physicalCpuCores,
|
|
456
|
+
cpuLimit: resources.physicalCpuCores,
|
|
457
|
+
memoryMiB: memoryPolicy.reservationMemoryMiB,
|
|
458
|
+
memoryLimitMiB: memoryPolicy.memoryLimitMiB,
|
|
435
459
|
timeoutMs: modalSandboxLifetimeMs(modalConfig.limits),
|
|
436
460
|
idleTimeoutMs: modalSandboxLifetimeMs(modalConfig.limits),
|
|
437
461
|
workdir: modalConfig.workdir,
|
|
@@ -473,8 +497,12 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
473
497
|
maxBillingDurationSeconds:
|
|
474
498
|
modalConfig.limits.timeoutSeconds +
|
|
475
499
|
PLAY_RUNNER_TERMINAL_GRACE_SECONDS,
|
|
476
|
-
cpu:
|
|
477
|
-
memoryGiB:
|
|
500
|
+
cpu: resources.physicalCpuCores,
|
|
501
|
+
memoryGiB: modalConfig.limits.memoryGiB,
|
|
502
|
+
...(memoryPolicy.memoryLimitMiB >
|
|
503
|
+
memoryPolicy.reservationMemoryMiB
|
|
504
|
+
? { memoryLimitGiB: memoryPolicy.memoryLimitMiB / 1024 }
|
|
505
|
+
: {}),
|
|
478
506
|
diskGiB: 0,
|
|
479
507
|
...(capacityReservation
|
|
480
508
|
? { sandboxCapacityLeaseId: capacityReservation.leaseId }
|
|
@@ -587,8 +615,11 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
587
615
|
maxBillingDurationSeconds:
|
|
588
616
|
modalConfig.limits.timeoutSeconds +
|
|
589
617
|
PLAY_RUNNER_TERMINAL_GRACE_SECONDS,
|
|
590
|
-
cpu:
|
|
591
|
-
memoryGiB:
|
|
618
|
+
cpu: resources.physicalCpuCores,
|
|
619
|
+
memoryGiB: modalConfig.limits.memoryGiB,
|
|
620
|
+
...(memoryPolicy.memoryLimitMiB > memoryPolicy.reservationMemoryMiB
|
|
621
|
+
? { memoryLimitGiB: memoryPolicy.memoryLimitMiB / 1024 }
|
|
622
|
+
: {}),
|
|
592
623
|
diskGiB: 0,
|
|
593
624
|
...(capacityReservation
|
|
594
625
|
? { sandboxCapacityLeaseId: capacityReservation.leaseId }
|
|
@@ -654,6 +685,9 @@ export const modalPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
654
685
|
},
|
|
655
686
|
bundlePromise: buildPlayRunnerBundle(),
|
|
656
687
|
config: withRunnerSandboxProvider(config, 'modal'),
|
|
688
|
+
...(memoryPolicy.memoryLimitMiB > memoryPolicy.reservationMemoryMiB
|
|
689
|
+
? { memoryLimitMiB: memoryPolicy.memoryLimitMiB }
|
|
690
|
+
: {}),
|
|
657
691
|
workDir: modalConfig.workdir,
|
|
658
692
|
startedAt,
|
|
659
693
|
emitStage: (stage, extra) =>
|
|
@@ -972,9 +1006,7 @@ export async function inspectDetachedModalRunner(input: {
|
|
|
972
1006
|
const deadline = new AbortController();
|
|
973
1007
|
const timer = setTimeout(() => {
|
|
974
1008
|
deadline.abort(
|
|
975
|
-
new Error(
|
|
976
|
-
`Modal detached-runner inspection exceeded ${timeoutMs}ms.`,
|
|
977
|
-
),
|
|
1009
|
+
new Error(`Modal detached-runner inspection exceeded ${timeoutMs}ms.`),
|
|
978
1010
|
);
|
|
979
1011
|
}, timeoutMs);
|
|
980
1012
|
try {
|
|
@@ -41,6 +41,8 @@ export type PlayRunnerRuntimeResource = {
|
|
|
41
41
|
terminalAt?: number | null;
|
|
42
42
|
cpu?: number | null;
|
|
43
43
|
memoryGiB?: number | null;
|
|
44
|
+
/** Optional Modal burst ceiling; absence retains the fixed reservation. */
|
|
45
|
+
memoryLimitGiB?: number | null;
|
|
44
46
|
diskGiB?: number | null;
|
|
45
47
|
/** Scheduler-only soft-capacity reservation made before provider create. */
|
|
46
48
|
sandboxCapacityLeaseId?: string;
|
|
@@ -362,16 +362,20 @@ export const RUNTIME_INCIDENT_DRILL_CATALOG: readonly RuntimeIncidentDrill[] = [
|
|
|
362
362
|
topologies: LOCAL_AND_PREVIEW_TOPOLOGIES,
|
|
363
363
|
control: {
|
|
364
364
|
kind: 'runtime_test_fault',
|
|
365
|
-
// The 120-second lease plus 80 seconds of confirmation
|
|
366
|
-
// provider read
|
|
367
|
-
// that read
|
|
368
|
-
|
|
365
|
+
// The 120-second lease plus 80 seconds of on-time confirmation is the
|
|
366
|
+
// earliest provider read. Preview woke late enough to exhaust 300
|
|
367
|
+
// seconds of silence before that read. Keep the synthetic runner quiet
|
|
368
|
+
// for seven minutes without changing the worker's liveness policy.
|
|
369
|
+
defaultValue: 420_000,
|
|
369
370
|
valueMeaning: 'milliseconds',
|
|
370
371
|
},
|
|
371
372
|
expected: {
|
|
372
373
|
outcome:
|
|
373
374
|
'The worker asks the provider once the lease and confirmation pass, the sandbox is not proven gone, and the same attempt finishes after heartbeats return.',
|
|
374
|
-
safetyFacts: [
|
|
375
|
+
safetyFacts: [
|
|
376
|
+
'same_logical_run',
|
|
377
|
+
'no_loss_verdict_without_provider_proof',
|
|
378
|
+
],
|
|
375
379
|
},
|
|
376
380
|
verification: {
|
|
377
381
|
kind: 'preview_black_box',
|
|
@@ -23,6 +23,7 @@ export function resolveRuntimeSandboxComputeItems(input: {
|
|
|
23
23
|
endedAt: number | null;
|
|
24
24
|
physicalCpuCores: number | null;
|
|
25
25
|
memoryGiB: number | null;
|
|
26
|
+
memoryLimitGiB: number | null;
|
|
26
27
|
maxBillingDurationSeconds: number | null;
|
|
27
28
|
}
|
|
28
29
|
>();
|
|
@@ -52,6 +53,10 @@ export function resolveRuntimeSandboxComputeItems(input: {
|
|
|
52
53
|
finiteNonNegative(value.cpu) ?? existing?.physicalCpuCores ?? null,
|
|
53
54
|
memoryGiB:
|
|
54
55
|
finiteNonNegative(value.memoryGiB) ?? existing?.memoryGiB ?? null,
|
|
56
|
+
memoryLimitGiB:
|
|
57
|
+
finiteNonNegative(value.memoryLimitGiB) ??
|
|
58
|
+
existing?.memoryLimitGiB ??
|
|
59
|
+
null,
|
|
55
60
|
maxBillingDurationSeconds:
|
|
56
61
|
finiteNonNegative(value.maxBillingDurationSeconds) ??
|
|
57
62
|
existing?.maxBillingDurationSeconds ??
|
|
@@ -77,6 +82,9 @@ export function resolveRuntimeSandboxComputeItems(input: {
|
|
|
77
82
|
wallTimeSeconds: Math.max(0, endedAt - resource.startedAt) / 1_000,
|
|
78
83
|
physicalCpuCores: resource.physicalCpuCores ?? 0.5,
|
|
79
84
|
memoryGiB: resource.memoryGiB ?? 1,
|
|
85
|
+
...(resource.memoryLimitGiB === null
|
|
86
|
+
? {}
|
|
87
|
+
: { memoryLimitGiB: resource.memoryLimitGiB }),
|
|
80
88
|
sandboxId,
|
|
81
89
|
startedAt: resource.startedAt,
|
|
82
90
|
endedAt,
|
|
@@ -204,6 +204,8 @@ export type SandboxExecutionResource = SandboxRunResource & {
|
|
|
204
204
|
billingEndedAtMs?: number | null;
|
|
205
205
|
cpu?: number | null;
|
|
206
206
|
memoryGiB?: number | null;
|
|
207
|
+
/** Optional provider burst ceiling, distinct from the reserved memory. */
|
|
208
|
+
memoryLimitGiB?: number | null;
|
|
207
209
|
diskGiB?: number | null;
|
|
208
210
|
/** A create settled after the launching attempt had already timed out. */
|
|
209
211
|
lateAcquired?: boolean;
|
package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts
CHANGED
|
@@ -254,6 +254,7 @@ function toSandboxResource(
|
|
|
254
254
|
maxBillingDurationSeconds: resource.maxBillingDurationSeconds ?? null,
|
|
255
255
|
cpu: resource.cpu ?? null,
|
|
256
256
|
memoryGiB: resource.memoryGiB ?? null,
|
|
257
|
+
memoryLimitGiB: resource.memoryLimitGiB ?? null,
|
|
257
258
|
diskGiB: resource.diskGiB ?? null,
|
|
258
259
|
// Historical Daytona facts use `daytonaEnvironment`; normalize it at the
|
|
259
260
|
// portable boundary so the cleanup job stays in the resource's actual
|
|
@@ -295,6 +296,7 @@ export function playRunnerRuntimeResourceFromSandboxExecutionResource(
|
|
|
295
296
|
maxBillingDurationSeconds: resource.maxBillingDurationSeconds ?? null,
|
|
296
297
|
cpu: resource.cpu ?? null,
|
|
297
298
|
memoryGiB: resource.memoryGiB ?? null,
|
|
299
|
+
memoryLimitGiB: resource.memoryLimitGiB ?? null,
|
|
298
300
|
diskGiB: resource.diskGiB ?? null,
|
|
299
301
|
...(resource.capacityLeaseId
|
|
300
302
|
? { sandboxCapacityLeaseId: resource.capacityLeaseId }
|
|
@@ -24428,7 +24428,11 @@ async function acknowledgeRunLedgerPrefixWithContinuation(
|
|
|
24428
24428
|
waitForRunLock: true,
|
|
24429
24429
|
},
|
|
24430
24430
|
options,
|
|
24431
|
-
{
|
|
24431
|
+
{
|
|
24432
|
+
eventIds,
|
|
24433
|
+
targetEventId,
|
|
24434
|
+
createdProjectionWake: input.createdProjectionWake,
|
|
24435
|
+
},
|
|
24432
24436
|
);
|
|
24433
24437
|
if (fast !== null) {
|
|
24434
24438
|
let continuation: RunLedgerOutboxDrainScope | null = null;
|
|
@@ -938,6 +938,12 @@ export function startRunLedgerOutboxRecovery(
|
|
|
938
938
|
* together for projection.
|
|
939
939
|
*/
|
|
940
940
|
export const RUN_CREATED_INLINE_DELIVERY_DEADLINE_MS = 1_500;
|
|
941
|
+
/**
|
|
942
|
+
* A response-owned background attempt can finish a cold projection without
|
|
943
|
+
* holding admission open. Keep its deadline plus release grace below the
|
|
944
|
+
* existing five-second delivery lease; foreground callers retain 1.5 seconds.
|
|
945
|
+
*/
|
|
946
|
+
export const RUN_CREATED_BACKGROUND_DELIVERY_DEADLINE_MS = 4_000;
|
|
941
947
|
/**
|
|
942
948
|
* How long an abandoned inline attempt may keep its caller while it gives the
|
|
943
949
|
* lease back. The caller is the only owner of that release: a serverless
|
|
@@ -1016,7 +1022,8 @@ function inlineAttemptErrorClass(error: unknown): string {
|
|
|
1016
1022
|
* Never throws and never exceeds `deadlineMs` plus the release grace. A
|
|
1017
1023
|
* deadline abandons the append and releases its lease without charging a
|
|
1018
1024
|
* retry, and that release completes before this returns whenever it fits the
|
|
1019
|
-
* grace
|
|
1025
|
+
* grace. Background callers own the returned promise through their response
|
|
1026
|
+
* lifecycle; foreground callers retain the shorter inline deadline.
|
|
1020
1027
|
*/
|
|
1021
1028
|
export async function deliverRunCreatedOutboxEventInline(input: {
|
|
1022
1029
|
runId: string;
|
|
@@ -1024,6 +1031,8 @@ export async function deliverRunCreatedOutboxEventInline(input: {
|
|
|
1024
1031
|
schedulerOptions?: Pick<PostgresSchedulerOptions, 'schema'>;
|
|
1025
1032
|
tokenAuthority: RunLedgerOutboxTokenAuthority;
|
|
1026
1033
|
appRuntimeFetch?: typeof fetch;
|
|
1034
|
+
/** The caller owns this attempt through its after-response lifecycle. */
|
|
1035
|
+
background?: boolean;
|
|
1027
1036
|
deadlineMs?: number;
|
|
1028
1037
|
/** Test seam; clamped to `RUN_CREATED_INLINE_RELEASE_GRACE_MS`. */
|
|
1029
1038
|
releaseGraceMs?: number;
|
|
@@ -1032,12 +1041,12 @@ export async function deliverRunCreatedOutboxEventInline(input: {
|
|
|
1032
1041
|
const now = input.now ?? Date.now;
|
|
1033
1042
|
const startedAt = now();
|
|
1034
1043
|
const elapsed = () => Math.max(0, now() - startedAt);
|
|
1044
|
+
const maximumDeadlineMs = input.background
|
|
1045
|
+
? RUN_CREATED_BACKGROUND_DELIVERY_DEADLINE_MS
|
|
1046
|
+
: RUN_CREATED_INLINE_DELIVERY_DEADLINE_MS;
|
|
1035
1047
|
const deadlineMs = Math.max(
|
|
1036
1048
|
1,
|
|
1037
|
-
Math.min(
|
|
1038
|
-
RUN_CREATED_INLINE_DELIVERY_DEADLINE_MS,
|
|
1039
|
-
input.deadlineMs ?? RUN_CREATED_INLINE_DELIVERY_DEADLINE_MS,
|
|
1040
|
-
),
|
|
1049
|
+
Math.min(maximumDeadlineMs, input.deadlineMs ?? maximumDeadlineMs),
|
|
1041
1050
|
);
|
|
1042
1051
|
const releaseGraceMs = Math.max(
|
|
1043
1052
|
1,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PlayDocflowNodeIoState } from './docflow-node-io';
|
|
2
2
|
import type { PlayMapRowActivitySource } from './run-ledger';
|
|
3
3
|
import type { PlayConditionCounts } from './cell-provenance';
|
|
4
|
+
import { PLAY_SANDBOX_SIZE_LIMITS } from '../plays/sandbox-runtime-limits';
|
|
4
5
|
|
|
5
6
|
export type PlayStagedFileRef = {
|
|
6
7
|
storageKind: 'r2';
|
|
@@ -69,6 +70,17 @@ export const MODAL_SANDBOX_COMPUTE_PRICING_USD = {
|
|
|
69
70
|
// Convex billing can use it without importing Modal's Node runtime config.
|
|
70
71
|
export const MODAL_SANDBOX_CPU_CORES = 0.5;
|
|
71
72
|
|
|
73
|
+
/** Scale Modal's physical-core request from Deepline's standard one-vCPU unit. */
|
|
74
|
+
export function modalSandboxResourcesForPlay(input: {
|
|
75
|
+
cpu: number;
|
|
76
|
+
memoryGiB: number;
|
|
77
|
+
}) {
|
|
78
|
+
return {
|
|
79
|
+
physicalCpuCores: MODAL_SANDBOX_CPU_CORES * input.cpu,
|
|
80
|
+
memoryMiB: input.memoryGiB * 1024,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
const NEON_COMPUTE_PRICING_USD = {
|
|
73
85
|
cuHour: 0.106,
|
|
74
86
|
defaultCu: 1,
|
|
@@ -78,6 +90,14 @@ function roundUsd(amount: number): number {
|
|
|
78
90
|
return Number(Math.max(0, amount).toFixed(12));
|
|
79
91
|
}
|
|
80
92
|
|
|
93
|
+
/** Portable billing identity derived from the resources actually acquired. */
|
|
94
|
+
function sandboxSizeMetadata(cpu: number, memoryGiB: number) {
|
|
95
|
+
const entry = Object.entries(PLAY_SANDBOX_SIZE_LIMITS).find(
|
|
96
|
+
([, limits]) => limits.cpu === cpu && limits.memoryGiB === memoryGiB,
|
|
97
|
+
);
|
|
98
|
+
return entry ? { sandboxSize: entry[0] } : {};
|
|
99
|
+
}
|
|
100
|
+
|
|
81
101
|
export function resolveDaytonaSandboxComputeItem(input: {
|
|
82
102
|
itemId: string;
|
|
83
103
|
source?: string;
|
|
@@ -110,6 +130,7 @@ export function resolveDaytonaSandboxComputeItem(input: {
|
|
|
110
130
|
units: billableSeconds,
|
|
111
131
|
providerCostUsd,
|
|
112
132
|
metadata: {
|
|
133
|
+
...sandboxSizeMetadata(cpu, memoryGiB),
|
|
113
134
|
sandboxId: input.sandboxId ?? null,
|
|
114
135
|
cpu,
|
|
115
136
|
memoryGiB,
|
|
@@ -126,6 +147,8 @@ export function resolveModalSandboxComputeItem(input: {
|
|
|
126
147
|
wallTimeSeconds: number;
|
|
127
148
|
physicalCpuCores: number;
|
|
128
149
|
memoryGiB: number;
|
|
150
|
+
/** Bounded burst allocation; absent on fixed-resource historical items. */
|
|
151
|
+
memoryLimitGiB?: number;
|
|
129
152
|
sandboxId?: string | null;
|
|
130
153
|
startedAt?: number;
|
|
131
154
|
endedAt?: number;
|
|
@@ -145,9 +168,22 @@ export function resolveModalSandboxComputeItem(input: {
|
|
|
145
168
|
units: billableSeconds,
|
|
146
169
|
providerCostUsd,
|
|
147
170
|
metadata: {
|
|
171
|
+
...sandboxSizeMetadata(
|
|
172
|
+
physicalCpuCores / MODAL_SANDBOX_CPU_CORES,
|
|
173
|
+
memoryGiB,
|
|
174
|
+
),
|
|
148
175
|
sandboxId: input.sandboxId ?? null,
|
|
149
176
|
physicalCpuCores,
|
|
150
177
|
memoryGiB,
|
|
178
|
+
...(input.memoryLimitGiB === undefined
|
|
179
|
+
? {}
|
|
180
|
+
: {
|
|
181
|
+
memoryLimitGiB: input.memoryLimitGiB,
|
|
182
|
+
// The Preview evaluation preserves the existing compute price.
|
|
183
|
+
// Sampled burst cost is diagnostic until provider billing can be
|
|
184
|
+
// reconciled; a hard ceiling is never presented as actual usage.
|
|
185
|
+
costBasis: 'reserved_resources',
|
|
186
|
+
}),
|
|
151
187
|
startedAt: input.startedAt,
|
|
152
188
|
endedAt: input.endedAt,
|
|
153
189
|
},
|
|
@@ -3,7 +3,10 @@ export type { BillingEntitlements } from '../integration-contracts/billing-entit
|
|
|
3
3
|
import { Type, type Static, type TSchema } from '@sinclair/typebox';
|
|
4
4
|
import { Value } from '@sinclair/typebox/value';
|
|
5
5
|
import type { PreviousCell } from './cell-staleness';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
PlaySandboxRuntimeLimits,
|
|
8
|
+
PlaySandboxSize,
|
|
9
|
+
} from './sandbox-runtime-limits';
|
|
7
10
|
import type {
|
|
8
11
|
BasicToolExecuteResult,
|
|
9
12
|
ToolExecuteResult,
|
|
@@ -207,6 +210,7 @@ export const PLAY_AUTHORING_CONTRACT_ISSUE_CODES = [
|
|
|
207
210
|
'play_authoring_row_sleep_unsupported',
|
|
208
211
|
'play_authoring_hitl_retry_loop_unsafe',
|
|
209
212
|
'play_authoring_binding_invalid',
|
|
213
|
+
'play_runtime_size_preview_only',
|
|
210
214
|
'play_authoring_input_schema_unresolved',
|
|
211
215
|
'tool_response_raw_access',
|
|
212
216
|
'check_error',
|
|
@@ -863,7 +867,7 @@ export type PlayAuthoringBindings<TInput = Record<string, unknown>> = {
|
|
|
863
867
|
*/
|
|
864
868
|
runtime?: {
|
|
865
869
|
timeout?: string;
|
|
866
|
-
size?:
|
|
870
|
+
size?: PlaySandboxSize;
|
|
867
871
|
};
|
|
868
872
|
/**
|
|
869
873
|
* Start at most one run of this Play per window, whatever started it.
|
|
@@ -2967,20 +2971,26 @@ export const PLAY_AUTHORING_FIELD_REGISTRY = {
|
|
|
2967
2971
|
'rateLimit.every must be a static duration from "10s" to "24h", such as "5m".',
|
|
2968
2972
|
},
|
|
2969
2973
|
'runtime.size': {
|
|
2970
|
-
schema: Type.
|
|
2974
|
+
schema: Type.Union([
|
|
2975
|
+
Type.Literal('standard'),
|
|
2976
|
+
Type.Literal('large'),
|
|
2977
|
+
Type.Literal('xlarge'),
|
|
2978
|
+
]),
|
|
2971
2979
|
fixtures: {
|
|
2972
|
-
valid: '
|
|
2973
|
-
invalid: '
|
|
2980
|
+
valid: 'large',
|
|
2981
|
+
invalid: 'xxlarge',
|
|
2974
2982
|
absent: undefined,
|
|
2975
2983
|
unresolved: { expression: 'size' },
|
|
2976
2984
|
edition1: 'standard',
|
|
2977
2985
|
},
|
|
2978
|
-
referenceType: "'standard'",
|
|
2986
|
+
referenceType: "'standard' | 'large' | 'xlarge'",
|
|
2979
2987
|
required: false,
|
|
2980
2988
|
resolution: 'static-required',
|
|
2981
2989
|
issueCode: 'play_authoring_binding_invalid',
|
|
2982
|
-
description:
|
|
2983
|
-
|
|
2990
|
+
description:
|
|
2991
|
+
'Deepline-managed sandbox size. Standard is 1 GiB memory. Large (4 GiB) and xlarge (8 GiB) are available only on branch Preview deployments. Production supports standard.',
|
|
2992
|
+
errorMessage:
|
|
2993
|
+
'runtime.size must be the static literal "standard", "large", or "xlarge".',
|
|
2984
2994
|
},
|
|
2985
2995
|
'ctx.customerDb.query.statement': {
|
|
2986
2996
|
schema: Type.Union([
|
|
@@ -1125,7 +1125,7 @@ function sandboxRuntimeDeclarationFromOptions(
|
|
|
1125
1125
|
if (unsupportedProperties.length > 0) {
|
|
1126
1126
|
throw new Error(
|
|
1127
1127
|
`Unsupported runtime sandbox option${unsupportedProperties.length === 1 ? '' : 's'} "${unsupportedProperties.join('", "')}". ` +
|
|
1128
|
-
'Use runtime.size with a Deepline prebuilt sandbox. Supported sizes: "standard".',
|
|
1128
|
+
'Use runtime.size with a Deepline prebuilt sandbox. Supported sizes: "standard", "large", or "xlarge".',
|
|
1129
1129
|
);
|
|
1130
1130
|
}
|
|
1131
1131
|
const timeout = resolveStaticProperty(runtime.value, 'timeout', context);
|
|
@@ -5,7 +5,7 @@ export type PlaySandboxRuntimeLimits = {
|
|
|
5
5
|
diskGiB: number;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
export type PlaySandboxSize = 'standard';
|
|
8
|
+
export type PlaySandboxSize = 'standard' | 'large' | 'xlarge';
|
|
9
9
|
|
|
10
10
|
export const PLAY_SANDBOX_SIZE_LIMITS = {
|
|
11
11
|
standard: {
|
|
@@ -13,6 +13,16 @@ export const PLAY_SANDBOX_SIZE_LIMITS = {
|
|
|
13
13
|
cpu: 1,
|
|
14
14
|
diskGiB: 3,
|
|
15
15
|
},
|
|
16
|
+
large: {
|
|
17
|
+
memoryGiB: 4,
|
|
18
|
+
cpu: 2,
|
|
19
|
+
diskGiB: 8,
|
|
20
|
+
},
|
|
21
|
+
xlarge: {
|
|
22
|
+
memoryGiB: 8,
|
|
23
|
+
cpu: 4,
|
|
24
|
+
diskGiB: 10,
|
|
25
|
+
},
|
|
16
26
|
} as const satisfies Record<
|
|
17
27
|
PlaySandboxSize,
|
|
18
28
|
Omit<PlaySandboxRuntimeLimits, 'timeoutSeconds'>
|
|
@@ -27,11 +37,50 @@ export const STANDARD_PLAY_SANDBOX_RUNTIME_LIMITS: PlaySandboxRuntimeLimits = {
|
|
|
27
37
|
// customer-authored Play can never ask Daytona for an unbounded resource.
|
|
28
38
|
export const MAX_PLAY_SANDBOX_RUNTIME_LIMITS: PlaySandboxRuntimeLimits = {
|
|
29
39
|
timeoutSeconds: 4 * 60 * 60,
|
|
30
|
-
|
|
31
|
-
cpu: STANDARD_PLAY_SANDBOX_RUNTIME_LIMITS.cpu,
|
|
32
|
-
diskGiB: STANDARD_PLAY_SANDBOX_RUNTIME_LIMITS.diskGiB,
|
|
40
|
+
...PLAY_SANDBOX_SIZE_LIMITS.xlarge,
|
|
33
41
|
};
|
|
34
42
|
|
|
43
|
+
/** Bounded Modal burst headroom; resource reservation remains the chosen profile. */
|
|
44
|
+
export function modalSandboxMemoryLimitGiBForPlay(
|
|
45
|
+
input: Pick<PlaySandboxRuntimeLimits, 'memoryGiB'>,
|
|
46
|
+
): number {
|
|
47
|
+
if (
|
|
48
|
+
!Object.values(PLAY_SANDBOX_SIZE_LIMITS).some(
|
|
49
|
+
(profile) => profile.memoryGiB === input.memoryGiB,
|
|
50
|
+
)
|
|
51
|
+
) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Unsupported Modal memory reservation: ${input.memoryGiB} GiB.`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return Math.min(
|
|
57
|
+
Math.max(4, input.memoryGiB * 2),
|
|
58
|
+
MAX_PLAY_SANDBOX_RUNTIME_LIMITS.memoryGiB,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function playSandboxSizeForLimits(
|
|
63
|
+
limits: Pick<PlaySandboxRuntimeLimits, 'memoryGiB' | 'cpu' | 'diskGiB'>,
|
|
64
|
+
): PlaySandboxSize | null {
|
|
65
|
+
return (
|
|
66
|
+
(
|
|
67
|
+
Object.entries(PLAY_SANDBOX_SIZE_LIMITS) as [
|
|
68
|
+
PlaySandboxSize,
|
|
69
|
+
(typeof PLAY_SANDBOX_SIZE_LIMITS)[PlaySandboxSize],
|
|
70
|
+
][]
|
|
71
|
+
).find(
|
|
72
|
+
([, profile]) =>
|
|
73
|
+
profile.memoryGiB === limits.memoryGiB &&
|
|
74
|
+
profile.cpu === limits.cpu &&
|
|
75
|
+
profile.diskGiB === limits.diskGiB,
|
|
76
|
+
)?.[0] ?? null
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const supportedPlaySandboxSizes = Object.keys(PLAY_SANDBOX_SIZE_LIMITS).join(
|
|
81
|
+
', ',
|
|
82
|
+
);
|
|
83
|
+
|
|
35
84
|
export type PlaySandboxRuntimeDeclaration = {
|
|
36
85
|
timeout?: string;
|
|
37
86
|
size?: PlaySandboxSize;
|
|
@@ -48,15 +97,11 @@ function parseTimeout(value: string): number | null {
|
|
|
48
97
|
export function validatePlaySandboxRuntimeLimits(
|
|
49
98
|
value: PlaySandboxRuntimeLimits,
|
|
50
99
|
): PlaySandboxRuntimeLimits {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
`Use runtime.size with a Deepline prebuilt sandbox. Supported sizes: "standard" ` +
|
|
57
|
-
`(${base.cpu} CPU, ${base.memoryGiB}GiB memory, ${base.diskGiB}GiB disk).`,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
100
|
+
if (!playSandboxSizeForLimits(value)) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Unsupported runtime sandbox resources: cpu=${value.cpu} memoryGiB=${value.memoryGiB} diskGiB=${value.diskGiB}. ` +
|
|
103
|
+
`Use runtime.size with a Deepline prebuilt sandbox. Supported sizes: ${supportedPlaySandboxSizes}.`,
|
|
104
|
+
);
|
|
60
105
|
}
|
|
61
106
|
if (
|
|
62
107
|
!Number.isSafeInteger(value.timeoutSeconds) ||
|
|
@@ -85,12 +130,15 @@ export function resolvePlaySandboxRuntimeLimits(
|
|
|
85
130
|
if (unsupportedProperties.length > 0) {
|
|
86
131
|
throw new Error(
|
|
87
132
|
`Unsupported runtime sandbox option${unsupportedProperties.length === 1 ? '' : 's'}: ${unsupportedProperties.join(', ')}. ` +
|
|
88
|
-
|
|
133
|
+
`Use runtime.size with a Deepline prebuilt sandbox. Supported sizes: ${supportedPlaySandboxSizes}.`,
|
|
89
134
|
);
|
|
90
135
|
}
|
|
91
|
-
if (
|
|
136
|
+
if (
|
|
137
|
+
declaration.size !== undefined &&
|
|
138
|
+
!Object.hasOwn(PLAY_SANDBOX_SIZE_LIMITS, declaration.size)
|
|
139
|
+
) {
|
|
92
140
|
throw new Error(
|
|
93
|
-
`Unsupported runtime sandbox size "${String(declaration.size)}". Supported sizes:
|
|
141
|
+
`Unsupported runtime sandbox size "${String(declaration.size)}". Supported sizes: ${supportedPlaySandboxSizes}.`,
|
|
94
142
|
);
|
|
95
143
|
}
|
|
96
144
|
const timeoutSeconds = declaration.timeout
|
|
@@ -413,7 +413,7 @@ export type ToolExecuteResultAccessors<
|
|
|
413
413
|
* incomplete lists throw: use readList(result, path) for explicit dataset access.
|
|
414
414
|
* Provider pagination requires a separate request; getters never fetch it.
|
|
415
415
|
* Historical editions 1–9 retain PlayDataset getters and async materialize/peek;
|
|
416
|
-
* missing getters never mean empty results. Inspect rawV2 for debugging: parsed,
|
|
416
|
+
* missing getters never mean empty results. Inspect toolResponse.rawV2 for debugging: parsed,
|
|
417
417
|
* scrubbed envelopes, pagination and siblings, not HTTP bytes or headers.
|
|
418
418
|
*
|
|
419
419
|
* @sdkReference runtime 200
|
|
@@ -21,6 +21,14 @@ export function isBillingSalesGroupKey(key: unknown): boolean {
|
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export const BILLING_ALERTS_SLACK_CHANNEL_ID = 'C0CEBRS6PHS';
|
|
25
|
+
export const BILLING_USAGE_GROUP_KEY = 'shadow.billing-usage';
|
|
26
|
+
export const BILLING_USAGE_DESTINATION_KEY = 'shadow.billing-usage.slack';
|
|
27
|
+
export function isPlatformBillingDestination(key: unknown): boolean {
|
|
28
|
+
return (
|
|
29
|
+
key === BILLING_USAGE_DESTINATION_KEY || isBillingSalesDestinationKey(key)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
24
32
|
export const BILLING_SALES_GROUP_KEY = 'shadow.billing-sales';
|
|
25
33
|
export const BILLING_SALES_DESTINATION_KEY = 'shadow.billing-sales.slack';
|
|
26
34
|
export const BILLING_SALES_SLACK_CHANNEL_ID = 'C0AGWVD2TNK';
|
|
@@ -33,13 +41,18 @@ export const BILLING_DELIVERY_LATE_RULE_KEYS: readonly string[] = [
|
|
|
33
41
|
BILLING_RENEWAL_LATE_RULE_KEY,
|
|
34
42
|
];
|
|
35
43
|
export const BILLING_SALES_RULE_KEYS: readonly string[] = [
|
|
44
|
+
'internal.billing.usage_charge',
|
|
36
45
|
'internal.billing.credit_purchase',
|
|
37
46
|
'internal.billing.paid_plan',
|
|
38
47
|
...BILLING_DELIVERY_LATE_RULE_KEYS,
|
|
39
48
|
];
|
|
40
49
|
|
|
41
50
|
export function isPlatformNotificationGroup(groupKey: string): boolean {
|
|
42
|
-
return
|
|
51
|
+
return (
|
|
52
|
+
groupKey === 'shadow' ||
|
|
53
|
+
isBillingSalesGroupKey(groupKey) ||
|
|
54
|
+
groupKey === BILLING_USAGE_GROUP_KEY
|
|
55
|
+
);
|
|
43
56
|
}
|
|
44
57
|
|
|
45
58
|
/** Permit only the code-owned purchase-rule move while old deliveries drain. */
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
BILLING_SALES_CREDIT_PURCHASE_MINIMUM_CENTS,
|
|
21
21
|
BILLING_CREDIT_PURCHASE_GROUP_KEY,
|
|
22
22
|
BILLING_SALES_GROUP_KEY,
|
|
23
|
+
BILLING_USAGE_GROUP_KEY,
|
|
23
24
|
} from './billing-sales';
|
|
24
25
|
|
|
25
26
|
export const DEFAULT_PLAY_FAILURE_SETTINGS = {
|
|
@@ -995,6 +996,45 @@ const PRODUCT_NOTIFICATION_TYPE_REGISTRY = [
|
|
|
995
996
|
}),
|
|
996
997
|
},
|
|
997
998
|
},
|
|
999
|
+
{
|
|
1000
|
+
id: 'internal.billing.usage_charge',
|
|
1001
|
+
eventName: ProductNotificationEvent.BillingUsageChargeObserved,
|
|
1002
|
+
requiredFilter: {},
|
|
1003
|
+
allowedTriggers: ['each_match'],
|
|
1004
|
+
catalog: undefined,
|
|
1005
|
+
shadow: true,
|
|
1006
|
+
rule: {
|
|
1007
|
+
default: {
|
|
1008
|
+
ruleKey: 'internal.billing.usage_charge',
|
|
1009
|
+
groupKey: BILLING_USAGE_GROUP_KEY,
|
|
1010
|
+
},
|
|
1011
|
+
create: (_input, base) => ({
|
|
1012
|
+
...base,
|
|
1013
|
+
repeatMode: 'every_match',
|
|
1014
|
+
trigger: { kind: 'each_match' },
|
|
1015
|
+
}),
|
|
1016
|
+
present: ({ payload }) => ({
|
|
1017
|
+
title: payload.paging
|
|
1018
|
+
? 'Large individual usage charge'
|
|
1019
|
+
: 'Individual usage charge over $10',
|
|
1020
|
+
summary: [
|
|
1021
|
+
{ workspace: true },
|
|
1022
|
+
` charged ${payload.amount} for ${payload.tool}.`,
|
|
1023
|
+
],
|
|
1024
|
+
details: [
|
|
1025
|
+
`Tool: ${payload.tool}`,
|
|
1026
|
+
`Charge record time (UTC): ${payload.chargeTime}`,
|
|
1027
|
+
`Charge: ${payload.chargeId}`,
|
|
1028
|
+
`Paging threshold: ${payload.threshold}`,
|
|
1029
|
+
'Investigate settlement and performed work. For verified legitimate large batches, raise monitoring.largeUsageChargeThresholds for this exact tool in its provider registry and publish the catalog. Keep over-$10 messages enabled. Runbook: https://github.com/getaero-io/deepline-api/blob/main/docs/billing-observability.md#individual-charge-slack-messages-and-response',
|
|
1030
|
+
],
|
|
1031
|
+
targetUrl: String(payload.targetUrl),
|
|
1032
|
+
subjectKind: 'usage_charge',
|
|
1033
|
+
subjectId: String(payload.chargeId),
|
|
1034
|
+
...(payload.paging ? { severity: 'error' as const } : {}),
|
|
1035
|
+
}),
|
|
1036
|
+
},
|
|
1037
|
+
},
|
|
998
1038
|
lateCreditDeliveryRegistration(
|
|
999
1039
|
BILLING_PURCHASE_LATE_RULE_KEY,
|
|
1000
1040
|
ProductNotificationEvent.BillingPurchaseLate,
|