@claritylabs/cl-sdk 1.1.0 → 1.3.1

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/index.mjs CHANGED
@@ -673,7 +673,8 @@ var EndorsementSchema = z5.object({
673
673
  namedParties: z5.array(EndorsementPartySchema).optional(),
674
674
  keyTerms: z5.array(z5.string()).optional(),
675
675
  premiumImpact: z5.string().optional(),
676
- content: z5.string(),
676
+ excerpt: z5.string().optional(),
677
+ content: z5.string().optional(),
677
678
  pageStart: z5.number(),
678
679
  pageEnd: z5.number().optional(),
679
680
  recordId: z5.string().optional(),
@@ -1286,7 +1287,10 @@ var SubsectionSchema = z16.object({
1286
1287
  title: z16.string(),
1287
1288
  sectionNumber: z16.string().optional(),
1288
1289
  pageNumber: z16.number().optional(),
1289
- content: z16.string()
1290
+ excerpt: z16.string().optional(),
1291
+ content: z16.string().optional(),
1292
+ sourceSpanIds: z16.array(z16.string()).optional(),
1293
+ sourceTextHash: z16.string().optional()
1290
1294
  });
1291
1295
  var SectionSchema = z16.object({
1292
1296
  title: z16.string(),
@@ -1295,7 +1299,8 @@ var SectionSchema = z16.object({
1295
1299
  pageEnd: z16.number().optional(),
1296
1300
  type: z16.string(),
1297
1301
  coverageType: z16.string().optional(),
1298
- content: z16.string(),
1302
+ excerpt: z16.string().optional(),
1303
+ content: z16.string().optional(),
1299
1304
  subsections: z16.array(SubsectionSchema).optional(),
1300
1305
  recordId: z16.string().optional(),
1301
1306
  sourceSpanIds: z16.array(z16.string()).optional(),
@@ -2471,6 +2476,254 @@ async function overlayTextOnPdf(pdfBytes, overlays) {
2471
2476
  return await pdfDoc.save();
2472
2477
  }
2473
2478
 
2479
+ // src/extraction/docling.ts
2480
+ function isDoclingExtractionInput(input) {
2481
+ return Boolean(
2482
+ input && typeof input === "object" && input.kind === "docling_document" && input.document && typeof input.document === "object"
2483
+ );
2484
+ }
2485
+ function normalizeDoclingDocument(document, options) {
2486
+ const itemMap = buildItemMap(document);
2487
+ const orderedRefs = getOrderedBodyRefs(document, itemMap);
2488
+ const orderedItems = orderedRefs.length > 0 ? orderedRefs.map((ref) => itemMap.get(ref)).filter((item) => Boolean(item)) : getFallbackOrderedItems(document, itemMap);
2489
+ const units = orderedItems.map(({ ref, item }) => normalizeItem(ref, item)).filter((unit) => Boolean(unit && unit.text.trim()));
2490
+ const pageCount = inferPageCount(document, units);
2491
+ const pageTexts = /* @__PURE__ */ new Map();
2492
+ for (const unit of units) {
2493
+ const page = clampPage(unit.pageStart ?? 1, pageCount);
2494
+ pageTexts.set(page, appendText(pageTexts.get(page), unit.text));
2495
+ }
2496
+ const fullText = Array.from({ length: pageCount }, (_, index) => {
2497
+ const pageNumber = index + 1;
2498
+ const text = pageTexts.get(pageNumber)?.trim();
2499
+ return text ? `Page ${pageNumber}
2500
+ ${text}` : "";
2501
+ }).filter(Boolean).join("\n\n");
2502
+ const sourceKind = options.sourceKind ?? "policy_pdf";
2503
+ const sourceSpans = units.map((unit, index) => {
2504
+ const span = buildSourceSpan(
2505
+ {
2506
+ documentId: options.documentId,
2507
+ sourceKind,
2508
+ text: unit.text,
2509
+ pageStart: unit.pageStart,
2510
+ pageEnd: unit.pageEnd,
2511
+ sectionId: unit.label,
2512
+ metadata: {
2513
+ sourceSystem: "docling",
2514
+ sourceUnit: "docling_item",
2515
+ doclingRef: unit.ref,
2516
+ ...unit.label ? { doclingLabel: unit.label } : {}
2517
+ }
2518
+ },
2519
+ index
2520
+ );
2521
+ return {
2522
+ ...span,
2523
+ kind: "plain_text",
2524
+ bbox: unit.bboxes?.length ? unit.bboxes : void 0
2525
+ };
2526
+ });
2527
+ return {
2528
+ pageCount,
2529
+ fullText,
2530
+ pageTexts,
2531
+ units,
2532
+ sourceSpans
2533
+ };
2534
+ }
2535
+ function getDoclingPageRangeText(normalized, startPage, endPage) {
2536
+ const start = clampPage(startPage, normalized.pageCount);
2537
+ const end = clampPage(endPage, normalized.pageCount);
2538
+ const lines = [];
2539
+ for (let page = start; page <= end; page++) {
2540
+ const text = normalized.pageTexts.get(page)?.trim();
2541
+ if (text) {
2542
+ lines.push(`Page ${page}
2543
+ ${text}`);
2544
+ }
2545
+ }
2546
+ return lines.join("\n\n");
2547
+ }
2548
+ function buildDoclingProviderOptions(normalized, existingOptions) {
2549
+ return {
2550
+ ...existingOptions,
2551
+ doclingText: normalized.fullText,
2552
+ doclingPageCount: normalized.pageCount
2553
+ };
2554
+ }
2555
+ function mergeSourceSpans(spans) {
2556
+ const seen = /* @__PURE__ */ new Set();
2557
+ const merged = [];
2558
+ for (const span of spans) {
2559
+ const key = [
2560
+ span.documentId,
2561
+ span.pageStart ?? span.location?.startPage ?? span.location?.page ?? "na",
2562
+ span.pageEnd ?? span.location?.endPage ?? span.pageStart ?? "na",
2563
+ span.sectionId ?? span.location?.fieldPath ?? "na",
2564
+ span.textHash ?? sourceSpanTextHash(span.text)
2565
+ ].join(":");
2566
+ if (seen.has(key)) continue;
2567
+ seen.add(key);
2568
+ merged.push(span);
2569
+ }
2570
+ return merged;
2571
+ }
2572
+ function buildItemMap(document) {
2573
+ const map = /* @__PURE__ */ new Map();
2574
+ addItems(map, "#/texts", document.texts ?? []);
2575
+ addItems(map, "#/tables", document.tables ?? []);
2576
+ addItems(map, "#/key_value_items", document.key_value_items ?? document.keyValueItems ?? []);
2577
+ addItems(map, "#/pictures", document.pictures ?? []);
2578
+ return map;
2579
+ }
2580
+ function addItems(map, baseRef, items) {
2581
+ items.forEach((item, index) => {
2582
+ const ref = getSelfRef(item) ?? `${baseRef}/${index}`;
2583
+ map.set(ref, { ref, item });
2584
+ });
2585
+ }
2586
+ function getFallbackOrderedItems(document, itemMap) {
2587
+ const refs = [
2588
+ ...(document.texts ?? []).map((item, index) => getSelfRef(item) ?? `#/texts/${index}`),
2589
+ ...(document.tables ?? []).map((item, index) => getSelfRef(item) ?? `#/tables/${index}`),
2590
+ ...(document.key_value_items ?? document.keyValueItems ?? []).map((item, index) => getSelfRef(item) ?? `#/key_value_items/${index}`)
2591
+ ];
2592
+ return refs.map((ref) => itemMap.get(ref)).filter((item) => Boolean(item));
2593
+ }
2594
+ function getOrderedBodyRefs(document, itemMap) {
2595
+ const groupMap = /* @__PURE__ */ new Map();
2596
+ (document.groups ?? []).forEach((group, index) => {
2597
+ groupMap.set(getSelfRef(group) ?? `#/groups/${index}`, group);
2598
+ });
2599
+ const refs = [];
2600
+ const visited = /* @__PURE__ */ new Set();
2601
+ const visitRef = (ref) => {
2602
+ const itemEntry = itemMap.get(ref);
2603
+ if (itemEntry) {
2604
+ if (!visited.has(ref)) {
2605
+ visited.add(ref);
2606
+ refs.push(ref);
2607
+ }
2608
+ visitNode(itemEntry.item);
2609
+ return;
2610
+ }
2611
+ visitNode(groupMap.get(ref));
2612
+ };
2613
+ const visitNode = (node) => {
2614
+ for (const child of node?.children ?? []) {
2615
+ const ref = getRef(child);
2616
+ if (!ref) continue;
2617
+ visitRef(ref);
2618
+ }
2619
+ };
2620
+ visitNode(document.body);
2621
+ return refs;
2622
+ }
2623
+ function normalizeItem(ref, item) {
2624
+ const text = getItemText(item).trim();
2625
+ if (!text) return void 0;
2626
+ const pages = (item.prov ?? []).map((prov) => getPageNumber(prov)).filter((page) => typeof page === "number" && page > 0);
2627
+ const pageStart = pages.length ? Math.min(...pages) : void 0;
2628
+ const pageEnd = pages.length ? Math.max(...pages) : pageStart;
2629
+ const bboxes = (item.prov ?? []).map((prov) => toSourceSpanBBox(prov)).filter((bbox) => Boolean(bbox));
2630
+ return {
2631
+ ref,
2632
+ label: typeof item.label === "string" ? item.label : void 0,
2633
+ text,
2634
+ pageStart,
2635
+ pageEnd,
2636
+ bboxes: bboxes.length ? bboxes : void 0
2637
+ };
2638
+ }
2639
+ function getItemText(item) {
2640
+ if (typeof item.text === "string" && item.text.trim()) return item.text;
2641
+ if (typeof item.orig === "string" && item.orig.trim()) return item.orig;
2642
+ const table = tableToMarkdown(item.data);
2643
+ if (table) return table;
2644
+ return "";
2645
+ }
2646
+ function tableToMarkdown(data) {
2647
+ const record = asRecord(data);
2648
+ const cells = Array.isArray(record?.table_cells) ? record.table_cells : Array.isArray(record?.tableCells) ? record.tableCells : void 0;
2649
+ if (!cells) return void 0;
2650
+ const parsedCells = cells.map((cell) => asRecord(cell)).filter((cell) => Boolean(cell)).map((cell) => ({
2651
+ row: firstNumber2([cell.start_row_offset, cell.row_header, cell.row, cell.rowIndex]) ?? 0,
2652
+ col: firstNumber2([cell.start_col_offset, cell.col, cell.colIndex]) ?? 0,
2653
+ text: firstString([cell.text, cell.orig, cell.content])
2654
+ })).filter((cell) => cell.text);
2655
+ if (parsedCells.length === 0) return void 0;
2656
+ const maxRow = Math.max(...parsedCells.map((cell) => cell.row));
2657
+ const maxCol = Math.max(...parsedCells.map((cell) => cell.col));
2658
+ const rows = Array.from({ length: maxRow + 1 }, () => Array.from({ length: maxCol + 1 }, () => ""));
2659
+ for (const cell of parsedCells) {
2660
+ rows[cell.row][cell.col] = cell.text;
2661
+ }
2662
+ if (rows.length === 1) return rows[0].filter(Boolean).join(" | ");
2663
+ const header = rows[0];
2664
+ const separator = header.map(() => "---");
2665
+ return [header, separator, ...rows.slice(1)].map((row) => `| ${row.map((value) => value.trim()).join(" | ")} |`).join("\n");
2666
+ }
2667
+ function inferPageCount(document, units) {
2668
+ const pages = document.pages;
2669
+ if (Array.isArray(pages)) return Math.max(1, pages.length);
2670
+ if (pages && typeof pages === "object") {
2671
+ const keys = Object.keys(pages);
2672
+ const numericMax = Math.max(0, ...keys.map((key) => Number(key)).filter((value) => Number.isFinite(value)));
2673
+ return Math.max(1, numericMax || keys.length);
2674
+ }
2675
+ return Math.max(1, ...units.flatMap((unit) => [unit.pageStart ?? 0, unit.pageEnd ?? 0]));
2676
+ }
2677
+ function getSelfRef(value) {
2678
+ return value.self_ref ?? value.selfRef;
2679
+ }
2680
+ function getRef(value) {
2681
+ if (typeof value === "string") return value;
2682
+ return value.$ref ?? value.ref;
2683
+ }
2684
+ function getPageNumber(prov) {
2685
+ return prov.page_no ?? prov.pageNo ?? prov.page;
2686
+ }
2687
+ function toSourceSpanBBox(prov) {
2688
+ const page = getPageNumber(prov);
2689
+ const bbox = asRecord(prov.bbox);
2690
+ if (!page || !bbox) return void 0;
2691
+ const x = firstNumber2([bbox.x, bbox.l, bbox.left]);
2692
+ const y = firstNumber2([bbox.y, bbox.t, bbox.top]);
2693
+ const width = firstNumber2([bbox.width]);
2694
+ const height = firstNumber2([bbox.height]);
2695
+ const right = firstNumber2([bbox.r, bbox.right]);
2696
+ const bottom = firstNumber2([bbox.b, bbox.bottom]);
2697
+ if (x == null || y == null) return void 0;
2698
+ const resolvedWidth = width ?? (right != null ? right - x : void 0);
2699
+ const resolvedHeight = height ?? (bottom != null ? bottom - y : void 0);
2700
+ if (resolvedWidth == null || resolvedHeight == null) return void 0;
2701
+ return { page, x, y, width: resolvedWidth, height: resolvedHeight };
2702
+ }
2703
+ function clampPage(page, pageCount) {
2704
+ return Math.max(1, Math.min(pageCount, page));
2705
+ }
2706
+ function appendText(existing, next) {
2707
+ return existing ? `${existing}
2708
+
2709
+ ${next}` : next;
2710
+ }
2711
+ function asRecord(value) {
2712
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2713
+ }
2714
+ function firstString(values) {
2715
+ for (const value of values) {
2716
+ if (typeof value === "string" && value.trim()) return value.trim();
2717
+ }
2718
+ return "";
2719
+ }
2720
+ function firstNumber2(values) {
2721
+ for (const value of values) {
2722
+ if (typeof value === "number" && Number.isFinite(value)) return value;
2723
+ }
2724
+ return void 0;
2725
+ }
2726
+
2474
2727
  // src/extraction/extractor.ts
2475
2728
  function sourceSpansForPageRange(providerOptions, startPage, endPage) {
2476
2729
  const sourceSpans = providerOptions?.sourceSpans;
@@ -2519,15 +2772,31 @@ async function runExtractor(params) {
2519
2772
  } = params;
2520
2773
  const extractorProviderOptions = { ...providerOptions };
2521
2774
  let fullPrompt;
2522
- const needsPdfBase64 = convertPdfToImages && !params.getPageImages || !convertPdfToImages && !params.getPageRangePdf;
2523
- const pdfBase64 = needsPdfBase64 ? await pdfInputToBase64(pdfInput) : void 0;
2524
- if (convertPdfToImages) {
2775
+ if (params.getPageRangeText) {
2776
+ const pageText = await params.getPageRangeText(startPage, endPage);
2777
+ extractorProviderOptions.doclingText = pageText;
2778
+ extractorProviderOptions.doclingPageRange = { startPage, endPage };
2779
+ fullPrompt = `${prompt}
2780
+
2781
+ [Document pages ${startPage}-${endPage} are provided below as Docling-extracted text.]
2782
+
2783
+ ${pageText || "(No Docling text was available for this page range.)"}`;
2784
+ } else if (convertPdfToImages) {
2785
+ if (!pdfInput) {
2786
+ throw new Error("pdfInput is required when extracting page images.");
2787
+ }
2788
+ const needsPdfBase64 = !params.getPageImages;
2789
+ const pdfBase64 = needsPdfBase64 ? await pdfInputToBase64(pdfInput) : void 0;
2525
2790
  const images = params.getPageImages ? await params.getPageImages(startPage, endPage) : await convertPdfToImages(pdfBase64, startPage, endPage);
2526
2791
  extractorProviderOptions.images = images;
2527
2792
  fullPrompt = `${prompt}
2528
2793
 
2529
2794
  [Document pages ${startPage}-${endPage} are provided as images.]`;
2530
2795
  } else {
2796
+ if (!pdfInput) {
2797
+ throw new Error("pdfInput is required when extracting page PDFs.");
2798
+ }
2799
+ const pdfBase64 = params.getPageRangePdf ? void 0 : await pdfInputToBase64(pdfInput);
2531
2800
  const cacheKey = `${startPage}-${endPage}`;
2532
2801
  const cachedPagesPdf = pageRangeCache?.get(cacheKey);
2533
2802
  const pagesPdf = cachedPagesPdf ?? (params.getPageRangePdf ? await params.getPageRangePdf(startPage, endPage) : await extractPageRange(pdfBase64, startPage, endPage));
@@ -2549,6 +2818,14 @@ async function runExtractor(params) {
2549
2818
  maxTokens,
2550
2819
  taskKind,
2551
2820
  budgetDiagnostics,
2821
+ trace: {
2822
+ label: `${name} pages ${startPage}-${endPage}`,
2823
+ extractorName: name,
2824
+ startPage,
2825
+ endPage,
2826
+ phase: "extractor",
2827
+ sourceBacked: !!sourceContext
2828
+ },
2552
2829
  providerOptions: extractorProviderOptions
2553
2830
  })
2554
2831
  );
@@ -3414,21 +3691,30 @@ function collectContentFields(doc) {
3414
3691
  entries.push({ id: id++, path, text });
3415
3692
  }
3416
3693
  }
3694
+ function hasSourceBacking(record) {
3695
+ return Array.isArray(record.sourceSpanIds) && record.sourceSpanIds.length > 0 || !!record.sourceTextHash;
3696
+ }
3417
3697
  add("summary", doc.summary);
3418
3698
  if (doc.sections) {
3419
3699
  for (let i = 0; i < doc.sections.length; i++) {
3420
3700
  const s = doc.sections[i];
3421
- add(`sections[${i}].content`, s.content);
3701
+ if (!hasSourceBacking(s)) {
3702
+ add(`sections[${i}].content`, s.content);
3703
+ }
3422
3704
  if (s.subsections) {
3423
3705
  for (let j = 0; j < s.subsections.length; j++) {
3424
- add(`sections[${i}].subsections[${j}].content`, s.subsections[j].content);
3706
+ if (!hasSourceBacking(s.subsections[j])) {
3707
+ add(`sections[${i}].subsections[${j}].content`, s.subsections[j].content);
3708
+ }
3425
3709
  }
3426
3710
  }
3427
3711
  }
3428
3712
  }
3429
3713
  if (doc.endorsements) {
3430
3714
  for (let i = 0; i < doc.endorsements.length; i++) {
3431
- add(`endorsements[${i}].content`, doc.endorsements[i].content);
3715
+ if (!hasSourceBacking(doc.endorsements[i])) {
3716
+ add(`endorsements[${i}].content`, doc.endorsements[i].content);
3717
+ }
3432
3718
  }
3433
3719
  }
3434
3720
  if (doc.exclusions) {
@@ -3530,6 +3816,12 @@ async function formatDocumentContent(doc, generateText, options) {
3530
3816
  maxTokens: options?.maxTokens ?? 16384,
3531
3817
  taskKind: options?.taskKind,
3532
3818
  budgetDiagnostics: options?.budgetDiagnostics,
3819
+ trace: {
3820
+ label: `format content batch ${batchIdx + 1}/${batches.length}`,
3821
+ phase: "format",
3822
+ batchIndex: batchIdx + 1,
3823
+ batchCount: batches.length
3824
+ },
3533
3825
  providerOptions: options?.providerOptions
3534
3826
  })
3535
3827
  );
@@ -3567,7 +3859,7 @@ function formatAddress(addr) {
3567
3859
  function asRecordArray(value) {
3568
3860
  return Array.isArray(value) ? value.filter((item) => Boolean(item) && typeof item === "object" && !Array.isArray(item)) : [];
3569
3861
  }
3570
- function firstString(item, keys) {
3862
+ function firstString2(item, keys) {
3571
3863
  for (const key of keys) {
3572
3864
  const value = item[key];
3573
3865
  if (typeof value === "string" && value.trim()) return value;
@@ -3604,7 +3896,7 @@ function chunkDocument(doc) {
3604
3896
  documentId: docId,
3605
3897
  type,
3606
3898
  text,
3607
- metadata: stringMetadata(metadata)
3899
+ metadata: stringMetadata({ evidenceKind: "structured_fact", ...metadata })
3608
3900
  });
3609
3901
  }
3610
3902
  pushChunk(
@@ -3883,16 +4175,29 @@ function chunkDocument(doc) {
3883
4175
  );
3884
4176
  });
3885
4177
  doc.endorsements?.forEach((end, i) => {
4178
+ const text = lines([
4179
+ `Endorsement: ${end.title}`,
4180
+ end.formNumber ? `Form: ${end.formNumber}` : null,
4181
+ end.editionDate ? `Edition: ${end.editionDate}` : null,
4182
+ `Type: ${end.endorsementType}`,
4183
+ end.effectiveDate ? `Effective Date: ${end.effectiveDate}` : null,
4184
+ end.affectedCoverageParts?.length ? `Affected Coverage Parts: ${end.affectedCoverageParts.join(", ")}` : null,
4185
+ end.keyTerms?.length ? `Key Terms: ${end.keyTerms.join("; ")}` : null,
4186
+ end.premiumImpact ? `Premium Impact: ${end.premiumImpact}` : null,
4187
+ end.excerpt ? `Excerpt: ${end.excerpt}` : null
4188
+ ]);
4189
+ if (!text.trim()) return;
3886
4190
  pushChunk(
3887
4191
  `endorsement:${i}`,
3888
4192
  "endorsement",
3889
- `Endorsement: ${end.title}
3890
- ${end.content}`.trim(),
4193
+ text,
3891
4194
  {
3892
4195
  endorsementType: end.endorsementType,
3893
4196
  formNumber: end.formNumber,
3894
4197
  pageStart: end.pageStart,
3895
4198
  pageEnd: end.pageEnd,
4199
+ sourceSpanIds: end.sourceSpanIds?.join(","),
4200
+ sourceTextHash: end.sourceTextHash,
3896
4201
  documentType: doc.type
3897
4202
  }
3898
4203
  );
@@ -3924,32 +4229,32 @@ ${exc.content}`.trim(), {
3924
4229
  );
3925
4230
  });
3926
4231
  asRecordArray(extendedDoc.definitions).forEach((definition, i) => {
3927
- const term = firstString(definition, ["term", "name", "title"]) ?? `Definition ${i + 1}`;
3928
- const body = firstString(definition, ["definition", "content", "text", "meaning"]);
4232
+ const term = firstString2(definition, ["term", "name", "title"]) ?? `Definition ${i + 1}`;
4233
+ const body = firstString2(definition, ["definition", "content", "text", "meaning"]);
3929
4234
  pushChunk(
3930
4235
  `definition:${i}`,
3931
4236
  "definition",
3932
4237
  lines([
3933
4238
  `Definition: ${term}`,
3934
4239
  body,
3935
- firstString(definition, ["originalContent", "source"]) ? `Source: ${firstString(definition, ["originalContent", "source"])}` : null
4240
+ firstString2(definition, ["originalContent", "source"]) ? `Source: ${firstString2(definition, ["originalContent", "source"])}` : null
3936
4241
  ]),
3937
4242
  {
3938
4243
  term,
3939
- formNumber: firstString(definition, ["formNumber"]),
3940
- formTitle: firstString(definition, ["formTitle"]),
4244
+ formNumber: firstString2(definition, ["formNumber"]),
4245
+ formTitle: firstString2(definition, ["formTitle"]),
3941
4246
  pageNumber: typeof definition.pageNumber === "number" ? definition.pageNumber : void 0,
3942
- sectionRef: firstString(definition, ["sectionRef", "sectionTitle"]),
4247
+ sectionRef: firstString2(definition, ["sectionRef", "sectionTitle"]),
3943
4248
  documentType: doc.type
3944
4249
  }
3945
4250
  );
3946
4251
  });
3947
4252
  const coveredReasons = asRecordArray(extendedDoc.coveredReasons ?? extendedDoc.covered_reasons);
3948
4253
  coveredReasons.forEach((coveredReason, i) => {
3949
- const title = firstString(coveredReason, ["title", "name", "reason", "peril", "cause"]) ?? `Covered Reason ${i + 1}`;
3950
- const coverageName = firstString(coveredReason, ["coverageName", "coverage", "coveragePart"]);
3951
- const reasonNumber = firstString(coveredReason, ["reasonNumber", "number"]);
3952
- const body = firstString(coveredReason, ["content", "description", "text", "coverageGrant"]);
4254
+ const title = firstString2(coveredReason, ["title", "name", "reason", "peril", "cause"]) ?? `Covered Reason ${i + 1}`;
4255
+ const coverageName = firstString2(coveredReason, ["coverageName", "coverage", "coveragePart"]);
4256
+ const reasonNumber = firstString2(coveredReason, ["reasonNumber", "number"]);
4257
+ const body = firstString2(coveredReason, ["content", "description", "text", "coverageGrant"]);
3953
4258
  pushChunk(
3954
4259
  `covered_reason:${i}`,
3955
4260
  "covered_reason",
@@ -3958,16 +4263,16 @@ ${exc.content}`.trim(), {
3958
4263
  reasonNumber ? `Reason Number: ${reasonNumber}` : null,
3959
4264
  `Covered Reason: ${title}`,
3960
4265
  body,
3961
- firstString(coveredReason, ["originalContent", "source"]) ? `Source: ${firstString(coveredReason, ["originalContent", "source"])}` : null
4266
+ firstString2(coveredReason, ["originalContent", "source"]) ? `Source: ${firstString2(coveredReason, ["originalContent", "source"])}` : null
3962
4267
  ]),
3963
4268
  {
3964
4269
  coverageName,
3965
4270
  reasonNumber,
3966
4271
  title,
3967
- formNumber: firstString(coveredReason, ["formNumber"]),
3968
- formTitle: firstString(coveredReason, ["formTitle"]),
4272
+ formNumber: firstString2(coveredReason, ["formNumber"]),
4273
+ formTitle: firstString2(coveredReason, ["formTitle"]),
3969
4274
  pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
3970
- sectionRef: firstString(coveredReason, ["sectionRef", "sectionTitle"]),
4275
+ sectionRef: firstString2(coveredReason, ["sectionRef", "sectionTitle"]),
3971
4276
  documentType: doc.type
3972
4277
  }
3973
4278
  );
@@ -3987,10 +4292,10 @@ ${exc.content}`.trim(), {
3987
4292
  reasonNumber,
3988
4293
  title,
3989
4294
  conditionIndex,
3990
- formNumber: firstString(coveredReason, ["formNumber"]),
3991
- formTitle: firstString(coveredReason, ["formTitle"]),
4295
+ formNumber: firstString2(coveredReason, ["formNumber"]),
4296
+ formTitle: firstString2(coveredReason, ["formTitle"]),
3992
4297
  pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
3993
- sectionRef: firstString(coveredReason, ["sectionRef", "sectionTitle"]),
4298
+ sectionRef: firstString2(coveredReason, ["sectionRef", "sectionTitle"]),
3994
4299
  documentType: doc.type
3995
4300
  }
3996
4301
  );
@@ -4014,93 +4319,51 @@ ${declLines.join("\n")}`, declMeta);
4014
4319
  }
4015
4320
  doc.sections?.forEach((sec, i) => {
4016
4321
  const hasSubsections = sec.subsections && sec.subsections.length > 0;
4017
- const contentLength = sec.content.length;
4018
- if (hasSubsections) {
4019
- pushChunk(
4020
- `section:${i}`,
4021
- "section",
4022
- `Section: ${sec.title}
4023
- ${sec.content}`,
4024
- {
4025
- sectionType: sec.type,
4026
- sectionNumber: sec.sectionNumber,
4027
- pageStart: sec.pageStart,
4028
- pageEnd: sec.pageEnd,
4029
- documentType: doc.type,
4030
- hasSubsections: "true"
4031
- }
4032
- );
4033
- sec.subsections.forEach((sub, j) => {
4034
- pushChunk(
4035
- `section:${i}:sub:${j}`,
4036
- "section",
4037
- `${sec.title} > ${sub.title}
4038
- ${sub.content}`,
4039
- {
4040
- sectionType: sec.type,
4041
- parentSection: sec.title,
4042
- sectionNumber: sub.sectionNumber,
4043
- pageNumber: sub.pageNumber,
4044
- documentType: doc.type
4045
- }
4046
- );
4047
- });
4048
- } else if (contentLength > 2e3) {
4049
- const paragraphs = sec.content.split(/\n\n+/);
4050
- let currentChunk = "";
4051
- let chunkIndex = 0;
4052
- for (const para of paragraphs) {
4053
- if (currentChunk.length + para.length > 1e3 && currentChunk.length > 0) {
4054
- pushChunk(
4055
- `section:${i}:part:${chunkIndex}`,
4056
- "section",
4057
- `Section: ${sec.title} (part ${chunkIndex + 1})
4058
- ${currentChunk.trim()}`,
4059
- {
4060
- sectionType: sec.type,
4061
- sectionNumber: sec.sectionNumber,
4062
- pageStart: sec.pageStart,
4063
- pageEnd: sec.pageEnd,
4064
- documentType: doc.type,
4065
- partIndex: chunkIndex
4066
- }
4067
- );
4068
- currentChunk = "";
4069
- chunkIndex++;
4070
- }
4071
- currentChunk += (currentChunk ? "\n\n" : "") + para;
4072
- }
4073
- if (currentChunk.trim()) {
4074
- pushChunk(
4075
- `section:${i}:part:${chunkIndex}`,
4076
- "section",
4077
- `Section: ${sec.title} (part ${chunkIndex + 1})
4078
- ${currentChunk.trim()}`,
4079
- {
4080
- sectionType: sec.type,
4081
- sectionNumber: sec.sectionNumber,
4082
- pageStart: sec.pageStart,
4083
- pageEnd: sec.pageEnd,
4084
- documentType: doc.type,
4085
- partIndex: chunkIndex
4086
- }
4087
- );
4322
+ pushChunk(
4323
+ `section:${i}`,
4324
+ "section",
4325
+ lines([
4326
+ `Section: ${sec.title}`,
4327
+ `Type: ${sec.type}`,
4328
+ sec.sectionNumber ? `Section Number: ${sec.sectionNumber}` : null,
4329
+ `Pages: ${sec.pageStart}${sec.pageEnd ? `-${sec.pageEnd}` : ""}`,
4330
+ sec.excerpt ? `Excerpt: ${sec.excerpt}` : null,
4331
+ hasSubsections ? `Subsections: ${sec.subsections.map((sub) => sub.title).join(", ")}` : null
4332
+ ]),
4333
+ {
4334
+ evidenceKind: "navigation",
4335
+ sectionType: sec.type,
4336
+ sectionNumber: sec.sectionNumber,
4337
+ pageStart: sec.pageStart,
4338
+ pageEnd: sec.pageEnd,
4339
+ sourceSpanIds: sec.sourceSpanIds?.join(","),
4340
+ sourceTextHash: sec.sourceTextHash,
4341
+ documentType: doc.type,
4342
+ hasSubsections
4088
4343
  }
4089
- } else {
4344
+ );
4345
+ sec.subsections?.forEach((sub, j) => {
4090
4346
  pushChunk(
4091
- `section:${i}`,
4347
+ `section:${i}:sub:${j}`,
4092
4348
  "section",
4093
- `Section: ${sec.title}
4094
- ${sec.content}`,
4349
+ lines([
4350
+ `Section: ${sec.title} > ${sub.title}`,
4351
+ sub.sectionNumber ? `Section Number: ${sub.sectionNumber}` : null,
4352
+ sub.pageNumber ? `Page: ${sub.pageNumber}` : null,
4353
+ sub.excerpt ? `Excerpt: ${sub.excerpt}` : null
4354
+ ]),
4095
4355
  {
4356
+ evidenceKind: "navigation",
4096
4357
  sectionType: sec.type,
4097
- sectionNumber: sec.sectionNumber,
4098
- pageStart: sec.pageStart,
4099
- pageEnd: sec.pageEnd,
4358
+ parentSection: sec.title,
4359
+ sectionNumber: sub.sectionNumber,
4360
+ pageNumber: sub.pageNumber,
4361
+ sourceSpanIds: sub.sourceSpanIds?.join(","),
4362
+ sourceTextHash: sub.sourceTextHash,
4100
4363
  documentType: doc.type
4101
4364
  }
4102
4365
  );
4103
- }
4366
+ });
4104
4367
  });
4105
4368
  doc.locations?.forEach((loc, i) => {
4106
4369
  chunks.push({
@@ -5972,14 +6235,17 @@ var EndorsementsSchema = z29.object({
5972
6235
  ).optional().describe("Named parties (additional insureds, loss payees, etc.)"),
5973
6236
  keyTerms: z29.array(z29.string()).optional().describe("Key terms or notable provisions in the endorsement"),
5974
6237
  premiumImpact: z29.string().optional().describe("Additional premium or credit"),
5975
- content: z29.string().describe("Full verbatim text of the endorsement"),
6238
+ excerpt: z29.string().optional().describe("Short source excerpt, not full verbatim text"),
6239
+ content: z29.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
5976
6240
  pageStart: z29.number().describe("Starting page number of this endorsement"),
5977
- pageEnd: z29.number().optional().describe("Ending page number of this endorsement")
6241
+ pageEnd: z29.number().optional().describe("Ending page number of this endorsement"),
6242
+ sourceSpanIds: z29.array(z29.string()).optional().describe("Source span IDs grounding this endorsement"),
6243
+ sourceTextHash: z29.string().optional().describe("Hash of the source text when available")
5978
6244
  })
5979
6245
  ).describe("All endorsements found in the document")
5980
6246
  });
5981
6247
  function buildEndorsementsPrompt() {
5982
- return `You are an expert insurance document analyst. Extract ALL endorsements from this document. Preserve original language verbatim.
6248
+ return `You are an expert insurance document analyst. Build a compact source-backed endorsement index for this document. Do not reproduce full endorsement language in the JSON output.
5983
6249
 
5984
6250
  For EACH endorsement, extract:
5985
6251
  - formNumber: the form identifier (e.g. "CG 21 47") \u2014 REQUIRED
@@ -5991,7 +6257,9 @@ For EACH endorsement, extract:
5991
6257
  - namedParties: for each party, extract name, role (additional_insured, loss_payee, mortgage_holder, certificate_holder, waiver_beneficiary, designated_person, other), relationship, and scope
5992
6258
  - keyTerms: notable provisions or key terms
5993
6259
  - premiumImpact: additional premium or credit if shown
5994
- - content: full verbatim text \u2014 REQUIRED
6260
+ - excerpt: short identifying source excerpt, capped at 300 characters
6261
+ - sourceSpanIds: source span IDs from the provided SOURCE SPANS that ground this endorsement
6262
+ - content: legacy fallback only; omit/null when sourceSpanIds are available
5995
6263
  - pageStart: page number where endorsement begins \u2014 REQUIRED
5996
6264
  - pageEnd: page number where endorsement ends
5997
6265
 
@@ -6001,6 +6269,11 @@ PERSONAL LINES ENDORSEMENT RECOGNITION:
6001
6269
  - HO 17 XX series: mobilehome endorsements
6002
6270
  - DP 04 XX series: dwelling fire endorsements
6003
6271
 
6272
+ Critical rules:
6273
+ - Return compact metadata plus source references. The original endorsement wording lives in source spans.
6274
+ - Do not return full endorsement text in content when sourceSpanIds are available.
6275
+ - Prefer sourceSpanIds over generated prose for evidence.
6276
+
6004
6277
  Return JSON only.`;
6005
6278
  }
6006
6279
 
@@ -6247,7 +6520,10 @@ var SubsectionSchema2 = z35.object({
6247
6520
  title: z35.string().describe("Subsection title"),
6248
6521
  sectionNumber: z35.string().optional().describe("Subsection number"),
6249
6522
  pageNumber: z35.number().optional().describe("Page number"),
6250
- content: z35.string().describe("Full verbatim text")
6523
+ excerpt: z35.string().optional().describe("Short source excerpt, not full verbatim text"),
6524
+ content: z35.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6525
+ sourceSpanIds: z35.array(z35.string()).optional().describe("Source span IDs grounding this subsection"),
6526
+ sourceTextHash: z35.string().optional().describe("Hash of the source text when available")
6251
6527
  });
6252
6528
  var SectionsSchema = z35.object({
6253
6529
  sections: z35.array(
@@ -6268,15 +6544,18 @@ var SectionsSchema = z35.object({
6268
6544
  "regulatory",
6269
6545
  "other"
6270
6546
  ]).describe("Section type classification"),
6271
- content: z35.string().describe("Full verbatim text of the section"),
6547
+ excerpt: z35.string().optional().describe("Short source excerpt, not full verbatim text"),
6548
+ content: z35.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6272
6549
  pageStart: z35.number().describe("Starting page number"),
6273
6550
  pageEnd: z35.number().optional().describe("Ending page number"),
6551
+ sourceSpanIds: z35.array(z35.string()).optional().describe("Source span IDs grounding this section"),
6552
+ sourceTextHash: z35.string().optional().describe("Hash of the source text when available"),
6274
6553
  subsections: z35.array(SubsectionSchema2).optional().describe("Subsections within this section")
6275
6554
  })
6276
6555
  ).describe("All document sections")
6277
6556
  });
6278
6557
  function buildSectionsPrompt() {
6279
- return `You are an expert insurance document analyst. Extract ALL sections, clauses, endorsements, and schedules from this document. Preserve the original language verbatim \u2014 do not summarize or paraphrase.
6558
+ return `You are an expert insurance document analyst. Build a compact source-backed section index for this document. Do not reproduce full policy language in the JSON output.
6280
6559
 
6281
6560
  For each section, classify its type:
6282
6561
  - "declarations" \u2014 declarations page(s) listing named insured, policy period, limits, premiums
@@ -6290,10 +6569,13 @@ For each section, classify its type:
6290
6569
  - "notice", "regulatory" \u2014 notice provisions or regulatory disclosures
6291
6570
  - "other" \u2014 anything that doesn't fit the above categories
6292
6571
 
6293
- Include accurate page numbers for every section. Include subsections only if the section has clearly defined subsections with their own titles.
6572
+ Include accurate page numbers for every section. Include sourceSpanIds from the provided SOURCE SPANS whenever available. Include subsections only if the section has clearly defined subsections with their own titles.
6294
6573
  If a page begins or ends in the middle of a section, treat it as a continuation of the existing section instead of creating a new orphan section from the fragment.
6295
6574
 
6296
6575
  Critical rules:
6576
+ - Return compact metadata plus source references. The original policy wording lives in source spans.
6577
+ - Use excerpt only for a short identifying snippet, capped at 300 characters.
6578
+ - Do not return full section text in content when sourceSpanIds are available. Leave content omitted/null in source-backed mode.
6297
6579
  - Ignore table-of-contents entries, page-number references, repeating headers/footers, and other navigational artifacts.
6298
6580
  - Do not create a new section from a lone continuation fragment such as a single paragraph tail or list item that clearly belongs to the previous page's section.
6299
6581
  - When a section spans multiple pages, keep it as one section with pageStart/pageEnd covering the full span represented in this extraction.
@@ -6461,21 +6743,21 @@ Return JSON only.`;
6461
6743
  }
6462
6744
 
6463
6745
  // src/prompts/extractors/index.ts
6464
- function asRecord(data) {
6746
+ function asRecord2(data) {
6465
6747
  return data && typeof data === "object" ? data : void 0;
6466
6748
  }
6467
6749
  function getSections2(data) {
6468
- const sections = asRecord(data)?.sections;
6750
+ const sections = asRecord2(data)?.sections;
6469
6751
  return Array.isArray(sections) ? sections : [];
6470
6752
  }
6471
6753
  function isCoveredReasonsEmpty(data) {
6472
- const record = asRecord(data);
6754
+ const record = asRecord2(data);
6473
6755
  if (!record) return true;
6474
6756
  const coveredReasons = Array.isArray(record.coveredReasons) ? record.coveredReasons : Array.isArray(record.covered_reasons) ? record.covered_reasons : [];
6475
6757
  return coveredReasons.length === 0;
6476
6758
  }
6477
6759
  function isDefinitionsEmpty(data) {
6478
- const definitions = asRecord(data)?.definitions;
6760
+ const definitions = asRecord2(data)?.definitions;
6479
6761
  return !Array.isArray(definitions) || definitions.length === 0;
6480
6762
  }
6481
6763
  function sectionLooksLikeCoveredReason(section) {
@@ -6709,6 +6991,14 @@ function decideReferentialResolutionAction(params) {
6709
6991
  }
6710
6992
 
6711
6993
  // src/extraction/resolve-referential.ts
6994
+ function formatDoclingTextContext(providerOptions) {
6995
+ const doclingText = providerOptions?.doclingText;
6996
+ if (typeof doclingText !== "string" || !doclingText.trim()) return "";
6997
+ return `
6998
+
6999
+ DOCLING DOCUMENT TEXT:
7000
+ ${doclingText}`;
7001
+ }
6712
7002
  function parseReferenceTarget(text) {
6713
7003
  if (typeof text !== "string") return void 0;
6714
7004
  const normalized = text.trim();
@@ -6790,12 +7080,12 @@ Return the page range (1-indexed) where this section is located. If the section
6790
7080
 
6791
7081
  If you cannot find the section, return startPage: 0 and endPage: 0.
6792
7082
 
6793
- Return JSON only.`,
7083
+ Return JSON only.${formatDoclingTextContext(providerOptions)}`,
6794
7084
  schema: PageLocationSchema,
6795
7085
  maxTokens: budget.maxTokens,
6796
7086
  taskKind: "extraction_referential_lookup",
6797
7087
  budgetDiagnostics: budget,
6798
- providerOptions: await buildPdfProviderOptions(pdfInput, providerOptions)
7088
+ providerOptions: pdfInput ? await buildPdfProviderOptions(pdfInput, providerOptions) : providerOptions
6799
7089
  },
6800
7090
  {
6801
7091
  fallback: { startPage: 0, endPage: 0 },
@@ -6829,6 +7119,7 @@ async function resolveReferentialCoverages(params) {
6829
7119
  convertPdfToImages,
6830
7120
  getPageRangePdf,
6831
7121
  getPageImages,
7122
+ getPageRangeText,
6832
7123
  concurrency = 2,
6833
7124
  providerOptions,
6834
7125
  modelCapabilities,
@@ -6940,6 +7231,7 @@ async function resolveReferentialCoverages(params) {
6940
7231
  convertPdfToImages,
6941
7232
  getPageRangePdf,
6942
7233
  getPageImages,
7234
+ getPageRangeText,
6943
7235
  maxTokens: budget.maxTokens,
6944
7236
  taskKind: "extraction_referential_lookup",
6945
7237
  budgetDiagnostics: budget,
@@ -7035,6 +7327,7 @@ async function runFocusedExtractorWithFallback(params) {
7035
7327
  pageRangeCache,
7036
7328
  getPageRangePdf,
7037
7329
  getPageImages,
7330
+ getPageRangeText,
7038
7331
  trackUsage,
7039
7332
  resolveBudget,
7040
7333
  log
@@ -7064,7 +7357,8 @@ async function runFocusedExtractorWithFallback(params) {
7064
7357
  providerOptions,
7065
7358
  pageRangeCache,
7066
7359
  getPageRangePdf,
7067
- getPageImages
7360
+ getPageImages,
7361
+ getPageRangeText
7068
7362
  });
7069
7363
  trackUsage(result.usage, {
7070
7364
  taskKind,
@@ -7109,7 +7403,8 @@ async function runFocusedExtractorWithFallback(params) {
7109
7403
  providerOptions,
7110
7404
  pageRangeCache,
7111
7405
  getPageRangePdf,
7112
- getPageImages
7406
+ getPageImages,
7407
+ getPageRangeText
7113
7408
  });
7114
7409
  trackUsage(fallbackResult.usage, {
7115
7410
  taskKind,
@@ -7953,7 +8248,7 @@ function createExtractor(config) {
7953
8248
  }
7954
8249
  return lines.length > 0 ? lines.join("\n") : "";
7955
8250
  }
7956
- async function runFocusedExtractorTask(task, pdfInput, memory, pageRangeCache, getPageRangePdf, getPageImages) {
8251
+ async function runFocusedExtractorTask(task, pdfInput, memory, pageRangeCache, getPageRangePdf, getPageImages, getPageRangeText) {
7957
8252
  if (task.extractorName === "supplementary") {
7958
8253
  const alreadyExtractedSummary = buildAlreadyExtractedSummary(memory);
7959
8254
  const budget = resolveBudget("extraction_focused", 4096);
@@ -7973,7 +8268,8 @@ function createExtractor(config) {
7973
8268
  providerOptions: activeProviderOptions,
7974
8269
  pageRangeCache,
7975
8270
  getPageRangePdf,
7976
- getPageImages
8271
+ getPageImages,
8272
+ getPageRangeText
7977
8273
  });
7978
8274
  trackUsage(result.usage, {
7979
8275
  taskKind: "extraction_focused",
@@ -7992,6 +8288,7 @@ function createExtractor(config) {
7992
8288
  pageRangeCache,
7993
8289
  getPageRangePdf,
7994
8290
  getPageImages,
8291
+ getPageRangeText,
7995
8292
  trackUsage,
7996
8293
  resolveBudget,
7997
8294
  log
@@ -8007,8 +8304,14 @@ function createExtractor(config) {
8007
8304
  if (extractorPages.size === 0) return "No page assignments available.";
8008
8305
  return [...extractorPages.entries()].map(([extractorName, pages]) => `${extractorName}: ${pages.length} page(s), pages ${pages.join(", ")}`).join("\n");
8009
8306
  }
8010
- async function extract(pdfInput, documentId, options) {
8307
+ async function extract(input, documentId, options) {
8011
8308
  const id = documentId ?? `doc-${Date.now()}`;
8309
+ const isDoclingInput = isDoclingExtractionInput(input);
8310
+ const pdfInput = isDoclingInput ? void 0 : input;
8311
+ const doclingDocument = isDoclingInput ? normalizeDoclingDocument(input.document, {
8312
+ documentId: id,
8313
+ sourceKind: input.sourceKind
8314
+ }) : void 0;
8012
8315
  const memory = /* @__PURE__ */ new Map();
8013
8316
  totalUsage = { inputTokens: 0, outputTokens: 0 };
8014
8317
  modelCalls = 0;
@@ -8018,7 +8321,10 @@ function createExtractor(config) {
8018
8321
  modelCalls: [],
8019
8322
  totalModelCallDurationMs: 0
8020
8323
  };
8021
- const sourceSpans = options?.sourceSpans ?? [];
8324
+ const sourceSpans = mergeSourceSpans([
8325
+ ...doclingDocument?.sourceSpans ?? [],
8326
+ ...options?.sourceSpans ?? []
8327
+ ]);
8022
8328
  const sourceChunks = sourceSpans.length ? chunkSourceSpans(sourceSpans) : [];
8023
8329
  activeProviderOptions = sourceSpans.length ? { ...providerOptions, sourceSpans, sourceChunks } : providerOptions;
8024
8330
  if (sourceStore && sourceSpans.length > 0) {
@@ -8047,24 +8353,40 @@ function createExtractor(config) {
8047
8353
  let fullPdfProviderOptionsPromise;
8048
8354
  let pageCountPromise;
8049
8355
  async function getPdfBase64ForExtraction() {
8356
+ if (!pdfInput) {
8357
+ throw new Error("PDF input is not available for Docling extraction.");
8358
+ }
8050
8359
  if (pdfBase64Cache === void 0) {
8051
8360
  pdfBase64Cache = await pdfInputToBase64(pdfInput);
8052
8361
  }
8053
8362
  return pdfBase64Cache;
8054
8363
  }
8055
8364
  async function getCachedPageCount() {
8365
+ if (doclingDocument) return doclingDocument.pageCount;
8366
+ if (!pdfInput) {
8367
+ throw new Error("PDF input is required to read page count.");
8368
+ }
8056
8369
  if (!pageCountPromise) {
8057
8370
  pageCountPromise = getPdfSlicer().then((slicer) => slicer.getPageCount()).catch(() => getPdfPageCount(pdfInput));
8058
8371
  }
8059
8372
  return pageCountPromise;
8060
8373
  }
8061
- async function getFullPdfProviderOptions() {
8374
+ async function getFullDocumentProviderOptions() {
8375
+ if (doclingDocument) {
8376
+ return buildDoclingProviderOptions(doclingDocument, activeProviderOptions);
8377
+ }
8378
+ if (!pdfInput) {
8379
+ return activeProviderOptions ?? {};
8380
+ }
8062
8381
  if (!fullPdfProviderOptionsPromise) {
8063
8382
  fullPdfProviderOptionsPromise = buildPdfProviderOptions(pdfInput, activeProviderOptions);
8064
8383
  }
8065
8384
  return fullPdfProviderOptionsPromise;
8066
8385
  }
8067
8386
  async function getPdfSlicer() {
8387
+ if (!pdfInput) {
8388
+ throw new Error("PDF input is not available for Docling extraction.");
8389
+ }
8068
8390
  if (!pdfSlicerPromise) {
8069
8391
  pdfSlicerPromise = createPdfPageSlicer(pdfInput);
8070
8392
  }
@@ -8103,6 +8425,23 @@ function createExtractor(config) {
8103
8425
  pageRangeImageCache.set(cacheKey, promise);
8104
8426
  return promise;
8105
8427
  }
8428
+ async function getPageRangeText(startPage, endPage) {
8429
+ return doclingDocument ? getDoclingPageRangeText(doclingDocument, startPage, endPage) : "";
8430
+ }
8431
+ function withFullDocumentTextContext(prompt) {
8432
+ if (!doclingDocument) return prompt;
8433
+ return `${prompt}
8434
+
8435
+ DOCLING DOCUMENT TEXT:
8436
+ ${doclingDocument.fullText}`;
8437
+ }
8438
+ function withPageRangeTextContext(prompt, startPage, endPage, pageText) {
8439
+ if (!doclingDocument) return prompt;
8440
+ return `${prompt}
8441
+
8442
+ DOCLING DOCUMENT PAGES ${startPage}-${endPage}:
8443
+ ${pageText || "(No Docling text was available for this page range.)"}`;
8444
+ }
8106
8445
  let classifyResult;
8107
8446
  if (resumed?.classifyResult && pipelineCtx.isPhaseComplete("classify")) {
8108
8447
  classifyResult = resumed.classifyResult;
@@ -8115,12 +8454,12 @@ function createExtractor(config) {
8115
8454
  const classifyResponse = await safeGenerateObject(
8116
8455
  generateObject,
8117
8456
  {
8118
- prompt: buildClassifyPrompt(),
8457
+ prompt: withFullDocumentTextContext(buildClassifyPrompt()),
8119
8458
  schema: ClassifyResultSchema,
8120
8459
  maxTokens: budget.maxTokens,
8121
8460
  taskKind: "extraction_classify",
8122
8461
  budgetDiagnostics: budget,
8123
- providerOptions: await getFullPdfProviderOptions()
8462
+ providerOptions: await getFullDocumentProviderOptions()
8124
8463
  },
8125
8464
  {
8126
8465
  fallback: { documentType: "policy", policyTypes: ["other"], confidence: 0 },
@@ -8165,12 +8504,12 @@ function createExtractor(config) {
8165
8504
  const formInventoryResponse = await safeGenerateObject(
8166
8505
  generateObject,
8167
8506
  {
8168
- prompt: buildFormInventoryPrompt(templateHints),
8507
+ prompt: withFullDocumentTextContext(buildFormInventoryPrompt(templateHints)),
8169
8508
  schema: FormInventorySchema,
8170
8509
  maxTokens: budget.maxTokens,
8171
8510
  taskKind: "extraction_form_inventory",
8172
8511
  budgetDiagnostics: budget,
8173
- providerOptions: await getFullPdfProviderOptions()
8512
+ providerOptions: await getFullDocumentProviderOptions()
8174
8513
  },
8175
8514
  {
8176
8515
  fallback: { forms: [] },
@@ -8213,18 +8552,24 @@ function createExtractor(config) {
8213
8552
  const pageMapResults = await Promise.all(
8214
8553
  pageMapChunks.map(
8215
8554
  ({ startPage, endPage }) => pageMapLimit(async () => {
8216
- const pagesPdf = await getPageRangePdf(startPage, endPage);
8555
+ const pagesPdf = doclingDocument ? void 0 : await getPageRangePdf(startPage, endPage);
8556
+ const pagesText = doclingDocument ? await getPageRangeText(startPage, endPage) : "";
8217
8557
  const budget = resolveBudget("extraction_page_map", 2048);
8218
8558
  const startedAt = Date.now();
8219
8559
  const mapResponse = await safeGenerateObject(
8220
8560
  generateObject,
8221
8561
  {
8222
- prompt: buildPageMapPrompt(templateHints, startPage, endPage, formInventoryHint),
8562
+ prompt: withPageRangeTextContext(
8563
+ buildPageMapPrompt(templateHints, startPage, endPage, formInventoryHint),
8564
+ startPage,
8565
+ endPage,
8566
+ pagesText
8567
+ ),
8223
8568
  schema: PageMapChunkSchema,
8224
8569
  maxTokens: budget.maxTokens,
8225
8570
  taskKind: "extraction_page_map",
8226
8571
  budgetDiagnostics: budget,
8227
- providerOptions: { ...activeProviderOptions, pdfBase64: pagesPdf }
8572
+ providerOptions: doclingDocument ? { ...activeProviderOptions, doclingText: pagesText, doclingPageRange: { startPage, endPage } } : { ...activeProviderOptions, pdfBase64: pagesPdf }
8228
8573
  },
8229
8574
  {
8230
8575
  fallback: {
@@ -8302,7 +8647,7 @@ function createExtractor(config) {
8302
8647
  }))
8303
8648
  ];
8304
8649
  onProgress?.(`Dispatching ${tasks.length} extractors...`);
8305
- const extractionPdfInput = await getPdfBase64ForExtraction();
8650
+ const extractionPdfInput = doclingDocument ? void 0 : await getPdfBase64ForExtraction();
8306
8651
  const extractorResults = await Promise.all(
8307
8652
  tasks.map(
8308
8653
  (task) => extractorLimit(async () => {
@@ -8313,7 +8658,8 @@ function createExtractor(config) {
8313
8658
  memory,
8314
8659
  completedPageRangePdfCache,
8315
8660
  getPageRangePdf,
8316
- convertPdfToImages ? getPageImages : void 0
8661
+ convertPdfToImages ? getPageImages : void 0,
8662
+ doclingDocument ? getPageRangeText : void 0
8317
8663
  );
8318
8664
  })
8319
8665
  )
@@ -8345,7 +8691,8 @@ function createExtractor(config) {
8345
8691
  providerOptions: activeProviderOptions,
8346
8692
  pageRangeCache: completedPageRangePdfCache,
8347
8693
  getPageRangePdf,
8348
- getPageImages: convertPdfToImages ? getPageImages : void 0
8694
+ getPageImages: convertPdfToImages ? getPageImages : void 0,
8695
+ getPageRangeText: doclingDocument ? getPageRangeText : void 0
8349
8696
  });
8350
8697
  trackUsage(supplementaryResult.usage, {
8351
8698
  taskKind: "extraction_focused",
@@ -8381,6 +8728,7 @@ function createExtractor(config) {
8381
8728
  concurrency,
8382
8729
  getPageRangePdf,
8383
8730
  getPageImages: convertPdfToImages ? getPageImages : void 0,
8731
+ getPageRangeText: doclingDocument ? getPageRangeText : void 0,
8384
8732
  providerOptions: activeProviderOptions,
8385
8733
  modelCapabilities,
8386
8734
  modelBudgetConstraints,
@@ -8429,12 +8777,12 @@ function createExtractor(config) {
8429
8777
  const reviewResponse = await safeGenerateObject(
8430
8778
  generateObject,
8431
8779
  {
8432
- prompt: buildReviewPrompt(template.required, extractedKeys, extractionSummary, pageMapSummary, extractorCatalog),
8780
+ prompt: withFullDocumentTextContext(buildReviewPrompt(template.required, extractedKeys, extractionSummary, pageMapSummary, extractorCatalog)),
8433
8781
  schema: ReviewResultSchema,
8434
8782
  maxTokens: budget.maxTokens,
8435
8783
  taskKind: "extraction_review",
8436
8784
  budgetDiagnostics: budget,
8437
- providerOptions: await getFullPdfProviderOptions()
8785
+ providerOptions: await getFullDocumentProviderOptions()
8438
8786
  },
8439
8787
  {
8440
8788
  fallback: {
@@ -8464,7 +8812,7 @@ function createExtractor(config) {
8464
8812
  break;
8465
8813
  }
8466
8814
  onProgress?.(`Review round ${round + 1}: dispatching ${reviewResponse.object.additionalTasks.length} follow-up extractors...`);
8467
- const extractionPdfInput = await getPdfBase64ForExtraction();
8815
+ const extractionPdfInput = doclingDocument ? void 0 : await getPdfBase64ForExtraction();
8468
8816
  const followUpResults = await Promise.all(
8469
8817
  reviewResponse.object.additionalTasks.map(
8470
8818
  (task) => extractorLimit(async () => {
@@ -8474,7 +8822,8 @@ function createExtractor(config) {
8474
8822
  memory,
8475
8823
  completedPageRangePdfCache,
8476
8824
  getPageRangePdf,
8477
- convertPdfToImages ? getPageImages : void 0
8825
+ convertPdfToImages ? getPageImages : void 0,
8826
+ doclingDocument ? getPageRangeText : void 0
8478
8827
  );
8479
8828
  })
8480
8829
  )
@@ -12473,6 +12822,7 @@ export {
12473
12822
  buildConfirmationSummaryPrompt,
12474
12823
  buildConversationMemoryGuidance,
12475
12824
  buildCoverageGapPrompt,
12825
+ buildDoclingProviderOptions,
12476
12826
  buildFieldExplanationPrompt,
12477
12827
  buildFieldExtractionPrompt,
12478
12828
  buildFlatPdfMappingPrompt,
@@ -12514,12 +12864,16 @@ export {
12514
12864
  fillAcroForm,
12515
12865
  generateNextMessage,
12516
12866
  getAcroFormFields,
12867
+ getDoclingPageRangeText,
12517
12868
  getExtractor,
12518
12869
  getFileIdentifier,
12519
12870
  getPdfPageCount,
12520
12871
  getTemplate,
12872
+ isDoclingExtractionInput,
12521
12873
  isFileReference,
12522
12874
  mergeQuestionAnswers,
12875
+ mergeSourceSpans,
12876
+ normalizeDoclingDocument,
12523
12877
  normalizeForMatch,
12524
12878
  orderSourceEvidence,
12525
12879
  overlayTextOnPdf,