@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/README.md +18 -3
- package/dist/index.d.mts +322 -84
- package/dist/index.d.ts +322 -84
- package/dist/index.js +503 -144
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +498 -144
- package/dist/index.mjs.map +1 -1
- package/dist/storage-sqlite.d.mts +96 -34
- package/dist/storage-sqlite.d.ts +96 -34
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
3928
|
-
const body =
|
|
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
|
-
|
|
4240
|
+
firstString2(definition, ["originalContent", "source"]) ? `Source: ${firstString2(definition, ["originalContent", "source"])}` : null
|
|
3936
4241
|
]),
|
|
3937
4242
|
{
|
|
3938
4243
|
term,
|
|
3939
|
-
formNumber:
|
|
3940
|
-
formTitle:
|
|
4244
|
+
formNumber: firstString2(definition, ["formNumber"]),
|
|
4245
|
+
formTitle: firstString2(definition, ["formTitle"]),
|
|
3941
4246
|
pageNumber: typeof definition.pageNumber === "number" ? definition.pageNumber : void 0,
|
|
3942
|
-
sectionRef:
|
|
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 =
|
|
3950
|
-
const coverageName =
|
|
3951
|
-
const reasonNumber =
|
|
3952
|
-
const body =
|
|
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
|
-
|
|
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:
|
|
3968
|
-
formTitle:
|
|
4272
|
+
formNumber: firstString2(coveredReason, ["formNumber"]),
|
|
4273
|
+
formTitle: firstString2(coveredReason, ["formTitle"]),
|
|
3969
4274
|
pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
|
|
3970
|
-
sectionRef:
|
|
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:
|
|
3991
|
-
formTitle:
|
|
4295
|
+
formNumber: firstString2(coveredReason, ["formNumber"]),
|
|
4296
|
+
formTitle: firstString2(coveredReason, ["formTitle"]),
|
|
3992
4297
|
pageNumber: typeof coveredReason.pageNumber === "number" ? coveredReason.pageNumber : void 0,
|
|
3993
|
-
sectionRef:
|
|
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
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
`
|
|
4023
|
-
${sec.
|
|
4024
|
-
{
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
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
|
-
|
|
4344
|
+
);
|
|
4345
|
+
sec.subsections?.forEach((sub, j) => {
|
|
4090
4346
|
pushChunk(
|
|
4091
|
-
`section:${i}`,
|
|
4347
|
+
`section:${i}:sub:${j}`,
|
|
4092
4348
|
"section",
|
|
4093
|
-
|
|
4094
|
-
${sec.
|
|
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
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
6746
|
+
function asRecord2(data) {
|
|
6465
6747
|
return data && typeof data === "object" ? data : void 0;
|
|
6466
6748
|
}
|
|
6467
6749
|
function getSections2(data) {
|
|
6468
|
-
const sections =
|
|
6750
|
+
const sections = asRecord2(data)?.sections;
|
|
6469
6751
|
return Array.isArray(sections) ? sections : [];
|
|
6470
6752
|
}
|
|
6471
6753
|
function isCoveredReasonsEmpty(data) {
|
|
6472
|
-
const record =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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,
|