@claritylabs/cl-sdk 2.0.1 → 3.0.1
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 +12 -11
- package/dist/index.d.mts +692 -20
- package/dist/index.d.ts +692 -20
- package/dist/index.js +1385 -253
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1374 -253
- package/dist/index.mjs.map +1 -1
- package/dist/storage-sqlite.d.mts +104 -0
- package/dist/storage-sqlite.d.ts +104 -0
- package/dist/storage-sqlite.js +80 -0
- package/dist/storage-sqlite.js.map +1 -1
- package/dist/storage-sqlite.mjs +80 -0
- package/dist/storage-sqlite.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -107,6 +107,8 @@ __export(index_exports, {
|
|
|
107
107
|
DocumentMetadataSchema: () => DocumentMetadataSchema,
|
|
108
108
|
DocumentNodeSchema: () => DocumentNodeSchema,
|
|
109
109
|
DocumentPageMapEntrySchema: () => DocumentPageMapEntrySchema,
|
|
110
|
+
DocumentSourceNodeKindSchema: () => DocumentSourceNodeKindSchema,
|
|
111
|
+
DocumentSourceNodeSchema: () => DocumentSourceNodeSchema,
|
|
110
112
|
DocumentTableOfContentsEntrySchema: () => DocumentTableOfContentsEntrySchema,
|
|
111
113
|
DocumentTypeSchema: () => DocumentTypeSchema,
|
|
112
114
|
DriverRecordSchema: () => DriverRecordSchema,
|
|
@@ -162,6 +164,9 @@ __export(index_exports, {
|
|
|
162
164
|
MemorySourceStore: () => MemorySourceStore,
|
|
163
165
|
MissingInfoQuestionSchema: () => MissingInfoQuestionSchema,
|
|
164
166
|
NamedInsuredSchema: () => NamedInsuredSchema,
|
|
167
|
+
OperationalCoverageLineSchema: () => OperationalCoverageLineSchema,
|
|
168
|
+
OperationalEndorsementSupportSchema: () => OperationalEndorsementSupportSchema,
|
|
169
|
+
OperationalPartySchema: () => OperationalPartySchema,
|
|
165
170
|
PERSONAL_AUTO_USAGES: () => PERSONAL_AUTO_USAGES,
|
|
166
171
|
PET_SPECIES: () => PET_SPECIES,
|
|
167
172
|
PLATFORM_CONFIGS: () => PLATFORM_CONFIGS,
|
|
@@ -191,6 +196,7 @@ __export(index_exports, {
|
|
|
191
196
|
PolicyChangeStatusSchema: () => PolicyChangeStatusSchema,
|
|
192
197
|
PolicyConditionSchema: () => PolicyConditionSchema,
|
|
193
198
|
PolicyDocumentSchema: () => PolicyDocumentSchema,
|
|
199
|
+
PolicyOperationalProfileSchema: () => PolicyOperationalProfileSchema,
|
|
194
200
|
PolicySectionTypeSchema: () => PolicySectionTypeSchema,
|
|
195
201
|
PolicyTermTypeSchema: () => PolicyTermTypeSchema,
|
|
196
202
|
PolicyTypeSchema: () => PolicyTypeSchema,
|
|
@@ -222,6 +228,7 @@ __export(index_exports, {
|
|
|
222
228
|
ScheduledItemCategorySchema: () => ScheduledItemCategorySchema,
|
|
223
229
|
SectionSchema: () => SectionSchema,
|
|
224
230
|
SharedLimitSchema: () => SharedLimitSchema,
|
|
231
|
+
SourceBackedValueSchema: () => SourceBackedValueSchema,
|
|
225
232
|
SourceChunkSchema: () => SourceChunkSchema,
|
|
226
233
|
SourceKindSchema: () => SourceKindSchema,
|
|
227
234
|
SourceSpanBBoxSchema: () => SourceSpanBBoxSchema,
|
|
@@ -263,7 +270,9 @@ __export(index_exports, {
|
|
|
263
270
|
buildConfirmationSummaryPrompt: () => buildConfirmationSummaryPrompt,
|
|
264
271
|
buildConversationMemoryGuidance: () => buildConversationMemoryGuidance,
|
|
265
272
|
buildCoverageGapPrompt: () => buildCoverageGapPrompt,
|
|
273
|
+
buildDeterministicOperationalProfile: () => buildDeterministicOperationalProfile,
|
|
266
274
|
buildDoclingProviderOptions: () => buildDoclingProviderOptions,
|
|
275
|
+
buildDocumentSourceTree: () => buildDocumentSourceTree,
|
|
267
276
|
buildFieldExplanationPrompt: () => buildFieldExplanationPrompt,
|
|
268
277
|
buildFieldExtractionPrompt: () => buildFieldExtractionPrompt,
|
|
269
278
|
buildFlatPdfMappingPrompt: () => buildFlatPdfMappingPrompt,
|
|
@@ -312,9 +321,11 @@ __export(index_exports, {
|
|
|
312
321
|
getTemplate: () => getTemplate,
|
|
313
322
|
isDoclingExtractionInput: () => isDoclingExtractionInput,
|
|
314
323
|
isFileReference: () => isFileReference,
|
|
324
|
+
mergeOperationalProfile: () => mergeOperationalProfile,
|
|
315
325
|
mergeQuestionAnswers: () => mergeQuestionAnswers,
|
|
316
326
|
mergeSourceSpans: () => mergeSourceSpans,
|
|
317
327
|
normalizeDoclingDocument: () => normalizeDoclingDocument,
|
|
328
|
+
normalizeDocumentSourceTreePaths: () => normalizeDocumentSourceTreePaths,
|
|
318
329
|
normalizeForMatch: () => normalizeForMatch,
|
|
319
330
|
orderSourceEvidence: () => orderSourceEvidence,
|
|
320
331
|
overlayTextOnPdf: () => overlayTextOnPdf,
|
|
@@ -1750,6 +1761,8 @@ var DocumentAgentGuidanceSchema = import_zod16.z.object({
|
|
|
1750
1761
|
sourceSpanIds: import_zod16.z.array(import_zod16.z.string()).optional()
|
|
1751
1762
|
});
|
|
1752
1763
|
var DocumentMetadataSchema = import_zod16.z.object({
|
|
1764
|
+
sourceTreeVersion: import_zod16.z.string().optional(),
|
|
1765
|
+
sourceTreeCanonical: import_zod16.z.boolean().optional(),
|
|
1753
1766
|
formInventory: import_zod16.z.array(FormReferenceSchema).optional(),
|
|
1754
1767
|
tableOfContents: import_zod16.z.array(DocumentTableOfContentsEntrySchema).optional(),
|
|
1755
1768
|
pageMap: import_zod16.z.array(DocumentPageMapEntrySchema).optional(),
|
|
@@ -2349,6 +2362,86 @@ var SourceChunkSchema = import_zod20.z.object({
|
|
|
2349
2362
|
pageEnd: import_zod20.z.number().int().positive().optional(),
|
|
2350
2363
|
metadata: import_zod20.z.record(import_zod20.z.string(), import_zod20.z.string()).default({})
|
|
2351
2364
|
});
|
|
2365
|
+
var DocumentSourceNodeKindSchema = import_zod20.z.enum([
|
|
2366
|
+
"document",
|
|
2367
|
+
"page_group",
|
|
2368
|
+
"page",
|
|
2369
|
+
"form",
|
|
2370
|
+
"endorsement",
|
|
2371
|
+
"section",
|
|
2372
|
+
"schedule",
|
|
2373
|
+
"clause",
|
|
2374
|
+
"table",
|
|
2375
|
+
"table_row",
|
|
2376
|
+
"table_cell",
|
|
2377
|
+
"text"
|
|
2378
|
+
]);
|
|
2379
|
+
var DocumentSourceNodeSchema = import_zod20.z.object({
|
|
2380
|
+
id: import_zod20.z.string().min(1),
|
|
2381
|
+
documentId: import_zod20.z.string().min(1),
|
|
2382
|
+
parentId: import_zod20.z.string().optional(),
|
|
2383
|
+
kind: DocumentSourceNodeKindSchema,
|
|
2384
|
+
title: import_zod20.z.string(),
|
|
2385
|
+
description: import_zod20.z.string(),
|
|
2386
|
+
textExcerpt: import_zod20.z.string().optional(),
|
|
2387
|
+
sourceSpanIds: import_zod20.z.array(import_zod20.z.string().min(1)),
|
|
2388
|
+
pageStart: import_zod20.z.number().int().positive().optional(),
|
|
2389
|
+
pageEnd: import_zod20.z.number().int().positive().optional(),
|
|
2390
|
+
bbox: import_zod20.z.array(SourceSpanBBoxSchema).optional(),
|
|
2391
|
+
order: import_zod20.z.number().int().nonnegative(),
|
|
2392
|
+
path: import_zod20.z.string(),
|
|
2393
|
+
metadata: import_zod20.z.record(import_zod20.z.string(), import_zod20.z.unknown()).optional()
|
|
2394
|
+
});
|
|
2395
|
+
var SourceBackedValueSchema = import_zod20.z.object({
|
|
2396
|
+
value: import_zod20.z.string(),
|
|
2397
|
+
normalizedValue: import_zod20.z.string().optional(),
|
|
2398
|
+
confidence: import_zod20.z.enum(["low", "medium", "high"]).default("medium"),
|
|
2399
|
+
sourceNodeIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([]),
|
|
2400
|
+
sourceSpanIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([])
|
|
2401
|
+
});
|
|
2402
|
+
var OperationalCoverageLineSchema = import_zod20.z.object({
|
|
2403
|
+
name: import_zod20.z.string(),
|
|
2404
|
+
coverageCode: import_zod20.z.string().optional(),
|
|
2405
|
+
limit: import_zod20.z.string().optional(),
|
|
2406
|
+
deductible: import_zod20.z.string().optional(),
|
|
2407
|
+
premium: import_zod20.z.string().optional(),
|
|
2408
|
+
formNumber: import_zod20.z.string().optional(),
|
|
2409
|
+
sectionRef: import_zod20.z.string().optional(),
|
|
2410
|
+
sourceNodeIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([]),
|
|
2411
|
+
sourceSpanIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([])
|
|
2412
|
+
});
|
|
2413
|
+
var OperationalPartySchema = import_zod20.z.object({
|
|
2414
|
+
role: import_zod20.z.string(),
|
|
2415
|
+
name: import_zod20.z.string(),
|
|
2416
|
+
sourceNodeIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([]),
|
|
2417
|
+
sourceSpanIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([])
|
|
2418
|
+
});
|
|
2419
|
+
var OperationalEndorsementSupportSchema = import_zod20.z.object({
|
|
2420
|
+
kind: import_zod20.z.string(),
|
|
2421
|
+
status: import_zod20.z.enum(["supported", "excluded", "requires_review"]),
|
|
2422
|
+
summary: import_zod20.z.string(),
|
|
2423
|
+
sourceNodeIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([]),
|
|
2424
|
+
sourceSpanIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([])
|
|
2425
|
+
});
|
|
2426
|
+
var PolicyOperationalProfileSchema = import_zod20.z.object({
|
|
2427
|
+
documentType: import_zod20.z.enum(["policy", "quote"]).default("policy"),
|
|
2428
|
+
policyTypes: import_zod20.z.array(import_zod20.z.string()).default(["other"]),
|
|
2429
|
+
policyNumber: SourceBackedValueSchema.optional(),
|
|
2430
|
+
namedInsured: SourceBackedValueSchema.optional(),
|
|
2431
|
+
insurer: SourceBackedValueSchema.optional(),
|
|
2432
|
+
broker: SourceBackedValueSchema.optional(),
|
|
2433
|
+
effectiveDate: SourceBackedValueSchema.optional(),
|
|
2434
|
+
expirationDate: SourceBackedValueSchema.optional(),
|
|
2435
|
+
retroactiveDate: SourceBackedValueSchema.optional(),
|
|
2436
|
+
premium: SourceBackedValueSchema.optional(),
|
|
2437
|
+
coverageTypes: import_zod20.z.array(import_zod20.z.string()).default([]),
|
|
2438
|
+
coverages: import_zod20.z.array(OperationalCoverageLineSchema).default([]),
|
|
2439
|
+
parties: import_zod20.z.array(OperationalPartySchema).default([]),
|
|
2440
|
+
endorsementSupport: import_zod20.z.array(OperationalEndorsementSupportSchema).default([]),
|
|
2441
|
+
sourceNodeIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([]),
|
|
2442
|
+
sourceSpanIds: import_zod20.z.array(import_zod20.z.string().min(1)).default([]),
|
|
2443
|
+
warnings: import_zod20.z.array(import_zod20.z.string()).default([])
|
|
2444
|
+
});
|
|
2352
2445
|
|
|
2353
2446
|
// src/source/ids.ts
|
|
2354
2447
|
function normalizeText(text) {
|
|
@@ -2532,8 +2625,8 @@ function chunkSourceSpans(spans, options = {}) {
|
|
|
2532
2625
|
if (current.length === 0) return;
|
|
2533
2626
|
const text = current.map((span) => span.text).join("\n\n");
|
|
2534
2627
|
const textHash = sourceSpanTextHash(text);
|
|
2535
|
-
const
|
|
2536
|
-
const
|
|
2628
|
+
const pageStart2 = firstNumber(current.map((span) => span.pageStart));
|
|
2629
|
+
const pageEnd2 = lastNumber(current.map((span) => span.pageEnd ?? span.pageStart));
|
|
2537
2630
|
const chunk = {
|
|
2538
2631
|
id: `${sanitizeIdPart(current[0].documentId)}:source_chunk:${chunks.length}:${stableHash2({
|
|
2539
2632
|
sourceSpanIds: current.map((span) => span.id),
|
|
@@ -2543,8 +2636,8 @@ function chunkSourceSpans(spans, options = {}) {
|
|
|
2543
2636
|
sourceSpanIds: current.map((span) => span.id),
|
|
2544
2637
|
text,
|
|
2545
2638
|
textHash,
|
|
2546
|
-
pageStart,
|
|
2547
|
-
pageEnd,
|
|
2639
|
+
pageStart: pageStart2,
|
|
2640
|
+
pageEnd: pageEnd2,
|
|
2548
2641
|
metadata: mergeMetadata(current)
|
|
2549
2642
|
};
|
|
2550
2643
|
chunks.push(SourceChunkSchema.parse(chunk));
|
|
@@ -2697,6 +2790,542 @@ function matchesFilters(span, filters) {
|
|
|
2697
2790
|
return true;
|
|
2698
2791
|
}
|
|
2699
2792
|
|
|
2793
|
+
// src/source/tree.ts
|
|
2794
|
+
function normalizeWhitespace2(value) {
|
|
2795
|
+
return value.replace(/\s+/g, " ").trim();
|
|
2796
|
+
}
|
|
2797
|
+
function sanitizeIdPart2(value) {
|
|
2798
|
+
return value.replace(/[^a-zA-Z0-9_.:-]/g, "_");
|
|
2799
|
+
}
|
|
2800
|
+
function truncate(value, maxChars) {
|
|
2801
|
+
const text = normalizeWhitespace2(value);
|
|
2802
|
+
return text.length > maxChars ? `${text.slice(0, maxChars).trimEnd()}...` : text;
|
|
2803
|
+
}
|
|
2804
|
+
function pageStart(span) {
|
|
2805
|
+
return span.pageStart ?? span.location?.page ?? span.location?.startPage;
|
|
2806
|
+
}
|
|
2807
|
+
function pageEnd(span) {
|
|
2808
|
+
return span.pageEnd ?? span.location?.endPage ?? pageStart(span);
|
|
2809
|
+
}
|
|
2810
|
+
function sourceUnit2(span) {
|
|
2811
|
+
return span.sourceUnit ?? span.metadata?.sourceUnit ?? span.metadata?.elementType;
|
|
2812
|
+
}
|
|
2813
|
+
function elementType(span) {
|
|
2814
|
+
return span.metadata?.elementType ?? span.metadata?.sourceUnit ?? span.sourceUnit;
|
|
2815
|
+
}
|
|
2816
|
+
function tableId(span) {
|
|
2817
|
+
return span.table?.tableId ?? span.metadata?.tableId;
|
|
2818
|
+
}
|
|
2819
|
+
function rowSpanId(span) {
|
|
2820
|
+
return span.parentSpanId ?? span.table?.rowSpanId ?? span.metadata?.rowSpanId;
|
|
2821
|
+
}
|
|
2822
|
+
function nodeId(documentId, kind, parts) {
|
|
2823
|
+
return [
|
|
2824
|
+
sanitizeIdPart2(documentId),
|
|
2825
|
+
"source_node",
|
|
2826
|
+
kind,
|
|
2827
|
+
stableHash2(parts.filter((part) => part !== void 0).join("|")).slice(0, 12)
|
|
2828
|
+
].join(":");
|
|
2829
|
+
}
|
|
2830
|
+
function titleCase(value) {
|
|
2831
|
+
return value.replace(/[_-]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase()).trim();
|
|
2832
|
+
}
|
|
2833
|
+
function nodeTextDescription(params) {
|
|
2834
|
+
return [
|
|
2835
|
+
params.title,
|
|
2836
|
+
params.kind.replace(/_/g, " "),
|
|
2837
|
+
params.page ? `page ${params.page}` : void 0,
|
|
2838
|
+
params.formNumber ? `form ${params.formNumber}` : void 0,
|
|
2839
|
+
params.text ? truncate(params.text, 1200) : void 0
|
|
2840
|
+
].filter(Boolean).join(" | ");
|
|
2841
|
+
}
|
|
2842
|
+
function normalizeNodeKind(span) {
|
|
2843
|
+
const unit = sourceUnit2(span);
|
|
2844
|
+
const element = elementType(span);
|
|
2845
|
+
if (unit === "page") return "page";
|
|
2846
|
+
if (unit === "table") return "table";
|
|
2847
|
+
if (unit === "table_row") return "table_row";
|
|
2848
|
+
if (unit === "table_cell") return "table_cell";
|
|
2849
|
+
if (unit === "key_value") return "schedule";
|
|
2850
|
+
if (unit === "section") return "section";
|
|
2851
|
+
if (element === "title" || element === "section_candidate") {
|
|
2852
|
+
const text = span.text.toLowerCase();
|
|
2853
|
+
if (/endorsement/.test(text)) return "endorsement";
|
|
2854
|
+
if (/schedule|declarations?/.test(text)) return "schedule";
|
|
2855
|
+
if (/clause|condition|exclusion|definition/.test(text)) return "clause";
|
|
2856
|
+
return "section";
|
|
2857
|
+
}
|
|
2858
|
+
return "text";
|
|
2859
|
+
}
|
|
2860
|
+
function pageNodeTitle(page) {
|
|
2861
|
+
return `Page ${page}`;
|
|
2862
|
+
}
|
|
2863
|
+
function makeNode(params) {
|
|
2864
|
+
return {
|
|
2865
|
+
id: params.id,
|
|
2866
|
+
documentId: params.documentId,
|
|
2867
|
+
parentId: params.parentId,
|
|
2868
|
+
kind: params.kind,
|
|
2869
|
+
title: params.title,
|
|
2870
|
+
description: params.description ?? nodeTextDescription({
|
|
2871
|
+
kind: params.kind,
|
|
2872
|
+
title: params.title,
|
|
2873
|
+
text: params.textExcerpt,
|
|
2874
|
+
page: params.pageStart,
|
|
2875
|
+
formNumber: typeof params.metadata?.formNumber === "string" ? params.metadata.formNumber : void 0
|
|
2876
|
+
}),
|
|
2877
|
+
textExcerpt: params.textExcerpt,
|
|
2878
|
+
sourceSpanIds: params.sourceSpanIds ?? [],
|
|
2879
|
+
pageStart: params.pageStart,
|
|
2880
|
+
pageEnd: params.pageEnd,
|
|
2881
|
+
bbox: params.bbox,
|
|
2882
|
+
order: params.order,
|
|
2883
|
+
path: "",
|
|
2884
|
+
metadata: params.metadata
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
function sortSpans(left, right) {
|
|
2888
|
+
const leftPage = pageStart(left) ?? 0;
|
|
2889
|
+
const rightPage = pageStart(right) ?? 0;
|
|
2890
|
+
if (leftPage !== rightPage) return leftPage - rightPage;
|
|
2891
|
+
const leftRow = left.table?.rowIndex ?? Number(left.metadata?.rowIndex ?? 0);
|
|
2892
|
+
const rightRow = right.table?.rowIndex ?? Number(right.metadata?.rowIndex ?? 0);
|
|
2893
|
+
if (leftRow !== rightRow) return leftRow - rightRow;
|
|
2894
|
+
const leftCol = left.table?.columnIndex ?? Number(left.metadata?.columnIndex ?? 0);
|
|
2895
|
+
const rightCol = right.table?.columnIndex ?? Number(right.metadata?.columnIndex ?? 0);
|
|
2896
|
+
if (leftCol !== rightCol) return leftCol - rightCol;
|
|
2897
|
+
return left.id.localeCompare(right.id);
|
|
2898
|
+
}
|
|
2899
|
+
function normalizeDocumentSourceTreePaths(nodes) {
|
|
2900
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
2901
|
+
for (const node of nodes) {
|
|
2902
|
+
const key = node.parentId;
|
|
2903
|
+
const group = byParent.get(key) ?? [];
|
|
2904
|
+
group.push(node);
|
|
2905
|
+
byParent.set(key, group);
|
|
2906
|
+
}
|
|
2907
|
+
for (const group of byParent.values()) {
|
|
2908
|
+
group.sort((left, right) => left.order - right.order || left.id.localeCompare(right.id));
|
|
2909
|
+
}
|
|
2910
|
+
const result = [];
|
|
2911
|
+
const visit = (node, path) => {
|
|
2912
|
+
const next = { ...node, path };
|
|
2913
|
+
result.push(next);
|
|
2914
|
+
const children = byParent.get(node.id) ?? [];
|
|
2915
|
+
children.forEach((child, index) => visit(child, `${path}.${index + 1}`));
|
|
2916
|
+
};
|
|
2917
|
+
const roots = byParent.get(void 0) ?? [];
|
|
2918
|
+
roots.forEach((root, index) => visit(root, String(index + 1)));
|
|
2919
|
+
return result;
|
|
2920
|
+
}
|
|
2921
|
+
function buildDocumentSourceTree(sourceSpans, documentId) {
|
|
2922
|
+
const orderedSpans = [...sourceSpans].sort(sortSpans);
|
|
2923
|
+
const resolvedDocumentId = documentId ?? orderedSpans[0]?.documentId ?? "document";
|
|
2924
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
2925
|
+
let order = 0;
|
|
2926
|
+
const rootId = nodeId(resolvedDocumentId, "document", [resolvedDocumentId]);
|
|
2927
|
+
nodes.set(rootId, makeNode({
|
|
2928
|
+
id: rootId,
|
|
2929
|
+
documentId: resolvedDocumentId,
|
|
2930
|
+
kind: "document",
|
|
2931
|
+
title: "Document",
|
|
2932
|
+
description: "Document root for source-native policy hierarchy",
|
|
2933
|
+
sourceSpanIds: orderedSpans.map((span) => span.id).slice(0, 200),
|
|
2934
|
+
pageStart: orderedSpans.map(pageStart).find((value) => typeof value === "number"),
|
|
2935
|
+
pageEnd: [...orderedSpans].reverse().map(pageEnd).find((value) => typeof value === "number"),
|
|
2936
|
+
order: order++,
|
|
2937
|
+
metadata: { sourceTreeVersion: "v3" }
|
|
2938
|
+
}));
|
|
2939
|
+
const pageNodeIds = /* @__PURE__ */ new Map();
|
|
2940
|
+
const tableNodeIds = /* @__PURE__ */ new Map();
|
|
2941
|
+
const rowNodeIds = /* @__PURE__ */ new Map();
|
|
2942
|
+
const ensurePage = (page) => {
|
|
2943
|
+
const existing = pageNodeIds.get(page);
|
|
2944
|
+
if (existing) return existing;
|
|
2945
|
+
const id = nodeId(resolvedDocumentId, "page", [page]);
|
|
2946
|
+
const pageSpan = orderedSpans.find((span) => pageStart(span) === page && sourceUnit2(span) === "page");
|
|
2947
|
+
nodes.set(id, makeNode({
|
|
2948
|
+
id,
|
|
2949
|
+
documentId: resolvedDocumentId,
|
|
2950
|
+
parentId: rootId,
|
|
2951
|
+
kind: "page",
|
|
2952
|
+
title: pageNodeTitle(page),
|
|
2953
|
+
description: pageSpan ? nodeTextDescription({ kind: "page", title: pageNodeTitle(page), text: pageSpan.text, page }) : pageNodeTitle(page),
|
|
2954
|
+
textExcerpt: pageSpan ? truncate(pageSpan.text, 1600) : void 0,
|
|
2955
|
+
sourceSpanIds: pageSpan ? [pageSpan.id] : [],
|
|
2956
|
+
pageStart: page,
|
|
2957
|
+
pageEnd: page,
|
|
2958
|
+
bbox: pageSpan?.bbox,
|
|
2959
|
+
order: order++,
|
|
2960
|
+
metadata: { sourceUnit: "page" }
|
|
2961
|
+
}));
|
|
2962
|
+
pageNodeIds.set(page, id);
|
|
2963
|
+
return id;
|
|
2964
|
+
};
|
|
2965
|
+
const ensureTable = (span, pageParentId) => {
|
|
2966
|
+
const idSource = tableId(span) ?? `${span.documentId}:p${pageStart(span) ?? "na"}:table:${nodes.size}`;
|
|
2967
|
+
const existing = tableNodeIds.get(idSource);
|
|
2968
|
+
if (existing) return existing;
|
|
2969
|
+
const id = nodeId(resolvedDocumentId, "table", [idSource]);
|
|
2970
|
+
nodes.set(id, makeNode({
|
|
2971
|
+
id,
|
|
2972
|
+
documentId: resolvedDocumentId,
|
|
2973
|
+
parentId: pageParentId,
|
|
2974
|
+
kind: "table",
|
|
2975
|
+
title: `Table ${tableNodeIds.size + 1}`,
|
|
2976
|
+
description: `Table on page ${pageStart(span) ?? "unknown"} for source rows and cells`,
|
|
2977
|
+
sourceSpanIds: [],
|
|
2978
|
+
pageStart: pageStart(span),
|
|
2979
|
+
pageEnd: pageEnd(span),
|
|
2980
|
+
order: order++,
|
|
2981
|
+
metadata: { tableId: idSource, sourceUnit: "table" }
|
|
2982
|
+
}));
|
|
2983
|
+
tableNodeIds.set(idSource, id);
|
|
2984
|
+
return id;
|
|
2985
|
+
};
|
|
2986
|
+
const addStandaloneSpanNode = (span, parentId) => {
|
|
2987
|
+
const kind = normalizeNodeKind(span);
|
|
2988
|
+
if (kind === "page") return;
|
|
2989
|
+
const page = pageStart(span);
|
|
2990
|
+
const title = span.sectionId ?? span.formNumber ?? (kind === "table_cell" && span.table?.columnName ? String(span.table.columnName) : void 0) ?? titleCase(kind);
|
|
2991
|
+
const id = nodeId(resolvedDocumentId, kind, [span.id]);
|
|
2992
|
+
nodes.set(id, makeNode({
|
|
2993
|
+
id,
|
|
2994
|
+
documentId: resolvedDocumentId,
|
|
2995
|
+
parentId,
|
|
2996
|
+
kind,
|
|
2997
|
+
title,
|
|
2998
|
+
description: nodeTextDescription({ kind, title, text: span.text, page, formNumber: span.formNumber }),
|
|
2999
|
+
textExcerpt: truncate(span.text, 1600),
|
|
3000
|
+
sourceSpanIds: [span.id],
|
|
3001
|
+
pageStart: page,
|
|
3002
|
+
pageEnd: pageEnd(span),
|
|
3003
|
+
bbox: span.bbox,
|
|
3004
|
+
order: order++,
|
|
3005
|
+
metadata: {
|
|
3006
|
+
...span.metadata ?? {},
|
|
3007
|
+
formNumber: span.formNumber,
|
|
3008
|
+
sourceUnit: sourceUnit2(span)
|
|
3009
|
+
}
|
|
3010
|
+
}));
|
|
3011
|
+
};
|
|
3012
|
+
for (const span of orderedSpans) {
|
|
3013
|
+
const page = pageStart(span);
|
|
3014
|
+
const pageParentId = page ? ensurePage(page) : rootId;
|
|
3015
|
+
const kind = normalizeNodeKind(span);
|
|
3016
|
+
if (kind === "page") continue;
|
|
3017
|
+
if (kind === "table_row") {
|
|
3018
|
+
const tableParentId = ensureTable(span, pageParentId);
|
|
3019
|
+
const rowKey = span.id;
|
|
3020
|
+
const id = nodeId(resolvedDocumentId, "table_row", [span.id]);
|
|
3021
|
+
nodes.set(id, makeNode({
|
|
3022
|
+
id,
|
|
3023
|
+
documentId: resolvedDocumentId,
|
|
3024
|
+
parentId: tableParentId,
|
|
3025
|
+
kind,
|
|
3026
|
+
title: span.table?.isHeader ? "Header row" : `Row ${(span.table?.rowIndex ?? 0) + 1}`,
|
|
3027
|
+
description: nodeTextDescription({ kind, title: "Table row", text: span.text, page }),
|
|
3028
|
+
textExcerpt: truncate(span.text, 1600),
|
|
3029
|
+
sourceSpanIds: [span.id],
|
|
3030
|
+
pageStart: page,
|
|
3031
|
+
pageEnd: pageEnd(span),
|
|
3032
|
+
bbox: span.bbox,
|
|
3033
|
+
order: order++,
|
|
3034
|
+
metadata: {
|
|
3035
|
+
...span.metadata ?? {},
|
|
3036
|
+
...span.table ?? {},
|
|
3037
|
+
sourceUnit: "table_row"
|
|
3038
|
+
}
|
|
3039
|
+
}));
|
|
3040
|
+
rowNodeIds.set(rowKey, id);
|
|
3041
|
+
continue;
|
|
3042
|
+
}
|
|
3043
|
+
if (kind === "table_cell") {
|
|
3044
|
+
const tableParentId = ensureTable(span, pageParentId);
|
|
3045
|
+
const parentRowId2 = rowSpanId(span);
|
|
3046
|
+
const parentId = parentRowId2 ? rowNodeIds.get(parentRowId2) ?? tableParentId : tableParentId;
|
|
3047
|
+
addStandaloneSpanNode(span, parentId);
|
|
3048
|
+
continue;
|
|
3049
|
+
}
|
|
3050
|
+
addStandaloneSpanNode(span, pageParentId);
|
|
3051
|
+
}
|
|
3052
|
+
return normalizeDocumentSourceTreePaths([...nodes.values()]);
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
// src/source/operational-profile.ts
|
|
3056
|
+
function normalizeWhitespace3(value) {
|
|
3057
|
+
return value.replace(/\s+/g, " ").trim();
|
|
3058
|
+
}
|
|
3059
|
+
function cleanValue(value) {
|
|
3060
|
+
if (!value) return void 0;
|
|
3061
|
+
return normalizeWhitespace3(value.replace(/^[\s:;#-]+|[\s;,.]+$/g, ""));
|
|
3062
|
+
}
|
|
3063
|
+
function moneyValue(value) {
|
|
3064
|
+
const clean = cleanValue(value);
|
|
3065
|
+
if (!clean) return void 0;
|
|
3066
|
+
if (/^\$/.test(clean)) return clean;
|
|
3067
|
+
if (/^\d{1,3}(?:,\d{3})*(?:\.\d{2})?$/.test(clean)) return `$${clean}`;
|
|
3068
|
+
return clean;
|
|
3069
|
+
}
|
|
3070
|
+
function nodeText(node) {
|
|
3071
|
+
return normalizeWhitespace3([
|
|
3072
|
+
node.title,
|
|
3073
|
+
node.description,
|
|
3074
|
+
node.textExcerpt
|
|
3075
|
+
].filter(Boolean).join(" "));
|
|
3076
|
+
}
|
|
3077
|
+
function valueFromNode(node, value, confidence = "medium") {
|
|
3078
|
+
return {
|
|
3079
|
+
value,
|
|
3080
|
+
confidence,
|
|
3081
|
+
sourceNodeIds: [node.id],
|
|
3082
|
+
sourceSpanIds: node.sourceSpanIds
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
function firstMatch(nodes, patterns) {
|
|
3086
|
+
for (const node of nodes) {
|
|
3087
|
+
const text = nodeText(node);
|
|
3088
|
+
for (const pattern of patterns) {
|
|
3089
|
+
const match = text.match(pattern);
|
|
3090
|
+
const value = cleanValue(match?.[1]);
|
|
3091
|
+
if (value) return valueFromNode(node, value, "high");
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
return void 0;
|
|
3095
|
+
}
|
|
3096
|
+
function inferPolicyTypes(nodes) {
|
|
3097
|
+
const text = nodes.slice(0, 40).map(nodeText).join(" ").toLowerCase();
|
|
3098
|
+
const types = [];
|
|
3099
|
+
const add = (pattern, type) => {
|
|
3100
|
+
if (pattern.test(text) && !types.includes(type)) types.push(type);
|
|
3101
|
+
};
|
|
3102
|
+
add(/\b(cyber|network security|privacy liability|data breach)\b/i, "cyber");
|
|
3103
|
+
add(/\b(professional liability|errors?\s*&?\s*omissions|e&o)\b/i, "professional_liability");
|
|
3104
|
+
add(/\b(commercial general liability|general liability|cgl)\b/i, "general_liability");
|
|
3105
|
+
add(/\b(umbrella|excess liability)\b/i, "umbrella");
|
|
3106
|
+
add(/\b(workers'? compensation|employers'? liability)\b/i, "workers_comp");
|
|
3107
|
+
add(/\b(commercial auto|business auto|automobile liability)\b/i, "commercial_auto");
|
|
3108
|
+
add(/\b(commercial property|property coverage|building coverage)\b/i, "commercial_property");
|
|
3109
|
+
return types.length ? types : ["other"];
|
|
3110
|
+
}
|
|
3111
|
+
function inferDocumentType(nodes) {
|
|
3112
|
+
const text = nodes.slice(0, 25).map(nodeText).join(" ").toLowerCase();
|
|
3113
|
+
if (/\b(quote|proposal|quotation|indication)\b/.test(text) && !/\bpolicy number\b/.test(text)) {
|
|
3114
|
+
return "quote";
|
|
3115
|
+
}
|
|
3116
|
+
return "policy";
|
|
3117
|
+
}
|
|
3118
|
+
function coverageNameFromRow(text) {
|
|
3119
|
+
const labelled = text.match(/\b(?:coverage|coverage part|line)\s*:?\s*([^|;$]{3,80})/i)?.[1];
|
|
3120
|
+
if (labelled) return cleanValue(labelled);
|
|
3121
|
+
const parts = text.split(/\s+\|\s+| {2,}|\t/).map(cleanValue).filter(Boolean);
|
|
3122
|
+
const first = parts.find(
|
|
3123
|
+
(part) => !/^(limit|limits?|deductible|premium|amount|basis|rate|retroactive|aggregate|each occurrence)$/i.test(part) && !/^\$?[\d,]+/.test(part)
|
|
3124
|
+
);
|
|
3125
|
+
return cleanValue(first);
|
|
3126
|
+
}
|
|
3127
|
+
function limitFromText(text) {
|
|
3128
|
+
return moneyValue(
|
|
3129
|
+
text.match(/\b(?:limit|liability|aggregate|occurrence|claim)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?|\$?\d[\d,]*\s*(?:each|per|aggregate)[^|;]*)/i)?.[1] ?? text.match(/(\$\s?\d[\d,]*(?:\.\d{2})?)(?=.*\b(limit|aggregate|occurrence|claim|liability)\b)/i)?.[1]
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
3132
|
+
function deductibleFromText(text) {
|
|
3133
|
+
return moneyValue(text.match(/\b(?:deductible|retention|sir)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i)?.[1]);
|
|
3134
|
+
}
|
|
3135
|
+
function premiumFromText(text) {
|
|
3136
|
+
return moneyValue(text.match(/\b(?:premium|total premium|total cost|amount due)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i)?.[1]);
|
|
3137
|
+
}
|
|
3138
|
+
function buildCoverages(nodes) {
|
|
3139
|
+
const rows = nodes.filter((node) => {
|
|
3140
|
+
const text = nodeText(node);
|
|
3141
|
+
return (node.kind === "table_row" || node.kind === "schedule" || node.kind === "text") && /\b(coverage|limit|deductible|aggregate|occurrence|liability|premium)\b/i.test(text);
|
|
3142
|
+
});
|
|
3143
|
+
const coverages = [];
|
|
3144
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3145
|
+
for (const row of rows) {
|
|
3146
|
+
const text = nodeText(row);
|
|
3147
|
+
const name = coverageNameFromRow(text);
|
|
3148
|
+
const limit = limitFromText(text);
|
|
3149
|
+
const deductible = deductibleFromText(text);
|
|
3150
|
+
const premium = premiumFromText(text);
|
|
3151
|
+
if (!name || !limit && !deductible && !premium) continue;
|
|
3152
|
+
const key = [name.toLowerCase(), limit, deductible, premium].join("|");
|
|
3153
|
+
if (seen.has(key)) continue;
|
|
3154
|
+
seen.add(key);
|
|
3155
|
+
coverages.push({
|
|
3156
|
+
name,
|
|
3157
|
+
limit,
|
|
3158
|
+
deductible,
|
|
3159
|
+
premium,
|
|
3160
|
+
formNumber: typeof row.metadata?.formNumber === "string" ? row.metadata.formNumber : void 0,
|
|
3161
|
+
sourceNodeIds: [row.id],
|
|
3162
|
+
sourceSpanIds: row.sourceSpanIds
|
|
3163
|
+
});
|
|
3164
|
+
if (coverages.length >= 60) break;
|
|
3165
|
+
}
|
|
3166
|
+
return coverages;
|
|
3167
|
+
}
|
|
3168
|
+
function buildParties(profile) {
|
|
3169
|
+
const parties = [];
|
|
3170
|
+
if (profile.namedInsured) {
|
|
3171
|
+
parties.push({
|
|
3172
|
+
role: "named_insured",
|
|
3173
|
+
name: profile.namedInsured.value,
|
|
3174
|
+
sourceNodeIds: profile.namedInsured.sourceNodeIds,
|
|
3175
|
+
sourceSpanIds: profile.namedInsured.sourceSpanIds
|
|
3176
|
+
});
|
|
3177
|
+
}
|
|
3178
|
+
if (profile.insurer) {
|
|
3179
|
+
parties.push({
|
|
3180
|
+
role: "insurer",
|
|
3181
|
+
name: profile.insurer.value,
|
|
3182
|
+
sourceNodeIds: profile.insurer.sourceNodeIds,
|
|
3183
|
+
sourceSpanIds: profile.insurer.sourceSpanIds
|
|
3184
|
+
});
|
|
3185
|
+
}
|
|
3186
|
+
if (profile.broker) {
|
|
3187
|
+
parties.push({
|
|
3188
|
+
role: "broker",
|
|
3189
|
+
name: profile.broker.value,
|
|
3190
|
+
sourceNodeIds: profile.broker.sourceNodeIds,
|
|
3191
|
+
sourceSpanIds: profile.broker.sourceSpanIds
|
|
3192
|
+
});
|
|
3193
|
+
}
|
|
3194
|
+
return parties;
|
|
3195
|
+
}
|
|
3196
|
+
function buildEndorsementSupport(nodes) {
|
|
3197
|
+
const support = [];
|
|
3198
|
+
for (const node of nodes) {
|
|
3199
|
+
const text = nodeText(node);
|
|
3200
|
+
const add = (kind, status) => {
|
|
3201
|
+
if (support.some((item) => item.kind === kind && item.status === status && item.sourceNodeIds.includes(node.id))) {
|
|
3202
|
+
return;
|
|
3203
|
+
}
|
|
3204
|
+
support.push({
|
|
3205
|
+
kind,
|
|
3206
|
+
status,
|
|
3207
|
+
summary: node.textExcerpt ?? node.description,
|
|
3208
|
+
sourceNodeIds: [node.id],
|
|
3209
|
+
sourceSpanIds: node.sourceSpanIds
|
|
3210
|
+
});
|
|
3211
|
+
};
|
|
3212
|
+
if (/additional insured/i.test(text)) add("additional_insured", /not included|requires endorsement|only by endorsement/i.test(text) ? "requires_review" : "supported");
|
|
3213
|
+
if (/waiver of subrogation|subrogation.*waived/i.test(text)) add("waiver_of_subrogation", /not included|requires endorsement|only by endorsement/i.test(text) ? "requires_review" : "supported");
|
|
3214
|
+
if (/primary.*non[-\s]?contributory|non[-\s]?contributory/i.test(text)) add("primary_non_contributory", /not included|requires endorsement|only by endorsement/i.test(text) ? "requires_review" : "supported");
|
|
3215
|
+
if (/loss payee|mortgagee/i.test(text)) add(/mortgagee/i.test(text) ? "mortgagee" : "loss_payee", "supported");
|
|
3216
|
+
if (support.length >= 20) break;
|
|
3217
|
+
}
|
|
3218
|
+
return support;
|
|
3219
|
+
}
|
|
3220
|
+
function buildDeterministicOperationalProfile(params) {
|
|
3221
|
+
const nodes = params.sourceTree.filter((node) => node.kind !== "document");
|
|
3222
|
+
const partial = {
|
|
3223
|
+
documentType: inferDocumentType(nodes),
|
|
3224
|
+
policyTypes: inferPolicyTypes(nodes),
|
|
3225
|
+
policyNumber: firstMatch(nodes, [
|
|
3226
|
+
/\bpolicy\s*(?:number|no\.?|#)\s*:?\s*([A-Z0-9][A-Z0-9-]{4,})/i,
|
|
3227
|
+
/\bpolicy\s*[:#]\s*([A-Z0-9][A-Z0-9-]{4,})/i
|
|
3228
|
+
]),
|
|
3229
|
+
namedInsured: firstMatch(nodes, [
|
|
3230
|
+
/\b(?:named insured|insured name|insured)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i,
|
|
3231
|
+
/\b(?:applicant|policyholder)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i
|
|
3232
|
+
]),
|
|
3233
|
+
insurer: firstMatch(nodes, [
|
|
3234
|
+
/\b(?:insurer|carrier|company|security)\s*:?\s*([^|;\n]{3,120})/i,
|
|
3235
|
+
/\bunderwritten by\s+([^|;\n]{3,120})/i
|
|
3236
|
+
]),
|
|
3237
|
+
broker: firstMatch(nodes, [
|
|
3238
|
+
/\b(?:broker|producer|agent)\s*:?\s*([^|;\n]{3,120})/i
|
|
3239
|
+
]),
|
|
3240
|
+
effectiveDate: firstMatch(nodes, [
|
|
3241
|
+
/\b(?:effective date|policy period from|from)\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})/i,
|
|
3242
|
+
/\b([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})\s+(?:to|through|-)\s+[0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}/i
|
|
3243
|
+
]),
|
|
3244
|
+
expirationDate: firstMatch(nodes, [
|
|
3245
|
+
/\b(?:expiration date|expiry date|expires|to)\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})/i,
|
|
3246
|
+
/\b[0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}\s+(?:to|through|-)\s+([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4})/i
|
|
3247
|
+
]),
|
|
3248
|
+
retroactiveDate: firstMatch(nodes, [
|
|
3249
|
+
/\bretroactive date\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}|full prior acts|none)/i
|
|
3250
|
+
]),
|
|
3251
|
+
premium: firstMatch(nodes, [
|
|
3252
|
+
/\b(?:total premium|premium|total cost|amount due)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i
|
|
3253
|
+
])
|
|
3254
|
+
};
|
|
3255
|
+
const coverages = buildCoverages(nodes);
|
|
3256
|
+
const coverageTypes = [...new Set(coverages.map((coverage) => coverage.name))];
|
|
3257
|
+
const sourceNodeIds = [.../* @__PURE__ */ new Set([
|
|
3258
|
+
...Object.values(partial).flatMap(
|
|
3259
|
+
(value) => value && typeof value === "object" && "sourceNodeIds" in value ? value.sourceNodeIds : []
|
|
3260
|
+
),
|
|
3261
|
+
...coverages.flatMap((coverage) => coverage.sourceNodeIds)
|
|
3262
|
+
])];
|
|
3263
|
+
const sourceSpanIds = [.../* @__PURE__ */ new Set([
|
|
3264
|
+
...Object.values(partial).flatMap(
|
|
3265
|
+
(value) => value && typeof value === "object" && "sourceSpanIds" in value ? value.sourceSpanIds : []
|
|
3266
|
+
),
|
|
3267
|
+
...coverages.flatMap((coverage) => coverage.sourceSpanIds)
|
|
3268
|
+
])];
|
|
3269
|
+
return PolicyOperationalProfileSchema.parse({
|
|
3270
|
+
...partial,
|
|
3271
|
+
coverageTypes,
|
|
3272
|
+
coverages,
|
|
3273
|
+
parties: buildParties(partial),
|
|
3274
|
+
endorsementSupport: buildEndorsementSupport(nodes),
|
|
3275
|
+
sourceNodeIds,
|
|
3276
|
+
sourceSpanIds,
|
|
3277
|
+
warnings: [
|
|
3278
|
+
...coverages.length === 0 ? ["No source-backed coverage schedule rows were identified deterministically."] : [],
|
|
3279
|
+
...!partial.policyNumber ? ["No source-backed policy number was identified deterministically."] : [],
|
|
3280
|
+
...!partial.namedInsured ? ["No source-backed named insured was identified deterministically."] : []
|
|
3281
|
+
]
|
|
3282
|
+
});
|
|
3283
|
+
}
|
|
3284
|
+
function mergeOperationalProfile(base, candidate, validNodeIds, validSpanIds) {
|
|
3285
|
+
const keepIds = (ids, valid) => Array.isArray(ids) ? ids.filter((id) => typeof id === "string" && valid.has(id)) : [];
|
|
3286
|
+
const mergeValue = (fallback, next) => {
|
|
3287
|
+
if (!next || typeof next !== "object" || Array.isArray(next)) return fallback;
|
|
3288
|
+
const record = next;
|
|
3289
|
+
const value = typeof record.value === "string" ? cleanValue(record.value) : void 0;
|
|
3290
|
+
if (!value) return fallback;
|
|
3291
|
+
const sourceNodeIds = keepIds(record.sourceNodeIds, validNodeIds);
|
|
3292
|
+
const sourceSpanIds = keepIds(record.sourceSpanIds, validSpanIds);
|
|
3293
|
+
if (sourceNodeIds.length === 0 && sourceSpanIds.length === 0) return fallback;
|
|
3294
|
+
return {
|
|
3295
|
+
value,
|
|
3296
|
+
normalizedValue: typeof record.normalizedValue === "string" ? record.normalizedValue : fallback?.normalizedValue,
|
|
3297
|
+
confidence: record.confidence === "high" || record.confidence === "low" || record.confidence === "medium" ? record.confidence : "medium",
|
|
3298
|
+
sourceNodeIds,
|
|
3299
|
+
sourceSpanIds
|
|
3300
|
+
};
|
|
3301
|
+
};
|
|
3302
|
+
const coverages = Array.isArray(candidate.coverages) ? candidate.coverages.map((coverage) => ({
|
|
3303
|
+
...coverage,
|
|
3304
|
+
sourceNodeIds: keepIds(coverage.sourceNodeIds, validNodeIds),
|
|
3305
|
+
sourceSpanIds: keepIds(coverage.sourceSpanIds, validSpanIds)
|
|
3306
|
+
})).filter((coverage) => coverage.name && (coverage.sourceNodeIds.length > 0 || coverage.sourceSpanIds.length > 0)) : base.coverages;
|
|
3307
|
+
return PolicyOperationalProfileSchema.parse({
|
|
3308
|
+
...base,
|
|
3309
|
+
documentType: candidate.documentType === "quote" ? "quote" : candidate.documentType === "policy" ? "policy" : base.documentType,
|
|
3310
|
+
policyTypes: Array.isArray(candidate.policyTypes) && candidate.policyTypes.length > 0 ? candidate.policyTypes : base.policyTypes,
|
|
3311
|
+
policyNumber: mergeValue(base.policyNumber, candidate.policyNumber),
|
|
3312
|
+
namedInsured: mergeValue(base.namedInsured, candidate.namedInsured),
|
|
3313
|
+
insurer: mergeValue(base.insurer, candidate.insurer),
|
|
3314
|
+
broker: mergeValue(base.broker, candidate.broker),
|
|
3315
|
+
effectiveDate: mergeValue(base.effectiveDate, candidate.effectiveDate),
|
|
3316
|
+
expirationDate: mergeValue(base.expirationDate, candidate.expirationDate),
|
|
3317
|
+
retroactiveDate: mergeValue(base.retroactiveDate, candidate.retroactiveDate),
|
|
3318
|
+
premium: mergeValue(base.premium, candidate.premium),
|
|
3319
|
+
coverageTypes: Array.isArray(candidate.coverageTypes) && candidate.coverageTypes.length > 0 ? candidate.coverageTypes : base.coverageTypes,
|
|
3320
|
+
coverages,
|
|
3321
|
+
parties: base.parties,
|
|
3322
|
+
endorsementSupport: base.endorsementSupport,
|
|
3323
|
+
sourceNodeIds: [.../* @__PURE__ */ new Set([...base.sourceNodeIds, ...keepIds(candidate.sourceNodeIds, validNodeIds)])],
|
|
3324
|
+
sourceSpanIds: [.../* @__PURE__ */ new Set([...base.sourceSpanIds, ...keepIds(candidate.sourceSpanIds, validSpanIds)])],
|
|
3325
|
+
warnings: base.warnings
|
|
3326
|
+
});
|
|
3327
|
+
}
|
|
3328
|
+
|
|
2700
3329
|
// src/extraction/pdf.ts
|
|
2701
3330
|
var import_pdf_lib = require("pdf-lib");
|
|
2702
3331
|
function isFileIdRef(input) {
|
|
@@ -3078,15 +3707,15 @@ function normalizeItem(ref, item) {
|
|
|
3078
3707
|
if (!text) return void 0;
|
|
3079
3708
|
const table = getItemTable(item);
|
|
3080
3709
|
const pages = (item.prov ?? []).map((prov) => getPageNumber(prov)).filter((page) => typeof page === "number" && page > 0);
|
|
3081
|
-
const
|
|
3082
|
-
const
|
|
3710
|
+
const pageStart2 = pages.length ? Math.min(...pages) : void 0;
|
|
3711
|
+
const pageEnd2 = pages.length ? Math.max(...pages) : pageStart2;
|
|
3083
3712
|
const bboxes = (item.prov ?? []).map((prov) => toSourceSpanBBox(prov)).filter((bbox) => Boolean(bbox));
|
|
3084
3713
|
return {
|
|
3085
3714
|
ref,
|
|
3086
3715
|
label: typeof item.label === "string" ? item.label : void 0,
|
|
3087
3716
|
text,
|
|
3088
|
-
pageStart,
|
|
3089
|
-
pageEnd,
|
|
3717
|
+
pageStart: pageStart2,
|
|
3718
|
+
pageEnd: pageEnd2,
|
|
3090
3719
|
bboxes: bboxes.length ? bboxes : void 0,
|
|
3091
3720
|
table
|
|
3092
3721
|
};
|
|
@@ -3098,7 +3727,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
3098
3727
|
doclingRef: unit.ref,
|
|
3099
3728
|
...unit.label ? { doclingLabel: unit.label } : {}
|
|
3100
3729
|
};
|
|
3101
|
-
const
|
|
3730
|
+
const tableId2 = unit.table ? `${unit.ref}:table` : void 0;
|
|
3102
3731
|
const tableSpan = withDoclingKind(buildSourceSpan(
|
|
3103
3732
|
{
|
|
3104
3733
|
documentId: options.documentId,
|
|
@@ -3108,7 +3737,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
3108
3737
|
pageEnd: unit.pageEnd,
|
|
3109
3738
|
sectionId: unit.label,
|
|
3110
3739
|
sourceUnit: unit.table ? "table" : labelToSourceUnit(unit.label),
|
|
3111
|
-
table:
|
|
3740
|
+
table: tableId2 ? { tableId: tableId2 } : void 0,
|
|
3112
3741
|
metadata: baseMetadata
|
|
3113
3742
|
},
|
|
3114
3743
|
index * 1e3
|
|
@@ -3132,7 +3761,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
3132
3761
|
sourceUnit: "table_row",
|
|
3133
3762
|
parentSpanId: tableSpan.id,
|
|
3134
3763
|
table: {
|
|
3135
|
-
tableId,
|
|
3764
|
+
tableId: tableId2,
|
|
3136
3765
|
tableSpanId: tableSpan.id,
|
|
3137
3766
|
rowIndex,
|
|
3138
3767
|
isHeader
|
|
@@ -3140,7 +3769,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
3140
3769
|
metadata: {
|
|
3141
3770
|
...baseMetadata,
|
|
3142
3771
|
sourceUnit: "table_row",
|
|
3143
|
-
tableId:
|
|
3772
|
+
tableId: tableId2 ?? "",
|
|
3144
3773
|
tableSpanId: tableSpan.id,
|
|
3145
3774
|
rowIndex: String(rowIndex),
|
|
3146
3775
|
isHeader: String(isHeader)
|
|
@@ -3164,7 +3793,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
3164
3793
|
sourceUnit: "table_cell",
|
|
3165
3794
|
parentSpanId: rowSpan.id,
|
|
3166
3795
|
table: {
|
|
3167
|
-
tableId,
|
|
3796
|
+
tableId: tableId2,
|
|
3168
3797
|
tableSpanId: tableSpan.id,
|
|
3169
3798
|
rowSpanId: rowSpan.id,
|
|
3170
3799
|
rowIndex,
|
|
@@ -3175,7 +3804,7 @@ function buildSourceSpansForUnit(unit, index, options) {
|
|
|
3175
3804
|
metadata: {
|
|
3176
3805
|
...baseMetadata,
|
|
3177
3806
|
sourceUnit: "table_cell",
|
|
3178
|
-
tableId:
|
|
3807
|
+
tableId: tableId2 ?? "",
|
|
3179
3808
|
tableSpanId: tableSpan.id,
|
|
3180
3809
|
rowSpanId: rowSpan.id,
|
|
3181
3810
|
rowIndex: String(rowIndex),
|
|
@@ -3330,7 +3959,7 @@ function buildSourceContext(spans, maxChars = 12e3) {
|
|
|
3330
3959
|
const lines = [];
|
|
3331
3960
|
let length = 0;
|
|
3332
3961
|
for (const span of orderSourceSpansForContext(spans)) {
|
|
3333
|
-
const unit =
|
|
3962
|
+
const unit = sourceUnit3(span);
|
|
3334
3963
|
const table = span.table;
|
|
3335
3964
|
const tableContext = [
|
|
3336
3965
|
unit ? ` unit:${unit}` : "",
|
|
@@ -3354,11 +3983,11 @@ ${lines.join("\n\n")}
|
|
|
3354
3983
|
|
|
3355
3984
|
Use sourceSpan IDs when grounding extracted contractual values.`;
|
|
3356
3985
|
}
|
|
3357
|
-
function
|
|
3986
|
+
function sourceUnit3(span) {
|
|
3358
3987
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
3359
3988
|
}
|
|
3360
3989
|
function sourceContextRank(span) {
|
|
3361
|
-
switch (
|
|
3990
|
+
switch (sourceUnit3(span)) {
|
|
3362
3991
|
case "table_row":
|
|
3363
3992
|
return 0;
|
|
3364
3993
|
case "table":
|
|
@@ -3377,10 +4006,10 @@ function sourceContextRank(span) {
|
|
|
3377
4006
|
}
|
|
3378
4007
|
function orderSourceSpansForContext(spans) {
|
|
3379
4008
|
const parentRows = new Set(
|
|
3380
|
-
spans.filter((span) =>
|
|
4009
|
+
spans.filter((span) => sourceUnit3(span) === "table_row").map((span) => span.id)
|
|
3381
4010
|
);
|
|
3382
4011
|
const filtered = spans.filter((span) => {
|
|
3383
|
-
if (
|
|
4012
|
+
if (sourceUnit3(span) !== "table_cell") return true;
|
|
3384
4013
|
const parent = span.parentSpanId ?? span.table?.rowSpanId ?? span.metadata?.rowSpanId;
|
|
3385
4014
|
return !parent || !parentRows.has(parent);
|
|
3386
4015
|
});
|
|
@@ -3774,7 +4403,7 @@ function stringValue2(record, ...keys) {
|
|
|
3774
4403
|
function stringArray(value) {
|
|
3775
4404
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && item.length > 0) : [];
|
|
3776
4405
|
}
|
|
3777
|
-
function
|
|
4406
|
+
function sourceUnit4(span) {
|
|
3778
4407
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
3779
4408
|
}
|
|
3780
4409
|
function spanPage(span) {
|
|
@@ -3784,7 +4413,7 @@ function spanPageEnd(span) {
|
|
|
3784
4413
|
return span.pageEnd ?? span.location?.endPage ?? spanPage(span);
|
|
3785
4414
|
}
|
|
3786
4415
|
function sourceSpansForPage(sourceSpans, page) {
|
|
3787
|
-
return sourceSpans.filter((span) => spanPage(span) === page &&
|
|
4416
|
+
return sourceSpans.filter((span) => spanPage(span) === page && sourceUnit4(span) === "page").map((span) => span.id);
|
|
3788
4417
|
}
|
|
3789
4418
|
function nodePageOverlaps(node, record) {
|
|
3790
4419
|
const recordStart = numberValue(record, "pageNumber", "pageStart", "resolvedFromPage");
|
|
@@ -3836,8 +4465,8 @@ function attachDocumentNodeIds(document, nodes) {
|
|
|
3836
4465
|
function buildNodeFromSection(section, index) {
|
|
3837
4466
|
const title = stringValue2(section, "title", "name", "sectionRef") ?? `Section ${index + 1}`;
|
|
3838
4467
|
const id = stringValue2(section, "documentNodeId", "recordId") ?? `section:${index}:${slugPart(title)}`;
|
|
3839
|
-
const
|
|
3840
|
-
const
|
|
4468
|
+
const pageStart2 = numberValue(section, "pageStart", "pageNumber");
|
|
4469
|
+
const pageEnd2 = numberValue(section, "pageEnd", "pageNumber") ?? pageStart2;
|
|
3841
4470
|
const type = stringValue2(section, "type");
|
|
3842
4471
|
const coverageType = stringValue2(section, "coverageType");
|
|
3843
4472
|
const sourceSpanIds = stringArray(section.sourceSpanIds);
|
|
@@ -3852,8 +4481,8 @@ function buildNodeFromSection(section, index) {
|
|
|
3852
4481
|
label: type,
|
|
3853
4482
|
level: 2,
|
|
3854
4483
|
sectionNumber: stringValue2(subsection, "sectionNumber"),
|
|
3855
|
-
pageStart: numberValue(subsection, "pageNumber") ??
|
|
3856
|
-
pageEnd: numberValue(subsection, "pageNumber") ??
|
|
4484
|
+
pageStart: numberValue(subsection, "pageNumber") ?? pageStart2,
|
|
4485
|
+
pageEnd: numberValue(subsection, "pageNumber") ?? pageStart2,
|
|
3857
4486
|
excerpt: stringValue2(subsection, "excerpt"),
|
|
3858
4487
|
content: stringValue2(subsection, "content"),
|
|
3859
4488
|
sourceSpanIds: stringArray(subsection.sourceSpanIds),
|
|
@@ -3868,8 +4497,8 @@ function buildNodeFromSection(section, index) {
|
|
|
3868
4497
|
label: type,
|
|
3869
4498
|
level: 1,
|
|
3870
4499
|
sectionNumber: stringValue2(section, "sectionNumber"),
|
|
3871
|
-
pageStart,
|
|
3872
|
-
pageEnd,
|
|
4500
|
+
pageStart: pageStart2,
|
|
4501
|
+
pageEnd: pageEnd2,
|
|
3873
4502
|
formNumber: stringValue2(section, "formNumber"),
|
|
3874
4503
|
formTitle: stringValue2(section, "formTitle"),
|
|
3875
4504
|
excerpt: stringValue2(section, "excerpt"),
|
|
@@ -3882,17 +4511,17 @@ function buildNodeFromSection(section, index) {
|
|
|
3882
4511
|
}
|
|
3883
4512
|
function buildNodesFromSourceSpans(sourceSpans) {
|
|
3884
4513
|
const candidates = sourceSpans.filter((span) => {
|
|
3885
|
-
const unit =
|
|
4514
|
+
const unit = sourceUnit4(span);
|
|
3886
4515
|
return unit === "section" || unit === "section_candidate" || unit === "page";
|
|
3887
4516
|
});
|
|
3888
4517
|
return candidates.sort((left, right) => (spanPage(left) ?? 0) - (spanPage(right) ?? 0) || left.id.localeCompare(right.id)).map((span, index) => {
|
|
3889
|
-
const title = span.sectionId ?? span.formNumber ?? (
|
|
4518
|
+
const title = span.sectionId ?? span.formNumber ?? (sourceUnit4(span) === "page" && spanPage(span) ? `Page ${spanPage(span)}` : `Source unit ${index + 1}`);
|
|
3890
4519
|
return {
|
|
3891
4520
|
id: `source:${index}:${slugPart(span.id)}`,
|
|
3892
4521
|
title,
|
|
3893
4522
|
originalTitle: title,
|
|
3894
|
-
type:
|
|
3895
|
-
label:
|
|
4523
|
+
type: sourceUnit4(span),
|
|
4524
|
+
label: sourceUnit4(span),
|
|
3896
4525
|
level: 1,
|
|
3897
4526
|
pageStart: spanPage(span),
|
|
3898
4527
|
pageEnd: spanPageEnd(span),
|
|
@@ -7644,7 +8273,7 @@ function numberValue2(value) {
|
|
|
7644
8273
|
function normalize(value) {
|
|
7645
8274
|
return value.toLowerCase().replace(/&/g, "and").replace(/[^a-z0-9]+/g, " ").trim();
|
|
7646
8275
|
}
|
|
7647
|
-
function
|
|
8276
|
+
function sourceUnit5(span) {
|
|
7648
8277
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
7649
8278
|
}
|
|
7650
8279
|
function pageNumber(span) {
|
|
@@ -7714,7 +8343,7 @@ function firstField(fields, patterns) {
|
|
|
7714
8343
|
}
|
|
7715
8344
|
function coverageFromRow(span) {
|
|
7716
8345
|
const rowText = span.text.trim();
|
|
7717
|
-
if (!rowText ||
|
|
8346
|
+
if (!rowText || sourceUnit5(span) !== "table_row") return void 0;
|
|
7718
8347
|
if (span.table?.isHeader || span.metadata?.isHeader === "true") return void 0;
|
|
7719
8348
|
const fields = splitRowFields(rowText);
|
|
7720
8349
|
let name;
|
|
@@ -7794,7 +8423,7 @@ function recoverCoverageScheduleRows(params) {
|
|
|
7794
8423
|
const payload = params.memory.get("coverage_limits");
|
|
7795
8424
|
const existing = Array.isArray(payload?.coverages) ? payload.coverages : [];
|
|
7796
8425
|
const pages = coveragePages(params.pageAssignments);
|
|
7797
|
-
const candidates = params.sourceSpans.filter((span) =>
|
|
8426
|
+
const candidates = params.sourceSpans.filter((span) => sourceUnit5(span) === "table_row").filter((span) => {
|
|
7798
8427
|
const page = pageNumber(span);
|
|
7799
8428
|
return page !== void 0 && pages.has(page);
|
|
7800
8429
|
}).map(coverageFromRow).filter((coverage) => Boolean(coverage));
|
|
@@ -8430,13 +9059,13 @@ function buildPlanFromPageAssignments(pageAssignments, pageCount, formInventory)
|
|
|
8430
9059
|
const expanded = new Set(pages);
|
|
8431
9060
|
for (const page of pages) {
|
|
8432
9061
|
for (const form of contextualForms) {
|
|
8433
|
-
const
|
|
8434
|
-
const
|
|
9062
|
+
const pageStart2 = form.pageStart;
|
|
9063
|
+
const pageEnd2 = form.pageEnd ?? form.pageStart;
|
|
8435
9064
|
const formType = form.formType;
|
|
8436
9065
|
const supportsContextualExpansion = extractorName === "endorsements" ? formType === "endorsement" : formType === "coverage" || formType === "endorsement";
|
|
8437
9066
|
if (!supportsContextualExpansion) continue;
|
|
8438
|
-
if (page <
|
|
8439
|
-
for (let current =
|
|
9067
|
+
if (page < pageStart2 || page > pageEnd2) continue;
|
|
9068
|
+
for (let current = pageStart2; current <= pageEnd2; current += 1) {
|
|
8440
9069
|
expanded.add(current);
|
|
8441
9070
|
}
|
|
8442
9071
|
}
|
|
@@ -8517,11 +9146,11 @@ function textMatches(record, span) {
|
|
|
8517
9146
|
function sourceHashFor(spans) {
|
|
8518
9147
|
return spans.map((span) => span.textHash ?? span.hash).filter(Boolean).join(":") || void 0;
|
|
8519
9148
|
}
|
|
8520
|
-
function
|
|
9149
|
+
function sourceUnit6(span) {
|
|
8521
9150
|
return span.sourceUnit ?? span.metadata?.sourceUnit;
|
|
8522
9151
|
}
|
|
8523
9152
|
function hierarchyScore(span) {
|
|
8524
|
-
switch (
|
|
9153
|
+
switch (sourceUnit6(span)) {
|
|
8525
9154
|
case "table_row":
|
|
8526
9155
|
return 5;
|
|
8527
9156
|
case "table":
|
|
@@ -8544,8 +9173,8 @@ function preferParentRows(matches, sourceSpans) {
|
|
|
8544
9173
|
const expanded = [];
|
|
8545
9174
|
const seen = /* @__PURE__ */ new Set();
|
|
8546
9175
|
for (const match of matches) {
|
|
8547
|
-
const parent =
|
|
8548
|
-
const preferred = parent &&
|
|
9176
|
+
const parent = sourceUnit6(match) === "table_cell" ? byId.get(parentRowId(match) ?? "") : void 0;
|
|
9177
|
+
const preferred = parent && sourceUnit6(parent) === "table_row" ? parent : match;
|
|
8549
9178
|
if (seen.has(preferred.id)) continue;
|
|
8550
9179
|
seen.add(preferred.id);
|
|
8551
9180
|
expanded.push(preferred);
|
|
@@ -8554,11 +9183,11 @@ function preferParentRows(matches, sourceSpans) {
|
|
|
8554
9183
|
}
|
|
8555
9184
|
function findSourceSpansForRecord(record, sourceSpans) {
|
|
8556
9185
|
if (sourceSpans.length === 0) return [];
|
|
8557
|
-
const
|
|
8558
|
-
const
|
|
9186
|
+
const pageStart2 = numberValue3(record, "pageNumber", "pageStart");
|
|
9187
|
+
const pageEnd2 = numberValue3(record, "pageNumber", "pageEnd");
|
|
8559
9188
|
const scored = sourceSpans.map((span) => {
|
|
8560
9189
|
let score = 0;
|
|
8561
|
-
if (pageOverlaps(
|
|
9190
|
+
if (pageOverlaps(pageStart2, pageEnd2, span)) score += 4;
|
|
8562
9191
|
if (formMatches(record, span)) score += 3;
|
|
8563
9192
|
if (textMatches(record, span)) score += 2;
|
|
8564
9193
|
if (score > 0) score += hierarchyScore(span);
|
|
@@ -8597,6 +9226,422 @@ function groundExtractionMemoryWithSourceSpans(memory, sourceSpans) {
|
|
|
8597
9226
|
}
|
|
8598
9227
|
}
|
|
8599
9228
|
|
|
9229
|
+
// src/extraction/source-tree-extractor.ts
|
|
9230
|
+
var import_zod41 = require("zod");
|
|
9231
|
+
var ORGANIZABLE_KINDS = [
|
|
9232
|
+
"page_group",
|
|
9233
|
+
"form",
|
|
9234
|
+
"endorsement",
|
|
9235
|
+
"section",
|
|
9236
|
+
"schedule",
|
|
9237
|
+
"clause"
|
|
9238
|
+
];
|
|
9239
|
+
var SourceTreeOrganizationSchema = import_zod41.z.object({
|
|
9240
|
+
labels: import_zod41.z.array(import_zod41.z.object({
|
|
9241
|
+
nodeId: import_zod41.z.string(),
|
|
9242
|
+
kind: import_zod41.z.enum([
|
|
9243
|
+
"document",
|
|
9244
|
+
"page_group",
|
|
9245
|
+
"page",
|
|
9246
|
+
"form",
|
|
9247
|
+
"endorsement",
|
|
9248
|
+
"section",
|
|
9249
|
+
"schedule",
|
|
9250
|
+
"clause",
|
|
9251
|
+
"table",
|
|
9252
|
+
"table_row",
|
|
9253
|
+
"table_cell",
|
|
9254
|
+
"text"
|
|
9255
|
+
]).optional(),
|
|
9256
|
+
title: import_zod41.z.string().optional(),
|
|
9257
|
+
description: import_zod41.z.string().optional()
|
|
9258
|
+
})).default([]),
|
|
9259
|
+
groups: import_zod41.z.array(import_zod41.z.object({
|
|
9260
|
+
kind: import_zod41.z.enum(ORGANIZABLE_KINDS),
|
|
9261
|
+
title: import_zod41.z.string(),
|
|
9262
|
+
description: import_zod41.z.string().optional(),
|
|
9263
|
+
childNodeIds: import_zod41.z.array(import_zod41.z.string()).min(1)
|
|
9264
|
+
})).default([])
|
|
9265
|
+
});
|
|
9266
|
+
var SourceBackedValueForPromptSchema = import_zod41.z.object({
|
|
9267
|
+
value: import_zod41.z.string(),
|
|
9268
|
+
normalizedValue: import_zod41.z.string().optional(),
|
|
9269
|
+
confidence: import_zod41.z.enum(["low", "medium", "high"]).optional(),
|
|
9270
|
+
sourceNodeIds: import_zod41.z.array(import_zod41.z.string()).default([]),
|
|
9271
|
+
sourceSpanIds: import_zod41.z.array(import_zod41.z.string()).default([])
|
|
9272
|
+
});
|
|
9273
|
+
var OperationalProfilePromptSchema = import_zod41.z.object({
|
|
9274
|
+
documentType: import_zod41.z.enum(["policy", "quote"]).optional(),
|
|
9275
|
+
policyTypes: import_zod41.z.array(import_zod41.z.string()).optional(),
|
|
9276
|
+
policyNumber: SourceBackedValueForPromptSchema.optional(),
|
|
9277
|
+
namedInsured: SourceBackedValueForPromptSchema.optional(),
|
|
9278
|
+
insurer: SourceBackedValueForPromptSchema.optional(),
|
|
9279
|
+
broker: SourceBackedValueForPromptSchema.optional(),
|
|
9280
|
+
effectiveDate: SourceBackedValueForPromptSchema.optional(),
|
|
9281
|
+
expirationDate: SourceBackedValueForPromptSchema.optional(),
|
|
9282
|
+
retroactiveDate: SourceBackedValueForPromptSchema.optional(),
|
|
9283
|
+
premium: SourceBackedValueForPromptSchema.optional(),
|
|
9284
|
+
coverageTypes: import_zod41.z.array(import_zod41.z.string()).optional(),
|
|
9285
|
+
coverages: import_zod41.z.array(import_zod41.z.object({
|
|
9286
|
+
name: import_zod41.z.string(),
|
|
9287
|
+
coverageCode: import_zod41.z.string().optional(),
|
|
9288
|
+
limit: import_zod41.z.string().optional(),
|
|
9289
|
+
deductible: import_zod41.z.string().optional(),
|
|
9290
|
+
premium: import_zod41.z.string().optional(),
|
|
9291
|
+
formNumber: import_zod41.z.string().optional(),
|
|
9292
|
+
sectionRef: import_zod41.z.string().optional(),
|
|
9293
|
+
sourceNodeIds: import_zod41.z.array(import_zod41.z.string()).default([]),
|
|
9294
|
+
sourceSpanIds: import_zod41.z.array(import_zod41.z.string()).default([])
|
|
9295
|
+
})).optional(),
|
|
9296
|
+
sourceNodeIds: import_zod41.z.array(import_zod41.z.string()).optional(),
|
|
9297
|
+
sourceSpanIds: import_zod41.z.array(import_zod41.z.string()).optional()
|
|
9298
|
+
});
|
|
9299
|
+
function cleanText(value, fallback) {
|
|
9300
|
+
const text = value?.replace(/\s+/g, " ").trim();
|
|
9301
|
+
return text || fallback;
|
|
9302
|
+
}
|
|
9303
|
+
function compactNode(node) {
|
|
9304
|
+
return {
|
|
9305
|
+
id: node.id,
|
|
9306
|
+
kind: node.kind,
|
|
9307
|
+
title: node.title,
|
|
9308
|
+
path: node.path,
|
|
9309
|
+
pageStart: node.pageStart,
|
|
9310
|
+
pageEnd: node.pageEnd,
|
|
9311
|
+
sourceSpanIds: node.sourceSpanIds.slice(0, 8),
|
|
9312
|
+
text: (node.textExcerpt ?? node.description).slice(0, 700)
|
|
9313
|
+
};
|
|
9314
|
+
}
|
|
9315
|
+
function buildOrganizationPrompt(sourceTree) {
|
|
9316
|
+
const nodes = sourceTree.filter((node) => node.kind !== "table_cell").slice(0, 180).map(compactNode);
|
|
9317
|
+
return `You organize an insurance document source tree.
|
|
9318
|
+
|
|
9319
|
+
Rules:
|
|
9320
|
+
- Use only node IDs from the provided list.
|
|
9321
|
+
- 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.
|
|
9323
|
+
- Groups must list existing childNodeIds only.
|
|
9324
|
+
- Keep descriptions short and useful for search.
|
|
9325
|
+
|
|
9326
|
+
Source nodes:
|
|
9327
|
+
${JSON.stringify(nodes, null, 2)}
|
|
9328
|
+
|
|
9329
|
+
Return JSON with labels and groups only.`;
|
|
9330
|
+
}
|
|
9331
|
+
function buildOperationalProfilePrompt(sourceTree, fallback) {
|
|
9332
|
+
const nodes = sourceTree.filter((node) => node.kind !== "document").slice(0, 240).map(compactNode);
|
|
9333
|
+
return `Extract a source-backed operational profile for an insurance policy or quote.
|
|
9334
|
+
|
|
9335
|
+
Return only high-value operational facts needed for policy lists, Q&A, compliance, and certificate generation:
|
|
9336
|
+
- policy number, named insured, insurer/carrier/security, broker/producer, policy period, retroactive date, premium
|
|
9337
|
+
- coverage lines with limits, deductibles, premiums, and form references
|
|
9338
|
+
- coverage type labels
|
|
9339
|
+
|
|
9340
|
+
Rules:
|
|
9341
|
+
- Every returned value must include sourceNodeIds or sourceSpanIds from the provided nodes.
|
|
9342
|
+
- If a value is not directly supported, omit it.
|
|
9343
|
+
- Prefer declarations, schedules, premium tables, and endorsement schedules over generic policy wording.
|
|
9344
|
+
- Do not copy entire policy wording into fields.
|
|
9345
|
+
|
|
9346
|
+
Deterministic baseline:
|
|
9347
|
+
${JSON.stringify(fallback, null, 2)}
|
|
9348
|
+
|
|
9349
|
+
Source nodes:
|
|
9350
|
+
${JSON.stringify(nodes, null, 2)}
|
|
9351
|
+
|
|
9352
|
+
Return JSON for the operational profile.`;
|
|
9353
|
+
}
|
|
9354
|
+
function groupNodeId(documentId, group) {
|
|
9355
|
+
return [
|
|
9356
|
+
documentId.replace(/[^a-zA-Z0-9_.:-]/g, "_"),
|
|
9357
|
+
"source_node",
|
|
9358
|
+
group.kind,
|
|
9359
|
+
group.childNodeIds.join("_").replace(/[^a-zA-Z0-9_.:-]/g, "_").slice(0, 80)
|
|
9360
|
+
].join(":");
|
|
9361
|
+
}
|
|
9362
|
+
function applyOrganization(sourceTree, organization) {
|
|
9363
|
+
const byId = new Map(sourceTree.map((node) => [node.id, node]));
|
|
9364
|
+
let nextTree = sourceTree.map((node) => {
|
|
9365
|
+
const label = organization.labels.find((item) => item.nodeId === node.id);
|
|
9366
|
+
if (!label) return node;
|
|
9367
|
+
return {
|
|
9368
|
+
...node,
|
|
9369
|
+
kind: label.kind ?? node.kind,
|
|
9370
|
+
title: cleanText(label.title, node.title),
|
|
9371
|
+
description: cleanText(label.description, node.description)
|
|
9372
|
+
};
|
|
9373
|
+
});
|
|
9374
|
+
for (const group of organization.groups.slice(0, 40)) {
|
|
9375
|
+
const children = group.childNodeIds.map((id2) => byId.get(id2)).filter((node2) => Boolean(node2));
|
|
9376
|
+
if (children.length === 0) continue;
|
|
9377
|
+
const parentId = children[0].parentId;
|
|
9378
|
+
if (!children.every((child) => child.parentId === parentId)) continue;
|
|
9379
|
+
const documentId = children[0].documentId;
|
|
9380
|
+
const id = groupNodeId(documentId, group);
|
|
9381
|
+
if (byId.has(id)) continue;
|
|
9382
|
+
const sourceSpanIds = [...new Set(children.flatMap((child) => child.sourceSpanIds))];
|
|
9383
|
+
const pageStarts = children.map((child) => child.pageStart).filter((page) => typeof page === "number");
|
|
9384
|
+
const pageEnds = children.map((child) => child.pageEnd ?? child.pageStart).filter((page) => typeof page === "number");
|
|
9385
|
+
const order = Math.min(...children.map((child) => child.order));
|
|
9386
|
+
const node = {
|
|
9387
|
+
id,
|
|
9388
|
+
documentId,
|
|
9389
|
+
parentId,
|
|
9390
|
+
kind: group.kind,
|
|
9391
|
+
title: group.title,
|
|
9392
|
+
description: group.description ?? group.title,
|
|
9393
|
+
textExcerpt: children.map((child) => child.textExcerpt ?? child.description).filter(Boolean).join("\n\n").slice(0, 1600),
|
|
9394
|
+
sourceSpanIds,
|
|
9395
|
+
pageStart: pageStarts.length ? Math.min(...pageStarts) : void 0,
|
|
9396
|
+
pageEnd: pageEnds.length ? Math.max(...pageEnds) : void 0,
|
|
9397
|
+
bbox: children.flatMap((child) => child.bbox ?? []).slice(0, 12),
|
|
9398
|
+
order,
|
|
9399
|
+
path: "",
|
|
9400
|
+
metadata: { sourceTreeVersion: "v3", organizer: "llm_group" }
|
|
9401
|
+
};
|
|
9402
|
+
nextTree = [
|
|
9403
|
+
...nextTree.map(
|
|
9404
|
+
(child) => group.childNodeIds.includes(child.id) ? { ...child, parentId: id, order: child.order + 1e-3 } : child
|
|
9405
|
+
),
|
|
9406
|
+
node
|
|
9407
|
+
];
|
|
9408
|
+
byId.set(id, node);
|
|
9409
|
+
}
|
|
9410
|
+
return normalizeDocumentSourceTreePaths(nextTree);
|
|
9411
|
+
}
|
|
9412
|
+
function sourceTreeToOutline(sourceTree) {
|
|
9413
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
9414
|
+
for (const node of sourceTree.filter((item) => item.kind !== "document")) {
|
|
9415
|
+
const group = byParent.get(node.parentId) ?? [];
|
|
9416
|
+
group.push(node);
|
|
9417
|
+
byParent.set(node.parentId, group);
|
|
9418
|
+
}
|
|
9419
|
+
const root = sourceTree.find((node) => node.kind === "document");
|
|
9420
|
+
const visit = (node) => ({
|
|
9421
|
+
id: node.id,
|
|
9422
|
+
title: node.title,
|
|
9423
|
+
type: node.kind,
|
|
9424
|
+
label: node.kind,
|
|
9425
|
+
pageStart: node.pageStart,
|
|
9426
|
+
pageEnd: node.pageEnd,
|
|
9427
|
+
excerpt: node.textExcerpt,
|
|
9428
|
+
content: node.textExcerpt,
|
|
9429
|
+
sourceSpanIds: node.sourceSpanIds,
|
|
9430
|
+
sourceTextHash: node.sourceSpanIds.join(":") || void 0,
|
|
9431
|
+
interpretationLabels: [node.kind],
|
|
9432
|
+
children: (byParent.get(node.id) ?? []).map(visit)
|
|
9433
|
+
});
|
|
9434
|
+
return (byParent.get(root?.id) ?? []).map(visit);
|
|
9435
|
+
}
|
|
9436
|
+
function valueOf(profile, key) {
|
|
9437
|
+
const value = profile[key];
|
|
9438
|
+
return value && typeof value === "object" && !Array.isArray(value) && "value" in value ? String(value.value) : void 0;
|
|
9439
|
+
}
|
|
9440
|
+
function materializeDocument(params) {
|
|
9441
|
+
const profile = params.operationalProfile;
|
|
9442
|
+
const policyNumber = valueOf(profile, "policyNumber") ?? "Unknown";
|
|
9443
|
+
const insuredName = valueOf(profile, "namedInsured") ?? "Unknown";
|
|
9444
|
+
const carrier = valueOf(profile, "insurer") ?? "Unknown";
|
|
9445
|
+
const effectiveDate = valueOf(profile, "effectiveDate") ?? "Unknown";
|
|
9446
|
+
const expirationDate = valueOf(profile, "expirationDate") ?? "Unknown";
|
|
9447
|
+
const premium = valueOf(profile, "premium");
|
|
9448
|
+
const coverages = profile.coverages.map((coverage) => ({
|
|
9449
|
+
name: coverage.name,
|
|
9450
|
+
coverageCode: coverage.coverageCode,
|
|
9451
|
+
limit: coverage.limit,
|
|
9452
|
+
deductible: coverage.deductible,
|
|
9453
|
+
premium: coverage.premium,
|
|
9454
|
+
formNumber: coverage.formNumber,
|
|
9455
|
+
sectionRef: coverage.sectionRef,
|
|
9456
|
+
sourceSpanIds: coverage.sourceSpanIds,
|
|
9457
|
+
documentNodeId: coverage.sourceNodeIds[0],
|
|
9458
|
+
originalContent: [coverage.name, coverage.limit, coverage.deductible, coverage.premium].filter(Boolean).join(" | ")
|
|
9459
|
+
}));
|
|
9460
|
+
const documentOutline = sourceTreeToOutline(params.sourceTree);
|
|
9461
|
+
const documentMetadata = {
|
|
9462
|
+
sourceTreeVersion: "v3",
|
|
9463
|
+
sourceTreeCanonical: true,
|
|
9464
|
+
tableOfContents: documentOutline.map((node) => ({
|
|
9465
|
+
title: node.title,
|
|
9466
|
+
pageStart: node.pageStart,
|
|
9467
|
+
pageEnd: node.pageEnd,
|
|
9468
|
+
documentNodeId: node.id,
|
|
9469
|
+
sourceSpanIds: node.sourceSpanIds
|
|
9470
|
+
})),
|
|
9471
|
+
agentGuidance: [
|
|
9472
|
+
{
|
|
9473
|
+
kind: "source_tree",
|
|
9474
|
+
title: "Use the source tree as canonical evidence",
|
|
9475
|
+
detail: "Operational fields are projections from source nodes and source spans. Use source nodes for policy wording and exact provenance."
|
|
9476
|
+
}
|
|
9477
|
+
]
|
|
9478
|
+
};
|
|
9479
|
+
const summary = [
|
|
9480
|
+
carrier !== "Unknown" ? carrier : void 0,
|
|
9481
|
+
policyNumber !== "Unknown" ? `#${policyNumber}` : void 0,
|
|
9482
|
+
insuredName !== "Unknown" ? `for ${insuredName}` : void 0,
|
|
9483
|
+
profile.coverageTypes.length ? `covering ${profile.coverageTypes.slice(0, 5).join(", ")}` : void 0
|
|
9484
|
+
].filter(Boolean).join(" ");
|
|
9485
|
+
const base = {
|
|
9486
|
+
id: params.id,
|
|
9487
|
+
type: profile.documentType,
|
|
9488
|
+
carrier,
|
|
9489
|
+
security: carrier,
|
|
9490
|
+
insuredName,
|
|
9491
|
+
premium,
|
|
9492
|
+
policyTypes: profile.policyTypes,
|
|
9493
|
+
coverages,
|
|
9494
|
+
documentMetadata,
|
|
9495
|
+
documentOutline,
|
|
9496
|
+
declarations: {
|
|
9497
|
+
fields: [
|
|
9498
|
+
profile.policyNumber ? { field: "policyNumber", value: profile.policyNumber.value, sourceSpanIds: profile.policyNumber.sourceSpanIds } : void 0,
|
|
9499
|
+
profile.namedInsured ? { field: "namedInsured", value: profile.namedInsured.value, sourceSpanIds: profile.namedInsured.sourceSpanIds } : void 0,
|
|
9500
|
+
profile.insurer ? { field: "insurer", value: profile.insurer.value, sourceSpanIds: profile.insurer.sourceSpanIds } : void 0,
|
|
9501
|
+
profile.effectiveDate ? { field: "policyPeriodStart", value: profile.effectiveDate.value, sourceSpanIds: profile.effectiveDate.sourceSpanIds } : void 0,
|
|
9502
|
+
profile.expirationDate ? { field: "policyPeriodEnd", value: profile.expirationDate.value, sourceSpanIds: profile.expirationDate.sourceSpanIds } : void 0
|
|
9503
|
+
].filter(Boolean)
|
|
9504
|
+
},
|
|
9505
|
+
supplementaryFacts: profile.endorsementSupport.map((item) => ({
|
|
9506
|
+
key: item.kind,
|
|
9507
|
+
value: item.summary,
|
|
9508
|
+
sourceSpanIds: item.sourceSpanIds,
|
|
9509
|
+
documentNodeId: item.sourceNodeIds[0]
|
|
9510
|
+
})),
|
|
9511
|
+
summary: summary || void 0
|
|
9512
|
+
};
|
|
9513
|
+
if (profile.documentType === "quote") {
|
|
9514
|
+
return {
|
|
9515
|
+
...base,
|
|
9516
|
+
type: "quote",
|
|
9517
|
+
quoteNumber: policyNumber,
|
|
9518
|
+
proposedEffectiveDate: effectiveDate === "Unknown" ? void 0 : effectiveDate,
|
|
9519
|
+
proposedExpirationDate: expirationDate === "Unknown" ? void 0 : expirationDate
|
|
9520
|
+
};
|
|
9521
|
+
}
|
|
9522
|
+
return {
|
|
9523
|
+
...base,
|
|
9524
|
+
type: "policy",
|
|
9525
|
+
policyNumber,
|
|
9526
|
+
effectiveDate,
|
|
9527
|
+
expirationDate,
|
|
9528
|
+
retroactiveDate: valueOf(profile, "retroactiveDate")
|
|
9529
|
+
};
|
|
9530
|
+
}
|
|
9531
|
+
async function runSourceTreeExtraction(params) {
|
|
9532
|
+
let sourceTree = buildDocumentSourceTree(params.sourceSpans, params.id);
|
|
9533
|
+
const warnings = [];
|
|
9534
|
+
let modelCalls = 0;
|
|
9535
|
+
let callsWithUsage = 0;
|
|
9536
|
+
let callsMissingUsage = 0;
|
|
9537
|
+
const tokenUsage = { inputTokens: 0, outputTokens: 0 };
|
|
9538
|
+
const performanceReport = { modelCalls: [], totalModelCallDurationMs: 0 };
|
|
9539
|
+
const localTrack = (usage, report) => {
|
|
9540
|
+
modelCalls += 1;
|
|
9541
|
+
if (usage) {
|
|
9542
|
+
callsWithUsage += 1;
|
|
9543
|
+
tokenUsage.inputTokens += usage.inputTokens;
|
|
9544
|
+
tokenUsage.outputTokens += usage.outputTokens;
|
|
9545
|
+
} else {
|
|
9546
|
+
callsMissingUsage += 1;
|
|
9547
|
+
}
|
|
9548
|
+
if (report) {
|
|
9549
|
+
performanceReport.modelCalls.push({ ...report, usage, usageReported: !!usage });
|
|
9550
|
+
if (report.durationMs != null) performanceReport.totalModelCallDurationMs += report.durationMs;
|
|
9551
|
+
}
|
|
9552
|
+
params.trackUsage(usage, report);
|
|
9553
|
+
};
|
|
9554
|
+
try {
|
|
9555
|
+
const budget = params.resolveBudget("extraction_source_tree", 4096);
|
|
9556
|
+
const startedAt = Date.now();
|
|
9557
|
+
const response = await safeGenerateObject(
|
|
9558
|
+
params.generateObject,
|
|
9559
|
+
{
|
|
9560
|
+
prompt: buildOrganizationPrompt(sourceTree),
|
|
9561
|
+
schema: SourceTreeOrganizationSchema,
|
|
9562
|
+
maxTokens: budget.maxTokens,
|
|
9563
|
+
taskKind: "extraction_source_tree",
|
|
9564
|
+
budgetDiagnostics: budget,
|
|
9565
|
+
providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans }
|
|
9566
|
+
},
|
|
9567
|
+
{
|
|
9568
|
+
fallback: { labels: [], groups: [] },
|
|
9569
|
+
log: params.log
|
|
9570
|
+
}
|
|
9571
|
+
);
|
|
9572
|
+
localTrack(response.usage, {
|
|
9573
|
+
taskKind: "extraction_source_tree",
|
|
9574
|
+
label: "source_tree_organizer",
|
|
9575
|
+
maxTokens: budget.maxTokens,
|
|
9576
|
+
durationMs: Date.now() - startedAt
|
|
9577
|
+
});
|
|
9578
|
+
sourceTree = applyOrganization(sourceTree, response.object);
|
|
9579
|
+
} catch (error) {
|
|
9580
|
+
warnings.push(`Source-tree organizer failed; deterministic tree used (${error instanceof Error ? error.message : String(error)})`);
|
|
9581
|
+
}
|
|
9582
|
+
const deterministicProfile = buildDeterministicOperationalProfile({
|
|
9583
|
+
sourceTree,
|
|
9584
|
+
sourceSpans: params.sourceSpans
|
|
9585
|
+
});
|
|
9586
|
+
let operationalProfile = deterministicProfile;
|
|
9587
|
+
try {
|
|
9588
|
+
const validNodeIds = new Set(sourceTree.map((node) => node.id));
|
|
9589
|
+
const validSpanIds = new Set(params.sourceSpans.map((span) => span.id));
|
|
9590
|
+
const budget = params.resolveBudget("extraction_operational_profile", 8192);
|
|
9591
|
+
const startedAt = Date.now();
|
|
9592
|
+
const response = await safeGenerateObject(
|
|
9593
|
+
params.generateObject,
|
|
9594
|
+
{
|
|
9595
|
+
prompt: buildOperationalProfilePrompt(sourceTree, deterministicProfile),
|
|
9596
|
+
schema: OperationalProfilePromptSchema,
|
|
9597
|
+
maxTokens: budget.maxTokens,
|
|
9598
|
+
taskKind: "extraction_operational_profile",
|
|
9599
|
+
budgetDiagnostics: budget,
|
|
9600
|
+
providerOptions: { ...params.providerOptions, sourceSpans: params.sourceSpans, sourceTree }
|
|
9601
|
+
},
|
|
9602
|
+
{
|
|
9603
|
+
fallback: deterministicProfile,
|
|
9604
|
+
log: params.log
|
|
9605
|
+
}
|
|
9606
|
+
);
|
|
9607
|
+
localTrack(response.usage, {
|
|
9608
|
+
taskKind: "extraction_operational_profile",
|
|
9609
|
+
label: "operational_profile",
|
|
9610
|
+
maxTokens: budget.maxTokens,
|
|
9611
|
+
durationMs: Date.now() - startedAt
|
|
9612
|
+
});
|
|
9613
|
+
operationalProfile = mergeOperationalProfile(
|
|
9614
|
+
deterministicProfile,
|
|
9615
|
+
response.object,
|
|
9616
|
+
validNodeIds,
|
|
9617
|
+
validSpanIds
|
|
9618
|
+
);
|
|
9619
|
+
} catch (error) {
|
|
9620
|
+
warnings.push(`Operational profile model pass failed; deterministic profile used (${error instanceof Error ? error.message : String(error)})`);
|
|
9621
|
+
}
|
|
9622
|
+
const document = materializeDocument({
|
|
9623
|
+
id: params.id,
|
|
9624
|
+
sourceTree,
|
|
9625
|
+
operationalProfile
|
|
9626
|
+
});
|
|
9627
|
+
return {
|
|
9628
|
+
sourceTree,
|
|
9629
|
+
sourceSpans: params.sourceSpans,
|
|
9630
|
+
sourceChunks: chunkSourceSpans(params.sourceSpans),
|
|
9631
|
+
operationalProfile,
|
|
9632
|
+
document,
|
|
9633
|
+
chunks: [],
|
|
9634
|
+
warnings: [...warnings, ...operationalProfile.warnings],
|
|
9635
|
+
tokenUsage,
|
|
9636
|
+
usageReporting: {
|
|
9637
|
+
modelCalls,
|
|
9638
|
+
callsWithUsage,
|
|
9639
|
+
callsMissingUsage
|
|
9640
|
+
},
|
|
9641
|
+
performanceReport
|
|
9642
|
+
};
|
|
9643
|
+
}
|
|
9644
|
+
|
|
8600
9645
|
// src/extraction/coordinator.ts
|
|
8601
9646
|
function createExtractor(config) {
|
|
8602
9647
|
const {
|
|
@@ -8782,17 +9827,17 @@ ${span.text}` : span.text;
|
|
|
8782
9827
|
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);
|
|
8783
9828
|
return {
|
|
8784
9829
|
sections: candidateSpans.map((span, index) => {
|
|
8785
|
-
const
|
|
8786
|
-
const
|
|
8787
|
-
const title = span.sectionId ?? span.formNumber ?? firstHeadingLine(span.text) ?? `Policy text page ${
|
|
9830
|
+
const pageStart2 = span.pageStart ?? span.location?.startPage ?? span.location?.page ?? startPage;
|
|
9831
|
+
const pageEnd2 = span.pageEnd ?? span.location?.endPage ?? pageStart2;
|
|
9832
|
+
const title = span.sectionId ?? span.formNumber ?? firstHeadingLine(span.text) ?? `Policy text page ${pageStart2}`;
|
|
8788
9833
|
return {
|
|
8789
9834
|
title,
|
|
8790
9835
|
sectionNumber: span.formNumber,
|
|
8791
|
-
pageStart,
|
|
8792
|
-
pageEnd,
|
|
9836
|
+
pageStart: pageStart2,
|
|
9837
|
+
pageEnd: pageEnd2,
|
|
8793
9838
|
type: inferSectionType(title, span.text),
|
|
8794
9839
|
excerpt: span.text.slice(0, 240),
|
|
8795
|
-
recordId: `section_index_${
|
|
9840
|
+
recordId: `section_index_${pageStart2}_${index}`,
|
|
8796
9841
|
sourceSpanIds: [span.id],
|
|
8797
9842
|
sourceTextHash: span.textHash ?? sourceSpanTextHash(span.text)
|
|
8798
9843
|
};
|
|
@@ -8931,6 +9976,51 @@ ${span.text}` : span.text;
|
|
|
8931
9976
|
await sourceStore.addSourceChunks(sourceChunks);
|
|
8932
9977
|
}
|
|
8933
9978
|
}
|
|
9979
|
+
if (sourceSpans.length > 0) {
|
|
9980
|
+
onProgress?.("Building source-native document tree...");
|
|
9981
|
+
const v3 = await runSourceTreeExtraction({
|
|
9982
|
+
id,
|
|
9983
|
+
sourceSpans,
|
|
9984
|
+
generateObject,
|
|
9985
|
+
providerOptions: activeProviderOptions,
|
|
9986
|
+
resolveBudget,
|
|
9987
|
+
trackUsage,
|
|
9988
|
+
log
|
|
9989
|
+
});
|
|
9990
|
+
const reviewReport2 = {
|
|
9991
|
+
issues: v3.warnings.map((warning) => ({
|
|
9992
|
+
code: "source_tree_warning",
|
|
9993
|
+
severity: "warning",
|
|
9994
|
+
message: warning
|
|
9995
|
+
})),
|
|
9996
|
+
rounds: [],
|
|
9997
|
+
artifacts: [
|
|
9998
|
+
{ kind: "source_tree", label: "Source Tree", itemCount: v3.sourceTree.length },
|
|
9999
|
+
{ kind: "source_spans", label: "Source Spans", itemCount: v3.sourceSpans.length },
|
|
10000
|
+
{ kind: "operational_profile", label: "Operational Profile", itemCount: v3.operationalProfile.coverages.length }
|
|
10001
|
+
],
|
|
10002
|
+
reviewRoundRecords: [],
|
|
10003
|
+
formInventory: [],
|
|
10004
|
+
qualityGateStatus: v3.warnings.length > 0 ? "warning" : "passed"
|
|
10005
|
+
};
|
|
10006
|
+
if (shouldFailQualityGate(qualityGate, reviewReport2.qualityGateStatus)) {
|
|
10007
|
+
throw new Error("Extraction quality gate failed. See reviewReport for blocking issues.");
|
|
10008
|
+
}
|
|
10009
|
+
onProgress?.("Source-tree extraction complete.");
|
|
10010
|
+
return {
|
|
10011
|
+
document: v3.document,
|
|
10012
|
+
chunks: [],
|
|
10013
|
+
sourceSpans: v3.sourceSpans,
|
|
10014
|
+
sourceChunks: v3.sourceChunks,
|
|
10015
|
+
sourceTree: v3.sourceTree,
|
|
10016
|
+
operationalProfile: v3.operationalProfile,
|
|
10017
|
+
warnings: v3.warnings,
|
|
10018
|
+
tokenUsage: v3.tokenUsage,
|
|
10019
|
+
usageReporting: v3.usageReporting,
|
|
10020
|
+
performanceReport: v3.performanceReport,
|
|
10021
|
+
reviewReport: reviewReport2
|
|
10022
|
+
};
|
|
10023
|
+
}
|
|
8934
10024
|
const pipelineCtx = createPipelineContext({
|
|
8935
10025
|
id,
|
|
8936
10026
|
onSave: onCheckpointSave,
|
|
@@ -9801,8 +10891,8 @@ Respond with JSON only:
|
|
|
9801
10891
|
}`;
|
|
9802
10892
|
|
|
9803
10893
|
// src/schemas/application.ts
|
|
9804
|
-
var
|
|
9805
|
-
var FieldTypeSchema =
|
|
10894
|
+
var import_zod42 = require("zod");
|
|
10895
|
+
var FieldTypeSchema = import_zod42.z.enum([
|
|
9806
10896
|
"text",
|
|
9807
10897
|
"numeric",
|
|
9808
10898
|
"currency",
|
|
@@ -9811,138 +10901,138 @@ var FieldTypeSchema = import_zod41.z.enum([
|
|
|
9811
10901
|
"table",
|
|
9812
10902
|
"declaration"
|
|
9813
10903
|
]);
|
|
9814
|
-
var ApplicationFieldSchema =
|
|
9815
|
-
id:
|
|
9816
|
-
label:
|
|
9817
|
-
section:
|
|
10904
|
+
var ApplicationFieldSchema = import_zod42.z.object({
|
|
10905
|
+
id: import_zod42.z.string(),
|
|
10906
|
+
label: import_zod42.z.string(),
|
|
10907
|
+
section: import_zod42.z.string(),
|
|
9818
10908
|
fieldType: FieldTypeSchema,
|
|
9819
|
-
required:
|
|
9820
|
-
options:
|
|
9821
|
-
columns:
|
|
9822
|
-
requiresExplanationIfYes:
|
|
9823
|
-
condition:
|
|
9824
|
-
dependsOn:
|
|
9825
|
-
whenValue:
|
|
10909
|
+
required: import_zod42.z.boolean(),
|
|
10910
|
+
options: import_zod42.z.array(import_zod42.z.string()).optional(),
|
|
10911
|
+
columns: import_zod42.z.array(import_zod42.z.string()).optional(),
|
|
10912
|
+
requiresExplanationIfYes: import_zod42.z.boolean().optional(),
|
|
10913
|
+
condition: import_zod42.z.object({
|
|
10914
|
+
dependsOn: import_zod42.z.string(),
|
|
10915
|
+
whenValue: import_zod42.z.string()
|
|
9826
10916
|
}).optional(),
|
|
9827
|
-
value:
|
|
9828
|
-
source:
|
|
9829
|
-
confidence:
|
|
9830
|
-
sourceSpanIds:
|
|
9831
|
-
userSourceSpanIds:
|
|
9832
|
-
pageNumber:
|
|
9833
|
-
fieldAnchorId:
|
|
9834
|
-
acroFormName:
|
|
9835
|
-
validationStatus:
|
|
9836
|
-
});
|
|
9837
|
-
var ApplicationClassifyResultSchema =
|
|
9838
|
-
isApplication:
|
|
9839
|
-
confidence:
|
|
9840
|
-
applicationType:
|
|
9841
|
-
});
|
|
9842
|
-
var FieldExtractionResultSchema =
|
|
9843
|
-
fields:
|
|
9844
|
-
});
|
|
9845
|
-
var AutoFillMatchSchema =
|
|
9846
|
-
fieldId:
|
|
9847
|
-
value:
|
|
9848
|
-
confidence:
|
|
9849
|
-
contextKey:
|
|
9850
|
-
});
|
|
9851
|
-
var AutoFillResultSchema =
|
|
9852
|
-
matches:
|
|
9853
|
-
});
|
|
9854
|
-
var QuestionBatchResultSchema =
|
|
9855
|
-
batches:
|
|
9856
|
-
});
|
|
9857
|
-
var LookupRequestSchema =
|
|
9858
|
-
type:
|
|
9859
|
-
description:
|
|
9860
|
-
url:
|
|
9861
|
-
targetFieldIds:
|
|
9862
|
-
});
|
|
9863
|
-
var ReplyIntentSchema =
|
|
9864
|
-
primaryIntent:
|
|
9865
|
-
hasAnswers:
|
|
9866
|
-
questionText:
|
|
9867
|
-
questionFieldIds:
|
|
9868
|
-
lookupRequests:
|
|
9869
|
-
});
|
|
9870
|
-
var ParsedAnswerSchema =
|
|
9871
|
-
fieldId:
|
|
9872
|
-
value:
|
|
9873
|
-
explanation:
|
|
9874
|
-
});
|
|
9875
|
-
var AnswerParsingResultSchema =
|
|
9876
|
-
answers:
|
|
9877
|
-
unanswered:
|
|
9878
|
-
});
|
|
9879
|
-
var LookupFillSchema =
|
|
9880
|
-
fieldId:
|
|
9881
|
-
value:
|
|
9882
|
-
source:
|
|
9883
|
-
sourceSpanIds:
|
|
9884
|
-
});
|
|
9885
|
-
var LookupFillResultSchema =
|
|
9886
|
-
fills:
|
|
9887
|
-
unfillable:
|
|
9888
|
-
explanation:
|
|
9889
|
-
});
|
|
9890
|
-
var FlatPdfPlacementSchema =
|
|
9891
|
-
fieldId:
|
|
9892
|
-
page:
|
|
9893
|
-
x:
|
|
9894
|
-
y:
|
|
9895
|
-
text:
|
|
9896
|
-
fontSize:
|
|
9897
|
-
isCheckmark:
|
|
9898
|
-
});
|
|
9899
|
-
var AcroFormMappingSchema =
|
|
9900
|
-
fieldId:
|
|
9901
|
-
acroFormName:
|
|
9902
|
-
value:
|
|
9903
|
-
});
|
|
9904
|
-
var QualityGateStatusSchema =
|
|
9905
|
-
var QualitySeveritySchema =
|
|
9906
|
-
var ApplicationQualityIssueSchema =
|
|
9907
|
-
code:
|
|
10917
|
+
value: import_zod42.z.string().optional(),
|
|
10918
|
+
source: import_zod42.z.string().optional().describe("Where the value came from: auto-fill, user, lookup"),
|
|
10919
|
+
confidence: import_zod42.z.enum(["confirmed", "high", "medium", "low"]).optional(),
|
|
10920
|
+
sourceSpanIds: import_zod42.z.array(import_zod42.z.string()).optional().describe("Stable source spans that support the field value or field anchor"),
|
|
10921
|
+
userSourceSpanIds: import_zod42.z.array(import_zod42.z.string()).optional().describe("Message or attachment spans that support user-provided values"),
|
|
10922
|
+
pageNumber: import_zod42.z.number().int().positive().optional().describe("Application page where the field label or anchor appears"),
|
|
10923
|
+
fieldAnchorId: import_zod42.z.string().optional().describe("Stable field anchor ID derived from page, section, label, and form metadata"),
|
|
10924
|
+
acroFormName: import_zod42.z.string().optional().describe("Native PDF AcroForm field name when available"),
|
|
10925
|
+
validationStatus: import_zod42.z.enum(["valid", "needs_review", "unsupported", "missing"]).optional()
|
|
10926
|
+
});
|
|
10927
|
+
var ApplicationClassifyResultSchema = import_zod42.z.object({
|
|
10928
|
+
isApplication: import_zod42.z.boolean(),
|
|
10929
|
+
confidence: import_zod42.z.number().min(0).max(1),
|
|
10930
|
+
applicationType: import_zod42.z.string().nullable()
|
|
10931
|
+
});
|
|
10932
|
+
var FieldExtractionResultSchema = import_zod42.z.object({
|
|
10933
|
+
fields: import_zod42.z.array(ApplicationFieldSchema)
|
|
10934
|
+
});
|
|
10935
|
+
var AutoFillMatchSchema = import_zod42.z.object({
|
|
10936
|
+
fieldId: import_zod42.z.string(),
|
|
10937
|
+
value: import_zod42.z.string(),
|
|
10938
|
+
confidence: import_zod42.z.enum(["confirmed"]),
|
|
10939
|
+
contextKey: import_zod42.z.string()
|
|
10940
|
+
});
|
|
10941
|
+
var AutoFillResultSchema = import_zod42.z.object({
|
|
10942
|
+
matches: import_zod42.z.array(AutoFillMatchSchema)
|
|
10943
|
+
});
|
|
10944
|
+
var QuestionBatchResultSchema = import_zod42.z.object({
|
|
10945
|
+
batches: import_zod42.z.array(import_zod42.z.array(import_zod42.z.string()).describe("Array of field IDs in this batch"))
|
|
10946
|
+
});
|
|
10947
|
+
var LookupRequestSchema = import_zod42.z.object({
|
|
10948
|
+
type: import_zod42.z.string().describe("Type of lookup: 'records', 'website', 'policy'"),
|
|
10949
|
+
description: import_zod42.z.string(),
|
|
10950
|
+
url: import_zod42.z.string().optional(),
|
|
10951
|
+
targetFieldIds: import_zod42.z.array(import_zod42.z.string())
|
|
10952
|
+
});
|
|
10953
|
+
var ReplyIntentSchema = import_zod42.z.object({
|
|
10954
|
+
primaryIntent: import_zod42.z.enum(["answers_only", "question", "lookup_request", "mixed"]),
|
|
10955
|
+
hasAnswers: import_zod42.z.boolean(),
|
|
10956
|
+
questionText: import_zod42.z.string().optional(),
|
|
10957
|
+
questionFieldIds: import_zod42.z.array(import_zod42.z.string()).optional(),
|
|
10958
|
+
lookupRequests: import_zod42.z.array(LookupRequestSchema).optional()
|
|
10959
|
+
});
|
|
10960
|
+
var ParsedAnswerSchema = import_zod42.z.object({
|
|
10961
|
+
fieldId: import_zod42.z.string(),
|
|
10962
|
+
value: import_zod42.z.string(),
|
|
10963
|
+
explanation: import_zod42.z.string().optional()
|
|
10964
|
+
});
|
|
10965
|
+
var AnswerParsingResultSchema = import_zod42.z.object({
|
|
10966
|
+
answers: import_zod42.z.array(ParsedAnswerSchema),
|
|
10967
|
+
unanswered: import_zod42.z.array(import_zod42.z.string()).describe("Field IDs that were not answered")
|
|
10968
|
+
});
|
|
10969
|
+
var LookupFillSchema = import_zod42.z.object({
|
|
10970
|
+
fieldId: import_zod42.z.string(),
|
|
10971
|
+
value: import_zod42.z.string(),
|
|
10972
|
+
source: import_zod42.z.string().describe("Specific citable reference, e.g. 'GL Policy #POL-12345 (Hartford)'"),
|
|
10973
|
+
sourceSpanIds: import_zod42.z.array(import_zod42.z.string()).optional()
|
|
10974
|
+
});
|
|
10975
|
+
var LookupFillResultSchema = import_zod42.z.object({
|
|
10976
|
+
fills: import_zod42.z.array(LookupFillSchema),
|
|
10977
|
+
unfillable: import_zod42.z.array(import_zod42.z.string()),
|
|
10978
|
+
explanation: import_zod42.z.string().optional()
|
|
10979
|
+
});
|
|
10980
|
+
var FlatPdfPlacementSchema = import_zod42.z.object({
|
|
10981
|
+
fieldId: import_zod42.z.string(),
|
|
10982
|
+
page: import_zod42.z.number(),
|
|
10983
|
+
x: import_zod42.z.number().describe("Percentage from left edge (0-100)"),
|
|
10984
|
+
y: import_zod42.z.number().describe("Percentage from top edge (0-100)"),
|
|
10985
|
+
text: import_zod42.z.string(),
|
|
10986
|
+
fontSize: import_zod42.z.number().optional(),
|
|
10987
|
+
isCheckmark: import_zod42.z.boolean().optional()
|
|
10988
|
+
});
|
|
10989
|
+
var AcroFormMappingSchema = import_zod42.z.object({
|
|
10990
|
+
fieldId: import_zod42.z.string(),
|
|
10991
|
+
acroFormName: import_zod42.z.string(),
|
|
10992
|
+
value: import_zod42.z.string()
|
|
10993
|
+
});
|
|
10994
|
+
var QualityGateStatusSchema = import_zod42.z.enum(["passed", "warning", "failed"]);
|
|
10995
|
+
var QualitySeveritySchema = import_zod42.z.enum(["info", "warning", "blocking"]);
|
|
10996
|
+
var ApplicationQualityIssueSchema = import_zod42.z.object({
|
|
10997
|
+
code: import_zod42.z.string(),
|
|
9908
10998
|
severity: QualitySeveritySchema,
|
|
9909
|
-
message:
|
|
9910
|
-
fieldId:
|
|
10999
|
+
message: import_zod42.z.string(),
|
|
11000
|
+
fieldId: import_zod42.z.string().optional()
|
|
9911
11001
|
});
|
|
9912
|
-
var ApplicationQualityRoundSchema =
|
|
9913
|
-
round:
|
|
9914
|
-
kind:
|
|
11002
|
+
var ApplicationQualityRoundSchema = import_zod42.z.object({
|
|
11003
|
+
round: import_zod42.z.number(),
|
|
11004
|
+
kind: import_zod42.z.string(),
|
|
9915
11005
|
status: QualityGateStatusSchema,
|
|
9916
|
-
summary:
|
|
11006
|
+
summary: import_zod42.z.string().optional()
|
|
9917
11007
|
});
|
|
9918
|
-
var ApplicationQualityArtifactSchema =
|
|
9919
|
-
kind:
|
|
9920
|
-
label:
|
|
9921
|
-
itemCount:
|
|
11008
|
+
var ApplicationQualityArtifactSchema = import_zod42.z.object({
|
|
11009
|
+
kind: import_zod42.z.string(),
|
|
11010
|
+
label: import_zod42.z.string().optional(),
|
|
11011
|
+
itemCount: import_zod42.z.number().optional()
|
|
9922
11012
|
});
|
|
9923
|
-
var ApplicationEmailReviewSchema =
|
|
9924
|
-
issues:
|
|
11013
|
+
var ApplicationEmailReviewSchema = import_zod42.z.object({
|
|
11014
|
+
issues: import_zod42.z.array(ApplicationQualityIssueSchema),
|
|
9925
11015
|
qualityGateStatus: QualityGateStatusSchema
|
|
9926
11016
|
});
|
|
9927
|
-
var ApplicationQualityReportSchema =
|
|
9928
|
-
issues:
|
|
9929
|
-
rounds:
|
|
9930
|
-
artifacts:
|
|
11017
|
+
var ApplicationQualityReportSchema = import_zod42.z.object({
|
|
11018
|
+
issues: import_zod42.z.array(ApplicationQualityIssueSchema),
|
|
11019
|
+
rounds: import_zod42.z.array(ApplicationQualityRoundSchema).optional(),
|
|
11020
|
+
artifacts: import_zod42.z.array(ApplicationQualityArtifactSchema).optional(),
|
|
9931
11021
|
emailReview: ApplicationEmailReviewSchema.optional(),
|
|
9932
11022
|
qualityGateStatus: QualityGateStatusSchema
|
|
9933
11023
|
});
|
|
9934
|
-
var ApplicationStateSchema =
|
|
9935
|
-
id:
|
|
9936
|
-
pdfBase64:
|
|
9937
|
-
title:
|
|
9938
|
-
applicationType:
|
|
9939
|
-
fields:
|
|
9940
|
-
batches:
|
|
9941
|
-
currentBatchIndex:
|
|
11024
|
+
var ApplicationStateSchema = import_zod42.z.object({
|
|
11025
|
+
id: import_zod42.z.string(),
|
|
11026
|
+
pdfBase64: import_zod42.z.string().optional().describe("Original PDF, omitted after extraction"),
|
|
11027
|
+
title: import_zod42.z.string().optional(),
|
|
11028
|
+
applicationType: import_zod42.z.string().nullable().optional(),
|
|
11029
|
+
fields: import_zod42.z.array(ApplicationFieldSchema),
|
|
11030
|
+
batches: import_zod42.z.array(import_zod42.z.array(import_zod42.z.string())).optional(),
|
|
11031
|
+
currentBatchIndex: import_zod42.z.number().default(0),
|
|
9942
11032
|
qualityReport: ApplicationQualityReportSchema.optional(),
|
|
9943
|
-
status:
|
|
9944
|
-
createdAt:
|
|
9945
|
-
updatedAt:
|
|
11033
|
+
status: import_zod42.z.enum(["classifying", "extracting", "auto_filling", "batching", "collecting", "confirming", "mapping", "complete"]),
|
|
11034
|
+
createdAt: import_zod42.z.number(),
|
|
11035
|
+
updatedAt: import_zod42.z.number()
|
|
9946
11036
|
});
|
|
9947
11037
|
|
|
9948
11038
|
// src/application/agents/classifier.ts
|
|
@@ -11297,104 +12387,106 @@ Respond with the final answer, deduplicated citations array, overall confidence
|
|
|
11297
12387
|
}
|
|
11298
12388
|
|
|
11299
12389
|
// src/schemas/query.ts
|
|
11300
|
-
var
|
|
11301
|
-
var QueryIntentSchema =
|
|
12390
|
+
var import_zod43 = require("zod");
|
|
12391
|
+
var QueryIntentSchema = import_zod43.z.enum([
|
|
11302
12392
|
"policy_question",
|
|
11303
12393
|
"coverage_comparison",
|
|
11304
12394
|
"document_search",
|
|
11305
12395
|
"claims_inquiry",
|
|
11306
12396
|
"general_knowledge"
|
|
11307
12397
|
]);
|
|
11308
|
-
var QueryAttachmentKindSchema =
|
|
11309
|
-
var QueryAttachmentSchema =
|
|
11310
|
-
id:
|
|
12398
|
+
var QueryAttachmentKindSchema = import_zod43.z.enum(["image", "pdf", "text"]);
|
|
12399
|
+
var QueryAttachmentSchema = import_zod43.z.object({
|
|
12400
|
+
id: import_zod43.z.string().optional().describe("Optional stable attachment ID from the caller"),
|
|
11311
12401
|
kind: QueryAttachmentKindSchema,
|
|
11312
|
-
name:
|
|
11313
|
-
mimeType:
|
|
11314
|
-
base64:
|
|
11315
|
-
text:
|
|
11316
|
-
description:
|
|
12402
|
+
name: import_zod43.z.string().optional().describe("Original filename or user-facing label"),
|
|
12403
|
+
mimeType: import_zod43.z.string().optional().describe("MIME type such as image/jpeg or application/pdf"),
|
|
12404
|
+
base64: import_zod43.z.string().optional().describe("Base64-encoded file content for image/pdf attachments"),
|
|
12405
|
+
text: import_zod43.z.string().optional().describe("Plain-text attachment content when available"),
|
|
12406
|
+
description: import_zod43.z.string().optional().describe("Caller-provided description of the attachment")
|
|
11317
12407
|
});
|
|
11318
|
-
var QueryRetrievalModeSchema =
|
|
12408
|
+
var QueryRetrievalModeSchema = import_zod43.z.enum([
|
|
11319
12409
|
"graph_only",
|
|
11320
12410
|
"source_rag",
|
|
11321
12411
|
"long_context",
|
|
11322
12412
|
"hybrid"
|
|
11323
12413
|
]);
|
|
11324
|
-
var SubQuestionSchema =
|
|
11325
|
-
question:
|
|
12414
|
+
var SubQuestionSchema = import_zod43.z.object({
|
|
12415
|
+
question: import_zod43.z.string().describe("Atomic sub-question to retrieve and answer independently"),
|
|
11326
12416
|
intent: QueryIntentSchema,
|
|
11327
|
-
chunkTypes:
|
|
11328
|
-
documentFilters:
|
|
11329
|
-
type:
|
|
11330
|
-
carrier:
|
|
11331
|
-
insuredName:
|
|
11332
|
-
policyNumber:
|
|
11333
|
-
quoteNumber:
|
|
11334
|
-
policyTypes:
|
|
12417
|
+
chunkTypes: import_zod43.z.array(import_zod43.z.string()).optional().describe("Chunk types to filter retrieval (e.g. coverage, endorsement, declaration)"),
|
|
12418
|
+
documentFilters: import_zod43.z.object({
|
|
12419
|
+
type: import_zod43.z.enum(["policy", "quote"]).optional(),
|
|
12420
|
+
carrier: import_zod43.z.string().optional(),
|
|
12421
|
+
insuredName: import_zod43.z.string().optional(),
|
|
12422
|
+
policyNumber: import_zod43.z.string().optional(),
|
|
12423
|
+
quoteNumber: import_zod43.z.string().optional(),
|
|
12424
|
+
policyTypes: import_zod43.z.array(PolicyTypeSchema).optional().describe("Filter by policy type (e.g. homeowners_ho3, renters_ho4, pet) to avoid mixing up similar policies")
|
|
11335
12425
|
}).optional().describe("Structured filters to narrow document lookup")
|
|
11336
12426
|
});
|
|
11337
|
-
var QueryClassifyResultSchema =
|
|
12427
|
+
var QueryClassifyResultSchema = import_zod43.z.object({
|
|
11338
12428
|
intent: QueryIntentSchema,
|
|
11339
|
-
subQuestions:
|
|
11340
|
-
requiresDocumentLookup:
|
|
11341
|
-
requiresChunkSearch:
|
|
11342
|
-
requiresConversationHistory:
|
|
12429
|
+
subQuestions: import_zod43.z.array(SubQuestionSchema).min(1).describe("Decomposed atomic sub-questions"),
|
|
12430
|
+
requiresDocumentLookup: import_zod43.z.boolean().describe("Whether structured document lookup is needed"),
|
|
12431
|
+
requiresChunkSearch: import_zod43.z.boolean().describe("Whether semantic chunk search is needed"),
|
|
12432
|
+
requiresConversationHistory: import_zod43.z.boolean().describe("Whether conversation history is relevant"),
|
|
11343
12433
|
retrievalMode: QueryRetrievalModeSchema.optional().describe("Preferred retrieval strategy for the query when source-span retrieval is available")
|
|
11344
12434
|
});
|
|
11345
|
-
var EvidenceItemSchema =
|
|
11346
|
-
source:
|
|
11347
|
-
chunkId:
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
12435
|
+
var EvidenceItemSchema = import_zod43.z.object({
|
|
12436
|
+
source: import_zod43.z.enum(["chunk", "document", "conversation", "attachment", "source_span", "source_node"]),
|
|
12437
|
+
chunkId: import_zod43.z.string().optional(),
|
|
12438
|
+
sourceNodeId: import_zod43.z.string().optional(),
|
|
12439
|
+
sourceSpanId: import_zod43.z.string().optional(),
|
|
12440
|
+
documentId: import_zod43.z.string().optional(),
|
|
12441
|
+
turnId: import_zod43.z.string().optional(),
|
|
12442
|
+
attachmentId: import_zod43.z.string().optional(),
|
|
12443
|
+
text: import_zod43.z.string().describe("Text excerpt from the source"),
|
|
12444
|
+
relevance: import_zod43.z.number().min(0).max(1),
|
|
11354
12445
|
retrievalMode: QueryRetrievalModeSchema.optional(),
|
|
11355
12446
|
sourceLocation: SourceSpanLocationSchema.optional(),
|
|
11356
|
-
metadata:
|
|
11357
|
-
});
|
|
11358
|
-
var AttachmentInterpretationSchema =
|
|
11359
|
-
summary:
|
|
11360
|
-
extractedFacts:
|
|
11361
|
-
recommendedFocus:
|
|
11362
|
-
confidence:
|
|
11363
|
-
});
|
|
11364
|
-
var RetrievalResultSchema =
|
|
11365
|
-
subQuestion:
|
|
11366
|
-
evidence:
|
|
11367
|
-
});
|
|
11368
|
-
var CitationSchema =
|
|
11369
|
-
index:
|
|
11370
|
-
chunkId:
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
|
|
12447
|
+
metadata: import_zod43.z.array(import_zod43.z.object({ key: import_zod43.z.string(), value: import_zod43.z.string() })).optional()
|
|
12448
|
+
});
|
|
12449
|
+
var AttachmentInterpretationSchema = import_zod43.z.object({
|
|
12450
|
+
summary: import_zod43.z.string().describe("Concise summary of what the attachment shows or contains"),
|
|
12451
|
+
extractedFacts: import_zod43.z.array(import_zod43.z.string()).describe("Specific observable or document facts grounded in the attachment"),
|
|
12452
|
+
recommendedFocus: import_zod43.z.array(import_zod43.z.string()).describe("Important details to incorporate when answering follow-up questions"),
|
|
12453
|
+
confidence: import_zod43.z.number().min(0).max(1)
|
|
12454
|
+
});
|
|
12455
|
+
var RetrievalResultSchema = import_zod43.z.object({
|
|
12456
|
+
subQuestion: import_zod43.z.string(),
|
|
12457
|
+
evidence: import_zod43.z.array(EvidenceItemSchema)
|
|
12458
|
+
});
|
|
12459
|
+
var CitationSchema = import_zod43.z.object({
|
|
12460
|
+
index: import_zod43.z.number().describe("Citation number [1], [2], etc."),
|
|
12461
|
+
chunkId: import_zod43.z.string().optional().describe("Source chunk ID, e.g. doc-123:coverage:2"),
|
|
12462
|
+
sourceNodeId: import_zod43.z.string().optional().describe("Source tree node ID when available"),
|
|
12463
|
+
sourceSpanId: import_zod43.z.string().optional().describe("Precise source span ID when available"),
|
|
12464
|
+
documentId: import_zod43.z.string(),
|
|
12465
|
+
documentType: import_zod43.z.enum(["policy", "quote"]).optional(),
|
|
12466
|
+
field: import_zod43.z.string().optional().describe("Specific field path, e.g. coverages[0].deductible"),
|
|
12467
|
+
quote: import_zod43.z.string().describe("Exact text from source that supports the claim"),
|
|
12468
|
+
relevance: import_zod43.z.number().min(0).max(1),
|
|
11377
12469
|
retrievalMode: QueryRetrievalModeSchema.optional(),
|
|
11378
12470
|
sourceLocation: SourceSpanLocationSchema.optional()
|
|
11379
12471
|
});
|
|
11380
|
-
var SubAnswerSchema =
|
|
11381
|
-
subQuestion:
|
|
11382
|
-
answer:
|
|
11383
|
-
citations:
|
|
11384
|
-
confidence:
|
|
11385
|
-
needsMoreContext:
|
|
11386
|
-
});
|
|
11387
|
-
var VerifyResultSchema =
|
|
11388
|
-
approved:
|
|
11389
|
-
issues:
|
|
11390
|
-
retrySubQuestions:
|
|
11391
|
-
});
|
|
11392
|
-
var QueryResultSchema =
|
|
11393
|
-
answer:
|
|
11394
|
-
citations:
|
|
12472
|
+
var SubAnswerSchema = import_zod43.z.object({
|
|
12473
|
+
subQuestion: import_zod43.z.string(),
|
|
12474
|
+
answer: import_zod43.z.string(),
|
|
12475
|
+
citations: import_zod43.z.array(CitationSchema),
|
|
12476
|
+
confidence: import_zod43.z.number().min(0).max(1),
|
|
12477
|
+
needsMoreContext: import_zod43.z.boolean().describe("True if evidence was insufficient to answer fully")
|
|
12478
|
+
});
|
|
12479
|
+
var VerifyResultSchema = import_zod43.z.object({
|
|
12480
|
+
approved: import_zod43.z.boolean().describe("Whether all sub-answers are adequately grounded"),
|
|
12481
|
+
issues: import_zod43.z.array(import_zod43.z.string()).describe("Specific grounding or consistency issues found"),
|
|
12482
|
+
retrySubQuestions: import_zod43.z.array(import_zod43.z.string()).optional().describe("Sub-questions that need additional retrieval or re-reasoning")
|
|
12483
|
+
});
|
|
12484
|
+
var QueryResultSchema = import_zod43.z.object({
|
|
12485
|
+
answer: import_zod43.z.string(),
|
|
12486
|
+
citations: import_zod43.z.array(CitationSchema),
|
|
11395
12487
|
intent: QueryIntentSchema,
|
|
11396
|
-
confidence:
|
|
11397
|
-
followUp:
|
|
12488
|
+
confidence: import_zod43.z.number().min(0).max(1),
|
|
12489
|
+
followUp: import_zod43.z.string().optional().describe("Suggested follow-up question if applicable")
|
|
11398
12490
|
});
|
|
11399
12491
|
|
|
11400
12492
|
// src/query/retriever.ts
|
|
@@ -11409,6 +12501,35 @@ async function retrieve(subQuestion, conversationId, config) {
|
|
|
11409
12501
|
tasks.push(
|
|
11410
12502
|
(async () => {
|
|
11411
12503
|
try {
|
|
12504
|
+
const nodeResults = await sourceRetriever?.searchSourceNodes?.({
|
|
12505
|
+
question: subQuestion.question,
|
|
12506
|
+
limit: retrievalLimit,
|
|
12507
|
+
mode: retrievalMode
|
|
12508
|
+
}) ?? [];
|
|
12509
|
+
for (const result of nodeResults) {
|
|
12510
|
+
const hierarchyText = result.hierarchy.map((node) => `${node.path} ${node.title}: ${node.textExcerpt ?? node.description}`).join("\n");
|
|
12511
|
+
const spanText = result.spans.map((span) => `[source-span:${span.id}${span.pageStart ? ` p.${span.pageStart}` : ""}]
|
|
12512
|
+
${span.text}`).join("\n\n");
|
|
12513
|
+
evidence.push({
|
|
12514
|
+
source: "source_node",
|
|
12515
|
+
sourceNodeId: result.node.id,
|
|
12516
|
+
sourceSpanId: result.spans[0]?.id,
|
|
12517
|
+
documentId: result.node.documentId,
|
|
12518
|
+
text: [hierarchyText, spanText].filter(Boolean).join("\n\n"),
|
|
12519
|
+
relevance: result.relevance,
|
|
12520
|
+
retrievalMode,
|
|
12521
|
+
sourceLocation: result.spans[0]?.location ?? (result.node.pageStart ? { page: result.node.pageStart } : void 0),
|
|
12522
|
+
metadata: [
|
|
12523
|
+
{ key: "kind", value: result.node.kind },
|
|
12524
|
+
{ key: "path", value: result.node.path },
|
|
12525
|
+
{ key: "title", value: result.node.title },
|
|
12526
|
+
...result.node.metadata ? recordToKVArray(Object.fromEntries(
|
|
12527
|
+
Object.entries(result.node.metadata).filter(([, value]) => typeof value === "string").map(([key, value]) => [key, value])
|
|
12528
|
+
)) : []
|
|
12529
|
+
]
|
|
12530
|
+
});
|
|
12531
|
+
}
|
|
12532
|
+
if (nodeResults.length > 0) return;
|
|
11412
12533
|
const sourceResults = await sourceRetriever?.searchSourceSpans({
|
|
11413
12534
|
question: subQuestion.question,
|
|
11414
12535
|
limit: retrievalLimit,
|
|
@@ -11428,7 +12549,7 @@ async function retrieve(subQuestion, conversationId, config) {
|
|
|
11428
12549
|
});
|
|
11429
12550
|
}
|
|
11430
12551
|
} catch (e) {
|
|
11431
|
-
await log?.(`Source
|
|
12552
|
+
await log?.(`Source tree search failed for "${subQuestion.question}": ${e}`);
|
|
11432
12553
|
}
|
|
11433
12554
|
})()
|
|
11434
12555
|
);
|
|
@@ -11630,7 +12751,7 @@ Answer the sub-question based on the evidence above. For every factual claim, in
|
|
|
11630
12751
|
async function reason(subQuestion, intent, evidence, config) {
|
|
11631
12752
|
const { generateObject, providerOptions } = config;
|
|
11632
12753
|
const evidenceText = evidence.map((e, i) => {
|
|
11633
|
-
const sourceLabel = e.source === "source_span" ? `[source-span:${e.sourceSpanId}]` : e.source === "chunk" ? `[chunk:${e.chunkId}]` : e.source === "document" ? `[doc:${e.documentId}]` : e.source === "attachment" ? `[attachment:${e.attachmentId}]` : `[turn:${e.turnId}]`;
|
|
12754
|
+
const sourceLabel = e.source === "source_node" ? `[source-node:${e.sourceNodeId} source-span:${e.sourceSpanId ?? "none"}]` : e.source === "source_span" ? `[source-span:${e.sourceSpanId}]` : e.source === "chunk" ? `[chunk:${e.chunkId}]` : e.source === "document" ? `[doc:${e.documentId}]` : e.source === "attachment" ? `[attachment:${e.attachmentId}]` : `[turn:${e.turnId}]`;
|
|
11634
12755
|
return `Evidence ${i + 1} ${sourceLabel} (relevance: ${e.relevance.toFixed(2)}):
|
|
11635
12756
|
${e.text}`;
|
|
11636
12757
|
}).join("\n\n");
|
|
@@ -12432,7 +13553,7 @@ ${sa.answer}`).join("\n\n"),
|
|
|
12432
13553
|
}
|
|
12433
13554
|
|
|
12434
13555
|
// src/pce/index.ts
|
|
12435
|
-
var
|
|
13556
|
+
var import_zod44 = require("zod");
|
|
12436
13557
|
|
|
12437
13558
|
// src/prompts/pce/index.ts
|
|
12438
13559
|
function buildPceNormalizePrompt(input) {
|
|
@@ -12466,11 +13587,11 @@ ${input.openQuestions.map((question) => `- ${question.id}${question.fieldPath ?
|
|
|
12466
13587
|
}
|
|
12467
13588
|
|
|
12468
13589
|
// src/pce/index.ts
|
|
12469
|
-
var ReplyAnswersSchema =
|
|
12470
|
-
answers:
|
|
12471
|
-
questionId:
|
|
12472
|
-
fieldPath:
|
|
12473
|
-
answer:
|
|
13590
|
+
var ReplyAnswersSchema = import_zod44.z.object({
|
|
13591
|
+
answers: import_zod44.z.array(import_zod44.z.object({
|
|
13592
|
+
questionId: import_zod44.z.string().optional(),
|
|
13593
|
+
fieldPath: import_zod44.z.string().optional(),
|
|
13594
|
+
answer: import_zod44.z.string()
|
|
12474
13595
|
}))
|
|
12475
13596
|
});
|
|
12476
13597
|
function createPceAgent(config = {}) {
|
|
@@ -13301,6 +14422,8 @@ var AGENT_TOOLS = [
|
|
|
13301
14422
|
DocumentMetadataSchema,
|
|
13302
14423
|
DocumentNodeSchema,
|
|
13303
14424
|
DocumentPageMapEntrySchema,
|
|
14425
|
+
DocumentSourceNodeKindSchema,
|
|
14426
|
+
DocumentSourceNodeSchema,
|
|
13304
14427
|
DocumentTableOfContentsEntrySchema,
|
|
13305
14428
|
DocumentTypeSchema,
|
|
13306
14429
|
DriverRecordSchema,
|
|
@@ -13356,6 +14479,9 @@ var AGENT_TOOLS = [
|
|
|
13356
14479
|
MemorySourceStore,
|
|
13357
14480
|
MissingInfoQuestionSchema,
|
|
13358
14481
|
NamedInsuredSchema,
|
|
14482
|
+
OperationalCoverageLineSchema,
|
|
14483
|
+
OperationalEndorsementSupportSchema,
|
|
14484
|
+
OperationalPartySchema,
|
|
13359
14485
|
PERSONAL_AUTO_USAGES,
|
|
13360
14486
|
PET_SPECIES,
|
|
13361
14487
|
PLATFORM_CONFIGS,
|
|
@@ -13385,6 +14511,7 @@ var AGENT_TOOLS = [
|
|
|
13385
14511
|
PolicyChangeStatusSchema,
|
|
13386
14512
|
PolicyConditionSchema,
|
|
13387
14513
|
PolicyDocumentSchema,
|
|
14514
|
+
PolicyOperationalProfileSchema,
|
|
13388
14515
|
PolicySectionTypeSchema,
|
|
13389
14516
|
PolicyTermTypeSchema,
|
|
13390
14517
|
PolicyTypeSchema,
|
|
@@ -13416,6 +14543,7 @@ var AGENT_TOOLS = [
|
|
|
13416
14543
|
ScheduledItemCategorySchema,
|
|
13417
14544
|
SectionSchema,
|
|
13418
14545
|
SharedLimitSchema,
|
|
14546
|
+
SourceBackedValueSchema,
|
|
13419
14547
|
SourceChunkSchema,
|
|
13420
14548
|
SourceKindSchema,
|
|
13421
14549
|
SourceSpanBBoxSchema,
|
|
@@ -13457,7 +14585,9 @@ var AGENT_TOOLS = [
|
|
|
13457
14585
|
buildConfirmationSummaryPrompt,
|
|
13458
14586
|
buildConversationMemoryGuidance,
|
|
13459
14587
|
buildCoverageGapPrompt,
|
|
14588
|
+
buildDeterministicOperationalProfile,
|
|
13460
14589
|
buildDoclingProviderOptions,
|
|
14590
|
+
buildDocumentSourceTree,
|
|
13461
14591
|
buildFieldExplanationPrompt,
|
|
13462
14592
|
buildFieldExtractionPrompt,
|
|
13463
14593
|
buildFlatPdfMappingPrompt,
|
|
@@ -13506,9 +14636,11 @@ var AGENT_TOOLS = [
|
|
|
13506
14636
|
getTemplate,
|
|
13507
14637
|
isDoclingExtractionInput,
|
|
13508
14638
|
isFileReference,
|
|
14639
|
+
mergeOperationalProfile,
|
|
13509
14640
|
mergeQuestionAnswers,
|
|
13510
14641
|
mergeSourceSpans,
|
|
13511
14642
|
normalizeDoclingDocument,
|
|
14643
|
+
normalizeDocumentSourceTreePaths,
|
|
13512
14644
|
normalizeForMatch,
|
|
13513
14645
|
orderSourceEvidence,
|
|
13514
14646
|
overlayTextOnPdf,
|