@claritylabs/cl-sdk 1.3.2 → 1.3.3
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 +171 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +171 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8185,7 +8185,7 @@ function normalizePageAssignments(pageAssignments, formInventory) {
|
|
|
8185
8185
|
}
|
|
8186
8186
|
return pageAssignments.map((assignment) => {
|
|
8187
8187
|
let extractorNames = [...new Set(
|
|
8188
|
-
|
|
8188
|
+
assignment.extractorNames.filter(Boolean)
|
|
8189
8189
|
)];
|
|
8190
8190
|
const hasDeclarations = extractorNames.includes("declarations");
|
|
8191
8191
|
const hasConditions = extractorNames.includes("conditions");
|
|
@@ -8204,9 +8204,6 @@ function normalizePageAssignments(pageAssignments, formInventory) {
|
|
|
8204
8204
|
if (inventoryTypes?.has("endorsement") && !extractorNames.includes("endorsements")) {
|
|
8205
8205
|
extractorNames = [...extractorNames, "endorsements"];
|
|
8206
8206
|
}
|
|
8207
|
-
if (extractorNames.length === 0) {
|
|
8208
|
-
extractorNames = ["sections"];
|
|
8209
|
-
}
|
|
8210
8207
|
return {
|
|
8211
8208
|
...assignment,
|
|
8212
8209
|
extractorNames
|
|
@@ -8243,20 +8240,12 @@ function groupContiguousPages(pages) {
|
|
|
8243
8240
|
function buildPlanFromPageAssignments(pageAssignments, pageCount, formInventory) {
|
|
8244
8241
|
const extractorPages = /* @__PURE__ */ new Map();
|
|
8245
8242
|
for (const assignment of pageAssignments) {
|
|
8246
|
-
const
|
|
8243
|
+
const focusedExtractors = assignment.extractorNames.filter((name) => name !== "sections");
|
|
8244
|
+
const extractors = focusedExtractors.length > 0 ? focusedExtractors : assignment.extractorNames;
|
|
8247
8245
|
for (const extractorName of extractors) {
|
|
8248
8246
|
extractorPages.set(extractorName, [...extractorPages.get(extractorName) ?? [], assignment.localPageNumber]);
|
|
8249
8247
|
}
|
|
8250
8248
|
}
|
|
8251
|
-
const coveredPages = /* @__PURE__ */ new Set();
|
|
8252
|
-
for (const pages of extractorPages.values()) {
|
|
8253
|
-
for (const page of pages) coveredPages.add(page);
|
|
8254
|
-
}
|
|
8255
|
-
for (let page = 1; page <= pageCount; page += 1) {
|
|
8256
|
-
if (!coveredPages.has(page)) {
|
|
8257
|
-
extractorPages.set("sections", [...extractorPages.get("sections") ?? [], page]);
|
|
8258
|
-
}
|
|
8259
|
-
}
|
|
8260
8249
|
const contextualExtractors = /* @__PURE__ */ new Set(["conditions", "covered_reasons", "definitions", "exclusions", "endorsements"]);
|
|
8261
8250
|
const contextualForms = (formInventory?.forms ?? []).filter(
|
|
8262
8251
|
(form) => form.pageStart != null && (form.pageEnd ?? form.pageStart) != null
|
|
@@ -8543,6 +8532,139 @@ function createExtractor(config) {
|
|
|
8543
8532
|
ranges.push({ startPage, endPage: previousPage });
|
|
8544
8533
|
return ranges;
|
|
8545
8534
|
}
|
|
8535
|
+
function pageNumberForSpan(span) {
|
|
8536
|
+
return span.pageStart ?? span.location?.startPage ?? span.location?.page;
|
|
8537
|
+
}
|
|
8538
|
+
function spansForPageRange(spans, startPage, endPage) {
|
|
8539
|
+
return spans.filter((span) => {
|
|
8540
|
+
const start = span.pageStart ?? span.location?.startPage ?? span.location?.page;
|
|
8541
|
+
const end = span.pageEnd ?? span.location?.endPage ?? start;
|
|
8542
|
+
return typeof start === "number" && typeof end === "number" && start <= endPage && end >= startPage;
|
|
8543
|
+
});
|
|
8544
|
+
}
|
|
8545
|
+
function inferSectionType(title, text) {
|
|
8546
|
+
const value = `${title} ${text.slice(0, 500)}`.toLowerCase();
|
|
8547
|
+
if (/\bdefinition|defined terms?\b/.test(value)) return "definition";
|
|
8548
|
+
if (/\bexclusion|not covered|does not apply\b/.test(value)) return "exclusion";
|
|
8549
|
+
if (/\bcondition|duties|loss condition|general condition\b/.test(value)) return "condition";
|
|
8550
|
+
if (/\bendorsement|amend|additional insured\b/.test(value)) return "endorsement";
|
|
8551
|
+
if (/\bcovered cause|covered reason|covered peril|cause of loss|perils insured\b/.test(value)) return "covered_reason";
|
|
8552
|
+
if (/\bdeclaration|schedule\b/.test(value)) return "declarations";
|
|
8553
|
+
return "policy_form";
|
|
8554
|
+
}
|
|
8555
|
+
function buildSourceBackedSectionIndex(spans, startPage, endPage) {
|
|
8556
|
+
const candidateSpans = spansForPageRange(spans, startPage, endPage).filter((span) => span.text.trim().length > 0).filter((span) => span.metadata?.sourceUnit === "section_candidate" || span.sectionId || span.text.length >= 160);
|
|
8557
|
+
return {
|
|
8558
|
+
sections: candidateSpans.map((span, index) => {
|
|
8559
|
+
const pageStart = span.pageStart ?? span.location?.startPage ?? span.location?.page ?? startPage;
|
|
8560
|
+
const pageEnd = span.pageEnd ?? span.location?.endPage ?? pageStart;
|
|
8561
|
+
const title = span.sectionId ?? span.formNumber ?? firstHeadingLine(span.text) ?? `Policy text page ${pageStart}`;
|
|
8562
|
+
return {
|
|
8563
|
+
title,
|
|
8564
|
+
sectionNumber: span.formNumber,
|
|
8565
|
+
pageStart,
|
|
8566
|
+
pageEnd,
|
|
8567
|
+
type: inferSectionType(title, span.text),
|
|
8568
|
+
excerpt: span.text.slice(0, 240),
|
|
8569
|
+
recordId: `section_index_${pageStart}_${index}`,
|
|
8570
|
+
sourceSpanIds: [span.id],
|
|
8571
|
+
sourceTextHash: span.textHash ?? sourceSpanTextHash(span.text)
|
|
8572
|
+
};
|
|
8573
|
+
})
|
|
8574
|
+
};
|
|
8575
|
+
}
|
|
8576
|
+
function firstHeadingLine(text) {
|
|
8577
|
+
const line = text.split(/\r?\n/).map((item) => item.trim()).find((item) => item.length > 0);
|
|
8578
|
+
if (!line) return void 0;
|
|
8579
|
+
return line.slice(0, 100);
|
|
8580
|
+
}
|
|
8581
|
+
function buildDeterministicFormInventory(spans, pageCount) {
|
|
8582
|
+
if (spans.length === 0) return void 0;
|
|
8583
|
+
const formPattern = /\b([A-Z]{1,4}\s?\d{2,5}(?:\s?\d{2,4})?|[A-Z]{2,8}-\d{2,8})\b/g;
|
|
8584
|
+
const seen = /* @__PURE__ */ new Map();
|
|
8585
|
+
for (const span of spans) {
|
|
8586
|
+
const page = pageNumberForSpan(span);
|
|
8587
|
+
if (!page) continue;
|
|
8588
|
+
const title = firstHeadingLine(span.text) ?? span.sectionId;
|
|
8589
|
+
const matches = /* @__PURE__ */ new Set([
|
|
8590
|
+
...span.formNumber ? [span.formNumber] : [],
|
|
8591
|
+
...Array.from(span.text.slice(0, 1200).matchAll(formPattern), (match) => match[1].trim())
|
|
8592
|
+
]);
|
|
8593
|
+
for (const formNumber of matches) {
|
|
8594
|
+
const key = `${formNumber}:${title ?? ""}`;
|
|
8595
|
+
const existing = seen.get(key);
|
|
8596
|
+
const formType = inferFormType(title ?? "", span.text);
|
|
8597
|
+
if (existing) {
|
|
8598
|
+
existing.pageStart = Math.min(existing.pageStart ?? page, page);
|
|
8599
|
+
existing.pageEnd = Math.max(existing.pageEnd ?? page, page);
|
|
8600
|
+
continue;
|
|
8601
|
+
}
|
|
8602
|
+
seen.set(key, {
|
|
8603
|
+
formNumber,
|
|
8604
|
+
title,
|
|
8605
|
+
formType,
|
|
8606
|
+
pageStart: Math.min(page, pageCount),
|
|
8607
|
+
pageEnd: Math.min(page, pageCount)
|
|
8608
|
+
});
|
|
8609
|
+
}
|
|
8610
|
+
}
|
|
8611
|
+
const forms = [...seen.values()].sort((a, b) => (a.pageStart ?? 0) - (b.pageStart ?? 0));
|
|
8612
|
+
return forms.length > 0 ? { forms } : void 0;
|
|
8613
|
+
}
|
|
8614
|
+
function inferFormType(title, text) {
|
|
8615
|
+
const value = `${title} ${text.slice(0, 700)}`.toLowerCase();
|
|
8616
|
+
if (/\bdeclarations?|schedule\b/.test(value)) return "declarations";
|
|
8617
|
+
if (/\bendorsement|amendatory|additional insured\b/.test(value)) return "endorsement";
|
|
8618
|
+
if (/\bnotice|department of insurance|complaint|privacy\b/.test(value)) return "notice";
|
|
8619
|
+
if (/\bapplication|questionnaire\b/.test(value)) return "application";
|
|
8620
|
+
if (/\bcoverage|policy form|conditions|exclusions|definitions|causes of loss\b/.test(value)) return "coverage";
|
|
8621
|
+
return "other";
|
|
8622
|
+
}
|
|
8623
|
+
function buildDeterministicPageAssignments(spans, pageCount) {
|
|
8624
|
+
if (spans.length === 0) return [];
|
|
8625
|
+
const pageTexts = /* @__PURE__ */ new Map();
|
|
8626
|
+
for (const span of spans) {
|
|
8627
|
+
const page = pageNumberForSpan(span);
|
|
8628
|
+
if (!page) continue;
|
|
8629
|
+
pageTexts.set(page, [pageTexts.get(page), span.sectionId, span.text].filter(Boolean).join("\n"));
|
|
8630
|
+
}
|
|
8631
|
+
return Array.from({ length: pageCount }, (_, index) => {
|
|
8632
|
+
const page = index + 1;
|
|
8633
|
+
const text = pageTexts.get(page) ?? "";
|
|
8634
|
+
const lower = text.toLowerCase();
|
|
8635
|
+
const extractorNames = [];
|
|
8636
|
+
if (/\bdeclarations?|policy period|named insured|producer|schedule\b/.test(lower)) {
|
|
8637
|
+
extractorNames.push("carrier_info", "named_insured", "declarations");
|
|
8638
|
+
}
|
|
8639
|
+
if (/\blimit|deductible|premium|coinsurance|scheduled amount|blanket\b/.test(lower) && /\$|\b\d{2,}(?:,\d{3})*\b/.test(lower)) {
|
|
8640
|
+
extractorNames.push("coverage_limits");
|
|
8641
|
+
}
|
|
8642
|
+
if (/\bpremium|tax|fee|surcharge\b/.test(lower) && /\$/.test(lower)) extractorNames.push("premium_breakdown");
|
|
8643
|
+
if (/\bendorsement|additional insured|amendatory\b/.test(lower)) extractorNames.push("endorsements");
|
|
8644
|
+
if (/\bexclusion|not covered|does not apply\b/.test(lower)) extractorNames.push("exclusions");
|
|
8645
|
+
if (/\bcondition|duties in the event|loss condition|general condition\b/.test(lower)) extractorNames.push("conditions");
|
|
8646
|
+
if (/\bdefinition|defined terms?\b/.test(lower)) extractorNames.push("definitions");
|
|
8647
|
+
if (/\bcovered cause|covered peril|cause of loss|perils insured\b/.test(lower)) extractorNames.push("covered_reasons");
|
|
8648
|
+
if (textIncludesSupplementarySignal(text)) extractorNames.push("supplementary");
|
|
8649
|
+
if (extractorNames.length === 0 && text.trim().length > 180) extractorNames.push("sections");
|
|
8650
|
+
return {
|
|
8651
|
+
localPageNumber: page,
|
|
8652
|
+
extractorNames: [...new Set(extractorNames)],
|
|
8653
|
+
pageRole: inferPageRole(lower),
|
|
8654
|
+
hasScheduleValues: /\$|\b\d{2,}(?:,\d{3})*\b/.test(lower) && /\blimit|deductible|premium|schedule|class|location\b/.test(lower),
|
|
8655
|
+
confidence: text.trim().length > 0 ? 0.8 : 0,
|
|
8656
|
+
notes: "Deterministic source-span page assignment"
|
|
8657
|
+
};
|
|
8658
|
+
});
|
|
8659
|
+
}
|
|
8660
|
+
function inferPageRole(lowerText) {
|
|
8661
|
+
if (/\bdeclarations?|schedule\b/.test(lowerText)) return "declarations_schedule";
|
|
8662
|
+
if (/\bendorsement\b/.test(lowerText)) return "endorsement_form";
|
|
8663
|
+
if (/\bexclusion|condition\b/.test(lowerText)) return "condition_exclusion_form";
|
|
8664
|
+
if (/\bnotice|department of insurance|complaint\b/.test(lowerText)) return "supplementary";
|
|
8665
|
+
if (lowerText.trim()) return "policy_form";
|
|
8666
|
+
return "other";
|
|
8667
|
+
}
|
|
8546
8668
|
function shouldRunLlmReview(mode, report, sourceSpansAvailable) {
|
|
8547
8669
|
if (mode === "skip" || maxReviewRounds <= 0) return false;
|
|
8548
8670
|
if (mode === "always") return true;
|
|
@@ -8578,7 +8700,14 @@ function createExtractor(config) {
|
|
|
8578
8700
|
}
|
|
8579
8701
|
return lines.length > 0 ? lines.join("\n") : "";
|
|
8580
8702
|
}
|
|
8581
|
-
async function runFocusedExtractorTask(task, pdfInput, memory, pageRangeCache, getPageRangePdf, getPageImages, getPageRangeText) {
|
|
8703
|
+
async function runFocusedExtractorTask(task, pdfInput, memory, sourceSpansForSections, pageRangeCache, getPageRangePdf, getPageImages, getPageRangeText) {
|
|
8704
|
+
if (task.extractorName === "sections" && sourceSpansForSections.length > 0) {
|
|
8705
|
+
return {
|
|
8706
|
+
name: "sections",
|
|
8707
|
+
data: buildSourceBackedSectionIndex(sourceSpansForSections, task.startPage, task.endPage),
|
|
8708
|
+
usage: void 0
|
|
8709
|
+
};
|
|
8710
|
+
}
|
|
8582
8711
|
if (task.extractorName === "supplementary") {
|
|
8583
8712
|
const alreadyExtractedSummary = buildAlreadyExtractedSummary(memory);
|
|
8584
8713
|
const budget = resolveBudget("extraction_focused", 4096);
|
|
@@ -8827,6 +8956,17 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8827
8956
|
formInventory = resumed.formInventory;
|
|
8828
8957
|
memory.set("form_inventory", formInventory);
|
|
8829
8958
|
onProgress?.("Resuming from checkpoint (form inventory complete)...");
|
|
8959
|
+
} else if (sourceSpans.length > 0) {
|
|
8960
|
+
formInventory = buildDeterministicFormInventory(sourceSpans, pageCount) ?? { forms: [] };
|
|
8961
|
+
onProgress?.(`Built deterministic form inventory for ${primaryType} ${documentType}.`);
|
|
8962
|
+
memory.set("form_inventory", formInventory);
|
|
8963
|
+
await pipelineCtx.save("form_inventory", {
|
|
8964
|
+
id,
|
|
8965
|
+
pageCount,
|
|
8966
|
+
classifyResult,
|
|
8967
|
+
formInventory,
|
|
8968
|
+
memory: Object.fromEntries(memory)
|
|
8969
|
+
});
|
|
8830
8970
|
} else {
|
|
8831
8971
|
onProgress?.(`Building form inventory for ${primaryType} ${documentType}...`);
|
|
8832
8972
|
const budget = resolveBudget("extraction_form_inventory", 2048);
|
|
@@ -8867,6 +9007,20 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8867
9007
|
if (resumed?.pageAssignments && pipelineCtx.isPhaseComplete("page_map")) {
|
|
8868
9008
|
pageAssignments = resumed.pageAssignments;
|
|
8869
9009
|
onProgress?.("Resuming from checkpoint (page map complete)...");
|
|
9010
|
+
} else if (sourceSpans.length > 0) {
|
|
9011
|
+
onProgress?.(`Mapping document pages from source spans for ${primaryType} ${documentType}...`);
|
|
9012
|
+
pageAssignments = normalizePageAssignments(
|
|
9013
|
+
buildDeterministicPageAssignments(sourceSpans, pageCount),
|
|
9014
|
+
formInventory
|
|
9015
|
+
);
|
|
9016
|
+
await pipelineCtx.save("page_map", {
|
|
9017
|
+
id,
|
|
9018
|
+
pageCount,
|
|
9019
|
+
classifyResult,
|
|
9020
|
+
formInventory,
|
|
9021
|
+
pageAssignments,
|
|
9022
|
+
memory: Object.fromEntries(memory)
|
|
9023
|
+
});
|
|
8870
9024
|
} else {
|
|
8871
9025
|
onProgress?.(`Mapping document pages for ${primaryType} ${documentType}...`);
|
|
8872
9026
|
const chunkSize = 8;
|
|
@@ -8986,6 +9140,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8986
9140
|
task,
|
|
8987
9141
|
extractionPdfInput,
|
|
8988
9142
|
memory,
|
|
9143
|
+
sourceSpans,
|
|
8989
9144
|
completedPageRangePdfCache,
|
|
8990
9145
|
getPageRangePdf,
|
|
8991
9146
|
convertPdfToImages ? getPageImages : void 0,
|
|
@@ -9150,6 +9305,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
9150
9305
|
task,
|
|
9151
9306
|
extractionPdfInput,
|
|
9152
9307
|
memory,
|
|
9308
|
+
sourceSpans,
|
|
9153
9309
|
completedPageRangePdfCache,
|
|
9154
9310
|
getPageRangePdf,
|
|
9155
9311
|
convertPdfToImages ? getPageImages : void 0,
|