@claritylabs/cl-sdk 3.0.2 → 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 +230 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +229 -42
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -327,6 +327,7 @@ __export(index_exports, {
|
|
|
327
327
|
normalizeDoclingDocument: () => normalizeDoclingDocument,
|
|
328
328
|
normalizeDocumentSourceTreePaths: () => normalizeDocumentSourceTreePaths,
|
|
329
329
|
normalizeForMatch: () => normalizeForMatch,
|
|
330
|
+
normalizeSourceSpans: () => normalizeSourceSpans,
|
|
330
331
|
orderSourceEvidence: () => orderSourceEvidence,
|
|
331
332
|
overlayTextOnPdf: () => overlayTextOnPdf,
|
|
332
333
|
pLimit: () => pLimit,
|
|
@@ -2655,9 +2656,117 @@ function chunkSourceSpans(spans, options = {}) {
|
|
|
2655
2656
|
flush();
|
|
2656
2657
|
return chunks;
|
|
2657
2658
|
}
|
|
2659
|
+
function normalizeSourceSpans(spans) {
|
|
2660
|
+
const droppedParentSpanIds = /* @__PURE__ */ new Set();
|
|
2661
|
+
const cleaned = [];
|
|
2662
|
+
for (const [index, span] of spans.entries()) {
|
|
2663
|
+
if (span.parentSpanId && droppedParentSpanIds.has(span.parentSpanId)) continue;
|
|
2664
|
+
const normalized = normalizeSourceSpanText(span);
|
|
2665
|
+
if (!normalized) {
|
|
2666
|
+
droppedParentSpanIds.add(span.id);
|
|
2667
|
+
continue;
|
|
2668
|
+
}
|
|
2669
|
+
cleaned.push({ ...normalized, __originalIndex: index });
|
|
2670
|
+
}
|
|
2671
|
+
return mergeTextRuns(cleaned).map(({ __originalIndex: _index, ...span }) => span);
|
|
2672
|
+
}
|
|
2658
2673
|
function sourceUnit(span) {
|
|
2659
2674
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
2660
2675
|
}
|
|
2676
|
+
function spanPage(span) {
|
|
2677
|
+
return span.pageStart ?? span.location?.page ?? span.location?.startPage;
|
|
2678
|
+
}
|
|
2679
|
+
function normalizeSourceSpanText(span) {
|
|
2680
|
+
const unit = sourceUnit(span);
|
|
2681
|
+
const text = normalizeWhitespace(span.text);
|
|
2682
|
+
if (!text) return void 0;
|
|
2683
|
+
if (isDiscardableBoilerplate(text, unit)) return void 0;
|
|
2684
|
+
const cleanedText = cleanBoilerplateLines(text);
|
|
2685
|
+
if (!cleanedText) return void 0;
|
|
2686
|
+
if (cleanedText === text) return span;
|
|
2687
|
+
return retextSpan(span, cleanedText, {
|
|
2688
|
+
boilerplateRemoved: "true",
|
|
2689
|
+
removedBoilerplateText: removedBoilerplateLines(text).join(" | ").slice(0, 500)
|
|
2690
|
+
});
|
|
2691
|
+
}
|
|
2692
|
+
function isDiscardableBoilerplate(text, unit) {
|
|
2693
|
+
const cleaned = normalizeWhitespace(text.replace(/\bColumn\s+\d+:\s*/gi, ""));
|
|
2694
|
+
if (/^SPECIMEN POLICY\s+[-—]\s+FOR TESTING ONLY$/i.test(cleaned)) return true;
|
|
2695
|
+
if (/^Page\s+\d+\s+of\s+\d+$/i.test(cleaned)) return true;
|
|
2696
|
+
if (/^[A-Z]{2,}(?:-[A-Z0-9]{2,})+\s+\d{2}\s+\d{2}$/i.test(cleaned)) return true;
|
|
2697
|
+
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;
|
|
2698
|
+
if (unit === "table_row" && /^[^|]{0,40}\|\s*Page\s+\d+\s+of\s+\d+$/i.test(cleaned)) return true;
|
|
2699
|
+
return false;
|
|
2700
|
+
}
|
|
2701
|
+
function isBoilerplateLine(line) {
|
|
2702
|
+
const cleaned = normalizeWhitespace(line.replace(/\bColumn\s+\d+:\s*/gi, ""));
|
|
2703
|
+
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);
|
|
2704
|
+
}
|
|
2705
|
+
function removedBoilerplateLines(text) {
|
|
2706
|
+
return text.split(/\s{2,}|\r?\n/).map(normalizeWhitespace).filter((line) => line && isBoilerplateLine(line));
|
|
2707
|
+
}
|
|
2708
|
+
function cleanBoilerplateLines(text) {
|
|
2709
|
+
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, " ");
|
|
2710
|
+
const lines = withoutInlineBoilerplate.split(/\r?\n/);
|
|
2711
|
+
const filtered = lines.map(normalizeWhitespace).filter((line) => line && !isBoilerplateLine(line));
|
|
2712
|
+
return normalizeWhitespace(filtered.join(" "));
|
|
2713
|
+
}
|
|
2714
|
+
function shouldMergeTextSpan(left, right) {
|
|
2715
|
+
if (sourceUnit(left) !== "text" || sourceUnit(right) !== "text") return false;
|
|
2716
|
+
if (spanPage(left) !== spanPage(right)) return false;
|
|
2717
|
+
if (left.metadata?.elementType === "title" || right.metadata?.elementType === "title") return false;
|
|
2718
|
+
const leftText = normalizeWhitespace(left.text);
|
|
2719
|
+
const rightText = normalizeWhitespace(right.text);
|
|
2720
|
+
if (!leftText || !rightText) return false;
|
|
2721
|
+
if (/[:.;!?)]$/.test(leftText)) return false;
|
|
2722
|
+
if (/^(?:[A-Z][A-Z0-9 &/(),.-]{8,}|Item\s+\d+|Section\s+\d+|Part\s+[A-Z]\b)/.test(rightText)) return false;
|
|
2723
|
+
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);
|
|
2724
|
+
}
|
|
2725
|
+
function mergeTextRuns(spans) {
|
|
2726
|
+
const result = [];
|
|
2727
|
+
let current;
|
|
2728
|
+
for (const span of spans) {
|
|
2729
|
+
if (current && shouldMergeTextSpan(current, span)) {
|
|
2730
|
+
current = mergeTextSpanPair(current, span);
|
|
2731
|
+
continue;
|
|
2732
|
+
}
|
|
2733
|
+
if (current) result.push(current);
|
|
2734
|
+
current = span;
|
|
2735
|
+
}
|
|
2736
|
+
if (current) result.push(current);
|
|
2737
|
+
return result;
|
|
2738
|
+
}
|
|
2739
|
+
function mergeTextSpanPair(left, right) {
|
|
2740
|
+
const text = normalizeWhitespace(`${left.text} ${right.text}`);
|
|
2741
|
+
const merged = retextSpan(left, text, {
|
|
2742
|
+
mergedSourceSpanIds: [left.metadata?.mergedSourceSpanIds, left.id, right.id, right.metadata?.mergedSourceSpanIds].filter(Boolean).join(","),
|
|
2743
|
+
sourceSpanNormalization: "merged_text_run"
|
|
2744
|
+
});
|
|
2745
|
+
return {
|
|
2746
|
+
...merged,
|
|
2747
|
+
bbox: [...left.bbox ?? [], ...right.bbox ?? []],
|
|
2748
|
+
pageEnd: right.pageEnd ?? left.pageEnd,
|
|
2749
|
+
location: {
|
|
2750
|
+
...left.location,
|
|
2751
|
+
endPage: right.location?.endPage ?? right.pageEnd ?? left.location?.endPage
|
|
2752
|
+
},
|
|
2753
|
+
__originalIndex: left.__originalIndex
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
function retextSpan(span, text, metadata) {
|
|
2757
|
+
const textHash = sourceSpanTextHash(text);
|
|
2758
|
+
return SourceSpanSchema.parse({
|
|
2759
|
+
...span,
|
|
2760
|
+
id: `${span.id.split(":").slice(0, -1).join(":")}:${textHash.slice(0, 12)}`,
|
|
2761
|
+
text,
|
|
2762
|
+
hash: textHash,
|
|
2763
|
+
textHash,
|
|
2764
|
+
metadata: {
|
|
2765
|
+
...span.metadata ?? {},
|
|
2766
|
+
...metadata
|
|
2767
|
+
}
|
|
2768
|
+
});
|
|
2769
|
+
}
|
|
2661
2770
|
function filterChunkableSourceSpans(spans) {
|
|
2662
2771
|
const rowIds = new Set(
|
|
2663
2772
|
spans.filter((span) => sourceUnit(span) === "table_row").map((span) => span.id)
|
|
@@ -4406,14 +4515,14 @@ function stringArray(value) {
|
|
|
4406
4515
|
function sourceUnit4(span) {
|
|
4407
4516
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
4408
4517
|
}
|
|
4409
|
-
function
|
|
4518
|
+
function spanPage2(span) {
|
|
4410
4519
|
return span.pageStart ?? span.location?.page ?? span.location?.startPage;
|
|
4411
4520
|
}
|
|
4412
4521
|
function spanPageEnd(span) {
|
|
4413
|
-
return span.pageEnd ?? span.location?.endPage ??
|
|
4522
|
+
return span.pageEnd ?? span.location?.endPage ?? spanPage2(span);
|
|
4414
4523
|
}
|
|
4415
4524
|
function sourceSpansForPage(sourceSpans, page) {
|
|
4416
|
-
return sourceSpans.filter((span) =>
|
|
4525
|
+
return sourceSpans.filter((span) => spanPage2(span) === page && sourceUnit4(span) === "page").map((span) => span.id);
|
|
4417
4526
|
}
|
|
4418
4527
|
function nodePageOverlaps(node, record) {
|
|
4419
4528
|
const recordStart = numberValue(record, "pageNumber", "pageStart", "resolvedFromPage");
|
|
@@ -4514,8 +4623,8 @@ function buildNodesFromSourceSpans(sourceSpans) {
|
|
|
4514
4623
|
const unit = sourceUnit4(span);
|
|
4515
4624
|
return unit === "section" || unit === "section_candidate" || unit === "page";
|
|
4516
4625
|
});
|
|
4517
|
-
return candidates.sort((left, right) => (
|
|
4518
|
-
const title = span.sectionId ?? span.formNumber ?? (sourceUnit4(span) === "page" &&
|
|
4626
|
+
return candidates.sort((left, right) => (spanPage2(left) ?? 0) - (spanPage2(right) ?? 0) || left.id.localeCompare(right.id)).map((span, index) => {
|
|
4627
|
+
const title = span.sectionId ?? span.formNumber ?? (sourceUnit4(span) === "page" && spanPage2(span) ? `Page ${spanPage2(span)}` : `Source unit ${index + 1}`);
|
|
4519
4628
|
return {
|
|
4520
4629
|
id: `source:${index}:${slugPart(span.id)}`,
|
|
4521
4630
|
title,
|
|
@@ -4523,7 +4632,7 @@ function buildNodesFromSourceSpans(sourceSpans) {
|
|
|
4523
4632
|
type: sourceUnit4(span),
|
|
4524
4633
|
label: sourceUnit4(span),
|
|
4525
4634
|
level: 1,
|
|
4526
|
-
pageStart:
|
|
4635
|
+
pageStart: spanPage2(span),
|
|
4527
4636
|
pageEnd: spanPageEnd(span),
|
|
4528
4637
|
formNumber: span.formNumber,
|
|
4529
4638
|
excerpt: span.text.slice(0, 500),
|
|
@@ -9236,6 +9345,8 @@ var ORGANIZABLE_KINDS = [
|
|
|
9236
9345
|
"schedule",
|
|
9237
9346
|
"clause"
|
|
9238
9347
|
];
|
|
9348
|
+
var ORGANIZATION_TOP_LEVEL_BATCH_SIZE = 80;
|
|
9349
|
+
var ORGANIZATION_CHILD_CONTEXT_LIMIT = 4;
|
|
9239
9350
|
var SourceTreeOrganizationSchema = import_zod41.z.object({
|
|
9240
9351
|
labels: import_zod41.z.array(import_zod41.z.object({
|
|
9241
9352
|
nodeId: import_zod41.z.string(),
|
|
@@ -9300,7 +9411,7 @@ function cleanText(value, fallback) {
|
|
|
9300
9411
|
const text = value?.replace(/\s+/g, " ").trim();
|
|
9301
9412
|
return text || fallback;
|
|
9302
9413
|
}
|
|
9303
|
-
function compactNode(node) {
|
|
9414
|
+
function compactNode(node, maxText = 700) {
|
|
9304
9415
|
return {
|
|
9305
9416
|
id: node.id,
|
|
9306
9417
|
kind: node.kind,
|
|
@@ -9309,20 +9420,89 @@ function compactNode(node) {
|
|
|
9309
9420
|
pageStart: node.pageStart,
|
|
9310
9421
|
pageEnd: node.pageEnd,
|
|
9311
9422
|
sourceSpanIds: node.sourceSpanIds.slice(0, 8),
|
|
9312
|
-
text: (node.textExcerpt ?? node.description).slice(0,
|
|
9423
|
+
text: (node.textExcerpt ?? node.description).slice(0, maxText)
|
|
9313
9424
|
};
|
|
9314
9425
|
}
|
|
9315
|
-
function
|
|
9316
|
-
const
|
|
9426
|
+
function nodesByParent(sourceTree) {
|
|
9427
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
9428
|
+
for (const node of sourceTree) {
|
|
9429
|
+
const children = byParent.get(node.parentId) ?? [];
|
|
9430
|
+
children.push(node);
|
|
9431
|
+
byParent.set(node.parentId, children);
|
|
9432
|
+
}
|
|
9433
|
+
for (const children of byParent.values()) {
|
|
9434
|
+
children.sort((left, right) => left.order - right.order || left.id.localeCompare(right.id));
|
|
9435
|
+
}
|
|
9436
|
+
return byParent;
|
|
9437
|
+
}
|
|
9438
|
+
function sourceTreeRootId(sourceTree) {
|
|
9439
|
+
return sourceTree.find((node) => node.kind === "document")?.id;
|
|
9440
|
+
}
|
|
9441
|
+
function organizationBatches(sourceTree) {
|
|
9442
|
+
const byParent = nodesByParent(sourceTree);
|
|
9443
|
+
const rootId = sourceTreeRootId(sourceTree);
|
|
9444
|
+
const topLevelNodes = (byParent.get(rootId) ?? []).filter((node) => node.kind !== "document");
|
|
9445
|
+
if (topLevelNodes.length === 0) {
|
|
9446
|
+
const nodes = sourceTree.filter((node) => node.kind !== "document").slice(0, 240);
|
|
9447
|
+
return [{
|
|
9448
|
+
label: "fallback node prefix because no document root children were found",
|
|
9449
|
+
topLevelNodeIds: nodes.map((node) => node.id),
|
|
9450
|
+
nodes
|
|
9451
|
+
}];
|
|
9452
|
+
}
|
|
9453
|
+
const batches = [];
|
|
9454
|
+
for (let index = 0; index < topLevelNodes.length; index += ORGANIZATION_TOP_LEVEL_BATCH_SIZE) {
|
|
9455
|
+
const topLevelBatch = topLevelNodes.slice(index, index + ORGANIZATION_TOP_LEVEL_BATCH_SIZE);
|
|
9456
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
9457
|
+
for (const node of topLevelBatch) {
|
|
9458
|
+
candidates.set(node.id, node);
|
|
9459
|
+
const childContext = (byParent.get(node.id) ?? []).filter((child) => child.kind !== "text" && child.kind !== "table_cell").slice(0, ORGANIZATION_CHILD_CONTEXT_LIMIT);
|
|
9460
|
+
for (const child of childContext) {
|
|
9461
|
+
candidates.set(child.id, child);
|
|
9462
|
+
}
|
|
9463
|
+
}
|
|
9464
|
+
batches.push({
|
|
9465
|
+
label: `top-level nodes ${index + 1}-${index + topLevelBatch.length} of ${topLevelNodes.length}`,
|
|
9466
|
+
topLevelNodeIds: topLevelBatch.map((node) => node.id),
|
|
9467
|
+
nodes: [...candidates.values()]
|
|
9468
|
+
});
|
|
9469
|
+
}
|
|
9470
|
+
return batches;
|
|
9471
|
+
}
|
|
9472
|
+
function mergeOrganizationResults(results) {
|
|
9473
|
+
const labels = /* @__PURE__ */ new Map();
|
|
9474
|
+
const groups = /* @__PURE__ */ new Map();
|
|
9475
|
+
for (const result of results) {
|
|
9476
|
+
for (const label of result.labels) {
|
|
9477
|
+
labels.set(label.nodeId, { ...labels.get(label.nodeId), ...label });
|
|
9478
|
+
}
|
|
9479
|
+
for (const group of result.groups) {
|
|
9480
|
+
const key = `${group.kind}:${group.childNodeIds.join("|")}`;
|
|
9481
|
+
groups.set(key, group);
|
|
9482
|
+
}
|
|
9483
|
+
}
|
|
9484
|
+
return {
|
|
9485
|
+
labels: [...labels.values()],
|
|
9486
|
+
groups: [...groups.values()]
|
|
9487
|
+
};
|
|
9488
|
+
}
|
|
9489
|
+
function buildOrganizationPrompt(batch) {
|
|
9490
|
+
const nodes = batch.nodes.map((node) => compactNode(node, node.kind === "page" ? 900 : 320));
|
|
9317
9491
|
return `You organize an insurance document source tree.
|
|
9318
9492
|
|
|
9493
|
+
Scope:
|
|
9494
|
+
- ${batch.label}
|
|
9495
|
+
- The provided list is a bounded extraction-time batch. It is not necessarily the whole document.
|
|
9496
|
+
- Top-level page/form candidates in this batch: ${JSON.stringify(batch.topLevelNodeIds)}
|
|
9497
|
+
|
|
9319
9498
|
Rules:
|
|
9320
9499
|
- Use only node IDs from the provided list.
|
|
9321
9500
|
- Do not invent text, page numbers, source spans, limits, or policy facts.
|
|
9322
|
-
- You may relabel existing nodes and group adjacent top-level/page nodes when they are clearly one form, endorsement, declarations set, schedule, or clause family.
|
|
9501
|
+
- You may relabel existing nodes and group adjacent top-level/page nodes from this batch when they are clearly one form, endorsement, declarations set, schedule, or clause family.
|
|
9323
9502
|
- Add concise, human-readable titles to generic text, table, row, and cell nodes when the text makes their role clear.
|
|
9324
9503
|
- Groups must list existing childNodeIds only.
|
|
9325
9504
|
- Keep descriptions short and useful for search.
|
|
9505
|
+
- Prefer the document's own form titles, endorsement titles, schedules, declarations headings, and page order over keyword-only guessing.
|
|
9326
9506
|
|
|
9327
9507
|
Source nodes:
|
|
9328
9508
|
${JSON.stringify(nodes, null, 2)}
|
|
@@ -9362,8 +9542,9 @@ function groupNodeId(documentId, group) {
|
|
|
9362
9542
|
}
|
|
9363
9543
|
function applyOrganization(sourceTree, organization) {
|
|
9364
9544
|
const byId = new Map(sourceTree.map((node) => [node.id, node]));
|
|
9545
|
+
const labels = new Map(organization.labels.map((label) => [label.nodeId, label]));
|
|
9365
9546
|
let nextTree = sourceTree.map((node) => {
|
|
9366
|
-
const label =
|
|
9547
|
+
const label = labels.get(node.id);
|
|
9367
9548
|
if (!label) return node;
|
|
9368
9549
|
return {
|
|
9369
9550
|
...node,
|
|
@@ -9372,7 +9553,7 @@ function applyOrganization(sourceTree, organization) {
|
|
|
9372
9553
|
description: cleanText(label.description, node.description)
|
|
9373
9554
|
};
|
|
9374
9555
|
});
|
|
9375
|
-
for (const group of organization.groups
|
|
9556
|
+
for (const group of organization.groups) {
|
|
9376
9557
|
const children = group.childNodeIds.map((id2) => byId.get(id2)).filter((node2) => Boolean(node2));
|
|
9377
9558
|
if (children.length === 0) continue;
|
|
9378
9559
|
const parentId = children[0].parentId;
|
|
@@ -9531,7 +9712,8 @@ function materializeDocument(params) {
|
|
|
9531
9712
|
};
|
|
9532
9713
|
}
|
|
9533
9714
|
async function runSourceTreeExtraction(params) {
|
|
9534
|
-
|
|
9715
|
+
const sourceSpans = normalizeSourceSpans(params.sourceSpans);
|
|
9716
|
+
let sourceTree = buildDocumentSourceTree(sourceSpans, params.id);
|
|
9535
9717
|
const warnings = [];
|
|
9536
9718
|
let modelCalls = 0;
|
|
9537
9719
|
let callsWithUsage = 0;
|
|
@@ -9554,41 +9736,46 @@ async function runSourceTreeExtraction(params) {
|
|
|
9554
9736
|
params.trackUsage(usage, report);
|
|
9555
9737
|
};
|
|
9556
9738
|
try {
|
|
9557
|
-
const
|
|
9558
|
-
const
|
|
9559
|
-
const
|
|
9560
|
-
params.
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9739
|
+
const organizations = [];
|
|
9740
|
+
const batches = organizationBatches(sourceTree);
|
|
9741
|
+
for (const [batchIndex, batch] of batches.entries()) {
|
|
9742
|
+
const budget = params.resolveBudget("extraction_source_tree", 4096);
|
|
9743
|
+
const startedAt = Date.now();
|
|
9744
|
+
const response = await safeGenerateObject(
|
|
9745
|
+
params.generateObject,
|
|
9746
|
+
{
|
|
9747
|
+
prompt: buildOrganizationPrompt(batch),
|
|
9748
|
+
schema: SourceTreeOrganizationSchema,
|
|
9749
|
+
maxTokens: budget.maxTokens,
|
|
9750
|
+
taskKind: "extraction_source_tree",
|
|
9751
|
+
budgetDiagnostics: budget,
|
|
9752
|
+
providerOptions: { ...params.providerOptions, sourceSpans }
|
|
9753
|
+
},
|
|
9754
|
+
{
|
|
9755
|
+
fallback: { labels: [], groups: [] },
|
|
9756
|
+
log: params.log
|
|
9757
|
+
}
|
|
9758
|
+
);
|
|
9759
|
+
localTrack(response.usage, {
|
|
9565
9760
|
taskKind: "extraction_source_tree",
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
);
|
|
9574
|
-
localTrack(response.usage, {
|
|
9575
|
-
taskKind: "extraction_source_tree",
|
|
9576
|
-
label: "source_tree_organizer",
|
|
9577
|
-
maxTokens: budget.maxTokens,
|
|
9578
|
-
durationMs: Date.now() - startedAt
|
|
9579
|
-
});
|
|
9580
|
-
sourceTree = applyOrganization(sourceTree, response.object);
|
|
9761
|
+
label: batches.length > 1 ? `source_tree_organizer_${batchIndex + 1}` : "source_tree_organizer",
|
|
9762
|
+
maxTokens: budget.maxTokens,
|
|
9763
|
+
durationMs: Date.now() - startedAt
|
|
9764
|
+
});
|
|
9765
|
+
organizations.push(response.object);
|
|
9766
|
+
}
|
|
9767
|
+
sourceTree = applyOrganization(sourceTree, mergeOrganizationResults(organizations));
|
|
9581
9768
|
} catch (error) {
|
|
9582
9769
|
warnings.push(`Source-tree organizer failed; deterministic tree used (${error instanceof Error ? error.message : String(error)})`);
|
|
9583
9770
|
}
|
|
9584
9771
|
const deterministicProfile = buildDeterministicOperationalProfile({
|
|
9585
9772
|
sourceTree,
|
|
9586
|
-
sourceSpans
|
|
9773
|
+
sourceSpans
|
|
9587
9774
|
});
|
|
9588
9775
|
let operationalProfile = deterministicProfile;
|
|
9589
9776
|
try {
|
|
9590
9777
|
const validNodeIds = new Set(sourceTree.map((node) => node.id));
|
|
9591
|
-
const validSpanIds = new Set(
|
|
9778
|
+
const validSpanIds = new Set(sourceSpans.map((span) => span.id));
|
|
9592
9779
|
const budget = params.resolveBudget("extraction_operational_profile", 8192);
|
|
9593
9780
|
const startedAt = Date.now();
|
|
9594
9781
|
const response = await safeGenerateObject(
|
|
@@ -9599,7 +9786,7 @@ async function runSourceTreeExtraction(params) {
|
|
|
9599
9786
|
maxTokens: budget.maxTokens,
|
|
9600
9787
|
taskKind: "extraction_operational_profile",
|
|
9601
9788
|
budgetDiagnostics: budget,
|
|
9602
|
-
providerOptions: { ...params.providerOptions, sourceSpans
|
|
9789
|
+
providerOptions: { ...params.providerOptions, sourceSpans, sourceTree }
|
|
9603
9790
|
},
|
|
9604
9791
|
{
|
|
9605
9792
|
fallback: deterministicProfile,
|
|
@@ -9628,8 +9815,8 @@ async function runSourceTreeExtraction(params) {
|
|
|
9628
9815
|
});
|
|
9629
9816
|
return {
|
|
9630
9817
|
sourceTree,
|
|
9631
|
-
sourceSpans
|
|
9632
|
-
sourceChunks: chunkSourceSpans(
|
|
9818
|
+
sourceSpans,
|
|
9819
|
+
sourceChunks: chunkSourceSpans(sourceSpans),
|
|
9633
9820
|
operationalProfile,
|
|
9634
9821
|
document,
|
|
9635
9822
|
chunks: [],
|
|
@@ -14644,6 +14831,7 @@ var AGENT_TOOLS = [
|
|
|
14644
14831
|
normalizeDoclingDocument,
|
|
14645
14832
|
normalizeDocumentSourceTreePaths,
|
|
14646
14833
|
normalizeForMatch,
|
|
14834
|
+
normalizeSourceSpans,
|
|
14647
14835
|
orderSourceEvidence,
|
|
14648
14836
|
overlayTextOnPdf,
|
|
14649
14837
|
pLimit,
|