deepline 0.1.175 → 0.1.177

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/cli/index.js CHANGED
@@ -622,17 +622,18 @@ var SDK_RELEASE = {
622
622
  // 0.1.111 ships dataset-native tool list getters and result row datasets.
623
623
  // 0.1.154 removes the short-lived generated enrich StepOptions recompute
624
624
  // fields shipped in 0.1.153.
625
- version: "0.1.175",
625
+ // 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
626
+ version: "0.1.177",
626
627
  apiContract: "2026-06-dataset-handle-results-hard-cutover",
627
628
  supportPolicy: {
628
- latest: "0.1.175",
629
+ latest: "0.1.177",
629
630
  minimumSupported: "0.1.53",
630
631
  deprecatedBelow: "0.1.53",
631
632
  commandMinimumSupported: [
632
633
  {
633
634
  command: "enrich",
634
- minimumSupported: "0.1.154",
635
- reason: "Older SDK CLI enrich generated stale play source; SDK CLI enrich 0.1.153 generated removed StepOptions fields in play source."
635
+ minimumSupported: "0.1.175",
636
+ reason: "Older SDK CLI enrich generated stale play source; SDK CLI enrich 0.1.153 generated removed StepOptions fields in play source; SDK CLI enrich before 0.1.175 could silently succeed on the empty-waterfall bug when a requested waterfall returned no values for selected rows."
636
637
  },
637
638
  {
638
639
  command: "plays",
@@ -886,9 +887,10 @@ var HttpClient = class {
886
887
  headers["Content-Type"] = "application/json";
887
888
  }
888
889
  let lastError = null;
889
- const candidateUrls = buildCandidateUrls(url);
890
+ const candidateUrls = options?.exactUrlOnly ? [url] : buildCandidateUrls(url);
890
891
  let retryAfterDelayMs = null;
891
- for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
892
+ const maxRetries = options?.maxRetries ?? this.config.maxRetries;
893
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
892
894
  if (attempt > 0) {
893
895
  const backoffMs = Math.min(1e3 * Math.pow(2, attempt - 1), 3e4);
894
896
  const delayMs = retryAfterDelayMs === null ? backoffMs : Math.max(backoffMs, retryAfterDelayMs);
@@ -915,7 +917,7 @@ var HttpClient = class {
915
917
  if (response.status === 429) {
916
918
  const retryAfter = parseRetryAfter(response);
917
919
  lastError = new RateLimitError(retryAfter);
918
- if (attempt < this.config.maxRetries) {
920
+ if (attempt < maxRetries) {
919
921
  retryAfterDelayMs = retryAfter;
920
922
  break;
921
923
  }
@@ -945,7 +947,7 @@ var HttpClient = class {
945
947
  ...htmlError.workerThrewException ? { workerThrewException: true } : {}
946
948
  }
947
949
  );
948
- if (retryableApiError && attempt < this.config.maxRetries) {
950
+ if (retryableApiError && attempt < maxRetries) {
949
951
  retryAfterDelayMs = parseOptionalRetryAfter(response);
950
952
  break;
951
953
  }
@@ -957,7 +959,7 @@ var HttpClient = class {
957
959
  lastError = new DeeplineError(msg, response.status, apiErrorCode, {
958
960
  response: parsed
959
961
  });
960
- if (retryableApiError && attempt < this.config.maxRetries) {
962
+ if (retryableApiError && attempt < maxRetries) {
961
963
  retryAfterDelayMs = parseOptionalRetryAfter(response);
962
964
  break;
963
965
  }
@@ -976,7 +978,7 @@ var HttpClient = class {
976
978
  lastError = error instanceof Error ? error : new Error(String(error));
977
979
  }
978
980
  }
979
- if (attempt < this.config.maxRetries) continue;
981
+ if (attempt < maxRetries) continue;
980
982
  }
981
983
  if (lastError instanceof DeeplineError) {
982
984
  throw lastError;
@@ -2111,6 +2113,7 @@ var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
2111
2113
  var REGISTER_PLAY_ARTIFACTS_COMPILE_CONCURRENCY = 3;
2112
2114
  var REGISTER_PLAY_ARTIFACTS_MAX_BATCH_COUNT = 3;
2113
2115
  var REGISTER_PLAY_ARTIFACTS_MAX_BATCH_BYTES = 25e5;
2116
+ var DEEPLINEAGENT_EXECUTE_TIMEOUT_MS = 15 * 60 * 1e3;
2114
2117
  function normalizePlayRunIntegrationMode(value) {
2115
2118
  if (value === "live" || value === "eval_stub" || value === "fixture") {
2116
2119
  return value;
@@ -2185,6 +2188,10 @@ function chunkRegisterPlayArtifacts(artifacts) {
2185
2188
  }
2186
2189
  return chunks;
2187
2190
  }
2191
+ function resolveToolExecuteTimeoutMs(toolId) {
2192
+ const normalized = toolId.trim().toLowerCase();
2193
+ return normalized === "deeplineagent" || normalized === "deeplineagent_deeplineagent" || normalized === "ai_inference" || normalized === "deeplineagent_ai_inference" || normalized === "aiinference" ? DEEPLINEAGENT_EXECUTE_TIMEOUT_MS : void 0;
2194
+ }
2188
2195
  var RUN_LOGS_PAGE_LIMIT = 1e3;
2189
2196
  function isRecord3(value) {
2190
2197
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
@@ -2624,7 +2631,12 @@ var DeeplineClient = class {
2624
2631
  `/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
2625
2632
  { payload: input2 },
2626
2633
  headers,
2627
- { forbiddenAsApiError: true }
2634
+ {
2635
+ forbiddenAsApiError: true,
2636
+ timeout: options?.timeout ?? resolveToolExecuteTimeoutMs(toolId),
2637
+ maxRetries: options?.maxRetries ?? 0,
2638
+ exactUrlOnly: true
2639
+ }
2628
2640
  );
2629
2641
  }
2630
2642
  /**
@@ -4572,10 +4584,21 @@ function failureMessageFromRecord(value) {
4572
4584
  }
4573
4585
  return directError || resultError || `Column status: ${status}`;
4574
4586
  }
4575
- function flattenObjectColumns(row) {
4587
+ function shouldPreserveJsonStringColumn(columns, key) {
4588
+ if (!columns) {
4589
+ return false;
4590
+ }
4591
+ if (columns.has(key)) {
4592
+ return true;
4593
+ }
4594
+ const normalizedKey = key.toLowerCase().replace(/[^a-z0-9]/g, "");
4595
+ return normalizedKey ? columns.has(normalizedKey) : false;
4596
+ }
4597
+ function flattenObjectColumns(row, options = {}) {
4576
4598
  const flattened = {};
4577
4599
  for (const [key, rawValue] of Object.entries(row)) {
4578
4600
  const value = parseMaybeJsonObject(rawValue);
4601
+ const parsedFromString = typeof rawValue === "string" && value !== rawValue;
4579
4602
  if (key === "_metadata") {
4580
4603
  flattened[key] = value && typeof value === "object" ? JSON.stringify(value) : value;
4581
4604
  continue;
@@ -4586,6 +4609,10 @@ function flattenObjectColumns(row) {
4586
4609
  if (hasMatchedEnvelope) {
4587
4610
  flattened[key] = JSON.stringify(record);
4588
4611
  continue;
4612
+ }
4613
+ if (parsedFromString && shouldPreserveJsonStringColumn(options.preserveJsonStringColumns, key)) {
4614
+ flattened[key] = rawValue;
4615
+ continue;
4589
4616
  } else {
4590
4617
  const failureMessage = failureMessageFromRecord(record);
4591
4618
  if (failureMessage) {
@@ -4610,8 +4637,8 @@ function recordRows(value) {
4610
4637
  (row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)
4611
4638
  );
4612
4639
  }
4613
- function dataExportRows(rows) {
4614
- return rows.map((row) => flattenObjectColumns(row));
4640
+ function dataExportRows(rows, options = {}) {
4641
+ return rows.map((row) => flattenObjectColumns(row, options));
4615
4642
  }
4616
4643
  function dataExportColumns(rows, preferredColumns = []) {
4617
4644
  const discoveredColumns = [
@@ -16883,7 +16910,8 @@ function helperSource() {
16883
16910
  // src/cli/commands/enrich.ts
16884
16911
  var ENRICH_EXPORT_PAGE_SIZE = 5e3;
16885
16912
  var ENRICH_AUTO_BATCH_ROWS = 250;
16886
- var ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS = 40;
16913
+ var ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS = 25;
16914
+ var ENRICH_NESTED_PROVIDER_AUTO_BATCH_ROWS = 50;
16887
16915
  var ENRICH_EXPORT_BACKING_ROWS_WAIT_MS = 6e4;
16888
16916
  var ENRICH_EXPORT_BACKING_ROWS_POLL_MS = 1e3;
16889
16917
  var ENRICH_SOURCE_ROW_INDEX_COLUMN = "__deeplineSourceRowIndex";
@@ -16898,6 +16926,12 @@ var HEAVY_ENRICH_AUTO_BATCH_PLAYS = /* @__PURE__ */ new Set([
16898
16926
  "company-to-contact-by-role-waterfall",
16899
16927
  "company_to_contact_by_role_waterfall"
16900
16928
  ]);
16929
+ var HEAVY_ENRICH_AUTO_BATCH_TOOLS = /* @__PURE__ */ new Set([
16930
+ "ai_inference",
16931
+ "aiinference",
16932
+ "deeplineagent"
16933
+ ]);
16934
+ var ENRICH_TEST_AI_INFERENCE_PAYLOAD_MARKER = "__deeplineTestAiInference";
16901
16935
  var PLAN_SHAPING_OPTION_NAMES = [
16902
16936
  "with",
16903
16937
  "withWaterfall",
@@ -16915,6 +16949,15 @@ function normalizeAlias2(value) {
16915
16949
  function hasPlanShapingArgs(args) {
16916
16950
  return optionWasProvided(args, "--with") || optionWasProvided(args, "--with-waterfall") || optionWasProvided(args, "--min-results") || optionWasProvided(args, "--end-waterfall");
16917
16951
  }
16952
+ function isMarkedTestAiInferenceCommand(command) {
16953
+ if ("with_waterfall" in command) {
16954
+ return false;
16955
+ }
16956
+ if (normalizeEnrichPlayRef(command.tool) !== "run_javascript") {
16957
+ return false;
16958
+ }
16959
+ return isRecord7(command.payload) && command.payload[ENRICH_TEST_AI_INFERENCE_PAYLOAD_MARKER] === true;
16960
+ }
16918
16961
  function enrichDebugEnabled(env = process.env) {
16919
16962
  const raw = String(env.DEEPLINE_DEBUG_ENRICH ?? "").trim().toLowerCase();
16920
16963
  if (["1", "true", "yes", "on"].includes(raw)) {
@@ -17682,8 +17725,6 @@ function normalizeEnrichPlayRef(value) {
17682
17725
  return normalized || null;
17683
17726
  }
17684
17727
  function configContainsHeavyEnrichPlay(config) {
17685
- let hasNestedPlayStep = false;
17686
- let hasSubrequestProviderStep = false;
17687
17728
  const visit = (commands) => {
17688
17729
  for (const command of commands) {
17689
17730
  if ("with_waterfall" in command) {
@@ -17707,18 +17748,67 @@ function configContainsHeavyEnrichPlay(config) {
17707
17748
  return true;
17708
17749
  }
17709
17750
  const normalizedTool = normalizeEnrichPlayRef(command.tool);
17751
+ const normalizedOperation = normalizeEnrichPlayRef(command.operation);
17752
+ if (isMarkedTestAiInferenceCommand(command) || normalizedTool && HEAVY_ENRICH_AUTO_BATCH_TOOLS.has(normalizedTool) || normalizedOperation && HEAVY_ENRICH_AUTO_BATCH_TOOLS.has(normalizedOperation)) {
17753
+ return true;
17754
+ }
17755
+ }
17756
+ return false;
17757
+ };
17758
+ return visit(config.commands);
17759
+ }
17760
+ function configContainsNestedProviderEnrichWorkload(config) {
17761
+ let hasNestedPlayStep = false;
17762
+ let hasSubrequestProviderStep = false;
17763
+ const visit = (commands) => {
17764
+ for (const command of commands) {
17765
+ if ("with_waterfall" in command) {
17766
+ visit(command.commands);
17767
+ continue;
17768
+ }
17769
+ if (command.disabled) {
17770
+ continue;
17771
+ }
17772
+ const normalizedTool = normalizeEnrichPlayRef(command.tool);
17710
17773
  if (command.play || normalizedTool === "test-play") {
17711
17774
  hasNestedPlayStep = true;
17712
17775
  } else if (normalizedTool !== null && normalizedTool !== "run_javascript") {
17713
17776
  hasSubrequestProviderStep = true;
17714
17777
  }
17715
17778
  }
17716
- return false;
17717
17779
  };
17718
- return visit(config.commands) || hasNestedPlayStep && hasSubrequestProviderStep;
17780
+ visit(config.commands);
17781
+ return hasNestedPlayStep && hasSubrequestProviderStep;
17719
17782
  }
17720
17783
  function enrichAutoBatchRowsForConfig(config) {
17721
- return configContainsHeavyEnrichPlay(config) ? ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS : ENRICH_AUTO_BATCH_ROWS;
17784
+ if (configContainsHeavyEnrichPlay(config)) {
17785
+ return ENRICH_HEAVY_PLAY_AUTO_BATCH_ROWS;
17786
+ }
17787
+ if (configContainsNestedProviderEnrichWorkload(config)) {
17788
+ return ENRICH_NESTED_PROVIDER_AUTO_BATCH_ROWS;
17789
+ }
17790
+ return ENRICH_AUTO_BATCH_ROWS;
17791
+ }
17792
+ function enrichAiRuntimeCompactAliases(config) {
17793
+ const aliases = /* @__PURE__ */ new Set();
17794
+ const visit = (commands) => {
17795
+ for (const command of commands) {
17796
+ if ("with_waterfall" in command) {
17797
+ visit(command.commands);
17798
+ continue;
17799
+ }
17800
+ if (command.disabled) {
17801
+ continue;
17802
+ }
17803
+ const normalizedTool = normalizeEnrichPlayRef(command.tool);
17804
+ const normalizedOperation = normalizeEnrichPlayRef(command.operation);
17805
+ if (isMarkedTestAiInferenceCommand(command) || normalizedTool && HEAVY_ENRICH_AUTO_BATCH_TOOLS.has(normalizedTool) || normalizedOperation && HEAVY_ENRICH_AUTO_BATCH_TOOLS.has(normalizedOperation)) {
17806
+ aliases.add(normalizeAlias2(command.alias));
17807
+ }
17808
+ }
17809
+ };
17810
+ visit(config.commands);
17811
+ return aliases;
17722
17812
  }
17723
17813
  async function maybeWriteOutputCsv(input2) {
17724
17814
  if (!input2.outputPath) return null;
@@ -17750,14 +17840,39 @@ function enrichOutputJson(exportResult) {
17750
17840
  ...exportResult.partial ? { rows: exportResult.rows, partial: true } : {}
17751
17841
  };
17752
17842
  }
17843
+ function enrichReportJson(report) {
17844
+ if (!report) {
17845
+ return {};
17846
+ }
17847
+ return {
17848
+ ...report.jobs.length > 0 ? {
17849
+ failure_report: {
17850
+ path: report.path,
17851
+ jobs: report.jobs.length
17852
+ }
17853
+ } : {},
17854
+ ...report.issues.length > 0 ? {
17855
+ enrich_issues: {
17856
+ path: report.path,
17857
+ issues: report.issues.length,
17858
+ items: report.issues
17859
+ }
17860
+ } : {}
17861
+ };
17862
+ }
17753
17863
  async function buildEnrichFailureReport(input2) {
17864
+ const fallbackRowsInfo = input2.exportResult ? null : extractCanonicalRowsInfo(input2.status);
17754
17865
  return maybeEmitEnrichFailureReport({
17755
17866
  config: input2.config,
17756
17867
  rows: input2.rows,
17757
17868
  rowRange: input2.rowRange,
17758
17869
  client: input2.client,
17759
17870
  outputPath: input2.reportOutputPath ?? input2.exportResult?.path ?? input2.outputPath ?? null,
17760
- status: input2.status
17871
+ followUpOutputPath: input2.followUpOutputPath,
17872
+ status: input2.status,
17873
+ rowSetComplete: input2.exportResult ? !input2.exportResult.partial : Boolean(
17874
+ fallbackRowsInfo?.complete && input2.rows.length >= fallbackRowsInfo.totalRows
17875
+ )
17761
17876
  });
17762
17877
  }
17763
17878
  function recordField(value, key) {
@@ -17814,6 +17929,52 @@ function selectedSourceCsvRange(sourceCsvPath, rows) {
17814
17929
  sourceRows
17815
17930
  };
17816
17931
  }
17932
+ function compactRuntimeCsvCell(value) {
17933
+ const parsed = parseMaybeJsonObject(value);
17934
+ const compacted = compactAiInferenceCellForCsv(parsed);
17935
+ return materializeCsvCellValue(compacted);
17936
+ }
17937
+ async function writeSlimBatchedRuntimeCsv(input2) {
17938
+ const cleanRows = readCsvRows(input2.cleanSourceCsvPath).map(
17939
+ (row) => ({ ...row })
17940
+ );
17941
+ const mergeRows = readCsvRows(input2.mergeSourceCsvPath);
17942
+ const preserveJsonStringColumns = /* @__PURE__ */ new Set([
17943
+ ...cleanRows.flatMap((row) => Object.keys(row)),
17944
+ ...mergeRows.flatMap((row) => Object.keys(row))
17945
+ ]);
17946
+ const selectedRange = selectedSourceCsvRange(
17947
+ input2.mergeSourceCsvPath,
17948
+ input2.rows
17949
+ );
17950
+ for (let rowIndex = selectedRange.start; rowIndex <= selectedRange.end; rowIndex += 1) {
17951
+ const mergeRow = mergeRows[rowIndex];
17952
+ if (!mergeRow) {
17953
+ continue;
17954
+ }
17955
+ const baseRow = cleanRows[rowIndex] ?? {};
17956
+ const compactOverlayCell = ([key, value]) => {
17957
+ return [
17958
+ key,
17959
+ input2.compactAliases.has(normalizeAlias2(key)) ? compactRuntimeCsvCell(value) : value
17960
+ ];
17961
+ };
17962
+ cleanRows[rowIndex] = {
17963
+ ...baseRow,
17964
+ ...Object.fromEntries(
17965
+ Object.entries(mergeRow).map(compactOverlayCell)
17966
+ )
17967
+ };
17968
+ }
17969
+ const columns = dataExportColumns(
17970
+ dataExportRows(cleanRows, { preserveJsonStringColumns })
17971
+ );
17972
+ await (0, import_promises3.writeFile)(
17973
+ input2.outputPath,
17974
+ csvStringFromRows(cleanRows, columns),
17975
+ "utf8"
17976
+ );
17977
+ }
17817
17978
  function selectedSourceCsvRowCount(options) {
17818
17979
  if (!options?.sourceCsvPath) {
17819
17980
  return null;
@@ -17988,7 +18149,7 @@ function emitPlainBatchRunFailure(input2) {
17988
18149
  `Batch ${input2.chunkIndex + 1}/${input2.chunkCount} failed for rows ${input2.rows.rowStart}:${input2.rows.rowEnd}.
17989
18150
  `
17990
18151
  );
17991
- const runId = extractRunId(input2.status);
18152
+ const runId = extractRunId(input2.status) ?? firstCollectedStringField(input2.status, "runId");
17992
18153
  const error = firstCollectedStringField(input2.status, "error") ?? firstCollectedStringField(input2.status, "message");
17993
18154
  if (runId) {
17994
18155
  process.stderr.write(`Run id: ${runId}
@@ -18120,6 +18281,22 @@ function mergeExportedSheetRow(target, next) {
18120
18281
  target._metadata = metadata;
18121
18282
  }
18122
18283
  }
18284
+ function countEnrichedRowsInSourceRange(exportResult, rows) {
18285
+ const start = Math.max(0, rows.rowStart ?? 0);
18286
+ const end = rows.rowEnd === null || rows.rowEnd === void 0 ? Number.MAX_SAFE_INTEGER : Math.max(start, rows.rowEnd);
18287
+ const rowIndexes = /* @__PURE__ */ new Set();
18288
+ for (const row of exportResult.enrichedDataRows) {
18289
+ const rowIndex = sourceRowIndexFromEnrichRow(row, start, end);
18290
+ if (rowIndex !== null) {
18291
+ rowIndexes.add(rowIndex);
18292
+ }
18293
+ }
18294
+ if (rowIndexes.size > 0) {
18295
+ return rowIndexes.size;
18296
+ }
18297
+ const selectedRows = end === Number.MAX_SAFE_INTEGER ? exportResult.enrichedRows : end - start + 1;
18298
+ return Math.min(exportResult.enrichedRows, Math.max(0, selectedRows));
18299
+ }
18123
18300
  function coalesceExportableSheetRows(rows, sourceRowStart = 0) {
18124
18301
  const mergedRows = [];
18125
18302
  const bySourceRowIndex = /* @__PURE__ */ new Map();
@@ -18188,6 +18365,38 @@ function collectHardFailureAliasSpecs(config) {
18188
18365
  }
18189
18366
  return aliases;
18190
18367
  }
18368
+ function collectWaterfallAliasSpecs(config) {
18369
+ const aliases = [];
18370
+ const seen = /* @__PURE__ */ new Set();
18371
+ for (const command of config.commands) {
18372
+ if (!("with_waterfall" in command)) {
18373
+ continue;
18374
+ }
18375
+ const alias = command.with_waterfall.trim();
18376
+ if (!alias || seen.has(alias)) {
18377
+ continue;
18378
+ }
18379
+ const activeChildren = command.commands.filter(
18380
+ (child) => !("with_waterfall" in child) && !child.disabled
18381
+ );
18382
+ if (activeChildren.length === 0) {
18383
+ continue;
18384
+ }
18385
+ seen.add(alias);
18386
+ const childOperations = activeChildren.map((child) => child.operation?.trim() || child.tool.trim()).filter(Boolean);
18387
+ aliases.push({
18388
+ alias,
18389
+ childAliases: activeChildren.map((child) => child.alias).filter(Boolean),
18390
+ childToolsByAlias: new Map(
18391
+ activeChildren.map(
18392
+ (child) => [child.alias, child.tool.trim()]
18393
+ )
18394
+ ),
18395
+ operation: childOperations.length > 0 ? childOperations.join(", ") : void 0
18396
+ });
18397
+ }
18398
+ return aliases;
18399
+ }
18191
18400
  function hardFailureOperationByAlias(config) {
18192
18401
  const operations = /* @__PURE__ */ new Map();
18193
18402
  if (!config) {
@@ -18200,6 +18409,60 @@ function hardFailureOperationByAlias(config) {
18200
18409
  }
18201
18410
  return operations;
18202
18411
  }
18412
+ function isWaterfallResultMeaningful(value) {
18413
+ if (Array.isArray(value)) {
18414
+ return value.some(isWaterfallResultMeaningful);
18415
+ }
18416
+ if (value && typeof value === "object") {
18417
+ const record = value;
18418
+ const status = typeof record.status === "string" ? record.status.trim().toLowerCase() : "";
18419
+ if (status === "error" || status === "failed") {
18420
+ return false;
18421
+ }
18422
+ if (typeof record.error === "string" && record.error.trim()) {
18423
+ return false;
18424
+ }
18425
+ if (Object.prototype.hasOwnProperty.call(record, "matched_result")) {
18426
+ return isWaterfallResultMeaningful(record.matched_result);
18427
+ }
18428
+ for (const key of [
18429
+ "value",
18430
+ "email",
18431
+ "phone",
18432
+ "phone_number",
18433
+ "mobile_phone",
18434
+ "mobile_phone_number",
18435
+ "url",
18436
+ "domain",
18437
+ "name",
18438
+ "result",
18439
+ "data"
18440
+ ]) {
18441
+ if (isWaterfallResultMeaningful(record[key])) {
18442
+ return true;
18443
+ }
18444
+ }
18445
+ return Object.entries(record).some(
18446
+ ([key, entry]) => !ENRICH_FLATTENED_CONTROL_FIELDS.has(key) && isWaterfallResultMeaningful(entry)
18447
+ );
18448
+ }
18449
+ return isNonEmptyCsvCell(value);
18450
+ }
18451
+ function aliasHasMeaningfulResult(row, alias) {
18452
+ return aliasFailureCellCandidates(row, alias).some(
18453
+ isWaterfallResultMeaningful
18454
+ );
18455
+ }
18456
+ function stableRowSnapshot(value) {
18457
+ if (Array.isArray(value)) {
18458
+ return `[${value.map(stableRowSnapshot).join(",")}]`;
18459
+ }
18460
+ if (value && typeof value === "object") {
18461
+ const record = value;
18462
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableRowSnapshot(record[key])}`).join(",")}}`;
18463
+ }
18464
+ return JSON.stringify(value);
18465
+ }
18203
18466
  function cellFailureError(value) {
18204
18467
  const parsed = parseMaybeJsonObject(value);
18205
18468
  if (!isRecord7(parsed)) {
@@ -18345,6 +18608,112 @@ function collectEnrichFailureJobs(input2) {
18345
18608
  });
18346
18609
  return jobs;
18347
18610
  }
18611
+ function collectEmptyWaterfallIssues(input2) {
18612
+ const aliases = collectWaterfallAliasSpecs(input2.config);
18613
+ if (aliases.length === 0 || input2.rows.length === 0 || !input2.rowSetComplete) {
18614
+ return [];
18615
+ }
18616
+ const runId = extractRunId(input2.status) ?? firstCollectedStringField(input2.status, "runId");
18617
+ const followUpCommands = collectEnrichFollowUpCommands({
18618
+ status: input2.status,
18619
+ runId,
18620
+ outputPath: input2.followUpOutputPath ?? input2.outputPath
18621
+ });
18622
+ const issues = [];
18623
+ aliases.forEach((spec) => {
18624
+ if (waterfallExecutionSignal(input2.status, spec) === "all_condition_skipped") {
18625
+ return;
18626
+ }
18627
+ const logicalRows = /* @__PURE__ */ new Map();
18628
+ input2.rows.forEach((row, rowIndex) => {
18629
+ const sourceRowId = sourceRowIndexFromEnrichRow(
18630
+ row,
18631
+ 0,
18632
+ Number.MAX_SAFE_INTEGER
18633
+ );
18634
+ const rowKey = sourceRowId !== null ? `source:${sourceRowId}` : `snapshot:${stableRowSnapshot(row)}`;
18635
+ const existing = logicalRows.get(rowKey);
18636
+ const hasMeaningfulResult = aliasHasMeaningfulResult(row, spec.alias);
18637
+ logicalRows.set(rowKey, {
18638
+ hasMeaningfulResult: (existing?.hasMeaningfulResult ?? false) || hasMeaningfulResult
18639
+ });
18640
+ });
18641
+ const emptyRows = Array.from(logicalRows.values()).filter(
18642
+ (row) => !row.hasMeaningfulResult
18643
+ );
18644
+ if (emptyRows.length !== logicalRows.size) {
18645
+ return;
18646
+ }
18647
+ const selectedRows = logicalRows.size;
18648
+ const message = `Waterfall ${spec.alias} produced 0 values for ${selectedRows} selected row(s).`;
18649
+ issues.push({
18650
+ issue_id: `${spec.alias}-empty-waterfall`,
18651
+ kind: "empty_waterfall",
18652
+ severity: "needs_attention",
18653
+ column: spec.alias,
18654
+ selected_rows: selectedRows,
18655
+ rows_with_value: 0,
18656
+ rows_without_value: selectedRows,
18657
+ message,
18658
+ next_steps: enrichIssueNextSteps({ runId }),
18659
+ follow_up_commands: followUpCommands,
18660
+ ...spec.operation ? { operation: spec.operation } : {},
18661
+ ...runId ? { run_id: runId } : {}
18662
+ });
18663
+ });
18664
+ return issues;
18665
+ }
18666
+ function waterfallExecutionSignal(status, spec) {
18667
+ const childAliases = spec.childAliases ?? [];
18668
+ if (childAliases.length === 0) {
18669
+ return "unknown";
18670
+ }
18671
+ const summaries = collectColumnStats(status);
18672
+ let sawChildStats = false;
18673
+ let everyChildStatOnlyConditionSkipped = true;
18674
+ const childAliasesWithStats = /* @__PURE__ */ new Set();
18675
+ for (const childAlias of childAliases) {
18676
+ for (const stat2 of summaries.map((summary) => summary[childAlias]).filter(isRecord7)) {
18677
+ sawChildStats = true;
18678
+ childAliasesWithStats.add(childAlias);
18679
+ const execution = isRecord7(stat2.execution) ? stat2.execution : null;
18680
+ const executedSummary = parseExecutionSummary(
18681
+ execution?.["completed:executed"]
18682
+ );
18683
+ const skippedConditionSummary = parseExecutionSummary(
18684
+ execution?.["skipped:condition"]
18685
+ );
18686
+ const executedCount = executedSummary?.count ?? 0;
18687
+ const skippedConditionCount = skippedConditionSummary?.count ?? 0;
18688
+ const totalCount = executedSummary?.total ?? skippedConditionSummary?.total;
18689
+ const onlyConditionSkips = totalCount !== void 0 && skippedConditionCount >= totalCount && executedCount <= skippedConditionCount;
18690
+ if (executedCount > 0 && !onlyConditionSkips || numericFailedRowSignal(execution?.failed) > 0 || numericFailedRowSignal(stat2.failed) > 0 || numericFailedRowSignal(stat2.failedRows) > 0) {
18691
+ return "executed";
18692
+ }
18693
+ if (!onlyConditionSkips) {
18694
+ everyChildStatOnlyConditionSkipped = false;
18695
+ }
18696
+ }
18697
+ }
18698
+ if (sawChildStats && childAliasesWithStats.size === childAliases.length && everyChildStatOnlyConditionSkipped) {
18699
+ return "all_condition_skipped";
18700
+ }
18701
+ return "unknown";
18702
+ }
18703
+ function mergeEnrichFailureJobs(...jobGroups) {
18704
+ const merged = [];
18705
+ const seen = /* @__PURE__ */ new Set();
18706
+ for (const jobs of jobGroups) {
18707
+ for (const job of jobs) {
18708
+ if (seen.has(job.job_id)) {
18709
+ continue;
18710
+ }
18711
+ seen.add(job.job_id);
18712
+ merged.push(job);
18713
+ }
18714
+ }
18715
+ return merged;
18716
+ }
18348
18717
  function collectStatusFailureJobs(input2) {
18349
18718
  const aliases = collectHardFailureAliasSpecs(input2.config);
18350
18719
  if (aliases.length === 0) {
@@ -18438,14 +18807,23 @@ function collectCompleteStatusFailureMessages(input2) {
18438
18807
  return complete;
18439
18808
  }
18440
18809
  function parseExecutionCount(value) {
18810
+ return parseExecutionSummary(value)?.count ?? null;
18811
+ }
18812
+ function parseExecutionSummary(value) {
18441
18813
  if (typeof value === "number" && Number.isFinite(value)) {
18442
- return Math.max(0, Math.trunc(value));
18814
+ return { count: Math.max(0, Math.trunc(value)) };
18443
18815
  }
18444
18816
  if (typeof value !== "string") {
18445
18817
  return null;
18446
18818
  }
18447
- const match = value.trim().match(/^(\d+)\s*\//);
18448
- return match?.[1] ? Number.parseInt(match[1], 10) : null;
18819
+ const match = value.trim().match(/^(\d+)(?:\s*\/\s*(\d+))?/);
18820
+ if (!match?.[1]) {
18821
+ return null;
18822
+ }
18823
+ return {
18824
+ count: Number.parseInt(match[1], 10),
18825
+ ...match[2] ? { total: Number.parseInt(match[2], 10) } : {}
18826
+ };
18449
18827
  }
18450
18828
  function executionSummaryText(count, total) {
18451
18829
  const percent = total > 0 ? Math.round(count / total * 100) : 0;
@@ -18571,19 +18949,145 @@ function summarizeFailedJobError(value) {
18571
18949
  const text = String(value ?? "").trim();
18572
18950
  return text.length > 500 ? `${text.slice(0, 497)}...` : text;
18573
18951
  }
18952
+ function shellSingleQuote2(value) {
18953
+ return `'${value.replace(/'/g, `'\\''`)}'`;
18954
+ }
18955
+ function addEnrichFollowUpCommand(commands, seen, command) {
18956
+ const normalized = command.command.trim();
18957
+ if (!normalized || seen.has(normalized)) {
18958
+ return;
18959
+ }
18960
+ seen.add(normalized);
18961
+ commands.push({ ...command, command: normalized });
18962
+ }
18963
+ function datasetSelectorForEnrichCommand(record, fallbackPath) {
18964
+ const candidates = [record.path, record.tableNamespace, fallbackPath];
18965
+ for (const candidate of candidates) {
18966
+ if (typeof candidate === "string" && candidate.trim()) {
18967
+ return candidate.trim();
18968
+ }
18969
+ }
18970
+ return null;
18971
+ }
18972
+ function collectEnrichFollowUpCommands(input2) {
18973
+ const commands = [];
18974
+ const seen = /* @__PURE__ */ new Set();
18975
+ if (input2.runId) {
18976
+ addEnrichFollowUpCommand(commands, seen, {
18977
+ label: "inspect run",
18978
+ command: `deepline runs get ${input2.runId} --full --json`
18979
+ });
18980
+ }
18981
+ collectDatasetFollowUpCommands(input2.status, {
18982
+ runId: input2.runId,
18983
+ outputPath: input2.outputPath,
18984
+ commands,
18985
+ seen,
18986
+ path: "result",
18987
+ depth: 0
18988
+ });
18989
+ if (input2.runId && input2.outputPath && !commands.some((command) => command.label === "export enrich rows")) {
18990
+ addEnrichFollowUpCommand(commands, seen, {
18991
+ label: "export enrich rows",
18992
+ path: GENERATED_ENRICH_ROWS_TABLE_NAMESPACE,
18993
+ command: `deepline runs export ${input2.runId} --dataset ${GENERATED_ENRICH_ROWS_TABLE_NAMESPACE} --out ${shellSingleQuote2(
18994
+ (0, import_node_path12.resolve)(input2.outputPath)
18995
+ )}`
18996
+ });
18997
+ }
18998
+ return commands.slice(0, 8);
18999
+ }
19000
+ function sidecarEnrichRowsExportPath(outputPath) {
19001
+ const resolved = (0, import_node_path12.resolve)(outputPath);
19002
+ const ext = (0, import_node_path12.extname)(resolved) || ".csv";
19003
+ const stem = (0, import_node_path12.basename)(resolved, ext);
19004
+ return (0, import_node_path12.join)((0, import_node_path12.dirname)(resolved), `${stem}.deepline-enrich-rows${ext}`);
19005
+ }
19006
+ function collectDatasetFollowUpCommands(value, state) {
19007
+ if (state.depth > 12 || !value || typeof value !== "object" || state.commands.length >= 8) {
19008
+ return;
19009
+ }
19010
+ if (Array.isArray(value)) {
19011
+ value.slice(0, 50).forEach(
19012
+ (entry, index) => collectDatasetFollowUpCommands(entry, {
19013
+ ...state,
19014
+ path: `${state.path}.${index}`,
19015
+ depth: state.depth + 1
19016
+ })
19017
+ );
19018
+ return;
19019
+ }
19020
+ const record = value;
19021
+ const isDataset = record.kind === "dataset";
19022
+ if (isDataset) {
19023
+ const selector = datasetSelectorForEnrichCommand(record, state.path);
19024
+ const labelPath = typeof record.path === "string" && record.path.trim() ? record.path.trim() : selector ?? state.path;
19025
+ if (typeof record.queryDatasetCommand === "string") {
19026
+ addEnrichFollowUpCommand(state.commands, state.seen, {
19027
+ label: `query ${labelPath}`,
19028
+ path: labelPath,
19029
+ command: record.queryDatasetCommand
19030
+ });
19031
+ }
19032
+ const exportCommand = typeof record.slowExportAsCsvCommand === "string" ? record.slowExportAsCsvCommand : typeof record.fullExportCommand === "string" ? record.fullExportCommand : null;
19033
+ if (exportCommand) {
19034
+ addEnrichFollowUpCommand(state.commands, state.seen, {
19035
+ label: `export ${labelPath}`,
19036
+ path: labelPath,
19037
+ command: exportCommand
19038
+ });
19039
+ } else if (state.runId && state.outputPath && selector) {
19040
+ addEnrichFollowUpCommand(state.commands, state.seen, {
19041
+ label: selector === GENERATED_ENRICH_ROWS_TABLE_NAMESPACE ? "export enrich rows" : `export ${labelPath}`,
19042
+ path: selector,
19043
+ command: `deepline runs export ${state.runId} --dataset ${shellSingleQuote2(
19044
+ selector
19045
+ )} --out ${shellSingleQuote2((0, import_node_path12.resolve)(state.outputPath))}`
19046
+ });
19047
+ }
19048
+ }
19049
+ for (const [key, child] of Object.entries(record)) {
19050
+ if (key === "preview" || key === "access") {
19051
+ continue;
19052
+ }
19053
+ collectDatasetFollowUpCommands(child, {
19054
+ ...state,
19055
+ path: `${state.path}.${key}`,
19056
+ depth: state.depth + 1
19057
+ });
19058
+ if (state.commands.length >= 8) {
19059
+ return;
19060
+ }
19061
+ }
19062
+ }
19063
+ function enrichIssueNextSteps(input2) {
19064
+ const steps = [
19065
+ "Inspect the run output and returned dataset handles.",
19066
+ "If runs get returns queryDatasetCommand or slowExportAsCsvCommand, run that command to fetch durable rows from the customer DB.",
19067
+ "For provider-backed waterfalls, execute the child provider tool on a sample row to confirm the provider returns the expected field."
19068
+ ];
19069
+ if (!input2.runId) {
19070
+ return steps;
19071
+ }
19072
+ return [
19073
+ `Inspect run output: deepline runs get ${input2.runId} --full --json`,
19074
+ ...steps.slice(1)
19075
+ ];
19076
+ }
18574
19077
  function formatFailureReportCommand(reportPath) {
18575
19078
  const quoted = reportPath.replace(/'/g, `'\\''`);
18576
19079
  return `Inspect failed jobs: jq -r '.jobs[] | [.job_id,.row_id,.col_index,.column,.status,.last_error] | @tsv' '${quoted}'`;
18577
19080
  }
18578
19081
  async function persistEnrichFailureReport(input2) {
18579
- if (input2.jobs.length === 0) {
19082
+ if (input2.jobs.length === 0 && input2.issues.length === 0) {
18580
19083
  return null;
18581
19084
  }
18582
19085
  const stateDir = (0, import_node_path12.join)((0, import_node_os8.homedir)(), ".local", "deepline", "runtime", "state");
19086
+ const reportPrefix = input2.jobs.length > 0 ? "run-block-failures" : "enrich-issues";
18583
19087
  await (0, import_promises3.mkdir)(stateDir, { recursive: true });
18584
19088
  const reportPath = (0, import_node_path12.join)(
18585
19089
  stateDir,
18586
- `run-block-failures-${Math.floor(Date.now() / 1e3)}-${process.pid}.json`
19090
+ `${reportPrefix}-${Math.floor(Date.now() / 1e3)}-${process.pid}.json`
18587
19091
  );
18588
19092
  const report = {
18589
19093
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -18598,6 +19102,7 @@ async function persistEnrichFailureReport(input2) {
18598
19102
  },
18599
19103
  jobs: input2.jobs,
18600
19104
  failed_jobs: input2.jobs,
19105
+ enrich_issues: input2.issues,
18601
19106
  canceled_jobs: [],
18602
19107
  pending_jobs: [],
18603
19108
  missing_job_ids: []
@@ -18610,48 +19115,100 @@ async function persistEnrichFailureReport(input2) {
18610
19115
  return reportPath;
18611
19116
  }
18612
19117
  async function maybeEmitEnrichFailureReport(input2) {
19118
+ const fallbackRowsInfo = extractCanonicalRowsInfo(input2.status);
19119
+ const rowSetComplete = input2.rowSetComplete ?? Boolean(
19120
+ fallbackRowsInfo?.complete && input2.rows.length >= fallbackRowsInfo.totalRows
19121
+ );
18613
19122
  const rowJobs = collectEnrichFailureJobs({
18614
19123
  config: input2.config,
18615
19124
  rows: input2.rows,
18616
19125
  rowStart: input2.rowRange.rowStart
18617
19126
  });
18618
- const jobs = rowJobs.length > 0 || input2.status === void 0 ? rowJobs : collectStatusFailureJobs({
19127
+ const enrichIssues = collectEmptyWaterfallIssues({
19128
+ config: input2.config,
19129
+ rows: input2.rows,
19130
+ status: input2.waterfallStatus ?? input2.status,
19131
+ outputPath: input2.outputPath,
19132
+ followUpOutputPath: input2.followUpOutputPath,
19133
+ rowSetComplete
19134
+ });
19135
+ const statusJobs = input2.status === void 0 || rowJobs.length > 0 ? [] : collectStatusFailureJobs({
18619
19136
  config: input2.config,
18620
19137
  status: input2.status,
18621
19138
  rowRange: input2.statusRowRange ?? input2.rowRange
18622
19139
  });
18623
- if (jobs.length === 0) {
19140
+ const jobs = rowJobs.length > 0 || statusJobs.length > 0 || input2.status === void 0 ? mergeEnrichFailureJobs(rowJobs, statusJobs) : [];
19141
+ if (jobs.length === 0 && enrichIssues.length === 0) {
18624
19142
  return null;
18625
19143
  }
18626
19144
  const reportPath = await persistEnrichFailureReport({
18627
19145
  jobs,
19146
+ issues: enrichIssues,
18628
19147
  apiUrl: input2.client.baseUrl,
18629
19148
  outputPath: input2.outputPath,
18630
19149
  rows: input2.rowRange
18631
19150
  });
18632
- process.stderr.write("Execution failed.\n");
18633
- process.stderr.write("Failure preview (up to 5 failed jobs):\n");
18634
- process.stderr.write("job_id row_id col_index column status error\n");
18635
- for (const job of jobs.slice(0, 5)) {
18636
- process.stderr.write(
18637
- `${job.job_id} ${job.row_id} ${job.col_index} ${job.column} ${job.status} ${summarizeFailedJobError(job.last_error)}
19151
+ if (jobs.length > 0) {
19152
+ process.stderr.write("Execution failed.\n");
19153
+ process.stderr.write("Failure preview (up to 5 failed jobs):\n");
19154
+ process.stderr.write("job_id row_id col_index column status error\n");
19155
+ for (const job of jobs.slice(0, 5)) {
19156
+ process.stderr.write(
19157
+ `${job.job_id} ${job.row_id} ${job.col_index} ${job.column} ${job.status} ${summarizeFailedJobError(job.last_error)}
18638
19158
  `
18639
- );
19159
+ );
19160
+ }
19161
+ if (jobs.length > 5) {
19162
+ process.stderr.write(`Showing 5 of ${jobs.length} failed jobs.
19163
+ `);
19164
+ }
18640
19165
  }
18641
- if (jobs.length > 5) {
18642
- process.stderr.write(`Showing 5 of ${jobs.length} failed jobs.
19166
+ if (enrichIssues.length > 0) {
19167
+ process.stderr.write("Enrichment needs attention.\n");
19168
+ process.stderr.write("Issue preview (up to 5 enrichment issues):\n");
19169
+ process.stderr.write(
19170
+ "issue_id column severity selected_rows rows_with_value message\n"
19171
+ );
19172
+ for (const issue of enrichIssues.slice(0, 5)) {
19173
+ process.stderr.write(
19174
+ `${issue.issue_id} ${issue.column} ${issue.severity} ${issue.selected_rows} ${issue.rows_with_value} ${issue.message}
19175
+ `
19176
+ );
19177
+ for (const step of issue.next_steps.slice(0, 2)) {
19178
+ process.stderr.write(`Next: ${step}
19179
+ `);
19180
+ }
19181
+ for (const command of issue.follow_up_commands.slice(0, 4)) {
19182
+ process.stderr.write(`Command: ${command.label}: ${command.command}
18643
19183
  `);
19184
+ }
19185
+ }
19186
+ if (enrichIssues.length > 5) {
19187
+ process.stderr.write(
19188
+ `Showing 5 of ${enrichIssues.length} enrichment issues.
19189
+ `
19190
+ );
19191
+ }
18644
19192
  }
18645
19193
  if (reportPath) {
18646
- process.stderr.write(`Full failure report: ${reportPath}
19194
+ if (jobs.length > 0) {
19195
+ process.stderr.write(`Full failure report: ${reportPath}
18647
19196
  `);
18648
- process.stderr.write(`${formatFailureReportCommand(reportPath)}
19197
+ process.stderr.write(`${formatFailureReportCommand(reportPath)}
18649
19198
  `);
18650
- process.stderr.write("Enrichment failed. See failure report above.\n");
18651
- return { path: reportPath, jobs };
19199
+ } else {
19200
+ process.stderr.write(`Full enrich report: ${reportPath}
19201
+ `);
19202
+ }
19203
+ process.stderr.write(
19204
+ jobs.length > 0 ? "Enrichment failed. See report above.\n" : "Enrichment produced no values for at least one requested waterfall. See issue preview above.\n"
19205
+ );
19206
+ return { path: reportPath, jobs, issues: enrichIssues };
18652
19207
  }
18653
- process.stderr.write("Enrichment failed.\n");
18654
- return { path: "", jobs };
19208
+ process.stderr.write(
19209
+ jobs.length > 0 ? "Enrichment failed.\n" : "Enrichment needs attention.\n"
19210
+ );
19211
+ return { path: "", jobs, issues: enrichIssues };
18655
19212
  }
18656
19213
  function mergePreferredColumns(preferredColumns, rows) {
18657
19214
  const columns = [];
@@ -18751,10 +19308,12 @@ async function fetchBackingRowsForCsvExport(input2) {
18751
19308
  };
18752
19309
  }
18753
19310
  function mergeRowsForCsvExport(enrichedRows, options) {
19311
+ const compactAliases = options?.config ? enrichAiRuntimeCompactAliases(options.config) : /* @__PURE__ */ new Set();
18754
19312
  const rows = dataExportRows(
18755
19313
  normalizeEnrichRowsForCsvExport(enrichedRows, options?.config, {
18756
19314
  statusFailureMessages: options?.statusFailureMessages
18757
- })
19315
+ }),
19316
+ { preserveJsonStringColumns: compactAliases }
18758
19317
  );
18759
19318
  const range = options?.rows;
18760
19319
  if (!options?.sourceCsvPath) {
@@ -18774,16 +19333,16 @@ function mergeRowsForCsvExport(enrichedRows, options) {
18774
19333
  const maxEnd = Math.max(start, baseRows.length - 1);
18775
19334
  const inclusiveEnd = range?.rowEnd === null || range?.rowEnd === void 0 ? maxEnd : Math.min(maxEnd, range.rowEnd);
18776
19335
  const expectedSelectedRows = baseRows.length === 0 ? 0 : Math.max(0, inclusiveEnd - start + 1);
18777
- const canMergeSparseBySourceIndex = rows.length > 0 && rows.every(
19336
+ const hasRowsInSelectedRange = rows.some(
18778
19337
  (row) => sourceRowIndexFromEnrichRow(row, start, inclusiveEnd) !== null
18779
19338
  );
18780
- if (options.inPlace && rows.length < expectedSelectedRows && !options.allowPartial && !canMergeSparseBySourceIndex) {
19339
+ if (options.inPlace && rows.length < expectedSelectedRows && !options.allowPartial && !hasRowsInSelectedRange) {
18781
19340
  throw new Error(
18782
19341
  `Refusing to write a partial in-place CSV export: the run returned ${rows.length} row(s) for ${expectedSelectedRows} selected source row(s).`
18783
19342
  );
18784
19343
  }
18785
19344
  const merged = [...baseRows];
18786
- if (canMergeSparseBySourceIndex) {
19345
+ if (hasRowsInSelectedRange) {
18787
19346
  for (const rawEnriched of rows) {
18788
19347
  const rowIndex = sourceRowIndexFromEnrichRow(
18789
19348
  rawEnriched,
@@ -18918,9 +19477,45 @@ function materializeCsvCellValue(value) {
18918
19477
  }
18919
19478
  return value;
18920
19479
  }
18921
- function materializeAliasSuccessCell(row, alias) {
19480
+ function disambiguateCompactAiInferencePayload(value) {
19481
+ const parsed = parseMaybeJsonObject(value);
19482
+ if (!isRecord7(parsed) || !cellFailureError(parsed)) {
19483
+ return value;
19484
+ }
19485
+ return {
19486
+ status: "completed",
19487
+ extracted_json: parsed
19488
+ };
19489
+ }
19490
+ function compactAiInferenceCellForCsv(value) {
19491
+ if (!isRecord7(value)) {
19492
+ return value;
19493
+ }
19494
+ const extractedJson = value.extracted_json;
19495
+ if (extractedJson !== null && extractedJson !== void 0) {
19496
+ return disambiguateCompactAiInferencePayload(extractedJson);
19497
+ }
19498
+ const result = isRecord7(value.result) ? value.result : null;
19499
+ const object = result?.object;
19500
+ if (object !== null && object !== void 0) {
19501
+ return disambiguateCompactAiInferencePayload(object);
19502
+ }
19503
+ const text = result?.text;
19504
+ if (typeof text === "string" && text.trim()) {
19505
+ return disambiguateCompactAiInferencePayload(text);
19506
+ }
19507
+ const output2 = value.output;
19508
+ if (typeof output2 === "string" && output2.trim()) {
19509
+ return disambiguateCompactAiInferencePayload(output2);
19510
+ }
19511
+ return value;
19512
+ }
19513
+ function materializeEnrichAliasCellForCsv(row, alias, options) {
18922
19514
  const direct = row[alias];
18923
19515
  if (isRecord7(direct)) {
19516
+ if (options?.compactAiCell && direct.status === "completed" && (isRecord7(direct.result) || Object.prototype.hasOwnProperty.call(direct, "extracted_json") || typeof direct.output === "string")) {
19517
+ return materializeCsvCellValue(compactAiInferenceCellForCsv(direct));
19518
+ }
18924
19519
  if (Object.prototype.hasOwnProperty.call(direct, "matched_result") || Object.prototype.hasOwnProperty.call(direct, "matchedResult") || Object.prototype.hasOwnProperty.call(direct, "result")) {
18925
19520
  return materializeCsvCellValue(direct);
18926
19521
  }
@@ -18979,6 +19574,7 @@ function materializeAliasSuccessCell(row, alias) {
18979
19574
  }
18980
19575
  function normalizeEnrichRowsForCsvExport(rows, config, options) {
18981
19576
  const aliases = config ? collectConfigScalarAliasOrder(config) : [];
19577
+ const aiCompactAliases = config ? enrichAiRuntimeCompactAliases(config) : null;
18982
19578
  const failureOperationByAlias = hardFailureOperationByAlias(config);
18983
19579
  return rows.map((row) => {
18984
19580
  const metadata = legacyMetadataFromRow(row);
@@ -19021,7 +19617,9 @@ function normalizeEnrichRowsForCsvExport(rows, config, options) {
19021
19617
  }
19022
19618
  }
19023
19619
  for (const alias of aliases) {
19024
- const value = materializeAliasSuccessCell(normalized, alias);
19620
+ const value = materializeEnrichAliasCellForCsv(normalized, alias, {
19621
+ compactAiCell: aiCompactAliases?.has(normalizeAlias2(alias)) ?? false
19622
+ });
19025
19623
  if (value !== void 0) {
19026
19624
  normalized[alias] = value;
19027
19625
  continue;
@@ -19276,6 +19874,7 @@ function registerEnrichCommand(program) {
19276
19874
  const inPlaceFinalOutputPath = options.inPlace ? (0, import_node_path12.resolve)(inputCsv) : null;
19277
19875
  const inPlaceCommitOutputPath = options.inPlace ? (await (0, import_promises3.lstat)(inputCsv)).isSymbolicLink() ? await (0, import_promises3.realpath)(inputCsv) : inPlaceFinalOutputPath : null;
19278
19876
  const failureReportOutputPath = options.inPlace ? inPlaceFinalOutputPath : null;
19877
+ const enrichIssueFollowUpOutputPath = options.inPlace && inPlaceFinalOutputPath ? sidecarEnrichRowsExportPath(inPlaceFinalOutputPath) : null;
19279
19878
  let inPlaceCommitted = false;
19280
19879
  const commitInPlaceOutput = async (exportResult) => {
19281
19880
  if (!inPlaceTempOutputPath || !inPlaceCommitOutputPath || !inPlaceFinalOutputPath) {
@@ -19346,7 +19945,7 @@ function registerEnrichCommand(program) {
19346
19945
  capturedResult: captured2.result,
19347
19946
  client: client2,
19348
19947
  config,
19349
- sourceCsvPath: input2.sourceCsvPath,
19948
+ sourceCsvPath: input2.mergeSourceCsvPath ?? input2.sourceCsvPath,
19350
19949
  rows: input2.rows,
19351
19950
  inPlace: Boolean(options.inPlace)
19352
19951
  });
@@ -19362,11 +19961,13 @@ function registerEnrichCommand(program) {
19362
19961
  `
19363
19962
  );
19364
19963
  }
19365
- let workingSourceCsvPath = sourceCsvPath;
19964
+ let workingMergeSourceCsvPath = sourceCsvPath;
19366
19965
  let lastStatus = null;
19966
+ const batchStatuses = [];
19367
19967
  let finalExportResult = null;
19368
19968
  let totalEnrichedRows = 0;
19369
19969
  const batchFailureRows = [];
19970
+ const runtimeCompactAliases = enrichAiRuntimeCompactAliases(config);
19370
19971
  for (let chunkStart = selectedRange.start, chunkIndex = 0; chunkStart <= selectedRange.end; chunkStart += autoBatchRows, chunkIndex += 1) {
19371
19972
  const chunkRows = {
19372
19973
  rowStart: chunkStart,
@@ -19381,18 +19982,33 @@ function registerEnrichCommand(program) {
19381
19982
  `
19382
19983
  );
19383
19984
  }
19985
+ const runtimeSourceCsvPath = options.inPlace ? sourceCsvPath : workingMergeSourceCsvPath === inputCsv ? inputCsv : (0, import_node_path12.join)(tempDir, `runtime-batch-${chunkIndex}.csv`);
19986
+ if (!options.inPlace && runtimeSourceCsvPath !== inputCsv) {
19987
+ await writeSlimBatchedRuntimeCsv({
19988
+ cleanSourceCsvPath: inputCsv,
19989
+ mergeSourceCsvPath: workingMergeSourceCsvPath,
19990
+ rows: chunkRows,
19991
+ compactAliases: runtimeCompactAliases,
19992
+ outputPath: runtimeSourceCsvPath
19993
+ });
19994
+ }
19384
19995
  const chunk = await runOne({
19385
- sourceCsvPath: workingSourceCsvPath,
19996
+ sourceCsvPath: runtimeSourceCsvPath,
19997
+ mergeSourceCsvPath: workingMergeSourceCsvPath,
19386
19998
  rows: chunkRows,
19387
19999
  json: true,
19388
20000
  passthroughStdout: false,
19389
20001
  suppressOpen: true
19390
20002
  });
19391
20003
  lastStatus = chunk.status;
20004
+ batchStatuses.push(chunk.status);
19392
20005
  if (chunk.captured.result !== 0) {
19393
20006
  if (chunk.exportResult) {
19394
20007
  finalExportResult = chunk.exportResult;
19395
- totalEnrichedRows += chunk.exportResult.enrichedRows;
20008
+ totalEnrichedRows += countEnrichedRowsInSourceRange(
20009
+ chunk.exportResult,
20010
+ chunkRows
20011
+ );
19396
20012
  batchFailureRows.push(...chunk.exportResult.enrichedDataRows);
19397
20013
  }
19398
20014
  const failureReport3 = await maybeEmitEnrichFailureReport({
@@ -19405,7 +20021,10 @@ function registerEnrichCommand(program) {
19405
20021
  statusRowRange: chunkRows,
19406
20022
  client: client2,
19407
20023
  outputPath: failureReportOutputPath ?? finalExportResult?.path ?? outputPath,
19408
- status: chunk.status
20024
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
20025
+ status: chunk.status,
20026
+ waterfallStatus: batchStatuses,
20027
+ ...finalExportResult ? { rowSetComplete: !finalExportResult.partial } : {}
19409
20028
  });
19410
20029
  const committedExportResult2 = finalExportResult ? await commitInPlaceOutput(finalExportResult) : null;
19411
20030
  if (options.json) {
@@ -19427,12 +20046,7 @@ function registerEnrichCommand(program) {
19427
20046
  partial: true
19428
20047
  } : {}
19429
20048
  } : null,
19430
- ...failureReport3 ? {
19431
- failure_report: {
19432
- path: failureReport3.path,
19433
- jobs: failureReport3.jobs.length
19434
- }
19435
- } : {}
20049
+ ...enrichReportJson(failureReport3)
19436
20050
  });
19437
20051
  } else {
19438
20052
  if (committedExportResult2) {
@@ -19453,9 +20067,12 @@ function registerEnrichCommand(program) {
19453
20067
  }
19454
20068
  if (chunk.exportResult) {
19455
20069
  finalExportResult = chunk.exportResult;
19456
- totalEnrichedRows += chunk.exportResult.enrichedRows;
20070
+ totalEnrichedRows += countEnrichedRowsInSourceRange(
20071
+ chunk.exportResult,
20072
+ chunkRows
20073
+ );
19457
20074
  batchFailureRows.push(...chunk.exportResult.enrichedDataRows);
19458
- workingSourceCsvPath = outputPath;
20075
+ workingMergeSourceCsvPath = outputPath;
19459
20076
  }
19460
20077
  }
19461
20078
  const outputRows = readCsvRows(outputPath);
@@ -19468,7 +20085,10 @@ function registerEnrichCommand(program) {
19468
20085
  },
19469
20086
  client: client2,
19470
20087
  outputPath: failureReportOutputPath ?? finalExportResult?.path ?? outputPath,
19471
- status: lastStatus
20088
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
20089
+ status: lastStatus,
20090
+ waterfallStatus: batchStatuses,
20091
+ ...finalExportResult ? { rowSetComplete: !finalExportResult.partial } : {}
19472
20092
  });
19473
20093
  finalExportResult = await commitInPlaceOutput(finalExportResult);
19474
20094
  if (options.json) {
@@ -19500,12 +20120,7 @@ function registerEnrichCommand(program) {
19500
20120
  enrichedRows: totalEnrichedRows,
19501
20121
  path: finalExportResult.path
19502
20122
  } : null,
19503
- ...failureReport2 ? {
19504
- failure_report: {
19505
- path: failureReport2.path,
19506
- jobs: failureReport2.jobs.length
19507
- }
19508
- } : {}
20123
+ ...enrichReportJson(failureReport2)
19509
20124
  });
19510
20125
  }
19511
20126
  if (failureReport2) {
@@ -19536,6 +20151,7 @@ function registerEnrichCommand(program) {
19536
20151
  exportResult: committedExportResult2,
19537
20152
  outputPath,
19538
20153
  reportOutputPath: failureReportOutputPath,
20154
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
19539
20155
  status
19540
20156
  });
19541
20157
  if (options.json) {
@@ -19543,12 +20159,7 @@ function registerEnrichCommand(program) {
19543
20159
  ok: false,
19544
20160
  run: status,
19545
20161
  output: enrichOutputJson(committedExportResult2),
19546
- ...failureReport2 ? {
19547
- failure_report: {
19548
- path: failureReport2.path,
19549
- jobs: failureReport2.jobs.length
19550
- }
19551
- } : {}
20162
+ ...enrichReportJson(failureReport2)
19552
20163
  });
19553
20164
  }
19554
20165
  process.exitCode = failureReport2 ? EXIT_SERVER2 : captured.result;
@@ -19563,6 +20174,7 @@ function registerEnrichCommand(program) {
19563
20174
  exportResult,
19564
20175
  outputPath,
19565
20176
  reportOutputPath: failureReportOutputPath,
20177
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
19566
20178
  status
19567
20179
  });
19568
20180
  const committedExportResult2 = await commitInPlaceOutput(exportResult);
@@ -19577,12 +20189,7 @@ function registerEnrichCommand(program) {
19577
20189
  ok: !failureReport2,
19578
20190
  run,
19579
20191
  output: enrichOutputJson(committedExportResult2),
19580
- ...failureReport2 ? {
19581
- failure_report: {
19582
- path: failureReport2.path,
19583
- jobs: failureReport2.jobs.length
19584
- }
19585
- } : {}
20192
+ ...enrichReportJson(failureReport2)
19586
20193
  });
19587
20194
  if (failureReport2) {
19588
20195
  process.exitCode = EXIT_SERVER2;
@@ -19595,7 +20202,9 @@ function registerEnrichCommand(program) {
19595
20202
  rowRange: rows,
19596
20203
  client: client2,
19597
20204
  outputPath: failureReportOutputPath ?? exportResult?.path ?? null,
19598
- status
20205
+ followUpOutputPath: enrichIssueFollowUpOutputPath,
20206
+ status,
20207
+ ...exportResult ? { rowSetComplete: !exportResult.partial } : {}
19599
20208
  });
19600
20209
  const committedExportResult = await commitInPlaceOutput(exportResult);
19601
20210
  if (committedExportResult) {