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.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.210",
355
+ version: "0.1.212",
356
356
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
357
357
  supportPolicy: {
358
- latest: "0.1.210",
358
+ latest: "0.1.212",
359
359
  minimumSupported: "0.1.53",
360
360
  deprecatedBelow: "0.1.53",
361
361
  commandMinimumSupported: [
@@ -1088,9 +1088,91 @@ function normalizePlayRunLedgerTerminalSource(value) {
1088
1088
  ) ? value : null;
1089
1089
  }
1090
1090
 
1091
+ // ../shared_libs/play-runtime/secret-redaction.ts
1092
+ var SECRET_REDACTION_PLACEHOLDER = "[REDACTED_SECRET]";
1093
+ var BEARER_TOKEN_RE = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/g;
1094
+ var JWT_RE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g;
1095
+ var PRIVATE_KEY_RE = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g;
1096
+ 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;
1097
+ var URL_SECRET_VALUE_RE = /\b(?:sk|pk|rk|pat|ghp|github_pat|xox)[A-Za-z0-9_./+=:-]{12,}\b/i;
1098
+ var HIGH_ENTROPY_ASSIGNMENT_RE = /\b(?:api[_-]?key|token|secret|password|authorization|access[_-]?token|refresh[_-]?token)\b\s*[:=]\s*["']?[^"',\s]{16,}["']?/gi;
1099
+ var SENSITIVE_URL_PARAM_RE = /[?#&](?:\w*(?:key|token)|secret|password|authorization|credential|signature|sig)(?:=|$)/i;
1100
+ function escapeRegExp(value) {
1101
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1102
+ }
1103
+ function isRecord(value) {
1104
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1105
+ }
1106
+ function redactSecretLikeString(value) {
1107
+ const trimmed = value.trim();
1108
+ if (/^https?:\/\/\S+$/i.test(trimmed)) {
1109
+ if (/^https?:\/\/[^/?#@]+@/i.test(trimmed) || SENSITIVE_URL_PARAM_RE.test(trimmed)) {
1110
+ return SECRET_REDACTION_PLACEHOLDER;
1111
+ }
1112
+ if (!URL_SECRET_VALUE_RE.test(value)) return value;
1113
+ }
1114
+ 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) => {
1115
+ const separator = match.includes("=") ? "=" : ":";
1116
+ const [key] = match.split(separator, 1);
1117
+ return `${key.trim()}${separator}${SECRET_REDACTION_PLACEHOLDER}`;
1118
+ });
1119
+ }
1120
+ function createSecretRedactionContext(initialValues = []) {
1121
+ const exactSecrets = /* @__PURE__ */ new Set();
1122
+ function register(value) {
1123
+ if (value.length >= 4) exactSecrets.add(value);
1124
+ }
1125
+ for (const value of initialValues) register(value);
1126
+ function redactString(value) {
1127
+ let output = value;
1128
+ for (const secret of exactSecrets) {
1129
+ output = output.replace(
1130
+ new RegExp(escapeRegExp(secret), "g"),
1131
+ SECRET_REDACTION_PLACEHOLDER
1132
+ );
1133
+ try {
1134
+ const encoded = encodeURIComponent(secret);
1135
+ if (encoded !== secret) {
1136
+ output = output.replace(
1137
+ new RegExp(escapeRegExp(encoded), "g"),
1138
+ SECRET_REDACTION_PLACEHOLDER
1139
+ );
1140
+ }
1141
+ } catch {
1142
+ }
1143
+ }
1144
+ return redactSecretLikeString(output);
1145
+ }
1146
+ function redact(value) {
1147
+ if (typeof value === "string") return redactString(value);
1148
+ if (Array.isArray(value)) return value.map((entry) => redact(entry));
1149
+ if (isRecord(value)) {
1150
+ return Object.fromEntries(
1151
+ Object.entries(value).map(([key, entry]) => [key, redact(entry)])
1152
+ );
1153
+ }
1154
+ return value;
1155
+ }
1156
+ return {
1157
+ register,
1158
+ redactString,
1159
+ redact
1160
+ };
1161
+ }
1162
+
1163
+ // ../shared_libs/play-runtime/output-size-limits.ts
1164
+ var encoder = typeof TextEncoder === "undefined" ? null : new TextEncoder();
1165
+ var CUSTOMER_OUTPUT_VALUE_MAX_BYTES = 1 * 1024 * 1024;
1166
+ var CUSTOMER_OUTPUT_TOTAL_MAX_BYTES = 2 * 1024 * 1024;
1167
+ var RUNTIME_RECEIPT_OUTPUT_MAX_BYTES = 10 * 1024 * 1024;
1168
+ var RUNTIME_RECEIPT_COMPLETION_BUFFER_MAX_BYTES = 32 * 1024 * 1024;
1169
+
1170
+ // ../shared_libs/play-runtime/ledger-safe-payload.ts
1171
+ var ledgerIngressRedactor = createSecretRedactionContext();
1172
+
1091
1173
  // ../shared_libs/play-runtime/run-ledger.ts
1092
1174
  var LOG_TAIL_LIMIT = 100;
1093
- function isRecord(value) {
1175
+ function isRecord2(value) {
1094
1176
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1095
1177
  }
1096
1178
  function finiteNumber(value) {
@@ -1172,6 +1254,8 @@ function createEmptyPlayRunLedgerSnapshot(input) {
1172
1254
  durationMs: startedAt !== null && finishedAt !== null ? Math.max(0, finishedAt - startedAt) : null,
1173
1255
  orderedStepIds: [],
1174
1256
  stepsById: {},
1257
+ orderedDatasetIds: [],
1258
+ datasetsById: {},
1175
1259
  logTail: [],
1176
1260
  totalLogCount: 0,
1177
1261
  logsTruncated: false,
@@ -1181,21 +1265,21 @@ function createEmptyPlayRunLedgerSnapshot(input) {
1181
1265
  };
1182
1266
  }
1183
1267
  function normalizePlayRunLedgerSnapshot(value, fallback) {
1184
- if (!isRecord(value)) {
1268
+ if (!isRecord2(value)) {
1185
1269
  return createEmptyPlayRunLedgerSnapshot(fallback);
1186
1270
  }
1187
1271
  const orderedStepIds = Array.isArray(value.orderedStepIds) ? value.orderedStepIds.filter(
1188
1272
  (entry) => typeof entry === "string" && Boolean(entry.trim())
1189
1273
  ) : [];
1190
- const rawSteps = isRecord(value.stepsById) ? value.stepsById : {};
1274
+ const rawSteps = isRecord2(value.stepsById) ? value.stepsById : {};
1191
1275
  const stepsById = {};
1192
1276
  for (const [stepId, rawStep] of Object.entries(rawSteps)) {
1193
- if (!stepId.trim() || !isRecord(rawStep)) continue;
1277
+ if (!stepId.trim() || !isRecord2(rawStep)) continue;
1194
1278
  const rawStatus = normalizeStepStatus(rawStep.status);
1195
1279
  if (!rawStatus) continue;
1196
1280
  const completedAt = finiteNumber(rawStep.completedAt);
1197
1281
  const status = rawStatus === "running" && completedAt !== null ? "completed" : rawStatus;
1198
- const rawProgress = isRecord(rawStep.progress) ? rawStep.progress : null;
1282
+ const rawProgress = isRecord2(rawStep.progress) ? rawStep.progress : null;
1199
1283
  stepsById[stepId] = {
1200
1284
  stepId,
1201
1285
  label: optionalString(rawStep.label),
@@ -1210,6 +1294,23 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
1210
1294
  progress: rawProgress ? normalizeStepProgress(rawProgress) : null
1211
1295
  };
1212
1296
  }
1297
+ const rawDatasets = isRecord2(value.datasetsById) ? value.datasetsById : {};
1298
+ const datasetsById = {};
1299
+ for (const [datasetId, rawDataset] of Object.entries(rawDatasets)) {
1300
+ if (!datasetId.trim() || !isRecord2(rawDataset)) continue;
1301
+ const phase = rawDataset.phase === "available" || rawDataset.phase === "failed" ? rawDataset.phase : "registered";
1302
+ datasetsById[datasetId] = {
1303
+ datasetId,
1304
+ path: optionalString(rawDataset.path) ?? `datasets.${datasetId}`,
1305
+ tableNamespace: optionalString(rawDataset.tableNamespace) ?? datasetId,
1306
+ phase,
1307
+ persistedRows: Math.max(0, finiteNumber(rawDataset.persistedRows) ?? 0),
1308
+ succeededRows: Math.max(0, finiteNumber(rawDataset.succeededRows) ?? 0),
1309
+ failedRows: Math.max(0, finiteNumber(rawDataset.failedRows) ?? 0),
1310
+ complete: rawDataset.complete === true,
1311
+ updatedAt: finiteNumber(rawDataset.updatedAt) ?? 0
1312
+ };
1313
+ }
1213
1314
  const createdAt = finiteNumber(value.createdAt) ?? fallback.createdAt ?? null;
1214
1315
  const startedAt = finiteNumber(value.startedAt) ?? fallback.startedAt ?? null;
1215
1316
  const finishedAt = finiteNumber(value.finishedAt) ?? fallback.finishedAt ?? null;
@@ -1229,6 +1330,10 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
1229
1330
  durationMs: startedAt !== null && finishedAt !== null ? Math.max(0, finishedAt - startedAt) : finiteNumber(value.durationMs),
1230
1331
  orderedStepIds: orderedStepIds.filter((stepId) => stepsById[stepId]),
1231
1332
  stepsById,
1333
+ orderedDatasetIds: (Array.isArray(value.orderedDatasetIds) ? value.orderedDatasetIds : Object.keys(datasetsById)).filter(
1334
+ (datasetId) => typeof datasetId === "string" && Boolean(datasetsById[datasetId])
1335
+ ),
1336
+ datasetsById,
1232
1337
  logTail: logTail.slice(-LOG_TAIL_LIMIT),
1233
1338
  // Snapshots persisted before totalLogCount existed only know the retained
1234
1339
  // tail, so the best lower bound for the cumulative count is the tail size.
@@ -1323,18 +1428,18 @@ function normalizePlayRunLiveStatus(value) {
1323
1428
  function isTerminalPlayRunLiveStatus(status) {
1324
1429
  return isTerminalPlayRunLifecycleStatus(status);
1325
1430
  }
1326
- function isRecord2(value) {
1431
+ function isRecord3(value) {
1327
1432
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
1328
1433
  }
1329
1434
  function finiteNumber2(value) {
1330
1435
  return typeof value === "number" && Number.isFinite(value) ? value : null;
1331
1436
  }
1332
1437
  function extractTerminalRunLogTail(result) {
1333
- if (!isRecord2(result) || !isRecord2(result._metadata)) {
1438
+ if (!isRecord3(result) || !isRecord3(result._metadata)) {
1334
1439
  return null;
1335
1440
  }
1336
1441
  const runLogTail = result._metadata.runLogTail;
1337
- if (!isRecord2(runLogTail) || !Array.isArray(runLogTail.tail)) {
1442
+ if (!isRecord3(runLogTail) || !Array.isArray(runLogTail.tail)) {
1338
1443
  return null;
1339
1444
  }
1340
1445
  const logTail = runLogTail.tail.filter(
@@ -1390,6 +1495,9 @@ function buildSnapshotFromLedger(snapshot) {
1390
1495
  ...snapshot.logsTruncated ? { logsTruncated: true } : {},
1391
1496
  activeArtifactTableNamespace: snapshot.activeArtifactTableNamespace ?? null,
1392
1497
  resultTableNamespace: snapshot.resultTableNamespace ?? null,
1498
+ datasets: snapshot.orderedDatasetIds.map((datasetId) => snapshot.datasetsById[datasetId]).filter(
1499
+ (dataset) => Boolean(dataset)
1500
+ ),
1393
1501
  nodeStates,
1394
1502
  activeNodeId: snapshot.activeStepId ?? null,
1395
1503
  ...rowOutcomes ? { rowOutcomes } : {}
@@ -2066,8 +2174,9 @@ function resolveToolExecuteTimeoutMs(toolId) {
2066
2174
  const normalized = toolId.trim().toLowerCase();
2067
2175
  return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
2068
2176
  }
2177
+ var RUNS_FAILED_LOG_LIMIT = 20;
2069
2178
  var RUN_LOGS_PAGE_LIMIT = 1e3;
2070
- function isRecord3(value) {
2179
+ function isRecord4(value) {
2071
2180
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
2072
2181
  }
2073
2182
  function isPrebuiltPlayDescription(play) {
@@ -2224,7 +2333,7 @@ function updatePlayLiveStatusState(state, event) {
2224
2333
  }
2225
2334
  const runId = typeof payload.runId === "string" && payload.runId ? payload.runId : isPlayRunPackage(payload) ? payload.run.id : state.runId;
2226
2335
  const status = normalizeLiveStatus(payload.status) ?? (isPlayRunPackage(payload) ? normalizeLiveStatus(payload.run.status) : null) ?? state.status;
2227
- const progressPayload = isRecord3(payload.progress) ? payload.progress : {};
2336
+ const progressPayload = isRecord4(payload.progress) ? payload.progress : {};
2228
2337
  if (event.type === "play.run.final_status" && state.logs.length === 0 && state.lastLogSeq === 0) {
2229
2338
  const payloadLogs = readStringArray(payload.logs);
2230
2339
  const progressLogs = readStringArray(progressPayload.logs);
@@ -2339,9 +2448,9 @@ var DeeplineClient = class {
2339
2448
  return fields.length > 0 ? { fields } : schema;
2340
2449
  }
2341
2450
  schemaMetadata(schema, key) {
2342
- if (!isRecord3(schema)) return null;
2451
+ if (!isRecord4(schema)) return null;
2343
2452
  const value = schema[key];
2344
- return isRecord3(value) ? value : null;
2453
+ return isRecord4(value) ? value : null;
2345
2454
  }
2346
2455
  playRunCommand(play, options) {
2347
2456
  const target = play.reference || play.name;
@@ -2390,7 +2499,7 @@ var DeeplineClient = class {
2390
2499
  aliases,
2391
2500
  inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
2392
2501
  outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
2393
- staticPipeline: isRecord3(play.staticPipeline) ? play.staticPipeline : isRecord3(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord3(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
2502
+ staticPipeline: isRecord4(play.staticPipeline) ? play.staticPipeline : isRecord4(play.currentRevision?.staticPipeline) ? play.currentRevision.staticPipeline : isRecord4(play.liveRevision?.staticPipeline) ? play.liveRevision.staticPipeline : null,
2394
2503
  ...csvInput ? { csvInput } : {},
2395
2504
  ...rowOutputSchema ? { rowOutputSchema } : {},
2396
2505
  runCommand,
@@ -3324,7 +3433,46 @@ var DeeplineClient = class {
3324
3433
  const response = await this.http.get(
3325
3434
  `/api/v2/runs/${encodeURIComponent(runId)}${query}`
3326
3435
  );
3327
- return normalizePlayStatus(response);
3436
+ const status = normalizePlayStatus(response);
3437
+ if (options?.failedLogs !== true || status.status !== "failed") {
3438
+ return status;
3439
+ }
3440
+ const requestedFailedLogLimit = typeof options.failedLogLimit === "number" && Number.isFinite(options.failedLogLimit) ? Math.max(1, Math.floor(options.failedLogLimit)) : RUNS_FAILED_LOG_LIMIT;
3441
+ let failedLogs;
3442
+ let failedLogsLoaded = true;
3443
+ try {
3444
+ failedLogs = await this.getRunLogs(runId, {
3445
+ failed: true,
3446
+ limit: Math.min(RUNS_FAILED_LOG_LIMIT, requestedFailedLogLimit)
3447
+ });
3448
+ } catch (error) {
3449
+ failedLogsLoaded = false;
3450
+ const retryCommand = `deepline runs get ${runId} --log-failed --json`;
3451
+ const reason = error instanceof Error && error.message.trim() ? ` (${error.message.trim().slice(0, 500)})` : "";
3452
+ failedLogs = {
3453
+ runId,
3454
+ totalCount: 0,
3455
+ returnedCount: 0,
3456
+ firstSequence: null,
3457
+ lastSequence: null,
3458
+ truncated: false,
3459
+ hasMore: false,
3460
+ entries: [],
3461
+ view: "failed",
3462
+ warning: `Failed logs could not be loaded${reason}. The run status and persisted datasets are still available.`,
3463
+ next: { logs: retryCommand }
3464
+ };
3465
+ }
3466
+ return {
3467
+ ...status,
3468
+ failedLogs: {
3469
+ ...failedLogs,
3470
+ view: "failed",
3471
+ ...failedLogsLoaded ? {
3472
+ association: failedLogs.association ?? "terminal_failure_window"
3473
+ } : {}
3474
+ }
3475
+ };
3328
3476
  }
3329
3477
  /**
3330
3478
  * List play runs using the public runs resource model.
@@ -3475,6 +3623,7 @@ var DeeplineClient = class {
3475
3623
  onNotice: options?.onNotice,
3476
3624
  fallback: "none"
3477
3625
  })) {
3626
+ options?.onEvent?.(event);
3478
3627
  const status = updatePlayLiveStatusState(state, event);
3479
3628
  if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
3480
3629
  continue;
@@ -3538,6 +3687,7 @@ var DeeplineClient = class {
3538
3687
  mode: "cli",
3539
3688
  signal: options?.signal
3540
3689
  })) {
3690
+ options?.onEvent?.(event);
3541
3691
  sawEvent = true;
3542
3692
  const status = updatePlayLiveStatusState(state, event);
3543
3693
  if (!status || !TERMINAL_PLAY_STATUSES.has(status.status)) {
@@ -3587,6 +3737,37 @@ var DeeplineClient = class {
3587
3737
  * ```
3588
3738
  */
3589
3739
  async getRunLogs(runId, options) {
3740
+ if (options?.all === true && options.failed === true) {
3741
+ throw new DeeplineError(
3742
+ "runs.logs cannot combine all and failed views.",
3743
+ void 0,
3744
+ "INVALID_RUN_LOG_VIEW"
3745
+ );
3746
+ }
3747
+ if (options?.failed === true) {
3748
+ const requestedLimit = typeof options.limit === "number" && Number.isFinite(options.limit) && options.limit > 0 ? Math.trunc(options.limit) : RUNS_FAILED_LOG_LIMIT;
3749
+ const failedLimit = Math.min(RUNS_FAILED_LOG_LIMIT, requestedLimit);
3750
+ const page = await this.http.get(
3751
+ `/api/v2/runs/${encodeURIComponent(runId)}/logs?view=failed&limit=${failedLimit}`
3752
+ );
3753
+ return {
3754
+ runId: page.runId,
3755
+ totalCount: page.totalLogCount,
3756
+ returnedCount: page.entries.length,
3757
+ firstSequence: page.firstSeq,
3758
+ lastSequence: page.lastSeq,
3759
+ // The failed view is a complete designed window, not a pageable slice.
3760
+ // `truncated` means retention loss here; association/warning explain it.
3761
+ truncated: page.logsTruncated === true,
3762
+ hasMore: false,
3763
+ entries: page.entries.map((entry) => entry.line),
3764
+ view: page.view ?? "failed",
3765
+ association: page.association ?? "terminal_failure_window",
3766
+ ...page.warning ? { warning: page.warning } : {},
3767
+ ...page.next ? { next: page.next } : {},
3768
+ ...page.logsTruncated ? { logsTruncated: true } : {}
3769
+ };
3770
+ }
3590
3771
  const limit = options?.all ? Number.MAX_SAFE_INTEGER : typeof options?.limit === "number" && Number.isFinite(options.limit) && options.limit > 0 ? Math.trunc(options.limit) : 200;
3591
3772
  const fetchPage = (afterSeq2, pageLimit) => this.http.get(
3592
3773
  `/api/v2/runs/${encodeURIComponent(runId)}/logs?afterSeq=${afterSeq2}&limit=${pageLimit}`
@@ -3620,6 +3801,7 @@ var DeeplineClient = class {
3620
3801
  truncated: entries.length < probe.totalLogCount,
3621
3802
  hasMore: lastSequence !== null && lastSequence < lastStoredSeq,
3622
3803
  entries: entries.map((entry) => entry.line),
3804
+ view: options?.all ? "all" : "tail",
3623
3805
  ...probe.logsTruncated ? { logsTruncated: true } : {}
3624
3806
  };
3625
3807
  }
@@ -4415,16 +4597,33 @@ var DeferredPlayDataset = class {
4415
4597
  take(limit, options) {
4416
4598
  return this.slice(0, limit, options);
4417
4599
  }
4418
- async materialize(limit) {
4600
+ async materialize(options) {
4601
+ const scope = typeof options === "object" ? options.scope ?? "result" : "result";
4602
+ const limit = typeof options === "number" ? options : options?.limit;
4419
4603
  const requestedLimit = limit !== void 0 ? Math.max(0, Math.floor(limit)) : void 0;
4420
4604
  const cap = resolveMaterializeLimitCap();
4605
+ const materialize = scope === "full_persisted_dataset" ? this.resolvers.materializeFullPersistedDataset : this.resolvers.materialize;
4606
+ if (!materialize) {
4607
+ throw new Error(
4608
+ 'PlayDataset.materialize({ scope: "full_persisted_dataset" }) is only available for a persisted dataset returned by ctx.dataset(...).run().'
4609
+ );
4610
+ }
4421
4611
  if (requestedLimit !== void 0) {
4422
4612
  if (requestedLimit > cap) {
4423
4613
  throw new Error(
4424
4614
  `PlayDataset.materialize(${requestedLimit}) exceeds the hard limit of ${cap} rows. Return the dataset handle instead, or request a smaller bounded slice.`
4425
4615
  );
4426
4616
  }
4427
- return await this.resolvers.materialize(requestedLimit);
4617
+ return await materialize(requestedLimit);
4618
+ }
4619
+ if (scope === "full_persisted_dataset") {
4620
+ const rows = await materialize(cap + 1);
4621
+ if (rows.length > cap) {
4622
+ throw new Error(
4623
+ `PlayDataset.materialize({ scope: "full_persisted_dataset" }) refuses to load more than ${cap} rows into memory. Pass an explicit bounded limit.`
4624
+ );
4625
+ }
4626
+ return rows;
4428
4627
  }
4429
4628
  const count = await this.count();
4430
4629
  if (count > cap) {
@@ -4432,7 +4631,7 @@ var DeferredPlayDataset = class {
4432
4631
  `PlayDataset.materialize() refuses to load ${count} rows into memory. The hard limit is ${cap}. Return the dataset handle instead or call materialize(limit).`
4433
4632
  );
4434
4633
  }
4435
- return await this.resolvers.materialize();
4634
+ return await materialize();
4436
4635
  }
4437
4636
  async *[Symbol.asyncIterator]() {
4438
4637
  for await (const row of this.resolvers.iterate()) {
@@ -4761,7 +4960,7 @@ var TARGET_FALLBACK_KEYS = {
4761
4960
  status: [/^email_status$/i, /^status$/i],
4762
4961
  email_status: [/^email_status$/i, /^status$/i]
4763
4962
  };
4764
- function isRecord4(value) {
4963
+ function isRecord5(value) {
4765
4964
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4766
4965
  }
4767
4966
  function toV2RawToolOutputPath(path) {
@@ -4821,7 +5020,7 @@ function valuesAtSegments(current, segments, path = []) {
4821
5020
  if (!Array.isArray(current)) return [];
4822
5021
  return valuesAtSegments(current[segment], rest, [...path, segment]);
4823
5022
  }
4824
- if (!isRecord4(current)) return [];
5023
+ if (!isRecord5(current)) return [];
4825
5024
  const directMatches = valuesAtSegments(current[segment], rest, [
4826
5025
  ...path,
4827
5026
  segment
@@ -4851,7 +5050,7 @@ function getValuesAtPath(root, path) {
4851
5050
  return valuesAtSegments(root, parsePath(path)).map((entry) => entry.value);
4852
5051
  }
4853
5052
  function toResultEnvelope(value) {
4854
- if (isRecord4(value) && "data" in value) {
5053
+ if (isRecord5(value) && "data" in value) {
4855
5054
  const envelope = { data: value.data };
4856
5055
  if ("meta" in value) envelope.meta = value.meta;
4857
5056
  return envelope;
@@ -4904,7 +5103,7 @@ function getAtPath(root, path) {
4904
5103
  current = current[segment];
4905
5104
  continue;
4906
5105
  }
4907
- if (!isRecord4(current)) return void 0;
5106
+ if (!isRecord5(current)) return void 0;
4908
5107
  current = current[segment];
4909
5108
  }
4910
5109
  return current;
@@ -4921,7 +5120,7 @@ function normalizeString(value) {
4921
5120
  }
4922
5121
  function normalizeRows(value) {
4923
5122
  if (!Array.isArray(value)) return null;
4924
- return value.map((entry) => isRecord4(entry) ? entry : { value: entry });
5123
+ return value.map((entry) => isRecord5(entry) ? entry : { value: entry });
4925
5124
  }
4926
5125
  function findFirstTargetByPath(result, paths) {
4927
5126
  for (const path of paths ?? []) {
@@ -4980,7 +5179,7 @@ function findFirstTargetByKey(result, target, depth = 0, path = []) {
4980
5179
  }
4981
5180
  return null;
4982
5181
  }
4983
- if (!isRecord4(result)) return null;
5182
+ if (!isRecord5(result)) return null;
4984
5183
  const patterns = TARGET_FALLBACK_KEYS[target] ?? [
4985
5184
  new RegExp(`^${target}$`, "i")
4986
5185
  ];
@@ -5040,7 +5239,7 @@ function normalizeJobChangeStatus(value) {
5040
5239
  function firstExperienceDate(value) {
5041
5240
  if (!Array.isArray(value)) return null;
5042
5241
  for (const entry of value) {
5043
- if (!isRecord4(entry)) continue;
5242
+ if (!isRecord5(entry)) continue;
5044
5243
  const date = normalizeString(
5045
5244
  entry.start_date ?? entry.started_at ?? entry.startDate
5046
5245
  );
@@ -5049,10 +5248,10 @@ function firstExperienceDate(value) {
5049
5248
  return null;
5050
5249
  }
5051
5250
  function normalizeJobChange(value) {
5052
- const record = isRecord4(value) ? value : {};
5053
- const nested = isRecord4(record.job_change) ? record.job_change : record;
5054
- const output = isRecord4(nested.output) ? nested.output : nested;
5055
- const person = isRecord4(output.person) ? output.person : {};
5251
+ const record = isRecord5(value) ? value : {};
5252
+ const nested = isRecord5(record.job_change) ? record.job_change : record;
5253
+ const output = isRecord5(nested.output) ? nested.output : nested;
5254
+ const person = isRecord5(output.person) ? output.person : {};
5056
5255
  const status = normalizeJobChangeStatus(
5057
5256
  output.status ?? output.job_change_status ?? output.job_changed ?? output.changed
5058
5257
  );
@@ -5417,7 +5616,7 @@ function attachToolResultListDataset(result, input) {
5417
5616
  root = replaceAtPath(root, candidate, serialized.preview);
5418
5617
  break;
5419
5618
  }
5420
- if (isRecord4(root) && isRecord4(root.toolResponse) && Object.prototype.hasOwnProperty.call(root.toolResponse, "raw")) {
5619
+ if (isRecord5(root) && isRecord5(root.toolResponse) && Object.prototype.hasOwnProperty.call(root.toolResponse, "raw")) {
5421
5620
  result.toolResponse.raw = root.toolResponse.raw;
5422
5621
  result.toolOutput.raw = root.toolResponse.raw;
5423
5622
  }
@@ -5435,7 +5634,7 @@ function replaceAtPath(root, path, replacement) {
5435
5634
  copy[segment] = replace(copy[segment], index + 1);
5436
5635
  return copy;
5437
5636
  }
5438
- if (!isRecord4(current)) return current;
5637
+ if (!isRecord5(current)) return current;
5439
5638
  return {
5440
5639
  ...current,
5441
5640
  [segment]: replace(current[segment], index + 1)
@@ -5756,11 +5955,11 @@ var Deepline = class {
5756
5955
  return new DeeplineContext(options);
5757
5956
  }
5758
5957
  };
5759
- function isRecord5(value) {
5958
+ function isRecord6(value) {
5760
5959
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5761
5960
  }
5762
5961
  function stringArrayRecord(value) {
5763
- if (!isRecord5(value)) return {};
5962
+ if (!isRecord6(value)) return {};
5764
5963
  return Object.fromEntries(
5765
5964
  Object.entries(value).map(([key, paths]) => [
5766
5965
  key,
@@ -5772,7 +5971,7 @@ function stringArray(value) {
5772
5971
  return Array.isArray(value) ? value.map(String) : [];
5773
5972
  }
5774
5973
  function emailStatusExtractorConfig(value) {
5775
- if (!isRecord5(value)) return void 0;
5974
+ if (!isRecord6(value)) return void 0;
5776
5975
  const readPaths = (key) => {
5777
5976
  const paths = stringArray(value[key]).map((path) => path.trim()).filter(Boolean);
5778
5977
  return paths.length > 0 ? paths : void 0;
@@ -5799,7 +5998,7 @@ function emailStatusExtractorConfig(value) {
5799
5998
  const paths = readPaths(key);
5800
5999
  if (paths) config[key] = paths;
5801
6000
  }
5802
- if (isRecord5(value.statusMap)) {
6001
+ if (isRecord6(value.statusMap)) {
5803
6002
  config.statusMap = value.statusMap;
5804
6003
  }
5805
6004
  if (Array.isArray(value.rules)) {
@@ -5808,10 +6007,10 @@ function emailStatusExtractorConfig(value) {
5808
6007
  return config;
5809
6008
  }
5810
6009
  function extractorDescriptorRecord(value) {
5811
- if (!isRecord5(value)) return {};
6010
+ if (!isRecord6(value)) return {};
5812
6011
  return Object.fromEntries(
5813
6012
  Object.entries(value).flatMap(([key, descriptor]) => {
5814
- if (!isRecord5(descriptor)) return [];
6013
+ if (!isRecord6(descriptor)) return [];
5815
6014
  const paths = stringArray(descriptor.paths).map((path) => path.trim()).filter(Boolean);
5816
6015
  if (paths.length === 0) return [];
5817
6016
  const transforms = stringArray(descriptor.transforms).map((transform) => transform.trim()).filter(Boolean);
@@ -5833,7 +6032,7 @@ function extractorDescriptorRecord(value) {
5833
6032
  }
5834
6033
  function rowsFromUnknown(value) {
5835
6034
  if (!Array.isArray(value)) return [];
5836
- return value.map((row) => isRecord5(row) ? row : { value: row });
6035
+ return value.map((row) => isRecord6(row) ? row : { value: row });
5837
6036
  }
5838
6037
  function finiteNonNegativeInteger(value) {
5839
6038
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
@@ -5855,8 +6054,8 @@ function stableHash(value) {
5855
6054
  }
5856
6055
  function attachSdkQueryResultDatasetResult(toolId, result, options) {
5857
6056
  if (!options || !isQueryResultDatasetTool(toolId)) return result;
5858
- const raw = isRecord5(result.toolResponse.raw) ? result.toolResponse.raw : null;
5859
- const dataset = isRecord5(raw?.dataset) ? raw.dataset : null;
6057
+ const raw = isRecord6(result.toolResponse.raw) ? result.toolResponse.raw : null;
6058
+ const dataset = isRecord6(raw?.dataset) ? raw.dataset : null;
5860
6059
  const totalRows = finiteNonNegativeInteger(dataset?.total_rows);
5861
6060
  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;
5862
6061
  if (!dataset || totalRows === null || !sql) {
@@ -5886,7 +6085,7 @@ function attachSdkQueryResultDatasetResult(toolId, result, options) {
5886
6085
  } : {}
5887
6086
  }
5888
6087
  });
5889
- const pageRaw = isRecord5(response.toolResponse?.raw) ? response.toolResponse.raw : null;
6088
+ const pageRaw = isRecord6(response.toolResponse?.raw) ? response.toolResponse.raw : null;
5890
6089
  return rowsFromUnknown(pageRaw?.rows);
5891
6090
  };
5892
6091
  const collectRows = async (limit) => {
@@ -5939,8 +6138,8 @@ function attachSdkQueryResultDatasetResult(toolId, result, options) {
5939
6138
  function toolExecutionEnvelopeToResult(fallbackToolId, response, options) {
5940
6139
  const raw = response.toolResponse?.raw ?? null;
5941
6140
  const meta = response.toolResponse?.meta;
5942
- const metadata = isRecord5(response._metadata) ? response._metadata.tool : null;
5943
- const toolMetadata = isRecord5(metadata) ? metadata : {};
6141
+ const metadata = isRecord6(response._metadata) ? response._metadata.tool : null;
6142
+ const toolMetadata = isRecord6(metadata) ? metadata : {};
5944
6143
  return attachSdkQueryResultDatasetResult(
5945
6144
  fallbackToolId,
5946
6145
  createToolExecuteResult({
@@ -5948,7 +6147,7 @@ function toolExecutionEnvelopeToResult(fallbackToolId, response, options) {
5948
6147
  jobId: typeof response.job_id === "string" ? response.job_id : void 0,
5949
6148
  result: {
5950
6149
  data: raw,
5951
- ...isRecord5(meta) ? { meta } : {}
6150
+ ...isRecord6(meta) ? { meta } : {}
5952
6151
  },
5953
6152
  metadata: {
5954
6153
  toolId: typeof toolMetadata.toolId === "string" ? toolMetadata.toolId : fallbackToolId,
@@ -5964,7 +6163,7 @@ function toolExecutionEnvelopeToResult(fallbackToolId, response, options) {
5964
6163
  cached: false,
5965
6164
  source: "live"
5966
6165
  },
5967
- meta: isRecord5(response.meta) ? response.meta : void 0
6166
+ meta: isRecord6(response.meta) ? response.meta : void 0
5968
6167
  }),
5969
6168
  options
5970
6169
  );