@claritylabs/cl-sdk 1.3.1 → 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/README.md +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +174 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +174 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -223,7 +223,8 @@ function resolveModelBudget(params) {
|
|
|
223
223
|
const schemaTokens = estimateTokens(params.schemaSizeBytes) ?? 0;
|
|
224
224
|
const expectedListLength = positiveInteger(params.expectedListLength) ?? 0;
|
|
225
225
|
const warnings = [];
|
|
226
|
-
|
|
226
|
+
const preferredOutputTokens = constrainedPreference ?? taskCapability ?? longListCapability ?? defaultCapability ?? hintTokens;
|
|
227
|
+
let maxTokens = hardMaxOutputTokens ?? modelMaxOutputTokens ?? preferredOutputTokens;
|
|
227
228
|
if (minOutputTokens) {
|
|
228
229
|
maxTokens = Math.max(maxTokens, minOutputTokens);
|
|
229
230
|
}
|
|
@@ -252,6 +253,7 @@ function resolveModelBudget(params) {
|
|
|
252
253
|
taskKind,
|
|
253
254
|
maxTokens,
|
|
254
255
|
hintTokens,
|
|
256
|
+
preferredOutputTokens,
|
|
255
257
|
modelMaxOutputTokens,
|
|
256
258
|
hardMaxOutputTokens,
|
|
257
259
|
estimatedInputTokens,
|
|
@@ -7855,7 +7857,7 @@ function normalizePageAssignments(pageAssignments, formInventory) {
|
|
|
7855
7857
|
}
|
|
7856
7858
|
return pageAssignments.map((assignment) => {
|
|
7857
7859
|
let extractorNames = [...new Set(
|
|
7858
|
-
|
|
7860
|
+
assignment.extractorNames.filter(Boolean)
|
|
7859
7861
|
)];
|
|
7860
7862
|
const hasDeclarations = extractorNames.includes("declarations");
|
|
7861
7863
|
const hasConditions = extractorNames.includes("conditions");
|
|
@@ -7874,9 +7876,6 @@ function normalizePageAssignments(pageAssignments, formInventory) {
|
|
|
7874
7876
|
if (inventoryTypes?.has("endorsement") && !extractorNames.includes("endorsements")) {
|
|
7875
7877
|
extractorNames = [...extractorNames, "endorsements"];
|
|
7876
7878
|
}
|
|
7877
|
-
if (extractorNames.length === 0) {
|
|
7878
|
-
extractorNames = ["sections"];
|
|
7879
|
-
}
|
|
7880
7879
|
return {
|
|
7881
7880
|
...assignment,
|
|
7882
7881
|
extractorNames
|
|
@@ -7913,20 +7912,12 @@ function groupContiguousPages(pages) {
|
|
|
7913
7912
|
function buildPlanFromPageAssignments(pageAssignments, pageCount, formInventory) {
|
|
7914
7913
|
const extractorPages = /* @__PURE__ */ new Map();
|
|
7915
7914
|
for (const assignment of pageAssignments) {
|
|
7916
|
-
const
|
|
7915
|
+
const focusedExtractors = assignment.extractorNames.filter((name) => name !== "sections");
|
|
7916
|
+
const extractors = focusedExtractors.length > 0 ? focusedExtractors : assignment.extractorNames;
|
|
7917
7917
|
for (const extractorName of extractors) {
|
|
7918
7918
|
extractorPages.set(extractorName, [...extractorPages.get(extractorName) ?? [], assignment.localPageNumber]);
|
|
7919
7919
|
}
|
|
7920
7920
|
}
|
|
7921
|
-
const coveredPages = /* @__PURE__ */ new Set();
|
|
7922
|
-
for (const pages of extractorPages.values()) {
|
|
7923
|
-
for (const page of pages) coveredPages.add(page);
|
|
7924
|
-
}
|
|
7925
|
-
for (let page = 1; page <= pageCount; page += 1) {
|
|
7926
|
-
if (!coveredPages.has(page)) {
|
|
7927
|
-
extractorPages.set("sections", [...extractorPages.get("sections") ?? [], page]);
|
|
7928
|
-
}
|
|
7929
|
-
}
|
|
7930
7921
|
const contextualExtractors = /* @__PURE__ */ new Set(["conditions", "covered_reasons", "definitions", "exclusions", "endorsements"]);
|
|
7931
7922
|
const contextualForms = (formInventory?.forms ?? []).filter(
|
|
7932
7923
|
(form) => form.pageStart != null && (form.pageEnd ?? form.pageStart) != null
|
|
@@ -8213,6 +8204,139 @@ function createExtractor(config) {
|
|
|
8213
8204
|
ranges.push({ startPage, endPage: previousPage });
|
|
8214
8205
|
return ranges;
|
|
8215
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
|
+
}
|
|
8216
8340
|
function shouldRunLlmReview(mode, report, sourceSpansAvailable) {
|
|
8217
8341
|
if (mode === "skip" || maxReviewRounds <= 0) return false;
|
|
8218
8342
|
if (mode === "always") return true;
|
|
@@ -8248,7 +8372,14 @@ function createExtractor(config) {
|
|
|
8248
8372
|
}
|
|
8249
8373
|
return lines.length > 0 ? lines.join("\n") : "";
|
|
8250
8374
|
}
|
|
8251
|
-
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
|
+
}
|
|
8252
8383
|
if (task.extractorName === "supplementary") {
|
|
8253
8384
|
const alreadyExtractedSummary = buildAlreadyExtractedSummary(memory);
|
|
8254
8385
|
const budget = resolveBudget("extraction_focused", 4096);
|
|
@@ -8497,6 +8628,17 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8497
8628
|
formInventory = resumed.formInventory;
|
|
8498
8629
|
memory.set("form_inventory", formInventory);
|
|
8499
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
|
+
});
|
|
8500
8642
|
} else {
|
|
8501
8643
|
onProgress?.(`Building form inventory for ${primaryType} ${documentType}...`);
|
|
8502
8644
|
const budget = resolveBudget("extraction_form_inventory", 2048);
|
|
@@ -8537,6 +8679,20 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8537
8679
|
if (resumed?.pageAssignments && pipelineCtx.isPhaseComplete("page_map")) {
|
|
8538
8680
|
pageAssignments = resumed.pageAssignments;
|
|
8539
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
|
+
});
|
|
8540
8696
|
} else {
|
|
8541
8697
|
onProgress?.(`Mapping document pages for ${primaryType} ${documentType}...`);
|
|
8542
8698
|
const chunkSize = 8;
|
|
@@ -8656,6 +8812,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8656
8812
|
task,
|
|
8657
8813
|
extractionPdfInput,
|
|
8658
8814
|
memory,
|
|
8815
|
+
sourceSpans,
|
|
8659
8816
|
completedPageRangePdfCache,
|
|
8660
8817
|
getPageRangePdf,
|
|
8661
8818
|
convertPdfToImages ? getPageImages : void 0,
|
|
@@ -8820,6 +8977,7 @@ ${pageText || "(No Docling text was available for this page range.)"}`;
|
|
|
8820
8977
|
task,
|
|
8821
8978
|
extractionPdfInput,
|
|
8822
8979
|
memory,
|
|
8980
|
+
sourceSpans,
|
|
8823
8981
|
completedPageRangePdfCache,
|
|
8824
8982
|
getPageRangePdf,
|
|
8825
8983
|
convertPdfToImages ? getPageImages : void 0,
|