deepline 0.3.461 → 0.3.462
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 +7593 -0
- package/dist/bundling-sources/sdk/src/client.ts +8 -7366
- package/dist/bundling-sources/sdk/src/http-core.ts +1239 -0
- package/dist/bundling-sources/sdk/src/http.ts +6 -1231
- package/dist/bundling-sources/sdk/src/index.ts +4 -1
- package/dist/bundling-sources/sdk/src/play.ts +5 -5
- package/dist/bundling-sources/sdk/src/plays/client-core.ts +437 -0
- package/dist/bundling-sources/sdk/src/plays/client.ts +4 -421
- package/dist/bundling-sources/sdk/src/plays/input-example.ts +3 -4
- package/dist/bundling-sources/sdk/src/plays/play-description.ts +1 -1
- package/dist/bundling-sources/sdk/src/plays/run-request.ts +1 -1
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/server.ts +43 -0
- package/dist/bundling-sources/sdk/src/types.ts +15 -5
- package/dist/bundling-sources/shared_libs/integration-contracts/billing-entitlements.ts +15 -0
- package/dist/bundling-sources/shared_libs/monitors/callback-security.ts +0 -307
- package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +3 -0
- package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +3 -2
- package/dist/bundling-sources/shared_libs/monitors/package.json +2 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-callback-verification.ts +34 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +59 -0
- package/dist/bundling-sources/shared_libs/monitors/provider-monitor-upstream-identity.ts +94 -1
- package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-dead-letter.ts +11 -1
- package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-failure-codes.ts +24 -0
- package/dist/bundling-sources/shared_libs/observability/dlq.ts +32 -0
- package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +57 -3
- package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +66 -1
- package/dist/bundling-sources/shared_libs/play-data-plane/sheet-column-storage.ts +36 -7
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +250 -11
- package/dist/bundling-sources/shared_libs/play-runtime/array-input-store.ts +319 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +991 -359
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +17 -0
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +13 -0
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-reaper.ts +110 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +155 -6
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +110 -6
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +127 -13
- package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +14 -1
- package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +57 -1
- package/dist/bundling-sources/shared_libs/play-runtime/free-company-lookup-batching.ts +218 -0
- package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +42 -5
- package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-budget-state-backend.ts +6 -1
- package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +92 -31
- package/dist/bundling-sources/shared_libs/play-runtime/governor/block-reserving-budget-state-backend.ts +69 -14
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +93 -23
- package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +15 -4
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +22 -18
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +5 -0
- package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +190 -14
- package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +131 -0
- package/dist/bundling-sources/shared_libs/play-runtime/modal-runtime-config.ts +77 -2
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +271 -2
- package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +51 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/contracts.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/job.ts +27 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-text-for-log.ts +63 -0
- package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +19 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-event-transport.ts +112 -16
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +104 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +265 -151
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-gateway-transport.ts +17 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +35 -14
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-sheet-persistence-retry.ts +12 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-control-transport.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-labels.ts +36 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-launch-transport.ts +136 -70
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +237 -36
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +148 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +285 -32
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +251 -56
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +29 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/sandbox-create-outcome.ts +27 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +22 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +1397 -382
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-array-input-receipts.ts +920 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-constants.ts +16 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +38 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-incident-drills.ts +26 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +30 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +14 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +31 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-transition.ts +47 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-compute-usage.ts +20 -7
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/index.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +1496 -320
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +31 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1389 -129
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +36 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-dispatch-authority.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +162 -23
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +499 -115
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +377 -9
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-ledger-reconciliation.ts +117 -8
- package/dist/bundling-sources/shared_libs/play-runtime/secret-resolution-retry-policy.ts +25 -0
- package/dist/bundling-sources/shared_libs/play-runtime/terminal-runtime-performance.ts +391 -0
- package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/mapped-calls.ts +171 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +16 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +26 -3
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +16 -2
- package/dist/bundling-sources/shared_libs/play-runtime/transport-error-diagnostics.ts +28 -0
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-storage-contract.ts +55 -5
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +41 -1
- package/dist/bundling-sources/shared_libs/plays/contracts.ts +4 -0
- package/dist/bundling-sources/shared_libs/plays/dataset.ts +9 -3
- package/dist/bundling-sources/shared_libs/plays/deploy/manifest-contract.ts +2 -0
- package/dist/bundling-sources/shared_libs/plays/deploy/manifest.ts +3 -2
- package/dist/bundling-sources/shared_libs/plays/deploy/project-serializer.ts +2 -2
- package/dist/bundling-sources/shared_libs/plays/run-output-summary.ts +66 -0
- package/dist/bundling-sources/shared_libs/plays/script-entry.ts +1 -1
- package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +43 -1
- package/dist/bundling-sources/shared_libs/product-notifications/content.ts +9 -0
- package/dist/bundling-sources/shared_libs/product-notifications/email.ts +91 -13
- package/dist/bundling-sources/shared_libs/product-notifications/events.ts +3 -0
- package/dist/bundling-sources/shared_libs/product-notifications/slack-delivery.ts +41 -24
- package/dist/bundling-sources/shared_libs/security/attested-client-ip.ts +91 -0
- package/dist/bundling-sources/shared_libs/security/internal-actor.ts +0 -11
- package/dist/cli/{auth-6HJXNWUG.mjs → auth-JDLEY7VU.mjs} +5 -4
- package/dist/cli/auth-UXKY6TCC.js +41 -0
- package/dist/cli/{billing-6P5HO6QG.js → billing-HXAXB3XZ.js} +152 -78
- package/dist/cli/{billing-MJ42N7YF.mjs → billing-SDHLBLMV.mjs} +84 -10
- package/dist/cli/{chunk-5MDIZX7M.js → chunk-3ACMRZRV.js} +8 -6
- package/dist/cli/{chunk-FGLKOWSC.mjs → chunk-3KZCFOZ6.mjs} +1 -1
- package/dist/cli/chunk-4KQ6SIBC.mjs +1038 -0
- package/dist/cli/{chunk-Z2GUFYT6.js → chunk-5LEAXRHV.js} +11 -11
- package/dist/cli/{chunk-MEAIOXJL.mjs → chunk-6NNVJDVR.mjs} +7 -5
- package/dist/cli/{chunk-NMJ4D2WO.js → chunk-6PMCRYDA.js} +216 -91
- package/dist/cli/{chunk-RY4IVOU3.mjs → chunk-6RNQGWFD.mjs} +16 -806
- package/dist/cli/{chunk-EBU7LQ64.js → chunk-6V7KVRR5.js} +3 -3
- package/dist/cli/{chunk-OZBWRICM.js → chunk-7LFIMWMW.js} +2 -2
- package/dist/cli/chunk-7MJ6VI2T.mjs +19 -0
- package/dist/cli/chunk-7SWNPNML.js +1039 -0
- package/dist/cli/{chunk-IHHLTHE7.mjs → chunk-7U3XNPOA.mjs} +267 -38
- package/dist/cli/{chunk-5FDKJQZE.js → chunk-7VZHXVOQ.js} +1 -1
- package/dist/cli/{chunk-R64BGGRQ.mjs → chunk-AT636LLU.mjs} +2 -2
- package/dist/cli/{chunk-MDJPEGVN.js → chunk-BGTPIMSM.js} +392 -261
- package/dist/cli/{chunk-KVJ5VHW5.mjs → chunk-CKSOY47X.mjs} +2 -2
- package/dist/cli/{chunk-7DH2FD7Y.mjs → chunk-D464JW3N.mjs} +5 -85
- package/dist/cli/chunk-D6DXOUTO.mjs +827 -0
- package/dist/cli/{describe-2WQY7ZCY.js → chunk-EM4TXCCI.js} +27 -44
- package/dist/cli/chunk-F6QV42MC.mjs +91 -0
- package/dist/cli/chunk-FKVYR3QA.mjs +1039 -0
- package/dist/cli/{chunk-FGMX4HUZ.js → chunk-GEGW5HPZ.js} +29 -27
- package/dist/cli/{chunk-TNMBPMMC.js → chunk-HUB3CCM2.js} +13 -4
- package/dist/cli/{chunk-ACCR7POB.js → chunk-I6VHOU5O.js} +27 -27
- package/dist/cli/{chunk-Z2XUZC34.js → chunk-IAYSWZDJ.js} +188 -76
- package/dist/cli/chunk-JF3TLIMQ.js +19 -0
- package/dist/cli/{chunk-HDFRJ4IT.mjs → chunk-JVHOS3K3.mjs} +177 -65
- package/dist/cli/{chunk-V7REJRDZ.mjs → chunk-LFXLQEZN.mjs} +1 -1
- package/dist/cli/{chunk-CRYOUPEB.js → chunk-LROWFPGN.js} +16 -16
- package/dist/cli/{chunk-SLEUWLJE.mjs → chunk-MSY22NQW.mjs} +5 -5
- package/dist/cli/{chunk-BGY2PLP7.mjs → chunk-MUUQZIOF.mjs} +23 -49
- package/dist/cli/{chunk-FCAZQ7WV.js → chunk-NBLSCHKK.js} +52 -50
- package/dist/cli/{chunk-QAJAJPKK.mjs → chunk-NHRWZPWZ.mjs} +4 -2
- package/dist/cli/{chunk-KXMNM4AQ.js → chunk-NMU3VR5U.js} +4 -5
- package/dist/cli/{chunk-QIW7TVV6.mjs → chunk-O2RX5A66.mjs} +14 -12
- package/dist/cli/{chunk-SAZFZQRI.js → chunk-OMQ23IXL.js} +2 -2
- package/dist/cli/{chunk-5IYOUBFZ.js → chunk-OPJAJBD4.js} +28 -54
- package/dist/cli/{chunk-FJZILBL7.mjs → chunk-PHSEINNH.mjs} +5 -5
- package/dist/cli/{chunk-3DNKFH2G.mjs → chunk-PKHVSIJG.mjs} +19 -1
- package/dist/cli/{chunk-WIYWSYDS.mjs → chunk-Q2EIZKVX.mjs} +3 -3
- package/dist/cli/{chunk-5FY72YOV.js → chunk-QJZ6WNWD.js} +8 -8
- package/dist/cli/{chunk-EIMG75BT.mjs → chunk-S3A4IXBQ.mjs} +4 -5
- package/dist/cli/{chunk-3BMLICF7.mjs → chunk-S42YIQNE.mjs} +13 -8
- package/dist/cli/{chunk-RFONC4WJ.mjs → chunk-S6UAJR6V.mjs} +3 -3
- package/dist/cli/{chunk-G7L27KZB.mjs → chunk-TKAQR3IB.mjs} +31 -21
- package/dist/cli/{chunk-QWRHGGUH.js → chunk-UAJFWWZE.js} +20 -2
- package/dist/cli/{chunk-VZBCEA5S.mjs → chunk-UDRPEZ5F.mjs} +223 -92
- package/dist/cli/{chunk-KCCOQ5G5.js → chunk-ULK7JGGI.js} +511 -282
- package/dist/cli/chunk-V335HGX5.js +1038 -0
- package/dist/cli/{chunk-MGXEUZHL.mjs → chunk-V3MEA7NB.mjs} +7 -5
- package/dist/cli/{chunk-O6QOMHCH.js → chunk-VFGVXXZP.js} +37 -35
- package/dist/cli/chunk-VLEVVDWG.js +91 -0
- package/dist/cli/{chunk-R2GLGLDR.mjs → chunk-VPHN2HAL.mjs} +216 -91
- package/dist/cli/{chunk-CFUTOWE4.js → chunk-WG3KGAII.js} +8 -88
- package/dist/cli/{describe-FRAVCY5F.mjs → chunk-WIY6U6GD.mjs} +19 -36
- package/dist/cli/{chunk-PNATXKLP.js → chunk-XANRM3QA.js} +6 -6
- package/dist/cli/{chunk-KGQNIA37.js → chunk-XQCTG5OO.js} +44 -34
- package/dist/cli/{chunk-T3MVIPHG.mjs → chunk-XZAFIOUQ.mjs} +1 -1
- package/dist/cli/chunk-Y4DPU4OM.js +827 -0
- package/dist/cli/chunk-YT5EODJO.js +920 -0
- package/dist/cli/{chunk-SCIR5JXW.js → chunk-ZGQSFYD2.js} +56 -51
- package/dist/cli/{chunk-QEYHTIV4.mjs → chunk-ZUK6LIJB.mjs} +10 -1
- package/dist/cli/command-docs.d.mts +5 -0
- package/dist/cli/command-docs.d.ts +5 -0
- package/dist/cli/command-docs.js +2 -2
- package/dist/cli/command-docs.mjs +1 -1
- package/dist/cli/{csv-NX7NO3O6.js → csv-C56GSCEU.js} +13 -12
- package/dist/cli/{csv-DQ6GW5B5.mjs → csv-L54JS7TF.mjs} +4 -3
- package/dist/cli/{db-R72DFMP6.js → db-MOGRMZTA.js} +30 -27
- package/dist/cli/{db-2YP33M4K.mjs → db-YVBUW2DX.mjs} +10 -7
- package/dist/cli/describe-KYEULWPG.js +48 -0
- package/dist/cli/describe-NLZKKT7C.mjs +48 -0
- package/dist/cli/describe-core.d.mts +153 -5
- package/dist/cli/describe-core.d.ts +153 -5
- package/dist/cli/describe-core.js +9 -5
- package/dist/cli/describe-core.mjs +10 -6
- package/dist/cli/{executions-ZLHD4QIT.js → executions-A7L4ULPP.js} +9 -7
- package/dist/cli/{executions-WFBU7L2Q.mjs → executions-ZBGSTT37.mjs} +7 -5
- package/dist/cli/{feedback-CN3HJFVF.mjs → feedback-G6GU37FD.mjs} +6 -5
- package/dist/cli/{feedback-NDV6TPHG.js → feedback-OHLY7RYD.js} +10 -9
- package/dist/cli/getting-started.d.mts +6 -6
- package/dist/cli/getting-started.d.ts +6 -6
- package/dist/cli/getting-started.js +2 -2
- package/dist/cli/getting-started.mjs +1 -1
- package/dist/cli/git-P76N4NDQ.js +25 -0
- package/dist/cli/{git-QAD6E3HW.mjs → git-PKZW3QD5.mjs} +5 -4
- package/dist/cli/index.js +152 -142
- package/dist/cli/index.mjs +56 -46
- package/dist/cli/{legacy-noops-KVC5QJ74.js → legacy-noops-5LM3D724.js} +8 -7
- package/dist/cli/{legacy-noops-TPTKNBI2.mjs → legacy-noops-LJJYG6YA.mjs} +5 -4
- package/dist/cli/{monitors-SV57JFLO.mjs → monitors-72QV4ALO.mjs} +19 -6
- package/dist/cli/{monitors-KCROV6PJ.js → monitors-UX3H5DC2.js} +103 -90
- package/dist/cli/{org-KX6QIR7A.mjs → org-6RRRKOCP.mjs} +9 -6
- package/dist/cli/{org-NJYX5743.js → org-IF7ISUVB.js} +70 -67
- package/dist/cli/pages-3SU3HKL7.js +252 -0
- package/dist/cli/pages-DXDYYKEK.mjs +252 -0
- package/dist/cli/{play-IQQ57L7Z.mjs → play-AHASKRLA.mjs} +512 -1508
- package/dist/cli/{play-32L7EQN4.js → play-EUIUVLUH.js} +1090 -2086
- package/dist/cli/{providers-4WEC2EQN.mjs → providers-GWGE3WY3.mjs} +7 -5
- package/dist/cli/{providers-ZQV6QLVQ.js → providers-V5WU4VXJ.js} +10 -8
- package/dist/cli/{quickstart-RQ76RIUE.mjs → quickstart-OXKQ5ZST.mjs} +5 -4
- package/dist/cli/{quickstart-HKUSFADF.js → quickstart-QP65I5PF.js} +13 -12
- package/dist/cli/run-6MM72IGL.mjs +443 -0
- package/dist/cli/run-F3FTYS56.js +443 -0
- package/dist/cli/search-OYKOOI7A.js +32 -0
- package/dist/cli/{search-ZRAVFBZC.mjs → search-ZMEBVJZB.mjs} +8 -6
- package/dist/cli/{secrets-J3G5Y43U.js → secrets-ACND5N6A.js} +16 -14
- package/dist/cli/{secrets-CMJOVNVH.mjs → secrets-XRCJFF3L.mjs} +7 -5
- package/dist/cli/{sessions-MDQYY5CB.mjs → sessions-RTK3CEW6.mjs} +5 -4
- package/dist/cli/{sessions-WY7VN4AE.js → sessions-ZGRJPCFF.js} +6 -5
- package/dist/cli/{settings-HTNTFKCE.js → settings-PD5KWQQZ.js} +80 -77
- package/dist/cli/{settings-4RWZPCT5.mjs → settings-XDRBPRDE.mjs} +14 -11
- package/dist/cli/{setup-P3GYYZWG.mjs → setup-3HPYAOCC.mjs} +12 -10
- package/dist/cli/{setup-QGCAP62X.js → setup-E2Q6PXHC.js} +53 -51
- package/dist/cli/{skills-7NAE4ICL.mjs → skills-OOQFMPOV.mjs} +7 -6
- package/dist/cli/skills-XYWV52KB.js +31 -0
- package/dist/cli/tools-ASCDZJCK.js +55 -0
- package/dist/cli/tools-C5ZT3UIC.mjs +55 -0
- package/dist/cli/update-5RQSEIFM.js +33 -0
- package/dist/cli/{update-GODLRKNB.mjs → update-ZWJTADIW.mjs} +9 -8
- package/dist/cli/{workflow-4BXOUVEO.mjs → workflow-23NMPAJ7.mjs} +10 -8
- package/dist/cli/{workflow-AO3A6LXN.js → workflow-TCXU5YJV.js} +20 -18
- package/dist/client-DS2IWYZF.d.ts +10 -0
- package/dist/client-DTwnz_AW.d.mts +10 -0
- package/dist/{client-CYqG23K1.d.ts → client-core-B_6HAIBy.d.ts} +385 -12
- package/dist/{client-BbU5_j7n.d.mts → client-core-DzBSlY1U.d.mts} +385 -12
- package/dist/{compiler-manifest-CWz_sNOQ.d.ts → compiler-manifest-Dcyd3-Zd.d.mts} +43 -1
- package/dist/{compiler-manifest-CWz_sNOQ.d.mts → compiler-manifest-Dcyd3-Zd.d.ts} +43 -1
- package/dist/errors-d-sTrZhe.d.mts +142 -0
- package/dist/errors-yQwfgrcX.d.ts +142 -0
- package/dist/{index-BF2JB_Ug.d.mts → index-C6oXchjN.d.mts} +1 -1
- package/dist/{index-4NPXDzlD.d.ts → index-P56zy_z5.d.ts} +1 -1
- package/dist/index.d.mts +11 -147
- package/dist/index.d.ts +11 -147
- package/dist/index.js +15 -11
- package/dist/index.mjs +14 -10
- package/dist/install-integrity.json +141 -104
- 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 +2 -1
- package/dist/plays/play-description.d.mts +2 -2
- package/dist/plays/play-description.d.ts +2 -2
- package/dist/plays/play-description.js +2 -2
- package/dist/plays/play-description.mjs +1 -1
- 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 +17 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.js +76 -0
- package/dist/server.mjs +76 -0
- package/package.json +6 -1
- package/dist/cli/auth-IACERYQH.js +0 -40
- package/dist/cli/chunk-PQUUWFXY.js +0 -95
- package/dist/cli/chunk-YBWAG72P.mjs +0 -95
- package/dist/cli/chunk-YQDUODZW.js +0 -1710
- package/dist/cli/git-JVI36ZFV.js +0 -24
- package/dist/cli/search-75X5LTDE.js +0 -30
- package/dist/cli/skills-BKJ53JOQ.js +0 -30
- package/dist/cli/tools-COWMIEJ6.mjs +0 -45
- package/dist/cli/tools-TASOCE7I.js +0 -45
- package/dist/cli/update-SJIKVME6.js +0 -32
|
@@ -54,6 +54,7 @@ import type { CompiledRequestBatch } from './batch-runtime';
|
|
|
54
54
|
import type { AnyBatchOperationStrategy } from './batching-types';
|
|
55
55
|
import {
|
|
56
56
|
getBillingEntitlementsViaAppRuntime,
|
|
57
|
+
writePageViaAppRuntime,
|
|
57
58
|
type RuntimeApiResponseMeta,
|
|
58
59
|
} from './app-runtime-api';
|
|
59
60
|
import {
|
|
@@ -109,6 +110,8 @@ import {
|
|
|
109
110
|
import { isImmutableRuntimeExecutionRecoveryOrigin } from './scheduler-backends/runtime-api-origin';
|
|
110
111
|
import {
|
|
111
112
|
isRetryableSecretResolutionStatus,
|
|
113
|
+
secretResolutionGotNoResponse,
|
|
114
|
+
secretResolutionOutageRetryDelayMs,
|
|
112
115
|
secretResolutionRetryDecision,
|
|
113
116
|
SECRET_RESOLUTION_MAX_ATTEMPTS,
|
|
114
117
|
SECRET_RESOLUTION_ATTEMPT_TIMEOUT_MS,
|
|
@@ -136,6 +139,7 @@ import {
|
|
|
136
139
|
type PacingResolver,
|
|
137
140
|
type PlayExecutionGovernor,
|
|
138
141
|
} from './governor/governor';
|
|
142
|
+
import { hasExplicitRowConcurrency } from './governor/policy';
|
|
139
143
|
import {
|
|
140
144
|
createRuntimeResourceGovernor,
|
|
141
145
|
type RuntimeResourceGovernor,
|
|
@@ -214,6 +218,7 @@ import {
|
|
|
214
218
|
createAlwaysFreshToolCallAdapter,
|
|
215
219
|
createExternallyOwnedToolResultReceipts,
|
|
216
220
|
createNativeBatchToolCallJob,
|
|
221
|
+
createMappedToolCallJob,
|
|
217
222
|
createToolCallReceiptCohortJob,
|
|
218
223
|
createRuntimeStepToolResultReceipts,
|
|
219
224
|
createToolCallJob,
|
|
@@ -232,6 +237,7 @@ import {
|
|
|
232
237
|
type ToolExecutionOutcome,
|
|
233
238
|
} from './tool-execution-outcome';
|
|
234
239
|
import {
|
|
240
|
+
toolExecuteConnectRetryDelayMs,
|
|
235
241
|
TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS,
|
|
236
242
|
TOOL_EXECUTE_RUNNER_ACCEPTS_HEADER,
|
|
237
243
|
TOOL_EXECUTE_RUNNER_ACCEPTS_VALUE,
|
|
@@ -260,6 +266,7 @@ import {
|
|
|
260
266
|
} from './tool-http-errors';
|
|
261
267
|
import {
|
|
262
268
|
describeTransportError,
|
|
269
|
+
transportFailureProvesRequestNeverSent,
|
|
263
270
|
transportGatewayOriginForDiagnostic,
|
|
264
271
|
} from './transport-error-diagnostics';
|
|
265
272
|
import {
|
|
@@ -292,6 +299,8 @@ import {
|
|
|
292
299
|
type PlaySecretPromise,
|
|
293
300
|
type PlaySqlQuery,
|
|
294
301
|
type PlayAuthoringRunScope,
|
|
302
|
+
type PlayAuthoringPageWriteOptions,
|
|
303
|
+
type PlayAuthoringPageWriteResult,
|
|
295
304
|
type PlayAuthoringRuntimeContext,
|
|
296
305
|
type PlayAuthoringRunStepsOptions,
|
|
297
306
|
} from '../plays/authoring-contract';
|
|
@@ -402,6 +411,14 @@ import {
|
|
|
402
411
|
type RuntimeMapHeapAdmissionSnapshot,
|
|
403
412
|
} from './map-memory-limits';
|
|
404
413
|
import { RuntimeMapRowFeed } from './runtime-map-row-feed';
|
|
414
|
+
import {
|
|
415
|
+
iterateSealedRuntimeArrayInput,
|
|
416
|
+
sealRuntimeArrayInput,
|
|
417
|
+
RuntimeArrayInputStoreUnavailableError,
|
|
418
|
+
isLosslessArrayInputValue,
|
|
419
|
+
type RuntimeArrayInputManifest,
|
|
420
|
+
type RuntimeArrayInputScope,
|
|
421
|
+
} from './array-input-store';
|
|
405
422
|
import { ProviderRowRetryQueue } from './provider-row-retry-queue';
|
|
406
423
|
import type { ProviderRowRetry } from './provider-row-retry-queue';
|
|
407
424
|
import type { RuntimeMapRowFeedSnapshot } from './runtime-map-row-feed';
|
|
@@ -655,6 +672,7 @@ const authoredStepContext = new AsyncLocalStorage<{
|
|
|
655
672
|
}>();
|
|
656
673
|
const toolExecutionOverrides = new AsyncLocalStorage<{ force: boolean }>();
|
|
657
674
|
const PROGRESS_HEARTBEAT_INTERVAL_MS = 1_000;
|
|
675
|
+
|
|
658
676
|
const PURE_JS_HEARTBEAT_ROW_INTERVAL = 250;
|
|
659
677
|
/** Executed-row sheet persistence chunking: rows AND bytes, whichever first. */
|
|
660
678
|
const MAP_PERSIST_CHUNK_ROWS = 2_000;
|
|
@@ -1462,9 +1480,23 @@ function isUnmarkedExecutionGateway502(input: {
|
|
|
1462
1480
|
}
|
|
1463
1481
|
}
|
|
1464
1482
|
|
|
1465
|
-
function waitForSecretResolutionRetry(
|
|
1483
|
+
function waitForSecretResolutionRetry(
|
|
1484
|
+
ms: number,
|
|
1485
|
+
signal?: AbortSignal,
|
|
1486
|
+
): Promise<void> {
|
|
1487
|
+
signal?.throwIfAborted();
|
|
1466
1488
|
if (ms <= 0) return Promise.resolve();
|
|
1467
|
-
return new Promise<void>((resolve) =>
|
|
1489
|
+
return new Promise<void>((resolve, reject) => {
|
|
1490
|
+
const onAbort = () => {
|
|
1491
|
+
clearTimeout(timer);
|
|
1492
|
+
reject(signal?.reason);
|
|
1493
|
+
};
|
|
1494
|
+
const timer = setTimeout(() => {
|
|
1495
|
+
signal?.removeEventListener('abort', onAbort);
|
|
1496
|
+
resolve();
|
|
1497
|
+
}, ms);
|
|
1498
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
1499
|
+
});
|
|
1468
1500
|
}
|
|
1469
1501
|
|
|
1470
1502
|
function cancelRuntimeResponseBody(response: Response): void {
|
|
@@ -2720,6 +2752,7 @@ type ScalarPlayAuthoringRuntimeContext = Pick<
|
|
|
2720
2752
|
| 'tools'
|
|
2721
2753
|
| 'customerDb'
|
|
2722
2754
|
| 'billing'
|
|
2755
|
+
| 'pages'
|
|
2723
2756
|
| 'run'
|
|
2724
2757
|
| 'tool'
|
|
2725
2758
|
| 'step'
|
|
@@ -2730,6 +2763,36 @@ type ScalarPlayAuthoringRuntimeContext = Pick<
|
|
|
2730
2763
|
| 'sleep'
|
|
2731
2764
|
>;
|
|
2732
2765
|
|
|
2766
|
+
/** Text stays text on the wire, so only real binary pays the base64 overhead. */
|
|
2767
|
+
function encodePageContent(
|
|
2768
|
+
name: string,
|
|
2769
|
+
options: PlayAuthoringPageWriteOptions,
|
|
2770
|
+
): { contentType: string } & (
|
|
2771
|
+
| { contentText: string }
|
|
2772
|
+
| { contentBase64: string }
|
|
2773
|
+
) {
|
|
2774
|
+
const { content, contentType } = options;
|
|
2775
|
+
if (typeof content === 'string') {
|
|
2776
|
+
return {
|
|
2777
|
+
contentType: contentType ?? 'text/plain; charset=utf-8',
|
|
2778
|
+
contentText: content,
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
if (content instanceof Uint8Array || content instanceof ArrayBuffer) {
|
|
2782
|
+
return {
|
|
2783
|
+
contentType: contentType ?? 'application/octet-stream',
|
|
2784
|
+
contentBase64: Buffer.from(content as Uint8Array).toString('base64'),
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
const contentText = JSON.stringify(content);
|
|
2788
|
+
if (contentText === undefined) {
|
|
2789
|
+
throw new Error(
|
|
2790
|
+
`ctx.pages.write("${name}") requires content: a string, bytes, or a JSON value.`,
|
|
2791
|
+
);
|
|
2792
|
+
}
|
|
2793
|
+
return { contentType: contentType ?? 'application/json', contentText };
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2733
2796
|
export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
2734
2797
|
private rowStates = new Map<number, RowState>();
|
|
2735
2798
|
private toolCallQueue: ToolCallRequest[] = [];
|
|
@@ -3023,6 +3086,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
3023
3086
|
private readonly providerResponseBodyGate = createRuntimeReceiptHydrationGate(
|
|
3024
3087
|
{
|
|
3025
3088
|
occupancy: this.runtimeMemoryOccupancy,
|
|
3089
|
+
reservationCategory: 'providerBody',
|
|
3090
|
+
// Existing egress byte-work boundary, not a memory/output/width limit.
|
|
3091
|
+
cooperativeYieldBytes: RUNTIME_RECEIPT_WRITER_TARGET_BATCH_BYTES,
|
|
3026
3092
|
reserve: (bytes) =>
|
|
3027
3093
|
this.memoryLedger.register({ category: 'providerBody', bytes }),
|
|
3028
3094
|
},
|
|
@@ -3355,6 +3421,40 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
3355
3421
|
},
|
|
3356
3422
|
};
|
|
3357
3423
|
|
|
3424
|
+
readonly pages = {
|
|
3425
|
+
write: async (
|
|
3426
|
+
name: string,
|
|
3427
|
+
options: PlayAuthoringPageWriteOptions,
|
|
3428
|
+
): Promise<PlayAuthoringPageWriteResult> => {
|
|
3429
|
+
this.assertNoPendingDurableSuspension();
|
|
3430
|
+
if (typeof name !== 'string' || !name) {
|
|
3431
|
+
throw new Error('ctx.pages.write(name, options) requires a page name.');
|
|
3432
|
+
}
|
|
3433
|
+
if (typeof options?.public !== 'boolean') {
|
|
3434
|
+
throw new Error(
|
|
3435
|
+
`ctx.pages.write("${name}") requires public: true or false, so the write always says who can see the page.`,
|
|
3436
|
+
);
|
|
3437
|
+
}
|
|
3438
|
+
const result = await writePageViaAppRuntime(
|
|
3439
|
+
{
|
|
3440
|
+
baseUrl: this.#options.baseUrl ?? '',
|
|
3441
|
+
executorToken: this.#options.executorToken ?? '',
|
|
3442
|
+
vercelProtectionBypassToken:
|
|
3443
|
+
this.#options.vercelProtectionBypassToken,
|
|
3444
|
+
signal: this.#options.executionSignal,
|
|
3445
|
+
},
|
|
3446
|
+
{
|
|
3447
|
+
name,
|
|
3448
|
+
public: options.public,
|
|
3449
|
+
description: options.description,
|
|
3450
|
+
...encodePageContent(name, options),
|
|
3451
|
+
},
|
|
3452
|
+
);
|
|
3453
|
+
for (const warning of result.warnings) this.log(warning);
|
|
3454
|
+
return result;
|
|
3455
|
+
},
|
|
3456
|
+
};
|
|
3457
|
+
|
|
3358
3458
|
readonly secrets = {
|
|
3359
3459
|
get: (name: string): PlaySecretPromise => {
|
|
3360
3460
|
if (typeof name !== 'string' || !name.trim()) {
|
|
@@ -4415,21 +4515,28 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
4415
4515
|
const url = `${this.#options.baseUrl.replace(/\/$/, '')}${PLAY_RUNTIME_API_COMPAT_PATH}`;
|
|
4416
4516
|
const operationId = `ctx-secret-operation-${crypto.randomUUID()}`;
|
|
4417
4517
|
const operationStartedAt = Date.now();
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4518
|
+
// Error responses spend the ordinary attempts. A lookup that gets no
|
|
4519
|
+
// response at all keeps retrying through a sandbox network cut, so the
|
|
4520
|
+
// run's cancellation must stop both the request and the wait.
|
|
4521
|
+
const executionSignal = this.#options.executionSignal;
|
|
4522
|
+
let respondedAttempts = 0;
|
|
4523
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
4524
|
+
executionSignal?.throwIfAborted();
|
|
4423
4525
|
const requestId = `ctx-secret-${crypto.randomUUID()}`;
|
|
4424
4526
|
const attemptStartedAt = Date.now();
|
|
4527
|
+
// Bound the control-plane call so a stalled connection aborts and is
|
|
4528
|
+
// caught below as a transport failure instead of hanging the tool
|
|
4529
|
+
// call "1 in flight" forever.
|
|
4530
|
+
const attemptTimeout = AbortSignal.timeout(
|
|
4531
|
+
SECRET_RESOLUTION_ATTEMPT_TIMEOUT_MS,
|
|
4532
|
+
);
|
|
4425
4533
|
let response: Response;
|
|
4426
4534
|
try {
|
|
4427
4535
|
response = await fetch(url, {
|
|
4428
4536
|
method: 'POST',
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
signal: AbortSignal.timeout(SECRET_RESOLUTION_ATTEMPT_TIMEOUT_MS),
|
|
4537
|
+
signal: executionSignal
|
|
4538
|
+
? AbortSignal.any([executionSignal, attemptTimeout])
|
|
4539
|
+
: attemptTimeout,
|
|
4433
4540
|
headers: {
|
|
4434
4541
|
Authorization: `Bearer ${this.#options.executorToken}`,
|
|
4435
4542
|
'Content-Type': 'application/json',
|
|
@@ -4445,11 +4552,23 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
4445
4552
|
}),
|
|
4446
4553
|
});
|
|
4447
4554
|
} catch (error) {
|
|
4555
|
+
executionSignal?.throwIfAborted();
|
|
4448
4556
|
const diagnostic = describeTransportError(error);
|
|
4449
|
-
const
|
|
4557
|
+
const ladder = secretResolutionRetryDecision({
|
|
4450
4558
|
attempt,
|
|
4451
4559
|
retryAfter: null,
|
|
4452
4560
|
});
|
|
4561
|
+
const outageRetryDelayMs =
|
|
4562
|
+
!ladder.retry && secretResolutionGotNoResponse(error)
|
|
4563
|
+
? secretResolutionOutageRetryDelayMs({
|
|
4564
|
+
attempt,
|
|
4565
|
+
elapsedMs: Date.now() - operationStartedAt,
|
|
4566
|
+
})
|
|
4567
|
+
: null;
|
|
4568
|
+
const retry =
|
|
4569
|
+
outageRetryDelayMs === null
|
|
4570
|
+
? ladder
|
|
4571
|
+
: { ...ladder, retry: true, retryDelayMs: outageRetryDelayMs };
|
|
4453
4572
|
this.runtimeLog(
|
|
4454
4573
|
`[runtime.secret_resolution_failure] ${JSON.stringify({
|
|
4455
4574
|
stage: 'transport',
|
|
@@ -4471,13 +4590,20 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
4471
4590
|
`Secret ${secret.name} resolution transport failed (request_id=${requestId}): ${diagnostic.message ?? 'unknown transport error'}`,
|
|
4472
4591
|
);
|
|
4473
4592
|
}
|
|
4474
|
-
await waitForSecretResolutionRetry(
|
|
4593
|
+
await waitForSecretResolutionRetry(
|
|
4594
|
+
retry.retryDelayMs,
|
|
4595
|
+
executionSignal,
|
|
4596
|
+
);
|
|
4475
4597
|
continue;
|
|
4476
4598
|
}
|
|
4477
4599
|
|
|
4478
4600
|
const retryAfter = response.headers.get('retry-after');
|
|
4601
|
+
respondedAttempts += 1;
|
|
4479
4602
|
const retry = isRetryableSecretResolutionStatus(response.status)
|
|
4480
|
-
? secretResolutionRetryDecision({
|
|
4603
|
+
? secretResolutionRetryDecision({
|
|
4604
|
+
attempt: respondedAttempts,
|
|
4605
|
+
retryAfter,
|
|
4606
|
+
})
|
|
4481
4607
|
: NO_SECRET_RESOLUTION_RETRY;
|
|
4482
4608
|
const responseDiagnostic = {
|
|
4483
4609
|
stage: response.ok ? 'invalid_response' : 'http_response',
|
|
@@ -4510,7 +4636,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
4510
4636
|
);
|
|
4511
4637
|
cancelRuntimeResponseBody(response);
|
|
4512
4638
|
if (retry.retry) {
|
|
4513
|
-
await waitForSecretResolutionRetry(
|
|
4639
|
+
await waitForSecretResolutionRetry(
|
|
4640
|
+
retry.retryDelayMs,
|
|
4641
|
+
executionSignal,
|
|
4642
|
+
);
|
|
4514
4643
|
continue;
|
|
4515
4644
|
}
|
|
4516
4645
|
throw new Error(
|
|
@@ -5422,6 +5551,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
5422
5551
|
private async withProviderResponseBodyTurn<T>(
|
|
5423
5552
|
response: Response,
|
|
5424
5553
|
read: (turn: RuntimeReceiptHydrationTurn) => Promise<T>,
|
|
5554
|
+
signal?: AbortSignal,
|
|
5425
5555
|
): Promise<{ value: T; waitMs: number }> {
|
|
5426
5556
|
const queuedAtMs = Date.now();
|
|
5427
5557
|
const expectedBytes = runtimeProviderResponseBodyExpectedBytes({
|
|
@@ -5432,9 +5562,30 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
5432
5562
|
this.#options.executionGatewayBaseUrl?.trim(),
|
|
5433
5563
|
),
|
|
5434
5564
|
});
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5565
|
+
let turn: RuntimeReceiptHydrationTurn;
|
|
5566
|
+
try {
|
|
5567
|
+
turn = await this.providerResponseBodyGate.acquire({
|
|
5568
|
+
...(expectedBytes === null ? {} : { expectedBytes }),
|
|
5569
|
+
...(signal === undefined ? {} : { signal }),
|
|
5570
|
+
});
|
|
5571
|
+
} catch (error) {
|
|
5572
|
+
// Headers already arrived: an abandoned waiter still owns this unread
|
|
5573
|
+
// stream. Cancel it without replacing the original admission/abort error.
|
|
5574
|
+
const reportCancelFailure = (cancelError: unknown) => {
|
|
5575
|
+
this.runtimeLog(
|
|
5576
|
+
`[runtime-provider-response] unread_body_cancel_failed error=${cancelError instanceof Error ? cancelError.name : 'UnknownError'}`,
|
|
5577
|
+
{ level: 'error' },
|
|
5578
|
+
);
|
|
5579
|
+
};
|
|
5580
|
+
try {
|
|
5581
|
+
// Stream cleanup may remain pending (for example, a tee's other branch).
|
|
5582
|
+
// Start it, but do not hold the caller's abort or provider permit on it.
|
|
5583
|
+
void response.body?.cancel(error).catch(reportCancelFailure);
|
|
5584
|
+
} catch (cancelError) {
|
|
5585
|
+
reportCancelFailure(cancelError);
|
|
5586
|
+
}
|
|
5587
|
+
throw error;
|
|
5588
|
+
}
|
|
5438
5589
|
const waitMs = Math.max(0, Date.now() - queuedAtMs);
|
|
5439
5590
|
try {
|
|
5440
5591
|
return { value: await read(turn), waitMs };
|
|
@@ -7475,7 +7626,12 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
7475
7626
|
return current;
|
|
7476
7627
|
}
|
|
7477
7628
|
if (isSerializedToolExecuteResult(current)) {
|
|
7478
|
-
|
|
7629
|
+
// Cells store the canonical dataset-valued result; a later column must
|
|
7630
|
+
// see the same edition getters as the column that executed the tool.
|
|
7631
|
+
return projectToolResultListGetters(
|
|
7632
|
+
deserializeToolExecuteResult(current),
|
|
7633
|
+
this.currentRuntimeContract.semantics.tools.listGetters,
|
|
7634
|
+
);
|
|
7479
7635
|
}
|
|
7480
7636
|
if (isSerializedPlayDatasetCell(current)) {
|
|
7481
7637
|
return deserializePlayDatasetCell(current, visit);
|
|
@@ -8494,85 +8650,94 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8494
8650
|
: Array.isArray(items)
|
|
8495
8651
|
? items
|
|
8496
8652
|
: null;
|
|
8497
|
-
const
|
|
8653
|
+
const replayMapInvocationId = `${normalizedMapNamespace}:${this.mapInvocationIndex}`;
|
|
8654
|
+
const replayMapFrame = this.checkpoint.mapFrames?.[replayMapInvocationId];
|
|
8655
|
+
const authoredCsvSource =
|
|
8498
8656
|
(isPlayDataset(items) && items.datasetKind === 'csv') ||
|
|
8499
8657
|
residentSourceRows?.some(
|
|
8500
8658
|
(_row, index) =>
|
|
8501
8659
|
getPlayDatasetSourceRowIdentityAt(residentSourceRows, index) !==
|
|
8502
8660
|
undefined,
|
|
8503
8661
|
) === true;
|
|
8504
|
-
const csvOccurrenceIdentityRequired =
|
|
8505
|
-
csvSource &&
|
|
8506
|
-
this.currentRuntimeSemantics.datasets.csvRowIdentity === 'source_row';
|
|
8507
|
-
const rowIdentityMode = csvOccurrenceIdentityRequired
|
|
8508
|
-
? 'source_row'
|
|
8509
|
-
: (options?.rowIdentity ??
|
|
8510
|
-
(options?.key !== undefined
|
|
8511
|
-
? 'key'
|
|
8512
|
-
: csvSource
|
|
8513
|
-
? this.currentRuntimeSemantics.datasets.csvRowIdentity
|
|
8514
|
-
: 'key'));
|
|
8515
|
-
const useSourceRowIdentity = rowIdentityMode === 'source_row';
|
|
8516
8662
|
const userKeyOption = options?.key;
|
|
8517
|
-
let
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
const raw =
|
|
8542
|
-
typeof userKeyOption === 'function'
|
|
8543
|
-
? (
|
|
8544
|
-
userKeyOption as (
|
|
8545
|
-
row: Record<string, unknown>,
|
|
8546
|
-
index: number,
|
|
8547
|
-
) => string | number | readonly unknown[]
|
|
8548
|
-
)(inputRow, index)
|
|
8549
|
-
: Array.isArray(userKeyOption)
|
|
8550
|
-
? userKeyOption.map((fieldName) => inputRow[fieldName])
|
|
8551
|
-
: inputRow[String(userKeyOption)];
|
|
8552
|
-
const parts = Array.isArray(raw) ? raw : [raw];
|
|
8553
|
-
if (parts.some((part) => part === null || part === undefined)) {
|
|
8554
|
-
throw new Error(
|
|
8555
|
-
`ctx.dataset("${normalizedMapNamespace}") key returned null or undefined for row ${index}. ` +
|
|
8556
|
-
'Return a non-empty string or number derived from a stable input column (e.g. row.email ?? row.domain).',
|
|
8663
|
+
let rowIdentityMode: 'source_row' | 'key' = 'key';
|
|
8664
|
+
let useSourceRowIdentity = false;
|
|
8665
|
+
const setSourceIdentityMode = (
|
|
8666
|
+
csvSource: boolean,
|
|
8667
|
+
): ((row: Record<string, unknown>, index: number) => string) | null => {
|
|
8668
|
+
const csvOccurrenceIdentityRequired =
|
|
8669
|
+
csvSource &&
|
|
8670
|
+
this.currentRuntimeSemantics.datasets.csvRowIdentity === 'source_row';
|
|
8671
|
+
rowIdentityMode = csvOccurrenceIdentityRequired
|
|
8672
|
+
? 'source_row'
|
|
8673
|
+
: (options?.rowIdentity ??
|
|
8674
|
+
(options?.key !== undefined
|
|
8675
|
+
? 'key'
|
|
8676
|
+
: csvSource
|
|
8677
|
+
? this.currentRuntimeSemantics.datasets.csvRowIdentity
|
|
8678
|
+
: 'key'));
|
|
8679
|
+
useSourceRowIdentity = rowIdentityMode === 'source_row';
|
|
8680
|
+
if (useSourceRowIdentity) {
|
|
8681
|
+
return (row, index) => {
|
|
8682
|
+
const source = getPlayDatasetSourceRowIdentity(row);
|
|
8683
|
+
const inputRow = Object.fromEntries(
|
|
8684
|
+
Object.entries(toSerializableCsvAliasedRow(row)).filter(
|
|
8685
|
+
([field]) => !field.startsWith('__deepline'),
|
|
8686
|
+
),
|
|
8557
8687
|
);
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8688
|
+
// Position distinguishes equal records; the input digest prevents a
|
|
8689
|
+
// changed file at the same path from replaying an earlier row's output.
|
|
8690
|
+
return JSON.stringify([
|
|
8691
|
+
'source-row-v1',
|
|
8692
|
+
source?.datasetId ??
|
|
8693
|
+
(isPlayDataset(items) ? items.datasetId : normalizedMapNamespace),
|
|
8694
|
+
source?.rowIndex ?? index,
|
|
8695
|
+
stableDigest(stableStringify(inputRow)),
|
|
8696
|
+
]);
|
|
8697
|
+
};
|
|
8698
|
+
} else if (userKeyOption !== undefined) {
|
|
8699
|
+
return (row, index) => {
|
|
8700
|
+
const inputRow = stripFieldOutputs(row);
|
|
8701
|
+
const raw =
|
|
8702
|
+
typeof userKeyOption === 'function'
|
|
8703
|
+
? (
|
|
8704
|
+
userKeyOption as (
|
|
8705
|
+
row: Record<string, unknown>,
|
|
8706
|
+
index: number,
|
|
8707
|
+
) => string | number | readonly unknown[]
|
|
8708
|
+
)(inputRow, index)
|
|
8709
|
+
: Array.isArray(userKeyOption)
|
|
8710
|
+
? userKeyOption.map((fieldName) => inputRow[fieldName])
|
|
8711
|
+
: inputRow[String(userKeyOption)];
|
|
8712
|
+
const parts = Array.isArray(raw) ? raw : [raw];
|
|
8713
|
+
if (parts.some((part) => part === null || part === undefined)) {
|
|
8714
|
+
throw new Error(
|
|
8715
|
+
`ctx.dataset("${normalizedMapNamespace}") key returned null or undefined for row ${index}. ` +
|
|
8716
|
+
'Return a non-empty string or number derived from a stable input column (e.g. row.email ?? row.domain).',
|
|
8717
|
+
);
|
|
8562
8718
|
}
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
)
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8719
|
+
const normalizedParts = parts.map((part) => {
|
|
8720
|
+
if (typeof part === 'number') {
|
|
8721
|
+
return Number.isFinite(part) ? String(part) : '';
|
|
8722
|
+
}
|
|
8723
|
+
return String(part).trim();
|
|
8724
|
+
});
|
|
8725
|
+
if (normalizedParts.some((part) => !part)) {
|
|
8726
|
+
throw new Error(
|
|
8727
|
+
`ctx.dataset("${normalizedMapNamespace}") key returned an empty value for row ${index}. ` +
|
|
8728
|
+
'Return a non-empty string or finite number derived from a stable input column.',
|
|
8729
|
+
);
|
|
8730
|
+
}
|
|
8731
|
+
return normalizedParts.length === 1
|
|
8732
|
+
? normalizedParts[0]!
|
|
8733
|
+
: JSON.stringify(normalizedParts);
|
|
8734
|
+
};
|
|
8735
|
+
}
|
|
8736
|
+
return null;
|
|
8737
|
+
};
|
|
8738
|
+
let explicitKeyResolver = setSourceIdentityMode(
|
|
8739
|
+
replayMapFrame?.arrayInput?.hasSourceIdentities ?? authoredCsvSource,
|
|
8740
|
+
);
|
|
8576
8741
|
|
|
8577
8742
|
const rowIdentity = (row: Record<string, unknown>, index = 0) => {
|
|
8578
8743
|
const runtimeKey = resolveMapRowOutcomeKey(row);
|
|
@@ -8612,17 +8777,115 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8612
8777
|
const mapMemoryLimits = resolveRuntimeMapMemoryLimits(
|
|
8613
8778
|
this.#options.runtimeMapMemoryLimits,
|
|
8614
8779
|
);
|
|
8780
|
+
// A derived key is "namespace:<64 hex chars>". Admission may rebind the
|
|
8781
|
+
// namespace after staging, so reserve its validated maximum up front.
|
|
8782
|
+
// normalizeTableNamespace emits ASCII and caps it at this many bytes.
|
|
8783
|
+
const implicitKeyReservationBytesPerRow =
|
|
8784
|
+
96 + MAP_KEY_NAMESPACE_MAX_LENGTH + 1 + 64;
|
|
8785
|
+
// Staged explicit-key dedupe retains a SHA-256 token, never an unbounded
|
|
8786
|
+
// authored key string. The same digest primitive already names row keys.
|
|
8787
|
+
const explicitKeyReservationBytesPerRow = 96 + 64;
|
|
8615
8788
|
const materializationMemoryTracker = createRuntimeMapMaterializationTracker(
|
|
8616
8789
|
{
|
|
8617
8790
|
mapName: normalizedMapNamespace,
|
|
8618
8791
|
budgetBytes: mapMemoryLimits.materializedBudgetBytes,
|
|
8619
8792
|
},
|
|
8620
8793
|
);
|
|
8621
|
-
|
|
8622
|
-
|
|
8794
|
+
// Keep transport response validation at its real boundary. The maps below
|
|
8795
|
+
// are local admission state, never a synthetic aggregate wire response.
|
|
8796
|
+
const admitMapRows = async (
|
|
8797
|
+
rows: Record<string, unknown>[],
|
|
8798
|
+
tableNamespace: string,
|
|
8799
|
+
mapContext: Parameters<NonNullable<ContextOptions['onMapStart']>>[2],
|
|
8800
|
+
admissionBudgetBytes = mapMemoryLimits.materializedBudgetBytes,
|
|
8801
|
+
) => {
|
|
8802
|
+
// Only transport paging creates cumulative response retention. Preserve
|
|
8803
|
+
// the legacy single callback's existing checks. Streamed sources pass
|
|
8804
|
+
// their reserved page budget; materialized admission uses the global one.
|
|
8805
|
+
const retainedAdmissionMemory = this.#options.onMapStartPages
|
|
8806
|
+
? createRuntimeMapMaterializationTracker({
|
|
8807
|
+
mapName: normalizedMapNamespace,
|
|
8808
|
+
budgetBytes: admissionBudgetBytes,
|
|
8809
|
+
})
|
|
8810
|
+
: undefined;
|
|
8811
|
+
const pages = this.#options.onMapStartPages
|
|
8812
|
+
? this.#options.onMapStartPages(rows, tableNamespace, mapContext)
|
|
8813
|
+
: (async function* (start: NonNullable<ContextOptions['onMapStart']>) {
|
|
8814
|
+
yield await start(rows, tableNamespace, mapContext);
|
|
8815
|
+
})(this.#options.onMapStart!);
|
|
8816
|
+
const pendingRowsByKey = new Map<string, Record<string, unknown>>();
|
|
8817
|
+
const completedRowsByKey = new Map<string, Record<string, unknown>>();
|
|
8818
|
+
const previousCellsByKey:
|
|
8819
|
+
| ReturnType<typeof assertDatasetAdmissionHistory>
|
|
8820
|
+
| undefined =
|
|
8821
|
+
this.currentRuntimeContract.datasetRowInput === 'current_run'
|
|
8822
|
+
? new Map()
|
|
8823
|
+
: undefined;
|
|
8824
|
+
let resolvedNamespace: string | undefined;
|
|
8825
|
+
for await (const result of pages) {
|
|
8826
|
+
const pageNamespace = normalizeTableNamespace(result.tableNamespace);
|
|
8827
|
+
if (resolvedNamespace && resolvedNamespace !== pageNamespace) {
|
|
8828
|
+
throw new Error('Dataset admission pages changed table namespace.');
|
|
8829
|
+
}
|
|
8830
|
+
resolvedNamespace = pageNamespace;
|
|
8831
|
+
// Legacy callbacks may resolve an alias and return unstamped rows.
|
|
8832
|
+
// Derive their fallback keys in that resolved namespace, as before.
|
|
8833
|
+
resolvedTableNamespace = pageNamespace;
|
|
8834
|
+
const history = previousCellsByKey
|
|
8835
|
+
? assertDatasetAdmissionHistory(
|
|
8836
|
+
result,
|
|
8837
|
+
Math.floor(
|
|
8838
|
+
admissionBudgetBytes /
|
|
8839
|
+
NODE_RUNTIME_MAP_MATERIALIZED_MEMORY_MULTIPLIER,
|
|
8840
|
+
),
|
|
8841
|
+
)
|
|
8842
|
+
: undefined;
|
|
8843
|
+
for (const [key, cells] of history ?? []) {
|
|
8844
|
+
if (!previousCellsByKey!.has(key)) {
|
|
8845
|
+
retainedAdmissionMemory?.track({ previousCells: cells });
|
|
8846
|
+
previousCellsByKey!.set(key, cells);
|
|
8847
|
+
}
|
|
8848
|
+
}
|
|
8849
|
+
for (const [index, row] of result.pendingRows.entries()) {
|
|
8850
|
+
const key =
|
|
8851
|
+
resolveMapRowOutcomeKey(row) ??
|
|
8852
|
+
rowIdentity(row, (mapContext.inputOffset ?? 0) + index);
|
|
8853
|
+
if (
|
|
8854
|
+
key &&
|
|
8855
|
+
(!pendingRowsByKey.has(key) || !this.#options.onMapStartPages)
|
|
8856
|
+
) {
|
|
8857
|
+
retainedAdmissionMemory?.track(row);
|
|
8858
|
+
pendingRowsByKey.set(key, row);
|
|
8859
|
+
}
|
|
8860
|
+
}
|
|
8861
|
+
for (const row of result.completedRows ?? []) {
|
|
8862
|
+
const key = resolveMapRowOutcomeKey(row) ?? rowIdentity(row, 0);
|
|
8863
|
+
if (
|
|
8864
|
+
key &&
|
|
8865
|
+
(!completedRowsByKey.has(key) || !this.#options.onMapStartPages)
|
|
8866
|
+
) {
|
|
8867
|
+
retainedAdmissionMemory?.track(row);
|
|
8868
|
+
completedRowsByKey.set(key, row);
|
|
8869
|
+
}
|
|
8870
|
+
}
|
|
8871
|
+
}
|
|
8872
|
+
if (!resolvedNamespace) {
|
|
8873
|
+
throw new Error('Dataset admission did not return a response page.');
|
|
8874
|
+
}
|
|
8875
|
+
return {
|
|
8876
|
+
tableNamespace: resolvedNamespace,
|
|
8877
|
+
pendingRowsByKey,
|
|
8878
|
+
completedRowsByKey,
|
|
8879
|
+
previousCellsByKey,
|
|
8880
|
+
};
|
|
8881
|
+
};
|
|
8882
|
+
// A pre-paging array checkpoint owns its pending authored inputs. Finish
|
|
8883
|
+
// that invocation on its original replay path even if the authored array
|
|
8884
|
+
// changed while the run was parked.
|
|
8885
|
+
const hasRuntimeSheetControls =
|
|
8623
8886
|
this.#options.runtimeSheetBackedMapDatasets === true &&
|
|
8624
8887
|
Boolean(
|
|
8625
|
-
this.#options.onMapStart &&
|
|
8888
|
+
(this.#options.onMapStart || this.#options.onMapStartPages) &&
|
|
8626
8889
|
this.#options.onMapRowsCompleted &&
|
|
8627
8890
|
this.#options.baseUrl &&
|
|
8628
8891
|
this.#options.executorToken &&
|
|
@@ -8633,8 +8896,6 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8633
8896
|
// rebuilt in authored call order. Look up a previously suspended plan now,
|
|
8634
8897
|
// before a stateful source query can decide that a sibling action is no
|
|
8635
8898
|
// longer eligible because an earlier action already completed.
|
|
8636
|
-
const replayMapInvocationId = `${normalizedMapNamespace}:${this.mapInvocationIndex}`;
|
|
8637
|
-
const replayMapFrame = this.checkpoint.mapFrames?.[replayMapInvocationId];
|
|
8638
8899
|
const canReadPersistedMapResults = Boolean(
|
|
8639
8900
|
this.#options.onMapRowsCompleted &&
|
|
8640
8901
|
this.#options.dbSessionStrategy &&
|
|
@@ -8643,6 +8904,153 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8643
8904
|
this.#options.playName &&
|
|
8644
8905
|
this.#options.runId,
|
|
8645
8906
|
);
|
|
8907
|
+
const sourceArrayEstimate = Array.isArray(items)
|
|
8908
|
+
? estimateRuntimeMapRowsMemory(items)
|
|
8909
|
+
: null;
|
|
8910
|
+
let sealedArrayInput: Extract<
|
|
8911
|
+
RuntimeArrayInputManifest,
|
|
8912
|
+
{ state: 'sealed' }
|
|
8913
|
+
> | null = null;
|
|
8914
|
+
const arrayInputStore = this.#options.runtimeArrayInputStore;
|
|
8915
|
+
const arrayInputScope: RuntimeArrayInputScope = {
|
|
8916
|
+
playName: this.#options.playName ?? '',
|
|
8917
|
+
runId: this.#options.runId ?? '',
|
|
8918
|
+
tableNamespace: resolvedTableNamespace,
|
|
8919
|
+
mapInvocationId: replayMapInvocationId,
|
|
8920
|
+
};
|
|
8921
|
+
if (
|
|
8922
|
+
replayMapFrame?.arrayInput &&
|
|
8923
|
+
(!Array.isArray(items) ||
|
|
8924
|
+
!hasRuntimeSheetControls ||
|
|
8925
|
+
!canReadPersistedMapResults ||
|
|
8926
|
+
!arrayInputStore)
|
|
8927
|
+
) {
|
|
8928
|
+
throw new Error(
|
|
8929
|
+
`Dataset ${resolvedTableNamespace} cannot replay its sealed array input without the runtime sheet and array input reader.`,
|
|
8930
|
+
);
|
|
8931
|
+
}
|
|
8932
|
+
if (
|
|
8933
|
+
Array.isArray(items) &&
|
|
8934
|
+
!(replayMapFrame?.suspendedInputRows && !replayMapFrame.arrayInput) &&
|
|
8935
|
+
hasRuntimeSheetControls &&
|
|
8936
|
+
canReadPersistedMapResults &&
|
|
8937
|
+
arrayInputStore
|
|
8938
|
+
) {
|
|
8939
|
+
let manifest: RuntimeArrayInputManifest;
|
|
8940
|
+
let storeUnavailable = false;
|
|
8941
|
+
try {
|
|
8942
|
+
// A sealed source may predate the first checkpoint. Probe even if the
|
|
8943
|
+
// current authored array is small or empty, so that intent survives a
|
|
8944
|
+
// crash between sealing and the first map frame write.
|
|
8945
|
+
manifest = await arrayInputStore.getManifest(arrayInputScope);
|
|
8946
|
+
} catch (error) {
|
|
8947
|
+
if (!(error instanceof RuntimeArrayInputStoreUnavailableError))
|
|
8948
|
+
throw error;
|
|
8949
|
+
if (replayMapFrame?.arrayInput) {
|
|
8950
|
+
throw new Error(
|
|
8951
|
+
`Dataset ${resolvedTableNamespace} requires its sealed array input, but this receiver cannot read array input pages.`,
|
|
8952
|
+
{ cause: error },
|
|
8953
|
+
);
|
|
8954
|
+
}
|
|
8955
|
+
manifest = { state: 'absent' };
|
|
8956
|
+
storeUnavailable = true;
|
|
8957
|
+
}
|
|
8958
|
+
// The sealed snapshot is the source of truth after a crash, including an
|
|
8959
|
+
// explicit false. The regenerated authored array can be empty or carry
|
|
8960
|
+
// different sidecars, so choose keys only after reading this manifest.
|
|
8961
|
+
if (manifest.state === 'sealed') {
|
|
8962
|
+
explicitKeyResolver = setSourceIdentityMode(
|
|
8963
|
+
manifest.hasSourceIdentities,
|
|
8964
|
+
);
|
|
8965
|
+
}
|
|
8966
|
+
if (manifest.state === 'absent' && replayMapFrame?.arrayInput) {
|
|
8967
|
+
throw new Error(
|
|
8968
|
+
`Dataset ${resolvedTableNamespace} sealed array input is missing on replay.`,
|
|
8969
|
+
);
|
|
8970
|
+
}
|
|
8971
|
+
const stagingCandidate =
|
|
8972
|
+
!storeUnavailable &&
|
|
8973
|
+
(manifest.state !== 'absent' ||
|
|
8974
|
+
(this.#options.runtimeArrayInputStagingEnabled === true &&
|
|
8975
|
+
sourceArrayEstimate !== null &&
|
|
8976
|
+
sourceArrayEstimate.estimatedResidentBytes <=
|
|
8977
|
+
mapMemoryLimits.materializedBudgetBytes &&
|
|
8978
|
+
sourceArrayEstimate.estimatedResidentBytes * 2 >
|
|
8979
|
+
mapMemoryLimits.materializedBudgetBytes));
|
|
8980
|
+
const sourceCanStageLosslessly =
|
|
8981
|
+
manifest.state === 'sealed' ||
|
|
8982
|
+
!stagingCandidate ||
|
|
8983
|
+
items.every(
|
|
8984
|
+
(item, index) =>
|
|
8985
|
+
isLosslessArrayInputValue(item) &&
|
|
8986
|
+
isLosslessArrayInputValue(
|
|
8987
|
+
getPlayDatasetSourceRowIdentityAt(items, index) ?? null,
|
|
8988
|
+
),
|
|
8989
|
+
);
|
|
8990
|
+
if (manifest.state === 'staging' && !sourceCanStageLosslessly) {
|
|
8991
|
+
throw new Error(
|
|
8992
|
+
`Dataset ${resolvedTableNamespace} source changed before its array input was sealed. Retry with the original source.`,
|
|
8993
|
+
);
|
|
8994
|
+
}
|
|
8995
|
+
const needsStaging = stagingCandidate && sourceCanStageLosslessly;
|
|
8996
|
+
if (needsStaging) {
|
|
8997
|
+
const stageKeyReservationBytes = !useSourceRowIdentity
|
|
8998
|
+
? items.length *
|
|
8999
|
+
(explicitKeyResolver
|
|
9000
|
+
? explicitKeyReservationBytesPerRow
|
|
9001
|
+
: implicitKeyReservationBytesPerRow)
|
|
9002
|
+
: 0;
|
|
9003
|
+
const stageResidentBytes =
|
|
9004
|
+
(sourceArrayEstimate?.estimatedResidentBytes ?? 0) +
|
|
9005
|
+
stageKeyReservationBytes;
|
|
9006
|
+
if (
|
|
9007
|
+
manifest.state !== 'sealed' &&
|
|
9008
|
+
sourceArrayEstimate &&
|
|
9009
|
+
stageResidentBytes >= mapMemoryLimits.materializedBudgetBytes
|
|
9010
|
+
) {
|
|
9011
|
+
throw new RuntimeMapMemoryLimitError({
|
|
9012
|
+
mapName: normalizedMapNamespace,
|
|
9013
|
+
phase: 'materialize',
|
|
9014
|
+
estimate: {
|
|
9015
|
+
...sourceArrayEstimate,
|
|
9016
|
+
estimatedResidentBytes: stageResidentBytes,
|
|
9017
|
+
},
|
|
9018
|
+
budgetBytes: mapMemoryLimits.materializedBudgetBytes,
|
|
9019
|
+
});
|
|
9020
|
+
}
|
|
9021
|
+
try {
|
|
9022
|
+
sealedArrayInput = await sealRuntimeArrayInput({
|
|
9023
|
+
scope: arrayInputScope,
|
|
9024
|
+
rows: items,
|
|
9025
|
+
store: arrayInputStore,
|
|
9026
|
+
manifest,
|
|
9027
|
+
maxPageMemoryBytes:
|
|
9028
|
+
manifest.state === 'sealed'
|
|
9029
|
+
? undefined
|
|
9030
|
+
: Math.floor(
|
|
9031
|
+
(mapMemoryLimits.materializedBudgetBytes -
|
|
9032
|
+
stageResidentBytes) /
|
|
9033
|
+
4,
|
|
9034
|
+
),
|
|
9035
|
+
normalize: (item, index) => ({
|
|
9036
|
+
data: sanitizePostgresJsonValue(
|
|
9037
|
+
cloneCsvAliasedRow(this.toOutputRow(item)),
|
|
9038
|
+
) as Record<string, unknown>,
|
|
9039
|
+
sourceIdentity: getPlayDatasetSourceRowIdentityAt(items, index),
|
|
9040
|
+
}),
|
|
9041
|
+
});
|
|
9042
|
+
} catch (error) {
|
|
9043
|
+
if (
|
|
9044
|
+
!(error instanceof RuntimeArrayInputStoreUnavailableError) ||
|
|
9045
|
+
manifest.state !== 'absent'
|
|
9046
|
+
)
|
|
9047
|
+
throw error;
|
|
9048
|
+
}
|
|
9049
|
+
}
|
|
9050
|
+
}
|
|
9051
|
+
const shouldStreamRuntimeBackedDataset =
|
|
9052
|
+
(isPlayDataset<T>(items) || sealedArrayInput !== null) &&
|
|
9053
|
+
hasRuntimeSheetControls;
|
|
8646
9054
|
// A suspended map's admitted pending inputs remain authoritative even
|
|
8647
9055
|
// when a stateful authored source returns fewer rows after a wake.
|
|
8648
9056
|
const suspendedInputRows = shouldStreamRuntimeBackedDataset
|
|
@@ -8698,10 +9106,77 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8698
9106
|
const isVisibleTerminalRow = (row: PersistableMapRow): boolean =>
|
|
8699
9107
|
visibility.isVisible(row.key);
|
|
8700
9108
|
if (shouldStreamRuntimeBackedDataset) {
|
|
9109
|
+
// A caller keeps an array alive across this await. Reserve its complete
|
|
9110
|
+
// resident estimate before admitting any row, then divide the remaining
|
|
9111
|
+
// budget among the active page, sheet-admission copies, retained row
|
|
9112
|
+
// outcomes, and the optional immediate result cache. A cursor has no
|
|
9113
|
+
// resident source.
|
|
9114
|
+
const arraySourceMemoryEstimate = sealedArrayInput
|
|
9115
|
+
? sourceArrayEstimate
|
|
9116
|
+
: null;
|
|
9117
|
+
if (
|
|
9118
|
+
arraySourceMemoryEstimate &&
|
|
9119
|
+
arraySourceMemoryEstimate.estimatedResidentBytes >
|
|
9120
|
+
mapMemoryLimits.materializedBudgetBytes
|
|
9121
|
+
) {
|
|
9122
|
+
throw new RuntimeMapMemoryLimitError({
|
|
9123
|
+
mapName: normalizedMapNamespace,
|
|
9124
|
+
phase: 'materialize',
|
|
9125
|
+
estimate: arraySourceMemoryEstimate,
|
|
9126
|
+
budgetBytes: mapMemoryLimits.materializedBudgetBytes,
|
|
9127
|
+
});
|
|
9128
|
+
}
|
|
9129
|
+
// Both explicit and implicit first-wins keys survive page settlement.
|
|
9130
|
+
// Reserve their bounded index apart from transient page allocations.
|
|
9131
|
+
const keyIndexBudgetBytes =
|
|
9132
|
+
sealedArrayInput && !useSourceRowIdentity
|
|
9133
|
+
? sealedArrayInput.sourceRows *
|
|
9134
|
+
(explicitKeyResolver
|
|
9135
|
+
? explicitKeyReservationBytesPerRow
|
|
9136
|
+
: implicitKeyReservationBytesPerRow)
|
|
9137
|
+
: 0;
|
|
9138
|
+
if (
|
|
9139
|
+
arraySourceMemoryEstimate &&
|
|
9140
|
+
arraySourceMemoryEstimate.estimatedResidentBytes +
|
|
9141
|
+
keyIndexBudgetBytes >=
|
|
9142
|
+
mapMemoryLimits.materializedBudgetBytes
|
|
9143
|
+
) {
|
|
9144
|
+
throw new RuntimeMapMemoryLimitError({
|
|
9145
|
+
mapName: normalizedMapNamespace,
|
|
9146
|
+
phase: 'materialize',
|
|
9147
|
+
estimate: {
|
|
9148
|
+
...arraySourceMemoryEstimate,
|
|
9149
|
+
estimatedResidentBytes:
|
|
9150
|
+
arraySourceMemoryEstimate.estimatedResidentBytes +
|
|
9151
|
+
keyIndexBudgetBytes,
|
|
9152
|
+
},
|
|
9153
|
+
budgetBytes: mapMemoryLimits.materializedBudgetBytes,
|
|
9154
|
+
});
|
|
9155
|
+
}
|
|
9156
|
+
const pageBudgetBytes = arraySourceMemoryEstimate
|
|
9157
|
+
? Math.max(
|
|
9158
|
+
1,
|
|
9159
|
+
Math.floor(
|
|
9160
|
+
(mapMemoryLimits.materializedBudgetBytes -
|
|
9161
|
+
arraySourceMemoryEstimate.estimatedResidentBytes -
|
|
9162
|
+
keyIndexBudgetBytes) /
|
|
9163
|
+
4,
|
|
9164
|
+
),
|
|
9165
|
+
)
|
|
9166
|
+
: mapMemoryLimits.materializedBudgetBytes;
|
|
8701
9167
|
// Net-new admission happens one source page at a time. Its progress and
|
|
8702
9168
|
// returned dataset describe admitted rows, not every provider/CSV row
|
|
8703
9169
|
// supplied to this run, so accumulate the admitted count below.
|
|
8704
|
-
totalInputCount =
|
|
9170
|
+
totalInputCount =
|
|
9171
|
+
options?.mode === 'net_new'
|
|
9172
|
+
? 0
|
|
9173
|
+
: sealedArrayInput
|
|
9174
|
+
? sealedArrayInput.sourceRows
|
|
9175
|
+
: isPlayDataset(items)
|
|
9176
|
+
? await items.count()
|
|
9177
|
+
: (() => {
|
|
9178
|
+
throw new Error('Runtime-backed map source is missing.');
|
|
9179
|
+
})();
|
|
8705
9180
|
const mapScope = this.createMapExecutionScope({
|
|
8706
9181
|
logicalNamespace: normalizedMapNamespace,
|
|
8707
9182
|
artifactTableNamespace: resolvedTableNamespace,
|
|
@@ -8713,6 +9188,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8713
9188
|
logicalNamespace: mapScope.logicalNamespace,
|
|
8714
9189
|
artifactTableNamespace: mapScope.artifactTableNamespace,
|
|
8715
9190
|
status: 'running',
|
|
9191
|
+
arrayInput: sealedArrayInput
|
|
9192
|
+
? { hasSourceIdentities: sealedArrayInput.hasSourceIdentities }
|
|
9193
|
+
: undefined,
|
|
8716
9194
|
totalRows: totalInputCount,
|
|
8717
9195
|
completedRowKeys: [],
|
|
8718
9196
|
pendingRowKeys: [],
|
|
@@ -8735,6 +9213,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8735
9213
|
});
|
|
8736
9214
|
|
|
8737
9215
|
const seenExplicitKeys = new Set<string>();
|
|
9216
|
+
let seenExplicitKeyBytes = 0;
|
|
9217
|
+
const seenImplicitRowKeys = new Set<string>();
|
|
9218
|
+
let seenImplicitRowKeyBytes = 0;
|
|
8738
9219
|
let processedCount = 0;
|
|
8739
9220
|
let successfulCount = 0;
|
|
8740
9221
|
let failedCount = 0;
|
|
@@ -8825,13 +9306,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8825
9306
|
await flushChunk();
|
|
8826
9307
|
};
|
|
8827
9308
|
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
const
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
9309
|
+
// The fed pool retains every appended row in executionRows. A staged
|
|
9310
|
+
// array must release each page after settlement to honor its source
|
|
9311
|
+
// reservation, including when a resolver invokes provider tools.
|
|
9312
|
+
const pipelinePages =
|
|
9313
|
+
!sealedArrayInput &&
|
|
9314
|
+
!this.canUsePureJsMapFastPath(
|
|
9315
|
+
input as MapFieldDefinition<Record<string, unknown>>,
|
|
9316
|
+
);
|
|
8835
9317
|
type PreparedPage = {
|
|
8836
9318
|
rows: Record<string, unknown>[];
|
|
8837
9319
|
rowKeys: string[];
|
|
@@ -8877,7 +9359,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8877
9359
|
}),
|
|
8878
9360
|
};
|
|
8879
9361
|
});
|
|
8880
|
-
const
|
|
9362
|
+
const admission = await admitMapRows(
|
|
8881
9363
|
pageStartRows,
|
|
8882
9364
|
resolvedTableNamespace,
|
|
8883
9365
|
{
|
|
@@ -8891,7 +9373,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8891
9373
|
? {
|
|
8892
9374
|
includePreviousCells: true,
|
|
8893
9375
|
previousCellsBudgetBytes: Math.floor(
|
|
8894
|
-
|
|
9376
|
+
pageBudgetBytes /
|
|
8895
9377
|
NODE_RUNTIME_MAP_MATERIALIZED_MEMORY_MULTIPLIER,
|
|
8896
9378
|
),
|
|
8897
9379
|
}
|
|
@@ -8900,37 +9382,11 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8900
9382
|
mode: options?.mode,
|
|
8901
9383
|
columnTypes: unchangedColumnTypes,
|
|
8902
9384
|
},
|
|
9385
|
+
pageBudgetBytes,
|
|
8903
9386
|
);
|
|
8904
|
-
resolvedTableNamespace =
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
const previousCellsByKey =
|
|
8908
|
-
this.currentRuntimeContract.datasetRowInput === 'current_run'
|
|
8909
|
-
? assertDatasetAdmissionHistory(
|
|
8910
|
-
mapStartResult,
|
|
8911
|
-
Math.floor(
|
|
8912
|
-
mapMemoryLimits.materializedBudgetBytes /
|
|
8913
|
-
NODE_RUNTIME_MAP_MATERIALIZED_MEMORY_MULTIPLIER,
|
|
8914
|
-
),
|
|
8915
|
-
)
|
|
8916
|
-
: undefined;
|
|
8917
|
-
|
|
8918
|
-
const pendingRowsByKey = new Map<string, Record<string, unknown>>();
|
|
8919
|
-
for (
|
|
8920
|
-
let index = 0;
|
|
8921
|
-
index < mapStartResult.pendingRows.length;
|
|
8922
|
-
index += 1
|
|
8923
|
-
) {
|
|
8924
|
-
const row = mapStartResult.pendingRows[index]!;
|
|
8925
|
-
const rowKey = persistedRowIdentity(row, page.offset + index);
|
|
8926
|
-
if (rowKey) pendingRowsByKey.set(rowKey, row);
|
|
8927
|
-
}
|
|
8928
|
-
const completedRowsByKey = new Map<string, Record<string, unknown>>();
|
|
8929
|
-
for (const row of mapStartResult.completedRows ?? []) {
|
|
8930
|
-
const rowKey = persistedRowIdentity(row);
|
|
8931
|
-
if (!rowKey) continue;
|
|
8932
|
-
completedRowsByKey.set(rowKey, row);
|
|
8933
|
-
}
|
|
9387
|
+
resolvedTableNamespace = admission.tableNamespace;
|
|
9388
|
+
const { pendingRowsByKey, completedRowsByKey, previousCellsByKey } =
|
|
9389
|
+
admission;
|
|
8934
9390
|
|
|
8935
9391
|
const seededItems = pageRawItems.map((row, index) => {
|
|
8936
9392
|
const originalIndex = page.offset + index;
|
|
@@ -8964,14 +9420,64 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8964
9420
|
for (const { row, index } of admittedSeededItems) {
|
|
8965
9421
|
if (explicitKeyResolver && !useSourceRowIdentity) {
|
|
8966
9422
|
const explicitKey = explicitKeyResolver(row, index);
|
|
8967
|
-
|
|
9423
|
+
const dedupeToken = sealedArrayInput
|
|
9424
|
+
? sha256Hex(explicitKey)
|
|
9425
|
+
: explicitKey;
|
|
9426
|
+
if (seenExplicitKeys.has(dedupeToken)) {
|
|
8968
9427
|
duplicateReuseCount += 1;
|
|
8969
9428
|
processedCount += 1;
|
|
8970
9429
|
continue;
|
|
8971
9430
|
}
|
|
8972
|
-
|
|
9431
|
+
if (sealedArrayInput) {
|
|
9432
|
+
seenExplicitKeyBytes +=
|
|
9433
|
+
96 + Buffer.byteLength(dedupeToken, 'utf8');
|
|
9434
|
+
if (seenExplicitKeyBytes > keyIndexBudgetBytes) {
|
|
9435
|
+
throw new RuntimeMapMemoryLimitError({
|
|
9436
|
+
mapName: normalizedMapNamespace,
|
|
9437
|
+
phase: 'materialize',
|
|
9438
|
+
estimate: {
|
|
9439
|
+
...(arraySourceMemoryEstimate ??
|
|
9440
|
+
estimateRuntimeMapRowsMemory([])),
|
|
9441
|
+
estimatedResidentBytes:
|
|
9442
|
+
(arraySourceMemoryEstimate?.estimatedResidentBytes ?? 0) +
|
|
9443
|
+
seenExplicitKeyBytes +
|
|
9444
|
+
pageBudgetBytes * 4,
|
|
9445
|
+
},
|
|
9446
|
+
budgetBytes: mapMemoryLimits.materializedBudgetBytes,
|
|
9447
|
+
});
|
|
9448
|
+
}
|
|
9449
|
+
}
|
|
9450
|
+
seenExplicitKeys.add(dedupeToken);
|
|
8973
9451
|
}
|
|
8974
9452
|
const rowKey = rowIdentity(row, index);
|
|
9453
|
+
if (
|
|
9454
|
+
sealedArrayInput &&
|
|
9455
|
+
!explicitKeyResolver &&
|
|
9456
|
+
!useSourceRowIdentity
|
|
9457
|
+
) {
|
|
9458
|
+
if (seenImplicitRowKeys.has(rowKey)) {
|
|
9459
|
+
duplicateReuseCount += 1;
|
|
9460
|
+
processedCount += 1;
|
|
9461
|
+
continue;
|
|
9462
|
+
}
|
|
9463
|
+
seenImplicitRowKeyBytes += 96 + Buffer.byteLength(rowKey, 'utf8');
|
|
9464
|
+
if (seenImplicitRowKeyBytes > keyIndexBudgetBytes) {
|
|
9465
|
+
throw new RuntimeMapMemoryLimitError({
|
|
9466
|
+
mapName: normalizedMapNamespace,
|
|
9467
|
+
phase: 'materialize',
|
|
9468
|
+
estimate: {
|
|
9469
|
+
...(arraySourceMemoryEstimate ??
|
|
9470
|
+
estimateRuntimeMapRowsMemory([])),
|
|
9471
|
+
estimatedResidentBytes:
|
|
9472
|
+
(arraySourceMemoryEstimate?.estimatedResidentBytes ?? 0) +
|
|
9473
|
+
seenImplicitRowKeyBytes +
|
|
9474
|
+
pageBudgetBytes * 4,
|
|
9475
|
+
},
|
|
9476
|
+
budgetBytes: mapMemoryLimits.materializedBudgetBytes,
|
|
9477
|
+
});
|
|
9478
|
+
}
|
|
9479
|
+
seenImplicitRowKeys.add(rowKey);
|
|
9480
|
+
}
|
|
8975
9481
|
if (!rowsToExecuteByKey.has(rowKey)) {
|
|
8976
9482
|
rowsToExecuteByKey.set(rowKey, { row, originalIndex: index });
|
|
8977
9483
|
} else {
|
|
@@ -9054,6 +9560,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9054
9560
|
logicalNamespace: mapScope.logicalNamespace,
|
|
9055
9561
|
artifactTableNamespace: resolvedTableNamespace,
|
|
9056
9562
|
status: 'running',
|
|
9563
|
+
arrayInput: sealedArrayInput
|
|
9564
|
+
? { hasSourceIdentities: sealedArrayInput.hasSourceIdentities }
|
|
9565
|
+
: undefined,
|
|
9057
9566
|
totalRows: totalInputCount,
|
|
9058
9567
|
completedRowKeys: [],
|
|
9059
9568
|
pendingRowKeys: execution.rowFeed ? [] : [...execution.rowKeys],
|
|
@@ -9094,8 +9603,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9094
9603
|
progressSkippedOffset: () => duplicateReuseCount,
|
|
9095
9604
|
progressTotalRows: () => totalInputCount,
|
|
9096
9605
|
rowFeed: execution.rowFeed,
|
|
9097
|
-
retainedRowsMemoryBudgetBytes:
|
|
9098
|
-
mapMemoryLimits.materializedBudgetBytes,
|
|
9606
|
+
retainedRowsMemoryBudgetBytes: pageBudgetBytes,
|
|
9099
9607
|
incrementalPersistence,
|
|
9100
9608
|
releasePersistedRowsOnMemoryPressure: true,
|
|
9101
9609
|
},
|
|
@@ -9181,9 +9689,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9181
9689
|
(observedResidentBytes / observedRowCount) *
|
|
9182
9690
|
Math.max(observedRowCount, totalInputCount - failedCount),
|
|
9183
9691
|
);
|
|
9184
|
-
if (
|
|
9185
|
-
projectedResidentBytes > mapMemoryLimits.materializedBudgetBytes
|
|
9186
|
-
) {
|
|
9692
|
+
if (projectedResidentBytes > pageBudgetBytes) {
|
|
9187
9693
|
// All-or-nothing cache: retaining a prefix that cannot fit once
|
|
9188
9694
|
// the known input finishes gives authored code no complete fast
|
|
9189
9695
|
// path. More importantly, that prefix would overlap the next
|
|
@@ -9192,7 +9698,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9192
9698
|
// rows observed so far and move to the already-durable sheet
|
|
9193
9699
|
// early instead of waiting for resident memory to reach a cliff.
|
|
9194
9700
|
disableImmediateMaterializedCache(
|
|
9195
|
-
`projected ${projectedResidentBytes} bytes exceeds ${
|
|
9701
|
+
`projected ${projectedResidentBytes} bytes exceeds ${pageBudgetBytes}-byte result cache budget`,
|
|
9196
9702
|
);
|
|
9197
9703
|
} else {
|
|
9198
9704
|
immediateMaterializedRows.push(materializedRow);
|
|
@@ -9216,13 +9722,83 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9216
9722
|
processedCount += execution.rows.length;
|
|
9217
9723
|
};
|
|
9218
9724
|
|
|
9219
|
-
const sourcePages = iteratePlayDatasetInputPages(
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9725
|
+
const sourcePages = iteratePlayDatasetInputPages<T>(
|
|
9726
|
+
sealedArrayInput
|
|
9727
|
+
? (iterateSealedRuntimeArrayInput(
|
|
9728
|
+
arrayInputStore!,
|
|
9729
|
+
arrayInputScope,
|
|
9730
|
+
sealedArrayInput,
|
|
9731
|
+
) as AsyncIterable<T>)
|
|
9732
|
+
: items,
|
|
9733
|
+
{
|
|
9734
|
+
maxPageBytes: pageBudgetBytes,
|
|
9735
|
+
estimateRowBytes: (item, index, sourceIdentity) => {
|
|
9736
|
+
// The legacy single callback's final guard prices raw rows. Keep
|
|
9737
|
+
// its existing cuts; only current-run seeding or paged retention
|
|
9738
|
+
// introduces the execution/admission shapes accounted below.
|
|
9739
|
+
if (
|
|
9740
|
+
this.currentRuntimeContract.datasetRowInput !== 'current_run' &&
|
|
9741
|
+
!this.#options.onMapStartPages
|
|
9742
|
+
) {
|
|
9743
|
+
return (
|
|
9744
|
+
runtimeMapJsonByteLength(item) *
|
|
9745
|
+
NODE_RUNTIME_MAP_MATERIALIZED_MEMORY_MULTIPLIER +
|
|
9746
|
+
NODE_RUNTIME_MAP_ROW_OVERHEAD_BYTES
|
|
9747
|
+
);
|
|
9748
|
+
}
|
|
9749
|
+
const row = this.toOutputRow(item as Record<string, unknown>);
|
|
9750
|
+
if (sourceIdentity) {
|
|
9751
|
+
setPlayDatasetSourceRowIdentity(row, sourceIdentity);
|
|
9752
|
+
}
|
|
9753
|
+
// Estimate the execution shape before any admission side effect.
|
|
9754
|
+
// Reserve a derived key's maximum namespace without invoking an
|
|
9755
|
+
// authored key resolver a second time. History never changes page
|
|
9756
|
+
// cuts; its returned values must fit this same fixed page budget.
|
|
9757
|
+
const stamped = {
|
|
9758
|
+
...toSerializableCsvAliasedRow(row),
|
|
9759
|
+
...(sourceIdentity
|
|
9760
|
+
? { __deeplineSourceRow: sourceIdentity }
|
|
9761
|
+
: {}),
|
|
9762
|
+
...mapRowOutcomeRuntimeFields({
|
|
9763
|
+
key:
|
|
9764
|
+
resolveMapRowOutcomeKey(row) ??
|
|
9765
|
+
'x'.repeat(MAP_KEY_NAMESPACE_MAX_LENGTH + 1 + 64),
|
|
9766
|
+
inputIndex: index,
|
|
9767
|
+
}),
|
|
9768
|
+
};
|
|
9769
|
+
const seeded = this.datasetRowInputs.seed(
|
|
9770
|
+
row,
|
|
9771
|
+
stamped,
|
|
9772
|
+
this.currentRuntimeContract.datasetRowInput,
|
|
9773
|
+
);
|
|
9774
|
+
const executionEstimate = estimateRuntimeMapRowsMemory([
|
|
9775
|
+
this.datasetRowInputs.memoryValue(seeded),
|
|
9776
|
+
]);
|
|
9777
|
+
// Paged admission retains the stamped row and an independent
|
|
9778
|
+
// history-map entry before seeding. Cover both existing trackers.
|
|
9779
|
+
const admissionEstimate = estimateRuntimeMapRowsMemory([
|
|
9780
|
+
stamped,
|
|
9781
|
+
...(this.currentRuntimeContract.datasetRowInput === 'current_run'
|
|
9782
|
+
? [{ previousCells: {} }]
|
|
9783
|
+
: []),
|
|
9784
|
+
]);
|
|
9785
|
+
const estimate =
|
|
9786
|
+
executionEstimate.estimatedResidentBytes >
|
|
9787
|
+
admissionEstimate.estimatedResidentBytes
|
|
9788
|
+
? executionEstimate
|
|
9789
|
+
: admissionEstimate;
|
|
9790
|
+
if (estimate.estimatedResidentBytes > pageBudgetBytes) {
|
|
9791
|
+
throw new RuntimeMapMemoryLimitError({
|
|
9792
|
+
mapName: normalizedMapNamespace,
|
|
9793
|
+
phase: 'materialize',
|
|
9794
|
+
estimate,
|
|
9795
|
+
budgetBytes: pageBudgetBytes,
|
|
9796
|
+
});
|
|
9797
|
+
}
|
|
9798
|
+
return estimate.estimatedResidentBytes;
|
|
9799
|
+
},
|
|
9800
|
+
},
|
|
9801
|
+
);
|
|
9226
9802
|
|
|
9227
9803
|
if (pipelinePages) {
|
|
9228
9804
|
// One worker pool for the whole source. Once page N's last row has
|
|
@@ -9327,6 +9903,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9327
9903
|
logicalNamespace: mapScope.logicalNamespace,
|
|
9328
9904
|
artifactTableNamespace: resolvedTableNamespace,
|
|
9329
9905
|
status: 'failed',
|
|
9906
|
+
arrayInput: sealedArrayInput
|
|
9907
|
+
? { hasSourceIdentities: sealedArrayInput.hasSourceIdentities }
|
|
9908
|
+
: undefined,
|
|
9330
9909
|
totalRows: totalInputCount,
|
|
9331
9910
|
completedRowKeys: [],
|
|
9332
9911
|
pendingRowKeys: [],
|
|
@@ -9370,6 +9949,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9370
9949
|
logicalNamespace: mapScope.logicalNamespace,
|
|
9371
9950
|
artifactTableNamespace: resolvedTableNamespace,
|
|
9372
9951
|
status: 'completed',
|
|
9952
|
+
arrayInput: sealedArrayInput
|
|
9953
|
+
? { hasSourceIdentities: sealedArrayInput.hasSourceIdentities }
|
|
9954
|
+
: undefined,
|
|
9373
9955
|
totalRows: totalInputCount,
|
|
9374
9956
|
completedRowKeys: [],
|
|
9375
9957
|
pendingRowKeys: [],
|
|
@@ -9620,12 +10202,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9620
10202
|
// counts, sheet writes, resumable keys) consistent — the resolver derives
|
|
9621
10203
|
// keys from row content, so dropped rows are excluded everywhere with no
|
|
9622
10204
|
// index mismatch. Replaces the prior throw-on-duplicate behavior.
|
|
10205
|
+
const materializedKeyResolver = explicitKeyResolver;
|
|
9623
10206
|
const dedupedMaterialized =
|
|
9624
|
-
|
|
10207
|
+
materializedKeyResolver && !useSourceRowIdentity
|
|
9625
10208
|
? dedupeExplicitMapKeyRows({
|
|
9626
10209
|
rows: rawMaterializedItems,
|
|
9627
10210
|
resolver: (item, index) =>
|
|
9628
|
-
|
|
10211
|
+
materializedKeyResolver(
|
|
9629
10212
|
this.toOutputRow(item as Record<string, unknown>),
|
|
9630
10213
|
originalInputIndexByItem.get(item) ?? index,
|
|
9631
10214
|
),
|
|
@@ -9796,7 +10379,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9796
10379
|
(item, index) => originalInputIndexByItem.get(item) ?? index,
|
|
9797
10380
|
);
|
|
9798
10381
|
const mapStartSeedRowsByKey = new Map<string, Record<string, unknown>>();
|
|
9799
|
-
if (this.#options.onMapStart) {
|
|
10382
|
+
if (this.#options.onMapStart || this.#options.onMapStartPages) {
|
|
9800
10383
|
// ALWAYS stamp the canonical seed row key — including no-explicit-key
|
|
9801
10384
|
// datasets — using seedRowIdentity (full-input-row hash, matching the
|
|
9802
10385
|
// server's own derivation). Without the stamp, seed and completion keys
|
|
@@ -9832,7 +10415,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9832
10415
|
}),
|
|
9833
10416
|
};
|
|
9834
10417
|
});
|
|
9835
|
-
const
|
|
10418
|
+
const admission = await admitMapRows(
|
|
9836
10419
|
mapStartRows,
|
|
9837
10420
|
resolvedTableNamespace,
|
|
9838
10421
|
{
|
|
@@ -9855,35 +10438,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9855
10438
|
columnTypes: unchangedColumnTypes,
|
|
9856
10439
|
},
|
|
9857
10440
|
);
|
|
9858
|
-
resolvedTableNamespace =
|
|
9859
|
-
|
|
9860
|
-
)
|
|
9861
|
-
|
|
9862
|
-
this.currentRuntimeContract.datasetRowInput === 'current_run'
|
|
9863
|
-
? assertDatasetAdmissionHistory(
|
|
9864
|
-
mapStartResult,
|
|
9865
|
-
Math.floor(
|
|
9866
|
-
mapMemoryLimits.materializedBudgetBytes /
|
|
9867
|
-
NODE_RUNTIME_MAP_MATERIALIZED_MEMORY_MULTIPLIER,
|
|
9868
|
-
),
|
|
9869
|
-
)
|
|
9870
|
-
: undefined;
|
|
9871
|
-
const persistedRowIdentity = (row: Record<string, unknown>, index = 0) =>
|
|
9872
|
-
resolveMapRowOutcomeKey(row) ?? rowIdentity(row, index);
|
|
9873
|
-
const pendingRowsByKey = new Map<string, Record<string, unknown>>();
|
|
9874
|
-
for (
|
|
9875
|
-
let index = 0;
|
|
9876
|
-
index < mapStartResult.pendingRows.length;
|
|
9877
|
-
index += 1
|
|
9878
|
-
) {
|
|
9879
|
-
const row = mapStartResult.pendingRows[index]!;
|
|
9880
|
-
const rowKey = persistedRowIdentity(row, index);
|
|
9881
|
-
if (rowKey) pendingRowsByKey.set(rowKey, row);
|
|
9882
|
-
}
|
|
9883
|
-
for (const row of mapStartResult.completedRows ?? []) {
|
|
9884
|
-
const rowKey = persistedRowIdentity(row);
|
|
9885
|
-
if (!rowKey) continue;
|
|
9886
|
-
mapStartSeedRowsByKey.set(rowKey, row);
|
|
10441
|
+
resolvedTableNamespace = admission.tableNamespace;
|
|
10442
|
+
const { pendingRowsByKey, previousCellsByKey } = admission;
|
|
10443
|
+
for (const [key, row] of admission.completedRowsByKey) {
|
|
10444
|
+
mapStartSeedRowsByKey.set(key, row);
|
|
9887
10445
|
}
|
|
9888
10446
|
const seededItems = materializedItems
|
|
9889
10447
|
.map((item, index) => ({
|
|
@@ -10815,6 +11373,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
10815
11373
|
: Math.min(items.length, requestedRowConcurrency);
|
|
10816
11374
|
const heapAdmission = createRuntimeMapHeapAdmission({
|
|
10817
11375
|
maxConcurrency: rowConcurrencyLimit,
|
|
11376
|
+
// The resolver above already rejects invalid supplied run maxima.
|
|
11377
|
+
// Share its authored-width predicate so invalid internal widths cannot
|
|
11378
|
+
// turn an automatic map into a requested missing-probe bypass.
|
|
11379
|
+
concurrencySource:
|
|
11380
|
+
hasExplicitRowConcurrency(this.#options.maxConcurrentRows) ||
|
|
11381
|
+
hasExplicitRowConcurrency(runtimeOptions?.concurrency)
|
|
11382
|
+
? 'requested'
|
|
11383
|
+
: 'automatic',
|
|
10818
11384
|
memoryLedger: this.memoryLedger,
|
|
10819
11385
|
...(this.#options.runtimeMapHeapProbe
|
|
10820
11386
|
? { heapProbe: this.#options.runtimeMapHeapProbe }
|
|
@@ -10833,7 +11399,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
10833
11399
|
// composes the existing capacity boundaries and returns them in reverse at
|
|
10834
11400
|
// the row's durable/in-memory handoff below.
|
|
10835
11401
|
const mapRowFlow = createRuntimeFlow<{
|
|
10836
|
-
|
|
11402
|
+
inputRow: T | Record<string, unknown>;
|
|
10837
11403
|
}>({
|
|
10838
11404
|
stages: [
|
|
10839
11405
|
{
|
|
@@ -10842,10 +11408,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
10842
11408
|
},
|
|
10843
11409
|
{
|
|
10844
11410
|
name: 'run-row',
|
|
10845
|
-
acquire: async ({
|
|
11411
|
+
acquire: async ({ inputRow }) =>
|
|
10846
11412
|
await this.resourceGovernor.acquireRow({
|
|
11413
|
+
// The source is already resident in the collected baseline or
|
|
11414
|
+
// accounted source page. Preserve this measurement as telemetry;
|
|
11415
|
+
// reserving it again would double-charge its existing bytes.
|
|
10847
11416
|
estimatedBytes: runtimeMapJsonByteLength(
|
|
10848
|
-
this.datasetRowInputs.memoryValue(
|
|
11417
|
+
this.datasetRowInputs.memoryValue(this.toOutputRow(inputRow)),
|
|
10849
11418
|
),
|
|
10850
11419
|
}),
|
|
10851
11420
|
},
|
|
@@ -11439,48 +12008,60 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
11439
12008
|
const waitingRow = providerRetry
|
|
11440
12009
|
? waitingBaseRows.get(idx)
|
|
11441
12010
|
: undefined;
|
|
11442
|
-
|
|
11443
|
-
? waitingRow?.baseRow
|
|
11444
|
-
: this.toOutputRow(items[idx]);
|
|
11445
|
-
if (!baseRow) {
|
|
12011
|
+
if (providerRetry && !waitingRow?.baseRow) {
|
|
11446
12012
|
throw new Error(
|
|
11447
12013
|
`Provider retry row ${idx} lost its resumable input.`,
|
|
11448
12014
|
);
|
|
11449
12015
|
}
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
this.datasetRowInputs.retain(baseRow, this.memoryLedger);
|
|
11454
|
-
}
|
|
11455
|
-
if (providerRetry) waitingBaseRows.delete(idx);
|
|
11456
|
-
else releaseDispatchedInputRow?.(idx);
|
|
11457
|
-
const callIndexes =
|
|
11458
|
-
waitingRow?.callIndexes ?? new RowReplayCallIndexes();
|
|
11459
|
-
callIndexes.resetAttempt();
|
|
11460
|
-
const retryAfterRelease = {
|
|
11461
|
-
pending: null as ProviderRowRetry | null,
|
|
11462
|
-
callIndexes,
|
|
11463
|
-
};
|
|
11464
|
-
settledResults[idx] = await mapRowFlow.run({ baseRow }, async () => {
|
|
12016
|
+
const inputRow = waitingRow?.baseRow ?? items[idx];
|
|
12017
|
+
const rowAttempt: { retry?: ProviderRowRetry } = {};
|
|
12018
|
+
settledResults[idx] = await mapRowFlow.run({ inputRow }, async () => {
|
|
11465
12019
|
this.assertRowAdmissionOpen();
|
|
12020
|
+
// Heap and run-row admission precede retaining per-row history or
|
|
12021
|
+
// replay state. Workers waiting for capacity retain only their
|
|
12022
|
+
// index and the already-resident input reference.
|
|
12023
|
+
const baseRow = providerRetry
|
|
12024
|
+
? waitingRow?.baseRow
|
|
12025
|
+
: this.toOutputRow(inputRow);
|
|
12026
|
+
if (!baseRow) {
|
|
12027
|
+
throw new Error(
|
|
12028
|
+
`Provider retry row ${idx} lost its resumable input.`,
|
|
12029
|
+
);
|
|
12030
|
+
}
|
|
12031
|
+
historyRow = baseRow;
|
|
12032
|
+
if (this.currentRuntimeContract.datasetRowInput === 'current_run') {
|
|
12033
|
+
activeRowHistories.set(idx, baseRow);
|
|
12034
|
+
this.datasetRowInputs.retain(baseRow, this.memoryLedger);
|
|
12035
|
+
}
|
|
12036
|
+
if (providerRetry) waitingBaseRows.delete(idx);
|
|
12037
|
+
else releaseDispatchedInputRow?.(idx);
|
|
12038
|
+
const callIndexes =
|
|
12039
|
+
waitingRow?.callIndexes ?? new RowReplayCallIndexes();
|
|
12040
|
+
callIndexes.resetAttempt();
|
|
12041
|
+
const retryAfterRelease = {
|
|
12042
|
+
pending: null as ProviderRowRetry | null,
|
|
12043
|
+
callIndexes,
|
|
12044
|
+
};
|
|
11466
12045
|
mapProgress.resolverStarted({ retry: Boolean(providerRetry) });
|
|
11467
12046
|
try {
|
|
11468
|
-
|
|
12047
|
+
const result = await runRow(idx, baseRow, retryAfterRelease);
|
|
12048
|
+
rowAttempt.retry = retryAfterRelease.pending ?? undefined;
|
|
12049
|
+
return result;
|
|
11469
12050
|
} finally {
|
|
11470
12051
|
mapProgress.resolverFinished();
|
|
11471
12052
|
}
|
|
11472
12053
|
});
|
|
11473
12054
|
// Publish only after both flow leases have returned. Another worker
|
|
11474
12055
|
// must never re-admit this index while the old attempt is unwinding.
|
|
11475
|
-
if (
|
|
11476
|
-
if (
|
|
11477
|
-
parkedProviderRows.add(
|
|
12056
|
+
if (rowAttempt.retry) {
|
|
12057
|
+
if (rowAttempt.retry.residentWaitBudgetExhausted) {
|
|
12058
|
+
parkedProviderRows.add(rowAttempt.retry);
|
|
11478
12059
|
} else {
|
|
11479
|
-
providerRowRetries.add(
|
|
12060
|
+
providerRowRetries.add(rowAttempt.retry);
|
|
11480
12061
|
}
|
|
11481
12062
|
rowFeed?.wakeWorkersAt(nextProviderRetry(true)!.readyAtMs);
|
|
11482
12063
|
} else if (settledResults[idx] !== WAITING_ROW) {
|
|
11483
|
-
this.datasetRowInputs.release(
|
|
12064
|
+
if (historyRow) this.datasetRowInputs.release(historyRow);
|
|
11484
12065
|
providerIdleWaitStartedAt = null;
|
|
11485
12066
|
}
|
|
11486
12067
|
if (mapProgress.activeResolvers === 0) retryWakeFeed.wakeWorkers();
|
|
@@ -11501,6 +12082,12 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
11501
12082
|
}
|
|
11502
12083
|
});
|
|
11503
12084
|
|
|
12085
|
+
const unregisterExternalPressure =
|
|
12086
|
+
this.currentExecutionGovernor.registerExternalExecutionPressure?.({
|
|
12087
|
+
read: () => heapAdmission.readExternalExecutionPressure(),
|
|
12088
|
+
subscribe: (changed) =>
|
|
12089
|
+
heapAdmission.subscribeExternalExecutionPressure(changed),
|
|
12090
|
+
}) ?? (() => {});
|
|
11504
12091
|
let settled: PromiseSettledResult<void>[];
|
|
11505
12092
|
try {
|
|
11506
12093
|
// Drain queued work but exit early if a suspension error occurs.
|
|
@@ -11580,6 +12167,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
11580
12167
|
settled = await Promise.allSettled(workers);
|
|
11581
12168
|
}
|
|
11582
12169
|
} finally {
|
|
12170
|
+
unregisterExternalPressure();
|
|
11583
12171
|
clearInterval(mapActivityTimer);
|
|
11584
12172
|
retryWakeFeed.wakeWorkers();
|
|
11585
12173
|
publishMapActivity();
|
|
@@ -16242,7 +16830,23 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
16242
16830
|
|
|
16243
16831
|
/** Aggregate waits and residence from this logical run for terminal diagnostics. */
|
|
16244
16832
|
getRuntimeResourceSnapshot(): RuntimeResourceSnapshot {
|
|
16245
|
-
|
|
16833
|
+
const body = this.providerResponseBodyGate.snapshot();
|
|
16834
|
+
return {
|
|
16835
|
+
...this.resourceGovernor.snapshot(),
|
|
16836
|
+
memoryAdmission: {
|
|
16837
|
+
toolResponseBody: {
|
|
16838
|
+
turns: body.turns,
|
|
16839
|
+
measuredTurns: body.measuredTurns,
|
|
16840
|
+
decodedUtf8BytesTotal: body.bytesMeasured,
|
|
16841
|
+
decodedUtf8BytesMax: body.bytesMeasuredMax,
|
|
16842
|
+
permitBytesPeak: body.bytesHeldPeak,
|
|
16843
|
+
queuedTurns: body.queuedTurns,
|
|
16844
|
+
budgetRefusals: body.holds,
|
|
16845
|
+
progressAdmissions: body.progressAdmissions,
|
|
16846
|
+
unpricedAdmissions: body.unpricedAdmissions,
|
|
16847
|
+
},
|
|
16848
|
+
},
|
|
16849
|
+
};
|
|
16246
16850
|
}
|
|
16247
16851
|
|
|
16248
16852
|
/** Attempt-local counts without serializing the diagnostic resource map. */
|
|
@@ -16728,150 +17332,73 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
16728
17332
|
const { toolId, requests } = input;
|
|
16729
17333
|
if (requests.length === 0) return [];
|
|
16730
17334
|
|
|
17335
|
+
// Admit receipt and presentation identities once. Provider invocation
|
|
17336
|
+
// identity remains the execution Adapter's existing request contract.
|
|
17337
|
+
// Canonical cache force differs from authored request.force on replay.
|
|
17338
|
+
const members = requests.map((request) => ({
|
|
17339
|
+
memberId: request.callId,
|
|
17340
|
+
...this.mappedToolResultReceiptPolicy(request),
|
|
17341
|
+
cacheKey: request.cacheKey,
|
|
17342
|
+
receiptKey: request.receiptKey!,
|
|
17343
|
+
forceFailedRefresh: request.forceFailedRefresh === true,
|
|
17344
|
+
waitMaxAttempts: resolveRuntimeToolReceiptWaitMaxAttempts(
|
|
17345
|
+
typeof request.receiptWaitMs === 'number'
|
|
17346
|
+
? { max_wait_ms: request.receiptWaitMs }
|
|
17347
|
+
: request.input,
|
|
17348
|
+
),
|
|
17349
|
+
request,
|
|
17350
|
+
}));
|
|
16731
17351
|
const requestForReceipt = new Map<string, ToolCallRequest>();
|
|
16732
17352
|
const requestsForReceipt = new Map<string, ToolCallRequest[]>();
|
|
16733
17353
|
const requestByCallId = new Map<string, ToolCallRequest>();
|
|
16734
|
-
for (const
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
16738
|
-
|
|
16739
|
-
|
|
16740
|
-
|
|
16741
|
-
|
|
16742
|
-
|
|
16743
|
-
|
|
16744
|
-
const store = this.createRuntimeStepToolCallReceiptCohortStore({
|
|
16745
|
-
toolId,
|
|
16746
|
-
requestForReceipt,
|
|
16747
|
-
requestsForReceipt,
|
|
16748
|
-
});
|
|
16749
|
-
|
|
16750
|
-
const cohort = await createToolCallReceiptCohortJob({
|
|
16751
|
-
store,
|
|
16752
|
-
timings: this.toolCallReceiptCohortTimings(requestByCallId),
|
|
16753
|
-
}).acquire({
|
|
16754
|
-
owner: {
|
|
16755
|
-
runId: this.currentReceiptOwnerRunId,
|
|
16756
|
-
attempt: this.currentRunAttempt,
|
|
16757
|
-
},
|
|
16758
|
-
members: requests.map((request) => ({
|
|
16759
|
-
memberId: request.callId,
|
|
16760
|
-
...this.mappedToolResultReceiptPolicy(request),
|
|
16761
|
-
forceFailedRefresh: request.forceFailedRefresh === true,
|
|
16762
|
-
waitMaxAttempts: resolveRuntimeToolReceiptWaitMaxAttempts(
|
|
16763
|
-
typeof request.receiptWaitMs === 'number'
|
|
16764
|
-
? { max_wait_ms: request.receiptWaitMs }
|
|
16765
|
-
: request.input,
|
|
16766
|
-
),
|
|
16767
|
-
})),
|
|
16768
|
-
});
|
|
16769
|
-
|
|
16770
|
-
const successful: ToolCallRequest[] = [];
|
|
16771
|
-
const resolve = async (
|
|
16772
|
-
request: ToolCallRequest,
|
|
16773
|
-
result: ToolExecuteResult,
|
|
16774
|
-
source: 'cache' | 'owner',
|
|
16775
|
-
): Promise<void> => {
|
|
16776
|
-
const receiptKey = request.receiptKey!;
|
|
16777
|
-
const finalResult = cloneToolExecuteResultWithExecution(result, {
|
|
16778
|
-
...toolExecutionMetadataForOutcome({
|
|
16779
|
-
kind: source === 'owner' ? 'live' : source,
|
|
16780
|
-
cacheKey: request.cacheKey,
|
|
16781
|
-
receiptKey,
|
|
16782
|
-
...(source === 'owner' ? {} : { attachedToReceiptKey: receiptKey }),
|
|
16783
|
-
}),
|
|
16784
|
-
resultReceiptKey:
|
|
16785
|
-
this.mappedToolResultReceiptPolicy(request).resultReceiptKey,
|
|
16786
|
-
});
|
|
16787
|
-
this.cacheToolResult(toolId, request.cacheKey, finalResult);
|
|
16788
|
-
const resolver = this.toolCallResolvers.get(request.callId);
|
|
16789
|
-
if (resolver) {
|
|
16790
|
-
resolver.resolve(finalResult);
|
|
16791
|
-
this.toolCallResolvers.delete(request.callId);
|
|
16792
|
-
}
|
|
16793
|
-
this.emitScopedFieldMetaUpdate({
|
|
16794
|
-
rowId: request.rowId,
|
|
16795
|
-
key: request.rowKey ?? null,
|
|
16796
|
-
tableNamespace: request.tableNamespace ?? null,
|
|
16797
|
-
fieldName: request.fieldName,
|
|
16798
|
-
status: source === 'owner' ? 'running' : 'cached',
|
|
16799
|
-
rowStatus: 'running',
|
|
16800
|
-
stage: toolId,
|
|
16801
|
-
provider: null,
|
|
16802
|
-
error: null,
|
|
16803
|
-
...(source === 'owner' ? {} : { reused: true }),
|
|
16804
|
-
dataPatch: {},
|
|
16805
|
-
});
|
|
16806
|
-
successful.push(request);
|
|
16807
|
-
};
|
|
16808
|
-
const reject = async (request: ToolCallRequest, error: unknown) => {
|
|
16809
|
-
await this.rejectToolCall(toolId, request, error, {
|
|
16810
|
-
// Failures are never cache entries, including failed local misses.
|
|
16811
|
-
persistReceiptFailure: false,
|
|
16812
|
-
});
|
|
16813
|
-
};
|
|
16814
|
-
|
|
16815
|
-
const cachedResults: Promise<void>[] = [];
|
|
16816
|
-
const owned: Array<{
|
|
16817
|
-
request: ToolCallRequest;
|
|
16818
|
-
receipts: ToolResultReceipts;
|
|
16819
|
-
}> = [];
|
|
16820
|
-
for (const request of requests) {
|
|
16821
|
-
const member = cohort.member(request.callId);
|
|
16822
|
-
if (member.kind === 'completed') {
|
|
16823
|
-
cachedResults.push(resolve(request, member.result, member.source));
|
|
16824
|
-
} else if (member.kind === 'owned') {
|
|
16825
|
-
owned.push({ request, receipts: member.receipts });
|
|
16826
|
-
} else {
|
|
16827
|
-
throw new Error(
|
|
16828
|
-
'A completed-result cache cannot own a pending invocation.',
|
|
16829
|
-
);
|
|
16830
|
-
}
|
|
16831
|
-
}
|
|
16832
|
-
|
|
16833
|
-
const width = Math.min(
|
|
16834
|
-
this.governor.policy.concurrency.toolCalls,
|
|
16835
|
-
Math.max(
|
|
16836
|
-
1,
|
|
16837
|
-
await this.resourceGovernor.suggestedToolParallelism(
|
|
17354
|
+
for (const member of members) {
|
|
17355
|
+
requestForReceipt.set(member.resultReceiptKey, member.request);
|
|
17356
|
+
const shared = requestsForReceipt.get(member.resultReceiptKey);
|
|
17357
|
+
if (shared) shared.push(member.request);
|
|
17358
|
+
else requestsForReceipt.set(member.resultReceiptKey, [member.request]);
|
|
17359
|
+
requestByCallId.set(member.memberId, member.request);
|
|
17360
|
+
}
|
|
17361
|
+
const calls = createMappedToolCallJob<ToolCallRequest>({
|
|
17362
|
+
receiptCohort: createToolCallReceiptCohortJob({
|
|
17363
|
+
store: this.createRuntimeStepToolCallReceiptCohortStore({
|
|
16838
17364
|
toolId,
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
|
|
16845
|
-
|
|
16846
|
-
|
|
16847
|
-
|
|
16848
|
-
|
|
16849
|
-
|
|
16850
|
-
|
|
16851
|
-
|
|
16852
|
-
|
|
16853
|
-
|
|
17365
|
+
requestForReceipt,
|
|
17366
|
+
requestsForReceipt,
|
|
17367
|
+
}),
|
|
17368
|
+
timings: this.toolCallReceiptCohortTimings(requestByCallId),
|
|
17369
|
+
}),
|
|
17370
|
+
admission: {
|
|
17371
|
+
parallelism: async () =>
|
|
17372
|
+
Math.min(
|
|
17373
|
+
this.governor.policy.concurrency.toolCalls,
|
|
17374
|
+
Math.max(
|
|
17375
|
+
1,
|
|
17376
|
+
await this.resourceGovernor.suggestedToolParallelism(
|
|
17377
|
+
toolId,
|
|
17378
|
+
this.governor.policy.concurrency.toolCalls,
|
|
17379
|
+
),
|
|
17380
|
+
),
|
|
17381
|
+
),
|
|
17382
|
+
assertDispatchAllowed: () => {
|
|
17383
|
+
if (!this.persistenceLatch.tripped) return;
|
|
16854
17384
|
this.persistenceLatch.preventedCallCount += 1;
|
|
16855
|
-
|
|
16856
|
-
|
|
16857
|
-
|
|
16858
|
-
|
|
16859
|
-
|
|
16860
|
-
|
|
16861
|
-
let releaseToolSlot: () => void = () => undefined;
|
|
16862
|
-
try {
|
|
17385
|
+
throw new RuntimePersistenceCircuitOpenError(this.persistenceLatch);
|
|
17386
|
+
},
|
|
17387
|
+
},
|
|
17388
|
+
execution: {
|
|
17389
|
+
call: async ({ member, receipts, retainToolSlot }) => {
|
|
17390
|
+
const request = member.request;
|
|
16863
17391
|
const providerOperationKey = this.providerInvocationKeyForToolCall({
|
|
16864
17392
|
operationKey:
|
|
16865
17393
|
request.providerIdempotencyKeyBase ?? request.receiptKey!,
|
|
16866
17394
|
logicalCallId: request.logicalCallId,
|
|
16867
17395
|
force: request.force,
|
|
16868
17396
|
});
|
|
16869
|
-
|
|
17397
|
+
return this.executeMappedToolCallThroughModule({
|
|
16870
17398
|
request,
|
|
16871
17399
|
dispatchToolId: toolId,
|
|
16872
17400
|
dispatchPayload: request.input,
|
|
16873
|
-
resultReceiptKey:
|
|
16874
|
-
this.mappedToolResultReceiptPolicy(request).resultReceiptKey,
|
|
17401
|
+
resultReceiptKey: member.resultReceiptKey,
|
|
16875
17402
|
providerOperationKey,
|
|
16876
17403
|
resultReceipts: receipts,
|
|
16877
17404
|
apiOptions: {
|
|
@@ -16910,22 +17437,52 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
16910
17437
|
typeof request.timeoutMs === 'number' && request.timeoutMs > 0
|
|
16911
17438
|
? request.timeoutMs
|
|
16912
17439
|
: undefined,
|
|
16913
|
-
retainToolSlot
|
|
16914
|
-
releaseToolSlot = release;
|
|
16915
|
-
},
|
|
17440
|
+
retainToolSlot,
|
|
16916
17441
|
},
|
|
16917
17442
|
});
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
16921
|
-
}
|
|
16922
|
-
|
|
16923
|
-
|
|
17443
|
+
},
|
|
17444
|
+
},
|
|
17445
|
+
delivery: {
|
|
17446
|
+
complete: async ({ member, result, source }) => {
|
|
17447
|
+
const request = member.request;
|
|
17448
|
+
this.cacheToolResult(toolId, member.cacheKey, result);
|
|
17449
|
+
const resolver = this.toolCallResolvers.get(member.memberId);
|
|
17450
|
+
if (resolver) {
|
|
17451
|
+
resolver.resolve(result);
|
|
17452
|
+
this.toolCallResolvers.delete(member.memberId);
|
|
17453
|
+
}
|
|
17454
|
+
this.emitScopedFieldMetaUpdate({
|
|
17455
|
+
rowId: request.rowId,
|
|
17456
|
+
key: request.rowKey ?? null,
|
|
17457
|
+
tableNamespace: request.tableNamespace ?? null,
|
|
17458
|
+
fieldName: request.fieldName,
|
|
17459
|
+
status: source === 'owner' ? 'running' : 'cached',
|
|
17460
|
+
rowStatus: 'running',
|
|
17461
|
+
stage: toolId,
|
|
17462
|
+
provider: null,
|
|
17463
|
+
error: null,
|
|
17464
|
+
...(source === 'owner' ? {} : { reused: true }),
|
|
17465
|
+
dataPatch: {},
|
|
17466
|
+
});
|
|
17467
|
+
},
|
|
17468
|
+
fail: async ({ member, error }) => {
|
|
17469
|
+
await this.rejectToolCall(toolId, member.request, error, {
|
|
17470
|
+
// A failure never replaces an immutable successful cache entry.
|
|
17471
|
+
persistReceiptFailure: false,
|
|
17472
|
+
});
|
|
17473
|
+
},
|
|
17474
|
+
},
|
|
17475
|
+
});
|
|
17476
|
+
const { successfulMemberIds } = await calls.call({
|
|
17477
|
+
owner: {
|
|
17478
|
+
runId: this.currentReceiptOwnerRunId,
|
|
17479
|
+
attempt: this.currentRunAttempt,
|
|
16924
17480
|
},
|
|
17481
|
+
members,
|
|
17482
|
+
});
|
|
17483
|
+
return successfulMemberIds.map(
|
|
17484
|
+
(memberId) => requestByCallId.get(memberId)!,
|
|
16925
17485
|
);
|
|
16926
|
-
|
|
16927
|
-
await Promise.all(cachedResults);
|
|
16928
|
-
return successful;
|
|
16929
17486
|
}
|
|
16930
17487
|
|
|
16931
17488
|
/**
|
|
@@ -19148,8 +19705,14 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19148
19705
|
// the current checkpoint cursor index belongs to a newer batch.
|
|
19149
19706
|
const providerResidentWaitKey = durableCallReceiptKey;
|
|
19150
19707
|
let transportAttempt = 0;
|
|
19708
|
+
let connectFailures = 0;
|
|
19709
|
+
let firstConnectFailureAtMs: number | null = null;
|
|
19151
19710
|
let invocationAttempt =
|
|
19152
19711
|
savedProviderRetryCursor?.invocationAttempt ?? 0;
|
|
19712
|
+
// The no-send claim covers the whole logical call, including
|
|
19713
|
+
// deliveries made before a checkpoint resume.
|
|
19714
|
+
let earlierDeliveryMayHaveArrived =
|
|
19715
|
+
savedProviderRetryCursor !== undefined || invocationAttempt > 0;
|
|
19153
19716
|
clearProviderRetryCursor = () => {
|
|
19154
19717
|
if (providerResidentWaitKey)
|
|
19155
19718
|
this.exhaustedProviderResidentWaitCalls.delete(
|
|
@@ -19271,8 +19834,21 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19271
19834
|
aborted: boolean;
|
|
19272
19835
|
/** The ingress rejected the request before any provider dispatch. */
|
|
19273
19836
|
knownNotDispatched?: boolean;
|
|
19837
|
+
/** No socket existed, so no byte of the request was written. */
|
|
19838
|
+
connectionNeverOpened?: boolean;
|
|
19274
19839
|
}): Promise<void> => {
|
|
19275
|
-
|
|
19840
|
+
if (!input.connectionNeverOpened)
|
|
19841
|
+
earlierDeliveryMayHaveArrived = true;
|
|
19842
|
+
let connectRetryDelayMs: number | null = null;
|
|
19843
|
+
if (input.connectionNeverOpened) {
|
|
19844
|
+
connectFailures += 1;
|
|
19845
|
+
firstConnectFailureAtMs ??= Date.now();
|
|
19846
|
+
connectRetryDelayMs = toolExecuteConnectRetryDelayMs({
|
|
19847
|
+
failures: connectFailures,
|
|
19848
|
+
elapsedMs: Date.now() - firstConnectFailureAtMs,
|
|
19849
|
+
});
|
|
19850
|
+
}
|
|
19851
|
+
if (connectRetryDelayMs === null) transportAttempt += 1;
|
|
19276
19852
|
const diagnostic = describeTransportError(input.error);
|
|
19277
19853
|
this.runtimeLog(
|
|
19278
19854
|
`[runtime.transport_failure] ${JSON.stringify({
|
|
@@ -19283,9 +19859,23 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19283
19859
|
elapsed_ms: input.elapsedMs,
|
|
19284
19860
|
request_id: input.requestId,
|
|
19285
19861
|
aborted: input.aborted,
|
|
19862
|
+
connection_never_opened: input.connectionNeverOpened === true,
|
|
19286
19863
|
error: diagnostic,
|
|
19287
19864
|
})}`,
|
|
19288
19865
|
);
|
|
19866
|
+
if (connectRetryDelayMs !== null) {
|
|
19867
|
+
// Nothing reached the gateway, so this is neither a provider
|
|
19868
|
+
// attempt nor a charged retry: the logical attempt stays as it was.
|
|
19869
|
+
span.setAttribute(
|
|
19870
|
+
'plays.connect_retry_failures',
|
|
19871
|
+
connectFailures,
|
|
19872
|
+
);
|
|
19873
|
+
this.runtimeLog(
|
|
19874
|
+
`Tool ${toolId} could not open a connection for ${url}; this attempt sent no request; retrying after ${connectRetryDelayMs}ms: ${diagnostic.message ?? 'unknown transport error'}`,
|
|
19875
|
+
);
|
|
19876
|
+
await waitForToolRetry(connectRetryDelayMs, false);
|
|
19877
|
+
return;
|
|
19878
|
+
}
|
|
19289
19879
|
if (
|
|
19290
19880
|
transportAttempt < TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS &&
|
|
19291
19881
|
(input.knownNotDispatched === true ||
|
|
@@ -19318,7 +19908,11 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19318
19908
|
}
|
|
19319
19909
|
throw createToolHttpError(
|
|
19320
19910
|
toolErrorSchemaVersion,
|
|
19321
|
-
|
|
19911
|
+
input.connectionNeverOpened
|
|
19912
|
+
? // Only these attempts are proven; a delivery before a resume
|
|
19913
|
+
// leaves no trace in this process, so never claim the call.
|
|
19914
|
+
`Tool ${toolId} could not open a connection for ${url} before the retry window closed. These connection attempts sent no request${earlierDeliveryMayHaveArrived ? ', but an earlier attempt of this call may have reached the provider' : ''}: ${diagnostic.message ?? 'unknown transport error'}`
|
|
19915
|
+
: `Tool ${toolId} transport failed calling ${url} after ${transportAttempt}/${TOOL_EXECUTE_TRANSPORT_MAX_ATTEMPTS} attempts: ${diagnostic.message ?? 'unknown transport error'}`,
|
|
19322
19916
|
null,
|
|
19323
19917
|
0,
|
|
19324
19918
|
'repairable',
|
|
@@ -19775,6 +20369,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19775
20369
|
: url,
|
|
19776
20370
|
{
|
|
19777
20371
|
method: 'POST',
|
|
20372
|
+
// A followed redirect could fail to connect after
|
|
20373
|
+
// this POST was delivered, which would look like
|
|
20374
|
+
// a request that was never sent.
|
|
20375
|
+
redirect: 'manual',
|
|
19778
20376
|
signal: abortController?.signal,
|
|
19779
20377
|
headers: {
|
|
19780
20378
|
'Content-Type': 'application/json',
|
|
@@ -19939,6 +20537,11 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19939
20537
|
// graph; the row-scoped body handle below then
|
|
19940
20538
|
// owns the measured value after this turn ends.
|
|
19941
20539
|
bodyTurn.settleBytes(responseBodyBytes);
|
|
20540
|
+
const bodyWork =
|
|
20541
|
+
bodyTurn.waitForCooperativeWork?.(
|
|
20542
|
+
abortController?.signal,
|
|
20543
|
+
);
|
|
20544
|
+
if (bodyWork) await bodyWork;
|
|
19942
20545
|
const transportBytes =
|
|
19943
20546
|
this.memoryLedger.register({
|
|
19944
20547
|
category: 'transportInFlight',
|
|
@@ -19964,6 +20567,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19964
20567
|
nativeBatchBodyAttribution,
|
|
19965
20568
|
);
|
|
19966
20569
|
},
|
|
20570
|
+
abortController?.signal,
|
|
19967
20571
|
);
|
|
19968
20572
|
providerBodyAdmissionWaitMs += bodyRead.waitMs;
|
|
19969
20573
|
} else {
|
|
@@ -19992,7 +20596,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
19992
20596
|
error,
|
|
19993
20597
|
);
|
|
19994
20598
|
}
|
|
20599
|
+
const bodyWork =
|
|
20600
|
+
bodyTurn.waitForCooperativeWork?.(
|
|
20601
|
+
abortController?.signal,
|
|
20602
|
+
);
|
|
20603
|
+
if (bodyWork) await bodyWork;
|
|
19995
20604
|
},
|
|
20605
|
+
abortController?.signal,
|
|
19996
20606
|
);
|
|
19997
20607
|
providerBodyAdmissionWaitMs += bodyRead.waitMs;
|
|
19998
20608
|
}
|
|
@@ -20342,8 +20952,12 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
20342
20952
|
402,
|
|
20343
20953
|
);
|
|
20344
20954
|
}
|
|
20955
|
+
const connectionNeverOpened =
|
|
20956
|
+
response === null &&
|
|
20957
|
+
transportFailureProvesRequestNeverSent(transportError);
|
|
20345
20958
|
const ambiguousDispatchedFailure =
|
|
20346
20959
|
fetchDispatched &&
|
|
20960
|
+
!connectionNeverOpened &&
|
|
20347
20961
|
(response === null ||
|
|
20348
20962
|
error instanceof ToolExecuteResponseBodyTransportError ||
|
|
20349
20963
|
error instanceof ToolExecuteInvalidJsonError);
|
|
@@ -20412,6 +21026,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
20412
21026
|
: Date.now() - providerCallStartedAt,
|
|
20413
21027
|
requestId: deeplineRequestId,
|
|
20414
21028
|
aborted: abortController?.signal.aborted === true,
|
|
21029
|
+
connectionNeverOpened,
|
|
20415
21030
|
});
|
|
20416
21031
|
continue;
|
|
20417
21032
|
} finally {
|
|
@@ -20426,6 +21041,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
20426
21041
|
`Tool ${toolId} transport completed without an HTTP response.`,
|
|
20427
21042
|
);
|
|
20428
21043
|
}
|
|
21044
|
+
connectFailures = 0;
|
|
21045
|
+
firstConnectFailureAtMs = null;
|
|
21046
|
+
earlierDeliveryMayHaveArrived = true;
|
|
20429
21047
|
span.setAttribute('plays.http_status_code', response.status);
|
|
20430
21048
|
|
|
20431
21049
|
if (providerPermitReceiverRejected) {
|
|
@@ -20451,6 +21069,17 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
20451
21069
|
);
|
|
20452
21070
|
}
|
|
20453
21071
|
|
|
21072
|
+
if (response.status >= 300 && response.status < 400) {
|
|
21073
|
+
const location = response.headers.get('location');
|
|
21074
|
+
throw createToolHttpError(
|
|
21075
|
+
toolErrorSchemaVersion,
|
|
21076
|
+
`Tool ${toolId} was redirected to ${location ? transportGatewayOriginForDiagnostic(location) : '<none>'}; tool execution refuses redirects, so the outcome of this call is unknown.`,
|
|
21077
|
+
null,
|
|
21078
|
+
response.status,
|
|
21079
|
+
'repairable',
|
|
21080
|
+
);
|
|
21081
|
+
}
|
|
21082
|
+
|
|
20454
21083
|
if (!response.ok) {
|
|
20455
21084
|
const text = responseErrorText ?? '';
|
|
20456
21085
|
const recoveryKey = asyncRecoveryKey(invocationAttempt);
|
|
@@ -20683,10 +21312,13 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
20683
21312
|
// not in question because there is nothing to replay. Every tool
|
|
20684
21313
|
// may pace on it, including one that never declared transient
|
|
20685
21314
|
// 5xx retries safe — otherwise a protective limit on the relay
|
|
20686
|
-
// turns straight into customer row failures.
|
|
21315
|
+
// turns straight into customer row failures. A scheduler refusal
|
|
21316
|
+
// proves only that this delivery went nowhere: an earlier delivery
|
|
21317
|
+
// of the same attempt may have a row, so the attempt must not move.
|
|
20687
21318
|
const shedKnownNotDispatched =
|
|
20688
21319
|
failure.reason === 'concurrency_backpressure' ||
|
|
20689
|
-
failure.reason === 'provider_pacing_wait'
|
|
21320
|
+
failure.reason === 'provider_pacing_wait' ||
|
|
21321
|
+
failure.reason === 'runtime_scheduler_capacity';
|
|
20690
21322
|
if (
|
|
20691
21323
|
failure.shouldRetry &&
|
|
20692
21324
|
(failure.knownNotDispatched ||
|
|
@@ -20703,8 +21335,8 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
20703
21335
|
failure.backpressureDelayMs !== null)
|
|
20704
21336
|
) {
|
|
20705
21337
|
// A gateway follower is retrying its owner's durable
|
|
20706
|
-
// invocation, while a concurrency
|
|
20707
|
-
// wrote no invocation
|
|
21338
|
+
// invocation, while a concurrency, provider-pacing or scheduler
|
|
21339
|
+
// refusal wrote no invocation itself. All reuse this logical attempt: advancing it
|
|
20708
21340
|
// either bypasses the live-owner replay fence or makes the
|
|
20709
21341
|
// prior-attempt sweep see an intentionally absent receipt.
|
|
20710
21342
|
if (
|