@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.mjs
CHANGED
|
@@ -7857,7 +7857,7 @@ function normalizePageAssignments(pageAssignments, formInventory) {
|
|
|
7857
7857
|
}
|
|
7858
7858
|
return pageAssignments.map((assignment) => {
|
|
7859
7859
|
let extractorNames = [...new Set(
|
|
7860
|
-
|
|
7860
|
+
assignment.extractorNames.filter(Boolean)
|
|
7861
7861
|
)];
|
|
7862
7862
|
const hasDeclarations = extractorNames.includes("declarations");
|
|
7863
7863
|
const hasConditions = extractorNames.includes("conditions");
|
|
@@ -7876,9 +7876,6 @@ function normalizePageAssignments(pageAssignments, formInventory) {
|
|
|
7876
7876
|
if (inventoryTypes?.has("endorsement") && !extractorNames.includes("endorsements")) {
|
|
7877
7877
|
extractorNames = [...extractorNames, "endorsements"];
|
|
7878
7878
|
}
|
|
7879
|
-
if (extractorNames.length === 0) {
|
|
7880
|
-
extractorNames = ["sections"];
|
|
7881
|
-
}
|
|
7882
7879
|
return {
|
|
7883
7880
|
...assignment,
|
|
7884
7881
|
extractorNames
|
|
@@ -7915,20 +7912,12 @@ function groupContiguousPages(pages) {
|
|
|
7915
7912
|
function buildPlanFromPageAssignments(pageAssignments, pageCount, formInventory) {
|
|
7916
7913
|
const extractorPages = /* @__PURE__ */ new Map();
|
|
7917
7914
|
for (const assignment of pageAssignments) {
|
|
7918
|
-
const
|
|
7915
|
+
const focusedExtractors = assignment.extractorNames.filter((name) => name !== "sections");
|
|
7916
|
+
const extractors = focusedExtractors.length > 0 ? focusedExtractors : assignment.extractorNames;
|
|
7919
7917
|
for (const extractorName of extractors) {
|
|
7920
7918
|
extractorPages.set(extractorName, [...extractorPages.get(extractorName) ?? [], assignment.localPageNumber]);
|
|
7921
7919
|
}
|
|
7922
7920
|
}
|
|
7923
|
-
const coveredPages = /* @__PURE__ */ new Set();
|
|
7924
|
-
for (const pages of extractorPages.values()) {
|
|
7925
|
-
for (const page of pages) coveredPages.add(page);
|
|
7926
|
-
}
|
|
7927
|
-
for (let page = 1; page <= pageCount; page += 1) {
|
|
7928
|
-
if (!coveredPages.has(page)) {
|
|
7929
|
-
extractorPages.set("sections", [...extractorPages.get("sections") ?? [], page]);
|
|
7930
|
-
}
|
|
7931
|
-
}
|
|
7932
7921
|
const contextualExtractors = /* @__PURE__ */ new Set(["conditions", "covered_reasons", "definitions", "exclusions", "endorsements"]);
|
|
7933
7922
|
const contextualForms = (formInventory?.forms ?? []).filter(
|
|
7934
7923
|
(form) => form.pageStart != null && (form.pageEnd ?? form.pageStart) != null
|
|
@@ -8215,6 +8204,139 @@ function createExtractor(config) {
|
|
|
8215
8204
|
ranges.push({ startPage, endPage: previousPage });
|
|
8216
8205
|
return ranges;
|
|
8217
8206
|
}
|
|
8207
|
+
function pageNumberForSpan(span) {
|
|
8208
|
+
return span.pageStart ?? span.location?.startPage ?? span.location?.page;
|
|
8209
|
+
}
|
|
8210
|
+
function spansForPageRange(spans, startPage, endPage) {
|
|
8211
|
+
return spans.filter((span) => {
|
|
8212
|
+
const start = span.pageStart ?? span.location?.startPage ?? span.location?.page;
|
|
8213
|
+
const end = span.pageEnd ?? span.location?.endPage ?? start;
|
|
8214
|
+
return typeof start === "number" && typeof end === "number" && start <= endPage && end >= startPage;
|
|
8215
|
+
});
|
|
8216
|
+
}
|
|
8217
|
+
function inferSectionType(title, text) {
|
|
8218
|
+
const value = `${title} ${text.slice(0, 500)}`.toLowerCase();
|
|
8219
|
+
if (/\bdefinition|defined terms?\b/.test(value)) return "definition";
|
|
8220
|
+
if (/\bexclusion|not covered|does not apply\b/.test(value)) return "exclusion";
|
|
8221
|
+
if (/\bcondition|duties|loss condition|general condition\b/.test(value)) return "condition";
|
|
8222
|
+
if (/\bendorsement|amend|additional insured\b/.test(value)) return "endorsement";
|
|
8223
|
+
if (/\bcovered cause|covered reason|covered peril|cause of loss|perils insured\b/.test(value)) return "covered_reason";
|
|
8224
|
+
if (/\bdeclaration|schedule\b/.test(value)) return "declarations";
|
|
8225
|
+
return "policy_form";
|
|
8226
|
+
}
|
|
8227
|
+
function buildSourceBackedSectionIndex(spans, startPage, endPage) {
|
|
8228
|
+
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);
|
|
8229
|
+
return {
|
|
8230
|
+
sections: candidateSpans.map((span, index) => {
|
|
8231
|
+
const pageStart = span.pageStart ?? span.location?.startPage ?? span.location?.page ?? startPage;
|
|
8232
|
+
const pageEnd = span.pageEnd ?? span.location?.endPage ?? pageStart;
|
|
8233
|
+
const title = span.sectionId ?? span.formNumber ?? firstHeadingLine(span.text) ?? `Policy text page ${pageStart}`;
|
|
8234
|
+
return {
|
|
8235
|
+
title,
|
|
8236
|
+
sectionNumber: span.formNumber,
|
|
8237
|
+
pageStart,
|
|
8238
|
+
pageEnd,
|
|
8239
|
+
type: inferSectionType(title, span.text),
|
|
8240
|
+
excerpt: span.text.slice(0, 240),
|
|
8241
|
+
recordId: `section_index_${pageStart}_${index}`,
|
|
8242
|
+
sourceSpanIds: [span.id],
|
|
8243
|
+
sourceTextHash: span.textHash ?? sourceSpanTextHash(span.text)
|
|
8244
|
+
};
|
|
8245
|
+
})
|
|
8246
|
+
};
|
|
8247
|
+
}
|
|
8248
|
+
function firstHeadingLine(text) {
|
|
8249
|
+
const line = text.split(/\r?\n/).map((item) => item.trim()).find((item) => item.length > 0);
|
|
8250
|
+
if (!line) return void 0;
|
|
8251
|
+
return line.slice(0, 100);
|
|
8252
|
+
}
|
|
8253
|
+
function buildDeterministicFormInventory(spans, pageCount) {
|
|
8254
|
+
if (spans.length === 0) return void 0;
|
|
8255
|
+
const formPattern = /\b([A-Z]{1,4}\s?\d{2,5}(?:\s?\d{2,4})?|[A-Z]{2,8}-\d{2,8})\b/g;
|
|
8256
|
+
const seen = /* @__PURE__ */ new Map();
|
|
8257
|
+
for (const span of spans) {
|
|
8258
|
+
const page = pageNumberForSpan(span);
|
|
8259
|
+
if (!page) continue;
|
|
8260
|
+
const title = firstHeadingLine(span.text) ?? span.sectionId;
|
|
8261
|
+
const matches = /* @__PURE__ */ new Set([
|
|
8262
|
+
...span.formNumber ? [span.formNumber] : [],
|
|
8263
|
+
...Array.from(span.text.slice(0, 1200).matchAll(formPattern), (match) => match[1].trim())
|
|
8264
|
+
]);
|
|
8265
|
+
for (const formNumber of matches) {
|
|
8266
|
+
const key = `${formNumber}:${title ?? ""}`;
|
|
8267
|
+
const existing = seen.get(key);
|
|
8268
|
+
const formType = inferFormType(title ?? "", span.text);
|
|
8269
|
+
if (existing) {
|
|
8270
|
+
existing.pageStart = Math.min(existing.pageStart ?? page, page);
|
|
8271
|
+
existing.pageEnd = Math.max(existing.pageEnd ?? page, page);
|
|
8272
|
+
continue;
|
|
8273
|
+
}
|
|
8274
|
+
seen.set(key, {
|
|
8275
|
+
formNumber,
|
|
8276
|
+
title,
|
|
8277
|
+
formType,
|
|
8278
|
+
pageStart: Math.min(page, pageCount),
|
|
8279
|
+
pageEnd: Math.min(page, pageCount)
|
|
8280
|
+
});
|
|
8281
|
+
}
|
|
8282
|
+
}
|
|
8283
|
+
const forms = [...seen.values()].sort((a, b) => (a.pageStart ?? 0) - (b.pageStart ?? 0));
|
|
8284
|
+
return forms.length > 0 ? { forms } : void 0;
|
|
8285
|
+
}
|
|
8286
|
+
function inferFormType(title, text) {
|
|
8287
|
+
const value = `${title} ${text.slice(0, 700)}`.toLowerCase();
|
|
8288
|
+
if (/\bdeclarations?|schedule\b/.test(value)) return "declarations";
|
|
8289
|
+
if (/\bendorsement|amendatory|additional insured\b/.test(value)) return "endorsement";
|
|
8290
|
+
if (/\bnotice|department of insurance|complaint|privacy\b/.test(value)) return "notice";
|
|
8291
|
+
if (/\bapplication|questionnaire\b/.test(value)) return "application";
|
|
8292
|
+
if (/\bcoverage|policy form|conditions|exclusions|definitions|causes of loss\b/.test(value)) return "coverage";
|
|
8293
|
+
return "other";
|
|
8294
|
+
}
|
|
8295
|
+
function buildDeterministicPageAssignments(spans, pageCount) {
|
|
8296
|
+
if (spans.length === 0) return [];
|
|
8297
|
+
const pageTexts = /* @__PURE__ */ new Map();
|
|
8298
|
+
for (const span of spans) {
|
|
8299
|
+
const page = pageNumberForSpan(span);
|
|
8300
|
+
if (!page) continue;
|
|
8301
|
+
pageTexts.set(page, [pageTexts.get(page), span.sectionId, span.text].filter(Boolean).join("\n"));
|
|
8302
|
+
}
|
|
8303
|
+
return Array.from({ length: pageCount }, (_, index) => {
|
|
8304
|
+
const page = index + 1;
|
|
8305
|
+
const text = pageTexts.get(page) ?? "";
|
|
8306
|
+
const lower = text.toLowerCase();
|
|
8307
|
+
const extractorNames = [];
|
|
8308
|
+
if (/\bdeclarations?|policy period|named insured|producer|schedule\b/.test(lower)) {
|
|
8309
|
+
extractorNames.push("carrier_info", "named_insured", "declarations");
|
|
8310
|
+
}
|
|
8311
|
+
if (/\blimit|deductible|premium|coinsurance|scheduled amount|blanket\b/.test(lower) && /\$|\b\d{2,}(?:,\d{3})*\b/.test(lower)) {
|
|
8312
|
+
extractorNames.push("coverage_limits");
|
|
8313
|
+
}
|
|
8314
|
+
if (/\bpremium|tax|fee|surcharge\b/.test(lower) && /\$/.test(lower)) extractorNames.push("premium_breakdown");
|
|
8315
|
+
if (/\bendorsement|additional insured|amendatory\b/.test(lower)) extractorNames.push("endorsements");
|
|
8316
|
+
if (/\bexclusion|not covered|does not apply\b/.test(lower)) extractorNames.push("exclusions");
|
|
8317
|
+
if (/\bcondition|duties in the event|loss condition|general condition\b/.test(lower)) extractorNames.push("conditions");
|
|
8318
|
+
if (/\bdefinition|defined terms?\b/.test(lower)) extractorNames.push("definitions");
|
|
8319
|
+
if (/\bcovered cause|covered peril|cause of loss|perils insured\b/.test(lower)) extractorNames.push("covered_reasons");
|
|
8320
|
+
if (textIncludesSupplementarySignal(text)) extractorNames.push("supplementary");
|
|
8321
|
+
if (extractorNames.length === 0 && text.trim().length > 180) extractorNames.push("sections");
|
|
8322
|
+
return {
|
|
8323
|
+
localPageNumber: page,
|
|
8324
|
+
extractorNames: [...new Set(extractorNames)],
|
|
8325
|
+
pageRole: inferPageRole(lower),
|
|
8326
|
+
hasScheduleValues: /\$|\b\d{2,}(?:,\d{3})*\b/.test(lower) && /\blimit|deductible|premium|schedule|class|location\b/.test(lower),
|
|
8327
|
+
confidence: text.trim().length > 0 ? 0.8 : 0,
|
|
8328
|
+
notes: "Deterministic source-span page assignment"
|
|
8329
|
+
};
|
|
8330
|
+
});
|
|
8331
|
+
}
|
|
8332
|
+
function inferPageRole(lowerText) {
|
|
8333
|
+
if (/\bdeclarations?|schedule\b/.test(lowerText)) return "declarations_schedule";
|
|
8334
|
+
if (/\bendorsement\b/.test(lowerText)) return "endorsement_form";
|
|
8335
|
+
if (/\bexclusion|condition\b/.test(lowerText)) return "condition_exclusion_form";
|
|
8336
|
+
if (/\bnotice|department of insurance|complaint\b/.test(lowerText)) return "supplementary";
|
|
8337
|
+
if (lowerText.trim()) return "policy_form";
|
|
8338
|
+
return "other";
|
|
8339
|
+
}
|
|
8218
8340
|
function shouldRunLlmReview(mode, report, sourceSpansAvailable) {
|
|
8219
8341
|
if (mode === "skip" || maxReviewRounds <= 0) return false;
|
|
8220
8342
|
if (mode === "always") return true;
|
|
@@ -8250,7 +8372,14 @@ function createExtractor(config) {
|
|
|
8250
8372
|
}
|
|
8251
8373
|
return lines.length > 0 ? lines.join("\n") : "";
|
|
8252
8374
|
}
|
|
8253
|
-
async function runFocusedExtractorTask(task, pdfInput, memory, pageRangeCache, getPageRangePdf, getPageImages, getPageRangeText) {
|
|
8375
|
+
async function runFocusedExtractorTask(task, pdfInput, memory, sourceSpansForSections, pageRangeCache, getPageRangePdf, getPageImages, getPageRangeText) {
|
|
8376
|
+
if (task.extractorName === "sections" && sourceSpansForSections.length > 0) {
|
|
8377
|
+
return {
|
|
8378
|
+
name: "sections",
|
|
8379
|
+
data: buildSourceBackedSectionIndex(sourceSpansForSections, task.startPage, task.endPage),
|
|
8380
|
+
usage: void 0
|
|
8381
|
+
};
|
|
8382
|
+
}
|
|
8254
8383
|
if (task.extractorName === "supplementary") {
|
|
8255
8384
|
const alreadyExtractedSummary = buildAlreadyExtractedSummary(memory);
|
|
8256
8385
|
const budget = resolveBudget("extraction_focused", 4096);
|
|
@@ -8499,6 +8628,17 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8499
8628
|
formInventory = resumed.formInventory;
|
|
8500
8629
|
memory.set("form_inventory", formInventory);
|
|
8501
8630
|
onProgress?.("Resuming from checkpoint (form inventory complete)...");
|
|
8631
|
+
} else if (sourceSpans.length > 0) {
|
|
8632
|
+
formInventory = buildDeterministicFormInventory(sourceSpans, pageCount) ?? { forms: [] };
|
|
8633
|
+
onProgress?.(`Built deterministic form inventory for ${primaryType} ${documentType}.`);
|
|
8634
|
+
memory.set("form_inventory", formInventory);
|
|
8635
|
+
await pipelineCtx.save("form_inventory", {
|
|
8636
|
+
id,
|
|
8637
|
+
pageCount,
|
|
8638
|
+
classifyResult,
|
|
8639
|
+
formInventory,
|
|
8640
|
+
memory: Object.fromEntries(memory)
|
|
8641
|
+
});
|
|
8502
8642
|
} else {
|
|
8503
8643
|
onProgress?.(`Building form inventory for ${primaryType} ${documentType}...`);
|
|
8504
8644
|
const budget = resolveBudget("extraction_form_inventory", 2048);
|
|
@@ -8539,6 +8679,20 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8539
8679
|
if (resumed?.pageAssignments && pipelineCtx.isPhaseComplete("page_map")) {
|
|
8540
8680
|
pageAssignments = resumed.pageAssignments;
|
|
8541
8681
|
onProgress?.("Resuming from checkpoint (page map complete)...");
|
|
8682
|
+
} else if (sourceSpans.length > 0) {
|
|
8683
|
+
onProgress?.(`Mapping document pages from source spans for ${primaryType} ${documentType}...`);
|
|
8684
|
+
pageAssignments = normalizePageAssignments(
|
|
8685
|
+
buildDeterministicPageAssignments(sourceSpans, pageCount),
|
|
8686
|
+
formInventory
|
|
8687
|
+
);
|
|
8688
|
+
await pipelineCtx.save("page_map", {
|
|
8689
|
+
id,
|
|
8690
|
+
pageCount,
|
|
8691
|
+
classifyResult,
|
|
8692
|
+
formInventory,
|
|
8693
|
+
pageAssignments,
|
|
8694
|
+
memory: Object.fromEntries(memory)
|
|
8695
|
+
});
|
|
8542
8696
|
} else {
|
|
8543
8697
|
onProgress?.(`Mapping document pages for ${primaryType} ${documentType}...`);
|
|
8544
8698
|
const chunkSize = 8;
|
|
@@ -8658,6 +8812,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8658
8812
|
task,
|
|
8659
8813
|
extractionPdfInput,
|
|
8660
8814
|
memory,
|
|
8815
|
+
sourceSpans,
|
|
8661
8816
|
completedPageRangePdfCache,
|
|
8662
8817
|
getPageRangePdf,
|
|
8663
8818
|
convertPdfToImages ? getPageImages : void 0,
|
|
@@ -8822,6 +8977,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8822
8977
|
task,
|
|
8823
8978
|
extractionPdfInput,
|
|
8824
8979
|
memory,
|
|
8980
|
+
sourceSpans,
|
|
8825
8981
|
completedPageRangePdfCache,
|
|
8826
8982
|
getPageRangePdf,
|
|
8827
8983
|
convertPdfToImages ? getPageImages : void 0,
|