@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.js CHANGED
@@ -256,6 +256,7 @@ __export(index_exports, {
256
256
  buildConfirmationSummaryPrompt: () => buildConfirmationSummaryPrompt,
257
257
  buildConversationMemoryGuidance: () => buildConversationMemoryGuidance,
258
258
  buildCoverageGapPrompt: () => buildCoverageGapPrompt,
259
+ buildDoclingProviderOptions: () => buildDoclingProviderOptions,
259
260
  buildFieldExplanationPrompt: () => buildFieldExplanationPrompt,
260
261
  buildFieldExtractionPrompt: () => buildFieldExtractionPrompt,
261
262
  buildFlatPdfMappingPrompt: () => buildFlatPdfMappingPrompt,
@@ -297,12 +298,16 @@ __export(index_exports, {
297
298
  fillAcroForm: () => fillAcroForm,
298
299
  generateNextMessage: () => generateNextMessage,
299
300
  getAcroFormFields: () => getAcroFormFields,
301
+ getDoclingPageRangeText: () => getDoclingPageRangeText,
300
302
  getExtractor: () => getExtractor,
301
303
  getFileIdentifier: () => getFileIdentifier,
302
304
  getPdfPageCount: () => getPdfPageCount,
303
305
  getTemplate: () => getTemplate,
306
+ isDoclingExtractionInput: () => isDoclingExtractionInput,
304
307
  isFileReference: () => isFileReference,
305
308
  mergeQuestionAnswers: () => mergeQuestionAnswers,
309
+ mergeSourceSpans: () => mergeSourceSpans,
310
+ normalizeDoclingDocument: () => normalizeDoclingDocument,
306
311
  normalizeForMatch: () => normalizeForMatch,
307
312
  orderSourceEvidence: () => orderSourceEvidence,
308
313
  overlayTextOnPdf: () => overlayTextOnPdf,
@@ -1004,7 +1009,8 @@ var EndorsementSchema = import_zod5.z.object({
1004
1009
  namedParties: import_zod5.z.array(EndorsementPartySchema).optional(),
1005
1010
  keyTerms: import_zod5.z.array(import_zod5.z.string()).optional(),
1006
1011
  premiumImpact: import_zod5.z.string().optional(),
1007
- content: import_zod5.z.string(),
1012
+ excerpt: import_zod5.z.string().optional(),
1013
+ content: import_zod5.z.string().optional(),
1008
1014
  pageStart: import_zod5.z.number(),
1009
1015
  pageEnd: import_zod5.z.number().optional(),
1010
1016
  recordId: import_zod5.z.string().optional(),
@@ -1617,7 +1623,10 @@ var SubsectionSchema = import_zod16.z.object({
1617
1623
  title: import_zod16.z.string(),
1618
1624
  sectionNumber: import_zod16.z.string().optional(),
1619
1625
  pageNumber: import_zod16.z.number().optional(),
1620
- content: import_zod16.z.string()
1626
+ excerpt: import_zod16.z.string().optional(),
1627
+ content: import_zod16.z.string().optional(),
1628
+ sourceSpanIds: import_zod16.z.array(import_zod16.z.string()).optional(),
1629
+ sourceTextHash: import_zod16.z.string().optional()
1621
1630
  });
1622
1631
  var SectionSchema = import_zod16.z.object({
1623
1632
  title: import_zod16.z.string(),
@@ -1626,7 +1635,8 @@ var SectionSchema = import_zod16.z.object({
1626
1635
  pageEnd: import_zod16.z.number().optional(),
1627
1636
  type: import_zod16.z.string(),
1628
1637
  coverageType: import_zod16.z.string().optional(),
1629
- content: import_zod16.z.string(),
1638
+ excerpt: import_zod16.z.string().optional(),
1639
+ content: import_zod16.z.string().optional(),
1630
1640
  subsections: import_zod16.z.array(SubsectionSchema).optional(),
1631
1641
  recordId: import_zod16.z.string().optional(),
1632
1642
  sourceSpanIds: import_zod16.z.array(import_zod16.z.string()).optional(),
@@ -2794,6 +2804,254 @@ async function overlayTextOnPdf(pdfBytes, overlays) {
2794
2804
  return await pdfDoc.save();
2795
2805
  }
2796
2806
 
2807
+ // src/extraction/docling.ts
2808
+ function isDoclingExtractionInput(input) {
2809
+ return Boolean(
2810
+ input && typeof input === "object" && input.kind === "docling_document" && input.document && typeof input.document === "object"
2811
+ );
2812
+ }
2813
+ function normalizeDoclingDocument(document, options) {
2814
+ const itemMap = buildItemMap(document);
2815
+ const orderedRefs = getOrderedBodyRefs(document, itemMap);
2816
+ const orderedItems = orderedRefs.length > 0 ? orderedRefs.map((ref) => itemMap.get(ref)).filter((item) => Boolean(item)) : getFallbackOrderedItems(document, itemMap);
2817
+ const units = orderedItems.map(({ ref, item }) => normalizeItem(ref, item)).filter((unit) => Boolean(unit && unit.text.trim()));
2818
+ const pageCount = inferPageCount(document, units);
2819
+ const pageTexts = /* @__PURE__ */ new Map();
2820
+ for (const unit of units) {
2821
+ const page = clampPage(unit.pageStart ?? 1, pageCount);
2822
+ pageTexts.set(page, appendText(pageTexts.get(page), unit.text));
2823
+ }
2824
+ const fullText = Array.from({ length: pageCount }, (_, index) => {
2825
+ const pageNumber = index + 1;
2826
+ const text = pageTexts.get(pageNumber)?.trim();
2827
+ return text ? `Page ${pageNumber}
2828
+ ${text}` : "";
2829
+ }).filter(Boolean).join("\n\n");
2830
+ const sourceKind = options.sourceKind ?? "policy_pdf";
2831
+ const sourceSpans = units.map((unit, index) => {
2832
+ const span = buildSourceSpan(
2833
+ {
2834
+ documentId: options.documentId,
2835
+ sourceKind,
2836
+ text: unit.text,
2837
+ pageStart: unit.pageStart,
2838
+ pageEnd: unit.pageEnd,
2839
+ sectionId: unit.label,
2840
+ metadata: {
2841
+ sourceSystem: "docling",
2842
+ sourceUnit: "docling_item",
2843
+ doclingRef: unit.ref,
2844
+ ...unit.label ? { doclingLabel: unit.label } : {}
2845
+ }
2846
+ },
2847
+ index
2848
+ );
2849
+ return {
2850
+ ...span,
2851
+ kind: "plain_text",
2852
+ bbox: unit.bboxes?.length ? unit.bboxes : void 0
2853
+ };
2854
+ });
2855
+ return {
2856
+ pageCount,
2857
+ fullText,
2858
+ pageTexts,
2859
+ units,
2860
+ sourceSpans
2861
+ };
2862
+ }
2863
+ function getDoclingPageRangeText(normalized, startPage, endPage) {
2864
+ const start = clampPage(startPage, normalized.pageCount);
2865
+ const end = clampPage(endPage, normalized.pageCount);
2866
+ const lines = [];
2867
+ for (let page = start; page <= end; page++) {
2868
+ const text = normalized.pageTexts.get(page)?.trim();
2869
+ if (text) {
2870
+ lines.push(`Page ${page}
2871
+ ${text}`);
2872
+ }
2873
+ }
2874
+ return lines.join("\n\n");
2875
+ }
2876
+ function buildDoclingProviderOptions(normalized, existingOptions) {
2877
+ return {
2878
+ ...existingOptions,
2879
+ doclingText: normalized.fullText,
2880
+ doclingPageCount: normalized.pageCount
2881
+ };
2882
+ }
2883
+ function mergeSourceSpans(spans) {
2884
+ const seen = /* @__PURE__ */ new Set();
2885
+ const merged = [];
2886
+ for (const span of spans) {
2887
+ const key = [
2888
+ span.documentId,
2889
+ span.pageStart ?? span.location?.startPage ?? span.location?.page ?? "na",
2890
+ span.pageEnd ?? span.location?.endPage ?? span.pageStart ?? "na",
2891
+ span.sectionId ?? span.location?.fieldPath ?? "na",
2892
+ span.textHash ?? sourceSpanTextHash(span.text)
2893
+ ].join(":");
2894
+ if (seen.has(key)) continue;
2895
+ seen.add(key);
2896
+ merged.push(span);
2897
+ }
2898
+ return merged;
2899
+ }
2900
+ function buildItemMap(document) {
2901
+ const map = /* @__PURE__ */ new Map();
2902
+ addItems(map, "#/texts", document.texts ?? []);
2903
+ addItems(map, "#/tables", document.tables ?? []);
2904
+ addItems(map, "#/key_value_items", document.key_value_items ?? document.keyValueItems ?? []);
2905
+ addItems(map, "#/pictures", document.pictures ?? []);
2906
+ return map;
2907
+ }
2908
+ function addItems(map, baseRef, items) {
2909
+ items.forEach((item, index) => {
2910
+ const ref = getSelfRef(item) ?? `${baseRef}/${index}`;
2911
+ map.set(ref, { ref, item });
2912
+ });
2913
+ }
2914
+ function getFallbackOrderedItems(document, itemMap) {
2915
+ const refs = [
2916
+ ...(document.texts ?? []).map((item, index) => getSelfRef(item) ?? `#/texts/${index}`),
2917
+ ...(document.tables ?? []).map((item, index) => getSelfRef(item) ?? `#/tables/${index}`),
2918
+ ...(document.key_value_items ?? document.keyValueItems ?? []).map((item, index) => getSelfRef(item) ?? `#/key_value_items/${index}`)
2919
+ ];
2920
+ return refs.map((ref) => itemMap.get(ref)).filter((item) => Boolean(item));
2921
+ }
2922
+ function getOrderedBodyRefs(document, itemMap) {
2923
+ const groupMap = /* @__PURE__ */ new Map();
2924
+ (document.groups ?? []).forEach((group, index) => {
2925
+ groupMap.set(getSelfRef(group) ?? `#/groups/${index}`, group);
2926
+ });
2927
+ const refs = [];
2928
+ const visited = /* @__PURE__ */ new Set();
2929
+ const visitRef = (ref) => {
2930
+ const itemEntry = itemMap.get(ref);
2931
+ if (itemEntry) {
2932
+ if (!visited.has(ref)) {
2933
+ visited.add(ref);
2934
+ refs.push(ref);
2935
+ }
2936
+ visitNode(itemEntry.item);
2937
+ return;
2938
+ }
2939
+ visitNode(groupMap.get(ref));
2940
+ };
2941
+ const visitNode = (node) => {
2942
+ for (const child of node?.children ?? []) {
2943
+ const ref = getRef(child);
2944
+ if (!ref) continue;
2945
+ visitRef(ref);
2946
+ }
2947
+ };
2948
+ visitNode(document.body);
2949
+ return refs;
2950
+ }
2951
+ function normalizeItem(ref, item) {
2952
+ const text = getItemText(item).trim();
2953
+ if (!text) return void 0;
2954
+ const pages = (item.prov ?? []).map((prov) => getPageNumber(prov)).filter((page) => typeof page === "number" && page > 0);
2955
+ const pageStart = pages.length ? Math.min(...pages) : void 0;
2956
+ const pageEnd = pages.length ? Math.max(...pages) : pageStart;
2957
+ const bboxes = (item.prov ?? []).map((prov) => toSourceSpanBBox(prov)).filter((bbox) => Boolean(bbox));
2958
+ return {
2959
+ ref,
2960
+ label: typeof item.label === "string" ? item.label : void 0,
2961
+ text,
2962
+ pageStart,
2963
+ pageEnd,
2964
+ bboxes: bboxes.length ? bboxes : void 0
2965
+ };
2966
+ }
2967
+ function getItemText(item) {
2968
+ if (typeof item.text === "string" && item.text.trim()) return item.text;
2969
+ if (typeof item.orig === "string" && item.orig.trim()) return item.orig;
2970
+ const table = tableToMarkdown(item.data);
2971
+ if (table) return table;
2972
+ return "";
2973
+ }
2974
+ function tableToMarkdown(data) {
2975
+ const record = asRecord(data);
2976
+ const cells = Array.isArray(record?.table_cells) ? record.table_cells : Array.isArray(record?.tableCells) ? record.tableCells : void 0;
2977
+ if (!cells) return void 0;
2978
+ const parsedCells = cells.map((cell) => asRecord(cell)).filter((cell) => Boolean(cell)).map((cell) => ({
2979
+ row: firstNumber2([cell.start_row_offset, cell.row_header, cell.row, cell.rowIndex]) ?? 0,
2980
+ col: firstNumber2([cell.start_col_offset, cell.col, cell.colIndex]) ?? 0,
2981
+ text: firstString([cell.text, cell.orig, cell.content])
2982
+ })).filter((cell) => cell.text);
2983
+ if (parsedCells.length === 0) return void 0;
2984
+ const maxRow = Math.max(...parsedCells.map((cell) => cell.row));
2985
+ const maxCol = Math.max(...parsedCells.map((cell) => cell.col));
2986
+ const rows = Array.from({ length: maxRow + 1 }, () => Array.from({ length: maxCol + 1 }, () => ""));
2987
+ for (const cell of parsedCells) {
2988
+ rows[cell.row][cell.col] = cell.text;
2989
+ }
2990
+ if (rows.length === 1) return rows[0].filter(Boolean).join(" | ");
2991
+ const header = rows[0];
2992
+ const separator = header.map(() => "---");
2993
+ return [header, separator, ...rows.slice(1)].map((row) => `| ${row.map((value) => value.trim()).join(" | ")} |`).join("\n");
2994
+ }
2995
+ function inferPageCount(document, units) {
2996
+ const pages = document.pages;
2997
+ if (Array.isArray(pages)) return Math.max(1, pages.length);
2998
+ if (pages && typeof pages === "object") {
2999
+ const keys = Object.keys(pages);
3000
+ const numericMax = Math.max(0, ...keys.map((key) => Number(key)).filter((value) => Number.isFinite(value)));
3001
+ return Math.max(1, numericMax || keys.length);
3002
+ }
3003
+ return Math.max(1, ...units.flatMap((unit) => [unit.pageStart ?? 0, unit.pageEnd ?? 0]));
3004
+ }
3005
+ function getSelfRef(value) {
3006
+ return value.self_ref ?? value.selfRef;
3007
+ }
3008
+ function getRef(value) {
3009
+ if (typeof value === "string") return value;
3010
+ return value.$ref ?? value.ref;
3011
+ }
3012
+ function getPageNumber(prov) {
3013
+ return prov.page_no ?? prov.pageNo ?? prov.page;
3014
+ }
3015
+ function toSourceSpanBBox(prov) {
3016
+ const page = getPageNumber(prov);
3017
+ const bbox = asRecord(prov.bbox);
3018
+ if (!page || !bbox) return void 0;
3019
+ const x = firstNumber2([bbox.x, bbox.l, bbox.left]);
3020
+ const y = firstNumber2([bbox.y, bbox.t, bbox.top]);
3021
+ const width = firstNumber2([bbox.width]);
3022
+ const height = firstNumber2([bbox.height]);
3023
+ const right = firstNumber2([bbox.r, bbox.right]);
3024
+ const bottom = firstNumber2([bbox.b, bbox.bottom]);
3025
+ if (x == null || y == null) return void 0;
3026
+ const resolvedWidth = width ?? (right != null ? right - x : void 0);
3027
+ const resolvedHeight = height ?? (bottom != null ? bottom - y : void 0);
3028
+ if (resolvedWidth == null || resolvedHeight == null) return void 0;
3029
+ return { page, x, y, width: resolvedWidth, height: resolvedHeight };
3030
+ }
3031
+ function clampPage(page, pageCount) {
3032
+ return Math.max(1, Math.min(pageCount, page));
3033
+ }
3034
+ function appendText(existing, next) {
3035
+ return existing ? `${existing}
3036
+
3037
+ ${next}` : next;
3038
+ }
3039
+ function asRecord(value) {
3040
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3041
+ }
3042
+ function firstString(values) {
3043
+ for (const value of values) {
3044
+ if (typeof value === "string" && value.trim()) return value.trim();
3045
+ }
3046
+ return "";
3047
+ }
3048
+ function firstNumber2(values) {
3049
+ for (const value of values) {
3050
+ if (typeof value === "number" && Number.isFinite(value)) return value;
3051
+ }
3052
+ return void 0;
3053
+ }
3054
+
2797
3055
  // src/extraction/extractor.ts
2798
3056
  function sourceSpansForPageRange(providerOptions, startPage, endPage) {
2799
3057
  const sourceSpans = providerOptions?.sourceSpans;
@@ -2842,15 +3100,31 @@ async function runExtractor(params) {
2842
3100
  } = params;
2843
3101
  const extractorProviderOptions = { ...providerOptions };
2844
3102
  let fullPrompt;
2845
- const needsPdfBase64 = convertPdfToImages && !params.getPageImages || !convertPdfToImages && !params.getPageRangePdf;
2846
- const pdfBase64 = needsPdfBase64 ? await pdfInputToBase64(pdfInput) : void 0;
2847
- if (convertPdfToImages) {
3103
+ if (params.getPageRangeText) {
3104
+ const pageText = await params.getPageRangeText(startPage, endPage);
3105
+ extractorProviderOptions.doclingText = pageText;
3106
+ extractorProviderOptions.doclingPageRange = { startPage, endPage };
3107
+ fullPrompt = `${prompt}
3108
+
3109
+ [Document pages ${startPage}-${endPage} are provided below as Docling-extracted text.]
3110
+
3111
+ ${pageText || "(No Docling text was available for this page range.)"}`;
3112
+ } else if (convertPdfToImages) {
3113
+ if (!pdfInput) {
3114
+ throw new Error("pdfInput is required when extracting page images.");
3115
+ }
3116
+ const needsPdfBase64 = !params.getPageImages;
3117
+ const pdfBase64 = needsPdfBase64 ? await pdfInputToBase64(pdfInput) : void 0;
2848
3118
  const images = params.getPageImages ? await params.getPageImages(startPage, endPage) : await convertPdfToImages(pdfBase64, startPage, endPage);
2849
3119
  extractorProviderOptions.images = images;
2850
3120
  fullPrompt = `${prompt}
2851
3121
 
2852
3122
  [Document pages ${startPage}-${endPage} are provided as images.]`;
2853
3123
  } else {
3124
+ if (!pdfInput) {
3125
+ throw new Error("pdfInput is required when extracting page PDFs.");
3126
+ }
3127
+ const pdfBase64 = params.getPageRangePdf ? void 0 : await pdfInputToBase64(pdfInput);
2854
3128
  const cacheKey = `${startPage}-${endPage}`;
2855
3129
  const cachedPagesPdf = pageRangeCache?.get(cacheKey);
2856
3130
  const pagesPdf = cachedPagesPdf ?? (params.getPageRangePdf ? await params.getPageRangePdf(startPage, endPage) : await extractPageRange(pdfBase64, startPage, endPage));
@@ -2872,6 +3146,14 @@ async function runExtractor(params) {
2872
3146
  maxTokens,
2873
3147
  taskKind,
2874
3148
  budgetDiagnostics,
3149
+ trace: {
3150
+ label: `${name} pages ${startPage}-${endPage}`,
3151
+ extractorName: name,
3152
+ startPage,
3153
+ endPage,
3154
+ phase: "extractor",
3155
+ sourceBacked: !!sourceContext
3156
+ },
2875
3157
  providerOptions: extractorProviderOptions
2876
3158
  })
2877
3159
  );
@@ -3737,21 +4019,30 @@ function collectContentFields(doc) {
3737
4019
  entries.push({ id: id++, path, text });
3738
4020
  }
3739
4021
  }
4022
+ function hasSourceBacking(record) {
4023
+ return Array.isArray(record.sourceSpanIds) && record.sourceSpanIds.length > 0 || !!record.sourceTextHash;
4024
+ }
3740
4025
  add("summary", doc.summary);
3741
4026
  if (doc.sections) {
3742
4027
  for (let i = 0; i < doc.sections.length; i++) {
3743
4028
  const s = doc.sections[i];
3744
- add(`sections[${i}].content`, s.content);
4029
+ if (!hasSourceBacking(s)) {
4030
+ add(`sections[${i}].content`, s.content);
4031
+ }
3745
4032
  if (s.subsections) {
3746
4033
  for (let j = 0; j < s.subsections.length; j++) {
3747
- add(`sections[${i}].subsections[${j}].content`, s.subsections[j].content);
4034
+ if (!hasSourceBacking(s.subsections[j])) {
4035
+ add(`sections[${i}].subsections[${j}].content`, s.subsections[j].content);
4036
+ }
3748
4037
  }
3749
4038
  }
3750
4039
  }
3751
4040
  }
3752
4041
  if (doc.endorsements) {
3753
4042
  for (let i = 0; i < doc.endorsements.length; i++) {
3754
- add(`endorsements[${i}].content`, doc.endorsements[i].content);
4043
+ if (!hasSourceBacking(doc.endorsements[i])) {
4044
+ add(`endorsements[${i}].content`, doc.endorsements[i].content);
4045
+ }
3755
4046
  }
3756
4047
  }
3757
4048
  if (doc.exclusions) {
@@ -3853,6 +4144,12 @@ async function formatDocumentContent(doc, generateText, options) {
3853
4144
  maxTokens: options?.maxTokens ?? 16384,
3854
4145
  taskKind: options?.taskKind,
3855
4146
  budgetDiagnostics: options?.budgetDiagnostics,
4147
+ trace: {
4148
+ label: `format content batch ${batchIdx + 1}/${batches.length}`,
4149
+ phase: "format",
4150
+ batchIndex: batchIdx + 1,
4151
+ batchCount: batches.length
4152
+ },
3856
4153
  providerOptions: options?.providerOptions
3857
4154
  })
3858
4155
  );
@@ -3890,7 +4187,7 @@ function formatAddress(addr) {
3890
4187
  function asRecordArray(value) {
3891
4188
  return Array.isArray(value) ? value.filter((item) => Boolean(item) && typeof item === "object" && !Array.isArray(item)) : [];
3892
4189
  }
3893
- function firstString(item, keys) {
4190
+ function firstString2(item, keys) {
3894
4191
  for (const key of keys) {
3895
4192
  const value = item[key];
3896
4193
  if (typeof value === "string" && value.trim()) return value;
@@ -3927,7 +4224,7 @@ function chunkDocument(doc) {
3927
4224
  documentId: docId,
3928
4225
  type,
3929
4226
  text,
3930
- metadata: stringMetadata(metadata)
4227
+ metadata: stringMetadata({ evidenceKind: "structured_fact", ...metadata })
3931
4228
  });
3932
4229
  }
3933
4230
  pushChunk(
@@ -4206,16 +4503,29 @@ function chunkDocument(doc) {
4206
4503
  );
4207
4504
  });
4208
4505
  doc.endorsements?.forEach((end, i) => {
4506
+ const text = lines([
4507
+ `Endorsement: ${end.title}`,
4508
+ end.formNumber ? `Form: ${end.formNumber}` : null,
4509
+ end.editionDate ? `Edition: ${end.editionDate}` : null,
4510
+ `Type: ${end.endorsementType}`,
4511
+ end.effectiveDate ? `Effective Date: ${end.effectiveDate}` : null,
4512
+ end.affectedCoverageParts?.length ? `Affected Coverage Parts: ${end.affectedCoverageParts.join(", ")}` : null,
4513
+ end.keyTerms?.length ? `Key Terms: ${end.keyTerms.join("; ")}` : null,
4514
+ end.premiumImpact ? `Premium Impact: ${end.premiumImpact}` : null,
4515
+ end.excerpt ? `Excerpt: ${end.excerpt}` : null
4516
+ ]);
4517
+ if (!text.trim()) return;
4209
4518
  pushChunk(
4210
4519
  `endorsement:${i}`,
4211
4520
  "endorsement",
4212
- `Endorsement: ${end.title}
4213
- ${end.content}`.trim(),
4521
+ text,
4214
4522
  {
4215
4523
  endorsementType: end.endorsementType,
4216
4524
  formNumber: end.formNumber,
4217
4525
  pageStart: end.pageStart,
4218
4526
  pageEnd: end.pageEnd,
4527
+ sourceSpanIds: end.sourceSpanIds?.join(","),
4528
+ sourceTextHash: end.sourceTextHash,
4219
4529
  documentType: doc.type
4220
4530
  }
4221
4531
  );
@@ -4247,32 +4557,32 @@ ${exc.content}`.trim(), {
4247
4557
  );
4248
4558
  });
4249
4559
  asRecordArray(extendedDoc.definitions).forEach((definition, i) => {
4250
- const term = firstString(definition, ["term", "name", "title"]) ?? `Definition ${i + 1}`;
4251
- const body = firstString(definition, ["definition", "content", "text", "meaning"]);
4560
+ const term = firstString2(definition, ["term", "name", "title"]) ?? `Definition ${i + 1}`;
4561
+ const body = firstString2(definition, ["definition", "content", "text", "meaning"]);
4252
4562
  pushChunk(
4253
4563
  `definition:${i}`,
4254
4564
  "definition",
4255
4565
  lines([
4256
4566
  `Definition: ${term}`,
4257
4567
  body,
4258
- firstString(definition, ["originalContent", "source"]) ? `Source: ${firstString(definition, ["originalContent", "source"])}` : null
4568
+ firstString2(definition, ["originalContent", "source"]) ? `Source: ${firstString2(definition, ["originalContent", "source"])}` : null
4259
4569
  ]),
4260
4570
  {
4261
4571
  term,
4262
- formNumber: firstString(definition, ["formNumber"]),
4263
- formTitle: firstString(definition, ["formTitle"]),
4572
+ formNumber: firstString2(definition, ["formNumber"]),
4573
+ formTitle: firstString2(definition, ["formTitle"]),
4264
4574
  pageNumber: typeof definition.pageNumber === "number" ? definition.pageNumber : void 0,
4265
- sectionRef: firstString(definition, ["sectionRef", "sectionTitle"]),
4575
+ sectionRef: firstString2(definition, ["sectionRef", "sectionTitle"]),
4266
4576
  documentType: doc.type
4267
4577
  }
4268
4578
  );
4269
4579
  });
4270
4580
  const coveredReasons = asRecordArray(extendedDoc.coveredReasons ?? extendedDoc.covered_reasons);
4271
4581
  coveredReasons.forEach((coveredReason, i) => {
4272
- const title = firstString(coveredReason, ["title", "name", "reason", "peril", "cause"]) ?? `Covered Reason ${i + 1}`;
4273
- const coverageName = firstString(coveredReason, ["coverageName", "coverage", "coveragePart"]);
4274
- const reasonNumber = firstString(coveredReason, ["reasonNumber", "number"]);
4275
- const body = firstString(coveredReason, ["content", "description", "text", "coverageGrant"]);
4582
+ const title = firstString2(coveredReason, ["title", "name", "reason", "peril", "cause"]) ?? `Covered Reason ${i + 1}`;
4583
+ const coverageName = firstString2(coveredReason, ["coverageName", "coverage", "coveragePart"]);
4584
+ const reasonNumber = firstString2(coveredReason, ["reasonNumber", "number"]);
4585
+ const body = firstString2(coveredReason, ["content", "description", "text", "coverageGrant"]);
4276
4586
  pushChunk(
4277
4587
  `covered_reason:${i}`,
4278
4588
  "covered_reason",
@@ -4281,16 +4591,16 @@ ${exc.content}`.trim(), {
4281
4591
  reasonNumber ? `Reason Number: ${reasonNumber}` : null,
4282
4592
  `Covered Reason: ${title}`,
4283
4593
  body,
4284
- firstString(coveredReason, ["originalContent", "source"]) ? `Source: ${firstString(coveredReason, ["originalContent", "source"])}` : null
4594
+ firstString2(coveredReason, ["originalContent", "source"]) ? `Source: ${firstString2(coveredReason, ["originalContent", "source"])}` : null
4285
4595
  ]),
4286
4596
  {
4287
4597
  coverageName,
4288
4598
  reasonNumber,
4289
4599
  title,
4290
- formNumber: firstString(coveredReason, ["formNumber"]),
4291
- formTitle: firstString(coveredReason, ["formTitle"]),
4600
+ formNumber: firstString2(coveredReason, ["formNumber"]),
4601
+ formTitle: firstString2(coveredReason, ["formTitle"]),
4292
4602
  pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
4293
- sectionRef: firstString(coveredReason, ["sectionRef", "sectionTitle"]),
4603
+ sectionRef: firstString2(coveredReason, ["sectionRef", "sectionTitle"]),
4294
4604
  documentType: doc.type
4295
4605
  }
4296
4606
  );
@@ -4310,10 +4620,10 @@ ${exc.content}`.trim(), {
4310
4620
  reasonNumber,
4311
4621
  title,
4312
4622
  conditionIndex,
4313
- formNumber: firstString(coveredReason, ["formNumber"]),
4314
- formTitle: firstString(coveredReason, ["formTitle"]),
4623
+ formNumber: firstString2(coveredReason, ["formNumber"]),
4624
+ formTitle: firstString2(coveredReason, ["formTitle"]),
4315
4625
  pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
4316
- sectionRef: firstString(coveredReason, ["sectionRef", "sectionTitle"]),
4626
+ sectionRef: firstString2(coveredReason, ["sectionRef", "sectionTitle"]),
4317
4627
  documentType: doc.type
4318
4628
  }
4319
4629
  );
@@ -4337,93 +4647,51 @@ ${declLines.join("\n")}`, declMeta);
4337
4647
  }
4338
4648
  doc.sections?.forEach((sec, i) => {
4339
4649
  const hasSubsections = sec.subsections && sec.subsections.length > 0;
4340
- const contentLength = sec.content.length;
4341
- if (hasSubsections) {
4342
- pushChunk(
4343
- `section:${i}`,
4344
- "section",
4345
- `Section: ${sec.title}
4346
- ${sec.content}`,
4347
- {
4348
- sectionType: sec.type,
4349
- sectionNumber: sec.sectionNumber,
4350
- pageStart: sec.pageStart,
4351
- pageEnd: sec.pageEnd,
4352
- documentType: doc.type,
4353
- hasSubsections: "true"
4354
- }
4355
- );
4356
- sec.subsections.forEach((sub, j) => {
4357
- pushChunk(
4358
- `section:${i}:sub:${j}`,
4359
- "section",
4360
- `${sec.title} > ${sub.title}
4361
- ${sub.content}`,
4362
- {
4363
- sectionType: sec.type,
4364
- parentSection: sec.title,
4365
- sectionNumber: sub.sectionNumber,
4366
- pageNumber: sub.pageNumber,
4367
- documentType: doc.type
4368
- }
4369
- );
4370
- });
4371
- } else if (contentLength > 2e3) {
4372
- const paragraphs = sec.content.split(/\n\n+/);
4373
- let currentChunk = "";
4374
- let chunkIndex = 0;
4375
- for (const para of paragraphs) {
4376
- if (currentChunk.length + para.length > 1e3 && currentChunk.length > 0) {
4377
- pushChunk(
4378
- `section:${i}:part:${chunkIndex}`,
4379
- "section",
4380
- `Section: ${sec.title} (part ${chunkIndex + 1})
4381
- ${currentChunk.trim()}`,
4382
- {
4383
- sectionType: sec.type,
4384
- sectionNumber: sec.sectionNumber,
4385
- pageStart: sec.pageStart,
4386
- pageEnd: sec.pageEnd,
4387
- documentType: doc.type,
4388
- partIndex: chunkIndex
4389
- }
4390
- );
4391
- currentChunk = "";
4392
- chunkIndex++;
4393
- }
4394
- currentChunk += (currentChunk ? "\n\n" : "") + para;
4395
- }
4396
- if (currentChunk.trim()) {
4397
- pushChunk(
4398
- `section:${i}:part:${chunkIndex}`,
4399
- "section",
4400
- `Section: ${sec.title} (part ${chunkIndex + 1})
4401
- ${currentChunk.trim()}`,
4402
- {
4403
- sectionType: sec.type,
4404
- sectionNumber: sec.sectionNumber,
4405
- pageStart: sec.pageStart,
4406
- pageEnd: sec.pageEnd,
4407
- documentType: doc.type,
4408
- partIndex: chunkIndex
4409
- }
4410
- );
4650
+ pushChunk(
4651
+ `section:${i}`,
4652
+ "section",
4653
+ lines([
4654
+ `Section: ${sec.title}`,
4655
+ `Type: ${sec.type}`,
4656
+ sec.sectionNumber ? `Section Number: ${sec.sectionNumber}` : null,
4657
+ `Pages: ${sec.pageStart}${sec.pageEnd ? `-${sec.pageEnd}` : ""}`,
4658
+ sec.excerpt ? `Excerpt: ${sec.excerpt}` : null,
4659
+ hasSubsections ? `Subsections: ${sec.subsections.map((sub) => sub.title).join(", ")}` : null
4660
+ ]),
4661
+ {
4662
+ evidenceKind: "navigation",
4663
+ sectionType: sec.type,
4664
+ sectionNumber: sec.sectionNumber,
4665
+ pageStart: sec.pageStart,
4666
+ pageEnd: sec.pageEnd,
4667
+ sourceSpanIds: sec.sourceSpanIds?.join(","),
4668
+ sourceTextHash: sec.sourceTextHash,
4669
+ documentType: doc.type,
4670
+ hasSubsections
4411
4671
  }
4412
- } else {
4672
+ );
4673
+ sec.subsections?.forEach((sub, j) => {
4413
4674
  pushChunk(
4414
- `section:${i}`,
4675
+ `section:${i}:sub:${j}`,
4415
4676
  "section",
4416
- `Section: ${sec.title}
4417
- ${sec.content}`,
4677
+ lines([
4678
+ `Section: ${sec.title} > ${sub.title}`,
4679
+ sub.sectionNumber ? `Section Number: ${sub.sectionNumber}` : null,
4680
+ sub.pageNumber ? `Page: ${sub.pageNumber}` : null,
4681
+ sub.excerpt ? `Excerpt: ${sub.excerpt}` : null
4682
+ ]),
4418
4683
  {
4684
+ evidenceKind: "navigation",
4419
4685
  sectionType: sec.type,
4420
- sectionNumber: sec.sectionNumber,
4421
- pageStart: sec.pageStart,
4422
- pageEnd: sec.pageEnd,
4686
+ parentSection: sec.title,
4687
+ sectionNumber: sub.sectionNumber,
4688
+ pageNumber: sub.pageNumber,
4689
+ sourceSpanIds: sub.sourceSpanIds?.join(","),
4690
+ sourceTextHash: sub.sourceTextHash,
4423
4691
  documentType: doc.type
4424
4692
  }
4425
4693
  );
4426
- }
4694
+ });
4427
4695
  });
4428
4696
  doc.locations?.forEach((loc, i) => {
4429
4697
  chunks.push({
@@ -6295,14 +6563,17 @@ var EndorsementsSchema = import_zod29.z.object({
6295
6563
  ).optional().describe("Named parties (additional insureds, loss payees, etc.)"),
6296
6564
  keyTerms: import_zod29.z.array(import_zod29.z.string()).optional().describe("Key terms or notable provisions in the endorsement"),
6297
6565
  premiumImpact: import_zod29.z.string().optional().describe("Additional premium or credit"),
6298
- content: import_zod29.z.string().describe("Full verbatim text of the endorsement"),
6566
+ excerpt: import_zod29.z.string().optional().describe("Short source excerpt, not full verbatim text"),
6567
+ content: import_zod29.z.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6299
6568
  pageStart: import_zod29.z.number().describe("Starting page number of this endorsement"),
6300
- pageEnd: import_zod29.z.number().optional().describe("Ending page number of this endorsement")
6569
+ pageEnd: import_zod29.z.number().optional().describe("Ending page number of this endorsement"),
6570
+ sourceSpanIds: import_zod29.z.array(import_zod29.z.string()).optional().describe("Source span IDs grounding this endorsement"),
6571
+ sourceTextHash: import_zod29.z.string().optional().describe("Hash of the source text when available")
6301
6572
  })
6302
6573
  ).describe("All endorsements found in the document")
6303
6574
  });
6304
6575
  function buildEndorsementsPrompt() {
6305
- return `You are an expert insurance document analyst. Extract ALL endorsements from this document. Preserve original language verbatim.
6576
+ 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.
6306
6577
 
6307
6578
  For EACH endorsement, extract:
6308
6579
  - formNumber: the form identifier (e.g. "CG 21 47") \u2014 REQUIRED
@@ -6314,7 +6585,9 @@ For EACH endorsement, extract:
6314
6585
  - namedParties: for each party, extract name, role (additional_insured, loss_payee, mortgage_holder, certificate_holder, waiver_beneficiary, designated_person, other), relationship, and scope
6315
6586
  - keyTerms: notable provisions or key terms
6316
6587
  - premiumImpact: additional premium or credit if shown
6317
- - content: full verbatim text \u2014 REQUIRED
6588
+ - excerpt: short identifying source excerpt, capped at 300 characters
6589
+ - sourceSpanIds: source span IDs from the provided SOURCE SPANS that ground this endorsement
6590
+ - content: legacy fallback only; omit/null when sourceSpanIds are available
6318
6591
  - pageStart: page number where endorsement begins \u2014 REQUIRED
6319
6592
  - pageEnd: page number where endorsement ends
6320
6593
 
@@ -6324,6 +6597,11 @@ PERSONAL LINES ENDORSEMENT RECOGNITION:
6324
6597
  - HO 17 XX series: mobilehome endorsements
6325
6598
  - DP 04 XX series: dwelling fire endorsements
6326
6599
 
6600
+ Critical rules:
6601
+ - Return compact metadata plus source references. The original endorsement wording lives in source spans.
6602
+ - Do not return full endorsement text in content when sourceSpanIds are available.
6603
+ - Prefer sourceSpanIds over generated prose for evidence.
6604
+
6327
6605
  Return JSON only.`;
6328
6606
  }
6329
6607
 
@@ -6570,7 +6848,10 @@ var SubsectionSchema2 = import_zod35.z.object({
6570
6848
  title: import_zod35.z.string().describe("Subsection title"),
6571
6849
  sectionNumber: import_zod35.z.string().optional().describe("Subsection number"),
6572
6850
  pageNumber: import_zod35.z.number().optional().describe("Page number"),
6573
- content: import_zod35.z.string().describe("Full verbatim text")
6851
+ excerpt: import_zod35.z.string().optional().describe("Short source excerpt, not full verbatim text"),
6852
+ content: import_zod35.z.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6853
+ sourceSpanIds: import_zod35.z.array(import_zod35.z.string()).optional().describe("Source span IDs grounding this subsection"),
6854
+ sourceTextHash: import_zod35.z.string().optional().describe("Hash of the source text when available")
6574
6855
  });
6575
6856
  var SectionsSchema = import_zod35.z.object({
6576
6857
  sections: import_zod35.z.array(
@@ -6591,15 +6872,18 @@ var SectionsSchema = import_zod35.z.object({
6591
6872
  "regulatory",
6592
6873
  "other"
6593
6874
  ]).describe("Section type classification"),
6594
- content: import_zod35.z.string().describe("Full verbatim text of the section"),
6875
+ excerpt: import_zod35.z.string().optional().describe("Short source excerpt, not full verbatim text"),
6876
+ content: import_zod35.z.string().optional().describe("Legacy fallback only; do not return full text when sourceSpanIds are available"),
6595
6877
  pageStart: import_zod35.z.number().describe("Starting page number"),
6596
6878
  pageEnd: import_zod35.z.number().optional().describe("Ending page number"),
6879
+ sourceSpanIds: import_zod35.z.array(import_zod35.z.string()).optional().describe("Source span IDs grounding this section"),
6880
+ sourceTextHash: import_zod35.z.string().optional().describe("Hash of the source text when available"),
6597
6881
  subsections: import_zod35.z.array(SubsectionSchema2).optional().describe("Subsections within this section")
6598
6882
  })
6599
6883
  ).describe("All document sections")
6600
6884
  });
6601
6885
  function buildSectionsPrompt() {
6602
- 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.
6886
+ 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.
6603
6887
 
6604
6888
  For each section, classify its type:
6605
6889
  - "declarations" \u2014 declarations page(s) listing named insured, policy period, limits, premiums
@@ -6613,10 +6897,13 @@ For each section, classify its type:
6613
6897
  - "notice", "regulatory" \u2014 notice provisions or regulatory disclosures
6614
6898
  - "other" \u2014 anything that doesn't fit the above categories
6615
6899
 
6616
- Include accurate page numbers for every section. Include subsections only if the section has clearly defined subsections with their own titles.
6900
+ 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.
6617
6901
  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.
6618
6902
 
6619
6903
  Critical rules:
6904
+ - Return compact metadata plus source references. The original policy wording lives in source spans.
6905
+ - Use excerpt only for a short identifying snippet, capped at 300 characters.
6906
+ - Do not return full section text in content when sourceSpanIds are available. Leave content omitted/null in source-backed mode.
6620
6907
  - Ignore table-of-contents entries, page-number references, repeating headers/footers, and other navigational artifacts.
6621
6908
  - 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.
6622
6909
  - When a section spans multiple pages, keep it as one section with pageStart/pageEnd covering the full span represented in this extraction.
@@ -6784,21 +7071,21 @@ Return JSON only.`;
6784
7071
  }
6785
7072
 
6786
7073
  // src/prompts/extractors/index.ts
6787
- function asRecord(data) {
7074
+ function asRecord2(data) {
6788
7075
  return data && typeof data === "object" ? data : void 0;
6789
7076
  }
6790
7077
  function getSections2(data) {
6791
- const sections = asRecord(data)?.sections;
7078
+ const sections = asRecord2(data)?.sections;
6792
7079
  return Array.isArray(sections) ? sections : [];
6793
7080
  }
6794
7081
  function isCoveredReasonsEmpty(data) {
6795
- const record = asRecord(data);
7082
+ const record = asRecord2(data);
6796
7083
  if (!record) return true;
6797
7084
  const coveredReasons = Array.isArray(record.coveredReasons) ? record.coveredReasons : Array.isArray(record.covered_reasons) ? record.covered_reasons : [];
6798
7085
  return coveredReasons.length === 0;
6799
7086
  }
6800
7087
  function isDefinitionsEmpty(data) {
6801
- const definitions = asRecord(data)?.definitions;
7088
+ const definitions = asRecord2(data)?.definitions;
6802
7089
  return !Array.isArray(definitions) || definitions.length === 0;
6803
7090
  }
6804
7091
  function sectionLooksLikeCoveredReason(section) {
@@ -7032,6 +7319,14 @@ function decideReferentialResolutionAction(params) {
7032
7319
  }
7033
7320
 
7034
7321
  // src/extraction/resolve-referential.ts
7322
+ function formatDoclingTextContext(providerOptions) {
7323
+ const doclingText = providerOptions?.doclingText;
7324
+ if (typeof doclingText !== "string" || !doclingText.trim()) return "";
7325
+ return `
7326
+
7327
+ DOCLING DOCUMENT TEXT:
7328
+ ${doclingText}`;
7329
+ }
7035
7330
  function parseReferenceTarget(text) {
7036
7331
  if (typeof text !== "string") return void 0;
7037
7332
  const normalized = text.trim();
@@ -7113,12 +7408,12 @@ Return the page range (1-indexed) where this section is located. If the section
7113
7408
 
7114
7409
  If you cannot find the section, return startPage: 0 and endPage: 0.
7115
7410
 
7116
- Return JSON only.`,
7411
+ Return JSON only.${formatDoclingTextContext(providerOptions)}`,
7117
7412
  schema: PageLocationSchema,
7118
7413
  maxTokens: budget.maxTokens,
7119
7414
  taskKind: "extraction_referential_lookup",
7120
7415
  budgetDiagnostics: budget,
7121
- providerOptions: await buildPdfProviderOptions(pdfInput, providerOptions)
7416
+ providerOptions: pdfInput ? await buildPdfProviderOptions(pdfInput, providerOptions) : providerOptions
7122
7417
  },
7123
7418
  {
7124
7419
  fallback: { startPage: 0, endPage: 0 },
@@ -7152,6 +7447,7 @@ async function resolveReferentialCoverages(params) {
7152
7447
  convertPdfToImages,
7153
7448
  getPageRangePdf,
7154
7449
  getPageImages,
7450
+ getPageRangeText,
7155
7451
  concurrency = 2,
7156
7452
  providerOptions,
7157
7453
  modelCapabilities,
@@ -7263,6 +7559,7 @@ async function resolveReferentialCoverages(params) {
7263
7559
  convertPdfToImages,
7264
7560
  getPageRangePdf,
7265
7561
  getPageImages,
7562
+ getPageRangeText,
7266
7563
  maxTokens: budget.maxTokens,
7267
7564
  taskKind: "extraction_referential_lookup",
7268
7565
  budgetDiagnostics: budget,
@@ -7358,6 +7655,7 @@ async function runFocusedExtractorWithFallback(params) {
7358
7655
  pageRangeCache,
7359
7656
  getPageRangePdf,
7360
7657
  getPageImages,
7658
+ getPageRangeText,
7361
7659
  trackUsage,
7362
7660
  resolveBudget,
7363
7661
  log
@@ -7387,7 +7685,8 @@ async function runFocusedExtractorWithFallback(params) {
7387
7685
  providerOptions,
7388
7686
  pageRangeCache,
7389
7687
  getPageRangePdf,
7390
- getPageImages
7688
+ getPageImages,
7689
+ getPageRangeText
7391
7690
  });
7392
7691
  trackUsage(result.usage, {
7393
7692
  taskKind,
@@ -7432,7 +7731,8 @@ async function runFocusedExtractorWithFallback(params) {
7432
7731
  providerOptions,
7433
7732
  pageRangeCache,
7434
7733
  getPageRangePdf,
7435
- getPageImages
7734
+ getPageImages,
7735
+ getPageRangeText
7436
7736
  });
7437
7737
  trackUsage(fallbackResult.usage, {
7438
7738
  taskKind,
@@ -8276,7 +8576,7 @@ function createExtractor(config) {
8276
8576
  }
8277
8577
  return lines.length > 0 ? lines.join("\n") : "";
8278
8578
  }
8279
- async function runFocusedExtractorTask(task, pdfInput, memory, pageRangeCache, getPageRangePdf, getPageImages) {
8579
+ async function runFocusedExtractorTask(task, pdfInput, memory, pageRangeCache, getPageRangePdf, getPageImages, getPageRangeText) {
8280
8580
  if (task.extractorName === "supplementary") {
8281
8581
  const alreadyExtractedSummary = buildAlreadyExtractedSummary(memory);
8282
8582
  const budget = resolveBudget("extraction_focused", 4096);
@@ -8296,7 +8596,8 @@ function createExtractor(config) {
8296
8596
  providerOptions: activeProviderOptions,
8297
8597
  pageRangeCache,
8298
8598
  getPageRangePdf,
8299
- getPageImages
8599
+ getPageImages,
8600
+ getPageRangeText
8300
8601
  });
8301
8602
  trackUsage(result.usage, {
8302
8603
  taskKind: "extraction_focused",
@@ -8315,6 +8616,7 @@ function createExtractor(config) {
8315
8616
  pageRangeCache,
8316
8617
  getPageRangePdf,
8317
8618
  getPageImages,
8619
+ getPageRangeText,
8318
8620
  trackUsage,
8319
8621
  resolveBudget,
8320
8622
  log
@@ -8330,8 +8632,14 @@ function createExtractor(config) {
8330
8632
  if (extractorPages.size === 0) return "No page assignments available.";
8331
8633
  return [...extractorPages.entries()].map(([extractorName, pages]) => `${extractorName}: ${pages.length} page(s), pages ${pages.join(", ")}`).join("\n");
8332
8634
  }
8333
- async function extract(pdfInput, documentId, options) {
8635
+ async function extract(input, documentId, options) {
8334
8636
  const id = documentId ?? `doc-${Date.now()}`;
8637
+ const isDoclingInput = isDoclingExtractionInput(input);
8638
+ const pdfInput = isDoclingInput ? void 0 : input;
8639
+ const doclingDocument = isDoclingInput ? normalizeDoclingDocument(input.document, {
8640
+ documentId: id,
8641
+ sourceKind: input.sourceKind
8642
+ }) : void 0;
8335
8643
  const memory = /* @__PURE__ */ new Map();
8336
8644
  totalUsage = { inputTokens: 0, outputTokens: 0 };
8337
8645
  modelCalls = 0;
@@ -8341,7 +8649,10 @@ function createExtractor(config) {
8341
8649
  modelCalls: [],
8342
8650
  totalModelCallDurationMs: 0
8343
8651
  };
8344
- const sourceSpans = options?.sourceSpans ?? [];
8652
+ const sourceSpans = mergeSourceSpans([
8653
+ ...doclingDocument?.sourceSpans ?? [],
8654
+ ...options?.sourceSpans ?? []
8655
+ ]);
8345
8656
  const sourceChunks = sourceSpans.length ? chunkSourceSpans(sourceSpans) : [];
8346
8657
  activeProviderOptions = sourceSpans.length ? { ...providerOptions, sourceSpans, sourceChunks } : providerOptions;
8347
8658
  if (sourceStore && sourceSpans.length > 0) {
@@ -8370,24 +8681,40 @@ function createExtractor(config) {
8370
8681
  let fullPdfProviderOptionsPromise;
8371
8682
  let pageCountPromise;
8372
8683
  async function getPdfBase64ForExtraction() {
8684
+ if (!pdfInput) {
8685
+ throw new Error("PDF input is not available for Docling extraction.");
8686
+ }
8373
8687
  if (pdfBase64Cache === void 0) {
8374
8688
  pdfBase64Cache = await pdfInputToBase64(pdfInput);
8375
8689
  }
8376
8690
  return pdfBase64Cache;
8377
8691
  }
8378
8692
  async function getCachedPageCount() {
8693
+ if (doclingDocument) return doclingDocument.pageCount;
8694
+ if (!pdfInput) {
8695
+ throw new Error("PDF input is required to read page count.");
8696
+ }
8379
8697
  if (!pageCountPromise) {
8380
8698
  pageCountPromise = getPdfSlicer().then((slicer) => slicer.getPageCount()).catch(() => getPdfPageCount(pdfInput));
8381
8699
  }
8382
8700
  return pageCountPromise;
8383
8701
  }
8384
- async function getFullPdfProviderOptions() {
8702
+ async function getFullDocumentProviderOptions() {
8703
+ if (doclingDocument) {
8704
+ return buildDoclingProviderOptions(doclingDocument, activeProviderOptions);
8705
+ }
8706
+ if (!pdfInput) {
8707
+ return activeProviderOptions ?? {};
8708
+ }
8385
8709
  if (!fullPdfProviderOptionsPromise) {
8386
8710
  fullPdfProviderOptionsPromise = buildPdfProviderOptions(pdfInput, activeProviderOptions);
8387
8711
  }
8388
8712
  return fullPdfProviderOptionsPromise;
8389
8713
  }
8390
8714
  async function getPdfSlicer() {
8715
+ if (!pdfInput) {
8716
+ throw new Error("PDF input is not available for Docling extraction.");
8717
+ }
8391
8718
  if (!pdfSlicerPromise) {
8392
8719
  pdfSlicerPromise = createPdfPageSlicer(pdfInput);
8393
8720
  }
@@ -8426,6 +8753,23 @@ function createExtractor(config) {
8426
8753
  pageRangeImageCache.set(cacheKey, promise);
8427
8754
  return promise;
8428
8755
  }
8756
+ async function getPageRangeText(startPage, endPage) {
8757
+ return doclingDocument ? getDoclingPageRangeText(doclingDocument, startPage, endPage) : "";
8758
+ }
8759
+ function withFullDocumentTextContext(prompt) {
8760
+ if (!doclingDocument) return prompt;
8761
+ return `${prompt}
8762
+
8763
+ DOCLING DOCUMENT TEXT:
8764
+ ${doclingDocument.fullText}`;
8765
+ }
8766
+ function withPageRangeTextContext(prompt, startPage, endPage, pageText) {
8767
+ if (!doclingDocument) return prompt;
8768
+ return `${prompt}
8769
+
8770
+ DOCLING DOCUMENT PAGES ${startPage}-${endPage}:
8771
+ ${pageText || "(No Docling text was available for this page range.)"}`;
8772
+ }
8429
8773
  let classifyResult;
8430
8774
  if (resumed?.classifyResult && pipelineCtx.isPhaseComplete("classify")) {
8431
8775
  classifyResult = resumed.classifyResult;
@@ -8438,12 +8782,12 @@ function createExtractor(config) {
8438
8782
  const classifyResponse = await safeGenerateObject(
8439
8783
  generateObject,
8440
8784
  {
8441
- prompt: buildClassifyPrompt(),
8785
+ prompt: withFullDocumentTextContext(buildClassifyPrompt()),
8442
8786
  schema: ClassifyResultSchema,
8443
8787
  maxTokens: budget.maxTokens,
8444
8788
  taskKind: "extraction_classify",
8445
8789
  budgetDiagnostics: budget,
8446
- providerOptions: await getFullPdfProviderOptions()
8790
+ providerOptions: await getFullDocumentProviderOptions()
8447
8791
  },
8448
8792
  {
8449
8793
  fallback: { documentType: "policy", policyTypes: ["other"], confidence: 0 },
@@ -8488,12 +8832,12 @@ function createExtractor(config) {
8488
8832
  const formInventoryResponse = await safeGenerateObject(
8489
8833
  generateObject,
8490
8834
  {
8491
- prompt: buildFormInventoryPrompt(templateHints),
8835
+ prompt: withFullDocumentTextContext(buildFormInventoryPrompt(templateHints)),
8492
8836
  schema: FormInventorySchema,
8493
8837
  maxTokens: budget.maxTokens,
8494
8838
  taskKind: "extraction_form_inventory",
8495
8839
  budgetDiagnostics: budget,
8496
- providerOptions: await getFullPdfProviderOptions()
8840
+ providerOptions: await getFullDocumentProviderOptions()
8497
8841
  },
8498
8842
  {
8499
8843
  fallback: { forms: [] },
@@ -8536,18 +8880,24 @@ function createExtractor(config) {
8536
8880
  const pageMapResults = await Promise.all(
8537
8881
  pageMapChunks.map(
8538
8882
  ({ startPage, endPage }) => pageMapLimit(async () => {
8539
- const pagesPdf = await getPageRangePdf(startPage, endPage);
8883
+ const pagesPdf = doclingDocument ? void 0 : await getPageRangePdf(startPage, endPage);
8884
+ const pagesText = doclingDocument ? await getPageRangeText(startPage, endPage) : "";
8540
8885
  const budget = resolveBudget("extraction_page_map", 2048);
8541
8886
  const startedAt = Date.now();
8542
8887
  const mapResponse = await safeGenerateObject(
8543
8888
  generateObject,
8544
8889
  {
8545
- prompt: buildPageMapPrompt(templateHints, startPage, endPage, formInventoryHint),
8890
+ prompt: withPageRangeTextContext(
8891
+ buildPageMapPrompt(templateHints, startPage, endPage, formInventoryHint),
8892
+ startPage,
8893
+ endPage,
8894
+ pagesText
8895
+ ),
8546
8896
  schema: PageMapChunkSchema,
8547
8897
  maxTokens: budget.maxTokens,
8548
8898
  taskKind: "extraction_page_map",
8549
8899
  budgetDiagnostics: budget,
8550
- providerOptions: { ...activeProviderOptions, pdfBase64: pagesPdf }
8900
+ providerOptions: doclingDocument ? { ...activeProviderOptions, doclingText: pagesText, doclingPageRange: { startPage, endPage } } : { ...activeProviderOptions, pdfBase64: pagesPdf }
8551
8901
  },
8552
8902
  {
8553
8903
  fallback: {
@@ -8625,7 +8975,7 @@ function createExtractor(config) {
8625
8975
  }))
8626
8976
  ];
8627
8977
  onProgress?.(`Dispatching ${tasks.length} extractors...`);
8628
- const extractionPdfInput = await getPdfBase64ForExtraction();
8978
+ const extractionPdfInput = doclingDocument ? void 0 : await getPdfBase64ForExtraction();
8629
8979
  const extractorResults = await Promise.all(
8630
8980
  tasks.map(
8631
8981
  (task) => extractorLimit(async () => {
@@ -8636,7 +8986,8 @@ function createExtractor(config) {
8636
8986
  memory,
8637
8987
  completedPageRangePdfCache,
8638
8988
  getPageRangePdf,
8639
- convertPdfToImages ? getPageImages : void 0
8989
+ convertPdfToImages ? getPageImages : void 0,
8990
+ doclingDocument ? getPageRangeText : void 0
8640
8991
  );
8641
8992
  })
8642
8993
  )
@@ -8668,7 +9019,8 @@ function createExtractor(config) {
8668
9019
  providerOptions: activeProviderOptions,
8669
9020
  pageRangeCache: completedPageRangePdfCache,
8670
9021
  getPageRangePdf,
8671
- getPageImages: convertPdfToImages ? getPageImages : void 0
9022
+ getPageImages: convertPdfToImages ? getPageImages : void 0,
9023
+ getPageRangeText: doclingDocument ? getPageRangeText : void 0
8672
9024
  });
8673
9025
  trackUsage(supplementaryResult.usage, {
8674
9026
  taskKind: "extraction_focused",
@@ -8704,6 +9056,7 @@ function createExtractor(config) {
8704
9056
  concurrency,
8705
9057
  getPageRangePdf,
8706
9058
  getPageImages: convertPdfToImages ? getPageImages : void 0,
9059
+ getPageRangeText: doclingDocument ? getPageRangeText : void 0,
8707
9060
  providerOptions: activeProviderOptions,
8708
9061
  modelCapabilities,
8709
9062
  modelBudgetConstraints,
@@ -8752,12 +9105,12 @@ function createExtractor(config) {
8752
9105
  const reviewResponse = await safeGenerateObject(
8753
9106
  generateObject,
8754
9107
  {
8755
- prompt: buildReviewPrompt(template.required, extractedKeys, extractionSummary, pageMapSummary, extractorCatalog),
9108
+ prompt: withFullDocumentTextContext(buildReviewPrompt(template.required, extractedKeys, extractionSummary, pageMapSummary, extractorCatalog)),
8756
9109
  schema: ReviewResultSchema,
8757
9110
  maxTokens: budget.maxTokens,
8758
9111
  taskKind: "extraction_review",
8759
9112
  budgetDiagnostics: budget,
8760
- providerOptions: await getFullPdfProviderOptions()
9113
+ providerOptions: await getFullDocumentProviderOptions()
8761
9114
  },
8762
9115
  {
8763
9116
  fallback: {
@@ -8787,7 +9140,7 @@ function createExtractor(config) {
8787
9140
  break;
8788
9141
  }
8789
9142
  onProgress?.(`Review round ${round + 1}: dispatching ${reviewResponse.object.additionalTasks.length} follow-up extractors...`);
8790
- const extractionPdfInput = await getPdfBase64ForExtraction();
9143
+ const extractionPdfInput = doclingDocument ? void 0 : await getPdfBase64ForExtraction();
8791
9144
  const followUpResults = await Promise.all(
8792
9145
  reviewResponse.object.additionalTasks.map(
8793
9146
  (task) => extractorLimit(async () => {
@@ -8797,7 +9150,8 @@ function createExtractor(config) {
8797
9150
  memory,
8798
9151
  completedPageRangePdfCache,
8799
9152
  getPageRangePdf,
8800
- convertPdfToImages ? getPageImages : void 0
9153
+ convertPdfToImages ? getPageImages : void 0,
9154
+ doclingDocument ? getPageRangeText : void 0
8801
9155
  );
8802
9156
  })
8803
9157
  )
@@ -12797,6 +13151,7 @@ var AGENT_TOOLS = [
12797
13151
  buildConfirmationSummaryPrompt,
12798
13152
  buildConversationMemoryGuidance,
12799
13153
  buildCoverageGapPrompt,
13154
+ buildDoclingProviderOptions,
12800
13155
  buildFieldExplanationPrompt,
12801
13156
  buildFieldExtractionPrompt,
12802
13157
  buildFlatPdfMappingPrompt,
@@ -12838,12 +13193,16 @@ var AGENT_TOOLS = [
12838
13193
  fillAcroForm,
12839
13194
  generateNextMessage,
12840
13195
  getAcroFormFields,
13196
+ getDoclingPageRangeText,
12841
13197
  getExtractor,
12842
13198
  getFileIdentifier,
12843
13199
  getPdfPageCount,
12844
13200
  getTemplate,
13201
+ isDoclingExtractionInput,
12845
13202
  isFileReference,
12846
13203
  mergeQuestionAnswers,
13204
+ mergeSourceSpans,
13205
+ normalizeDoclingDocument,
12847
13206
  normalizeForMatch,
12848
13207
  orderSourceEvidence,
12849
13208
  overlayTextOnPdf,