deepline 0.1.210 → 0.1.212
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/apps/play-runner-workers/src/entry.ts +203 -12
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +23 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +15 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-latency-profile.ts +90 -0
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +162 -100
- package/dist/bundling-sources/sdk/src/client.ts +118 -3
- package/dist/bundling-sources/sdk/src/play.ts +2 -0
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/sdk/src/types.ts +47 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +253 -30
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +365 -103
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-runtime/dataset-id.ts +10 -4
- package/dist/bundling-sources/shared_libs/play-runtime/db-session.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +45 -8
- package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +14 -2
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +4 -2
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-sql.ts +21 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +128 -6
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +5 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +37 -5
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +19 -10
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +63 -7
- package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +18 -4
- package/dist/bundling-sources/shared_libs/play-runtime/single-flight.ts +31 -0
- package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +12 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +29 -9
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-state-machine.ts +22 -1
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +79 -1
- package/dist/bundling-sources/shared_libs/plays/dataset.ts +41 -5
- package/dist/cli/index.js +728 -239
- package/dist/cli/index.mjs +728 -239
- package/dist/index.d.mts +93 -7
- package/dist/index.d.ts +93 -7
- package/dist/index.js +245 -46
- package/dist/index.mjs +245 -46
- package/dist/plays/bundle-play-file.mjs +65 -4
- package/package.json +1 -1
|
@@ -229,7 +229,7 @@ type WorkerToolCompletionResult =
|
|
|
229
229
|
const WORKER_TOOL_BATCH_GRACE_MS = 250;
|
|
230
230
|
const COMPLETE_RECEIPT_RETRY_BACKOFFS_MS = [1_000, 3_000, 9_000] as const;
|
|
231
231
|
const COMPLETE_RECEIPT_RETRY_MIN_HEADROOM_MS = 10_000;
|
|
232
|
-
export const WORKER_TOOL_COMPLETE_RECEIPTS_MAX_BATCH_BYTES =
|
|
232
|
+
export const WORKER_TOOL_COMPLETE_RECEIPTS_MAX_BATCH_BYTES = 32 * 1024 * 1024;
|
|
233
233
|
export const WORKER_TOOL_COMPLETE_RECEIPTS_MAX_BATCH_MEMBERS = 500;
|
|
234
234
|
export const WORKER_TOOL_RECEIPT_RECOVERY_MAX_CONCURRENT_READS = 25;
|
|
235
235
|
|
|
@@ -2000,8 +2000,14 @@ export class WorkerToolBatchScheduler {
|
|
|
2000
2000
|
toolId: string,
|
|
2001
2001
|
requests: WorkerToolBatchRequest[],
|
|
2002
2002
|
): Promise<void> {
|
|
2003
|
+
const receiptPrepareStartedAt = this.options.nowMs();
|
|
2003
2004
|
const { claimedRequests, deferredClaimedRequests } =
|
|
2004
2005
|
await this.prepareDurableToolRequests(requests);
|
|
2006
|
+
this.options.recordPerfTrace?.({
|
|
2007
|
+
phase: 'runner.tool.receipt_prepare',
|
|
2008
|
+
ms: this.options.nowMs() - receiptPrepareStartedAt,
|
|
2009
|
+
extra: { toolId, requests: requests.length },
|
|
2010
|
+
});
|
|
2005
2011
|
await this.executeClaimedToolRequests(
|
|
2006
2012
|
toolId,
|
|
2007
2013
|
requests.length,
|
|
@@ -2071,6 +2077,7 @@ export class WorkerToolBatchScheduler {
|
|
|
2071
2077
|
// charges tool budget, holds a global tool-concurrency slot, and
|
|
2072
2078
|
// applies per-(org,provider) pacing before the call runs.
|
|
2073
2079
|
let slot: { release: () => void };
|
|
2080
|
+
const admissionStartedAt = this.options.nowMs();
|
|
2074
2081
|
try {
|
|
2075
2082
|
slot = await this.options.governor.acquireToolSlot(toolId, {
|
|
2076
2083
|
signal: this.options.abortSignal,
|
|
@@ -2082,6 +2089,11 @@ export class WorkerToolBatchScheduler {
|
|
|
2082
2089
|
);
|
|
2083
2090
|
return;
|
|
2084
2091
|
}
|
|
2092
|
+
this.options.recordPerfTrace?.({
|
|
2093
|
+
phase: 'runner.tool.admission',
|
|
2094
|
+
ms: this.options.nowMs() - admissionStartedAt,
|
|
2095
|
+
extra: { toolId, requests: 1 },
|
|
2096
|
+
});
|
|
2085
2097
|
try {
|
|
2086
2098
|
let result: unknown;
|
|
2087
2099
|
try {
|
|
@@ -2100,59 +2112,68 @@ export class WorkerToolBatchScheduler {
|
|
|
2100
2112
|
claimed,
|
|
2101
2113
|
})
|
|
2102
2114
|
: null;
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
this.options.
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
this.
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2115
|
+
const providerStartedAt = this.options.nowMs();
|
|
2116
|
+
try {
|
|
2117
|
+
result = await executeWithWorkerReceiptHeartbeats({
|
|
2118
|
+
playName: this.options.req.playName,
|
|
2119
|
+
runId: this.options.req.runId,
|
|
2120
|
+
runAttempt: this.options.req.runAttempt ?? 0,
|
|
2121
|
+
...(this.options.receiptStore
|
|
2122
|
+
? { receiptStore: this.options.receiptStore }
|
|
2123
|
+
: {}),
|
|
2124
|
+
budgetMeter: this.options.budgetMeter,
|
|
2125
|
+
heartbeatIntervalMs:
|
|
2126
|
+
this.options.runtimeReceiptHeartbeatIntervalMs,
|
|
2127
|
+
targets: claimed.receiptKey
|
|
2128
|
+
? [
|
|
2129
|
+
{
|
|
2130
|
+
key: claimed.receiptKey,
|
|
2131
|
+
leaseId: claimed.receiptLeaseId,
|
|
2132
|
+
},
|
|
2133
|
+
]
|
|
2134
|
+
: [],
|
|
2135
|
+
execute: () =>
|
|
2136
|
+
this.options.executeTool({
|
|
2137
|
+
id: request.id,
|
|
2138
|
+
toolId,
|
|
2139
|
+
input: request.input,
|
|
2140
|
+
workflowStep: request.workflowStep,
|
|
2141
|
+
callbacks: this.options.callbacks,
|
|
2142
|
+
onProviderBackpressure: (retryAfterMs) =>
|
|
2143
|
+
this.reportBackpressure(toolId, retryAfterMs),
|
|
2144
|
+
onRetryAttempt: () =>
|
|
2145
|
+
this.options.governor.chargeBudget('retry'),
|
|
2146
|
+
transientHttpRetrySafe:
|
|
2147
|
+
toolContract?.retrySafeTransientHttp === true,
|
|
2148
|
+
...(durableReceiptKey
|
|
2149
|
+
? {
|
|
2150
|
+
durableCallReceiptKey: durableReceiptKey,
|
|
2151
|
+
executionAuthScopeDigest:
|
|
2152
|
+
request.executionAuthScopeDigest,
|
|
2153
|
+
providerIdempotencyKey:
|
|
2154
|
+
providerIdempotencyKeyForClaimed({
|
|
2155
|
+
req: this.options.req,
|
|
2156
|
+
claimed,
|
|
2157
|
+
}),
|
|
2158
|
+
}
|
|
2159
|
+
: {}),
|
|
2160
|
+
runtimeTimeoutMs: resolveWorkerToolRuntimeTimeoutMs(
|
|
2161
|
+
[claimed],
|
|
2162
|
+
{
|
|
2163
|
+
resolveOwnerTimeoutMs: (request) =>
|
|
2164
|
+
request.runtimeTimeoutMs,
|
|
2165
|
+
},
|
|
2166
|
+
),
|
|
2167
|
+
directOptions: request.directOptions,
|
|
2168
|
+
}),
|
|
2169
|
+
});
|
|
2170
|
+
} finally {
|
|
2171
|
+
this.options.recordPerfTrace?.({
|
|
2172
|
+
phase: 'runner.tool.provider',
|
|
2173
|
+
ms: this.options.nowMs() - providerStartedAt,
|
|
2174
|
+
extra: { toolId, requests: 1 },
|
|
2175
|
+
});
|
|
2176
|
+
}
|
|
2156
2177
|
} catch (error) {
|
|
2157
2178
|
if (error instanceof RuntimeLeaseLostError) {
|
|
2158
2179
|
this.rejectRequests(claimed, error);
|
|
@@ -2173,10 +2194,16 @@ export class WorkerToolBatchScheduler {
|
|
|
2173
2194
|
return;
|
|
2174
2195
|
}
|
|
2175
2196
|
try {
|
|
2197
|
+
const receiptCompleteStartedAt = this.options.nowMs();
|
|
2176
2198
|
this.settleRequests(
|
|
2177
2199
|
claimed,
|
|
2178
2200
|
await this.completeDurableToolRequest(claimed, result),
|
|
2179
2201
|
);
|
|
2202
|
+
this.options.recordPerfTrace?.({
|
|
2203
|
+
phase: 'runner.tool.receipt_complete',
|
|
2204
|
+
ms: this.options.nowMs() - receiptCompleteStartedAt,
|
|
2205
|
+
extra: { toolId, requests: 1 },
|
|
2206
|
+
});
|
|
2180
2207
|
} catch (receiptError) {
|
|
2181
2208
|
this.rejectRequests(claimed, receiptError);
|
|
2182
2209
|
}
|
|
@@ -2261,12 +2288,22 @@ export class WorkerToolBatchScheduler {
|
|
|
2261
2288
|
}
|
|
2262
2289
|
// One provider call per batch -> one tool slot (budget + global
|
|
2263
2290
|
// concurrency + per-(org,provider) pacing) around the whole batch.
|
|
2291
|
+
const admissionStartedAt = this.options.nowMs();
|
|
2264
2292
|
const slot = await this.options.governor.acquireToolSlot(
|
|
2265
2293
|
batch.batchOperation,
|
|
2266
2294
|
{
|
|
2267
2295
|
signal: this.options.abortSignal,
|
|
2268
2296
|
},
|
|
2269
2297
|
);
|
|
2298
|
+
this.options.recordPerfTrace?.({
|
|
2299
|
+
phase: 'runner.tool.admission',
|
|
2300
|
+
ms: this.options.nowMs() - admissionStartedAt,
|
|
2301
|
+
extra: {
|
|
2302
|
+
toolId: batch.batchOperation,
|
|
2303
|
+
requests: batch.memberRequests.length,
|
|
2304
|
+
batched: true,
|
|
2305
|
+
},
|
|
2306
|
+
});
|
|
2270
2307
|
try {
|
|
2271
2308
|
await this.markAdmittedToolRequestsRunning(batch.memberRequests);
|
|
2272
2309
|
this.options.budgetMeter?.count('provider');
|
|
@@ -2281,54 +2318,69 @@ export class WorkerToolBatchScheduler {
|
|
|
2281
2318
|
batchOperation: batch.batchOperation,
|
|
2282
2319
|
receiptKeys,
|
|
2283
2320
|
});
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
+
const providerStartedAt = this.options.nowMs();
|
|
2322
|
+
try {
|
|
2323
|
+
return await executeWithWorkerReceiptHeartbeats({
|
|
2324
|
+
playName: this.options.req.playName,
|
|
2325
|
+
runId: this.options.req.runId,
|
|
2326
|
+
runAttempt: this.options.req.runAttempt ?? 0,
|
|
2327
|
+
...(this.options.receiptStore
|
|
2328
|
+
? { receiptStore: this.options.receiptStore }
|
|
2329
|
+
: {}),
|
|
2330
|
+
budgetMeter: this.options.budgetMeter,
|
|
2331
|
+
heartbeatIntervalMs:
|
|
2332
|
+
this.options.runtimeReceiptHeartbeatIntervalMs,
|
|
2333
|
+
targets: batch.memberRequests.map((member) => ({
|
|
2334
|
+
key: member.receiptKey,
|
|
2335
|
+
leaseId: member.receiptLeaseId,
|
|
2336
|
+
})),
|
|
2337
|
+
execute: () =>
|
|
2338
|
+
this.options.executeTool({
|
|
2339
|
+
id: `batch:${batch.memberRequests.map((request) => request.request.id).join('|')}`,
|
|
2340
|
+
toolId: batch.batchOperation,
|
|
2341
|
+
input: batch.batchPayload,
|
|
2342
|
+
callbacks: this.options.callbacks,
|
|
2343
|
+
onProviderBackpressure: (retryAfterMs) =>
|
|
2344
|
+
this.reportBackpressure(input.sourceToolId, retryAfterMs),
|
|
2345
|
+
onRetryAttempt: () =>
|
|
2346
|
+
this.options.governor.chargeBudget('retry'),
|
|
2347
|
+
transientHttpRetrySafe:
|
|
2348
|
+
toolContract?.retrySafeTransientHttp === true,
|
|
2349
|
+
durableCallReceiptKey: aggregateReceiptKey,
|
|
2350
|
+
executionAuthScopeDigest:
|
|
2351
|
+
batch.memberRequests[0]?.request.executionAuthScopeDigest ??
|
|
2352
|
+
null,
|
|
2353
|
+
providerIdempotencyKey: buildBatchProviderIdempotencyKey({
|
|
2354
|
+
aggregateReceiptKey,
|
|
2355
|
+
receiptKeys,
|
|
2356
|
+
providerIdempotencyKeys: batch.memberRequests.map(
|
|
2357
|
+
(member) =>
|
|
2358
|
+
providerIdempotencyKeyForClaimed({
|
|
2359
|
+
req: this.options.req,
|
|
2360
|
+
claimed: member,
|
|
2361
|
+
}),
|
|
2362
|
+
),
|
|
2363
|
+
}),
|
|
2364
|
+
runtimeTimeoutMs: resolveWorkerToolRuntimeTimeoutMs(
|
|
2365
|
+
batch.memberRequests,
|
|
2366
|
+
{
|
|
2367
|
+
resolveOwnerTimeoutMs: (request) =>
|
|
2368
|
+
request.runtimeTimeoutMs,
|
|
2369
|
+
},
|
|
2321
2370
|
),
|
|
2322
2371
|
}),
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2372
|
+
});
|
|
2373
|
+
} finally {
|
|
2374
|
+
this.options.recordPerfTrace?.({
|
|
2375
|
+
phase: 'runner.tool.provider',
|
|
2376
|
+
ms: this.options.nowMs() - providerStartedAt,
|
|
2377
|
+
extra: {
|
|
2378
|
+
toolId: batch.batchOperation,
|
|
2379
|
+
requests: batch.memberRequests.length,
|
|
2380
|
+
batched: true,
|
|
2381
|
+
},
|
|
2382
|
+
});
|
|
2383
|
+
}
|
|
2332
2384
|
} finally {
|
|
2333
2385
|
slot.release();
|
|
2334
2386
|
}
|
|
@@ -2389,6 +2441,7 @@ export class WorkerToolBatchScheduler {
|
|
|
2389
2441
|
: entry.request.memberRequests.map(() => null);
|
|
2390
2442
|
let completedResults: WorkerToolCompletionResult[];
|
|
2391
2443
|
try {
|
|
2444
|
+
const receiptCompleteStartedAt = this.options.nowMs();
|
|
2392
2445
|
completedResults = await this.completeDurableToolRequests(
|
|
2393
2446
|
entry.request.memberRequests.map((claimed, index) => ({
|
|
2394
2447
|
claimed,
|
|
@@ -2399,6 +2452,15 @@ export class WorkerToolBatchScheduler {
|
|
|
2399
2452
|
),
|
|
2400
2453
|
})),
|
|
2401
2454
|
);
|
|
2455
|
+
this.options.recordPerfTrace?.({
|
|
2456
|
+
phase: 'runner.tool.receipt_complete',
|
|
2457
|
+
ms: this.options.nowMs() - receiptCompleteStartedAt,
|
|
2458
|
+
extra: {
|
|
2459
|
+
toolId: entry.request.batchOperation,
|
|
2460
|
+
requests: entry.request.memberRequests.length,
|
|
2461
|
+
batched: true,
|
|
2462
|
+
},
|
|
2463
|
+
});
|
|
2402
2464
|
} catch (receiptError) {
|
|
2403
2465
|
for (const claimed of entry.request.memberRequests) {
|
|
2404
2466
|
this.rejectRequests(claimed, receiptError);
|
|
@@ -282,9 +282,23 @@ export type RunsListOptions = {
|
|
|
282
282
|
limit?: number;
|
|
283
283
|
};
|
|
284
284
|
|
|
285
|
+
/** Options for `client.runs.get(...)`. */
|
|
286
|
+
export type RunsGetOptions = {
|
|
287
|
+
/** Return the raw status payload instead of the compact package. */
|
|
288
|
+
full?: boolean;
|
|
289
|
+
/** Attach a bounded end-of-stream window for a failed run. */
|
|
290
|
+
failedLogs?: boolean;
|
|
291
|
+
/** Requested failed-log lines to attach (default 20, hard-capped at 20). */
|
|
292
|
+
failedLogLimit?: number;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const RUNS_FAILED_LOG_LIMIT = 20;
|
|
296
|
+
|
|
285
297
|
/** Streaming options for `client.runs.tail(...)`. */
|
|
286
298
|
export type RunsTailOptions = {
|
|
287
299
|
signal?: AbortSignal;
|
|
300
|
+
/** Observe each canonical live event while `tail` waits for terminal state. */
|
|
301
|
+
onEvent?: (event: PlayLiveEvent) => void;
|
|
288
302
|
/**
|
|
289
303
|
* Called before each stream reconnect. Server stream windows are finite, so
|
|
290
304
|
* long runs reconnect with backoff until a terminal status is observed.
|
|
@@ -308,6 +322,8 @@ export type RunsLogsOptions = {
|
|
|
308
322
|
limit?: number;
|
|
309
323
|
/** Fetch every stored log line, paginating to the full totalCount. */
|
|
310
324
|
all?: boolean;
|
|
325
|
+
/** Select the bounded failure view; truncated runs degrade explicitly. */
|
|
326
|
+
failed?: boolean;
|
|
311
327
|
};
|
|
312
328
|
|
|
313
329
|
/** Persisted log response for one play run. */
|
|
@@ -320,6 +336,14 @@ export type RunsLogsResult = {
|
|
|
320
336
|
truncated: boolean;
|
|
321
337
|
hasMore: boolean;
|
|
322
338
|
entries: string[];
|
|
339
|
+
/** Selected public log view. */
|
|
340
|
+
view?: 'tail' | 'failed' | 'all';
|
|
341
|
+
/** Whether entries are terminal context or the last pre-truncation lines. */
|
|
342
|
+
association?: 'terminal_failure_window' | 'retained_before_truncation';
|
|
343
|
+
/** Loud explanation when the terminal failure window was not retained. */
|
|
344
|
+
warning?: string;
|
|
345
|
+
/** Exact follow-up command when the selected view is degraded. */
|
|
346
|
+
next?: { logs: string };
|
|
323
347
|
/**
|
|
324
348
|
* True when the run crossed the Run Log Stream retention cap: `totalCount`
|
|
325
349
|
* keeps counting, but stored line bodies end at a loud truncation marker.
|
|
@@ -342,6 +366,10 @@ type RunLogsPageResponse = {
|
|
|
342
366
|
lastSeq: number | null;
|
|
343
367
|
hasMore: boolean;
|
|
344
368
|
nextAfterSeq: number | null;
|
|
369
|
+
view?: 'failed';
|
|
370
|
+
association?: 'terminal_failure_window' | 'retained_before_truncation';
|
|
371
|
+
warning?: string;
|
|
372
|
+
next?: { logs: string };
|
|
345
373
|
};
|
|
346
374
|
|
|
347
375
|
/** One persisted runtime-sheet row returned by `client.runs.exportDatasetRows(...)`. */
|
|
@@ -395,7 +423,7 @@ export type PlaySecretMetadata = {
|
|
|
395
423
|
*/
|
|
396
424
|
export type RunsNamespace = {
|
|
397
425
|
/** Get current run status by public run id. */
|
|
398
|
-
get: (runId: string, options?:
|
|
426
|
+
get: (runId: string, options?: RunsGetOptions) => Promise<PlayStatus>;
|
|
399
427
|
/** List runs for one play, optionally filtered by status. */
|
|
400
428
|
list: (options: RunsListOptions) => Promise<PlayRunListItem[]>;
|
|
401
429
|
/** Stream run events and return the latest/terminal run status. */
|
|
@@ -2469,7 +2497,7 @@ export class DeeplineClient {
|
|
|
2469
2497
|
*/
|
|
2470
2498
|
async getRunStatus(
|
|
2471
2499
|
runId: string,
|
|
2472
|
-
options?:
|
|
2500
|
+
options?: RunsGetOptions,
|
|
2473
2501
|
): Promise<PlayStatus> {
|
|
2474
2502
|
const params = new URLSearchParams();
|
|
2475
2503
|
if (options?.full === true) {
|
|
@@ -2479,7 +2507,55 @@ export class DeeplineClient {
|
|
|
2479
2507
|
const response = await this.http.get<Record<string, unknown>>(
|
|
2480
2508
|
`/api/v2/runs/${encodeURIComponent(runId)}${query}`,
|
|
2481
2509
|
);
|
|
2482
|
-
|
|
2510
|
+
const status = normalizePlayStatus(response);
|
|
2511
|
+
if (options?.failedLogs !== true || status.status !== 'failed') {
|
|
2512
|
+
return status;
|
|
2513
|
+
}
|
|
2514
|
+
const requestedFailedLogLimit =
|
|
2515
|
+
typeof options.failedLogLimit === 'number' &&
|
|
2516
|
+
Number.isFinite(options.failedLogLimit)
|
|
2517
|
+
? Math.max(1, Math.floor(options.failedLogLimit))
|
|
2518
|
+
: RUNS_FAILED_LOG_LIMIT;
|
|
2519
|
+
let failedLogs: RunsLogsResult;
|
|
2520
|
+
let failedLogsLoaded = true;
|
|
2521
|
+
try {
|
|
2522
|
+
failedLogs = await this.getRunLogs(runId, {
|
|
2523
|
+
failed: true,
|
|
2524
|
+
limit: Math.min(RUNS_FAILED_LOG_LIMIT, requestedFailedLogLimit),
|
|
2525
|
+
});
|
|
2526
|
+
} catch (error) {
|
|
2527
|
+
failedLogsLoaded = false;
|
|
2528
|
+
const retryCommand = `deepline runs get ${runId} --log-failed --json`;
|
|
2529
|
+
const reason =
|
|
2530
|
+
error instanceof Error && error.message.trim()
|
|
2531
|
+
? ` (${error.message.trim().slice(0, 500)})`
|
|
2532
|
+
: '';
|
|
2533
|
+
failedLogs = {
|
|
2534
|
+
runId,
|
|
2535
|
+
totalCount: 0,
|
|
2536
|
+
returnedCount: 0,
|
|
2537
|
+
firstSequence: null,
|
|
2538
|
+
lastSequence: null,
|
|
2539
|
+
truncated: false,
|
|
2540
|
+
hasMore: false,
|
|
2541
|
+
entries: [],
|
|
2542
|
+
view: 'failed',
|
|
2543
|
+
warning: `Failed logs could not be loaded${reason}. The run status and persisted datasets are still available.`,
|
|
2544
|
+
next: { logs: retryCommand },
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
return {
|
|
2548
|
+
...status,
|
|
2549
|
+
failedLogs: {
|
|
2550
|
+
...failedLogs,
|
|
2551
|
+
view: 'failed' as const,
|
|
2552
|
+
...(failedLogsLoaded
|
|
2553
|
+
? {
|
|
2554
|
+
association: failedLogs.association ?? 'terminal_failure_window',
|
|
2555
|
+
}
|
|
2556
|
+
: {}),
|
|
2557
|
+
},
|
|
2558
|
+
};
|
|
2483
2559
|
}
|
|
2484
2560
|
|
|
2485
2561
|
/**
|
|
@@ -2657,6 +2733,7 @@ export class DeeplineClient {
|
|
|
2657
2733
|
onNotice: options?.onNotice,
|
|
2658
2734
|
fallback: 'none',
|
|
2659
2735
|
})) {
|
|
2736
|
+
options?.onEvent?.(event);
|
|
2660
2737
|
const status = updatePlayLiveStatusState(state, event);
|
|
2661
2738
|
if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
2662
2739
|
continue;
|
|
@@ -2725,6 +2802,7 @@ export class DeeplineClient {
|
|
|
2725
2802
|
mode: 'cli',
|
|
2726
2803
|
signal: options?.signal,
|
|
2727
2804
|
})) {
|
|
2805
|
+
options?.onEvent?.(event);
|
|
2728
2806
|
sawEvent = true;
|
|
2729
2807
|
const status = updatePlayLiveStatusState(state, event);
|
|
2730
2808
|
if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
@@ -2786,6 +2864,42 @@ export class DeeplineClient {
|
|
|
2786
2864
|
runId: string,
|
|
2787
2865
|
options?: RunsLogsOptions,
|
|
2788
2866
|
): Promise<RunsLogsResult> {
|
|
2867
|
+
if (options?.all === true && options.failed === true) {
|
|
2868
|
+
throw new DeeplineError(
|
|
2869
|
+
'runs.logs cannot combine all and failed views.',
|
|
2870
|
+
undefined,
|
|
2871
|
+
'INVALID_RUN_LOG_VIEW',
|
|
2872
|
+
);
|
|
2873
|
+
}
|
|
2874
|
+
if (options?.failed === true) {
|
|
2875
|
+
const requestedLimit =
|
|
2876
|
+
typeof options.limit === 'number' &&
|
|
2877
|
+
Number.isFinite(options.limit) &&
|
|
2878
|
+
options.limit > 0
|
|
2879
|
+
? Math.trunc(options.limit)
|
|
2880
|
+
: RUNS_FAILED_LOG_LIMIT;
|
|
2881
|
+
const failedLimit = Math.min(RUNS_FAILED_LOG_LIMIT, requestedLimit);
|
|
2882
|
+
const page = await this.http.get<RunLogsPageResponse>(
|
|
2883
|
+
`/api/v2/runs/${encodeURIComponent(runId)}/logs?view=failed&limit=${failedLimit}`,
|
|
2884
|
+
);
|
|
2885
|
+
return {
|
|
2886
|
+
runId: page.runId,
|
|
2887
|
+
totalCount: page.totalLogCount,
|
|
2888
|
+
returnedCount: page.entries.length,
|
|
2889
|
+
firstSequence: page.firstSeq,
|
|
2890
|
+
lastSequence: page.lastSeq,
|
|
2891
|
+
// The failed view is a complete designed window, not a pageable slice.
|
|
2892
|
+
// `truncated` means retention loss here; association/warning explain it.
|
|
2893
|
+
truncated: page.logsTruncated === true,
|
|
2894
|
+
hasMore: false,
|
|
2895
|
+
entries: page.entries.map((entry) => entry.line),
|
|
2896
|
+
view: page.view ?? 'failed',
|
|
2897
|
+
association: page.association ?? 'terminal_failure_window',
|
|
2898
|
+
...(page.warning ? { warning: page.warning } : {}),
|
|
2899
|
+
...(page.next ? { next: page.next } : {}),
|
|
2900
|
+
...(page.logsTruncated ? { logsTruncated: true } : {}),
|
|
2901
|
+
};
|
|
2902
|
+
}
|
|
2789
2903
|
const limit = options?.all
|
|
2790
2904
|
? Number.MAX_SAFE_INTEGER
|
|
2791
2905
|
: typeof options?.limit === 'number' &&
|
|
@@ -2830,6 +2944,7 @@ export class DeeplineClient {
|
|
|
2830
2944
|
truncated: entries.length < probe.totalLogCount,
|
|
2831
2945
|
hasMore: lastSequence !== null && lastSequence < lastStoredSeq,
|
|
2832
2946
|
entries: entries.map((entry) => entry.line),
|
|
2947
|
+
view: options?.all ? 'all' : 'tail',
|
|
2833
2948
|
...(probe.logsTruncated ? { logsTruncated: true } : {}),
|
|
2834
2949
|
};
|
|
2835
2950
|
}
|
|
@@ -173,6 +173,8 @@ export type PlayBindings = {
|
|
|
173
173
|
* older clients can continue to register revisions during the migration.
|
|
174
174
|
*/
|
|
175
175
|
description?: string;
|
|
176
|
+
/** Allow compilers to bundle this named handler directly without a child run. */
|
|
177
|
+
inline?: boolean;
|
|
176
178
|
/** Optional per-run billing controls enforced by the runtime. */
|
|
177
179
|
billing?: {
|
|
178
180
|
/** Stop the run before a billed action would push total run credits above this cap. */
|
|
@@ -39,7 +39,7 @@ export type {
|
|
|
39
39
|
|
|
40
40
|
export { extractDefinedPlayName } from '../../../shared_libs/plays/bundling/index.js';
|
|
41
41
|
|
|
42
|
-
const PLAY_BUNDLE_CACHE_VERSION =
|
|
42
|
+
const PLAY_BUNDLE_CACHE_VERSION = 31;
|
|
43
43
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
44
44
|
const SDK_PACKAGE_ROOT = resolve(MODULE_DIR, '..', '..');
|
|
45
45
|
const SOURCE_REPO_ROOT = resolve(SDK_PACKAGE_ROOT, '..');
|
|
@@ -106,10 +106,10 @@ export const SDK_RELEASE = {
|
|
|
106
106
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
107
107
|
// fields shipped in 0.1.153.
|
|
108
108
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
109
|
-
version: '0.1.
|
|
109
|
+
version: '0.1.212',
|
|
110
110
|
apiContract: '2026-06-dataset-handle-results-hard-cutover',
|
|
111
111
|
supportPolicy: {
|
|
112
|
-
latest: '0.1.
|
|
112
|
+
latest: '0.1.212',
|
|
113
113
|
minimumSupported: '0.1.53',
|
|
114
114
|
deprecatedBelow: '0.1.53',
|
|
115
115
|
commandMinimumSupported: [
|
|
@@ -463,6 +463,14 @@ export type PlayRunActionPackage =
|
|
|
463
463
|
runId: string;
|
|
464
464
|
datasetPath: string;
|
|
465
465
|
format: 'csv';
|
|
466
|
+
}
|
|
467
|
+
| {
|
|
468
|
+
kind: 'deepline_run_logs';
|
|
469
|
+
runId: string;
|
|
470
|
+
view: 'failed' | 'tail';
|
|
471
|
+
limit: number;
|
|
472
|
+
command: string;
|
|
473
|
+
api: { method: 'GET'; path: string };
|
|
466
474
|
};
|
|
467
475
|
|
|
468
476
|
/**
|
|
@@ -493,11 +501,30 @@ export interface PlayRunPackage {
|
|
|
493
501
|
steps: Array<Record<string, unknown>>;
|
|
494
502
|
/** Named output summaries, including dataset handles and scalar outputs. */
|
|
495
503
|
outputs: Record<string, Record<string, unknown>>;
|
|
504
|
+
/** Every durable Dataset Handle explicitly registered by this run. */
|
|
505
|
+
datasets?: Array<{
|
|
506
|
+
kind: 'dataset';
|
|
507
|
+
datasetId?: string;
|
|
508
|
+
path: string;
|
|
509
|
+
tableNamespace?: string;
|
|
510
|
+
rowCount?: number;
|
|
511
|
+
recovered?: true;
|
|
512
|
+
preview?: Record<string, unknown>;
|
|
513
|
+
actions?: Record<string, PlayRunActionPackage>;
|
|
514
|
+
}>;
|
|
515
|
+
/** Small retained tail of customer and runtime logs; fetch the full stream through `runs.logs`. */
|
|
516
|
+
logs?: {
|
|
517
|
+
tail: string[];
|
|
518
|
+
totalCount: number;
|
|
519
|
+
returnedCount: number;
|
|
520
|
+
truncated?: boolean;
|
|
521
|
+
};
|
|
496
522
|
/** Follow-up actions a caller can perform against the run. */
|
|
497
523
|
next?: {
|
|
498
524
|
inspect?: PlayRunActionPackage;
|
|
499
525
|
export?: PlayRunActionPackage;
|
|
500
526
|
query?: PlayRunActionPackage;
|
|
527
|
+
logs?: PlayRunActionPackage;
|
|
501
528
|
};
|
|
502
529
|
}
|
|
503
530
|
|
|
@@ -524,6 +551,8 @@ export interface PlayStatus {
|
|
|
524
551
|
apiVersion?: number;
|
|
525
552
|
/** Saved play name for this run, when available. */
|
|
526
553
|
name?: string;
|
|
554
|
+
/** Exact saved revision launched for this run, when applicable. */
|
|
555
|
+
revisionId?: string;
|
|
527
556
|
/** Alias for `name` used by run/result APIs. */
|
|
528
557
|
playName?: string;
|
|
529
558
|
/** Dashboard URL for inspecting the play and its run output in the app. */
|
|
@@ -564,6 +593,24 @@ export interface PlayStatus {
|
|
|
564
593
|
} | null;
|
|
565
594
|
/** Structured follow-up actions for inspect/query/export. */
|
|
566
595
|
next?: PlayRunPackage['next'] | Record<string, unknown>;
|
|
596
|
+
/** Bounded terminal-failure log window requested by `runs.get`. */
|
|
597
|
+
failedLogs?: {
|
|
598
|
+
runId: string;
|
|
599
|
+
totalCount: number;
|
|
600
|
+
returnedCount: number;
|
|
601
|
+
firstSequence: number | null;
|
|
602
|
+
lastSequence: number | null;
|
|
603
|
+
truncated: boolean;
|
|
604
|
+
hasMore: boolean;
|
|
605
|
+
entries: string[];
|
|
606
|
+
view?: 'failed';
|
|
607
|
+
association?: 'terminal_failure_window' | 'retained_before_truncation';
|
|
608
|
+
warning?: string;
|
|
609
|
+
next?: { logs: string };
|
|
610
|
+
logsTruncated?: boolean;
|
|
611
|
+
};
|
|
612
|
+
/** Exact ordinary `plays run` command that can rerun a failed execution. */
|
|
613
|
+
rerunCommand?: string;
|
|
567
614
|
}
|
|
568
615
|
|
|
569
616
|
export type LiveEventScope = 'play' | 'agent';
|