deepline 0.1.190 → 0.1.192
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/coordinator-entry.ts +144 -10
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +24 -9
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +5 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +1 -3
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +2 -2
- package/dist/cli/index.js +64 -13
- package/dist/cli/index.mjs +74 -21
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
|
@@ -131,6 +131,8 @@ export type PlayWorkflowParams = {
|
|
|
131
131
|
dynamicWorkerCode?: string | null;
|
|
132
132
|
executorToken: string;
|
|
133
133
|
baseUrl: string;
|
|
134
|
+
runtimeApiBaseUrl?: string | null;
|
|
135
|
+
callbackUrl?: string | null;
|
|
134
136
|
integrationMode?: 'live' | 'eval_stub' | 'fixture' | null;
|
|
135
137
|
orgId: string;
|
|
136
138
|
userEmail: string;
|
|
@@ -402,6 +404,15 @@ function recordCoordinatorPerfTrace(event: CoordinatorPerfTraceInput): void {
|
|
|
402
404
|
logCoordinatorPerfTrace(payload);
|
|
403
405
|
}
|
|
404
406
|
|
|
407
|
+
function safeOrigin(value: string | null | undefined): string | null {
|
|
408
|
+
if (!value?.trim()) return null;
|
|
409
|
+
try {
|
|
410
|
+
return new URL(value).origin;
|
|
411
|
+
} catch {
|
|
412
|
+
return '<invalid>';
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
405
416
|
async function appendCoordinatorPerfTrace(
|
|
406
417
|
env: CoordinatorEnv,
|
|
407
418
|
payload: CoordinatorPerfTracePayload,
|
|
@@ -1330,9 +1341,23 @@ async function markWorkflowRuntimeFailure(input: {
|
|
|
1330
1341
|
const backoffMs = [200, 500, 1500];
|
|
1331
1342
|
let lastError: unknown = null;
|
|
1332
1343
|
for (let attempt = 0; attempt <= backoffMs.length; attempt += 1) {
|
|
1344
|
+
const requestId = crypto.randomUUID();
|
|
1333
1345
|
try {
|
|
1346
|
+
headers.set('x-deepline-request-id', requestId);
|
|
1334
1347
|
const response = await fetch(url, { method: 'POST', headers, body });
|
|
1335
|
-
if (response.ok)
|
|
1348
|
+
if (response.ok) {
|
|
1349
|
+
if (attempt > 0) {
|
|
1350
|
+
console.info('[coordinator.runtime_api.retry]', {
|
|
1351
|
+
action: 'append_run_events',
|
|
1352
|
+
status: 'ok',
|
|
1353
|
+
attempt,
|
|
1354
|
+
runId,
|
|
1355
|
+
requestId,
|
|
1356
|
+
baseOrigin: safeOrigin(baseUrl),
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1336
1361
|
lastError = new Error(
|
|
1337
1362
|
`runtime API responded ${response.status}: ${(await response.text().catch(() => '')).slice(0, 400)}`,
|
|
1338
1363
|
);
|
|
@@ -1348,6 +1373,19 @@ async function markWorkflowRuntimeFailure(input: {
|
|
|
1348
1373
|
lastError = error;
|
|
1349
1374
|
}
|
|
1350
1375
|
if (attempt < backoffMs.length) {
|
|
1376
|
+
console.warn('[coordinator.runtime_api.retry]', {
|
|
1377
|
+
action: 'append_run_events',
|
|
1378
|
+
status: 'retry',
|
|
1379
|
+
attempt: attempt + 1,
|
|
1380
|
+
retryDelayMs: backoffMs[attempt],
|
|
1381
|
+
runId,
|
|
1382
|
+
requestId,
|
|
1383
|
+
baseOrigin: safeOrigin(baseUrl),
|
|
1384
|
+
error:
|
|
1385
|
+
lastError instanceof Error
|
|
1386
|
+
? lastError.message.slice(0, 300)
|
|
1387
|
+
: String(lastError).slice(0, 300),
|
|
1388
|
+
});
|
|
1351
1389
|
await new Promise((resolve) => setTimeout(resolve, backoffMs[attempt]));
|
|
1352
1390
|
}
|
|
1353
1391
|
}
|
|
@@ -2203,6 +2241,26 @@ async function callRuntimeApiFromCoordinator(input: {
|
|
|
2203
2241
|
});
|
|
2204
2242
|
|
|
2205
2243
|
const fetchStartedAt = Date.now();
|
|
2244
|
+
const requestId = crypto.randomUUID();
|
|
2245
|
+
const action =
|
|
2246
|
+
body && typeof body === 'object' && !Array.isArray(body)
|
|
2247
|
+
? String((body as { action?: unknown }).action ?? 'unknown')
|
|
2248
|
+
: 'unknown';
|
|
2249
|
+
const runId =
|
|
2250
|
+
body && typeof body === 'object' && !Array.isArray(body)
|
|
2251
|
+
? String(
|
|
2252
|
+
(body as { runId?: unknown; playId?: unknown }).runId ??
|
|
2253
|
+
(body as { runId?: unknown; playId?: unknown }).playId ??
|
|
2254
|
+
'',
|
|
2255
|
+
) || null
|
|
2256
|
+
: null;
|
|
2257
|
+
console.info('[coordinator.runtime_api.breadcrumb]', {
|
|
2258
|
+
phase: 'request',
|
|
2259
|
+
action,
|
|
2260
|
+
runId,
|
|
2261
|
+
requestId,
|
|
2262
|
+
baseOrigin: safeOrigin(input.baseUrl),
|
|
2263
|
+
});
|
|
2206
2264
|
const response = await input.env.HARNESS.runtimeApiCall({
|
|
2207
2265
|
contract: PLAY_RUNTIME_CONTRACT,
|
|
2208
2266
|
executorToken: input.executorToken,
|
|
@@ -2210,11 +2268,20 @@ async function callRuntimeApiFromCoordinator(input: {
|
|
|
2210
2268
|
path: PLAY_RUNTIME_API_COMPAT_PATH,
|
|
2211
2269
|
body,
|
|
2212
2270
|
headers: {
|
|
2213
|
-
'x-deepline-request-id':
|
|
2271
|
+
'x-deepline-request-id': requestId,
|
|
2214
2272
|
[PLAY_RUNTIME_CONTRACT_HEADER]: String(PLAY_RUNTIME_CONTRACT),
|
|
2215
2273
|
},
|
|
2216
2274
|
});
|
|
2217
2275
|
recordTiming('coordinator.runtime_api.fetch', fetchStartedAt);
|
|
2276
|
+
console.info('[coordinator.runtime_api.breadcrumb]', {
|
|
2277
|
+
phase: 'response',
|
|
2278
|
+
action,
|
|
2279
|
+
runId,
|
|
2280
|
+
requestId,
|
|
2281
|
+
status: response.status,
|
|
2282
|
+
ms: Date.now() - fetchStartedAt,
|
|
2283
|
+
baseOrigin: safeOrigin(input.baseUrl),
|
|
2284
|
+
});
|
|
2218
2285
|
|
|
2219
2286
|
const bodyStartedAt = Date.now();
|
|
2220
2287
|
const responseBody = response.body;
|
|
@@ -2361,12 +2428,75 @@ function normalizeRuntimeBaseUrl(value: unknown): string | null {
|
|
|
2361
2428
|
return parsed.toString().replace(/\/$/, '');
|
|
2362
2429
|
}
|
|
2363
2430
|
|
|
2364
|
-
|
|
2431
|
+
const DEEPLINE_PRODUCTION_APP_HOST = 'code.deepline.com';
|
|
2432
|
+
const DEEPLINE_VERCEL_DEPLOYMENT_HOST_RE =
|
|
2433
|
+
/^deepline-api(?:-[a-z0-9-]+)?-aero-team-0f650658\.vercel\.app$/i;
|
|
2434
|
+
const DEEPLINE_VERCEL_PROJECT_HOST_RE =
|
|
2435
|
+
/^deepline-[a-z0-9]+-aero-team-0f650658\.vercel\.app$/i;
|
|
2436
|
+
const DEEPLINE_WORKERS_DEV_SUBDOMAINS = new Set(['chirag-d94']);
|
|
2437
|
+
|
|
2438
|
+
function isDeeplineCoordinatorWorkerHost(hostname: string): boolean {
|
|
2439
|
+
const labels = hostname.toLowerCase().split('.');
|
|
2440
|
+
return (
|
|
2441
|
+
labels.length === 4 &&
|
|
2442
|
+
labels[0]?.startsWith('deepline-play-coordinator-') &&
|
|
2443
|
+
labels[2] === 'workers' &&
|
|
2444
|
+
labels[3] === 'dev' &&
|
|
2445
|
+
DEEPLINE_WORKERS_DEV_SUBDOMAINS.has(labels[1] ?? '')
|
|
2446
|
+
);
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
function shouldCanonicalizeRuntimeApiBaseUrl(input: {
|
|
2450
|
+
configuredBaseUrl: URL;
|
|
2451
|
+
overrideBaseUrl: URL;
|
|
2452
|
+
}): boolean {
|
|
2453
|
+
if (input.overrideBaseUrl.host === input.configuredBaseUrl.host) {
|
|
2454
|
+
return false;
|
|
2455
|
+
}
|
|
2456
|
+
const configuredHostname = input.configuredBaseUrl.hostname.toLowerCase();
|
|
2457
|
+
const overrideHostname = input.overrideBaseUrl.hostname.toLowerCase();
|
|
2458
|
+
if (DEEPLINE_VERCEL_DEPLOYMENT_HOST_RE.test(overrideHostname)) {
|
|
2459
|
+
return true;
|
|
2460
|
+
}
|
|
2461
|
+
if (
|
|
2462
|
+
(configuredHostname === DEEPLINE_PRODUCTION_APP_HOST ||
|
|
2463
|
+
DEEPLINE_VERCEL_PROJECT_HOST_RE.test(configuredHostname)) &&
|
|
2464
|
+
DEEPLINE_VERCEL_PROJECT_HOST_RE.test(overrideHostname)
|
|
2465
|
+
) {
|
|
2466
|
+
return true;
|
|
2467
|
+
}
|
|
2468
|
+
return isDeeplineCoordinatorWorkerHost(overrideHostname);
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2471
|
+
function resolveRuntimeApiBaseUrl(
|
|
2472
|
+
env: CoordinatorEnv,
|
|
2473
|
+
body: Record<string, unknown>,
|
|
2474
|
+
): string {
|
|
2475
|
+
const configuredBaseUrl = env.DEEPLINE_API_BASE_URL.replace(/\/$/, '');
|
|
2476
|
+
const overrideBaseUrl =
|
|
2477
|
+
normalizeRuntimeBaseUrl(body.runtimeApiBaseUrl) ??
|
|
2478
|
+
normalizeRuntimeBaseUrl(body.baseUrl);
|
|
2479
|
+
if (!overrideBaseUrl) {
|
|
2480
|
+
return configuredBaseUrl;
|
|
2481
|
+
}
|
|
2482
|
+
if (
|
|
2483
|
+
shouldCanonicalizeRuntimeApiBaseUrl({
|
|
2484
|
+
configuredBaseUrl: new URL(configuredBaseUrl),
|
|
2485
|
+
overrideBaseUrl: new URL(overrideBaseUrl),
|
|
2486
|
+
})
|
|
2487
|
+
) {
|
|
2488
|
+
return configuredBaseUrl;
|
|
2489
|
+
}
|
|
2490
|
+
return overrideBaseUrl;
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
function resolveWorkflowCallbackBaseUrl(
|
|
2365
2494
|
env: CoordinatorEnv,
|
|
2366
2495
|
body: Record<string, unknown>,
|
|
2367
2496
|
): string {
|
|
2368
2497
|
return (
|
|
2369
2498
|
normalizeRuntimeBaseUrl(body.callbackBaseUrl) ??
|
|
2499
|
+
normalizeRuntimeBaseUrl(body.callbackUrl) ??
|
|
2370
2500
|
normalizeRuntimeBaseUrl(body.baseUrl) ??
|
|
2371
2501
|
env.DEEPLINE_API_BASE_URL.replace(/\/$/, '')
|
|
2372
2502
|
);
|
|
@@ -2388,7 +2518,8 @@ function validateChildSubmitBody(input: {
|
|
|
2388
2518
|
const { parentRunId, body } = input;
|
|
2389
2519
|
const manifest = body.manifest as PlayRuntimeManifest | undefined;
|
|
2390
2520
|
const governance = body.internalRunPlay as
|
|
2391
|
-
|
|
2521
|
+
| PlayCallGovernanceSnapshot
|
|
2522
|
+
| undefined;
|
|
2392
2523
|
const childPlayName =
|
|
2393
2524
|
typeof body.name === 'string' && body.name.trim()
|
|
2394
2525
|
? body.name.trim()
|
|
@@ -2480,7 +2611,8 @@ function buildChildWorkflowParams(input: {
|
|
|
2480
2611
|
dynamicWorkerCode,
|
|
2481
2612
|
preloadedDbSessions,
|
|
2482
2613
|
} = input;
|
|
2483
|
-
const baseUrl =
|
|
2614
|
+
const baseUrl = resolveRuntimeApiBaseUrl(env, body);
|
|
2615
|
+
const callbackUrl = resolveWorkflowCallbackBaseUrl(env, body);
|
|
2484
2616
|
return {
|
|
2485
2617
|
runId: childRunId,
|
|
2486
2618
|
playId: childRunId,
|
|
@@ -2517,7 +2649,9 @@ function buildChildWorkflowParams(input: {
|
|
|
2517
2649
|
preloadedDbSessions,
|
|
2518
2650
|
dynamicWorkerCode,
|
|
2519
2651
|
executorToken: childToken,
|
|
2520
|
-
baseUrl,
|
|
2652
|
+
baseUrl: callbackUrl,
|
|
2653
|
+
runtimeApiBaseUrl: baseUrl,
|
|
2654
|
+
callbackUrl,
|
|
2521
2655
|
integrationMode: normalizeIntegrationMode(body.integrationMode),
|
|
2522
2656
|
force: body.force === true || body.forceToolRefresh === true,
|
|
2523
2657
|
forceToolRefresh: body.forceToolRefresh === true,
|
|
@@ -2545,9 +2679,9 @@ function runRequestFromPlayWorkflowParams(
|
|
|
2545
2679
|
params.inputFile?.r2Key ?? params.inputFile?.storageKey ?? null;
|
|
2546
2680
|
return {
|
|
2547
2681
|
runId: params.runId,
|
|
2548
|
-
callbackUrl: params.baseUrl,
|
|
2682
|
+
callbackUrl: params.callbackUrl ?? params.baseUrl,
|
|
2549
2683
|
executorToken: params.executorToken,
|
|
2550
|
-
baseUrl: params.baseUrl,
|
|
2684
|
+
baseUrl: params.runtimeApiBaseUrl ?? params.baseUrl,
|
|
2551
2685
|
integrationMode: normalizeIntegrationMode(params.integrationMode),
|
|
2552
2686
|
orgId: params.orgId,
|
|
2553
2687
|
playName: params.playName,
|
|
@@ -2742,7 +2876,7 @@ async function executeChildInline(input: {
|
|
|
2742
2876
|
input.body.parentPlayName.trim()
|
|
2743
2877
|
? input.body.parentPlayName.trim()
|
|
2744
2878
|
: governance.parentPlayName;
|
|
2745
|
-
const baseUrl =
|
|
2879
|
+
const baseUrl = resolveRuntimeApiBaseUrl(input.env, input.body);
|
|
2746
2880
|
const { childToken, preloadedDbSessions, prepareTimings, transportTimings } =
|
|
2747
2881
|
await prepareInlineChildRunWithRuntime({
|
|
2748
2882
|
env: input.env,
|
|
@@ -3072,7 +3206,7 @@ async function submitChildWorkflowThroughCoordinator(input: {
|
|
|
3072
3206
|
parentRunId: input.parentRunId,
|
|
3073
3207
|
body: input.body,
|
|
3074
3208
|
});
|
|
3075
|
-
const baseUrl =
|
|
3209
|
+
const baseUrl = resolveRuntimeApiBaseUrl(input.env, input.body);
|
|
3076
3210
|
|
|
3077
3211
|
const tokenStartedAt = Date.now();
|
|
3078
3212
|
const childToken = await mintChildWorkflowExecutorToken({
|
|
@@ -1386,9 +1386,18 @@ async function postRuntimeApi<T>(
|
|
|
1386
1386
|
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
1387
1387
|
}
|
|
1388
1388
|
|
|
1389
|
+
const RETRYABLE_RUNTIME_API_ERROR_RE =
|
|
1390
|
+
/timeout|timed out|fetch failed|ECONNRESET|ECONNREFUSED|DeploymentNotFound|requested deployment .*exist|Authentication infrastructure/i;
|
|
1391
|
+
|
|
1389
1392
|
function isRetryableRuntimeApiError(error: unknown): boolean {
|
|
1393
|
+
return RETRYABLE_RUNTIME_API_ERROR_RE.test(
|
|
1394
|
+
error instanceof Error ? error.message : String(error),
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
function isRetryableRuntimePersistenceError(error: unknown): boolean {
|
|
1390
1399
|
const message = error instanceof Error ? error.message : String(error);
|
|
1391
|
-
return /timed out|
|
|
1400
|
+
return /deadlock detected|Runtime Postgres connection timed out|could not serialize access|tuple concurrently updated/i.test(
|
|
1392
1401
|
message,
|
|
1393
1402
|
);
|
|
1394
1403
|
}
|
|
@@ -1404,12 +1413,7 @@ function isRetryableRuntimeApiResponse(status: number, body: string): boolean {
|
|
|
1404
1413
|
) {
|
|
1405
1414
|
return true;
|
|
1406
1415
|
}
|
|
1407
|
-
return (
|
|
1408
|
-
status === 500 &&
|
|
1409
|
-
/timeout exceeded when trying to connect|timed out|fetch failed|ECONNRESET|UND_ERR_CONNECT_TIMEOUT/i.test(
|
|
1410
|
-
body,
|
|
1411
|
-
)
|
|
1412
|
-
);
|
|
1416
|
+
return status === 500 && RETRYABLE_RUNTIME_API_ERROR_RE.test(body);
|
|
1413
1417
|
}
|
|
1414
1418
|
|
|
1415
1419
|
async function sleepRuntimeApiRetry(attempt: number): Promise<void> {
|
|
@@ -4495,6 +4499,10 @@ function createMinimalWorkerCtx(
|
|
|
4495
4499
|
executionPlan: plan,
|
|
4496
4500
|
staticPipeline: staticPipelineFromReq(req),
|
|
4497
4501
|
});
|
|
4502
|
+
const mapHasExternalSideEffects =
|
|
4503
|
+
mapDispatchPlan.workEstimate.providerToolCallsPerRow > 0 ||
|
|
4504
|
+
mapDispatchPlan.workEstimate.childPlaySubmitsPerRow > 0 ||
|
|
4505
|
+
mapDispatchPlan.workEstimate.eventWaitsPerRow > 0;
|
|
4498
4506
|
const rowsPerChunk = mapDispatchPlan.rowsPerChunk;
|
|
4499
4507
|
recordRunnerPerfTrace({
|
|
4500
4508
|
req,
|
|
@@ -5765,6 +5773,13 @@ function createMinimalWorkerCtx(
|
|
|
5765
5773
|
},
|
|
5766
5774
|
});
|
|
5767
5775
|
} catch (error) {
|
|
5776
|
+
if (
|
|
5777
|
+
workflowStep &&
|
|
5778
|
+
!mapHasExternalSideEffects &&
|
|
5779
|
+
isRetryableRuntimePersistenceError(error)
|
|
5780
|
+
) {
|
|
5781
|
+
throw error;
|
|
5782
|
+
}
|
|
5768
5783
|
tripRuntimePersistenceLatch(persistenceLatch, error);
|
|
5769
5784
|
recordRunnerPerfTrace({
|
|
5770
5785
|
req,
|
|
@@ -8287,9 +8302,9 @@ function runRequestFromWorkflowParams(
|
|
|
8287
8302
|
: null;
|
|
8288
8303
|
return {
|
|
8289
8304
|
runId: String(params.runId ?? ''),
|
|
8290
|
-
callbackUrl: String(params.baseUrl ?? ''),
|
|
8305
|
+
callbackUrl: String(params.callbackUrl ?? params.baseUrl ?? ''),
|
|
8291
8306
|
executorToken: String(params.executorToken ?? ''),
|
|
8292
|
-
baseUrl: String(params.baseUrl ?? ''),
|
|
8307
|
+
baseUrl: String(params.runtimeApiBaseUrl ?? params.baseUrl ?? ''),
|
|
8293
8308
|
integrationMode: normalizeIntegrationMode(params.integrationMode),
|
|
8294
8309
|
orgId: String(params.orgId ?? ''),
|
|
8295
8310
|
playName: String(params.playName ?? ''),
|
|
@@ -105,10 +105,10 @@ export const SDK_RELEASE = {
|
|
|
105
105
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
106
106
|
// fields shipped in 0.1.153.
|
|
107
107
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
108
|
-
version: '0.1.
|
|
108
|
+
version: '0.1.192',
|
|
109
109
|
apiContract: '2026-06-dataset-handle-results-hard-cutover',
|
|
110
110
|
supportPolicy: {
|
|
111
|
-
latest: '0.1.
|
|
111
|
+
latest: '0.1.192',
|
|
112
112
|
minimumSupported: '0.1.53',
|
|
113
113
|
deprecatedBelow: '0.1.53',
|
|
114
114
|
commandMinimumSupported: [
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
isPlayExecutionSuspendedError,
|
|
12
12
|
isPlayRowExecutionSuspendedError,
|
|
13
13
|
} from './suspension';
|
|
14
|
+
import { getToolHttpErrorReceiptFailureKind } from './tool-http-errors';
|
|
14
15
|
import type { WorkReceiptFailureKind } from './work-receipts';
|
|
15
16
|
import {
|
|
16
17
|
PLAY_RUNTIME_WORK_RECEIPT_LEASE_TTL_MS,
|
|
@@ -48,6 +49,8 @@ function isInFlightRuntimeReceipt(
|
|
|
48
49
|
export function runtimeReceiptFailureKindForError(
|
|
49
50
|
error: unknown,
|
|
50
51
|
): WorkReceiptFailureKind {
|
|
52
|
+
const toolFailureKind = getToolHttpErrorReceiptFailureKind(error);
|
|
53
|
+
if (toolFailureKind) return toolFailureKind;
|
|
51
54
|
return isPlayExecutionSuspendedError(error) ||
|
|
52
55
|
isPlayRowExecutionSuspendedError(error)
|
|
53
56
|
? 'repairable'
|
|
@@ -128,6 +128,11 @@ export type PlaySchedulerSubmitInput = {
|
|
|
128
128
|
/** Optional immutable Worker module source for local Dynamic Worker loading. */
|
|
129
129
|
dynamicWorkerCode?: string | null;
|
|
130
130
|
executorToken: string;
|
|
131
|
+
/**
|
|
132
|
+
* Public app origin used by Workers to call Deepline runtime API routes.
|
|
133
|
+
* When omitted, legacy schedulers fall back to baseUrl.
|
|
134
|
+
*/
|
|
135
|
+
runtimeApiBaseUrl?: string | null;
|
|
131
136
|
baseUrl: string;
|
|
132
137
|
/** Optional per-run provider execution mode. Defaults to server policy when omitted. */
|
|
133
138
|
integrationMode?: 'live' | 'eval_stub' | 'fixture';
|
|
@@ -204,9 +204,7 @@ export function classifyToolExecuteHttpFailure(input: {
|
|
|
204
204
|
});
|
|
205
205
|
const shouldRetry =
|
|
206
206
|
retryDecision.retryable && input.attempt < retryDecision.attemptCap;
|
|
207
|
-
error.receiptFailureKind =
|
|
208
|
-
? 'repairable'
|
|
209
|
-
: 'terminal';
|
|
207
|
+
if (retryDecision.retryable) error.receiptFailureKind = 'repairable';
|
|
210
208
|
const retryAfterMs = parseToolExecuteRetryAfterMs(
|
|
211
209
|
input.retryAfterHeader,
|
|
212
210
|
input.nowMs,
|
|
@@ -4,13 +4,13 @@ export class ToolHttpError extends Error {
|
|
|
4
4
|
readonly billing: Record<string, unknown> | null;
|
|
5
5
|
/** HTTP status of the failed tool-execute response (e.g. 429, 502). */
|
|
6
6
|
readonly status: number;
|
|
7
|
-
receiptFailureKind: WorkReceiptFailureKind
|
|
7
|
+
receiptFailureKind: WorkReceiptFailureKind;
|
|
8
8
|
|
|
9
9
|
constructor(
|
|
10
10
|
message: string,
|
|
11
11
|
billing: Record<string, unknown> | null,
|
|
12
12
|
status: number,
|
|
13
|
-
receiptFailureKind: WorkReceiptFailureKind
|
|
13
|
+
receiptFailureKind: WorkReceiptFailureKind = 'terminal',
|
|
14
14
|
) {
|
|
15
15
|
super(message);
|
|
16
16
|
this.name = 'ToolHttpError';
|
package/dist/cli/index.js
CHANGED
|
@@ -623,10 +623,10 @@ var SDK_RELEASE = {
|
|
|
623
623
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
624
624
|
// fields shipped in 0.1.153.
|
|
625
625
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
626
|
-
version: "0.1.
|
|
626
|
+
version: "0.1.192",
|
|
627
627
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
628
628
|
supportPolicy: {
|
|
629
|
-
latest: "0.1.
|
|
629
|
+
latest: "0.1.192",
|
|
630
630
|
minimumSupported: "0.1.53",
|
|
631
631
|
deprecatedBelow: "0.1.53",
|
|
632
632
|
commandMinimumSupported: [
|
|
@@ -7443,6 +7443,9 @@ async function waitForRenderHealth(url, state) {
|
|
|
7443
7443
|
if (isOwnedCsvRenderHealth(await fetchCsvRenderHealth(url), state)) {
|
|
7444
7444
|
return true;
|
|
7445
7445
|
}
|
|
7446
|
+
if (state.pid && !processAlive(state.pid)) {
|
|
7447
|
+
return false;
|
|
7448
|
+
}
|
|
7446
7449
|
await new Promise((resolveDelay) => setTimeout(resolveDelay, 100));
|
|
7447
7450
|
}
|
|
7448
7451
|
return false;
|
|
@@ -7505,6 +7508,10 @@ const server = http.createServer((req, res) => {
|
|
|
7505
7508
|
});
|
|
7506
7509
|
|
|
7507
7510
|
server.listen(port, '127.0.0.1');
|
|
7511
|
+
server.on('error', (error) => {
|
|
7512
|
+
console.error(error && error.stack ? error.stack : error);
|
|
7513
|
+
process.exit(1);
|
|
7514
|
+
});
|
|
7508
7515
|
process.on('SIGTERM', () => server.close(() => process.exit(0)));
|
|
7509
7516
|
process.on('SIGINT', () => server.close(() => process.exit(0)));
|
|
7510
7517
|
`;
|
|
@@ -7560,17 +7567,23 @@ async function handleCsvRenderStart(options) {
|
|
|
7560
7567
|
}
|
|
7561
7568
|
ensureCsvRenderStateDir();
|
|
7562
7569
|
const logPath = csvRenderLogPath();
|
|
7570
|
+
const logFd = (0, import_node_fs7.openSync)(logPath, "w");
|
|
7563
7571
|
const token = (0, import_node_crypto2.randomUUID)();
|
|
7564
|
-
const child = (0, import_node_child_process.spawn)(
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
+
const child = (0, import_node_child_process.spawn)(
|
|
7573
|
+
process.execPath,
|
|
7574
|
+
["-e", CSV_RENDER_SERVER_SOURCE],
|
|
7575
|
+
{
|
|
7576
|
+
detached: true,
|
|
7577
|
+
stdio: ["ignore", logFd, logFd],
|
|
7578
|
+
env: {
|
|
7579
|
+
...process.env,
|
|
7580
|
+
DEEPLINE_CSV_RENDER_PORT: String(port),
|
|
7581
|
+
DEEPLINE_CSV_RENDER_CSV: csvPath,
|
|
7582
|
+
DEEPLINE_CSV_RENDER_TOKEN: token
|
|
7583
|
+
}
|
|
7572
7584
|
}
|
|
7573
|
-
|
|
7585
|
+
);
|
|
7586
|
+
(0, import_node_fs7.closeSync)(logFd);
|
|
7574
7587
|
child.unref();
|
|
7575
7588
|
const state = {
|
|
7576
7589
|
pid: child.pid ?? null,
|
|
@@ -7586,7 +7599,19 @@ async function handleCsvRenderStart(options) {
|
|
|
7586
7599
|
if (processAlive(child.pid)) {
|
|
7587
7600
|
process.kill(child.pid, "SIGTERM");
|
|
7588
7601
|
}
|
|
7589
|
-
|
|
7602
|
+
let detail = "";
|
|
7603
|
+
try {
|
|
7604
|
+
const log = (0, import_node_fs7.readFileSync)(logPath, "utf8").trim();
|
|
7605
|
+
if (log) {
|
|
7606
|
+
detail = `
|
|
7607
|
+
CSV render log:
|
|
7608
|
+
${clip(log, 2e3)}`;
|
|
7609
|
+
}
|
|
7610
|
+
} catch {
|
|
7611
|
+
}
|
|
7612
|
+
throw new Error(
|
|
7613
|
+
`Timed out waiting for CSV render to start at ${url}.${detail}`
|
|
7614
|
+
);
|
|
7590
7615
|
}
|
|
7591
7616
|
writeCsvRenderState(state);
|
|
7592
7617
|
(0, import_node_fs7.writeFileSync)(
|
|
@@ -19360,6 +19385,30 @@ function coalesceExportableSheetRows(rows, sourceRowStart = 0) {
|
|
|
19360
19385
|
bySourceRowIndex.set(rowIndex, next);
|
|
19361
19386
|
mergedRows.push(next);
|
|
19362
19387
|
}
|
|
19388
|
+
if (bySourceRowIndex.size > 0) {
|
|
19389
|
+
mergedRows.sort((left, right) => {
|
|
19390
|
+
const leftIndex = sourceRowIndexFromEnrichRow(
|
|
19391
|
+
left,
|
|
19392
|
+
sourceRowStart,
|
|
19393
|
+
Number.MAX_SAFE_INTEGER
|
|
19394
|
+
);
|
|
19395
|
+
const rightIndex = sourceRowIndexFromEnrichRow(
|
|
19396
|
+
right,
|
|
19397
|
+
sourceRowStart,
|
|
19398
|
+
Number.MAX_SAFE_INTEGER
|
|
19399
|
+
);
|
|
19400
|
+
if (leftIndex !== null && rightIndex !== null) {
|
|
19401
|
+
return leftIndex - rightIndex;
|
|
19402
|
+
}
|
|
19403
|
+
if (leftIndex !== null) {
|
|
19404
|
+
return -1;
|
|
19405
|
+
}
|
|
19406
|
+
if (rightIndex !== null) {
|
|
19407
|
+
return 1;
|
|
19408
|
+
}
|
|
19409
|
+
return 0;
|
|
19410
|
+
});
|
|
19411
|
+
}
|
|
19363
19412
|
return mergedRows;
|
|
19364
19413
|
}
|
|
19365
19414
|
function sourceRowIndexFromEnrichRow(row, start, end) {
|
|
@@ -21202,7 +21251,9 @@ function registerEnrichCommand(program) {
|
|
|
21202
21251
|
...finalExportResult ? { rowSetComplete: !finalExportResult.partial } : {}
|
|
21203
21252
|
});
|
|
21204
21253
|
if (chunk.exportResult) {
|
|
21205
|
-
currentChunkCommittedExportResult = await commitInPlaceOutput(
|
|
21254
|
+
currentChunkCommittedExportResult = await commitInPlaceOutput(
|
|
21255
|
+
chunk.exportResult
|
|
21256
|
+
);
|
|
21206
21257
|
finalExportResult = currentChunkCommittedExportResult;
|
|
21207
21258
|
}
|
|
21208
21259
|
const reportedExportResult = currentChunkCommittedExportResult ?? finalExportResult;
|
package/dist/cli/index.mjs
CHANGED
|
@@ -608,10 +608,10 @@ var SDK_RELEASE = {
|
|
|
608
608
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
609
609
|
// fields shipped in 0.1.153.
|
|
610
610
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
611
|
-
version: "0.1.
|
|
611
|
+
version: "0.1.192",
|
|
612
612
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
613
613
|
supportPolicy: {
|
|
614
|
-
latest: "0.1.
|
|
614
|
+
latest: "0.1.192",
|
|
615
615
|
minimumSupported: "0.1.53",
|
|
616
616
|
deprecatedBelow: "0.1.53",
|
|
617
617
|
commandMinimumSupported: [
|
|
@@ -6670,8 +6670,10 @@ Examples:
|
|
|
6670
6670
|
import { spawn } from "child_process";
|
|
6671
6671
|
import { randomUUID } from "crypto";
|
|
6672
6672
|
import {
|
|
6673
|
+
closeSync,
|
|
6673
6674
|
existsSync as existsSync6,
|
|
6674
6675
|
mkdirSync as mkdirSync5,
|
|
6676
|
+
openSync,
|
|
6675
6677
|
readFileSync as readFileSync6,
|
|
6676
6678
|
rmSync as rmSync3,
|
|
6677
6679
|
writeFileSync as writeFileSync6
|
|
@@ -7446,6 +7448,9 @@ async function waitForRenderHealth(url, state) {
|
|
|
7446
7448
|
if (isOwnedCsvRenderHealth(await fetchCsvRenderHealth(url), state)) {
|
|
7447
7449
|
return true;
|
|
7448
7450
|
}
|
|
7451
|
+
if (state.pid && !processAlive(state.pid)) {
|
|
7452
|
+
return false;
|
|
7453
|
+
}
|
|
7449
7454
|
await new Promise((resolveDelay) => setTimeout(resolveDelay, 100));
|
|
7450
7455
|
}
|
|
7451
7456
|
return false;
|
|
@@ -7508,6 +7513,10 @@ const server = http.createServer((req, res) => {
|
|
|
7508
7513
|
});
|
|
7509
7514
|
|
|
7510
7515
|
server.listen(port, '127.0.0.1');
|
|
7516
|
+
server.on('error', (error) => {
|
|
7517
|
+
console.error(error && error.stack ? error.stack : error);
|
|
7518
|
+
process.exit(1);
|
|
7519
|
+
});
|
|
7511
7520
|
process.on('SIGTERM', () => server.close(() => process.exit(0)));
|
|
7512
7521
|
process.on('SIGINT', () => server.close(() => process.exit(0)));
|
|
7513
7522
|
`;
|
|
@@ -7563,17 +7572,23 @@ async function handleCsvRenderStart(options) {
|
|
|
7563
7572
|
}
|
|
7564
7573
|
ensureCsvRenderStateDir();
|
|
7565
7574
|
const logPath = csvRenderLogPath();
|
|
7575
|
+
const logFd = openSync(logPath, "w");
|
|
7566
7576
|
const token = randomUUID();
|
|
7567
|
-
const child = spawn(
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7577
|
+
const child = spawn(
|
|
7578
|
+
process.execPath,
|
|
7579
|
+
["-e", CSV_RENDER_SERVER_SOURCE],
|
|
7580
|
+
{
|
|
7581
|
+
detached: true,
|
|
7582
|
+
stdio: ["ignore", logFd, logFd],
|
|
7583
|
+
env: {
|
|
7584
|
+
...process.env,
|
|
7585
|
+
DEEPLINE_CSV_RENDER_PORT: String(port),
|
|
7586
|
+
DEEPLINE_CSV_RENDER_CSV: csvPath,
|
|
7587
|
+
DEEPLINE_CSV_RENDER_TOKEN: token
|
|
7588
|
+
}
|
|
7575
7589
|
}
|
|
7576
|
-
|
|
7590
|
+
);
|
|
7591
|
+
closeSync(logFd);
|
|
7577
7592
|
child.unref();
|
|
7578
7593
|
const state = {
|
|
7579
7594
|
pid: child.pid ?? null,
|
|
@@ -7589,7 +7604,19 @@ async function handleCsvRenderStart(options) {
|
|
|
7589
7604
|
if (processAlive(child.pid)) {
|
|
7590
7605
|
process.kill(child.pid, "SIGTERM");
|
|
7591
7606
|
}
|
|
7592
|
-
|
|
7607
|
+
let detail = "";
|
|
7608
|
+
try {
|
|
7609
|
+
const log = readFileSync6(logPath, "utf8").trim();
|
|
7610
|
+
if (log) {
|
|
7611
|
+
detail = `
|
|
7612
|
+
CSV render log:
|
|
7613
|
+
${clip(log, 2e3)}`;
|
|
7614
|
+
}
|
|
7615
|
+
} catch {
|
|
7616
|
+
}
|
|
7617
|
+
throw new Error(
|
|
7618
|
+
`Timed out waiting for CSV render to start at ${url}.${detail}`
|
|
7619
|
+
);
|
|
7593
7620
|
}
|
|
7594
7621
|
writeCsvRenderState(state);
|
|
7595
7622
|
writeFileSync6(
|
|
@@ -8155,8 +8182,8 @@ import { parse as parseCsvSync2 } from "csv-parse/sync";
|
|
|
8155
8182
|
|
|
8156
8183
|
// src/cli/commands/plays/bootstrap.ts
|
|
8157
8184
|
import {
|
|
8158
|
-
closeSync,
|
|
8159
|
-
openSync,
|
|
8185
|
+
closeSync as closeSync2,
|
|
8186
|
+
openSync as openSync2,
|
|
8160
8187
|
readSync,
|
|
8161
8188
|
statSync as statSync2,
|
|
8162
8189
|
writeFileSync as writeFileSync8
|
|
@@ -8734,11 +8761,11 @@ function inferCsvColumnSpecs(headers, rows) {
|
|
|
8734
8761
|
function readCsvSample(csvPath) {
|
|
8735
8762
|
const resolvedPath = resolve7(csvPath);
|
|
8736
8763
|
const size = statSync2(resolvedPath).size;
|
|
8737
|
-
const fd =
|
|
8764
|
+
const fd = openSync2(resolvedPath, "r");
|
|
8738
8765
|
const byteLength = Math.min(size, CSV_HEADER_SAMPLE_BYTES);
|
|
8739
8766
|
const buffer = Buffer.alloc(byteLength);
|
|
8740
8767
|
const bytesRead = readSync(fd, buffer, 0, byteLength, 0);
|
|
8741
|
-
|
|
8768
|
+
closeSync2(fd);
|
|
8742
8769
|
if (bytesRead === 0) {
|
|
8743
8770
|
throw new PlayBootstrapUsageError(`--from csv:${csvPath} is empty.`);
|
|
8744
8771
|
}
|
|
@@ -19387,6 +19414,30 @@ function coalesceExportableSheetRows(rows, sourceRowStart = 0) {
|
|
|
19387
19414
|
bySourceRowIndex.set(rowIndex, next);
|
|
19388
19415
|
mergedRows.push(next);
|
|
19389
19416
|
}
|
|
19417
|
+
if (bySourceRowIndex.size > 0) {
|
|
19418
|
+
mergedRows.sort((left, right) => {
|
|
19419
|
+
const leftIndex = sourceRowIndexFromEnrichRow(
|
|
19420
|
+
left,
|
|
19421
|
+
sourceRowStart,
|
|
19422
|
+
Number.MAX_SAFE_INTEGER
|
|
19423
|
+
);
|
|
19424
|
+
const rightIndex = sourceRowIndexFromEnrichRow(
|
|
19425
|
+
right,
|
|
19426
|
+
sourceRowStart,
|
|
19427
|
+
Number.MAX_SAFE_INTEGER
|
|
19428
|
+
);
|
|
19429
|
+
if (leftIndex !== null && rightIndex !== null) {
|
|
19430
|
+
return leftIndex - rightIndex;
|
|
19431
|
+
}
|
|
19432
|
+
if (leftIndex !== null) {
|
|
19433
|
+
return -1;
|
|
19434
|
+
}
|
|
19435
|
+
if (rightIndex !== null) {
|
|
19436
|
+
return 1;
|
|
19437
|
+
}
|
|
19438
|
+
return 0;
|
|
19439
|
+
});
|
|
19440
|
+
}
|
|
19390
19441
|
return mergedRows;
|
|
19391
19442
|
}
|
|
19392
19443
|
function sourceRowIndexFromEnrichRow(row, start, end) {
|
|
@@ -21229,7 +21280,9 @@ function registerEnrichCommand(program) {
|
|
|
21229
21280
|
...finalExportResult ? { rowSetComplete: !finalExportResult.partial } : {}
|
|
21230
21281
|
});
|
|
21231
21282
|
if (chunk.exportResult) {
|
|
21232
|
-
currentChunkCommittedExportResult = await commitInPlaceOutput(
|
|
21283
|
+
currentChunkCommittedExportResult = await commitInPlaceOutput(
|
|
21284
|
+
chunk.exportResult
|
|
21285
|
+
);
|
|
21233
21286
|
finalExportResult = currentChunkCommittedExportResult;
|
|
21234
21287
|
}
|
|
21235
21288
|
const reportedExportResult = currentChunkCommittedExportResult ?? finalExportResult;
|
|
@@ -24354,9 +24407,9 @@ import { join as join11, resolve as resolve11 } from "path";
|
|
|
24354
24407
|
|
|
24355
24408
|
// src/tool-output.ts
|
|
24356
24409
|
import {
|
|
24357
|
-
closeSync as
|
|
24410
|
+
closeSync as closeSync3,
|
|
24358
24411
|
mkdirSync as mkdirSync8,
|
|
24359
|
-
openSync as
|
|
24412
|
+
openSync as openSync3,
|
|
24360
24413
|
writeFileSync as writeFileSync12,
|
|
24361
24414
|
writeSync
|
|
24362
24415
|
} from "fs";
|
|
@@ -24509,7 +24562,7 @@ function writeCsvOutputFile(rows, stem, options) {
|
|
|
24509
24562
|
}
|
|
24510
24563
|
return normalized;
|
|
24511
24564
|
};
|
|
24512
|
-
const fd =
|
|
24565
|
+
const fd = openSync3(outputPath, "w");
|
|
24513
24566
|
try {
|
|
24514
24567
|
writeSync(fd, `${columns.map(escapeCell).join(",")}
|
|
24515
24568
|
`);
|
|
@@ -24521,7 +24574,7 @@ function writeCsvOutputFile(rows, stem, options) {
|
|
|
24521
24574
|
);
|
|
24522
24575
|
}
|
|
24523
24576
|
} finally {
|
|
24524
|
-
|
|
24577
|
+
closeSync3(fd);
|
|
24525
24578
|
}
|
|
24526
24579
|
const previewRows = rows.slice(0, 5);
|
|
24527
24580
|
const previewColumns = columns.slice(0, 5);
|
package/dist/index.js
CHANGED
|
@@ -422,10 +422,10 @@ var SDK_RELEASE = {
|
|
|
422
422
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
423
423
|
// fields shipped in 0.1.153.
|
|
424
424
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
425
|
-
version: "0.1.
|
|
425
|
+
version: "0.1.192",
|
|
426
426
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
427
427
|
supportPolicy: {
|
|
428
|
-
latest: "0.1.
|
|
428
|
+
latest: "0.1.192",
|
|
429
429
|
minimumSupported: "0.1.53",
|
|
430
430
|
deprecatedBelow: "0.1.53",
|
|
431
431
|
commandMinimumSupported: [
|
package/dist/index.mjs
CHANGED
|
@@ -352,10 +352,10 @@ var SDK_RELEASE = {
|
|
|
352
352
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
353
353
|
// fields shipped in 0.1.153.
|
|
354
354
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
355
|
-
version: "0.1.
|
|
355
|
+
version: "0.1.192",
|
|
356
356
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
357
357
|
supportPolicy: {
|
|
358
|
-
latest: "0.1.
|
|
358
|
+
latest: "0.1.192",
|
|
359
359
|
minimumSupported: "0.1.53",
|
|
360
360
|
deprecatedBelow: "0.1.53",
|
|
361
361
|
commandMinimumSupported: [
|