@claritylabs/cl-sdk 3.0.3 → 3.0.4
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.d.mts +12 -11
- package/dist/index.d.ts +12 -11
- package/dist/index.js +124 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +123 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2301,9 +2301,117 @@ function chunkSourceSpans(spans, options = {}) {
|
|
|
2301
2301
|
flush();
|
|
2302
2302
|
return chunks;
|
|
2303
2303
|
}
|
|
2304
|
+
function normalizeSourceSpans(spans) {
|
|
2305
|
+
const droppedParentSpanIds = /* @__PURE__ */ new Set();
|
|
2306
|
+
const cleaned = [];
|
|
2307
|
+
for (const [index, span] of spans.entries()) {
|
|
2308
|
+
if (span.parentSpanId && droppedParentSpanIds.has(span.parentSpanId)) continue;
|
|
2309
|
+
const normalized = normalizeSourceSpanText(span);
|
|
2310
|
+
if (!normalized) {
|
|
2311
|
+
droppedParentSpanIds.add(span.id);
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
cleaned.push({ ...normalized, __originalIndex: index });
|
|
2315
|
+
}
|
|
2316
|
+
return mergeTextRuns(cleaned).map(({ __originalIndex: _index, ...span }) => span);
|
|
2317
|
+
}
|
|
2304
2318
|
function sourceUnit(span) {
|
|
2305
2319
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
2306
2320
|
}
|
|
2321
|
+
function spanPage(span) {
|
|
2322
|
+
return span.pageStart ?? span.location?.page ?? span.location?.startPage;
|
|
2323
|
+
}
|
|
2324
|
+
function normalizeSourceSpanText(span) {
|
|
2325
|
+
const unit = sourceUnit(span);
|
|
2326
|
+
const text = normalizeWhitespace(span.text);
|
|
2327
|
+
if (!text) return void 0;
|
|
2328
|
+
if (isDiscardableBoilerplate(text, unit)) return void 0;
|
|
2329
|
+
const cleanedText = cleanBoilerplateLines(text);
|
|
2330
|
+
if (!cleanedText) return void 0;
|
|
2331
|
+
if (cleanedText === text) return span;
|
|
2332
|
+
return retextSpan(span, cleanedText, {
|
|
2333
|
+
boilerplateRemoved: "true",
|
|
2334
|
+
removedBoilerplateText: removedBoilerplateLines(text).join(" | ").slice(0, 500)
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
function isDiscardableBoilerplate(text, unit) {
|
|
2338
|
+
const cleaned = normalizeWhitespace(text.replace(/\bColumn\s+\d+:\s*/gi, ""));
|
|
2339
|
+
if (/^SPECIMEN POLICY\s+[-—]\s+FOR TESTING ONLY$/i.test(cleaned)) return true;
|
|
2340
|
+
if (/^Page\s+\d+\s+of\s+\d+$/i.test(cleaned)) return true;
|
|
2341
|
+
if (/^[A-Z]{2,}(?:-[A-Z0-9]{2,})+\s+\d{2}\s+\d{2}$/i.test(cleaned)) return true;
|
|
2342
|
+
if (/^[A-Z]{2,}(?:-[A-Z0-9]{2,})+\s+\d{2}\s+\d{2}\s*\|\s*Page\s+\d+\s+of\s+\d+$/i.test(cleaned)) return true;
|
|
2343
|
+
if (unit === "table_row" && /^[^|]{0,40}\|\s*Page\s+\d+\s+of\s+\d+$/i.test(cleaned)) return true;
|
|
2344
|
+
return false;
|
|
2345
|
+
}
|
|
2346
|
+
function isBoilerplateLine(line) {
|
|
2347
|
+
const cleaned = normalizeWhitespace(line.replace(/\bColumn\s+\d+:\s*/gi, ""));
|
|
2348
|
+
return isDiscardableBoilerplate(cleaned) || /^IMPORTANT NOTICE\s*[-—]\s*/i.test(cleaned) || /^THIS IS A CLAIMS-MADE AND REPORTED POLICY\.? PLEASE READ IT CAREFULLY\.?$/i.test(cleaned);
|
|
2349
|
+
}
|
|
2350
|
+
function removedBoilerplateLines(text) {
|
|
2351
|
+
return text.split(/\s{2,}|\r?\n/).map(normalizeWhitespace).filter((line) => line && isBoilerplateLine(line));
|
|
2352
|
+
}
|
|
2353
|
+
function cleanBoilerplateLines(text) {
|
|
2354
|
+
const withoutInlineBoilerplate = text.replace(/\b(?:Column\s+\d+:\s*)?[A-Z]{2,}(?:-[A-Z0-9]{2,})+\s+\d{2}\s+\d{2}\s+(?:\|\s*)?(?:Column\s+\d+:\s*)?Page\s+\d+\s+of\s+\d+\b/gi, " ").replace(/\bSPECIMEN POLICY\s+[-—]\s+FOR TESTING ONLY\b/gi, " ").replace(/\bPage\s+\d+\s+of\s+\d+\b/gi, " ");
|
|
2355
|
+
const lines = withoutInlineBoilerplate.split(/\r?\n/);
|
|
2356
|
+
const filtered = lines.map(normalizeWhitespace).filter((line) => line && !isBoilerplateLine(line));
|
|
2357
|
+
return normalizeWhitespace(filtered.join(" "));
|
|
2358
|
+
}
|
|
2359
|
+
function shouldMergeTextSpan(left, right) {
|
|
2360
|
+
if (sourceUnit(left) !== "text" || sourceUnit(right) !== "text") return false;
|
|
2361
|
+
if (spanPage(left) !== spanPage(right)) return false;
|
|
2362
|
+
if (left.metadata?.elementType === "title" || right.metadata?.elementType === "title") return false;
|
|
2363
|
+
const leftText = normalizeWhitespace(left.text);
|
|
2364
|
+
const rightText = normalizeWhitespace(right.text);
|
|
2365
|
+
if (!leftText || !rightText) return false;
|
|
2366
|
+
if (/[:.;!?)]$/.test(leftText)) return false;
|
|
2367
|
+
if (/^(?:[A-Z][A-Z0-9 &/(),.-]{8,}|Item\s+\d+|Section\s+\d+|Part\s+[A-Z]\b)/.test(rightText)) return false;
|
|
2368
|
+
return /^[a-z(]/.test(rightText) || /\b(?:a|an|and|any|as|at|by|for|from|in|into|may|must|of|or|that|the|this|to|with|within|you|your)$/i.test(leftText);
|
|
2369
|
+
}
|
|
2370
|
+
function mergeTextRuns(spans) {
|
|
2371
|
+
const result = [];
|
|
2372
|
+
let current;
|
|
2373
|
+
for (const span of spans) {
|
|
2374
|
+
if (current && shouldMergeTextSpan(current, span)) {
|
|
2375
|
+
current = mergeTextSpanPair(current, span);
|
|
2376
|
+
continue;
|
|
2377
|
+
}
|
|
2378
|
+
if (current) result.push(current);
|
|
2379
|
+
current = span;
|
|
2380
|
+
}
|
|
2381
|
+
if (current) result.push(current);
|
|
2382
|
+
return result;
|
|
2383
|
+
}
|
|
2384
|
+
function mergeTextSpanPair(left, right) {
|
|
2385
|
+
const text = normalizeWhitespace(`${left.text} ${right.text}`);
|
|
2386
|
+
const merged = retextSpan(left, text, {
|
|
2387
|
+
mergedSourceSpanIds: [left.metadata?.mergedSourceSpanIds, left.id, right.id, right.metadata?.mergedSourceSpanIds].filter(Boolean).join(","),
|
|
2388
|
+
sourceSpanNormalization: "merged_text_run"
|
|
2389
|
+
});
|
|
2390
|
+
return {
|
|
2391
|
+
...merged,
|
|
2392
|
+
bbox: [...left.bbox ?? [], ...right.bbox ?? []],
|
|
2393
|
+
pageEnd: right.pageEnd ?? left.pageEnd,
|
|
2394
|
+
location: {
|
|
2395
|
+
...left.location,
|
|
2396
|
+
endPage: right.location?.endPage ?? right.pageEnd ?? left.location?.endPage
|
|
2397
|
+
},
|
|
2398
|
+
__originalIndex: left.__originalIndex
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
function retextSpan(span, text, metadata) {
|
|
2402
|
+
const textHash = sourceSpanTextHash(text);
|
|
2403
|
+
return SourceSpanSchema.parse({
|
|
2404
|
+
...span,
|
|
2405
|
+
id: `${span.id.split(":").slice(0, -1).join(":")}:${textHash.slice(0, 12)}`,
|
|
2406
|
+
text,
|
|
2407
|
+
hash: textHash,
|
|
2408
|
+
textHash,
|
|
2409
|
+
metadata: {
|
|
2410
|
+
...span.metadata ?? {},
|
|
2411
|
+
...metadata
|
|
2412
|
+
}
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2307
2415
|
function filterChunkableSourceSpans(spans) {
|
|
2308
2416
|
const rowIds = new Set(
|
|
2309
2417
|
spans.filter((span) => sourceUnit(span) === "table_row").map((span) => span.id)
|
|
@@ -4060,14 +4168,14 @@ function stringArray(value) {
|
|
|
4060
4168
|
function sourceUnit4(span) {
|
|
4061
4169
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
4062
4170
|
}
|
|
4063
|
-
function
|
|
4171
|
+
function spanPage2(span) {
|
|
4064
4172
|
return span.pageStart ?? span.location?.page ?? span.location?.startPage;
|
|
4065
4173
|
}
|
|
4066
4174
|
function spanPageEnd(span) {
|
|
4067
|
-
return span.pageEnd ?? span.location?.endPage ??
|
|
4175
|
+
return span.pageEnd ?? span.location?.endPage ?? spanPage2(span);
|
|
4068
4176
|
}
|
|
4069
4177
|
function sourceSpansForPage(sourceSpans, page) {
|
|
4070
|
-
return sourceSpans.filter((span) =>
|
|
4178
|
+
return sourceSpans.filter((span) => spanPage2(span) === page && sourceUnit4(span) === "page").map((span) => span.id);
|
|
4071
4179
|
}
|
|
4072
4180
|
function nodePageOverlaps(node, record) {
|
|
4073
4181
|
const recordStart = numberValue(record, "pageNumber", "pageStart", "resolvedFromPage");
|
|
@@ -4168,8 +4276,8 @@ function buildNodesFromSourceSpans(sourceSpans) {
|
|
|
4168
4276
|
const unit = sourceUnit4(span);
|
|
4169
4277
|
return unit === "section" || unit === "section_candidate" || unit === "page";
|
|
4170
4278
|
});
|
|
4171
|
-
return candidates.sort((left, right) => (
|
|
4172
|
-
const title = span.sectionId ?? span.formNumber ?? (sourceUnit4(span) === "page" &&
|
|
4279
|
+
return candidates.sort((left, right) => (spanPage2(left) ?? 0) - (spanPage2(right) ?? 0) || left.id.localeCompare(right.id)).map((span, index) => {
|
|
4280
|
+
const title = span.sectionId ?? span.formNumber ?? (sourceUnit4(span) === "page" && spanPage2(span) ? `Page ${spanPage2(span)}` : `Source unit ${index + 1}`);
|
|
4173
4281
|
return {
|
|
4174
4282
|
id: `source:${index}:${slugPart(span.id)}`,
|
|
4175
4283
|
title,
|
|
@@ -4177,7 +4285,7 @@ function buildNodesFromSourceSpans(sourceSpans) {
|
|
|
4177
4285
|
type: sourceUnit4(span),
|
|
4178
4286
|
label: sourceUnit4(span),
|
|
4179
4287
|
level: 1,
|
|
4180
|
-
pageStart:
|
|
4288
|
+
pageStart: spanPage2(span),
|
|
4181
4289
|
pageEnd: spanPageEnd(span),
|
|
4182
4290
|
formNumber: span.formNumber,
|
|
4183
4291
|
excerpt: span.text.slice(0, 500),
|
|
@@ -9257,7 +9365,8 @@ function materializeDocument(params) {
|
|
|
9257
9365
|
};
|
|
9258
9366
|
}
|
|
9259
9367
|
async function runSourceTreeExtraction(params) {
|
|
9260
|
-
|
|
9368
|
+
const sourceSpans = normalizeSourceSpans(params.sourceSpans);
|
|
9369
|
+
let sourceTree = buildDocumentSourceTree(sourceSpans, params.id);
|
|
9261
9370
|
const warnings = [];
|
|
9262
9371
|
let modelCalls = 0;
|
|
9263
9372
|
let callsWithUsage = 0;
|
|
@@ -9293,7 +9402,7 @@ async function runSourceTreeExtraction(params) {
|
|
|
9293
9402
|
maxTokens: budget.maxTokens,
|
|
9294
9403
|
taskKind: "extraction_source_tree",
|
|
9295
9404
|
budgetDiagnostics: budget,
|
|
9296
|
-
providerOptions: { ...params.providerOptions, sourceSpans
|
|
9405
|
+
providerOptions: { ...params.providerOptions, sourceSpans }
|
|
9297
9406
|
},
|
|
9298
9407
|
{
|
|
9299
9408
|
fallback: { labels: [], groups: [] },
|
|
@@ -9314,12 +9423,12 @@ async function runSourceTreeExtraction(params) {
|
|
|
9314
9423
|
}
|
|
9315
9424
|
const deterministicProfile = buildDeterministicOperationalProfile({
|
|
9316
9425
|
sourceTree,
|
|
9317
|
-
sourceSpans
|
|
9426
|
+
sourceSpans
|
|
9318
9427
|
});
|
|
9319
9428
|
let operationalProfile = deterministicProfile;
|
|
9320
9429
|
try {
|
|
9321
9430
|
const validNodeIds = new Set(sourceTree.map((node) => node.id));
|
|
9322
|
-
const validSpanIds = new Set(
|
|
9431
|
+
const validSpanIds = new Set(sourceSpans.map((span) => span.id));
|
|
9323
9432
|
const budget = params.resolveBudget("extraction_operational_profile", 8192);
|
|
9324
9433
|
const startedAt = Date.now();
|
|
9325
9434
|
const response = await safeGenerateObject(
|
|
@@ -9330,7 +9439,7 @@ async function runSourceTreeExtraction(params) {
|
|
|
9330
9439
|
maxTokens: budget.maxTokens,
|
|
9331
9440
|
taskKind: "extraction_operational_profile",
|
|
9332
9441
|
budgetDiagnostics: budget,
|
|
9333
|
-
providerOptions: { ...params.providerOptions, sourceSpans
|
|
9442
|
+
providerOptions: { ...params.providerOptions, sourceSpans, sourceTree }
|
|
9334
9443
|
},
|
|
9335
9444
|
{
|
|
9336
9445
|
fallback: deterministicProfile,
|
|
@@ -9359,8 +9468,8 @@ async function runSourceTreeExtraction(params) {
|
|
|
9359
9468
|
});
|
|
9360
9469
|
return {
|
|
9361
9470
|
sourceTree,
|
|
9362
|
-
sourceSpans
|
|
9363
|
-
sourceChunks: chunkSourceSpans(
|
|
9471
|
+
sourceSpans,
|
|
9472
|
+
sourceChunks: chunkSourceSpans(sourceSpans),
|
|
9364
9473
|
operationalProfile,
|
|
9365
9474
|
document,
|
|
9366
9475
|
chunks: [],
|
|
@@ -14374,6 +14483,7 @@ export {
|
|
|
14374
14483
|
normalizeDoclingDocument,
|
|
14375
14484
|
normalizeDocumentSourceTreePaths,
|
|
14376
14485
|
normalizeForMatch,
|
|
14486
|
+
normalizeSourceSpans,
|
|
14377
14487
|
orderSourceEvidence,
|
|
14378
14488
|
overlayTextOnPdf,
|
|
14379
14489
|
pLimit,
|