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.
Files changed (40) hide show
  1. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +203 -12
  2. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +23 -0
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +15 -0
  4. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-latency-profile.ts +90 -0
  5. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +162 -100
  6. package/dist/bundling-sources/sdk/src/client.ts +118 -3
  7. package/dist/bundling-sources/sdk/src/play.ts +2 -0
  8. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
  9. package/dist/bundling-sources/sdk/src/release.ts +2 -2
  10. package/dist/bundling-sources/sdk/src/types.ts +47 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +253 -30
  12. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +365 -103
  13. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +12 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/dataset-id.ts +10 -4
  15. package/dist/bundling-sources/shared_libs/play-runtime/db-session.ts +9 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +45 -8
  17. package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +14 -2
  18. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +4 -2
  19. package/dist/bundling-sources/shared_libs/play-runtime/receipt-sql.ts +21 -1
  20. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +128 -6
  21. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +7 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +5 -1
  23. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +37 -5
  24. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +19 -10
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +63 -7
  26. package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +18 -4
  27. package/dist/bundling-sources/shared_libs/play-runtime/single-flight.ts +31 -0
  28. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +12 -1
  29. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +29 -9
  30. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-state-machine.ts +22 -1
  31. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +79 -1
  32. package/dist/bundling-sources/shared_libs/plays/dataset.ts +41 -5
  33. package/dist/cli/index.js +728 -239
  34. package/dist/cli/index.mjs +728 -239
  35. package/dist/index.d.mts +93 -7
  36. package/dist/index.d.ts +93 -7
  37. package/dist/index.js +245 -46
  38. package/dist/index.mjs +245 -46
  39. package/dist/plays/bundle-play-file.mjs +65 -4
  40. package/package.json +1 -1
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.210",
425
+ version: "0.1.212",
426
426
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
427
427
  supportPolicy: {
428
- latest: "0.1.210",
428
+ latest: "0.1.212",
429
429
  minimumSupported: "0.1.53",
430
430
  deprecatedBelow: "0.1.53",
431
431
  commandMinimumSupported: [
@@ -1158,9 +1158,91 @@ function normalizePlayRunLedgerTerminalSource(value) {
1158
1158
  ) ? value : null;
1159
1159
  }
1160
1160
 
1161
+ // ../shared_libs/play-runtime/secret-redaction.ts
1162
+ var SECRET_REDACTION_PLACEHOLDER = "[REDACTED_SECRET]";
1163
+ var BEARER_TOKEN_RE = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/g;
1164
+ var JWT_RE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g;
1165
+ var PRIVATE_KEY_RE = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g;
1166
+ var COMMON_SECRET_RE = /\b(?:sk|pk|rk|pat|ghp|github_pat|xox[baprs]|key|token|secret|api[_-]?key)[A-Za-z0-9_./+=:-]{12,}\b/gi;
1167
+ var URL_SECRET_VALUE_RE = /\b(?:sk|pk|rk|pat|ghp|github_pat|xox)[A-Za-z0-9_./+=:-]{12,}\b/i;
1168
+ var HIGH_ENTROPY_ASSIGNMENT_RE = /\b(?:api[_-]?key|token|secret|password|authorization|access[_-]?token|refresh[_-]?token)\b\s*[:=]\s*["']?[^"',\s]{16,}["']?/gi;
1169
+ var SENSITIVE_URL_PARAM_RE = /[?#&](?:\w*(?:key|token)|secret|password|authorization|credential|signature|sig)(?:=|$)/i;
1170
+ function escapeRegExp(value) {
1171
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1172
+ }
1173
+ function isRecord(value) {
1174
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1175
+ }
1176
+ function redactSecretLikeString(value) {
1177
+ const trimmed = value.trim();
1178
+ if (/^https?:\/\/\S+$/i.test(trimmed)) {
1179
+ if (/^https?:\/\/[^/?#@]+@/i.test(trimmed) || SENSITIVE_URL_PARAM_RE.test(trimmed)) {
1180
+ return SECRET_REDACTION_PLACEHOLDER;
1181
+ }
1182
+ if (!URL_SECRET_VALUE_RE.test(value)) return value;
1183
+ }
1184
+ return value.replace(PRIVATE_KEY_RE, SECRET_REDACTION_PLACEHOLDER).replace(BEARER_TOKEN_RE, `Bearer ${SECRET_REDACTION_PLACEHOLDER}`).replace(JWT_RE, SECRET_REDACTION_PLACEHOLDER).replace(COMMON_SECRET_RE, SECRET_REDACTION_PLACEHOLDER).replace(HIGH_ENTROPY_ASSIGNMENT_RE, (match) => {
1185
+ const separator = match.includes("=") ? "=" : ":";
1186
+ const [key] = match.split(separator, 1);
1187
+ return `${key.trim()}${separator}${SECRET_REDACTION_PLACEHOLDER}`;
1188
+ });
1189
+ }
1190
+ function createSecretRedactionContext(initialValues = []) {
1191
+ const exactSecrets = /* @__PURE__ */ new Set();
1192
+ function register(value) {
1193
+ if (value.length >= 4) exactSecrets.add(value);
1194
+ }
1195
+ for (const value of initialValues) register(value);
1196
+ function redactString(value) {
1197
+ let output = value;
1198
+ for (const secret of exactSecrets) {
1199
+ output = output.replace(
1200
+ new RegExp(escapeRegExp(secret), "g"),
1201
+ SECRET_REDACTION_PLACEHOLDER
1202
+ );
1203
+ try {
1204
+ const encoded = encodeURIComponent(secret);
1205
+ if (encoded !== secret) {
1206
+ output = output.replace(
1207
+ new RegExp(escapeRegExp(encoded), "g"),
1208
+ SECRET_REDACTION_PLACEHOLDER
1209
+ );
1210
+ }
1211
+ } catch {
1212
+ }
1213
+ }
1214
+ return redactSecretLikeString(output);
1215
+ }
1216
+ function redact(value) {
1217
+ if (typeof value === "string") return redactString(value);
1218
+ if (Array.isArray(value)) return value.map((entry) => redact(entry));
1219
+ if (isRecord(value)) {
1220
+ return Object.fromEntries(
1221
+ Object.entries(value).map(([key, entry]) => [key, redact(entry)])
1222
+ );
1223
+ }
1224
+ return value;
1225
+ }
1226
+ return {
1227
+ register,
1228
+ redactString,
1229
+ redact
1230
+ };
1231
+ }
1232
+
1233
+ // ../shared_libs/play-runtime/output-size-limits.ts
1234
+ var encoder = typeof TextEncoder === "undefined" ? null : new TextEncoder();
1235
+ var CUSTOMER_OUTPUT_VALUE_MAX_BYTES = 1 * 1024 * 1024;
1236
+ var CUSTOMER_OUTPUT_TOTAL_MAX_BYTES = 2 * 1024 * 1024;
1237
+ var RUNTIME_RECEIPT_OUTPUT_MAX_BYTES = 10 * 1024 * 1024;
1238
+ var RUNTIME_RECEIPT_COMPLETION_BUFFER_MAX_BYTES = 32 * 1024 * 1024;
1239
+
1240
+ // ../shared_libs/play-runtime/ledger-safe-payload.ts
1241
+ var ledgerIngressRedactor = createSecretRedactionContext();
1242
+
1161
1243
  // ../shared_libs/play-runtime/run-ledger.ts
1162
1244
  var LOG_TAIL_LIMIT = 100;
1163
- function isRecord(value) {
1245
+ function isRecord2(value) {
1164
1246
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1165
1247
  }
1166
1248
  function finiteNumber(value) {
@@ -1242,6 +1324,8 @@ function createEmptyPlayRunLedgerSnapshot(input) {
1242
1324
  durationMs: startedAt !== null && finishedAt !== null ? Math.max(0, finishedAt - startedAt) : null,
1243
1325
  orderedStepIds: [],
1244
1326
  stepsById: {},
1327
+ orderedDatasetIds: [],
1328
+ datasetsById: {},
1245
1329
  logTail: [],
1246
1330
  totalLogCount: 0,
1247
1331
  logsTruncated: false,
@@ -1251,21 +1335,21 @@ function createEmptyPlayRunLedgerSnapshot(input) {
1251
1335
  };
1252
1336
  }
1253
1337
  function normalizePlayRunLedgerSnapshot(value, fallback) {
1254
- if (!isRecord(value)) {
1338
+ if (!isRecord2(value)) {
1255
1339
  return createEmptyPlayRunLedgerSnapshot(fallback);
1256
1340
  }
1257
1341
  const orderedStepIds = Array.isArray(value.orderedStepIds) ? value.orderedStepIds.filter(
1258
1342
  (entry) => typeof entry === "string" && Boolean(entry.trim())
1259
1343
  ) : [];
1260
- const rawSteps = isRecord(value.stepsById) ? value.stepsById : {};
1344
+ const rawSteps = isRecord2(value.stepsById) ? value.stepsById : {};
1261
1345
  const stepsById = {};
1262
1346
  for (const [stepId, rawStep] of Object.entries(rawSteps)) {
1263
- if (!stepId.trim() || !isRecord(rawStep)) continue;
1347
+ if (!stepId.trim() || !isRecord2(rawStep)) continue;
1264
1348
  const rawStatus = normalizeStepStatus(rawStep.status);
1265
1349
  if (!rawStatus) continue;
1266
1350
  const completedAt = finiteNumber(rawStep.completedAt);
1267
1351
  const status = rawStatus === "running" && completedAt !== null ? "completed" : rawStatus;
1268
- const rawProgress = isRecord(rawStep.progress) ? rawStep.progress : null;
1352
+ const rawProgress = isRecord2(rawStep.progress) ? rawStep.progress : null;
1269
1353
  stepsById[stepId] = {
1270
1354
  stepId,
1271
1355
  label: optionalString(rawStep.label),
@@ -1280,6 +1364,23 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
1280
1364
  progress: rawProgress ? normalizeStepProgress(rawProgress) : null
1281
1365
  };
1282
1366
  }
1367
+ const rawDatasets = isRecord2(value.datasetsById) ? value.datasetsById : {};
1368
+ const datasetsById = {};
1369
+ for (const [datasetId, rawDataset] of Object.entries(rawDatasets)) {
1370
+ if (!datasetId.trim() || !isRecord2(rawDataset)) continue;
1371
+ const phase = rawDataset.phase === "available" || rawDataset.phase === "failed" ? rawDataset.phase : "registered";
1372
+ datasetsById[datasetId] = {
1373
+ datasetId,
1374
+ path: optionalString(rawDataset.path) ?? `datasets.${datasetId}`,
1375
+ tableNamespace: optionalString(rawDataset.tableNamespace) ?? datasetId,
1376
+ phase,
1377
+ persistedRows: Math.max(0, finiteNumber(rawDataset.persistedRows) ?? 0),
1378
+ succeededRows: Math.max(0, finiteNumber(rawDataset.succeededRows) ?? 0),
1379
+ failedRows: Math.max(0, finiteNumber(rawDataset.failedRows) ?? 0),
1380
+ complete: rawDataset.complete === true,
1381
+ updatedAt: finiteNumber(rawDataset.updatedAt) ?? 0
1382
+ };
1383
+ }
1283
1384
  const createdAt = finiteNumber(value.createdAt) ?? fallback.createdAt ?? null;
1284
1385
  const startedAt = finiteNumber(value.startedAt) ?? fallback.startedAt ?? null;
1285
1386
  const finishedAt = finiteNumber(value.finishedAt) ?? fallback.finishedAt ?? null;
@@ -1299,6 +1400,10 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
1299
1400
  durationMs: startedAt !== null && finishedAt !== null ? Math.max(0, finishedAt - startedAt) : finiteNumber(value.durationMs),
1300
1401
  orderedStepIds: orderedStepIds.filter((stepId) => stepsById[stepId]),
1301
1402
  stepsById,
1403
+ orderedDatasetIds: (Array.isArray(value.orderedDatasetIds) ? value.orderedDatasetIds : Object.keys(datasetsById)).filter(
1404
+ (datasetId) => typeof datasetId === "string" && Boolean(datasetsById[datasetId])
1405
+ ),
1406
+ datasetsById,
1302
1407
  logTail: logTail.slice(-LOG_TAIL_LIMIT),
1303
1408
  // Snapshots persisted before totalLogCount existed only know the retained
1304
1409
  // tail, so the best lower bound for the cumulative count is the tail size.
@@ -1393,18 +1498,18 @@ function normalizePlayRunLiveStatus(value) {
1393
1498
  function isTerminalPlayRunLiveStatus(status) {
1394
1499
  return isTerminalPlayRunLifecycleStatus(status);
1395
1500
  }
1396
- function isRecord2(value) {
1501
+ function isRecord3(value) {
1397
1502
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1398
1503
  }
1399
1504
  function finiteNumber2(value) {
1400
1505
  return typeof value === "number" && Number.isFinite(value) ? value : null;
1401
1506
  }
1402
1507
  function extractTerminalRunLogTail(result) {
1403
- if (!isRecord2(result) || !isRecord2(result._metadata)) {
1508
+ if (!isRecord3(result) || !isRecord3(result._metadata)) {
1404
1509
  return null;
1405
1510
  }
1406
1511
  const runLogTail = result._metadata.runLogTail;
1407
- if (!isRecord2(runLogTail) || !Array.isArray(runLogTail.tail)) {
1512
+ if (!isRecord3(runLogTail) || !Array.isArray(runLogTail.tail)) {
1408
1513
  return null;
1409
1514
  }
1410
1515
  const logTail = runLogTail.tail.filter(
@@ -1460,6 +1565,9 @@ function buildSnapshotFromLedger(snapshot) {
1460
1565
  ...snapshot.logsTruncated ? { logsTruncated: true } : {},
1461
1566
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1462
1567
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1568
+ datasets: snapshot.orderedDatasetIds.map((datasetId) => snapshot.datasetsById[datasetId]).filter(
1569
+ (dataset) => Boolean(dataset)
1570
+ ),
1463
1571
  nodeStates,
1464
1572
  activeNodeId: snapshot.activeStepId ?? null,
1465
1573
  ...rowOutcomes ? { rowOutcomes } : {}
@@ -2136,8 +2244,9 @@ function resolveToolExecuteTimeoutMs(toolId) {
2136
2244
  const normalized = toolId.trim().toLowerCase();
2137
2245
  return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
2138
2246
  }
2247
+ var RUNS_FAILED_LOG_LIMIT = 20;
2139
2248
  var RUN_LOGS_PAGE_LIMIT = 1e3;
2140
- function isRecord3(value) {
2249
+ function isRecord4(value) {
2141
2250
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
2142
2251
  }
2143
2252
  function isPrebuiltPlayDescription(play) {
@@ -2294,7 +2403,7 @@ function updatePlayLiveStatusState(state, event) {
2294
2403
  }
2295
2404
  const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : isPlayRunPackage(payload) ? payload.run.id : state.runId;
2296
2405
  const status = normalizeLiveStatus(payload.status) ?? (isPlayRunPackage(payload) ? normalizeLiveStatus(payload.run.status) : null) ?? state.status;
2297
- const progressPayload = isRecord3(payload.progress) ? payload.progress : {};
2406
+ const progressPayload = isRecord4(payload.progress) ? payload.progress : {};
2298
2407
  if (event.type === "play.run.final_status" && state.logs.length === 0 && state.lastLogSeq === 0) {
2299
2408
  const payloadLogs = readStringArray(payload.logs);
2300
2409
  const progressLogs = readStringArray(progressPayload.logs);
@@ -2409,9 +2518,9 @@ var DeeplineClient = class {
2409
2518
  return fields.length > 0 ? { fields } : schema;
2410
2519
  }
2411
2520
  schemaMetadata(schema, key) {
2412
- if (!isRecord3(schema)) return null;
2521
+ if (!isRecord4(schema)) return null;
2413
2522
  const value = schema[key];
2414
- return isRecord3(value) ? value : null;
2523
+ return isRecord4(value) ? value : null;
2415
2524
  }
2416
2525
  playRunCommand(play, options) {
2417
2526
  const target = play.reference || play.name;
@@ -2460,7 +2569,7 @@ var DeeplineClient = class {
2460
2569
  aliases,
2461
2570
  inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
2462
2571
  outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
2463
- staticPipeline: isRecord3(play.staticPipeline) ? play.staticPipeline : isRecord3(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord3(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
2572
+ staticPipeline: isRecord4(play.staticPipeline) ? play.staticPipeline : isRecord4(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord4(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
2464
2573
  ...csvInput ? { csvInput } : {},
2465
2574
  ...rowOutputSchema ? { rowOutputSchema } : {},
2466
2575
  runCommand,
@@ -3394,7 +3503,46 @@ var DeeplineClient = class {
3394
3503
  const response = await this.http.get(
3395
3504
  `/api/v2/runs/${encodeURIComponent(runId)}${query}`
3396
3505
  );
3397
- return normalizePlayStatus(response);
3506
+ const status = normalizePlayStatus(response);
3507
+ if (options?.failedLogs !== true || status.status !== "failed") {
3508
+ return status;
3509
+ }
3510
+ const requestedFailedLogLimit = typeof options.failedLogLimit === "number" && Number.isFinite(options.failedLogLimit) ? Math.max(1, Math.floor(options.failedLogLimit)) : RUNS_FAILED_LOG_LIMIT;
3511
+ let failedLogs;
3512
+ let failedLogsLoaded = true;
3513
+ try {
3514
+ failedLogs = await this.getRunLogs(runId, {
3515
+ failed: true,
3516
+ limit: Math.min(RUNS_FAILED_LOG_LIMIT, requestedFailedLogLimit)
3517
+ });
3518
+ } catch (error) {
3519
+ failedLogsLoaded = false;
3520
+ const retryCommand = `deepline runs get ${runId} --log-failed --json`;
3521
+ const reason = error instanceof Error && error.message.trim() ? ` (${error.message.trim().slice(0, 500)})` : "";
3522
+ failedLogs = {
3523
+ runId,
3524
+ totalCount: 0,
3525
+ returnedCount: 0,
3526
+ firstSequence: null,
3527
+ lastSequence: null,
3528
+ truncated: false,
3529
+ hasMore: false,
3530
+ entries: [],
3531
+ view: "failed",
3532
+ warning: `Failed logs could not be loaded${reason}. The run status and persisted datasets are still available.`,
3533
+ next: { logs: retryCommand }
3534
+ };
3535
+ }
3536
+ return {
3537
+ ...status,
3538
+ failedLogs: {
3539
+ ...failedLogs,
3540
+ view: "failed",
3541
+ ...failedLogsLoaded ? {
3542
+ association: failedLogs.association ?? "terminal_failure_window"
3543
+ } : {}
3544
+ }
3545
+ };
3398
3546
  }
3399
3547
  /**
3400
3548
  * List play runs using the public runs resource model.
@@ -3545,6 +3693,7 @@ var DeeplineClient = class {
3545
3693
  onNotice: options?.onNotice,
3546
3694
  fallback: "none"
3547
3695
  })) {
3696
+ options?.onEvent?.(event);
3548
3697
  const status = updatePlayLiveStatusState(state, event);
3549
3698
  if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
3550
3699
  continue;
@@ -3608,6 +3757,7 @@ var DeeplineClient = class {
3608
3757
  mode: "cli",
3609
3758
  signal: options?.signal
3610
3759
  })) {
3760
+ options?.onEvent?.(event);
3611
3761
  sawEvent = true;
3612
3762
  const status = updatePlayLiveStatusState(state, event);
3613
3763
  if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
@@ -3657,6 +3807,37 @@ var DeeplineClient = class {
3657
3807
  * ```
3658
3808
  */
3659
3809
  async getRunLogs(runId, options) {
3810
+ if (options?.all === true && options.failed === true) {
3811
+ throw new DeeplineError(
3812
+ "runs.logs cannot combine all and failed views.",
3813
+ void 0,
3814
+ "INVALID_RUN_LOG_VIEW"
3815
+ );
3816
+ }
3817
+ if (options?.failed === true) {
3818
+ const requestedLimit = typeof options.limit === "number" && Number.isFinite(options.limit) && options.limit > 0 ? Math.trunc(options.limit) : RUNS_FAILED_LOG_LIMIT;
3819
+ const failedLimit = Math.min(RUNS_FAILED_LOG_LIMIT, requestedLimit);
3820
+ const page = await this.http.get(
3821
+ `/api/v2/runs/${encodeURIComponent(runId)}/logs?view=failed&limit=${failedLimit}`
3822
+ );
3823
+ return {
3824
+ runId: page.runId,
3825
+ totalCount: page.totalLogCount,
3826
+ returnedCount: page.entries.length,
3827
+ firstSequence: page.firstSeq,
3828
+ lastSequence: page.lastSeq,
3829
+ // The failed view is a complete designed window, not a pageable slice.
3830
+ // `truncated` means retention loss here; association/warning explain it.
3831
+ truncated: page.logsTruncated === true,
3832
+ hasMore: false,
3833
+ entries: page.entries.map((entry) => entry.line),
3834
+ view: page.view ?? "failed",
3835
+ association: page.association ?? "terminal_failure_window",
3836
+ ...page.warning ? { warning: page.warning } : {},
3837
+ ...page.next ? { next: page.next } : {},
3838
+ ...page.logsTruncated ? { logsTruncated: true } : {}
3839
+ };
3840
+ }
3660
3841
  const limit = options?.all ? Number.MAX_SAFE_INTEGER : typeof options?.limit === "number" && Number.isFinite(options.limit) && options.limit > 0 ? Math.trunc(options.limit) : 200;
3661
3842
  const fetchPage = (afterSeq2, pageLimit) => this.http.get(
3662
3843
  `/api/v2/runs/${encodeURIComponent(runId)}/logs?afterSeq=${afterSeq2}&limit=${pageLimit}`
@@ -3690,6 +3871,7 @@ var DeeplineClient = class {
3690
3871
  truncated: entries.length < probe.totalLogCount,
3691
3872
  hasMore: lastSequence !== null && lastSequence < lastStoredSeq,
3692
3873
  entries: entries.map((entry) => entry.line),
3874
+ view: options?.all ? "all" : "tail",
3693
3875
  ...probe.logsTruncated ? { logsTruncated: true } : {}
3694
3876
  };
3695
3877
  }
@@ -4485,16 +4667,33 @@ var DeferredPlayDataset = class {
4485
4667
  take(limit, options) {
4486
4668
  return this.slice(0, limit, options);
4487
4669
  }
4488
- async materialize(limit) {
4670
+ async materialize(options) {
4671
+ const scope = typeof options === "object" ? options.scope ?? "result" : "result";
4672
+ const limit = typeof options === "number" ? options : options?.limit;
4489
4673
  const requestedLimit = limit !== void 0 ? Math.max(0, Math.floor(limit)) : void 0;
4490
4674
  const cap = resolveMaterializeLimitCap();
4675
+ const materialize = scope === "full_persisted_dataset" ? this.resolvers.materializeFullPersistedDataset : this.resolvers.materialize;
4676
+ if (!materialize) {
4677
+ throw new Error(
4678
+ 'PlayDataset.materialize({ scope: "full_persisted_dataset" }) is only available for a persisted dataset returned by ctx.dataset(...).run().'
4679
+ );
4680
+ }
4491
4681
  if (requestedLimit !== void 0) {
4492
4682
  if (requestedLimit > cap) {
4493
4683
  throw new Error(
4494
4684
  `PlayDataset.materialize(${requestedLimit}) exceeds the hard limit of ${cap} rows. Return the dataset handle instead, or request a smaller bounded slice.`
4495
4685
  );
4496
4686
  }
4497
- return await this.resolvers.materialize(requestedLimit);
4687
+ return await materialize(requestedLimit);
4688
+ }
4689
+ if (scope === "full_persisted_dataset") {
4690
+ const rows = await materialize(cap + 1);
4691
+ if (rows.length > cap) {
4692
+ throw new Error(
4693
+ `PlayDataset.materialize({ scope: "full_persisted_dataset" }) refuses to load more than ${cap} rows into memory. Pass an explicit bounded limit.`
4694
+ );
4695
+ }
4696
+ return rows;
4498
4697
  }
4499
4698
  const count = await this.count();
4500
4699
  if (count > cap) {
@@ -4502,7 +4701,7 @@ var DeferredPlayDataset = class {
4502
4701
  `PlayDataset.materialize() refuses to load ${count} rows into memory. The hard limit is ${cap}. Return the dataset handle instead or call materialize(limit).`
4503
4702
  );
4504
4703
  }
4505
- return await this.resolvers.materialize();
4704
+ return await materialize();
4506
4705
  }
4507
4706
  async *[Symbol.asyncIterator]() {
4508
4707
  for await (const row of this.resolvers.iterate()) {
@@ -4831,7 +5030,7 @@ var TARGET_FALLBACK_KEYS = {
4831
5030
  status: [/^email_status$/i, /^status$/i],
4832
5031
  email_status: [/^email_status$/i, /^status$/i]
4833
5032
  };
4834
- function isRecord4(value) {
5033
+ function isRecord5(value) {
4835
5034
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4836
5035
  }
4837
5036
  function toV2RawToolOutputPath(path) {
@@ -4891,7 +5090,7 @@ function valuesAtSegments(current, segments, path = []) {
4891
5090
  if (!Array.isArray(current)) return [];
4892
5091
  return valuesAtSegments(current[segment], rest, [...path, segment]);
4893
5092
  }
4894
- if (!isRecord4(current)) return [];
5093
+ if (!isRecord5(current)) return [];
4895
5094
  const directMatches = valuesAtSegments(current[segment], rest, [
4896
5095
  ...path,
4897
5096
  segment
@@ -4921,7 +5120,7 @@ function getValuesAtPath(root, path) {
4921
5120
  return valuesAtSegments(root, parsePath(path)).map((entry) => entry.value);
4922
5121
  }
4923
5122
  function toResultEnvelope(value) {
4924
- if (isRecord4(value) && "data" in value) {
5123
+ if (isRecord5(value) && "data" in value) {
4925
5124
  const envelope = { data: value.data };
4926
5125
  if ("meta" in value) envelope.meta = value.meta;
4927
5126
  return envelope;
@@ -4974,7 +5173,7 @@ function getAtPath(root, path) {
4974
5173
  current = current[segment];
4975
5174
  continue;
4976
5175
  }
4977
- if (!isRecord4(current)) return void 0;
5176
+ if (!isRecord5(current)) return void 0;
4978
5177
  current = current[segment];
4979
5178
  }
4980
5179
  return current;
@@ -4991,7 +5190,7 @@ function normalizeString(value) {
4991
5190
  }
4992
5191
  function normalizeRows(value) {
4993
5192
  if (!Array.isArray(value)) return null;
4994
- return value.map((entry) => isRecord4(entry) ? entry : { value: entry });
5193
+ return value.map((entry) => isRecord5(entry) ? entry : { value: entry });
4995
5194
  }
4996
5195
  function findFirstTargetByPath(result, paths) {
4997
5196
  for (const path of paths ?? []) {
@@ -5050,7 +5249,7 @@ function findFirstTargetByKey(result, target, depth = 0, path = []) {
5050
5249
  }
5051
5250
  return null;
5052
5251
  }
5053
- if (!isRecord4(result)) return null;
5252
+ if (!isRecord5(result)) return null;
5054
5253
  const patterns = TARGET_FALLBACK_KEYS[target] ?? [
5055
5254
  new RegExp(`^${target}$`, "i")
5056
5255
  ];
@@ -5110,7 +5309,7 @@ function normalizeJobChangeStatus(value) {
5110
5309
  function firstExperienceDate(value) {
5111
5310
  if (!Array.isArray(value)) return null;
5112
5311
  for (const entry of value) {
5113
- if (!isRecord4(entry)) continue;
5312
+ if (!isRecord5(entry)) continue;
5114
5313
  const date = normalizeString(
5115
5314
  entry.start_date ?? entry.started_at ?? entry.startDate
5116
5315
  );
@@ -5119,10 +5318,10 @@ function firstExperienceDate(value) {
5119
5318
  return null;
5120
5319
  }
5121
5320
  function normalizeJobChange(value) {
5122
- const record = isRecord4(value) ? value : {};
5123
- const nested = isRecord4(record.job_change) ? record.job_change : record;
5124
- const output = isRecord4(nested.output) ? nested.output : nested;
5125
- const person = isRecord4(output.person) ? output.person : {};
5321
+ const record = isRecord5(value) ? value : {};
5322
+ const nested = isRecord5(record.job_change) ? record.job_change : record;
5323
+ const output = isRecord5(nested.output) ? nested.output : nested;
5324
+ const person = isRecord5(output.person) ? output.person : {};
5126
5325
  const status = normalizeJobChangeStatus(
5127
5326
  output.status ?? output.job_change_status ?? output.job_changed ?? output.changed
5128
5327
  );
@@ -5487,7 +5686,7 @@ function attachToolResultListDataset(result, input) {
5487
5686
  root = replaceAtPath(root, candidate, serialized.preview);
5488
5687
  break;
5489
5688
  }
5490
- if (isRecord4(root) && isRecord4(root.toolResponse) && Object.prototype.hasOwnProperty.call(root.toolResponse, "raw")) {
5689
+ if (isRecord5(root) && isRecord5(root.toolResponse) && Object.prototype.hasOwnProperty.call(root.toolResponse, "raw")) {
5491
5690
  result.toolResponse.raw = root.toolResponse.raw;
5492
5691
  result.toolOutput.raw = root.toolResponse.raw;
5493
5692
  }
@@ -5505,7 +5704,7 @@ function replaceAtPath(root, path, replacement) {
5505
5704
  copy[segment] = replace(copy[segment], index + 1);
5506
5705
  return copy;
5507
5706
  }
5508
- if (!isRecord4(current)) return current;
5707
+ if (!isRecord5(current)) return current;
5509
5708
  return {
5510
5709
  ...current,
5511
5710
  [segment]: replace(current[segment], index + 1)
@@ -5826,11 +6025,11 @@ var Deepline = class {
5826
6025
  return new DeeplineContext(options);
5827
6026
  }
5828
6027
  };
5829
- function isRecord5(value) {
6028
+ function isRecord6(value) {
5830
6029
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5831
6030
  }
5832
6031
  function stringArrayRecord(value) {
5833
- if (!isRecord5(value)) return {};
6032
+ if (!isRecord6(value)) return {};
5834
6033
  return Object.fromEntries(
5835
6034
  Object.entries(value).map(([key, paths]) => [
5836
6035
  key,
@@ -5842,7 +6041,7 @@ function stringArray(value) {
5842
6041
  return Array.isArray(value) ? value.map(String) : [];
5843
6042
  }
5844
6043
  function emailStatusExtractorConfig(value) {
5845
- if (!isRecord5(value)) return void 0;
6044
+ if (!isRecord6(value)) return void 0;
5846
6045
  const readPaths = (key) => {
5847
6046
  const paths = stringArray(value[key]).map((path) => path.trim()).filter(Boolean);
5848
6047
  return paths.length > 0 ? paths : void 0;
@@ -5869,7 +6068,7 @@ function emailStatusExtractorConfig(value) {
5869
6068
  const paths = readPaths(key);
5870
6069
  if (paths) config[key] = paths;
5871
6070
  }
5872
- if (isRecord5(value.statusMap)) {
6071
+ if (isRecord6(value.statusMap)) {
5873
6072
  config.statusMap = value.statusMap;
5874
6073
  }
5875
6074
  if (Array.isArray(value.rules)) {
@@ -5878,10 +6077,10 @@ function emailStatusExtractorConfig(value) {
5878
6077
  return config;
5879
6078
  }
5880
6079
  function extractorDescriptorRecord(value) {
5881
- if (!isRecord5(value)) return {};
6080
+ if (!isRecord6(value)) return {};
5882
6081
  return Object.fromEntries(
5883
6082
  Object.entries(value).flatMap(([key, descriptor]) => {
5884
- if (!isRecord5(descriptor)) return [];
6083
+ if (!isRecord6(descriptor)) return [];
5885
6084
  const paths = stringArray(descriptor.paths).map((path) => path.trim()).filter(Boolean);
5886
6085
  if (paths.length === 0) return [];
5887
6086
  const transforms = stringArray(descriptor.transforms).map((transform) => transform.trim()).filter(Boolean);
@@ -5903,7 +6102,7 @@ function extractorDescriptorRecord(value) {
5903
6102
  }
5904
6103
  function rowsFromUnknown(value) {
5905
6104
  if (!Array.isArray(value)) return [];
5906
- return value.map((row) => isRecord5(row) ? row : { value: row });
6105
+ return value.map((row) => isRecord6(row) ? row : { value: row });
5907
6106
  }
5908
6107
  function finiteNonNegativeInteger(value) {
5909
6108
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
@@ -5925,8 +6124,8 @@ function stableHash(value) {
5925
6124
  }
5926
6125
  function attachSdkQueryResultDatasetResult(toolId, result, options) {
5927
6126
  if (!options || !isQueryResultDatasetTool(toolId)) return result;
5928
- const raw = isRecord5(result.toolResponse.raw) ? result.toolResponse.raw : null;
5929
- const dataset = isRecord5(raw?.dataset) ? raw.dataset : null;
6127
+ const raw = isRecord6(result.toolResponse.raw) ? result.toolResponse.raw : null;
6128
+ const dataset = isRecord6(raw?.dataset) ? raw.dataset : null;
5930
6129
  const totalRows = finiteNonNegativeInteger(dataset?.total_rows);
5931
6130
  const sql = typeof options.input.sql === "string" ? options.input.sql : typeof options.input.query === "string" ? options.input.query : typeof raw?.sql === "string" ? raw.sql : null;
5932
6131
  if (!dataset || totalRows === null || !sql) {
@@ -5956,7 +6155,7 @@ function attachSdkQueryResultDatasetResult(toolId, result, options) {
5956
6155
  } : {}
5957
6156
  }
5958
6157
  });
5959
- const pageRaw = isRecord5(response.toolResponse?.raw) ? response.toolResponse.raw : null;
6158
+ const pageRaw = isRecord6(response.toolResponse?.raw) ? response.toolResponse.raw : null;
5960
6159
  return rowsFromUnknown(pageRaw?.rows);
5961
6160
  };
5962
6161
  const collectRows = async (limit) => {
@@ -6009,8 +6208,8 @@ function attachSdkQueryResultDatasetResult(toolId, result, options) {
6009
6208
  function toolExecutionEnvelopeToResult(fallbackToolId, response, options) {
6010
6209
  const raw = response.toolResponse?.raw ?? null;
6011
6210
  const meta = response.toolResponse?.meta;
6012
- const metadata = isRecord5(response._metadata) ? response._metadata.tool : null;
6013
- const toolMetadata = isRecord5(metadata) ? metadata : {};
6211
+ const metadata = isRecord6(response._metadata) ? response._metadata.tool : null;
6212
+ const toolMetadata = isRecord6(metadata) ? metadata : {};
6014
6213
  return attachSdkQueryResultDatasetResult(
6015
6214
  fallbackToolId,
6016
6215
  createToolExecuteResult({
@@ -6018,7 +6217,7 @@ function toolExecutionEnvelopeToResult(fallbackToolId, response, options) {
6018
6217
  jobId: typeof response.job_id === "string" ? response.job_id : void 0,
6019
6218
  result: {
6020
6219
  data: raw,
6021
- ...isRecord5(meta) ? { meta } : {}
6220
+ ...isRecord6(meta) ? { meta } : {}
6022
6221
  },
6023
6222
  metadata: {
6024
6223
  toolId: typeof toolMetadata.toolId === "string" ? toolMetadata.toolId : fallbackToolId,
@@ -6034,7 +6233,7 @@ function toolExecutionEnvelopeToResult(fallbackToolId, response, options) {
6034
6233
  cached: false,
6035
6234
  source: "live"
6036
6235
  },
6037
- meta: isRecord5(response.meta) ? response.meta : void 0
6236
+ meta: isRecord6(response.meta) ? response.meta : void 0
6038
6237
  }),
6039
6238
  options
6040
6239
  );