deepline 0.3.392 → 0.3.393
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundling-sources/sdk/src/client.ts +156 -24
- package/dist/bundling-sources/sdk/src/compat.ts +9 -0
- package/dist/bundling-sources/sdk/src/http.ts +5 -1
- package/dist/bundling-sources/sdk/src/index.ts +5 -0
- package/dist/bundling-sources/sdk/src/plays/run-request.ts +182 -6
- package/dist/bundling-sources/sdk/src/release.ts +4 -1
- package/dist/bundling-sources/sdk/src/types.ts +13 -0
- package/dist/bundling-sources/shared_libs/integration-contracts/request-warnings.ts +64 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/runtime-sheet-storage-contract.ts +315 -0
- package/dist/bundling-sources/shared_libs/play-runtime/async-operation.ts +41 -8
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +418 -44
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +36 -3
- package/dist/bundling-sources/shared_libs/play-runtime/durable-invocation-fence.ts +36 -0
- package/dist/bundling-sources/shared_libs/play-runtime/map-execution-frame.ts +11 -3
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/gateway-adapter.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +19 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-identity.ts +26 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +158 -10
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +235 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +92 -58
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +7 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +30 -7
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1161 -316
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +28 -15
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +24 -3
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +31 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +37 -4
- package/dist/bundling-sources/shared_libs/plays/dataset.ts +172 -79
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +173 -1
- package/dist/cli/{auth-6JSA2ZCW.mjs → auth-5PXHA232.mjs} +4 -4
- package/dist/cli/auth-P3MVDTXM.js +39 -0
- package/dist/cli/{billing-Q5BLQHIU.js → billing-JFB2XLSO.js} +101 -74
- package/dist/cli/{billing-MRRO643H.mjs → billing-Z2N7ZAGM.mjs} +32 -5
- package/dist/cli/{chunk-CVLM3WMJ.js → chunk-2HAD745V.js} +242 -183
- package/dist/cli/{chunk-HGYBEAQP.mjs → chunk-2LGC4EFT.mjs} +3 -3
- package/dist/cli/{chunk-A3APGZFP.mjs → chunk-4PT2VA3A.mjs} +2 -2
- package/dist/cli/{chunk-6DBOU7UH.js → chunk-4XX6443T.js} +176 -87
- package/dist/cli/{chunk-2QLML6G4.mjs → chunk-5KWKZIQR.mjs} +4 -4
- package/dist/cli/{chunk-2G7DXFHI.mjs → chunk-5PRVMXKB.mjs} +27 -2
- package/dist/cli/{chunk-DSWSEHRX.mjs → chunk-6I73X254.mjs} +1 -1
- package/dist/cli/{chunk-ZTACINO5.mjs → chunk-7HR7BGZL.mjs} +13 -3
- package/dist/cli/{chunk-BB3FNYFY.js → chunk-AARX5L4B.js} +2 -2
- package/dist/cli/{chunk-WMS5U6YB.js → chunk-CDFH2DYL.js} +20 -19
- package/dist/cli/{chunk-R3O2CZ4H.mjs → chunk-FQ6VHPW4.mjs} +2 -2
- package/dist/cli/{chunk-MU6M3URX.mjs → chunk-HLEESTCH.mjs} +1 -1
- package/dist/cli/{chunk-Q6EOHNRH.mjs → chunk-JI2B4RZP.mjs} +119 -6
- package/dist/cli/{chunk-2Q3GEFL4.mjs → chunk-KIYU2TGL.mjs} +2 -2
- package/dist/cli/{chunk-Y6VOGHF2.mjs → chunk-KZZC33PY.mjs} +0 -181
- package/dist/cli/{chunk-UCKJQG25.js → chunk-L2SYLGRP.js} +8 -8
- package/dist/cli/{chunk-2GAHHSLB.mjs → chunk-LMMEAMA7.mjs} +3 -2
- package/dist/cli/{chunk-YAZCDBXX.mjs → chunk-LZPCDB7U.mjs} +3 -2
- package/dist/cli/{chunk-RV6ALZIX.js → chunk-M7Y7JYZX.js} +32 -7
- package/dist/cli/{chunk-QGKPTBRR.js → chunk-MS6GUPBB.js} +3 -3
- package/dist/cli/{chunk-4SFPVW7A.js → chunk-OXNOAD6Y.js} +26 -26
- package/dist/cli/{chunk-JOFPQGXW.js → chunk-PTDECJGP.js} +50 -50
- package/dist/cli/{chunk-5O4B6AUN.js → chunk-PWSWAN7Q.js} +25 -2
- package/dist/cli/{chunk-YN6YA7ZZ.mjs → chunk-Q26LUSQ2.mjs} +79 -20
- package/dist/cli/{chunk-3VN4FTE3.js → chunk-RDXFGPJU.js} +1 -182
- package/dist/cli/{chunk-7E66A24V.mjs → chunk-RKMB3N7K.mjs} +25 -2
- package/dist/cli/{chunk-JSLPHFP7.js → chunk-RWHWF5ZJ.js} +3 -2
- package/dist/cli/{chunk-3FV4GBRK.mjs → chunk-STNYIMIV.mjs} +97 -8
- package/dist/cli/chunk-UBKA33KY.mjs +310 -0
- package/dist/cli/{chunk-PAIMOGCM.js → chunk-UHNDVD3P.js} +125 -12
- package/dist/cli/{chunk-24VEN5PQ.mjs → chunk-UOGZUA24.mjs} +179 -17
- package/dist/cli/{chunk-T7OKJ2T6.js → chunk-VIQJIX2P.js} +73 -63
- package/dist/cli/{chunk-RIV2GS5E.js → chunk-VIWE6WRK.js} +627 -465
- package/dist/cli/{chunk-EY7RFC6A.js → chunk-W4WOMXR3.js} +15 -15
- package/dist/cli/chunk-XDVT3GOM.js +310 -0
- package/dist/cli/{chunk-2FQG2HU4.js → chunk-Z3OOZM5L.js} +8 -8
- package/dist/cli/{csv-E4QGUIGI.mjs → csv-KJWZHKCH.mjs} +3 -3
- package/dist/cli/{csv-26U5T24Z.js → csv-P3Z3YE7H.js} +12 -12
- package/dist/cli/{db-JTRJIAQW.mjs → db-NCM4CQIS.mjs} +6 -5
- package/dist/cli/{db-QHBFLMVL.js → db-NUZGJNQC.js} +31 -30
- package/dist/cli/{describe-E3DE3ZK3.mjs → describe-WT6MM2GO.mjs} +17 -16
- package/dist/cli/{describe-FDV2V74F.js → describe-YGSEN5WC.js} +24 -23
- package/dist/cli/{executions-VZYOGVQY.js → executions-PCOLHN7Q.js} +8 -7
- package/dist/cli/{executions-B3GTNPRE.mjs → executions-XS2IPJ4W.mjs} +6 -5
- package/dist/cli/{feedback-CR55FJA2.js → feedback-4MSH7TFU.js} +7 -7
- package/dist/cli/{feedback-4CEBR3OV.mjs → feedback-CCLTS5SV.mjs} +3 -3
- package/dist/cli/{git-NM2PHHZ4.mjs → git-K2DHPMPC.mjs} +4 -4
- package/dist/cli/git-RNM45FX4.js +23 -0
- package/dist/cli/index.js +96 -92
- package/dist/cli/index.mjs +46 -42
- package/dist/cli/{legacy-noops-A7MSW5ND.mjs → legacy-noops-B5S4AR3P.mjs} +4 -4
- package/dist/cli/{legacy-noops-ZUA4YFIH.js → legacy-noops-GPNOPFXV.js} +7 -7
- package/dist/cli/{monitors-NVPRQYP3.mjs → monitors-JLMAIPRG.mjs} +6 -5
- package/dist/cli/{monitors-ZE3TLZ4H.js → monitors-ZAWD7NSN.js} +87 -86
- package/dist/cli/{org-U7A6DV5D.js → org-P2KN4CES.js} +66 -65
- package/dist/cli/{org-KUBILNQV.mjs → org-T3JTHP4G.mjs} +6 -5
- package/dist/cli/{play-HRDXQ4QE.mjs → play-NK6BLRGL.mjs} +11 -10
- package/dist/cli/play-PDXR6JFB.js +158 -0
- package/dist/cli/{providers-OHIWI453.mjs → providers-3NQRA7IT.mjs} +6 -5
- package/dist/cli/{providers-VD6YTVQZ.js → providers-5QRZN3DT.js} +9 -8
- package/dist/cli/{quickstart-UBV2FONF.mjs → quickstart-PIA2JGPV.mjs} +3 -3
- package/dist/cli/{quickstart-ETTCWPA4.js → quickstart-R7NUZGNW.js} +5 -5
- package/dist/cli/run-identity-G257GQED.js +25 -0
- package/dist/cli/run-identity-MRNCEGV2.mjs +25 -0
- package/dist/cli/{search-F44IZRT7.mjs → search-AIDIIGLY.mjs} +7 -6
- package/dist/cli/search-QRWL7MFM.js +27 -0
- package/dist/cli/{secrets-CAEMRORF.js → secrets-BT3PGMWN.js} +15 -14
- package/dist/cli/{secrets-R6XOJZKU.mjs → secrets-OQNHL45O.mjs} +6 -5
- package/dist/cli/{sessions-6GC7OFTT.js → sessions-EYXWOSWK.js} +5 -5
- package/dist/cli/{sessions-RLN6UQS3.mjs → sessions-SF7WJPJP.mjs} +4 -4
- package/dist/cli/{settings-DPNVUAV2.js → settings-BA3GHBOD.js} +76 -75
- package/dist/cli/{settings-KIPAMRPP.mjs → settings-Y57JTFDD.mjs} +9 -8
- package/dist/cli/{setup-TU2F7PU5.mjs → setup-7GR5GBHA.mjs} +6 -6
- package/dist/cli/{setup-DTL3L5SG.js → setup-RERXYC66.js} +41 -41
- package/dist/cli/{skills-UV5MYJ46.mjs → skills-SJWIQAV5.mjs} +4 -4
- package/dist/cli/skills-V7EY75HB.js +28 -0
- package/dist/cli/tools-H5HLBCHH.js +41 -0
- package/dist/cli/{tools-QRRNDCQ7.mjs → tools-ZF3JXPNL.mjs} +10 -9
- package/dist/cli/update-472HA3LT.js +28 -0
- package/dist/cli/{update-4426TF35.mjs → update-FFFYQAOJ.mjs} +6 -6
- package/dist/cli/{workflow-HNLOVISB.js → workflow-SZJVQH4T.js} +17 -16
- package/dist/cli/{workflow-N4U5VLZ3.mjs → workflow-XVFEEGAS.mjs} +7 -6
- package/dist/{client-e6Qh5ZIg.d.mts → client-DU5dtHDy.d.mts} +153 -4
- package/dist/{client-Uxuy-xQ2.d.ts → client-mCE88hC4.d.ts} +153 -4
- package/dist/{compiler-manifest-CY2v8ab0.d.ts → compiler-manifest-DE4RdAiY.d.mts} +61 -1
- package/dist/{compiler-manifest-CY2v8ab0.d.mts → compiler-manifest-DE4RdAiY.d.ts} +61 -1
- package/dist/{index-B9fBZH1g.d.mts → index-BI6nWgaV.d.mts} +1 -1
- package/dist/{index-BZ6uzZJl.d.ts → index-Bi-f7HFT.d.ts} +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +120 -29
- package/dist/index.mjs +111 -20
- package/dist/install-integrity.json +91 -86
- 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 -2
- package/dist/plays/run-request.d.mts +2 -2
- package/dist/plays/run-request.d.ts +2 -2
- package/dist/plays/run-request.js +5 -2
- package/dist/plays/run-request.mjs +4 -1
- package/dist/release.d.mts +4 -1
- package/dist/release.d.ts +4 -1
- package/dist/release.js +2 -2
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
- package/dist/cli/auth-67TAELQL.js +0 -39
- package/dist/cli/git-I5JTK6YU.js +0 -23
- package/dist/cli/play-A2V7YDU7.js +0 -157
- package/dist/cli/search-WWXMBVPH.js +0 -26
- package/dist/cli/skills-SWOSEZLB.js +0 -28
- package/dist/cli/tools-IL2YCDQ6.js +0 -40
- package/dist/cli/update-BERDPEYR.js +0 -28
|
@@ -345,10 +345,12 @@ export interface RuntimeDatasetOptions<TItem = Record<string, unknown>> {
|
|
|
345
345
|
* row. Use this to pin identity to primary columns (e.g. `{ key: "email" }`
|
|
346
346
|
* or `{ key: ["first_name", "last_name", "domain"] }`) so harmless
|
|
347
347
|
* mutations to other columns don't invalidate the cache.
|
|
348
|
+
* Providing a key selects key identity for non-CSV sources and retained
|
|
349
|
+
* authoring editions.
|
|
348
350
|
*
|
|
349
351
|
* Must return a non-empty string (numbers are coerced). Empty keys throw
|
|
350
352
|
* loudly before any provider work runs. Rows whose keys duplicate an earlier
|
|
351
|
-
* row are
|
|
353
|
+
* row are deduped (first occurrence wins) and counted, never failing
|
|
352
354
|
* the run. The key function should reference *input*
|
|
353
355
|
* columns only — values produced by this dataset's field resolvers are stripped
|
|
354
356
|
* before identity is computed.
|
|
@@ -357,6 +359,14 @@ export interface RuntimeDatasetOptions<TItem = Record<string, unknown>> {
|
|
|
357
359
|
| (keyof TItem & string)
|
|
358
360
|
| readonly (keyof TItem & string)[]
|
|
359
361
|
| ((row: TItem, index: number) => string | number | readonly unknown[]);
|
|
362
|
+
/**
|
|
363
|
+
* Edition 11 CSV inputs always use source_row: the original CSV record
|
|
364
|
+
* ordinal distinguishes equal records and every occurrence is processed,
|
|
365
|
+
* even when key or rowIdentity: 'key' is supplied. For non-CSV sources and
|
|
366
|
+
* retained editions, rowIdentity: 'key' keeps the existing first-wins
|
|
367
|
+
* dedupe behavior.
|
|
368
|
+
*/
|
|
369
|
+
rowIdentity?: 'source_row' | 'key';
|
|
360
370
|
/**
|
|
361
371
|
* Row failure policy for this dataset run.
|
|
362
372
|
*
|
|
@@ -400,7 +410,12 @@ export type RuntimeDatasetDefinitionOptions<TItem = Record<string, unknown>> =
|
|
|
400
410
|
|
|
401
411
|
export type RuntimeDatasetRunOptions<TItem = Record<string, unknown>> = Pick<
|
|
402
412
|
RuntimeDatasetOptions<TItem>,
|
|
403
|
-
|
|
413
|
+
| 'description'
|
|
414
|
+
| 'key'
|
|
415
|
+
| 'rowIdentity'
|
|
416
|
+
| 'onRowError'
|
|
417
|
+
| 'mode'
|
|
418
|
+
| 'undrawnColumns'
|
|
404
419
|
>;
|
|
405
420
|
|
|
406
421
|
/** Runtime-only receipt recovery bit; never part of the customer authoring API. */
|
|
@@ -500,6 +515,11 @@ export interface MapExecutionFrame {
|
|
|
500
515
|
suspendedInputRows?: Array<{
|
|
501
516
|
inputIndex: number;
|
|
502
517
|
data: Record<string, unknown>;
|
|
518
|
+
/** Original admission input, separate from restored execution/output cells. */
|
|
519
|
+
authoredInput?: {
|
|
520
|
+
data: Record<string, unknown>;
|
|
521
|
+
source?: Readonly<{ datasetId: string; rowIndex: number }>;
|
|
522
|
+
};
|
|
503
523
|
/** Digest of the authored input before Runtime Sheet outputs were merged. */
|
|
504
524
|
authoredInputDigest?: string;
|
|
505
525
|
}>;
|
|
@@ -507,6 +527,13 @@ export interface MapExecutionFrame {
|
|
|
507
527
|
completedRowsCount?: number;
|
|
508
528
|
pendingRowsCount?: number;
|
|
509
529
|
failedRowsCount?: number;
|
|
530
|
+
/** Original source cardinality retained across pending-only checkpoint replay. */
|
|
531
|
+
inputCardinality?: {
|
|
532
|
+
sourceRows: number;
|
|
533
|
+
uniqueInputRows: number;
|
|
534
|
+
duplicateOccurrences: number;
|
|
535
|
+
rowIdentity: 'source_row' | 'key';
|
|
536
|
+
};
|
|
510
537
|
/** Bounded final-row causes, additive for checkpoint compatibility. */
|
|
511
538
|
failureCounts?: import('./row-failure-summary').RowFailureCounts;
|
|
512
539
|
/** Terminal rows omitted from this run's latest view because a newer write won. */
|
|
@@ -988,7 +1015,9 @@ export interface ContextOptions {
|
|
|
988
1015
|
tableNamespace: string;
|
|
989
1016
|
succeededRows: number;
|
|
990
1017
|
failedRows: number;
|
|
991
|
-
|
|
1018
|
+
expectedRows?: number;
|
|
1019
|
+
staticPipeline?: PlayStaticPipeline | null;
|
|
1020
|
+
}) => void | Promise<void>;
|
|
992
1021
|
/**
|
|
993
1022
|
* Persists coalesced, non-terminal row patches before a map suspends.
|
|
994
1023
|
* Terminal rows use onMapRowsCompleted; this narrow seam only preserves
|
|
@@ -1071,6 +1100,10 @@ export interface ContextOptions {
|
|
|
1071
1100
|
toolId: string,
|
|
1072
1101
|
) => Promise<string[]> | string[];
|
|
1073
1102
|
getToolAuthScopeDigest?: (toolId: string) => Promise<string> | string;
|
|
1103
|
+
/** Absent on older app readers; only the declared async boundary may opt in. */
|
|
1104
|
+
getToolAsyncExecutionRecovery?: (
|
|
1105
|
+
toolId: string,
|
|
1106
|
+
) => Promise<{ origin: string } | null>;
|
|
1074
1107
|
/** Original run for an explicit customer rerun, never an automatic retry. */
|
|
1075
1108
|
replayedFromRunId?: string | null;
|
|
1076
1109
|
getToolRateScope?: (
|
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
import { sha256Hex } from '../plays/row-identity';
|
|
2
|
+
|
|
3
|
+
export const RUNTIME_EXECUTION_RECOVERY_KEY_PREFIX = 'runtime-gateway:';
|
|
4
|
+
export const RUNTIME_EXECUTION_RECOVERY_SUPPORTED_HEADER =
|
|
5
|
+
'x-deepline-idempotency-supported';
|
|
6
|
+
export const RUNTIME_EXECUTION_RECOVERY_ONLY_HEADER =
|
|
7
|
+
'x-deepline-execution-recovery-only';
|
|
8
|
+
/** Gateway-owned support for forwarding a keyed async call and its app ACK. */
|
|
9
|
+
export const RUNTIME_ASYNC_EXECUTION_RECOVERY_TRANSPORT_HEADER =
|
|
10
|
+
'x-deepline-async-execution-recovery-transport';
|
|
11
|
+
|
|
12
|
+
/** Same-run delivery recovery must not coalesce separate Play runs. */
|
|
13
|
+
export function buildRuntimeExecutionRecoveryKey(input: {
|
|
14
|
+
parentRunId: string;
|
|
15
|
+
invocationKey: string;
|
|
16
|
+
}): string {
|
|
17
|
+
if (!input.parentRunId.trim() || !input.invocationKey.trim()) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
'Runtime execution recovery requires run and invocation identities.',
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return `${RUNTIME_EXECUTION_RECOVERY_KEY_PREFIX}${sha256Hex(input.parentRunId)}:${sha256Hex(input.invocationKey)}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A known key is not authority to read another executor run's response. */
|
|
26
|
+
export function isRuntimeExecutionRecoveryKeyForRun(
|
|
27
|
+
key: string,
|
|
28
|
+
runId: string,
|
|
29
|
+
): boolean {
|
|
30
|
+
if (!runId.trim()) return false;
|
|
31
|
+
const prefix = `${RUNTIME_EXECUTION_RECOVERY_KEY_PREFIX}${sha256Hex(runId)}:`;
|
|
32
|
+
return (
|
|
33
|
+
key.startsWith(prefix) && /^[a-f0-9]{64}$/.test(key.slice(prefix.length))
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
1
37
|
/**
|
|
2
38
|
* `execute-fenced-v2` is the first operation that requires semantic provider
|
|
3
39
|
* identity. It is intentionally a named operation rather than a runtime-wide
|
|
@@ -24,10 +24,18 @@ export function cloneMapFrame(frame: MapExecutionFrame): MapExecutionFrame {
|
|
|
24
24
|
...(frame.suspendedInputRows
|
|
25
25
|
? {
|
|
26
26
|
suspendedInputRows: frame.suspendedInputRows.map((row) => ({
|
|
27
|
-
|
|
27
|
+
...row,
|
|
28
28
|
data: cloneCsvAliasedRow(row.data),
|
|
29
|
-
...(row.
|
|
30
|
-
? {
|
|
29
|
+
...(row.authoredInput
|
|
30
|
+
? {
|
|
31
|
+
authoredInput: {
|
|
32
|
+
...row.authoredInput,
|
|
33
|
+
data: cloneCsvAliasedRow(row.authoredInput.data),
|
|
34
|
+
...(row.authoredInput.source
|
|
35
|
+
? { source: { ...row.authoredInput.source } }
|
|
36
|
+
: {}),
|
|
37
|
+
},
|
|
38
|
+
}
|
|
31
39
|
: {}),
|
|
32
40
|
})),
|
|
33
41
|
}
|
package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/gateway-adapter.ts
CHANGED
|
@@ -35,6 +35,7 @@ export function createGatewayRunLedgerProjectionAdapter(
|
|
|
35
35
|
runId: input.runId,
|
|
36
36
|
runtimeApi: input.runtimeApi,
|
|
37
37
|
tokenAuthority: 'gateway' as const,
|
|
38
|
+
...(input.runtimeApi.signal ? { signal: input.runtimeApi.signal } : {}),
|
|
38
39
|
};
|
|
39
40
|
return {
|
|
40
41
|
async deliver(request) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
normalizePlayAuthoringContractEdition,
|
|
3
3
|
playToolListGetterMode,
|
|
4
|
+
playCsvDatasetRowIdentity,
|
|
4
5
|
type PlayAuthoringContractEdition,
|
|
5
6
|
} from '../plays/authoring-contract';
|
|
6
7
|
|
|
@@ -50,11 +51,12 @@ export type PlayRuntimeSemantics = Readonly<{
|
|
|
50
51
|
slackHitl: Readonly<{
|
|
51
52
|
defaultTimeoutMs: number;
|
|
52
53
|
}>;
|
|
54
|
+
datasets: Readonly<{ csvRowIdentity: 'source_row' | 'key' }>;
|
|
53
55
|
}>;
|
|
54
56
|
|
|
55
57
|
type PlayRuntimeSemanticsTemplate = Omit<
|
|
56
58
|
PlayRuntimeSemantics,
|
|
57
|
-
'authoringContractEdition' | 'tools'
|
|
59
|
+
'authoringContractEdition' | 'tools' | 'datasets'
|
|
58
60
|
> & { tools: Omit<PlayRuntimeSemantics['tools'], 'listGetters'> };
|
|
59
61
|
|
|
60
62
|
function definePlayRuntimeSemantics(
|
|
@@ -72,6 +74,11 @@ function definePlayRuntimeSemantics(
|
|
|
72
74
|
listGetters: playToolListGetterMode(semantics.authoringContractEdition),
|
|
73
75
|
}),
|
|
74
76
|
slackHitl: Object.freeze({ ...semantics.slackHitl }),
|
|
77
|
+
datasets: Object.freeze({
|
|
78
|
+
csvRowIdentity: playCsvDatasetRowIdentity(
|
|
79
|
+
semantics.authoringContractEdition,
|
|
80
|
+
),
|
|
81
|
+
}),
|
|
75
82
|
});
|
|
76
83
|
}
|
|
77
84
|
|
|
@@ -198,6 +205,17 @@ const PLAY_RUNTIME_SEMANTICS_BY_AUTHORING = {
|
|
|
198
205
|
tools: { nativeBatchResponse: 'logical_response' },
|
|
199
206
|
slackHitl: WEEK_LONG_SLACK_HITL_SEMANTICS,
|
|
200
207
|
},
|
|
208
|
+
11: {
|
|
209
|
+
...PLAINTEXT_SECRET_SEMANTICS,
|
|
210
|
+
fetch: {
|
|
211
|
+
httpFailure: 'throw_typed_error',
|
|
212
|
+
persistHttpFailure: false,
|
|
213
|
+
receiptIdentityEdition: FETCH_RECEIPT_IDENTITIES.typedHttpFailure,
|
|
214
|
+
},
|
|
215
|
+
inlineChild: { runtimeOnly: true },
|
|
216
|
+
tools: { nativeBatchResponse: 'logical_response' },
|
|
217
|
+
slackHitl: WEEK_LONG_SLACK_HITL_SEMANTICS,
|
|
218
|
+
},
|
|
201
219
|
} satisfies Record<PlayAuthoringContractEdition, PlayRuntimeSemanticsTemplate>;
|
|
202
220
|
|
|
203
221
|
const PLAY_RUNTIME_SEMANTICS = Object.fromEntries(
|
|
@@ -90,6 +90,32 @@ export function buildPlayWorkflowId(
|
|
|
90
90
|
return `play/${familyKey}/run/${buildPlayWorkflowRunSuffix(timestamp)}${entropy}`;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/** Caller-owned identity binds the complete submitted JSON before admission. */
|
|
94
|
+
export function buildCallerPlayWorkflowId(
|
|
95
|
+
playName: string,
|
|
96
|
+
request: Record<string, unknown>,
|
|
97
|
+
now?: Date,
|
|
98
|
+
): string {
|
|
99
|
+
const { workflowId: _ignored, ...intent } = request;
|
|
100
|
+
const wireIntent = JSON.parse(JSON.stringify(intent));
|
|
101
|
+
return `${buildPlayWorkflowId(playName, now, { unique: true })}-caller-${sha256Hex(stableStringify(wireIntent))}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function callerPlayWorkflowIdMatchesRequest(
|
|
105
|
+
workflowId: string,
|
|
106
|
+
request: Record<string, unknown>,
|
|
107
|
+
): boolean {
|
|
108
|
+
const match =
|
|
109
|
+
/^play\/[a-z0-9/-]+\/run\/\d{8}t\d{6}-\d{3}-[a-z0-9]{8}-caller-([a-f0-9]{64})$/.exec(
|
|
110
|
+
workflowId,
|
|
111
|
+
);
|
|
112
|
+
if (!match || canonicalPlayRunStartedAtMs(workflowId) === null) return false;
|
|
113
|
+
const { workflowId: _ignored, ...intent } = request;
|
|
114
|
+
return (
|
|
115
|
+
match[1] === sha256Hex(stableStringify(JSON.parse(JSON.stringify(intent))))
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
93
119
|
export type PlayRunIdentity = {
|
|
94
120
|
workflowId: string;
|
|
95
121
|
runId: string;
|
|
@@ -19,6 +19,7 @@ import { csvInputTextOptions } from '../../plays/csv-text-repair';
|
|
|
19
19
|
import { install as installSourceMapSupport } from 'source-map-support';
|
|
20
20
|
import {
|
|
21
21
|
createDeferredPlayDataset,
|
|
22
|
+
setPlayDatasetSourceRowIdentity,
|
|
22
23
|
isPlayDataset,
|
|
23
24
|
isSerializedPlayDataset,
|
|
24
25
|
iteratePlayDatasetInputPages,
|
|
@@ -128,6 +129,7 @@ import {
|
|
|
128
129
|
import {
|
|
129
130
|
resolveRuntimeReferencedPlay,
|
|
130
131
|
createCompleteRuntimeMapRowsOperation,
|
|
132
|
+
finishRuntimeSheetRunMembership,
|
|
131
133
|
createRuntimeSheetDatasetPageReader,
|
|
132
134
|
type RuntimeSheetDatasetPageReader,
|
|
133
135
|
readRuntimeSheetDatasetRowKeys,
|
|
@@ -140,6 +142,7 @@ import {
|
|
|
140
142
|
} from '../runtime-api';
|
|
141
143
|
import { installPgRuntimePoolDriver } from '../runtime-pg-driver-pg';
|
|
142
144
|
import { createRuntimeToolAuthScopeDigestResolver } from '../auth-scope-resolver';
|
|
145
|
+
import { RUNTIME_ASYNC_EXECUTION_RECOVERY_TRANSPORT_HEADER } from '../durable-invocation-fence';
|
|
143
146
|
import { createRunScopedChildPlayResolver } from './child-play-resolver';
|
|
144
147
|
import { normalizePlayContractCompatibility } from '../../plays/contracts';
|
|
145
148
|
import { ToolExecutionError } from '../../plays/tool-execution-error';
|
|
@@ -379,6 +382,8 @@ type RuntimeToolMetadata = {
|
|
|
379
382
|
|
|
380
383
|
type RuntimeToolAuthScope = {
|
|
381
384
|
digest?: unknown;
|
|
385
|
+
managedAsyncExecutionRecovery?: unknown;
|
|
386
|
+
managedAsyncExecutionRecoveryOrigin?: unknown;
|
|
382
387
|
rateScope?: {
|
|
383
388
|
bucketId?: unknown;
|
|
384
389
|
provider?: unknown;
|
|
@@ -534,7 +539,7 @@ export function runtimeSheetTerminalMapCounts(
|
|
|
534
539
|
}
|
|
535
540
|
|
|
536
541
|
async function vercelBypassHeaders(
|
|
537
|
-
config: PlayRunnerExecutionConfig,
|
|
542
|
+
config: Pick<PlayRunnerExecutionConfig, 'context'>,
|
|
538
543
|
): Promise<Record<string, string>> {
|
|
539
544
|
return vercelProtectionBypassHeader(
|
|
540
545
|
config.context.vercelProtectionBypassToken,
|
|
@@ -723,9 +728,14 @@ function createRuntimeToolMetadataResolver(config: PlayRunnerExecutionConfig) {
|
|
|
723
728
|
};
|
|
724
729
|
}
|
|
725
730
|
|
|
726
|
-
function createAppRuntimeToolAuthScopeDigestResolver(
|
|
727
|
-
config: PlayRunnerExecutionConfig,
|
|
731
|
+
export function createAppRuntimeToolAuthScopeDigestResolver(
|
|
732
|
+
config: Pick<PlayRunnerExecutionConfig, 'context'>,
|
|
728
733
|
) {
|
|
734
|
+
const asyncRecoveryOrigins = new Map<string, string>();
|
|
735
|
+
const executionRelayRecovery = new Map<
|
|
736
|
+
string,
|
|
737
|
+
Promise<{ origin: string } | null>
|
|
738
|
+
>();
|
|
729
739
|
const rateScopes = new Map<
|
|
730
740
|
string,
|
|
731
741
|
{ bucketId: string; provider: string; token: string }
|
|
@@ -783,6 +793,18 @@ function createAppRuntimeToolAuthScopeDigestResolver(
|
|
|
783
793
|
);
|
|
784
794
|
}
|
|
785
795
|
rateScopes.set(normalizedToolId, { bucketId, provider, token });
|
|
796
|
+
if (
|
|
797
|
+
response.headers.get(
|
|
798
|
+
RUNTIME_ASYNC_EXECUTION_RECOVERY_TRANSPORT_HEADER,
|
|
799
|
+
) === 'true' &&
|
|
800
|
+
body.managedAsyncExecutionRecovery === true &&
|
|
801
|
+
typeof body.managedAsyncExecutionRecoveryOrigin === 'string'
|
|
802
|
+
) {
|
|
803
|
+
asyncRecoveryOrigins.set(
|
|
804
|
+
normalizedToolId,
|
|
805
|
+
body.managedAsyncExecutionRecoveryOrigin,
|
|
806
|
+
);
|
|
807
|
+
}
|
|
786
808
|
return digest;
|
|
787
809
|
},
|
|
788
810
|
});
|
|
@@ -793,6 +815,10 @@ function createAppRuntimeToolAuthScopeDigestResolver(
|
|
|
793
815
|
const normalized = String(toolId || '').trim();
|
|
794
816
|
if (normalized) rateScopes.delete(normalized);
|
|
795
817
|
else rateScopes.clear();
|
|
818
|
+
if (normalized) asyncRecoveryOrigins.delete(normalized);
|
|
819
|
+
else asyncRecoveryOrigins.clear();
|
|
820
|
+
if (normalized) executionRelayRecovery.delete(normalized);
|
|
821
|
+
else executionRelayRecovery.clear();
|
|
796
822
|
},
|
|
797
823
|
rateScope: async (toolId: string, expectedProvider: string) => {
|
|
798
824
|
await digestResolver(toolId);
|
|
@@ -804,6 +830,60 @@ function createAppRuntimeToolAuthScopeDigestResolver(
|
|
|
804
830
|
}
|
|
805
831
|
return { bucketId: scope.bucketId, token: scope.token };
|
|
806
832
|
},
|
|
833
|
+
asyncExecutionRecovery: async (toolId: string) => {
|
|
834
|
+
const normalized = toolId.trim();
|
|
835
|
+
const digest = await digestResolver(normalized);
|
|
836
|
+
const receiptBase = config.context.baseUrl!.trim().replace(/\/$/, '');
|
|
837
|
+
const executionBase =
|
|
838
|
+
config.context.executionGatewayBaseUrl?.trim().replace(/\/$/, '') ||
|
|
839
|
+
receiptBase;
|
|
840
|
+
if (executionBase === receiptBase) {
|
|
841
|
+
const origin = asyncRecoveryOrigins.get(normalized);
|
|
842
|
+
return origin ? { origin } : null;
|
|
843
|
+
}
|
|
844
|
+
// Receipt and execution fleets roll independently. Keep canonical
|
|
845
|
+
// digest/rate truth on the receipt owner, but never treat its transport
|
|
846
|
+
// capability as proof that the execution relay forwards the app ACK.
|
|
847
|
+
let proof = executionRelayRecovery.get(normalized);
|
|
848
|
+
if (!proof) {
|
|
849
|
+
proof = (async () => {
|
|
850
|
+
const response = await fetchRunnerRuntimeControl({
|
|
851
|
+
url: `${executionBase}/api/v2/plays/runtime-tools/${encodeURIComponent(normalized)}/auth-scope`,
|
|
852
|
+
description: `Runtime async recovery capability for tool ${normalized}`,
|
|
853
|
+
retrySafe: true,
|
|
854
|
+
init: {
|
|
855
|
+
method: 'GET',
|
|
856
|
+
headers: {
|
|
857
|
+
Authorization: `Bearer ${config.context.executorToken}`,
|
|
858
|
+
...(await vercelBypassHeaders(config)),
|
|
859
|
+
},
|
|
860
|
+
},
|
|
861
|
+
});
|
|
862
|
+
if (
|
|
863
|
+
!response.ok ||
|
|
864
|
+
response.headers.get(
|
|
865
|
+
RUNTIME_ASYNC_EXECUTION_RECOVERY_TRANSPORT_HEADER,
|
|
866
|
+
) !== 'true'
|
|
867
|
+
)
|
|
868
|
+
return null;
|
|
869
|
+
const body = (await response.json()) as RuntimeToolAuthScope;
|
|
870
|
+
return body.digest === digest &&
|
|
871
|
+
body.managedAsyncExecutionRecovery === true &&
|
|
872
|
+
typeof body.managedAsyncExecutionRecoveryOrigin === 'string'
|
|
873
|
+
? { origin: body.managedAsyncExecutionRecoveryOrigin }
|
|
874
|
+
: null;
|
|
875
|
+
})().catch(() => {
|
|
876
|
+
// This optional capability cannot authorize replay on an unavailable
|
|
877
|
+
// hop. Preserve the existing unkeyed path and allow later discovery.
|
|
878
|
+
if (executionRelayRecovery.get(normalized) === proof) {
|
|
879
|
+
executionRelayRecovery.delete(normalized);
|
|
880
|
+
}
|
|
881
|
+
return null;
|
|
882
|
+
});
|
|
883
|
+
executionRelayRecovery.set(normalized, proof);
|
|
884
|
+
}
|
|
885
|
+
return await proof;
|
|
886
|
+
},
|
|
807
887
|
});
|
|
808
888
|
}
|
|
809
889
|
|
|
@@ -1122,11 +1202,19 @@ async function createStreamingCsvDataset(input: {
|
|
|
1122
1202
|
options?: CsvRenameOptions;
|
|
1123
1203
|
}): Promise<PlayDataset<Record<string, unknown>>> {
|
|
1124
1204
|
let cachedCount: number | null = null;
|
|
1205
|
+
const datasetId = createRuntimeDatasetId(
|
|
1206
|
+
input.playName,
|
|
1207
|
+
input.tableNamespace,
|
|
1208
|
+
);
|
|
1125
1209
|
const iterateProjected = () =>
|
|
1126
1210
|
({
|
|
1127
1211
|
async *[Symbol.asyncIterator]() {
|
|
1212
|
+
let rowIndex = 0;
|
|
1128
1213
|
for await (const row of input.source.iterate()) {
|
|
1129
|
-
yield
|
|
1214
|
+
yield setPlayDatasetSourceRowIdentity(
|
|
1215
|
+
applyCsvRenameProjection([row], input.options)[0]!,
|
|
1216
|
+
{ datasetId, rowIndex: rowIndex++ },
|
|
1217
|
+
);
|
|
1130
1218
|
}
|
|
1131
1219
|
},
|
|
1132
1220
|
}) as AsyncIterable<Record<string, unknown>>;
|
|
@@ -1142,7 +1230,7 @@ async function createStreamingCsvDataset(input: {
|
|
|
1142
1230
|
const previewRows = await collect(10);
|
|
1143
1231
|
return createDeferredPlayDataset({
|
|
1144
1232
|
datasetKind: 'csv',
|
|
1145
|
-
datasetId
|
|
1233
|
+
datasetId,
|
|
1146
1234
|
count: 0,
|
|
1147
1235
|
knownCount: null,
|
|
1148
1236
|
previewRows,
|
|
@@ -2204,6 +2292,7 @@ async function run(
|
|
|
2204
2292
|
writeVersion?: number;
|
|
2205
2293
|
}
|
|
2206
2294
|
>();
|
|
2295
|
+
const membershipCapturingMaps = new Set<string>();
|
|
2207
2296
|
const runtimeMapDatasetSettlements = new Map<
|
|
2208
2297
|
string,
|
|
2209
2298
|
{
|
|
@@ -2449,6 +2538,8 @@ async function run(
|
|
|
2449
2538
|
];
|
|
2450
2539
|
},
|
|
2451
2540
|
getToolAuthScopeDigest: getRuntimeToolAuthScopeDigest,
|
|
2541
|
+
getToolAsyncExecutionRecovery:
|
|
2542
|
+
getRuntimeToolAuthScopeDigest.asyncExecutionRecovery,
|
|
2452
2543
|
getToolRateScope: getRuntimeToolAuthScopeDigest.rateScope,
|
|
2453
2544
|
invalidateToolAuthScopeDigest: (toolId) =>
|
|
2454
2545
|
getRuntimeToolAuthScopeDigest.invalidate?.(toolId),
|
|
@@ -2734,6 +2825,8 @@ async function run(
|
|
|
2734
2825
|
},
|
|
2735
2826
|
),
|
|
2736
2827
|
});
|
|
2828
|
+
if (mapStartResult.membershipCapture === true)
|
|
2829
|
+
membershipCapturingMaps.add(attemptKey);
|
|
2737
2830
|
const datasetId = createRuntimeDatasetId(playName, tableNamespace);
|
|
2738
2831
|
const datasetPath = `datasets.${tableNamespace}`;
|
|
2739
2832
|
const settlement = runtimeMapDatasetSettlements.get(datasetId) ?? {
|
|
@@ -2889,11 +2982,66 @@ async function run(
|
|
|
2889
2982
|
),
|
|
2890
2983
|
});
|
|
2891
2984
|
},
|
|
2892
|
-
onMapRowsSettled: (input) => {
|
|
2893
|
-
const
|
|
2894
|
-
|
|
2895
|
-
input.
|
|
2896
|
-
|
|
2985
|
+
onMapRowsSettled: async (input) => {
|
|
2986
|
+
const playName = input.playName ?? config.context.playName!;
|
|
2987
|
+
const runId =
|
|
2988
|
+
input.runId ??
|
|
2989
|
+
config.context.runId ??
|
|
2990
|
+
config.context.workflowId ??
|
|
2991
|
+
'anonymous-run';
|
|
2992
|
+
const mapKey = runtimeSheetAttemptKey({
|
|
2993
|
+
playName,
|
|
2994
|
+
runId,
|
|
2995
|
+
tableNamespace: input.tableNamespace,
|
|
2996
|
+
});
|
|
2997
|
+
if (
|
|
2998
|
+
membershipCapturingMaps.has(mapKey) &&
|
|
2999
|
+
input.expectedRows !== undefined
|
|
3000
|
+
) {
|
|
3001
|
+
const sheetContract = resolveSheetContractForTableNamespace(
|
|
3002
|
+
input.staticPipeline ?? config.context.staticPipeline,
|
|
3003
|
+
input.tableNamespace,
|
|
3004
|
+
);
|
|
3005
|
+
if (!sheetContract)
|
|
3006
|
+
throw new Error(
|
|
3007
|
+
`Missing sheet contract while finishing membership for ${input.tableNamespace}.`,
|
|
3008
|
+
);
|
|
3009
|
+
const canUseRoot =
|
|
3010
|
+
runId === (config.context.runId ?? config.context.workflowId);
|
|
3011
|
+
await retryRuntimeSheetPersistence({
|
|
3012
|
+
description: `runtime membership finish table=${input.tableNamespace}`,
|
|
3013
|
+
log: (line) => emitWorkerLog(line, options),
|
|
3014
|
+
signal: persistenceSignal,
|
|
3015
|
+
run: () =>
|
|
3016
|
+
finishRuntimeSheetRunMembership(
|
|
3017
|
+
{
|
|
3018
|
+
executorToken: config.context.executorToken,
|
|
3019
|
+
baseUrl: config.context.baseUrl!,
|
|
3020
|
+
orgId: config.context.orgId!,
|
|
3021
|
+
playName,
|
|
3022
|
+
runId,
|
|
3023
|
+
userEmail: config.context.userEmail,
|
|
3024
|
+
vercelProtectionBypassToken:
|
|
3025
|
+
config.context.vercelProtectionBypassToken,
|
|
3026
|
+
dbSessionStrategy: config.context.dbSessionStrategy,
|
|
3027
|
+
preloadedDbSessions: canUseRoot
|
|
3028
|
+
? runtimePreloadedDbSessions
|
|
3029
|
+
: undefined,
|
|
3030
|
+
postgresSessionUnwrapKey: canUseRoot
|
|
3031
|
+
? runtimePostgresSessionUnwrapKey
|
|
3032
|
+
: config.context.executorToken,
|
|
3033
|
+
abortSignal: persistenceSignal,
|
|
3034
|
+
},
|
|
3035
|
+
{
|
|
3036
|
+
runId,
|
|
3037
|
+
tableNamespace: input.tableNamespace,
|
|
3038
|
+
sheetContract,
|
|
3039
|
+
expectedRows: input.expectedRows!,
|
|
3040
|
+
},
|
|
3041
|
+
),
|
|
3042
|
+
});
|
|
3043
|
+
}
|
|
3044
|
+
const datasetId = createRuntimeDatasetId(playName, input.tableNamespace);
|
|
2897
3045
|
const settlement = runtimeMapDatasetSettlements.get(datasetId);
|
|
2898
3046
|
if (settlement && (!input.runId || settlement.runId === input.runId)) {
|
|
2899
3047
|
Object.assign(
|